github.com/jandre/docker@v1.7.0/links/links.go (about) 1 package links 2 3 import ( 4 "fmt" 5 "path" 6 "strings" 7 8 "github.com/docker/docker/nat" 9 ) 10 11 type Link struct { 12 ParentIP string 13 ChildIP string 14 Name string 15 ChildEnvironment []string 16 Ports []nat.Port 17 IsEnabled bool 18 } 19 20 func NewLink(parentIP, childIP, name string, env []string, exposedPorts map[nat.Port]struct{}) (*Link, error) { 21 22 var ( 23 i int 24 ports = make([]nat.Port, len(exposedPorts)) 25 ) 26 27 for p := range exposedPorts { 28 ports[i] = p 29 i++ 30 } 31 32 l := &Link{ 33 Name: name, 34 ChildIP: childIP, 35 ParentIP: parentIP, 36 ChildEnvironment: env, 37 Ports: ports, 38 } 39 return l, nil 40 41 } 42 43 func (l *Link) Alias() string { 44 _, alias := path.Split(l.Name) 45 return alias 46 } 47 48 func nextContiguous(ports []nat.Port, value int, index int) int { 49 if index+1 == len(ports) { 50 return index 51 } 52 for i := index + 1; i < len(ports); i++ { 53 if ports[i].Int() > value+1 { 54 return i - 1 55 } 56 57 value++ 58 } 59 return len(ports) - 1 60 } 61 62 func (l *Link) ToEnv() []string { 63 env := []string{} 64 alias := strings.Replace(strings.ToUpper(l.Alias()), "-", "_", -1) 65 66 if p := l.getDefaultPort(); p != nil { 67 env = append(env, fmt.Sprintf("%s_PORT=%s://%s:%s", alias, p.Proto(), l.ChildIP, p.Port())) 68 } 69 70 //sort the ports so that we can bulk the continuous ports together 71 nat.Sort(l.Ports, func(ip, jp nat.Port) bool { 72 // If the two ports have the same number, tcp takes priority 73 // Sort in desc order 74 return ip.Int() < jp.Int() || (ip.Int() == jp.Int() && strings.ToLower(ip.Proto()) == "tcp") 75 }) 76 77 for i := 0; i < len(l.Ports); { 78 p := l.Ports[i] 79 j := nextContiguous(l.Ports, p.Int(), i) 80 if j > i+1 { 81 env = append(env, fmt.Sprintf("%s_PORT_%s_%s_START=%s://%s:%s", alias, p.Port(), strings.ToUpper(p.Proto()), p.Proto(), l.ChildIP, p.Port())) 82 env = append(env, fmt.Sprintf("%s_PORT_%s_%s_ADDR=%s", alias, p.Port(), strings.ToUpper(p.Proto()), l.ChildIP)) 83 env = append(env, fmt.Sprintf("%s_PORT_%s_%s_PROTO=%s", alias, p.Port(), strings.ToUpper(p.Proto()), p.Proto())) 84 env = append(env, fmt.Sprintf("%s_PORT_%s_%s_PORT_START=%s", alias, p.Port(), strings.ToUpper(p.Proto()), p.Port())) 85 86 q := l.Ports[j] 87 env = append(env, fmt.Sprintf("%s_PORT_%s_%s_END=%s://%s:%s", alias, p.Port(), strings.ToUpper(q.Proto()), q.Proto(), l.ChildIP, q.Port())) 88 env = append(env, fmt.Sprintf("%s_PORT_%s_%s_PORT_END=%s", alias, p.Port(), strings.ToUpper(q.Proto()), q.Port())) 89 90 i = j + 1 91 continue 92 } else { 93 i++ 94 } 95 } 96 for _, p := range l.Ports { 97 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())) 98 env = append(env, fmt.Sprintf("%s_PORT_%s_%s_ADDR=%s", alias, p.Port(), strings.ToUpper(p.Proto()), l.ChildIP)) 99 env = append(env, fmt.Sprintf("%s_PORT_%s_%s_PORT=%s", alias, p.Port(), strings.ToUpper(p.Proto()), p.Port())) 100 env = append(env, fmt.Sprintf("%s_PORT_%s_%s_PROTO=%s", alias, p.Port(), strings.ToUpper(p.Proto()), p.Proto())) 101 } 102 103 // Load the linked container's name into the environment 104 env = append(env, fmt.Sprintf("%s_NAME=%s", alias, l.Name)) 105 106 if l.ChildEnvironment != nil { 107 for _, v := range l.ChildEnvironment { 108 parts := strings.SplitN(v, "=", 2) 109 if len(parts) < 2 { 110 continue 111 } 112 // Ignore a few variables that are added during docker build (and not really relevant to linked containers) 113 if parts[0] == "HOME" || parts[0] == "PATH" { 114 continue 115 } 116 env = append(env, fmt.Sprintf("%s_ENV_%s=%s", alias, parts[0], parts[1])) 117 } 118 } 119 return env 120 } 121 122 // Default port rules 123 func (l *Link) getDefaultPort() *nat.Port { 124 var p nat.Port 125 i := len(l.Ports) 126 127 if i == 0 { 128 return nil 129 } else if i > 1 { 130 nat.Sort(l.Ports, func(ip, jp nat.Port) bool { 131 // If the two ports have the same number, tcp takes priority 132 // Sort in desc order 133 return ip.Int() < jp.Int() || (ip.Int() == jp.Int() && strings.ToLower(ip.Proto()) == "tcp") 134 }) 135 } 136 p = l.Ports[0] 137 return &p 138 } 139 140 func (l *Link) Enable() error { 141 l.IsEnabled = true 142 return nil 143 } 144 145 func (l *Link) Disable() { 146 l.IsEnabled = false 147 }