Signed-off-by: Madhu Venugopal <madhu@docker.com>
| ... | ... |
@@ -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 |
} |
| ... | ... |
@@ -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. |