diff --git a/components/engine/api/client/network.go b/components/engine/api/client/network.go index eb42e805d1..66ec8a70eb 100644 --- a/components/engine/api/client/network.go +++ b/components/engine/api/client/network.go @@ -1,14 +1,207 @@ -// +build experimental - package client import ( - nwclient "github.com/docker/libnetwork/client" + "bytes" + "encoding/json" + "fmt" + "io" + "text/tabwriter" + + "github.com/docker/docker/api/types" + Cli "github.com/docker/docker/cli" + flag "github.com/docker/docker/pkg/mflag" + "github.com/docker/docker/pkg/stringid" ) -// CmdNetwork is used to create, display and configure network endpoints. +// CmdNetwork is the parent subcommand for all network commands +// +// Usage: docker network [OPTIONS] func (cli *DockerCli) CmdNetwork(args ...string) error { - nCli := nwclient.NewNetworkCli(cli.out, cli.err, nwclient.CallFunc(cli.callWrapper)) - args = append([]string{"network"}, args...) - return nCli.Cmd("docker", args...) + cmd := Cli.Subcmd("network", []string{"COMMAND [OPTIONS]"}, networkUsage(), false) + cmd.Require(flag.Min, 1) + err := cmd.ParseFlags(args, true) + cmd.Usage() + return err +} + +// CmdNetworkCreate creates a new network with a given name +// +// Usage: docker network create [OPTIONS] +func (cli *DockerCli) CmdNetworkCreate(args ...string) error { + cmd := Cli.Subcmd("network create", []string{"NETWORK-NAME"}, "Creates a new network with a name specified by the user", false) + flDriver := cmd.String([]string{"d", "-driver"}, "", "Driver to manage the Network") + cmd.Require(flag.Exact, 1) + err := cmd.ParseFlags(args, true) + if err != nil { + return err + } + + // Construct network create request body + nc := types.NetworkCreate{Name: cmd.Arg(0), Driver: *flDriver, CheckDuplicate: true} + obj, _, err := readBody(cli.call("POST", "/networks/create", nc, nil)) + if err != nil { + return err + } + var resp types.NetworkCreateResponse + err = json.Unmarshal(obj, &resp) + if err != nil { + return err + } + fmt.Fprintf(cli.out, "%s\n", resp.ID) + return nil +} + +// CmdNetworkRm deletes a network +// +// Usage: docker network rm +func (cli *DockerCli) CmdNetworkRm(args ...string) error { + cmd := Cli.Subcmd("network rm", []string{"NETWORK"}, "Deletes a network", false) + cmd.Require(flag.Exact, 1) + err := cmd.ParseFlags(args, true) + if err != nil { + return err + } + _, _, err = readBody(cli.call("DELETE", "/networks/"+cmd.Arg(0), nil, nil)) + if err != nil { + return err + } + return nil +} + +// CmdNetworkConnect connects a container to a network +// +// Usage: docker network connect +func (cli *DockerCli) CmdNetworkConnect(args ...string) error { + cmd := Cli.Subcmd("network connect", []string{"NETWORK CONTAINER"}, "Connects a container to a network", false) + cmd.Require(flag.Exact, 2) + err := cmd.ParseFlags(args, true) + if err != nil { + return err + } + + nc := types.NetworkConnect{Container: cmd.Arg(1)} + _, _, err = readBody(cli.call("POST", "/networks/"+cmd.Arg(0)+"/connect", nc, nil)) + return err +} + +// CmdNetworkDisconnect disconnects a container from a network +// +// Usage: docker network disconnect +func (cli *DockerCli) CmdNetworkDisconnect(args ...string) error { + cmd := Cli.Subcmd("network disconnect", []string{"NETWORK CONTAINER"}, "Disconnects container from a network", false) + cmd.Require(flag.Exact, 2) + err := cmd.ParseFlags(args, true) + if err != nil { + return err + } + + nc := types.NetworkConnect{Container: cmd.Arg(1)} + _, _, err = readBody(cli.call("POST", "/networks/"+cmd.Arg(0)+"/disconnect", nc, nil)) + return err +} + +// CmdNetworkLs lists all the netorks managed by docker daemon +// +// Usage: docker network ls [OPTIONS] +func (cli *DockerCli) CmdNetworkLs(args ...string) error { + cmd := Cli.Subcmd("network ls", []string{""}, "Lists all the networks created by the user", false) + quiet := cmd.Bool([]string{"q", "-quiet"}, false, "Only display numeric IDs") + noTrunc := cmd.Bool([]string{"", "-no-trunc"}, false, "Do not truncate the output") + nLatest := cmd.Bool([]string{"l", "-latest"}, false, "Show the latest network created") + last := cmd.Int([]string{"n"}, -1, "Show n last created networks") + err := cmd.ParseFlags(args, true) + if err != nil { + return err + } + obj, _, err := readBody(cli.call("GET", "/networks", nil, nil)) + if err != nil { + return err + } + if *last == -1 && *nLatest { + *last = 1 + } + + var networkResources []types.NetworkResource + err = json.Unmarshal(obj, &networkResources) + if err != nil { + return err + } + + wr := tabwriter.NewWriter(cli.out, 20, 1, 3, ' ', 0) + + // unless quiet (-q) is specified, print field titles + if !*quiet { + fmt.Fprintln(wr, "NETWORK ID\tNAME\tDRIVER") + } + + for _, networkResource := range networkResources { + ID := networkResource.ID + netName := networkResource.Name + if !*noTrunc { + ID = stringid.TruncateID(ID) + } + if *quiet { + fmt.Fprintln(wr, ID) + continue + } + driver := networkResource.Driver + fmt.Fprintf(wr, "%s\t%s\t%s\t", + ID, + netName, + driver) + fmt.Fprint(wr, "\n") + } + wr.Flush() + return nil +} + +// CmdNetworkInspect inspects the network object for more details +// +// Usage: docker network inspect +// CmdNetworkInspect handles Network inspect UI +func (cli *DockerCli) CmdNetworkInspect(args ...string) error { + cmd := Cli.Subcmd("network inspect", []string{"NETWORK"}, "Displays detailed information on a network", false) + cmd.Require(flag.Exact, 1) + err := cmd.ParseFlags(args, true) + if err != nil { + return err + } + + obj, _, err := readBody(cli.call("GET", "/networks/"+cmd.Arg(0), nil, nil)) + if err != nil { + return err + } + networkResource := &types.NetworkResource{} + if err := json.NewDecoder(bytes.NewReader(obj)).Decode(networkResource); err != nil { + return err + } + + indented := new(bytes.Buffer) + if err := json.Indent(indented, obj, "", " "); err != nil { + return err + } + if _, err := io.Copy(cli.out, indented); err != nil { + return err + } + return nil +} + +func networkUsage() string { + networkCommands := map[string]string{ + "create": "Create a network", + "connect": "Connect container to a network", + "disconnect": "Disconnect container from a network", + "inspect": "Display detailed network information", + "ls": "List all networks", + "rm": "Remove a network", + } + + help := "Commands:\n" + + for cmd, description := range networkCommands { + help += fmt.Sprintf(" %-25.25s%s\n", cmd, description) + } + + help += fmt.Sprintf("\nRun 'docker network COMMAND --help' for more information on a command.") + return help } diff --git a/components/engine/api/client/service.go b/components/engine/api/client/service.go deleted file mode 100644 index 9f0b1fcfc4..0000000000 --- a/components/engine/api/client/service.go +++ /dev/null @@ -1,17 +0,0 @@ -// +build experimental - -package client - -import ( - "os" - - nwclient "github.com/docker/libnetwork/client" -) - -// CmdService is used to manage network services. -// service command is user to publish, attach and list a service from a container. -func (cli *DockerCli) CmdService(args ...string) error { - nCli := nwclient.NewNetworkCli(cli.out, cli.err, nwclient.CallFunc(cli.callWrapper)) - args = append([]string{"service"}, args...) - return nCli.Cmd(os.Args[0], args...) -} diff --git a/components/engine/integration-cli/docker_api_service_test.go b/components/engine/integration-cli/docker_api_service_test.go deleted file mode 100644 index df072197c7..0000000000 --- a/components/engine/integration-cli/docker_api_service_test.go +++ /dev/null @@ -1,113 +0,0 @@ -// +build experimental - -package main - -import ( - "encoding/json" - "fmt" - "net/http" - - "github.com/go-check/check" -) - -func isServiceAvailable(c *check.C, name string, network string) bool { - status, body, err := sockRequest("GET", "/services", nil) - c.Assert(status, check.Equals, http.StatusOK) - c.Assert(err, check.IsNil) - - var inspectJSON []struct { - Name string - ID string - Network string - } - if err = json.Unmarshal(body, &inspectJSON); err != nil { - c.Fatalf("unable to unmarshal response body: %v", err) - } - for _, s := range inspectJSON { - if s.Name == name && s.Network == network { - return true - } - } - return false - -} - -func isServiceNetworkAvailable(c *check.C, name string) bool { - status, body, err := sockRequest("GET", "/networks", nil) - c.Assert(status, check.Equals, http.StatusOK) - c.Assert(err, check.IsNil) - - var inspectJSON []struct { - Name string - ID string - Type string - } - if err = json.Unmarshal(body, &inspectJSON); err != nil { - c.Fatalf("unable to unmarshal response body: %v", err) - } - for _, n := range inspectJSON { - if n.Name == name { - return true - } - } - return false - -} - -func (s *DockerSuite) TestServiceApiCreateDelete(c *check.C) { - name := "testnetwork" - config := map[string]interface{}{ - "name": name, - "network_type": "bridge", - } - - status, resp, err := sockRequest("POST", "/networks", config) - c.Assert(status, check.Equals, http.StatusCreated) - c.Assert(err, check.IsNil) - - if !isServiceNetworkAvailable(c, name) { - c.Fatalf("Network %s not found", name) - } - - var nid string - err = json.Unmarshal(resp, &nid) - if err != nil { - c.Fatal(err) - } - - sname := "service1" - sconfig := map[string]interface{}{ - "name": sname, - "network_name": name, - } - - status, resp, err = sockRequest("POST", "/services", sconfig) - c.Assert(status, check.Equals, http.StatusCreated) - c.Assert(err, check.IsNil) - - if !isServiceAvailable(c, sname, name) { - c.Fatalf("Service %s.%s not found", sname, name) - } - - var id string - err = json.Unmarshal(resp, &id) - if err != nil { - c.Fatal(err) - } - - status, _, err = sockRequest("DELETE", fmt.Sprintf("/services/%s", id), nil) - c.Assert(status, check.Equals, http.StatusOK) - c.Assert(err, check.IsNil) - - if isServiceAvailable(c, sname, name) { - c.Fatalf("Service %s.%s not deleted", sname, name) - } - - status, _, err = sockRequest("DELETE", fmt.Sprintf("/networks/%s", nid), nil) - c.Assert(status, check.Equals, http.StatusOK) - c.Assert(err, check.IsNil) - - if isNetworkAvailable(c, name) { - c.Fatalf("Network %s not deleted", name) - } -} diff --git a/components/engine/integration-cli/docker_cli_network_test.go b/components/engine/integration-cli/docker_cli_network_test.go index 08b225d2c6..134133918d 100644 --- a/components/engine/integration-cli/docker_cli_network_test.go +++ b/components/engine/integration-cli/docker_cli_network_test.go @@ -1,10 +1,11 @@ -// +build experimental - package main import ( + "encoding/json" + "net" "strings" + "github.com/docker/docker/api/types" "github.com/go-check/check" ) @@ -31,6 +32,14 @@ func isNwPresent(c *check.C, name string) bool { return false } +func getNwResource(c *check.C, name string) *types.NetworkResource { + out, _ := dockerCmd(c, "network", "inspect", name) + nr := types.NetworkResource{} + err := json.Unmarshal([]byte(out), &nr) + c.Assert(err, check.IsNil) + return &nr +} + func (s *DockerSuite) TestDockerNetworkLsDefault(c *check.C) { defaults := []string{"bridge", "host", "none"} for _, nn := range defaults { @@ -45,3 +54,45 @@ func (s *DockerSuite) TestDockerNetworkCreateDelete(c *check.C) { dockerCmd(c, "network", "rm", "test") assertNwNotAvailable(c, "test") } + +func (s *DockerSuite) TestDockerNetworkConnectDisconnect(c *check.C) { + dockerCmd(c, "network", "create", "test") + assertNwIsAvailable(c, "test") + nr := getNwResource(c, "test") + + c.Assert(nr.Name, check.Equals, "test") + c.Assert(len(nr.Containers), check.Equals, 0) + + // run a container + out, _ := dockerCmd(c, "run", "-d", "--name", "test", "busybox", "top") + c.Assert(waitRun("test"), check.IsNil) + containerID := strings.TrimSpace(out) + + // connect the container to the test network + dockerCmd(c, "network", "connect", "test", containerID) + + // inspect the network to make sure container is connected + nr = getNetworkResource(c, nr.ID) + c.Assert(len(nr.Containers), check.Equals, 1) + c.Assert(nr.Containers[containerID], check.NotNil) + + // check if container IP matches network inspect + ip, _, err := net.ParseCIDR(nr.Containers[containerID].IPv4Address) + c.Assert(err, check.IsNil) + containerIP := findContainerIP(c, "test") + c.Assert(ip.String(), check.Equals, containerIP) + + // disconnect container from the network + dockerCmd(c, "network", "disconnect", "test", containerID) + nr = getNwResource(c, "test") + c.Assert(nr.Name, check.Equals, "test") + c.Assert(len(nr.Containers), check.Equals, 0) + + // check if network connect fails for inactive containers + dockerCmd(c, "stop", containerID) + _, _, err = dockerCmdWithError("network", "connect", "test", containerID) + c.Assert(err, check.NotNil) + + dockerCmd(c, "network", "rm", "test") + assertNwNotAvailable(c, "test") +} diff --git a/components/engine/integration-cli/docker_cli_run_test.go b/components/engine/integration-cli/docker_cli_run_test.go index c8d93ad975..e9d6854754 100644 --- a/components/engine/integration-cli/docker_cli_run_test.go +++ b/components/engine/integration-cli/docker_cli_run_test.go @@ -18,7 +18,9 @@ import ( "sync" "time" + "github.com/docker/docker/pkg/integration/checker" "github.com/docker/docker/pkg/nat" + "github.com/docker/docker/runconfig" "github.com/docker/libnetwork/resolvconf" "github.com/go-check/check" ) @@ -3408,6 +3410,7 @@ func (s *DockerSuite) TestContainersInUserDefinedNetwork(c *check.C) { testRequires(c, DaemonIsLinux) dockerCmd(c, "network", "create", "-d", "bridge", "testnetwork") dockerCmd(c, "run", "-d", "--net=testnetwork", "--name=first", "busybox", "top") + c.Assert(waitRun("first"), check.IsNil) dockerCmd(c, "run", "-t", "--net=testnetwork", "--name=second", "busybox", "ping", "-c", "1", "first") dockerCmd(c, "stop", "first") dockerCmd(c, "stop", "second") @@ -3421,7 +3424,9 @@ func (s *DockerSuite) TestContainersInMultipleNetworks(c *check.C) { dockerCmd(c, "network", "create", "-d", "bridge", "testnetwork2") // Run and connect containers to testnetwork1 dockerCmd(c, "run", "-d", "--net=testnetwork1", "--name=first", "busybox", "top") + c.Assert(waitRun("first"), check.IsNil) dockerCmd(c, "run", "-d", "--net=testnetwork1", "--name=second", "busybox", "top") + c.Assert(waitRun("second"), check.IsNil) // Check connectivity between containers in testnetwork2 dockerCmd(c, "exec", "first", "ping", "-c", "1", "second.testnetwork1") // Connect containers to testnetwork2 @@ -3440,9 +3445,11 @@ func (s *DockerSuite) TestContainersNetworkIsolation(c *check.C) { // Create 2 networks using bridge driver dockerCmd(c, "network", "create", "-d", "bridge", "testnetwork1") dockerCmd(c, "network", "create", "-d", "bridge", "testnetwork2") - // Run 1 containers in testnetwork1 and another in testnetwork2 + // Run 1 container in testnetwork1 and another in testnetwork2 dockerCmd(c, "run", "-d", "--net=testnetwork1", "--name=first", "busybox", "top") + c.Assert(waitRun("first"), check.IsNil) dockerCmd(c, "run", "-d", "--net=testnetwork2", "--name=second", "busybox", "top") + c.Assert(waitRun("second"), check.IsNil) // Check Isolation between containers : ping must fail _, _, err := dockerCmdWithError("exec", "first", "ping", "-c", "1", "second") @@ -3471,7 +3478,9 @@ func (s *DockerSuite) TestNetworkRmWithActiveContainers(c *check.C) { dockerCmd(c, "network", "create", "-d", "bridge", "testnetwork1") // Run and connect containers to testnetwork1 dockerCmd(c, "run", "-d", "--net=testnetwork1", "--name=first", "busybox", "top") + c.Assert(waitRun("first"), check.IsNil) dockerCmd(c, "run", "-d", "--net=testnetwork1", "--name=second", "busybox", "top") + c.Assert(waitRun("second"), check.IsNil) // Network delete with active containers must fail _, _, err := dockerCmdWithError("network", "rm", "testnetwork1") c.Assert(err, check.NotNil) @@ -3492,7 +3501,9 @@ func (s *DockerSuite) TestContainerRestartInMultipleNetworks(c *check.C) { dockerCmd(c, "network", "create", "-d", "bridge", "testnetwork2") // Run and connect containers to testnetwork1 dockerCmd(c, "run", "-d", "--net=testnetwork1", "--name=first", "busybox", "top") + c.Assert(waitRun("first"), check.IsNil) dockerCmd(c, "run", "-d", "--net=testnetwork1", "--name=second", "busybox", "top") + c.Assert(waitRun("second"), check.IsNil) // Check connectivity between containers in testnetwork2 dockerCmd(c, "exec", "first", "ping", "-c", "1", "second.testnetwork1") // Connect containers to testnetwork2 @@ -3523,6 +3534,7 @@ func (s *DockerSuite) TestContainerWithConflictingHostNetworks(c *check.C) { testRequires(c, DaemonIsLinux) // Run a container with --net=host dockerCmd(c, "run", "-d", "--net=host", "--name=first", "busybox", "top") + c.Assert(waitRun("first"), check.IsNil) // Create a network using bridge driver dockerCmd(c, "network", "create", "-d", "bridge", "testnetwork1") @@ -3537,14 +3549,43 @@ func (s *DockerSuite) TestContainerWithConflictingHostNetworks(c *check.C) { func (s *DockerSuite) TestContainerWithConflictingSharedNetwork(c *check.C) { testRequires(c, DaemonIsLinux) dockerCmd(c, "run", "-d", "--name=first", "busybox", "top") + c.Assert(waitRun("first"), check.IsNil) // Run second container in first container's network namespace dockerCmd(c, "run", "-d", "--net=container:first", "--name=second", "busybox", "top") + c.Assert(waitRun("second"), check.IsNil) // Create a network using bridge driver dockerCmd(c, "network", "create", "-d", "bridge", "testnetwork1") // Connecting to the user defined network must fail - _, _, err := dockerCmdWithError("network", "connect", "testnetwork1", "second") + out, _, err := dockerCmdWithError("network", "connect", "testnetwork1", "second") + c.Assert(err, check.NotNil) + c.Assert(out, checker.Contains, runconfig.ErrConflictSharedNetwork.Error()) + + dockerCmd(c, "stop", "first") + dockerCmd(c, "stop", "second") + dockerCmd(c, "network", "rm", "testnetwork1") +} + +func (s *DockerSuite) TestContainerWithConflictingNoneNetwork(c *check.C) { + testRequires(c, DaemonIsLinux) + dockerCmd(c, "run", "-d", "--net=none", "--name=first", "busybox", "top") + c.Assert(waitRun("first"), check.IsNil) + + // Create a network using bridge driver + dockerCmd(c, "network", "create", "-d", "bridge", "testnetwork1") + + // Connecting to the user defined network must fail + out, _, err := dockerCmdWithError("network", "connect", "testnetwork1", "first") + c.Assert(err, check.NotNil) + c.Assert(out, checker.Contains, runconfig.ErrConflictNoNetwork.Error()) + + // create a container connected to testnetwork1 + dockerCmd(c, "run", "-d", "--net=testnetwork1", "--name=second", "busybox", "top") + c.Assert(waitRun("second"), check.IsNil) + + // Connect second container to none network. it must fail as well + _, _, err = dockerCmdWithError("network", "connect", "none", "second") c.Assert(err, check.NotNil) dockerCmd(c, "stop", "first") diff --git a/components/engine/integration-cli/docker_cli_service_test.go b/components/engine/integration-cli/docker_cli_service_test.go deleted file mode 100644 index aaf5e8199e..0000000000 --- a/components/engine/integration-cli/docker_cli_service_test.go +++ /dev/null @@ -1,69 +0,0 @@ -// +build experimental - -package main - -import ( - "fmt" - "strings" - - "github.com/go-check/check" -) - -func assertSrvIsAvailable(c *check.C, sname, name string) { - if !isSrvPresent(c, sname, name) { - c.Fatalf("Service %s on network %s not found in service ls o/p", sname, name) - } -} - -func assertSrvNotAvailable(c *check.C, sname, name string) { - if isSrvPresent(c, sname, name) { - c.Fatalf("Found service %s on network %s in service ls o/p", sname, name) - } -} - -func isSrvPresent(c *check.C, sname, name string) bool { - out, _, _ := dockerCmdWithStdoutStderr(c, "service", "ls") - lines := strings.Split(out, "\n") - for i := 1; i < len(lines)-1; i++ { - if strings.Contains(lines[i], sname) && strings.Contains(lines[i], name) { - return true - } - } - return false -} - -func isCntPresent(c *check.C, cname, sname, name string) bool { - out, _, _ := dockerCmdWithStdoutStderr(c, "service", "ls", "--no-trunc") - lines := strings.Split(out, "\n") - for i := 1; i < len(lines)-1; i++ { - fmt.Println(lines) - if strings.Contains(lines[i], name) && strings.Contains(lines[i], sname) && strings.Contains(lines[i], cname) { - return true - } - } - return false -} - -func (s *DockerSuite) TestDockerServiceCreateDelete(c *check.C) { - dockerCmdWithStdoutStderr(c, "network", "create", "test") - assertNwIsAvailable(c, "test") - - dockerCmdWithStdoutStderr(c, "service", "publish", "s1.test") - assertSrvIsAvailable(c, "s1", "test") - - dockerCmdWithStdoutStderr(c, "service", "unpublish", "s1.test") - assertSrvNotAvailable(c, "s1", "test") - - dockerCmdWithStdoutStderr(c, "network", "rm", "test") - assertNwNotAvailable(c, "test") -} - -func (s *DockerSuite) TestDockerPublishServiceFlag(c *check.C) { - // Run saying the container is the backend for the specified service on the specified network - out, _ := dockerCmd(c, "run", "-d", "--expose=23", "--publish-service", "telnet.production", "busybox", "top") - cid := strings.TrimSpace(out) - - // Verify container is attached in service ps o/p - assertSrvIsAvailable(c, "telnet", "production") - dockerCmd(c, "rm", "-f", cid) -} diff --git a/components/engine/vendor/src/github.com/docker/libnetwork/client/client.go b/components/engine/vendor/src/github.com/docker/libnetwork/client/client.go deleted file mode 100644 index c5713b01b3..0000000000 --- a/components/engine/vendor/src/github.com/docker/libnetwork/client/client.go +++ /dev/null @@ -1,115 +0,0 @@ -package client - -import ( - "fmt" - "io" - "io/ioutil" - "net/http" - "reflect" - "strings" - - flag "github.com/docker/docker/pkg/mflag" -) - -// CallFunc provides environment specific call utility to invoke backend functions from UI -type CallFunc func(string, string, interface{}, map[string][]string) (io.ReadCloser, http.Header, int, error) - -// NetworkCli is the UI object for network subcmds -type NetworkCli struct { - out io.Writer - err io.Writer - call CallFunc -} - -// NewNetworkCli is a convenient function to create a NetworkCli object -func NewNetworkCli(out, err io.Writer, call CallFunc) *NetworkCli { - return &NetworkCli{ - out: out, - err: err, - call: call, - } -} - -// getMethod is Borrowed from Docker UI which uses reflection to identify the UI Handler -func (cli *NetworkCli) getMethod(args ...string) (func(string, ...string) error, bool) { - camelArgs := make([]string, len(args)) - for i, s := range args { - if len(s) == 0 { - return nil, false - } - camelArgs[i] = strings.ToUpper(s[:1]) + strings.ToLower(s[1:]) - } - methodName := "Cmd" + strings.Join(camelArgs, "") - method := reflect.ValueOf(cli).MethodByName(methodName) - if !method.IsValid() { - return nil, false - } - return method.Interface().(func(string, ...string) error), true -} - -// Cmd is borrowed from Docker UI and acts as the entry point for network UI commands. -// network UI commands are designed to be invoked from multiple parent chains -func (cli *NetworkCli) Cmd(chain string, args ...string) error { - if len(args) > 2 { - method, exists := cli.getMethod(args[:3]...) - if exists { - return method(chain+" "+args[0]+" "+args[1], args[3:]...) - } - } - if len(args) > 1 { - method, exists := cli.getMethod(args[:2]...) - if exists { - return method(chain+" "+args[0], args[2:]...) - } - } - if len(args) > 0 { - method, exists := cli.getMethod(args[0]) - if !exists { - return fmt.Errorf("%s: '%s' is not a %s command. See '%s --help'.\n", chain, args[0], chain, chain) - } - return method(chain, args[1:]...) - } - flag.Usage() - return nil -} - -// Subcmd is borrowed from Docker UI and performs the same function of configuring the subCmds -func (cli *NetworkCli) Subcmd(chain, name, signature, description string, exitOnError bool) *flag.FlagSet { - var errorHandling flag.ErrorHandling - if exitOnError { - errorHandling = flag.ExitOnError - } else { - errorHandling = flag.ContinueOnError - } - flags := flag.NewFlagSet(name, errorHandling) - flags.Usage = func() { - flags.ShortUsage() - flags.PrintDefaults() - } - flags.ShortUsage = func() { - options := "" - if signature != "" { - signature = " " + signature - } - if flags.FlagCountUndeprecated() > 0 { - options = " [OPTIONS]" - } - fmt.Fprintf(cli.out, "\nUsage: %s %s%s%s\n\n%s\n\n", chain, name, options, signature, description) - flags.SetOutput(cli.out) - } - return flags -} - -func readBody(stream io.ReadCloser, hdr http.Header, statusCode int, err error) ([]byte, int, error) { - if stream != nil { - defer stream.Close() - } - if err != nil { - return nil, statusCode, err - } - body, err := ioutil.ReadAll(stream) - if err != nil { - return nil, -1, err - } - return body, statusCode, nil -} diff --git a/components/engine/vendor/src/github.com/docker/libnetwork/client/network.go b/components/engine/vendor/src/github.com/docker/libnetwork/client/network.go deleted file mode 100644 index a244ad5f69..0000000000 --- a/components/engine/vendor/src/github.com/docker/libnetwork/client/network.go +++ /dev/null @@ -1,231 +0,0 @@ -package client - -import ( - "bytes" - "encoding/json" - "fmt" - "net/http" - "text/tabwriter" - - flag "github.com/docker/docker/pkg/mflag" - "github.com/docker/docker/pkg/stringid" -) - -type command struct { - name string - description string -} - -var ( - networkCommands = []command{ - {"create", "Create a network"}, - {"rm", "Remove a network"}, - {"ls", "List all networks"}, - {"info", "Display information of a network"}, - } -) - -// CmdNetwork handles the root Network UI -func (cli *NetworkCli) CmdNetwork(chain string, args ...string) error { - cmd := cli.Subcmd(chain, "network", "COMMAND [OPTIONS] [arg...]", networkUsage(chain), false) - cmd.Require(flag.Min, 1) - err := cmd.ParseFlags(args, true) - if err == nil { - cmd.Usage() - return fmt.Errorf("invalid command : %v", args) - } - return err -} - -// CmdNetworkCreate handles Network Create UI -func (cli *NetworkCli) CmdNetworkCreate(chain string, args ...string) error { - cmd := cli.Subcmd(chain, "create", "NETWORK-NAME", "Creates a new network with a name specified by the user", false) - flDriver := cmd.String([]string{"d", "-driver"}, "", "Driver to manage the Network") - cmd.Require(flag.Exact, 1) - err := cmd.ParseFlags(args, true) - if err != nil { - return err - } - - // Construct network create request body - ops := make(map[string]interface{}) - nc := networkCreate{Name: cmd.Arg(0), NetworkType: *flDriver, Options: ops} - obj, _, err := readBody(cli.call("POST", "/networks", nc, nil)) - if err != nil { - return err - } - var replyID string - err = json.Unmarshal(obj, &replyID) - if err != nil { - return err - } - fmt.Fprintf(cli.out, "%s\n", replyID) - return nil -} - -// CmdNetworkRm handles Network Delete UI -func (cli *NetworkCli) CmdNetworkRm(chain string, args ...string) error { - cmd := cli.Subcmd(chain, "rm", "NETWORK", "Deletes a network", false) - cmd.Require(flag.Exact, 1) - err := cmd.ParseFlags(args, true) - if err != nil { - return err - } - id, err := lookupNetworkID(cli, cmd.Arg(0)) - if err != nil { - return err - } - _, _, err = readBody(cli.call("DELETE", "/networks/"+id, nil, nil)) - if err != nil { - return err - } - return nil -} - -// CmdNetworkLs handles Network List UI -func (cli *NetworkCli) CmdNetworkLs(chain string, args ...string) error { - cmd := cli.Subcmd(chain, "ls", "", "Lists all the networks created by the user", false) - quiet := cmd.Bool([]string{"q", "-quiet"}, false, "Only display numeric IDs") - noTrunc := cmd.Bool([]string{"#notrunc", "-no-trunc"}, false, "Do not truncate the output") - nLatest := cmd.Bool([]string{"l", "-latest"}, false, "Show the latest network created") - last := cmd.Int([]string{"n"}, -1, "Show n last created networks") - err := cmd.ParseFlags(args, true) - if err != nil { - return err - } - obj, _, err := readBody(cli.call("GET", "/networks", nil, nil)) - if err != nil { - return err - } - if *last == -1 && *nLatest { - *last = 1 - } - - var networkResources []networkResource - err = json.Unmarshal(obj, &networkResources) - if err != nil { - return err - } - - wr := tabwriter.NewWriter(cli.out, 20, 1, 3, ' ', 0) - - // unless quiet (-q) is specified, print field titles - if !*quiet { - fmt.Fprintln(wr, "NETWORK ID\tNAME\tTYPE") - } - - for _, networkResource := range networkResources { - ID := networkResource.ID - netName := networkResource.Name - if !*noTrunc { - ID = stringid.TruncateID(ID) - } - if *quiet { - fmt.Fprintln(wr, ID) - continue - } - netType := networkResource.Type - fmt.Fprintf(wr, "%s\t%s\t%s\t", - ID, - netName, - netType) - fmt.Fprint(wr, "\n") - } - wr.Flush() - return nil -} - -// CmdNetworkInfo handles Network Info UI -func (cli *NetworkCli) CmdNetworkInfo(chain string, args ...string) error { - cmd := cli.Subcmd(chain, "info", "NETWORK", "Displays detailed information on a network", false) - cmd.Require(flag.Exact, 1) - err := cmd.ParseFlags(args, true) - if err != nil { - return err - } - - id, err := lookupNetworkID(cli, cmd.Arg(0)) - if err != nil { - return err - } - - obj, _, err := readBody(cli.call("GET", "/networks/"+id, nil, nil)) - if err != nil { - return err - } - networkResource := &networkResource{} - if err := json.NewDecoder(bytes.NewReader(obj)).Decode(networkResource); err != nil { - return err - } - fmt.Fprintf(cli.out, "Network Id: %s\n", networkResource.ID) - fmt.Fprintf(cli.out, "Name: %s\n", networkResource.Name) - fmt.Fprintf(cli.out, "Type: %s\n", networkResource.Type) - if networkResource.Services != nil { - for _, serviceResource := range networkResource.Services { - fmt.Fprintf(cli.out, " Service Id: %s\n", serviceResource.ID) - fmt.Fprintf(cli.out, "\tName: %s\n", serviceResource.Name) - } - } - - return nil -} - -// Helper function to predict if a string is a name or id or partial-id -// This provides a best-effort mechanism to identify a id with the help of GET Filter APIs -// Being a UI, its most likely that name will be used by the user, which is used to lookup -// the corresponding ID. If ID is not found, this function will assume that the passed string -// is an ID by itself. - -func lookupNetworkID(cli *NetworkCli, nameID string) (string, error) { - obj, statusCode, err := readBody(cli.call("GET", "/networks?name="+nameID, nil, nil)) - if err != nil { - return "", err - } - - if statusCode != http.StatusOK { - return "", fmt.Errorf("name query failed for %s due to : statuscode(%d) %v", nameID, statusCode, string(obj)) - } - - var list []*networkResource - err = json.Unmarshal(obj, &list) - if err != nil { - return "", err - } - if len(list) > 0 { - // name query filter will always return a single-element collection - return list[0].ID, nil - } - - // Check for Partial-id - obj, statusCode, err = readBody(cli.call("GET", "/networks?partial-id="+nameID, nil, nil)) - if err != nil { - return "", err - } - - if statusCode != http.StatusOK { - return "", fmt.Errorf("partial-id match query failed for %s due to : statuscode(%d) %v", nameID, statusCode, string(obj)) - } - - err = json.Unmarshal(obj, &list) - if err != nil { - return "", err - } - if len(list) == 0 { - return "", fmt.Errorf("resource not found %s", nameID) - } - if len(list) > 1 { - return "", fmt.Errorf("multiple Networks matching the partial identifier (%s). Please use full identifier", nameID) - } - return list[0].ID, nil -} - -func networkUsage(chain string) string { - help := "Commands:\n" - - for _, cmd := range networkCommands { - help += fmt.Sprintf(" %-25.25s%s\n", cmd.name, cmd.description) - } - - help += fmt.Sprintf("\nRun '%s network COMMAND --help' for more information on a command.", chain) - return help -} diff --git a/components/engine/vendor/src/github.com/docker/libnetwork/client/service.go b/components/engine/vendor/src/github.com/docker/libnetwork/client/service.go deleted file mode 100644 index f2ecedddeb..0000000000 --- a/components/engine/vendor/src/github.com/docker/libnetwork/client/service.go +++ /dev/null @@ -1,392 +0,0 @@ -package client - -import ( - "bytes" - "encoding/json" - "fmt" - "net/http" - "strings" - "text/tabwriter" - - flag "github.com/docker/docker/pkg/mflag" - "github.com/docker/docker/pkg/stringid" -) - -var ( - serviceCommands = []command{ - {"publish", "Publish a service"}, - {"unpublish", "Remove a service"}, - {"attach", "Attach a backend (container) to the service"}, - {"detach", "Detach the backend from the service"}, - {"ls", "Lists all services"}, - {"info", "Display information about a service"}, - } -) - -func lookupServiceID(cli *NetworkCli, nwName, svNameID string) (string, error) { - // Sanity Check - obj, _, err := readBody(cli.call("GET", fmt.Sprintf("/networks?name=%s", nwName), nil, nil)) - if err != nil { - return "", err - } - var nwList []networkResource - if err = json.Unmarshal(obj, &nwList); err != nil { - return "", err - } - if len(nwList) == 0 { - return "", fmt.Errorf("Network %s does not exist", nwName) - } - - if nwName == "" { - obj, _, err := readBody(cli.call("GET", "/networks/"+nwList[0].ID, nil, nil)) - if err != nil { - return "", err - } - networkResource := &networkResource{} - if err := json.NewDecoder(bytes.NewReader(obj)).Decode(networkResource); err != nil { - return "", err - } - nwName = networkResource.Name - } - - // Query service by name - obj, statusCode, err := readBody(cli.call("GET", fmt.Sprintf("/services?name=%s", svNameID), nil, nil)) - if err != nil { - return "", err - } - - if statusCode != http.StatusOK { - return "", fmt.Errorf("name query failed for %s due to: (%d) %s", svNameID, statusCode, string(obj)) - } - - var list []*serviceResource - if err = json.Unmarshal(obj, &list); err != nil { - return "", err - } - for _, sr := range list { - if sr.Network == nwName { - return sr.ID, nil - } - } - - // Query service by Partial-id (this covers full id as well) - obj, statusCode, err = readBody(cli.call("GET", fmt.Sprintf("/services?partial-id=%s", svNameID), nil, nil)) - if err != nil { - return "", err - } - - if statusCode != http.StatusOK { - return "", fmt.Errorf("partial-id match query failed for %s due to: (%d) %s", svNameID, statusCode, string(obj)) - } - - if err = json.Unmarshal(obj, &list); err != nil { - return "", err - } - for _, sr := range list { - if sr.Network == nwName { - return sr.ID, nil - } - } - - return "", fmt.Errorf("Service %s not found on network %s", svNameID, nwName) -} - -func lookupContainerID(cli *NetworkCli, cnNameID string) (string, error) { - // Container is a Docker resource, ask docker about it. - // In case of connecton error, we assume we are running in dnet and return whatever was passed to us - obj, _, err := readBody(cli.call("GET", fmt.Sprintf("/containers/%s/json", cnNameID), nil, nil)) - if err != nil { - // We are probably running outside of docker - return cnNameID, nil - } - - var x map[string]interface{} - err = json.Unmarshal(obj, &x) - if err != nil { - return "", err - } - if iid, ok := x["Id"]; ok { - if id, ok := iid.(string); ok { - return id, nil - } - return "", fmt.Errorf("Unexpected data type for container ID in json response") - } - return "", fmt.Errorf("Cannot find container ID in json response") -} - -func lookupSandboxID(cli *NetworkCli, containerID string) (string, error) { - obj, _, err := readBody(cli.call("GET", fmt.Sprintf("/sandboxes?partial-container-id=%s", containerID), nil, nil)) - if err != nil { - return "", err - } - - var sandboxList []SandboxResource - err = json.Unmarshal(obj, &sandboxList) - if err != nil { - return "", err - } - - if len(sandboxList) == 0 { - return "", fmt.Errorf("cannot find sandbox for container: %s", containerID) - } - - return sandboxList[0].ID, nil -} - -// CmdService handles the service UI -func (cli *NetworkCli) CmdService(chain string, args ...string) error { - cmd := cli.Subcmd(chain, "service", "COMMAND [OPTIONS] [arg...]", serviceUsage(chain), false) - cmd.Require(flag.Min, 1) - err := cmd.ParseFlags(args, true) - if err == nil { - cmd.Usage() - return fmt.Errorf("Invalid command : %v", args) - } - return err -} - -// Parse service name for "SERVICE[.NETWORK]" format -func parseServiceName(name string) (string, string) { - s := strings.Split(name, ".") - var sName, nName string - if len(s) > 1 { - nName = s[len(s)-1] - sName = strings.Join(s[:len(s)-1], ".") - } else { - sName = s[0] - } - return sName, nName -} - -// CmdServicePublish handles service create UI -func (cli *NetworkCli) CmdServicePublish(chain string, args ...string) error { - cmd := cli.Subcmd(chain, "publish", "SERVICE[.NETWORK]", "Publish a new service on a network", false) - cmd.Require(flag.Exact, 1) - err := cmd.ParseFlags(args, true) - if err != nil { - return err - } - - sn, nn := parseServiceName(cmd.Arg(0)) - sc := serviceCreate{Name: sn, Network: nn} - obj, _, err := readBody(cli.call("POST", "/services", sc, nil)) - if err != nil { - return err - } - - var replyID string - err = json.Unmarshal(obj, &replyID) - if err != nil { - return err - } - - fmt.Fprintf(cli.out, "%s\n", replyID) - return nil -} - -// CmdServiceUnpublish handles service delete UI -func (cli *NetworkCli) CmdServiceUnpublish(chain string, args ...string) error { - cmd := cli.Subcmd(chain, "unpublish", "SERVICE[.NETWORK]", "Removes a service", false) - cmd.Require(flag.Exact, 1) - err := cmd.ParseFlags(args, true) - if err != nil { - return err - } - - sn, nn := parseServiceName(cmd.Arg(0)) - serviceID, err := lookupServiceID(cli, nn, sn) - if err != nil { - return err - } - - _, _, err = readBody(cli.call("DELETE", "/services/"+serviceID, nil, nil)) - - return err -} - -// CmdServiceLs handles service list UI -func (cli *NetworkCli) CmdServiceLs(chain string, args ...string) error { - cmd := cli.Subcmd(chain, "ls", "SERVICE", "Lists all the services on a network", false) - flNetwork := cmd.String([]string{"net", "-network"}, "", "Only show the services that are published on the specified network") - quiet := cmd.Bool([]string{"q", "-quiet"}, false, "Only display numeric IDs") - noTrunc := cmd.Bool([]string{"#notrunc", "-no-trunc"}, false, "Do not truncate the output") - - err := cmd.ParseFlags(args, true) - if err != nil { - return err - } - - var obj []byte - if *flNetwork == "" { - obj, _, err = readBody(cli.call("GET", "/services", nil, nil)) - } else { - obj, _, err = readBody(cli.call("GET", "/services?network="+*flNetwork, nil, nil)) - } - if err != nil { - return err - } - - var serviceResources []serviceResource - err = json.Unmarshal(obj, &serviceResources) - if err != nil { - fmt.Println(err) - return err - } - - wr := tabwriter.NewWriter(cli.out, 20, 1, 3, ' ', 0) - // unless quiet (-q) is specified, print field titles - if !*quiet { - fmt.Fprintln(wr, "SERVICE ID\tNAME\tNETWORK\tCONTAINER\tSANDBOX") - } - - for _, sr := range serviceResources { - ID := sr.ID - bkID, sbID, err := getBackendID(cli, ID) - if err != nil { - return err - } - if !*noTrunc { - ID = stringid.TruncateID(ID) - bkID = stringid.TruncateID(bkID) - sbID = stringid.TruncateID(sbID) - } - if !*quiet { - fmt.Fprintf(wr, "%s\t%s\t%s\t%s\t%s\n", ID, sr.Name, sr.Network, bkID, sbID) - } else { - fmt.Fprintln(wr, ID) - } - } - wr.Flush() - - return nil -} - -func getBackendID(cli *NetworkCli, servID string) (string, string, error) { - var ( - obj []byte - err error - bk string - sb string - ) - - if obj, _, err = readBody(cli.call("GET", "/services/"+servID+"/backend", nil, nil)); err == nil { - var sr SandboxResource - if err := json.NewDecoder(bytes.NewReader(obj)).Decode(&sr); err == nil { - bk = sr.ContainerID - sb = sr.ID - } else { - // Only print a message, don't make the caller cli fail for this - fmt.Fprintf(cli.out, "Failed to retrieve backend list for service %s (%v)\n", servID, err) - } - } - - return bk, sb, err -} - -// CmdServiceInfo handles service info UI -func (cli *NetworkCli) CmdServiceInfo(chain string, args ...string) error { - cmd := cli.Subcmd(chain, "info", "SERVICE[.NETWORK]", "Displays detailed information about a service", false) - cmd.Require(flag.Min, 1) - - err := cmd.ParseFlags(args, true) - if err != nil { - return err - } - - sn, nn := parseServiceName(cmd.Arg(0)) - serviceID, err := lookupServiceID(cli, nn, sn) - if err != nil { - return err - } - - obj, _, err := readBody(cli.call("GET", "/services/"+serviceID, nil, nil)) - if err != nil { - return err - } - - sr := &serviceResource{} - if err := json.NewDecoder(bytes.NewReader(obj)).Decode(sr); err != nil { - return err - } - - fmt.Fprintf(cli.out, "Service Id: %s\n", sr.ID) - fmt.Fprintf(cli.out, "\tName: %s\n", sr.Name) - fmt.Fprintf(cli.out, "\tNetwork: %s\n", sr.Network) - - return nil -} - -// CmdServiceAttach handles service attach UI -func (cli *NetworkCli) CmdServiceAttach(chain string, args ...string) error { - cmd := cli.Subcmd(chain, "attach", "CONTAINER SERVICE[.NETWORK]", "Sets a container as a service backend", false) - cmd.Require(flag.Min, 2) - err := cmd.ParseFlags(args, true) - if err != nil { - return err - } - - containerID, err := lookupContainerID(cli, cmd.Arg(0)) - if err != nil { - return err - } - - sandboxID, err := lookupSandboxID(cli, containerID) - if err != nil { - return err - } - - sn, nn := parseServiceName(cmd.Arg(1)) - serviceID, err := lookupServiceID(cli, nn, sn) - if err != nil { - return err - } - - nc := serviceAttach{SandboxID: sandboxID} - - _, _, err = readBody(cli.call("POST", "/services/"+serviceID+"/backend", nc, nil)) - - return err -} - -// CmdServiceDetach handles service detach UI -func (cli *NetworkCli) CmdServiceDetach(chain string, args ...string) error { - cmd := cli.Subcmd(chain, "detach", "CONTAINER SERVICE", "Removes a container from service backend", false) - cmd.Require(flag.Min, 2) - err := cmd.ParseFlags(args, true) - if err != nil { - return err - } - - sn, nn := parseServiceName(cmd.Arg(1)) - containerID, err := lookupContainerID(cli, cmd.Arg(0)) - if err != nil { - return err - } - - sandboxID, err := lookupSandboxID(cli, containerID) - if err != nil { - return err - } - - serviceID, err := lookupServiceID(cli, nn, sn) - if err != nil { - return err - } - - _, _, err = readBody(cli.call("DELETE", "/services/"+serviceID+"/backend/"+sandboxID, nil, nil)) - if err != nil { - return err - } - return nil -} - -func serviceUsage(chain string) string { - help := "Commands:\n" - - for _, cmd := range serviceCommands { - help += fmt.Sprintf(" %-10.10s%s\n", cmd.name, cmd.description) - } - - help += fmt.Sprintf("\nRun '%s service COMMAND --help' for more information on a command.", chain) - return help -} diff --git a/components/engine/vendor/src/github.com/docker/libnetwork/client/types.go b/components/engine/vendor/src/github.com/docker/libnetwork/client/types.go deleted file mode 100644 index 1848884509..0000000000 --- a/components/engine/vendor/src/github.com/docker/libnetwork/client/types.go +++ /dev/null @@ -1,79 +0,0 @@ -package client - -import "github.com/docker/libnetwork/types" - -/*********** - Resources -************/ - -// networkResource is the body of the "get network" http response message -type networkResource struct { - Name string `json:"name"` - ID string `json:"id"` - Type string `json:"type"` - Services []*serviceResource `json:"services"` -} - -// serviceResource is the body of the "get service" http response message -type serviceResource struct { - Name string `json:"name"` - ID string `json:"id"` - Network string `json:"network"` -} - -// SandboxResource is the body of "get service backend" response message -type SandboxResource struct { - ID string `json:"id"` - Key string `json:"key"` - ContainerID string `json:"container_id"` -} - -/*********** - Body types - ************/ - -// networkCreate is the expected body of the "create network" http request message -type networkCreate struct { - Name string `json:"name"` - NetworkType string `json:"network_type"` - Options map[string]interface{} `json:"options"` -} - -// serviceCreate represents the body of the "publish service" http request message -type serviceCreate struct { - Name string `json:"name"` - Network string `json:"network_name"` - ExposedPorts []types.TransportPort `json:"exposed_ports"` - PortMapping []types.PortBinding `json:"port_mapping"` -} - -// serviceAttach represents the expected body of the "attach/detach sandbox to/from service" http request messages -type serviceAttach struct { - SandboxID string `json:"sandbox_id"` -} - -// SandboxCreate is the body of the "post /sandboxes" http request message -type SandboxCreate struct { - ContainerID string `json:"container_id"` - HostName string `json:"host_name"` - DomainName string `json:"domain_name"` - HostsPath string `json:"hosts_path"` - ResolvConfPath string `json:"resolv_conf_path"` - DNS []string `json:"dns"` - ExtraHosts []extraHost `json:"extra_hosts"` - UseDefaultSandbox bool `json:"use_default_sandbox"` -} - -// extraHost represents the extra host object -type extraHost struct { - Name string `json:"name"` - Address string `json:"address"` -} - -// sandboxParentUpdate is the object carrying the information about the -// sanbox parent that needs to be updated -type sandboxParentUpdate struct { - ContainerID string `json:"container_id"` - Name string `json:"name"` - Address string `json:"address"` -}