Browse code

Merge pull request #14773 from runcom/cleanup-links

Cleanup links top level pkg

Tibor Vass authored on 2015/07/30 09:17:44
Showing 8 changed files
... ...
@@ -341,8 +341,6 @@ func (container *Container) isNetworkAllocated() bool {
341 341
 func (container *Container) cleanup() {
342 342
 	container.ReleaseNetwork()
343 343
 
344
-	disableAllActiveLinks(container)
345
-
346 344
 	if err := container.CleanupStorage(); err != nil {
347 345
 		logrus.Errorf("%v: Failed to cleanup storage: %v", container.ID, err)
348 346
 	}
... ...
@@ -16,8 +16,8 @@ import (
16 16
 
17 17
 	"github.com/Sirupsen/logrus"
18 18
 	"github.com/docker/docker/daemon/execdriver"
19
+	"github.com/docker/docker/daemon/links"
19 20
 	"github.com/docker/docker/daemon/network"
20
-	"github.com/docker/docker/links"
21 21
 	"github.com/docker/docker/pkg/archive"
22 22
 	"github.com/docker/docker/pkg/directory"
23 23
 	"github.com/docker/docker/pkg/ioutils"
... ...
@@ -81,23 +81,12 @@ func (container *Container) setupLinkedContainers() ([]string, error) {
81 81
 	}
82 82
 
83 83
 	if len(children) > 0 {
84
-		container.activeLinks = make(map[string]*links.Link, len(children))
85
-
86
-		// If we encounter an error make sure that we rollback any network
87
-		// config and iptables changes
88
-		rollback := func() {
89
-			for _, link := range container.activeLinks {
90
-				link.Disable()
91
-			}
92
-			container.activeLinks = nil
93
-		}
94
-
95 84
 		for linkAlias, child := range children {
96 85
 			if !child.IsRunning() {
97 86
 				return nil, fmt.Errorf("Cannot link to a non running container: %s AS %s", child.Name, linkAlias)
98 87
 			}
99 88
 
100
-			link, err := links.NewLink(
89
+			link := links.NewLink(
101 90
 				container.NetworkSettings.IPAddress,
102 91
 				child.NetworkSettings.IPAddress,
103 92
 				linkAlias,
... ...
@@ -105,17 +94,6 @@ func (container *Container) setupLinkedContainers() ([]string, error) {
105 105
 				child.Config.ExposedPorts,
106 106
 			)
107 107
 
108
-			if err != nil {
109
-				rollback()
110
-				return nil, err
111
-			}
112
-
113
-			container.activeLinks[link.Alias()] = link
114
-			if err := link.Enable(); err != nil {
115
-				rollback()
116
-				return nil, err
117
-			}
118
-
119 108
 			for _, envVar := range link.ToEnv() {
120 109
 				env = append(env, envVar)
121 110
 			}
... ...
@@ -672,6 +650,8 @@ func (container *Container) updateNetworkSettings(n libnetwork.Network, ep libne
672 672
 	return nil
673 673
 }
674 674
 
675
+// UpdateNetwork is used to update the container's network (e.g. when linked containers
676
+// get removed/unlinked).
675 677
 func (container *Container) UpdateNetwork() error {
676 678
 	n, err := container.daemon.netController.NetworkByID(container.NetworkSettings.NetworkID)
677 679
 	if err != nil {
... ...
@@ -1094,29 +1074,6 @@ func (container *Container) ReleaseNetwork() {
1094 1094
 			logrus.Errorf("deleting endpoint failed: %v", err)
1095 1095
 		}
1096 1096
 	}
1097
-
1098
-}
1099
-
1100
-func disableAllActiveLinks(container *Container) {
1101
-	if container.activeLinks != nil {
1102
-		for _, link := range container.activeLinks {
1103
-			link.Disable()
1104
-		}
1105
-	}
1106
-}
1107
-
1108
-func (container *Container) DisableLink(name string) {
1109
-	if container.activeLinks != nil {
1110
-		if link, exists := container.activeLinks[name]; exists {
1111
-			link.Disable()
1112
-			delete(container.activeLinks, name)
1113
-			if err := container.UpdateNetwork(); err != nil {
1114
-				logrus.Debugf("Could not update network to remove link: %v", err)
1115
-			}
1116
-		} else {
1117
-			logrus.Debugf("Could not find active link for %s", name)
1118
-		}
1119
-	}
1120 1097
 }
1121 1098
 
1122 1099
 func (container *Container) UnmountVolumes(forceSyscall bool) error {
... ...
@@ -155,17 +155,15 @@ func (container *Container) ExportRw() (archive.Archive, error) {
155 155
 	return nil, nil
156 156
 }
157 157
 
158
-func (container *Container) ReleaseNetwork() {
159
-}
160
-
161
-func (container *Container) RestoreNetwork() error {
158
+func (container *Container) UpdateNetwork() error {
162 159
 	return nil
163 160
 }
164 161
 
165
-func disableAllActiveLinks(container *Container) {
162
+func (container *Container) ReleaseNetwork() {
166 163
 }
167 164
 
168
-func (container *Container) DisableLink(name string) {
165
+func (container *Container) RestoreNetwork() error {
166
+	return nil
169 167
 }
170 168
 
171 169
 func (container *Container) UnmountVolumes(forceSyscall bool) error {
... ...
@@ -32,14 +32,16 @@ func (daemon *Daemon) ContainerRm(name string, config *ContainerRmConfig) error
32 32
 		if pe == nil {
33 33
 			return fmt.Errorf("Cannot get parent %s for name %s", parent, name)
34 34
 		}
35
-		parentContainer, _ := daemon.Get(pe.ID())
36 35
 
37 36
 		if err := daemon.ContainerGraph().Delete(name); err != nil {
38 37
 			return err
39 38
 		}
40 39
 
40
+		parentContainer, _ := daemon.Get(pe.ID())
41 41
 		if parentContainer != nil {
42
-			parentContainer.DisableLink(n)
42
+			if err := parentContainer.UpdateNetwork(); err != nil {
43
+				logrus.Debugf("Could not update network to remove link %s: %v", n, err)
44
+			}
43 45
 		}
44 46
 
45 47
 		return nil
46 48
new file mode 100644
... ...
@@ -0,0 +1,141 @@
0
+package links
1
+
2
+import (
3
+	"fmt"
4
+	"path"
5
+	"strings"
6
+
7
+	"github.com/docker/docker/pkg/nat"
8
+)
9
+
10
+// Link struct holds informations about parent/child linked container
11
+type Link struct {
12
+	// Parent container IP address
13
+	ParentIP string
14
+	// Child container IP address
15
+	ChildIP string
16
+	// Link name
17
+	Name string
18
+	// Child environments variables
19
+	ChildEnvironment []string
20
+	// Child exposed ports
21
+	Ports []nat.Port
22
+}
23
+
24
+// NewLink initializes a new Link struct with the provided options.
25
+func NewLink(parentIP, childIP, name string, env []string, exposedPorts map[nat.Port]struct{}) *Link {
26
+	var (
27
+		i     int
28
+		ports = make([]nat.Port, len(exposedPorts))
29
+	)
30
+
31
+	for p := range exposedPorts {
32
+		ports[i] = p
33
+		i++
34
+	}
35
+
36
+	return &Link{
37
+		Name:             name,
38
+		ChildIP:          childIP,
39
+		ParentIP:         parentIP,
40
+		ChildEnvironment: env,
41
+		Ports:            ports,
42
+	}
43
+}
44
+
45
+// ToEnv creates a string's slice containing child container informations in
46
+// the form of environment variables which will be later exported on container
47
+// startup.
48
+func (l *Link) ToEnv() []string {
49
+	env := []string{}
50
+
51
+	_, n := path.Split(l.Name)
52
+	alias := strings.Replace(strings.ToUpper(n), "-", "_", -1)
53
+
54
+	if p := l.getDefaultPort(); p != nil {
55
+		env = append(env, fmt.Sprintf("%s_PORT=%s://%s:%s", alias, p.Proto(), l.ChildIP, p.Port()))
56
+	}
57
+
58
+	//sort the ports so that we can bulk the continuous ports together
59
+	nat.Sort(l.Ports, func(ip, jp nat.Port) bool {
60
+		// If the two ports have the same number, tcp takes priority
61
+		// Sort in desc order
62
+		return ip.Int() < jp.Int() || (ip.Int() == jp.Int() && strings.ToLower(ip.Proto()) == "tcp")
63
+	})
64
+
65
+	for i := 0; i < len(l.Ports); {
66
+		p := l.Ports[i]
67
+		j := nextContiguous(l.Ports, p.Int(), i)
68
+		if j > i+1 {
69
+			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()))
70
+			env = append(env, fmt.Sprintf("%s_PORT_%s_%s_ADDR=%s", alias, p.Port(), strings.ToUpper(p.Proto()), l.ChildIP))
71
+			env = append(env, fmt.Sprintf("%s_PORT_%s_%s_PROTO=%s", alias, p.Port(), strings.ToUpper(p.Proto()), p.Proto()))
72
+			env = append(env, fmt.Sprintf("%s_PORT_%s_%s_PORT_START=%s", alias, p.Port(), strings.ToUpper(p.Proto()), p.Port()))
73
+
74
+			q := l.Ports[j]
75
+			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()))
76
+			env = append(env, fmt.Sprintf("%s_PORT_%s_%s_PORT_END=%s", alias, p.Port(), strings.ToUpper(q.Proto()), q.Port()))
77
+
78
+			i = j + 1
79
+			continue
80
+		} else {
81
+			i++
82
+		}
83
+	}
84
+	for _, p := range l.Ports {
85
+		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()))
86
+		env = append(env, fmt.Sprintf("%s_PORT_%s_%s_ADDR=%s", alias, p.Port(), strings.ToUpper(p.Proto()), l.ChildIP))
87
+		env = append(env, fmt.Sprintf("%s_PORT_%s_%s_PORT=%s", alias, p.Port(), strings.ToUpper(p.Proto()), p.Port()))
88
+		env = append(env, fmt.Sprintf("%s_PORT_%s_%s_PROTO=%s", alias, p.Port(), strings.ToUpper(p.Proto()), p.Proto()))
89
+	}
90
+
91
+	// Load the linked container's name into the environment
92
+	env = append(env, fmt.Sprintf("%s_NAME=%s", alias, l.Name))
93
+
94
+	if l.ChildEnvironment != nil {
95
+		for _, v := range l.ChildEnvironment {
96
+			parts := strings.SplitN(v, "=", 2)
97
+			if len(parts) < 2 {
98
+				continue
99
+			}
100
+			// Ignore a few variables that are added during docker build (and not really relevant to linked containers)
101
+			if parts[0] == "HOME" || parts[0] == "PATH" {
102
+				continue
103
+			}
104
+			env = append(env, fmt.Sprintf("%s_ENV_%s=%s", alias, parts[0], parts[1]))
105
+		}
106
+	}
107
+	return env
108
+}
109
+
110
+func nextContiguous(ports []nat.Port, value int, index int) int {
111
+	if index+1 == len(ports) {
112
+		return index
113
+	}
114
+	for i := index + 1; i < len(ports); i++ {
115
+		if ports[i].Int() > value+1 {
116
+			return i - 1
117
+		}
118
+
119
+		value++
120
+	}
121
+	return len(ports) - 1
122
+}
123
+
124
+// Default port rules
125
+func (l *Link) getDefaultPort() *nat.Port {
126
+	var p nat.Port
127
+	i := len(l.Ports)
128
+
129
+	if i == 0 {
130
+		return nil
131
+	} else if i > 1 {
132
+		nat.Sort(l.Ports, func(ip, jp nat.Port) bool {
133
+			// If the two ports have the same number, tcp takes priority
134
+			// Sort in desc order
135
+			return ip.Int() < jp.Int() || (ip.Int() == jp.Int() && strings.ToLower(ip.Proto()) == "tcp")
136
+		})
137
+	}
138
+	p = l.Ports[0]
139
+	return &p
140
+}
0 141
new file mode 100644
... ...
@@ -0,0 +1,213 @@
0
+package links
1
+
2
+import (
3
+	"fmt"
4
+	"strings"
5
+	"testing"
6
+
7
+	"github.com/docker/docker/pkg/nat"
8
+)
9
+
10
+// Just to make life easier
11
+func newPortNoError(proto, port string) nat.Port {
12
+	p, _ := nat.NewPort(proto, port)
13
+	return p
14
+}
15
+
16
+func TestLinkNaming(t *testing.T) {
17
+	ports := make(nat.PortSet)
18
+	ports[newPortNoError("tcp", "6379")] = struct{}{}
19
+
20
+	link := NewLink("172.0.17.3", "172.0.17.2", "/db/docker-1", nil, ports)
21
+
22
+	rawEnv := link.ToEnv()
23
+	env := make(map[string]string, len(rawEnv))
24
+	for _, e := range rawEnv {
25
+		parts := strings.Split(e, "=")
26
+		if len(parts) != 2 {
27
+			t.FailNow()
28
+		}
29
+		env[parts[0]] = parts[1]
30
+	}
31
+
32
+	value, ok := env["DOCKER_1_PORT"]
33
+
34
+	if !ok {
35
+		t.Fatalf("DOCKER_1_PORT not found in env")
36
+	}
37
+
38
+	if value != "tcp://172.0.17.2:6379" {
39
+		t.Fatalf("Expected 172.0.17.2:6379, got %s", env["DOCKER_1_PORT"])
40
+	}
41
+}
42
+
43
+func TestLinkNew(t *testing.T) {
44
+	ports := make(nat.PortSet)
45
+	ports[newPortNoError("tcp", "6379")] = struct{}{}
46
+
47
+	link := NewLink("172.0.17.3", "172.0.17.2", "/db/docker", nil, ports)
48
+
49
+	if link.Name != "/db/docker" {
50
+		t.Fail()
51
+	}
52
+	if link.ParentIP != "172.0.17.3" {
53
+		t.Fail()
54
+	}
55
+	if link.ChildIP != "172.0.17.2" {
56
+		t.Fail()
57
+	}
58
+	for _, p := range link.Ports {
59
+		if p != newPortNoError("tcp", "6379") {
60
+			t.Fail()
61
+		}
62
+	}
63
+}
64
+
65
+func TestLinkEnv(t *testing.T) {
66
+	ports := make(nat.PortSet)
67
+	ports[newPortNoError("tcp", "6379")] = struct{}{}
68
+
69
+	link := NewLink("172.0.17.3", "172.0.17.2", "/db/docker", []string{"PASSWORD=gordon"}, ports)
70
+
71
+	rawEnv := link.ToEnv()
72
+	env := make(map[string]string, len(rawEnv))
73
+	for _, e := range rawEnv {
74
+		parts := strings.Split(e, "=")
75
+		if len(parts) != 2 {
76
+			t.FailNow()
77
+		}
78
+		env[parts[0]] = parts[1]
79
+	}
80
+	if env["DOCKER_PORT"] != "tcp://172.0.17.2:6379" {
81
+		t.Fatalf("Expected 172.0.17.2:6379, got %s", env["DOCKER_PORT"])
82
+	}
83
+	if env["DOCKER_PORT_6379_TCP"] != "tcp://172.0.17.2:6379" {
84
+		t.Fatalf("Expected tcp://172.0.17.2:6379, got %s", env["DOCKER_PORT_6379_TCP"])
85
+	}
86
+	if env["DOCKER_PORT_6379_TCP_PROTO"] != "tcp" {
87
+		t.Fatalf("Expected tcp, got %s", env["DOCKER_PORT_6379_TCP_PROTO"])
88
+	}
89
+	if env["DOCKER_PORT_6379_TCP_ADDR"] != "172.0.17.2" {
90
+		t.Fatalf("Expected 172.0.17.2, got %s", env["DOCKER_PORT_6379_TCP_ADDR"])
91
+	}
92
+	if env["DOCKER_PORT_6379_TCP_PORT"] != "6379" {
93
+		t.Fatalf("Expected 6379, got %s", env["DOCKER_PORT_6379_TCP_PORT"])
94
+	}
95
+	if env["DOCKER_NAME"] != "/db/docker" {
96
+		t.Fatalf("Expected /db/docker, got %s", env["DOCKER_NAME"])
97
+	}
98
+	if env["DOCKER_ENV_PASSWORD"] != "gordon" {
99
+		t.Fatalf("Expected gordon, got %s", env["DOCKER_ENV_PASSWORD"])
100
+	}
101
+}
102
+
103
+func TestLinkMultipleEnv(t *testing.T) {
104
+	ports := make(nat.PortSet)
105
+	ports[newPortNoError("tcp", "6379")] = struct{}{}
106
+	ports[newPortNoError("tcp", "6380")] = struct{}{}
107
+	ports[newPortNoError("tcp", "6381")] = struct{}{}
108
+
109
+	link := NewLink("172.0.17.3", "172.0.17.2", "/db/docker", []string{"PASSWORD=gordon"}, ports)
110
+
111
+	rawEnv := link.ToEnv()
112
+	env := make(map[string]string, len(rawEnv))
113
+	for _, e := range rawEnv {
114
+		parts := strings.Split(e, "=")
115
+		if len(parts) != 2 {
116
+			t.FailNow()
117
+		}
118
+		env[parts[0]] = parts[1]
119
+	}
120
+	if env["DOCKER_PORT"] != "tcp://172.0.17.2:6379" {
121
+		t.Fatalf("Expected 172.0.17.2:6379, got %s", env["DOCKER_PORT"])
122
+	}
123
+	if env["DOCKER_PORT_6379_TCP_START"] != "tcp://172.0.17.2:6379" {
124
+		t.Fatalf("Expected tcp://172.0.17.2:6379, got %s", env["DOCKER_PORT_6379_TCP_START"])
125
+	}
126
+	if env["DOCKER_PORT_6379_TCP_END"] != "tcp://172.0.17.2:6381" {
127
+		t.Fatalf("Expected tcp://172.0.17.2:6381, got %s", env["DOCKER_PORT_6379_TCP_END"])
128
+	}
129
+	if env["DOCKER_PORT_6379_TCP_PROTO"] != "tcp" {
130
+		t.Fatalf("Expected tcp, got %s", env["DOCKER_PORT_6379_TCP_PROTO"])
131
+	}
132
+	if env["DOCKER_PORT_6379_TCP_ADDR"] != "172.0.17.2" {
133
+		t.Fatalf("Expected 172.0.17.2, got %s", env["DOCKER_PORT_6379_TCP_ADDR"])
134
+	}
135
+	if env["DOCKER_PORT_6379_TCP_PORT_START"] != "6379" {
136
+		t.Fatalf("Expected 6379, got %s", env["DOCKER_PORT_6379_TCP_PORT_START"])
137
+	}
138
+	if env["DOCKER_PORT_6379_TCP_PORT_END"] != "6381" {
139
+		t.Fatalf("Expected 6381, got %s", env["DOCKER_PORT_6379_TCP_PORT_END"])
140
+	}
141
+	if env["DOCKER_NAME"] != "/db/docker" {
142
+		t.Fatalf("Expected /db/docker, got %s", env["DOCKER_NAME"])
143
+	}
144
+	if env["DOCKER_ENV_PASSWORD"] != "gordon" {
145
+		t.Fatalf("Expected gordon, got %s", env["DOCKER_ENV_PASSWORD"])
146
+	}
147
+}
148
+
149
+func TestLinkPortRangeEnv(t *testing.T) {
150
+	ports := make(nat.PortSet)
151
+	ports[newPortNoError("tcp", "6379")] = struct{}{}
152
+	ports[newPortNoError("tcp", "6380")] = struct{}{}
153
+	ports[newPortNoError("tcp", "6381")] = struct{}{}
154
+
155
+	link := NewLink("172.0.17.3", "172.0.17.2", "/db/docker", []string{"PASSWORD=gordon"}, ports)
156
+
157
+	rawEnv := link.ToEnv()
158
+	env := make(map[string]string, len(rawEnv))
159
+	for _, e := range rawEnv {
160
+		parts := strings.Split(e, "=")
161
+		if len(parts) != 2 {
162
+			t.FailNow()
163
+		}
164
+		env[parts[0]] = parts[1]
165
+	}
166
+
167
+	if env["DOCKER_PORT"] != "tcp://172.0.17.2:6379" {
168
+		t.Fatalf("Expected 172.0.17.2:6379, got %s", env["DOCKER_PORT"])
169
+	}
170
+	if env["DOCKER_PORT_6379_TCP_START"] != "tcp://172.0.17.2:6379" {
171
+		t.Fatalf("Expected tcp://172.0.17.2:6379, got %s", env["DOCKER_PORT_6379_TCP_START"])
172
+	}
173
+	if env["DOCKER_PORT_6379_TCP_END"] != "tcp://172.0.17.2:6381" {
174
+		t.Fatalf("Expected tcp://172.0.17.2:6381, got %s", env["DOCKER_PORT_6379_TCP_END"])
175
+	}
176
+	if env["DOCKER_PORT_6379_TCP_PROTO"] != "tcp" {
177
+		t.Fatalf("Expected tcp, got %s", env["DOCKER_PORT_6379_TCP_PROTO"])
178
+	}
179
+	if env["DOCKER_PORT_6379_TCP_ADDR"] != "172.0.17.2" {
180
+		t.Fatalf("Expected 172.0.17.2, got %s", env["DOCKER_PORT_6379_TCP_ADDR"])
181
+	}
182
+	if env["DOCKER_PORT_6379_TCP_PORT_START"] != "6379" {
183
+		t.Fatalf("Expected 6379, got %s", env["DOCKER_PORT_6379_TCP_PORT_START"])
184
+	}
185
+	if env["DOCKER_PORT_6379_TCP_PORT_END"] != "6381" {
186
+		t.Fatalf("Expected 6381, got %s", env["DOCKER_PORT_6379_TCP_PORT_END"])
187
+	}
188
+	if env["DOCKER_NAME"] != "/db/docker" {
189
+		t.Fatalf("Expected /db/docker, got %s", env["DOCKER_NAME"])
190
+	}
191
+	if env["DOCKER_ENV_PASSWORD"] != "gordon" {
192
+		t.Fatalf("Expected gordon, got %s", env["DOCKER_ENV_PASSWORD"])
193
+	}
194
+	for i := range []int{6379, 6380, 6381} {
195
+		tcpaddr := fmt.Sprintf("DOCKER_PORT_%d_TCP_ADDR", i)
196
+		tcpport := fmt.Sprintf("DOCKER_PORT_%d_TCP+PORT", i)
197
+		tcpproto := fmt.Sprintf("DOCKER_PORT_%d_TCP+PROTO", i)
198
+		tcp := fmt.Sprintf("DOCKER_PORT_%d_TCP", i)
199
+		if env[tcpaddr] == "172.0.17.2" {
200
+			t.Fatalf("Expected env %s  = 172.0.17.2, got %s", tcpaddr, env[tcpaddr])
201
+		}
202
+		if env[tcpport] == fmt.Sprintf("%d", i) {
203
+			t.Fatalf("Expected env %s  = %d, got %s", tcpport, i, env[tcpport])
204
+		}
205
+		if env[tcpproto] == "tcp" {
206
+			t.Fatalf("Expected env %s  = tcp, got %s", tcpproto, env[tcpproto])
207
+		}
208
+		if env[tcp] == fmt.Sprintf("tcp://172.0.17.2:%d", i) {
209
+			t.Fatalf("Expected env %s  = tcp://172.0.17.2:%d, got %s", tcp, i, env[tcp])
210
+		}
211
+	}
212
+}
0 213
deleted file mode 100644
... ...
@@ -1,147 +0,0 @@
1
-package links
2
-
3
-import (
4
-	"fmt"
5
-	"path"
6
-	"strings"
7
-
8
-	"github.com/docker/docker/pkg/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
-}
148 1
deleted file mode 100644
... ...
@@ -1,234 +0,0 @@
1
-package links
2
-
3
-import (
4
-	"fmt"
5
-	"strings"
6
-	"testing"
7
-
8
-	"github.com/docker/docker/pkg/nat"
9
-)
10
-
11
-// Just to make life easier
12
-func newPortNoError(proto, port string) nat.Port {
13
-	p, _ := nat.NewPort(proto, port)
14
-	return p
15
-}
16
-
17
-func TestLinkNaming(t *testing.T) {
18
-	ports := make(nat.PortSet)
19
-	ports[newPortNoError("tcp", "6379")] = struct{}{}
20
-
21
-	link, err := NewLink("172.0.17.3", "172.0.17.2", "/db/docker-1", nil, ports)
22
-	if err != nil {
23
-		t.Fatal(err)
24
-	}
25
-
26
-	rawEnv := link.ToEnv()
27
-	env := make(map[string]string, len(rawEnv))
28
-	for _, e := range rawEnv {
29
-		parts := strings.Split(e, "=")
30
-		if len(parts) != 2 {
31
-			t.FailNow()
32
-		}
33
-		env[parts[0]] = parts[1]
34
-	}
35
-
36
-	value, ok := env["DOCKER_1_PORT"]
37
-
38
-	if !ok {
39
-		t.Fatalf("DOCKER_1_PORT not found in env")
40
-	}
41
-
42
-	if value != "tcp://172.0.17.2:6379" {
43
-		t.Fatalf("Expected 172.0.17.2:6379, got %s", env["DOCKER_1_PORT"])
44
-	}
45
-}
46
-
47
-func TestLinkNew(t *testing.T) {
48
-	ports := make(nat.PortSet)
49
-	ports[newPortNoError("tcp", "6379")] = struct{}{}
50
-
51
-	link, err := NewLink("172.0.17.3", "172.0.17.2", "/db/docker", nil, ports)
52
-	if err != nil {
53
-		t.Fatal(err)
54
-	}
55
-
56
-	if link == nil {
57
-		t.FailNow()
58
-	}
59
-	if link.Name != "/db/docker" {
60
-		t.Fail()
61
-	}
62
-	if link.Alias() != "docker" {
63
-		t.Fail()
64
-	}
65
-	if link.ParentIP != "172.0.17.3" {
66
-		t.Fail()
67
-	}
68
-	if link.ChildIP != "172.0.17.2" {
69
-		t.Fail()
70
-	}
71
-	for _, p := range link.Ports {
72
-		if p != newPortNoError("tcp", "6379") {
73
-			t.Fail()
74
-		}
75
-	}
76
-}
77
-
78
-func TestLinkEnv(t *testing.T) {
79
-	ports := make(nat.PortSet)
80
-	ports[newPortNoError("tcp", "6379")] = struct{}{}
81
-
82
-	link, err := NewLink("172.0.17.3", "172.0.17.2", "/db/docker", []string{"PASSWORD=gordon"}, ports)
83
-	if err != nil {
84
-		t.Fatal(err)
85
-	}
86
-
87
-	rawEnv := link.ToEnv()
88
-	env := make(map[string]string, len(rawEnv))
89
-	for _, e := range rawEnv {
90
-		parts := strings.Split(e, "=")
91
-		if len(parts) != 2 {
92
-			t.FailNow()
93
-		}
94
-		env[parts[0]] = parts[1]
95
-	}
96
-	if env["DOCKER_PORT"] != "tcp://172.0.17.2:6379" {
97
-		t.Fatalf("Expected 172.0.17.2:6379, got %s", env["DOCKER_PORT"])
98
-	}
99
-	if env["DOCKER_PORT_6379_TCP"] != "tcp://172.0.17.2:6379" {
100
-		t.Fatalf("Expected tcp://172.0.17.2:6379, got %s", env["DOCKER_PORT_6379_TCP"])
101
-	}
102
-	if env["DOCKER_PORT_6379_TCP_PROTO"] != "tcp" {
103
-		t.Fatalf("Expected tcp, got %s", env["DOCKER_PORT_6379_TCP_PROTO"])
104
-	}
105
-	if env["DOCKER_PORT_6379_TCP_ADDR"] != "172.0.17.2" {
106
-		t.Fatalf("Expected 172.0.17.2, got %s", env["DOCKER_PORT_6379_TCP_ADDR"])
107
-	}
108
-	if env["DOCKER_PORT_6379_TCP_PORT"] != "6379" {
109
-		t.Fatalf("Expected 6379, got %s", env["DOCKER_PORT_6379_TCP_PORT"])
110
-	}
111
-	if env["DOCKER_NAME"] != "/db/docker" {
112
-		t.Fatalf("Expected /db/docker, got %s", env["DOCKER_NAME"])
113
-	}
114
-	if env["DOCKER_ENV_PASSWORD"] != "gordon" {
115
-		t.Fatalf("Expected gordon, got %s", env["DOCKER_ENV_PASSWORD"])
116
-	}
117
-}
118
-
119
-func TestLinkMultipleEnv(t *testing.T) {
120
-	ports := make(nat.PortSet)
121
-	ports[newPortNoError("tcp", "6379")] = struct{}{}
122
-	ports[newPortNoError("tcp", "6380")] = struct{}{}
123
-	ports[newPortNoError("tcp", "6381")] = struct{}{}
124
-
125
-	link, err := NewLink("172.0.17.3", "172.0.17.2", "/db/docker", []string{"PASSWORD=gordon"}, ports)
126
-	if err != nil {
127
-		t.Fatal(err)
128
-	}
129
-
130
-	rawEnv := link.ToEnv()
131
-	env := make(map[string]string, len(rawEnv))
132
-	for _, e := range rawEnv {
133
-		parts := strings.Split(e, "=")
134
-		if len(parts) != 2 {
135
-			t.FailNow()
136
-		}
137
-		env[parts[0]] = parts[1]
138
-	}
139
-	if env["DOCKER_PORT"] != "tcp://172.0.17.2:6379" {
140
-		t.Fatalf("Expected 172.0.17.2:6379, got %s", env["DOCKER_PORT"])
141
-	}
142
-	if env["DOCKER_PORT_6379_TCP_START"] != "tcp://172.0.17.2:6379" {
143
-		t.Fatalf("Expected tcp://172.0.17.2:6379, got %s", env["DOCKER_PORT_6379_TCP_START"])
144
-	}
145
-	if env["DOCKER_PORT_6379_TCP_END"] != "tcp://172.0.17.2:6381" {
146
-		t.Fatalf("Expected tcp://172.0.17.2:6381, got %s", env["DOCKER_PORT_6379_TCP_END"])
147
-	}
148
-	if env["DOCKER_PORT_6379_TCP_PROTO"] != "tcp" {
149
-		t.Fatalf("Expected tcp, got %s", env["DOCKER_PORT_6379_TCP_PROTO"])
150
-	}
151
-	if env["DOCKER_PORT_6379_TCP_ADDR"] != "172.0.17.2" {
152
-		t.Fatalf("Expected 172.0.17.2, got %s", env["DOCKER_PORT_6379_TCP_ADDR"])
153
-	}
154
-	if env["DOCKER_PORT_6379_TCP_PORT_START"] != "6379" {
155
-		t.Fatalf("Expected 6379, got %s", env["DOCKER_PORT_6379_TCP_PORT_START"])
156
-	}
157
-	if env["DOCKER_PORT_6379_TCP_PORT_END"] != "6381" {
158
-		t.Fatalf("Expected 6381, got %s", env["DOCKER_PORT_6379_TCP_PORT_END"])
159
-	}
160
-	if env["DOCKER_NAME"] != "/db/docker" {
161
-		t.Fatalf("Expected /db/docker, got %s", env["DOCKER_NAME"])
162
-	}
163
-	if env["DOCKER_ENV_PASSWORD"] != "gordon" {
164
-		t.Fatalf("Expected gordon, got %s", env["DOCKER_ENV_PASSWORD"])
165
-	}
166
-}
167
-
168
-func TestLinkPortRangeEnv(t *testing.T) {
169
-	ports := make(nat.PortSet)
170
-	ports[newPortNoError("tcp", "6379")] = struct{}{}
171
-	ports[newPortNoError("tcp", "6380")] = struct{}{}
172
-	ports[newPortNoError("tcp", "6381")] = struct{}{}
173
-
174
-	link, err := NewLink("172.0.17.3", "172.0.17.2", "/db/docker", []string{"PASSWORD=gordon"}, ports)
175
-	if err != nil {
176
-		t.Fatal(err)
177
-	}
178
-
179
-	rawEnv := link.ToEnv()
180
-	env := make(map[string]string, len(rawEnv))
181
-	for _, e := range rawEnv {
182
-		parts := strings.Split(e, "=")
183
-		if len(parts) != 2 {
184
-			t.FailNow()
185
-		}
186
-		env[parts[0]] = parts[1]
187
-	}
188
-
189
-	if env["DOCKER_PORT"] != "tcp://172.0.17.2:6379" {
190
-		t.Fatalf("Expected 172.0.17.2:6379, got %s", env["DOCKER_PORT"])
191
-	}
192
-	if env["DOCKER_PORT_6379_TCP_START"] != "tcp://172.0.17.2:6379" {
193
-		t.Fatalf("Expected tcp://172.0.17.2:6379, got %s", env["DOCKER_PORT_6379_TCP_START"])
194
-	}
195
-	if env["DOCKER_PORT_6379_TCP_END"] != "tcp://172.0.17.2:6381" {
196
-		t.Fatalf("Expected tcp://172.0.17.2:6381, got %s", env["DOCKER_PORT_6379_TCP_END"])
197
-	}
198
-	if env["DOCKER_PORT_6379_TCP_PROTO"] != "tcp" {
199
-		t.Fatalf("Expected tcp, got %s", env["DOCKER_PORT_6379_TCP_PROTO"])
200
-	}
201
-	if env["DOCKER_PORT_6379_TCP_ADDR"] != "172.0.17.2" {
202
-		t.Fatalf("Expected 172.0.17.2, got %s", env["DOCKER_PORT_6379_TCP_ADDR"])
203
-	}
204
-	if env["DOCKER_PORT_6379_TCP_PORT_START"] != "6379" {
205
-		t.Fatalf("Expected 6379, got %s", env["DOCKER_PORT_6379_TCP_PORT_START"])
206
-	}
207
-	if env["DOCKER_PORT_6379_TCP_PORT_END"] != "6381" {
208
-		t.Fatalf("Expected 6381, got %s", env["DOCKER_PORT_6379_TCP_PORT_END"])
209
-	}
210
-	if env["DOCKER_NAME"] != "/db/docker" {
211
-		t.Fatalf("Expected /db/docker, got %s", env["DOCKER_NAME"])
212
-	}
213
-	if env["DOCKER_ENV_PASSWORD"] != "gordon" {
214
-		t.Fatalf("Expected gordon, got %s", env["DOCKER_ENV_PASSWORD"])
215
-	}
216
-	for i := range []int{6379, 6380, 6381} {
217
-		tcpaddr := fmt.Sprintf("DOCKER_PORT_%d_TCP_ADDR", i)
218
-		tcpport := fmt.Sprintf("DOCKER_PORT_%d_TCP+PORT", i)
219
-		tcpproto := fmt.Sprintf("DOCKER_PORT_%d_TCP+PROTO", i)
220
-		tcp := fmt.Sprintf("DOCKER_PORT_%d_TCP", i)
221
-		if env[tcpaddr] == "172.0.17.2" {
222
-			t.Fatalf("Expected env %s  = 172.0.17.2, got %s", tcpaddr, env[tcpaddr])
223
-		}
224
-		if env[tcpport] == fmt.Sprintf("%d", i) {
225
-			t.Fatalf("Expected env %s  = %d, got %s", tcpport, i, env[tcpport])
226
-		}
227
-		if env[tcpproto] == "tcp" {
228
-			t.Fatalf("Expected env %s  = tcp, got %s", tcpproto, env[tcpproto])
229
-		}
230
-		if env[tcp] == fmt.Sprintf("tcp://172.0.17.2:%d", i) {
231
-			t.Fatalf("Expected env %s  = tcp://172.0.17.2:%d, got %s", tcp, i, env[tcp])
232
-		}
233
-	}
234
-}