Преглед на файлове

- Added Join option support
- Added basic /etc/hosts generation support in libnetwork

Signed-off-by: Jana Radhakrishnan <mrjana@docker.com>

Jana Radhakrishnan преди 10 години
родител
ревизия
b8f81862d0
променени са 3 файла, в които са добавени 182 реда и са изтрити 19 реда
  1. 137 14
      libnetwork/endpoint.go
  2. 43 3
      libnetwork/libnetwork_test.go
  3. 2 2
      libnetwork/sandbox/namespace_linux.go

+ 137 - 14
libnetwork/endpoint.go

@@ -1,6 +1,10 @@
 package libnetwork
 
 import (
+	"os"
+	"path/filepath"
+
+	"github.com/docker/docker/pkg/etchosts"
 	"github.com/docker/libnetwork/sandbox"
 	"github.com/docker/libnetwork/types"
 )
@@ -19,7 +23,7 @@ type Endpoint interface {
 	// Join creates a new sandbox for the given container ID and populates the
 	// network resources allocated for the endpoint and joins the sandbox to
 	// the endpoint. It returns the sandbox key to the caller
-	Join(containerID string) (string, error)
+	Join(containerID string, options ...JoinOption) (*ContainerData, error)
 
 	// Leave removes the sandbox associated with  container ID and detaches
 	// the network resources populated in the sandbox
@@ -32,15 +36,38 @@ type Endpoint interface {
 	Delete() error
 }
 
+// ContainerData is a set of data returned when a container joins an endpoint.
+type ContainerData struct {
+	SandboxKey string
+	HostsPath  string
+}
+
+// JoinOption is a option setter function type used to pass varios options to
+// endpoint Join method.
+type JoinOption func(ep Endpoint)
+
+type containerConfig struct {
+	Hostname   string
+	Domainname string
+}
+
+type containerInfo struct {
+	ID     string
+	Config containerConfig
+	Data   ContainerData
+}
+
 type endpoint struct {
 	name        string
 	id          types.UUID
 	network     *network
 	sandboxInfo *sandbox.Info
 	sandBox     sandbox.Sandbox
-	containerID string
+	container   *containerInfo
 }
 
+const prefix = "/var/lib/docker/network/files"
+
 func (ep *endpoint) ID() string {
 	return string(ep.id)
 }
@@ -60,19 +87,69 @@ func (ep *endpoint) SandboxInfo() *sandbox.Info {
 	return ep.sandboxInfo.GetCopy()
 }
 
-func (ep *endpoint) Join(containerID string) (string, error) {
+func createBasePath(dir string) error {
+	err := os.MkdirAll(dir, 0644)
+	if err != nil && !os.IsExist(err) {
+		return err
+	}
+
+	return nil
+}
+
+func createHostsFile(path string) error {
+	var f *os.File
+
+	dir, _ := filepath.Split(path)
+	err := createBasePath(dir)
+	if err != nil {
+		return err
+	}
+
+	f, err = os.Create(path)
+	if err == nil {
+		f.Close()
+	}
+
+	return err
+}
+
+func (ep *endpoint) Join(containerID string, options ...JoinOption) (*ContainerData, error) {
+	var err error
+
 	if containerID == "" {
-		return "", InvalidContainerIDError(containerID)
+		return nil, InvalidContainerIDError(containerID)
 	}
 
-	if ep.containerID != "" {
-		return "", ErrInvalidJoin
+	if ep.container != nil {
+		return nil, ErrInvalidJoin
+	}
+
+	ep.container = &containerInfo{}
+	defer func() {
+		if err != nil {
+			ep.container = nil
+		}
+	}()
+
+	if options != nil {
+		ep.processOptions(options...)
+	}
+
+	ep.container.Data.HostsPath = prefix + "/" + containerID + "/hosts"
+	err = createHostsFile(ep.container.Data.HostsPath)
+	if err != nil {
+		return nil, err
+	}
+
+	err = ep.buildHostsFiles()
+	if err != nil {
+		return nil, err
 	}
 
 	sboxKey := sandbox.GenerateKey(containerID)
 	sb, err := ep.network.ctrlr.sandboxAdd(sboxKey)
 	if err != nil {
-		return "", err
+		return nil, err
 	}
 	defer func() {
 		if err != nil {
@@ -85,32 +162,36 @@ func (ep *endpoint) Join(containerID string) (string, error) {
 		for _, i := range sinfo.Interfaces {
 			err = sb.AddInterface(i)
 			if err != nil {
-				return "", err
+				return nil, err
 			}
 		}
 
 		err = sb.SetGateway(sinfo.Gateway)
 		if err != nil {
-			return "", err
+			return nil, err
 		}
 
 		err = sb.SetGatewayIPv6(sinfo.GatewayIPv6)
 		if err != nil {
-			return "", err
+			return nil, err
 		}
 	}
 
-	ep.containerID = containerID
-	return sb.Key(), nil
+	ep.container.ID = containerID
+	ep.container.Data.SandboxKey = sb.Key()
+
+	cData := ep.container.Data
+	return &cData, nil
 }
 
 func (ep *endpoint) Leave(containerID string) error {
-	if ep.containerID == "" || containerID == "" || ep.containerID != containerID {
+	if ep.container == nil || ep.container.ID == "" ||
+		containerID == "" || ep.container.ID != containerID {
 		return InvalidContainerIDError(containerID)
 	}
 
 	ep.network.ctrlr.sandboxRm(sandbox.GenerateKey(containerID))
-	ep.containerID = ""
+	ep.container = nil
 	return nil
 }
 
@@ -138,3 +219,45 @@ func (ep *endpoint) Delete() error {
 	err = n.driver.DeleteEndpoint(n.id, ep.id)
 	return err
 }
+
+func (ep *endpoint) buildHostsFiles() error {
+	var extraContent []etchosts.Record
+
+	name := ep.container.Config.Hostname
+	if ep.container.Config.Domainname != "" {
+		name = name + "." + ep.container.Config.Domainname
+	}
+
+	IP := ""
+	if ep.sandboxInfo != nil && ep.sandboxInfo.Interfaces[0] != nil &&
+		ep.sandboxInfo.Interfaces[0].Address != nil {
+		IP = ep.sandboxInfo.Interfaces[0].Address.IP.String()
+	}
+
+	return etchosts.Build(ep.container.Data.HostsPath, IP, ep.container.Config.Hostname,
+		ep.container.Config.Domainname, extraContent)
+}
+
+// JoinOptionHostname function returns an option setter for hostname option to
+// be passed to endpoint Join method.
+func JoinOptionHostname(name string) JoinOption {
+	return func(e Endpoint) {
+		ep := e.(*endpoint)
+		ep.container.Config.Hostname = name
+	}
+}
+
+// JoinOptionDomainname function returns an option setter for domainname option to
+// be passed to endpoint Join method.
+func JoinOptionDomainname(name string) JoinOption {
+	return func(e Endpoint) {
+		ep := e.(*endpoint)
+		ep.container.Config.Domainname = name
+	}
+}
+
+func (ep *endpoint) processOptions(options ...JoinOption) {
+	for _, opt := range options {
+		opt(ep)
+	}
+}

+ 43 - 3
libnetwork/libnetwork_test.go

@@ -31,6 +31,38 @@ func createTestNetwork(networkType, networkName string, option options.Generic)
 	return network, nil
 }
 
+func TestNull(t *testing.T) {
+	network, err := createTestNetwork("null", "testnetwork", options.Generic{})
+	if err != nil {
+		t.Fatal(err)
+	}
+
+	ep, err := network.CreateEndpoint("testep", nil)
+	if err != nil {
+		t.Fatal(err)
+	}
+
+	_, err = ep.Join(containerID,
+		libnetwork.JoinOptionHostname("test"),
+		libnetwork.JoinOptionDomainname("docker.io"))
+	if err != nil {
+		t.Fatal(err)
+	}
+
+	err = ep.Leave(containerID)
+	if err != nil {
+		t.Fatal(err)
+	}
+
+	if err := ep.Delete(); err != nil {
+		t.Fatal(err)
+	}
+
+	if err := network.Delete(); err != nil {
+		t.Fatal(err)
+	}
+}
+
 func TestBridge(t *testing.T) {
 	defer netutils.SetupTestNetNS(t)()
 	ip, subnet, err := net.ParseCIDR("192.168.100.1/24")
@@ -485,7 +517,9 @@ func TestEndpointJoin(t *testing.T) {
 		t.Fatal(err)
 	}
 
-	_, err = ep.Join(containerID)
+	_, err = ep.Join(containerID,
+		libnetwork.JoinOptionHostname("test"),
+		libnetwork.JoinOptionDomainname("docker.io"))
 	if err != nil {
 		t.Fatal(err)
 	}
@@ -532,7 +566,10 @@ func TestEndpointMultipleJoins(t *testing.T) {
 		t.Fatal(err)
 	}
 
-	_, err = ep.Join(containerID)
+	_, err = ep.Join(containerID,
+		libnetwork.JoinOptionHostname("test"),
+		libnetwork.JoinOptionDomainname("docker.io"))
+
 	if err != nil {
 		t.Fatal(err)
 	}
@@ -574,7 +611,10 @@ func TestEndpointInvalidLeave(t *testing.T) {
 		t.Fatalf("Failed for unexpected reason: %v", err)
 	}
 
-	_, err = ep.Join(containerID)
+	_, err = ep.Join(containerID,
+		libnetwork.JoinOptionHostname("test"),
+		libnetwork.JoinOptionDomainname("docker.io"))
+
 	if err != nil {
 		t.Fatal(err)
 	}

+ 2 - 2
libnetwork/sandbox/namespace_linux.go

@@ -24,7 +24,7 @@ type networkNamespace struct {
 	sinfo *Info
 }
 
-func creatBasePath() {
+func createBasePath() {
 	err := os.MkdirAll(prefix, 0644)
 	if err != nil && !os.IsExist(err) {
 		panic("Could not create net namespace path directory")
@@ -87,7 +87,7 @@ func createNetworkNamespace(path string) (Sandbox, error) {
 func createNamespaceFile(path string) (err error) {
 	var f *os.File
 
-	once.Do(creatBasePath)
+	once.Do(createBasePath)
 	if f, err = os.Create(path); err == nil {
 		f.Close()
 	}