Browse code

Support to provide external key to sandbox

Signed-off-by: Madhu Venugopal <madhu@docker.com>

Madhu Venugopal authored on 2015/09/10 08:20:54
Showing 9 changed files
... ...
@@ -245,6 +245,9 @@ func (sc *sandboxCreate) parseOptions() []libnetwork.SandboxOption {
245 245
 	if sc.UseDefaultSandbox {
246 246
 		setFctList = append(setFctList, libnetwork.OptionUseDefaultSandbox())
247 247
 	}
248
+	if sc.UseExternalKey {
249
+		setFctList = append(setFctList, libnetwork.OptionUseExternalKey())
250
+	}
248 251
 	if sc.DNS != nil {
249 252
 		for _, d := range sc.DNS {
250 253
 			setFctList = append(setFctList, libnetwork.OptionDNS(d))
... ...
@@ -57,6 +57,7 @@ type sandboxCreate struct {
57 57
 	DNS               []string    `json:"dns"`
58 58
 	ExtraHosts        []extraHost `json:"extra_hosts"`
59 59
 	UseDefaultSandbox bool        `json:"use_default_sandbox"`
60
+	UseExternalKey    bool        `json:"use_external_key"`
60 61
 }
61 62
 
62 63
 // endpointJoin represents the expected body of the "join endpoint" or "leave endpoint" http request messages
... ...
@@ -414,7 +414,7 @@ func (c *controller) NewSandbox(containerID string, options ...SandboxOption) (S
414 414
 		return nil, err
415 415
 	}
416 416
 
417
-	if sb.osSbox == nil {
417
+	if sb.osSbox == nil && !sb.config.useExternalKey {
418 418
 		if sb.osSbox, err = osl.NewSandbox(sb.Key(), !sb.config.useDefaultSandBox); err != nil {
419 419
 			return nil, fmt.Errorf("failed to create new osl sandbox: %v", err)
420 420
 		}
... ...
@@ -1,6 +1,7 @@
1 1
 package libnetwork
2 2
 
3 3
 import (
4
+	"container/heap"
4 5
 	"encoding/json"
5 6
 	"fmt"
6 7
 	"net"
... ...
@@ -289,10 +290,25 @@ func (ep *endpoint) Join(sbox Sandbox, options ...EndpointOption) error {
289 289
 		return err
290 290
 	}
291 291
 
292
+	sb.Lock()
293
+	heap.Push(&sb.endpoints, ep)
294
+	sb.Unlock()
295
+	defer func() {
296
+		if err != nil {
297
+			for i, e := range sb.getConnectedEndpoints() {
298
+				if e == ep {
299
+					sb.Lock()
300
+					heap.Remove(&sb.endpoints, i)
301
+					sb.Unlock()
302
+					return
303
+				}
304
+			}
305
+		}
306
+	}()
307
+
292 308
 	if err = sb.populateNetworkResources(ep); err != nil {
293 309
 		return err
294 310
 	}
295
-
296 311
 	return nil
297 312
 }
298 313
 
... ...
@@ -1188,6 +1188,117 @@ func (f *fakeSandbox) Delete() error {
1188 1188
 	return nil
1189 1189
 }
1190 1190
 
1191
+func (f *fakeSandbox) SetKey(key string) error {
1192
+	return nil
1193
+}
1194
+
1195
+func TestExternalKey(t *testing.T) {
1196
+	if !netutils.IsRunningInContainer() {
1197
+		defer osl.SetupTestOSContext(t)()
1198
+	}
1199
+
1200
+	n, err := createTestNetwork(bridgeNetType, "testnetwork", options.Generic{
1201
+		netlabel.GenericData: options.Generic{
1202
+			"BridgeName":            "testnetwork",
1203
+			"AllowNonDefaultBridge": true,
1204
+		},
1205
+	})
1206
+	if err != nil {
1207
+		t.Fatal(err)
1208
+	}
1209
+	defer func() {
1210
+		if err := n.Delete(); err != nil {
1211
+			t.Fatal(err)
1212
+		}
1213
+	}()
1214
+
1215
+	ep, err := n.CreateEndpoint("ep1")
1216
+	if err != nil {
1217
+		t.Fatal(err)
1218
+	}
1219
+	defer func() {
1220
+		err = ep.Delete()
1221
+		if err != nil {
1222
+			t.Fatal(err)
1223
+		}
1224
+	}()
1225
+
1226
+	ep2, err := n.CreateEndpoint("ep2")
1227
+	if err != nil {
1228
+		t.Fatal(err)
1229
+	}
1230
+	defer func() {
1231
+		err = ep2.Delete()
1232
+		if err != nil {
1233
+			t.Fatal(err)
1234
+		}
1235
+	}()
1236
+
1237
+	cnt, err := controller.NewSandbox(containerID,
1238
+		libnetwork.OptionHostname("test"),
1239
+		libnetwork.OptionDomainname("docker.io"),
1240
+		libnetwork.OptionUseExternalKey(),
1241
+		libnetwork.OptionExtraHost("web", "192.168.0.1"))
1242
+	defer func() {
1243
+		if err := cnt.Delete(); err != nil {
1244
+			t.Fatal(err)
1245
+		}
1246
+	}()
1247
+
1248
+	// Join endpoint to sandbox before SetKey
1249
+	err = ep.Join(cnt)
1250
+	runtime.LockOSThread()
1251
+	if err != nil {
1252
+		t.Fatal(err)
1253
+	}
1254
+	defer func() {
1255
+		err = ep.Leave(cnt)
1256
+		runtime.LockOSThread()
1257
+		if err != nil {
1258
+			t.Fatal(err)
1259
+		}
1260
+	}()
1261
+
1262
+	sbox := ep.Info().Sandbox()
1263
+	if sbox == nil {
1264
+		t.Fatalf("Expected to have a valid Sandbox")
1265
+	}
1266
+
1267
+	// Setting an non-existing key (namespace) must fail
1268
+	if err := sbox.SetKey("this-must-fail"); err == nil {
1269
+		t.Fatalf("Setkey must fail if the corresponding namespace is not created")
1270
+	}
1271
+
1272
+	// Create a new OS sandbox using the osl API before using it in SetKey
1273
+	if _, err := osl.NewSandbox("ValidKey", true); err != nil {
1274
+		t.Fatalf("Failed to create new osl sandbox")
1275
+	}
1276
+
1277
+	if err := sbox.SetKey("ValidKey"); err != nil {
1278
+		t.Fatalf("Setkey failed with %v", err)
1279
+	}
1280
+
1281
+	// Join endpoint to sandbox after SetKey
1282
+	err = ep2.Join(sbox)
1283
+	if err != nil {
1284
+		t.Fatal(err)
1285
+	}
1286
+	runtime.LockOSThread()
1287
+	defer func() {
1288
+		err = ep2.Leave(sbox)
1289
+		runtime.LockOSThread()
1290
+		if err != nil {
1291
+			t.Fatal(err)
1292
+		}
1293
+	}()
1294
+
1295
+	if ep.Info().Sandbox().Key() != ep2.Info().Sandbox().Key() {
1296
+		t.Fatalf("ep1 and ep2 returned different container sandbox key")
1297
+	}
1298
+
1299
+	checkSandbox(t, ep.Info())
1300
+}
1301
+
1191 1302
 func TestEndpointDeleteWithActiveContainer(t *testing.T) {
1192 1303
 	if !netutils.IsRunningInContainer() {
1193 1304
 		defer osl.SetupTestOSContext(t)()
... ...
@@ -157,16 +157,38 @@ func (n *networkNamespace) NeighborOptions() NeighborOptionSetter {
157 157
 	return n
158 158
 }
159 159
 
160
-func reexecCreateNamespace() {
161
-	if len(os.Args) < 2 {
162
-		log.Fatal("no namespace path provided")
160
+func mountNetworkNamespace(basePath string, lnPath string) error {
161
+	if err := syscall.Mount(basePath, lnPath, "bind", syscall.MS_BIND, ""); err != nil {
162
+		return err
163 163
 	}
164 164
 
165
-	if err := syscall.Mount("/proc/self/ns/net", os.Args[1], "bind", syscall.MS_BIND, ""); err != nil {
166
-		log.Fatal(err)
165
+	if err := loopbackUp(); err != nil {
166
+		return err
167 167
 	}
168
+	return nil
169
+}
168 170
 
169
-	if err := loopbackUp(); err != nil {
171
+// GetSandboxForExternalKey returns sandbox object for the supplied path
172
+func GetSandboxForExternalKey(basePath string, key string) (Sandbox, error) {
173
+	var err error
174
+	if err = createNamespaceFile(key); err != nil {
175
+		return nil, err
176
+	}
177
+	n := &networkNamespace{path: basePath}
178
+	n.InvokeFunc(func() {
179
+		err = mountNetworkNamespace(basePath, key)
180
+	})
181
+	if err != nil {
182
+		return nil, err
183
+	}
184
+	return &networkNamespace{path: key}, nil
185
+}
186
+
187
+func reexecCreateNamespace() {
188
+	if len(os.Args) < 2 {
189
+		log.Fatal("no namespace path provided")
190
+	}
191
+	if err := mountNetworkNamespace("/proc/self/ns/net", os.Args[1]); err != nil {
170 192
 		log.Fatal(err)
171 193
 	}
172 194
 }
... ...
@@ -6,3 +6,7 @@ package osl
6 6
 // and waits for it.
7 7
 func GC() {
8 8
 }
9
+
10
+func GetSandboxForExternalKey(path string, key string) (Sandbox, error) {
11
+	return nil, nil
12
+}
... ...
@@ -19,6 +19,10 @@ func NewSandbox(key string, osCreate bool) (Sandbox, error) {
19 19
 	return nil, nil
20 20
 }
21 21
 
22
+func GetSandboxForExternalKey(path string, key string) (Sandbox, error) {
23
+	return nil, nil
24
+}
25
+
22 26
 // GC triggers garbage collection of namespace path right away
23 27
 // and waits for it.
24 28
 func GC() {
... ...
@@ -32,6 +32,8 @@ type Sandbox interface {
32 32
 	// Refresh leaves all the endpoints, resets and re-apply the options,
33 33
 	// re-joins all the endpoints without destroying the osl sandbox
34 34
 	Refresh(options ...SandboxOption) error
35
+	// SetKey updates the Sandbox Key
36
+	SetKey(key string) error
35 37
 	// Delete destroys this container after detaching it from all connected endpoints.
36 38
 	Delete() error
37 39
 }
... ...
@@ -102,6 +104,7 @@ type containerConfig struct {
102 102
 	resolvConfPathConfig
103 103
 	generic           map[string]interface{}
104 104
 	useDefaultSandBox bool
105
+	useExternalKey    bool
105 106
 	prio              int // higher the value, more the priority
106 107
 }
107 108
 
... ...
@@ -241,8 +244,14 @@ func (sb *sandbox) getConnectedEndpoints() []*endpoint {
241 241
 }
242 242
 
243 243
 func (sb *sandbox) updateGateway(ep *endpoint) error {
244
-	sb.osSbox.UnsetGateway()
245
-	sb.osSbox.UnsetGatewayIPv6()
244
+	sb.Lock()
245
+	osSbox := sb.osSbox
246
+	sb.Unlock()
247
+	if osSbox == nil {
248
+		return nil
249
+	}
250
+	osSbox.UnsetGateway()
251
+	osSbox.UnsetGatewayIPv6()
246 252
 
247 253
 	if ep == nil {
248 254
 		return nil
... ...
@@ -252,18 +261,60 @@ func (sb *sandbox) updateGateway(ep *endpoint) error {
252 252
 	joinInfo := ep.joinInfo
253 253
 	ep.Unlock()
254 254
 
255
-	if err := sb.osSbox.SetGateway(joinInfo.gw); err != nil {
255
+	if err := osSbox.SetGateway(joinInfo.gw); err != nil {
256 256
 		return fmt.Errorf("failed to set gateway while updating gateway: %v", err)
257 257
 	}
258 258
 
259
-	if err := sb.osSbox.SetGatewayIPv6(joinInfo.gw6); err != nil {
259
+	if err := osSbox.SetGatewayIPv6(joinInfo.gw6); err != nil {
260 260
 		return fmt.Errorf("failed to set IPv6 gateway while updating gateway: %v", err)
261 261
 	}
262 262
 
263 263
 	return nil
264 264
 }
265 265
 
266
+func (sb *sandbox) SetKey(basePath string) error {
267
+	var err error
268
+	if basePath == "" {
269
+		return types.BadRequestErrorf("invalid sandbox key")
270
+	}
271
+
272
+	sb.Lock()
273
+	if sb.osSbox != nil {
274
+		sb.Unlock()
275
+		return types.ForbiddenErrorf("failed to set sandbox key : already assigned")
276
+	}
277
+	sb.Unlock()
278
+	osSbox, err := osl.GetSandboxForExternalKey(basePath, sb.Key())
279
+	if err != nil {
280
+		return err
281
+	}
282
+	sb.Lock()
283
+	sb.osSbox = osSbox
284
+	sb.Unlock()
285
+	defer func() {
286
+		if err != nil {
287
+			sb.Lock()
288
+			sb.osSbox = nil
289
+			sb.Unlock()
290
+		}
291
+	}()
292
+
293
+	for _, ep := range sb.getConnectedEndpoints() {
294
+		if err = sb.populateNetworkResources(ep); err != nil {
295
+			return err
296
+		}
297
+	}
298
+	return nil
299
+}
300
+
266 301
 func (sb *sandbox) populateNetworkResources(ep *endpoint) error {
302
+	sb.Lock()
303
+	if sb.osSbox == nil {
304
+		sb.Unlock()
305
+		return nil
306
+	}
307
+	sb.Unlock()
308
+
267 309
 	ep.Lock()
268 310
 	joinInfo := ep.joinInfo
269 311
 	ifaces := ep.iFaces
... ...
@@ -292,7 +343,6 @@ func (sb *sandbox) populateNetworkResources(ep *endpoint) error {
292 292
 	}
293 293
 
294 294
 	sb.Lock()
295
-	heap.Push(&sb.endpoints, ep)
296 295
 	highEp := sb.endpoints[0]
297 296
 	sb.Unlock()
298 297
 	if ep == highEp {
... ...
@@ -305,24 +355,28 @@ func (sb *sandbox) populateNetworkResources(ep *endpoint) error {
305 305
 }
306 306
 
307 307
 func (sb *sandbox) clearNetworkResources(ep *endpoint) error {
308
-
309
-	for _, i := range sb.osSbox.Info().Interfaces() {
310
-		// Only remove the interfaces owned by this endpoint from the sandbox.
311
-		if ep.hasInterface(i.SrcName()) {
312
-			if err := i.Remove(); err != nil {
313
-				log.Debugf("Remove interface failed: %v", err)
308
+	sb.Lock()
309
+	osSbox := sb.osSbox
310
+	sb.Unlock()
311
+	if osSbox != nil {
312
+		for _, i := range osSbox.Info().Interfaces() {
313
+			// Only remove the interfaces owned by this endpoint from the sandbox.
314
+			if ep.hasInterface(i.SrcName()) {
315
+				if err := i.Remove(); err != nil {
316
+					log.Debugf("Remove interface failed: %v", err)
317
+				}
314 318
 			}
315 319
 		}
316
-	}
317 320
 
318
-	ep.Lock()
319
-	joinInfo := ep.joinInfo
320
-	ep.Unlock()
321
+		ep.Lock()
322
+		joinInfo := ep.joinInfo
323
+		ep.Unlock()
321 324
 
322
-	// Remove non-interface routes.
323
-	for _, r := range joinInfo.StaticRoutes {
324
-		if err := sb.osSbox.RemoveStaticRoute(r); err != nil {
325
-			log.Debugf("Remove route failed: %v", err)
325
+		// Remove non-interface routes.
326
+		for _, r := range joinInfo.StaticRoutes {
327
+			if err := osSbox.RemoveStaticRoute(r); err != nil {
328
+				log.Debugf("Remove route failed: %v", err)
329
+			}
326 330
 		}
327 331
 	}
328 332
 
... ...
@@ -670,6 +724,14 @@ func OptionUseDefaultSandbox() SandboxOption {
670 670
 	}
671 671
 }
672 672
 
673
+// OptionUseExternalKey function returns an option setter for using provided namespace
674
+// instead of creating one.
675
+func OptionUseExternalKey() SandboxOption {
676
+	return func(sb *sandbox) {
677
+		sb.config.useExternalKey = true
678
+	}
679
+}
680
+
673 681
 // OptionGeneric function returns an option setter for Generic configuration
674 682
 // that is not managed by libNetwork but can be used by the Drivers during the call to
675 683
 // net container creation method. Container Labels are a good example.