func TestEndpointDeleteWithActiveContainer(t *testing.T) { if !testutils.IsRunningInContainer() { defer testutils.SetupTestOSContext(t)() } n, err := createTestNetwork(bridgeNetType, "testnetwork", options.Generic{ netlabel.GenericData: options.Generic{ "BridgeName": "testnetwork", }, }, nil, nil) if err != nil { t.Fatal(err) } defer func() { if err := n.Delete(); err != nil { t.Fatal(err) } }() ep, err := n.CreateEndpoint("ep1") if err != nil { t.Fatal(err) } defer func() { err = ep.Delete(false) if err != nil { t.Fatal(err) } }() cnt, err := controller.NewSandbox(containerID, libnetwork.OptionHostname("test"), libnetwork.OptionDomainname("docker.io"), libnetwork.OptionExtraHost("web", "192.168.0.1")) defer func() { if err := cnt.Delete(); err != nil { t.Fatal(err) } }() err = ep.Join(cnt) if err != nil { t.Fatal(err) } defer func() { err = ep.Leave(cnt) if err != nil { t.Fatal(err) } }() err = ep.Delete(false) if err == nil { t.Fatal("Expected to fail. But instead succeeded") } if _, ok := err.(*libnetwork.ActiveContainerError); !ok { t.Fatalf("Did not fail with expected error. Actual error: %v", err) } }
func (sc *sandboxCreate) parseOptions() []libnetwork.SandboxOption { var setFctList []libnetwork.SandboxOption if sc.HostName != "" { setFctList = append(setFctList, libnetwork.OptionHostname(sc.HostName)) } if sc.DomainName != "" { setFctList = append(setFctList, libnetwork.OptionDomainname(sc.DomainName)) } if sc.HostsPath != "" { setFctList = append(setFctList, libnetwork.OptionHostsPath(sc.HostsPath)) } if sc.ResolvConfPath != "" { setFctList = append(setFctList, libnetwork.OptionResolvConfPath(sc.ResolvConfPath)) } if sc.UseDefaultSandbox { setFctList = append(setFctList, libnetwork.OptionUseDefaultSandbox()) } if sc.DNS != nil { for _, d := range sc.DNS { setFctList = append(setFctList, libnetwork.OptionDNS(d)) } } if sc.ExtraHosts != nil { for _, e := range sc.ExtraHosts { setFctList = append(setFctList, libnetwork.OptionExtraHost(e.Name, e.Address)) } } return setFctList }
func main() { // Create a new controller instance controller, err := libnetwork.New() if err != nil { return } // Select and configure the network driver networkType := "bridge" driverOptions := options.Generic{} genericOption := make(map[string]interface{}) genericOption[netlabel.GenericData] = driverOptions err = controller.ConfigureNetworkDriver(networkType, genericOption) if err != nil { return } // Create a network for containers to join. // NewNetwork accepts Variadic optional arguments that libnetwork and Drivers can use. network, err := controller.NewNetwork(networkType, "network1") if err != nil { return } // For each new container: allocate IP and interfaces. The returned network // settings will be used for container infos (inspect and such), as well as // iptables rules for port publishing. This info is contained or accessible // from the returned endpoint. ep, err := network.CreateEndpoint("Endpoint1") if err != nil { return } // Create the sandbox for the containr. sbx, err := controller.NewSandbox("container1", libnetwork.OptionHostname("test"), libnetwork.OptionDomainname("docker.io")) // A sandbox can join the endpoint via the join api. // Join accepts Variadic arguments which libnetwork and Drivers can use. err = ep.Join(sbx) if err != nil { return } // libnetwork client can check the endpoint's operational data via the Info() API epInfo, err := ep.DriverInfo() mapData, ok := epInfo[netlabel.PortMap] if ok { portMapping, ok := mapData.([]types.PortBinding) if ok { fmt.Printf("Current port mapping for endpoint %s: %v", ep.Name(), portMapping) } } }
func TestNull(t *testing.T) { cnt, err := controller.NewSandbox("null_container", libnetwork.OptionHostname("test"), libnetwork.OptionDomainname("docker.io"), libnetwork.OptionExtraHost("web", "192.168.0.1")) if err != nil { t.Fatal(err) } network, err := createTestNetwork("null", "testnull", options.Generic{}) if err != nil { t.Fatal(err) } ep, err := network.CreateEndpoint("testep") if err != nil { t.Fatal(err) } err = ep.Join(cnt) if err != nil { t.Fatal(err) } err = ep.Leave(cnt) if err != nil { t.Fatal(err) } if err := ep.Delete(); err != nil { t.Fatal(err) } if err := cnt.Delete(); err != nil { t.Fatal(err) } // host type is special network. Cannot be removed. err = network.Delete() if err == nil { t.Fatal(err) } if _, ok := err.(types.ForbiddenError); !ok { t.Fatalf("Unexpected error type") } }
func (daemon *Daemon) buildSandboxOptions(container *Container, n libnetwork.Network) ([]libnetwork.SandboxOption, error) { var ( sboxOptions []libnetwork.SandboxOption err error dns []string dnsSearch []string dnsOptions []string ) sboxOptions = append(sboxOptions, libnetwork.OptionHostname(container.Config.Hostname), libnetwork.OptionDomainname(container.Config.Domainname)) if container.hostConfig.NetworkMode.IsHost() { sboxOptions = append(sboxOptions, libnetwork.OptionUseDefaultSandbox()) sboxOptions = append(sboxOptions, libnetwork.OptionOriginHostsPath("/etc/hosts")) sboxOptions = append(sboxOptions, libnetwork.OptionOriginResolvConfPath("/etc/resolv.conf")) } else if daemon.execDriver.SupportsHooks() { // OptionUseExternalKey is mandatory for userns support. // But optional for non-userns support sboxOptions = append(sboxOptions, libnetwork.OptionUseExternalKey()) } container.HostsPath, err = container.getRootResourcePath("hosts") if err != nil { return nil, err } sboxOptions = append(sboxOptions, libnetwork.OptionHostsPath(container.HostsPath)) container.ResolvConfPath, err = container.getRootResourcePath("resolv.conf") if err != nil { return nil, err } sboxOptions = append(sboxOptions, libnetwork.OptionResolvConfPath(container.ResolvConfPath)) if len(container.hostConfig.DNS) > 0 { dns = container.hostConfig.DNS } else if len(daemon.configStore.DNS) > 0 { dns = daemon.configStore.DNS } for _, d := range dns { sboxOptions = append(sboxOptions, libnetwork.OptionDNS(d)) } if len(container.hostConfig.DNSSearch) > 0 { dnsSearch = container.hostConfig.DNSSearch } else if len(daemon.configStore.DNSSearch) > 0 { dnsSearch = daemon.configStore.DNSSearch } for _, ds := range dnsSearch { sboxOptions = append(sboxOptions, libnetwork.OptionDNSSearch(ds)) } if len(container.hostConfig.DNSOptions) > 0 { dnsOptions = container.hostConfig.DNSOptions } else if len(daemon.configStore.DNSOptions) > 0 { dnsOptions = daemon.configStore.DNSOptions } for _, ds := range dnsOptions { sboxOptions = append(sboxOptions, libnetwork.OptionDNSOptions(ds)) } if container.NetworkSettings.SecondaryIPAddresses != nil { name := container.Config.Hostname if container.Config.Domainname != "" { name = name + "." + container.Config.Domainname } for _, a := range container.NetworkSettings.SecondaryIPAddresses { sboxOptions = append(sboxOptions, libnetwork.OptionExtraHost(name, a.Addr)) } } for _, extraHost := range container.hostConfig.ExtraHosts { // allow IPv6 addresses in extra hosts; only split on first ":" parts := strings.SplitN(extraHost, ":", 2) sboxOptions = append(sboxOptions, libnetwork.OptionExtraHost(parts[0], parts[1])) } // Link feature is supported only for the default bridge network. // return if this call to build join options is not for default bridge network if n.Name() != "bridge" { return sboxOptions, nil } ep, _ := container.getEndpointInNetwork(n) if ep == nil { return sboxOptions, nil } var childEndpoints, parentEndpoints []string children, err := daemon.children(container.Name) if err != nil { return nil, err } for linkAlias, child := range children { if !isLinkable(child) { return nil, fmt.Errorf("Cannot link to %s, as it does not belong to the default network", child.Name) } _, alias := path.Split(linkAlias) // allow access to the linked container via the alias, real name, and container hostname aliasList := alias + " " + child.Config.Hostname // only add the name if alias isn't equal to the name if alias != child.Name[1:] { aliasList = aliasList + " " + child.Name[1:] } sboxOptions = append(sboxOptions, libnetwork.OptionExtraHost(aliasList, child.NetworkSettings.Networks["bridge"].IPAddress)) cEndpoint, _ := child.getEndpointInNetwork(n) if cEndpoint != nil && cEndpoint.ID() != "" { childEndpoints = append(childEndpoints, cEndpoint.ID()) } } bridgeSettings := container.NetworkSettings.Networks["bridge"] refs := daemon.containerGraph().RefPaths(container.ID) for _, ref := range refs { if ref.ParentID == "0" { continue } c, err := daemon.Get(ref.ParentID) if err != nil { logrus.Error(err) } if c != nil && !daemon.configStore.DisableBridge && container.hostConfig.NetworkMode.IsPrivate() { logrus.Debugf("Update /etc/hosts of %s for alias %s with ip %s", c.ID, ref.Name, bridgeSettings.IPAddress) sboxOptions = append(sboxOptions, libnetwork.OptionParentUpdate(c.ID, ref.Name, bridgeSettings.IPAddress)) if ep.ID() != "" { parentEndpoints = append(parentEndpoints, ep.ID()) } } } linkOptions := options.Generic{ netlabel.GenericData: options.Generic{ "ParentEndpoints": parentEndpoints, "ChildEndpoints": childEndpoints, }, } sboxOptions = append(sboxOptions, libnetwork.OptionGeneric(linkOptions)) return sboxOptions, nil }
func TestEndpointJoin(t *testing.T) { if !netutils.IsRunningInContainer() { defer netutils.SetupTestNetNS(t)() } // Create network 1 and add 2 endpoint: ep11, ep12 n1, err := createTestNetwork(bridgeNetType, "testnetwork1", options.Generic{ netlabel.GenericData: options.Generic{ "BridgeName": "testnetwork1", "AllowNonDefaultBridge": true, }, }) if err != nil { t.Fatal(err) } defer func() { if err := n1.Delete(); err != nil { t.Fatal(err) } }() ep1, err := n1.CreateEndpoint("ep1") if err != nil { t.Fatal(err) } defer func() { if err := ep1.Delete(); err != nil { t.Fatal(err) } }() // Validate if ep.Info() only gives me IP address info and not names and gateway during CreateEndpoint() info := ep1.Info() for _, iface := range info.InterfaceList() { if iface.Address().IP.To4() == nil { t.Fatalf("Invalid IP address returned: %v", iface.Address()) } } if info.Gateway().To4() != nil { t.Fatalf("Expected empty gateway for an empty endpoint. Instead found a gateway: %v", info.Gateway()) } if info.Sandbox() != nil { t.Fatalf("Expected an empty sandbox key for an empty endpoint. Instead found a non-empty sandbox key: %s", info.Sandbox().Key()) } // test invalid joins err = ep1.Join(nil) if err == nil { t.Fatalf("Expected to fail join with nil Sandbox") } if _, ok := err.(types.BadRequestError); !ok { t.Fatalf("Unexpected error type returned: %T", err) } fsbx := &fakeSandbox{} if err = ep1.Join(fsbx); err == nil { t.Fatalf("Expected to fail join with invalid Sandbox") } if _, ok := err.(types.BadRequestError); !ok { t.Fatalf("Unexpected error type returned: %T", err) } sb, err := controller.NewSandbox(containerID, libnetwork.OptionHostname("test"), libnetwork.OptionDomainname("docker.io"), libnetwork.OptionExtraHost("web", "192.168.0.1")) if err != nil { t.Fatal(err) } defer func() { if err := sb.Delete(); err != nil { t.Fatal(err) } }() err = ep1.Join(sb) runtime.LockOSThread() if err != nil { t.Fatal(err) } defer func() { err = ep1.Leave(sb) runtime.LockOSThread() if err != nil { t.Fatal(err) } }() // Validate if ep.Info() only gives valid gateway and sandbox key after has container has joined. info = ep1.Info() if info.Gateway().To4() == nil { t.Fatalf("Expected a valid gateway for a joined endpoint. Instead found an invalid gateway: %v", info.Gateway()) } if info.Sandbox() == nil { t.Fatalf("Expected an non-empty sandbox key for a joined endpoint. Instead found a empty sandbox key") } // Check endpoint provided container information if ep1.Info().Sandbox().Key() != sb.Key() { t.Fatalf("Endpoint Info returned unexpected sandbox key: %s", sb.Key()) } // Attempt retrieval of endpoint interfaces statistics stats, err := sb.Statistics() if err != nil { t.Fatal(err) } if _, ok := stats["eth0"]; !ok { t.Fatalf("Did not find eth0 statistics") } // Now test the container joining another network n2, err := createTestNetwork(bridgeNetType, "testnetwork2", options.Generic{ netlabel.GenericData: options.Generic{ "BridgeName": "testnetwork2", "AllowNonDefaultBridge": true, }, }) if err != nil { t.Fatal(err) } defer func() { if err := n2.Delete(); err != nil { t.Fatal(err) } }() ep2, err := n2.CreateEndpoint("ep2") if err != nil { t.Fatal(err) } defer func() { if err := ep2.Delete(); err != nil { t.Fatal(err) } }() err = ep2.Join(sb) if err != nil { t.Fatal(err) } runtime.LockOSThread() defer func() { err = ep2.Leave(sb) runtime.LockOSThread() if err != nil { t.Fatal(err) } }() if ep1.Info().Sandbox().Key() != ep2.Info().Sandbox().Key() { t.Fatalf("ep1 and ep2 returned different container sandbox key") } checkSandbox(t, info) }
func TestHost(t *testing.T) { sbx1, err := controller.NewSandbox("host_c1", libnetwork.OptionHostname("test1"), libnetwork.OptionDomainname("docker.io"), libnetwork.OptionExtraHost("web", "192.168.0.1"), libnetwork.OptionUseDefaultSandbox()) if err != nil { t.Fatal(err) } defer func() { if err := sbx1.Delete(); err != nil { t.Fatal(err) } }() sbx2, err := controller.NewSandbox("host_c2", libnetwork.OptionHostname("test2"), libnetwork.OptionDomainname("docker.io"), libnetwork.OptionExtraHost("web", "192.168.0.1"), libnetwork.OptionUseDefaultSandbox()) if err != nil { t.Fatal(err) } defer func() { if err := sbx2.Delete(); err != nil { t.Fatal(err) } }() network, err := createTestNetwork("host", "testhost", options.Generic{}) if err != nil { t.Fatal(err) } ep1, err := network.CreateEndpoint("testep1") if err != nil { t.Fatal(err) } if err := ep1.Join(sbx1); err != nil { t.Fatal(err) } ep2, err := network.CreateEndpoint("testep2") if err != nil { t.Fatal(err) } if err := ep2.Join(sbx2); err != nil { t.Fatal(err) } if err := ep1.Leave(sbx1); err != nil { t.Fatal(err) } if err := ep2.Leave(sbx2); err != nil { t.Fatal(err) } if err := ep1.Delete(); err != nil { t.Fatal(err) } if err := ep2.Delete(); err != nil { t.Fatal(err) } // Try to create another host endpoint and join/leave that. cnt3, err := controller.NewSandbox("host_c3", libnetwork.OptionHostname("test3"), libnetwork.OptionDomainname("docker.io"), libnetwork.OptionExtraHost("web", "192.168.0.1"), libnetwork.OptionUseDefaultSandbox()) if err != nil { t.Fatal(err) } defer func() { if err := cnt3.Delete(); err != nil { t.Fatal(err) } }() ep3, err := network.CreateEndpoint("testep3") if err != nil { t.Fatal(err) } if err := ep3.Join(sbx2); err != nil { t.Fatal(err) } if err := ep3.Leave(sbx2); err != nil { t.Fatal(err) } if err := ep3.Delete(); err != nil { t.Fatal(err) } // host type is special network. Cannot be removed. err = network.Delete() if err == nil { t.Fatal(err) } if _, ok := err.(types.ForbiddenError); !ok { t.Fatalf("Unexpected error type") } }
func TestEndpointUpdateParent(t *testing.T) { if !netutils.IsRunningInContainer() { defer netutils.SetupTestNetNS(t)() } n, err := createTestNetwork("bridge", "testnetwork", options.Generic{ netlabel.GenericData: options.Generic{ "BridgeName": "testnetwork", "AllowNonDefaultBridge": true, }, }) if err != nil { t.Fatal(err) } defer func() { if err := n.Delete(); err != nil { t.Fatal(err) } }() ep1, err := n.CreateEndpoint("ep1") if err != nil { t.Fatal(err) } defer func() { if err := ep1.Delete(); err != nil { t.Fatal(err) } }() ep2, err := n.CreateEndpoint("ep2") if err != nil { t.Fatal(err) } defer func() { if err := ep2.Delete(); err != nil { t.Fatal(err) } }() sbx1, err := controller.NewSandbox(containerID, libnetwork.OptionHostname("test"), libnetwork.OptionDomainname("docker.io"), libnetwork.OptionExtraHost("web", "192.168.0.1")) if err != nil { t.Fatal(err) } defer func() { if err := sbx1.Delete(); err != nil { t.Fatal(err) } }() sbx2, err := controller.NewSandbox("c2", libnetwork.OptionHostname("test2"), libnetwork.OptionDomainname("docker.io"), libnetwork.OptionHostsPath("/var/lib/docker/test_network/container2/hosts"), libnetwork.OptionExtraHost("web", "192.168.0.2")) if err != nil { t.Fatal(err) } defer func() { if err := sbx2.Delete(); err != nil { t.Fatal(err) } }() err = ep1.Join(sbx1) runtime.LockOSThread() if err != nil { t.Fatal(err) } err = ep2.Join(sbx2) runtime.LockOSThread() if err != nil { t.Fatal(err) } err = ep2.Leave(sbx2) runtime.LockOSThread() if err != nil { t.Fatal(err) } }
func TestontainerInvalidLeave(t *testing.T) { if !netutils.IsRunningInContainer() { defer netutils.SetupTestNetNS(t)() } n, err := createTestNetwork(bridgeNetType, "testnetwork", options.Generic{ netlabel.GenericData: options.Generic{ "BridgeName": "testnetwork", "AllowNonDefaultBridge": true, }, }) if err != nil { t.Fatal(err) } defer func() { if err := n.Delete(); err != nil { t.Fatal(err) } }() ep, err := n.CreateEndpoint("ep1") if err != nil { t.Fatal(err) } defer func() { if err := ep.Delete(); err != nil { t.Fatal(err) } }() cnt, err := controller.NewSandbox(containerID, libnetwork.OptionHostname("test"), libnetwork.OptionDomainname("docker.io"), libnetwork.OptionExtraHost("web", "192.168.0.1")) if err != nil { t.Fatal(err) } defer func() { if err := cnt.Delete(); err != nil { t.Fatal(err) } }() err = ep.Leave(cnt) if err == nil { t.Fatal("Expected to fail leave from an endpoint which has no active join") } if _, ok := err.(types.ForbiddenError); !ok { t.Fatalf("Failed with unexpected error type: %T. Desc: %s", err, err.Error()) } if err := ep.Leave(nil); err == nil { t.Fatalf("Expected to fail leave nil Sandbox") } if _, ok := err.(types.BadRequestError); !ok { t.Fatalf("Unexpected error type returned: %T", err) } fsbx := &fakeSandbox{} if err = ep.Leave(fsbx); err == nil { t.Fatalf("Expected to fail leave with invalid Sandbox") } if _, ok := err.(types.BadRequestError); !ok { t.Fatalf("Unexpected error type returned: %T", err) } }
func TestEndpointMultipleJoins(t *testing.T) { if !netutils.IsRunningInContainer() { defer netutils.SetupTestNetNS(t)() } n, err := createTestNetwork(bridgeNetType, "testmultiple", options.Generic{ netlabel.GenericData: options.Generic{ "BridgeName": "testmultiple", "AllowNonDefaultBridge": true, }, }) if err != nil { t.Fatal(err) } defer func() { if err := n.Delete(); err != nil { t.Fatal(err) } }() ep, err := n.CreateEndpoint("ep1") if err != nil { t.Fatal(err) } defer func() { if err := ep.Delete(); err != nil { t.Fatal(err) } }() sbx1, err := controller.NewSandbox(containerID, libnetwork.OptionHostname("test"), libnetwork.OptionDomainname("docker.io"), libnetwork.OptionExtraHost("web", "192.168.0.1")) defer func() { if err := sbx1.Delete(); err != nil { t.Fatal(err) } }() sbx2, err := controller.NewSandbox("c2") defer func() { if err := sbx2.Delete(); err != nil { t.Fatal(err) } runtime.LockOSThread() }() err = ep.Join(sbx1) runtime.LockOSThread() if err != nil { t.Fatal(err) } defer func() { err = ep.Leave(sbx1) runtime.LockOSThread() if err != nil { t.Fatal(err) } }() err = ep.Join(sbx2) if err == nil { t.Fatal("Expected to fail multiple joins for the same endpoint") } if _, ok := err.(types.ForbiddenError); !ok { t.Fatalf("Failed with unexpected error type: %T. Desc: %s", err, err.Error()) } }
func (container *Container) buildSandboxOptions() ([]libnetwork.SandboxOption, error) { var ( sboxOptions []libnetwork.SandboxOption err error dns []string dnsSearch []string ) sboxOptions = append(sboxOptions, libnetwork.OptionHostname(container.Config.Hostname), libnetwork.OptionDomainname(container.Config.Domainname)) if container.hostConfig.NetworkMode.IsHost() { sboxOptions = append(sboxOptions, libnetwork.OptionUseDefaultSandbox()) sboxOptions = append(sboxOptions, libnetwork.OptionOriginHostsPath("/etc/hosts")) sboxOptions = append(sboxOptions, libnetwork.OptionOriginResolvConfPath("/etc/resolv.conf")) } container.HostsPath, err = container.getRootResourcePath("hosts") if err != nil { return nil, err } sboxOptions = append(sboxOptions, libnetwork.OptionHostsPath(container.HostsPath)) container.ResolvConfPath, err = container.getRootResourcePath("resolv.conf") if err != nil { return nil, err } sboxOptions = append(sboxOptions, libnetwork.OptionResolvConfPath(container.ResolvConfPath)) if len(container.hostConfig.DNS) > 0 { dns = container.hostConfig.DNS } else if len(container.daemon.configStore.DNS) > 0 { dns = container.daemon.configStore.DNS } for _, d := range dns { sboxOptions = append(sboxOptions, libnetwork.OptionDNS(d)) } if len(container.hostConfig.DNSSearch) > 0 { dnsSearch = container.hostConfig.DNSSearch } else if len(container.daemon.configStore.DNSSearch) > 0 { dnsSearch = container.daemon.configStore.DNSSearch } for _, ds := range dnsSearch { sboxOptions = append(sboxOptions, libnetwork.OptionDNSSearch(ds)) } if container.NetworkSettings.SecondaryIPAddresses != nil { name := container.Config.Hostname if container.Config.Domainname != "" { name = name + "." + container.Config.Domainname } for _, a := range container.NetworkSettings.SecondaryIPAddresses { sboxOptions = append(sboxOptions, libnetwork.OptionExtraHost(name, a.Addr)) } } var childEndpoints, parentEndpoints []string children, err := container.daemon.children(container.Name) if err != nil { return nil, err } for linkAlias, child := range children { _, alias := path.Split(linkAlias) // allow access to the linked container via the alias, real name, and container hostname aliasList := alias + " " + child.Config.Hostname // only add the name if alias isn't equal to the name if alias != child.Name[1:] { aliasList = aliasList + " " + child.Name[1:] } sboxOptions = append(sboxOptions, libnetwork.OptionExtraHost(aliasList, child.NetworkSettings.IPAddress)) if child.NetworkSettings.EndpointID != "" { childEndpoints = append(childEndpoints, child.NetworkSettings.EndpointID) } } for _, extraHost := range container.hostConfig.ExtraHosts { // allow IPv6 addresses in extra hosts; only split on first ":" parts := strings.SplitN(extraHost, ":", 2) sboxOptions = append(sboxOptions, libnetwork.OptionExtraHost(parts[0], parts[1])) } refs := container.daemon.containerGraph().RefPaths(container.ID) for _, ref := range refs { if ref.ParentID == "0" { continue } c, err := container.daemon.Get(ref.ParentID) if err != nil { logrus.Error(err) } if c != nil && !container.daemon.configStore.DisableBridge && container.hostConfig.NetworkMode.IsPrivate() { logrus.Debugf("Update /etc/hosts of %s for alias %s with ip %s", c.ID, ref.Name, container.NetworkSettings.IPAddress) sboxOptions = append(sboxOptions, libnetwork.OptionParentUpdate(c.ID, ref.Name, container.NetworkSettings.IPAddress)) if c.NetworkSettings.EndpointID != "" { parentEndpoints = append(parentEndpoints, c.NetworkSettings.EndpointID) } } } linkOptions := options.Generic{ netlabel.GenericData: options.Generic{ "ParentEndpoints": parentEndpoints, "ChildEndpoints": childEndpoints, }, } sboxOptions = append(sboxOptions, libnetwork.OptionGeneric(linkOptions)) return sboxOptions, nil }
func (daemon *Daemon) buildSandboxOptions(container *container.Container, n libnetwork.Network) ([]libnetwork.SandboxOption, error) { var ( sboxOptions []libnetwork.SandboxOption err error dns []string dnsSearch []string dnsOptions []string bindings = make(nat.PortMap) pbList []types.PortBinding exposeList []types.TransportPort ) defaultNetName := runconfig.DefaultDaemonNetworkMode().NetworkName() sboxOptions = append(sboxOptions, libnetwork.OptionHostname(container.Config.Hostname), libnetwork.OptionDomainname(container.Config.Domainname)) if container.HostConfig.NetworkMode.IsHost() { sboxOptions = append(sboxOptions, libnetwork.OptionUseDefaultSandbox()) sboxOptions = append(sboxOptions, libnetwork.OptionOriginHostsPath("/etc/hosts")) sboxOptions = append(sboxOptions, libnetwork.OptionOriginResolvConfPath("/etc/resolv.conf")) } else if daemon.execDriver.SupportsHooks() { // OptionUseExternalKey is mandatory for userns support. // But optional for non-userns support sboxOptions = append(sboxOptions, libnetwork.OptionUseExternalKey()) } container.HostsPath, err = container.GetRootResourcePath("hosts") if err != nil { return nil, err } sboxOptions = append(sboxOptions, libnetwork.OptionHostsPath(container.HostsPath)) container.ResolvConfPath, err = container.GetRootResourcePath("resolv.conf") if err != nil { return nil, err } sboxOptions = append(sboxOptions, libnetwork.OptionResolvConfPath(container.ResolvConfPath)) if len(container.HostConfig.DNS) > 0 { dns = container.HostConfig.DNS } else if len(daemon.configStore.DNS) > 0 { dns = daemon.configStore.DNS } for _, d := range dns { sboxOptions = append(sboxOptions, libnetwork.OptionDNS(d)) } if len(container.HostConfig.DNSSearch) > 0 { dnsSearch = container.HostConfig.DNSSearch } else if len(daemon.configStore.DNSSearch) > 0 { dnsSearch = daemon.configStore.DNSSearch } for _, ds := range dnsSearch { sboxOptions = append(sboxOptions, libnetwork.OptionDNSSearch(ds)) } if len(container.HostConfig.DNSOptions) > 0 { dnsOptions = container.HostConfig.DNSOptions } else if len(daemon.configStore.DNSOptions) > 0 { dnsOptions = daemon.configStore.DNSOptions } for _, ds := range dnsOptions { sboxOptions = append(sboxOptions, libnetwork.OptionDNSOptions(ds)) } if container.NetworkSettings.SecondaryIPAddresses != nil { name := container.Config.Hostname if container.Config.Domainname != "" { name = name + "." + container.Config.Domainname } for _, a := range container.NetworkSettings.SecondaryIPAddresses { sboxOptions = append(sboxOptions, libnetwork.OptionExtraHost(name, a.Addr)) } } for _, extraHost := range container.HostConfig.ExtraHosts { // allow IPv6 addresses in extra hosts; only split on first ":" parts := strings.SplitN(extraHost, ":", 2) sboxOptions = append(sboxOptions, libnetwork.OptionExtraHost(parts[0], parts[1])) } if container.HostConfig.PortBindings != nil { for p, b := range container.HostConfig.PortBindings { bindings[p] = []nat.PortBinding{} for _, bb := range b { bindings[p] = append(bindings[p], nat.PortBinding{ HostIP: bb.HostIP, HostPort: bb.HostPort, }) } } } portSpecs := container.Config.ExposedPorts ports := make([]nat.Port, len(portSpecs)) var i int for p := range portSpecs { ports[i] = p i++ } nat.SortPortMap(ports, bindings) for _, port := range ports { expose := types.TransportPort{} expose.Proto = types.ParseProtocol(port.Proto()) expose.Port = uint16(port.Int()) exposeList = append(exposeList, expose) pb := types.PortBinding{Port: expose.Port, Proto: expose.Proto} binding := bindings[port] for i := 0; i < len(binding); i++ { pbCopy := pb.GetCopy() newP, err := nat.NewPort(nat.SplitProtoPort(binding[i].HostPort)) var portStart, portEnd int if err == nil { portStart, portEnd, err = newP.Range() } if err != nil { return nil, fmt.Errorf("Error parsing HostPort value(%s):%v", binding[i].HostPort, err) } pbCopy.HostPort = uint16(portStart) pbCopy.HostPortEnd = uint16(portEnd) pbCopy.HostIP = net.ParseIP(binding[i].HostIP) pbList = append(pbList, pbCopy) } if container.HostConfig.PublishAllPorts && len(binding) == 0 { pbList = append(pbList, pb) } } sboxOptions = append(sboxOptions, libnetwork.OptionPortMapping(pbList), libnetwork.OptionExposedPorts(exposeList)) // Link feature is supported only for the default bridge network. // return if this call to build join options is not for default bridge network if n.Name() != defaultNetName { return sboxOptions, nil } ep, _ := container.GetEndpointInNetwork(n) if ep == nil { return sboxOptions, nil } var childEndpoints, parentEndpoints []string children := daemon.children(container) for linkAlias, child := range children { if !isLinkable(child) { return nil, fmt.Errorf("Cannot link to %s, as it does not belong to the default network", child.Name) } _, alias := path.Split(linkAlias) // allow access to the linked container via the alias, real name, and container hostname aliasList := alias + " " + child.Config.Hostname // only add the name if alias isn't equal to the name if alias != child.Name[1:] { aliasList = aliasList + " " + child.Name[1:] } sboxOptions = append(sboxOptions, libnetwork.OptionExtraHost(aliasList, child.NetworkSettings.Networks[defaultNetName].IPAddress)) cEndpoint, _ := child.GetEndpointInNetwork(n) if cEndpoint != nil && cEndpoint.ID() != "" { childEndpoints = append(childEndpoints, cEndpoint.ID()) } } bridgeSettings := container.NetworkSettings.Networks[defaultNetName] for alias, parent := range daemon.parents(container) { if daemon.configStore.DisableBridge || !container.HostConfig.NetworkMode.IsPrivate() { continue } _, alias = path.Split(alias) logrus.Debugf("Update /etc/hosts of %s for alias %s with ip %s", parent.ID, alias, bridgeSettings.IPAddress) sboxOptions = append(sboxOptions, libnetwork.OptionParentUpdate( parent.ID, alias, bridgeSettings.IPAddress, )) if ep.ID() != "" { parentEndpoints = append(parentEndpoints, ep.ID()) } } linkOptions := options.Generic{ netlabel.GenericData: options.Generic{ "ParentEndpoints": parentEndpoints, "ChildEndpoints": childEndpoints, }, } sboxOptions = append(sboxOptions, libnetwork.OptionGeneric(linkOptions)) return sboxOptions, nil }
func externalKeyTest(t *testing.T, reexec bool) { if !testutils.IsRunningInContainer() { defer testutils.SetupTestOSContext(t)() } n, err := createTestNetwork(bridgeNetType, "testnetwork", options.Generic{ netlabel.GenericData: options.Generic{ "BridgeName": "testnetwork", }, }, nil, nil) if err != nil { t.Fatal(err) } defer func() { if err := n.Delete(); err != nil { t.Fatal(err) } }() ep, err := n.CreateEndpoint("ep1") if err != nil { t.Fatal(err) } defer func() { err = ep.Delete() if err != nil { t.Fatal(err) } }() ep2, err := n.CreateEndpoint("ep2") if err != nil { t.Fatal(err) } defer func() { err = ep2.Delete() if err != nil { t.Fatal(err) } }() cnt, err := controller.NewSandbox(containerID, libnetwork.OptionHostname("test"), libnetwork.OptionDomainname("docker.io"), libnetwork.OptionUseExternalKey(), libnetwork.OptionExtraHost("web", "192.168.0.1")) defer func() { if err := cnt.Delete(); err != nil { t.Fatal(err) } osl.GC() }() // Join endpoint to sandbox before SetKey err = ep.Join(cnt) runtime.LockOSThread() if err != nil { t.Fatal(err) } defer func() { err = ep.Leave(cnt) runtime.LockOSThread() if err != nil { t.Fatal(err) } }() sbox := ep.Info().Sandbox() if sbox == nil { t.Fatalf("Expected to have a valid Sandbox") } if reexec { err := reexecSetKey("this-must-fail", containerID, controller.ID()) if err == nil { t.Fatalf("SetExternalKey must fail if the corresponding namespace is not created") } } else { // Setting an non-existing key (namespace) must fail if err := sbox.SetKey("this-must-fail"); err == nil { t.Fatalf("Setkey must fail if the corresponding namespace is not created") } } // Create a new OS sandbox using the osl API before using it in SetKey if extOsBox, err := osl.NewSandbox("ValidKey", true); err != nil { t.Fatalf("Failed to create new osl sandbox") } else { defer func() { if err := extOsBox.Destroy(); err != nil { log.Warnf("Failed to remove os sandbox: %v", err) } }() } if reexec { err := reexecSetKey("ValidKey", containerID, controller.ID()) if err != nil { t.Fatalf("SetExternalKey failed with %v", err) } } else { if err := sbox.SetKey("ValidKey"); err != nil { t.Fatalf("Setkey failed with %v", err) } } // Join endpoint to sandbox after SetKey err = ep2.Join(sbox) if err != nil { t.Fatal(err) } runtime.LockOSThread() defer func() { err = ep2.Leave(sbox) runtime.LockOSThread() if err != nil { t.Fatal(err) } }() if ep.Info().Sandbox().Key() != ep2.Info().Sandbox().Key() { t.Fatalf("ep1 and ep2 returned different container sandbox key") } checkSandbox(t, ep.Info()) }
func TestHost(t *testing.T) { sbx1, err := controller.NewSandbox("host_c1", libnetwork.OptionHostname("test1"), libnetwork.OptionDomainname("docker.io"), libnetwork.OptionExtraHost("web", "192.168.0.1"), libnetwork.OptionUseDefaultSandbox()) if err != nil { t.Fatal(err) } defer func() { if err := sbx1.Delete(); err != nil { t.Fatal(err) } }() sbx2, err := controller.NewSandbox("host_c2", libnetwork.OptionHostname("test2"), libnetwork.OptionDomainname("docker.io"), libnetwork.OptionExtraHost("web", "192.168.0.1"), libnetwork.OptionUseDefaultSandbox()) if err != nil { t.Fatal(err) } defer func() { if err := sbx2.Delete(); err != nil { t.Fatal(err) } }() network, err := createTestNetwork("host", "testhost", options.Generic{}, nil, nil) if err != nil { t.Fatal(err) } ep1, err := network.CreateEndpoint("testep1") if err != nil { t.Fatal(err) } if err := ep1.Join(sbx1); err != nil { t.Fatal(err) } ep2, err := network.CreateEndpoint("testep2") if err != nil { t.Fatal(err) } if err := ep2.Join(sbx2); err != nil { t.Fatal(err) } if err := ep1.Leave(sbx1); err != nil { t.Fatal(err) } if err := ep2.Leave(sbx2); err != nil { t.Fatal(err) } if err := ep1.Delete(false); err != nil { t.Fatal(err) } if err := ep2.Delete(false); err != nil { t.Fatal(err) } // Try to create another host endpoint and join/leave that. cnt3, err := controller.NewSandbox("host_c3", libnetwork.OptionHostname("test3"), libnetwork.OptionDomainname("docker.io"), libnetwork.OptionExtraHost("web", "192.168.0.1"), libnetwork.OptionUseDefaultSandbox()) if err != nil { t.Fatal(err) } defer func() { if err := cnt3.Delete(); err != nil { t.Fatal(err) } }() ep3, err := network.CreateEndpoint("testep3") if err != nil { t.Fatal(err) } if err := ep3.Join(sbx2); err != nil { t.Fatal(err) } if err := ep3.Leave(sbx2); err != nil { t.Fatal(err) } if err := ep3.Delete(false); err != nil { t.Fatal(err) } }
func TestEndpointJoin(t *testing.T) { if !testutils.IsRunningInContainer() { defer testutils.SetupTestOSContext(t)() } // Create network 1 and add 2 endpoint: ep11, ep12 netOption := options.Generic{ netlabel.GenericData: options.Generic{ "BridgeName": "testnetwork1", "EnableICC": true, "EnableIPMasquerade": true, }, } ipamV6ConfList := []*libnetwork.IpamConf{{PreferredPool: "fe90::/64", Gateway: "fe90::22"}} n1, err := controller.NewNetwork(bridgeNetType, "testnetwork1", "", libnetwork.NetworkOptionGeneric(netOption), libnetwork.NetworkOptionEnableIPv6(true), libnetwork.NetworkOptionIpam(ipamapi.DefaultIPAM, "", nil, ipamV6ConfList, nil), libnetwork.NetworkOptionDeferIPv6Alloc(true)) if err != nil { t.Fatal(err) } defer func() { if err := n1.Delete(); err != nil { t.Fatal(err) } }() ep1, err := n1.CreateEndpoint("ep1") if err != nil { t.Fatal(err) } defer func() { if err := ep1.Delete(false); err != nil { t.Fatal(err) } }() // Validate if ep.Info() only gives me IP address info and not names and gateway during CreateEndpoint() info := ep1.Info() iface := info.Iface() if iface.Address() != nil && iface.Address().IP.To4() == nil { t.Fatalf("Invalid IP address returned: %v", iface.Address()) } if iface.AddressIPv6() != nil && iface.AddressIPv6().IP == nil { t.Fatalf("Invalid IPv6 address returned: %v", iface.Address()) } if len(info.Gateway()) != 0 { t.Fatalf("Expected empty gateway for an empty endpoint. Instead found a gateway: %v", info.Gateway()) } if len(info.GatewayIPv6()) != 0 { t.Fatalf("Expected empty gateway for an empty ipv6 endpoint. Instead found a gateway: %v", info.GatewayIPv6()) } if info.Sandbox() != nil { t.Fatalf("Expected an empty sandbox key for an empty endpoint. Instead found a non-empty sandbox key: %s", info.Sandbox().Key()) } // test invalid joins err = ep1.Join(nil) if err == nil { t.Fatalf("Expected to fail join with nil Sandbox") } if _, ok := err.(types.BadRequestError); !ok { t.Fatalf("Unexpected error type returned: %T", err) } fsbx := &fakeSandbox{} if err = ep1.Join(fsbx); err == nil { t.Fatalf("Expected to fail join with invalid Sandbox") } if _, ok := err.(types.BadRequestError); !ok { t.Fatalf("Unexpected error type returned: %T", err) } sb, err := controller.NewSandbox(containerID, libnetwork.OptionHostname("test"), libnetwork.OptionDomainname("docker.io"), libnetwork.OptionExtraHost("web", "192.168.0.1")) if err != nil { t.Fatal(err) } defer func() { if err := sb.Delete(); err != nil { t.Fatal(err) } }() err = ep1.Join(sb) if err != nil { t.Fatal(err) } defer func() { err = ep1.Leave(sb) if err != nil { t.Fatal(err) } }() // Validate if ep.Info() only gives valid gateway and sandbox key after has container has joined. info = ep1.Info() if len(info.Gateway()) == 0 { t.Fatalf("Expected a valid gateway for a joined endpoint. Instead found an invalid gateway: %v", info.Gateway()) } if len(info.GatewayIPv6()) == 0 { t.Fatalf("Expected a valid ipv6 gateway for a joined endpoint. Instead found an invalid gateway: %v", info.GatewayIPv6()) } if info.Sandbox() == nil { t.Fatalf("Expected an non-empty sandbox key for a joined endpoint. Instead found a empty sandbox key") } // Check endpoint provided container information if ep1.Info().Sandbox().Key() != sb.Key() { t.Fatalf("Endpoint Info returned unexpected sandbox key: %s", sb.Key()) } // Attempt retrieval of endpoint interfaces statistics stats, err := sb.Statistics() if err != nil { t.Fatal(err) } if _, ok := stats["eth0"]; !ok { t.Fatalf("Did not find eth0 statistics") } // Now test the container joining another network n2, err := createTestNetwork(bridgeNetType, "testnetwork2", options.Generic{ netlabel.GenericData: options.Generic{ "BridgeName": "testnetwork2", }, }, nil, nil) if err != nil { t.Fatal(err) } defer func() { if err := n2.Delete(); err != nil { t.Fatal(err) } }() ep2, err := n2.CreateEndpoint("ep2") if err != nil { t.Fatal(err) } defer func() { if err := ep2.Delete(false); err != nil { t.Fatal(err) } }() err = ep2.Join(sb) if err != nil { t.Fatal(err) } defer func() { err = ep2.Leave(sb) if err != nil { t.Fatal(err) } }() if ep1.Info().Sandbox().Key() != ep2.Info().Sandbox().Key() { t.Fatalf("ep1 and ep2 returned different container sandbox key") } checkSandbox(t, info) }
func main() { if reexec.Init() { return } // Select and configure the network driver networkType := "bridge" // Create a new controller instance driverOptions := options.Generic{} genericOption := make(map[string]interface{}) genericOption[netlabel.GenericData] = driverOptions controller, err := libnetwork.New(config.OptionDriverConfig(networkType, genericOption)) if err != nil { log.Fatalf("libnetwork.New: %s", err) } // Create a network for containers to join. // NewNetwork accepts Variadic optional arguments that libnetwork and Drivers can use. network, err := controller.NewNetwork(networkType, "network1") if err != nil { log.Fatalf("controller.NewNetwork: %s", err) } // For each new container: allocate IP and interfaces. The returned network // settings will be used for container infos (inspect and such), as well as // iptables rules for port publishing. This info is contained or accessible // from the returned endpoint. ep, err := network.CreateEndpoint("Endpoint1") if err != nil { log.Fatalf("network.CreateEndpoint: %s", err) } // Create the sandbox for the container. // NewSandbox accepts Variadic optional arguments which libnetwork can use. sbx, err := controller.NewSandbox("container1", libnetwork.OptionHostname("test"), libnetwork.OptionDomainname("docker.io")) if err != nil { log.Fatalf("controller.NewSandbox: %s", err) } // A sandbox can join the endpoint via the join api. err = ep.Join(sbx) if err != nil { log.Fatalf("ep.Join: %s", err) } // libnetwork client can check the endpoint's operational data via the Info() API epInfo, err := ep.DriverInfo() if err != nil { log.Fatalf("ep.DriverInfo: %s", err) } macAddress, ok := epInfo[netlabel.MacAddress] if !ok { log.Fatalf("failed to get mac address from endpoint info") } fmt.Printf("Joined endpoint %s (%s) to sandbox %s (%s)\n", ep.Name(), macAddress, sbx.ContainerID(), sbx.Key()) }