links.go 3.3 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137
  1. package links
  2. import (
  3. "fmt"
  4. "github.com/dotcloud/docker/engine"
  5. "github.com/dotcloud/docker/nat"
  6. "path"
  7. "strings"
  8. )
  9. type Link struct {
  10. ParentIP string
  11. ChildIP string
  12. Name string
  13. ChildEnvironment []string
  14. Ports []nat.Port
  15. IsEnabled bool
  16. eng *engine.Engine
  17. }
  18. func NewLink(parentIP, childIP, name string, env []string, exposedPorts map[nat.Port]struct{}, eng *engine.Engine) (*Link, error) {
  19. var (
  20. i int
  21. ports = make([]nat.Port, len(exposedPorts))
  22. )
  23. for p := range exposedPorts {
  24. ports[i] = p
  25. i++
  26. }
  27. l := &Link{
  28. Name: name,
  29. ChildIP: childIP,
  30. ParentIP: parentIP,
  31. ChildEnvironment: env,
  32. Ports: ports,
  33. eng: eng,
  34. }
  35. return l, nil
  36. }
  37. func (l *Link) Alias() string {
  38. _, alias := path.Split(l.Name)
  39. return alias
  40. }
  41. func (l *Link) ToEnv() []string {
  42. env := []string{}
  43. alias := strings.ToUpper(l.Alias())
  44. if p := l.getDefaultPort(); p != nil {
  45. env = append(env, fmt.Sprintf("%s_PORT=%s://%s:%s", alias, p.Proto(), l.ChildIP, p.Port()))
  46. }
  47. // Load exposed ports into the environment
  48. for _, p := range l.Ports {
  49. env = append(env, fmt.Sprintf("%s_PORT_%s_%s=%s://%s:%s", alias, p.Port(), strings.ToUpper(p.Proto()), p.Proto(), l.ChildIP, p.Port()))
  50. env = append(env, fmt.Sprintf("%s_PORT_%s_%s_ADDR=%s", alias, p.Port(), strings.ToUpper(p.Proto()), l.ChildIP))
  51. env = append(env, fmt.Sprintf("%s_PORT_%s_%s_PORT=%s", alias, p.Port(), strings.ToUpper(p.Proto()), p.Port()))
  52. env = append(env, fmt.Sprintf("%s_PORT_%s_%s_PROTO=%s", alias, p.Port(), strings.ToUpper(p.Proto()), p.Proto()))
  53. }
  54. // Load the linked container's name into the environment
  55. env = append(env, fmt.Sprintf("%s_NAME=%s", alias, l.Name))
  56. if l.ChildEnvironment != nil {
  57. for _, v := range l.ChildEnvironment {
  58. parts := strings.Split(v, "=")
  59. if len(parts) != 2 {
  60. continue
  61. }
  62. // Ignore a few variables that are added during docker build (and not really relevant to linked containers)
  63. if parts[0] == "HOME" || parts[0] == "PATH" {
  64. continue
  65. }
  66. env = append(env, fmt.Sprintf("%s_ENV_%s=%s", alias, parts[0], parts[1]))
  67. }
  68. }
  69. return env
  70. }
  71. // Default port rules
  72. func (l *Link) getDefaultPort() *nat.Port {
  73. var p nat.Port
  74. i := len(l.Ports)
  75. if i == 0 {
  76. return nil
  77. } else if i > 1 {
  78. nat.Sort(l.Ports, func(ip, jp nat.Port) bool {
  79. // If the two ports have the same number, tcp takes priority
  80. // Sort in desc order
  81. return ip.Int() < jp.Int() || (ip.Int() == jp.Int() && strings.ToLower(ip.Proto()) == "tcp")
  82. })
  83. }
  84. p = l.Ports[0]
  85. return &p
  86. }
  87. func (l *Link) Enable() error {
  88. if err := l.toggle("-I", false); err != nil {
  89. return err
  90. }
  91. l.IsEnabled = true
  92. return nil
  93. }
  94. func (l *Link) Disable() {
  95. // We do not care about errors here because the link may not
  96. // exist in iptables
  97. l.toggle("-D", true)
  98. l.IsEnabled = false
  99. }
  100. func (l *Link) toggle(action string, ignoreErrors bool) error {
  101. job := l.eng.Job("link", action)
  102. job.Setenv("ParentIP", l.ParentIP)
  103. job.Setenv("ChildIP", l.ChildIP)
  104. job.SetenvBool("IgnoreErrors", ignoreErrors)
  105. out := make([]string, len(l.Ports))
  106. for i, p := range l.Ports {
  107. out[i] = fmt.Sprintf("%s/%s", p.Port(), p.Proto())
  108. }
  109. job.SetenvList("Ports", out)
  110. if err := job.Run(); err != nil {
  111. // TODO: get ouput from job
  112. return err
  113. }
  114. return nil
  115. }