Browse code

Network UX and integration tests

* Exiting experimental network UX
* removed experimental service UX
* integrated with the new network remote API

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

Madhu Venugopal authored on 2015/09/27 20:09:27
Showing 10 changed files
... ...
@@ -1,14 +1,207 @@
1
-// +build experimental
2
-
3 1
 package client
4 2
 
5 3
 import (
6
-	nwclient "github.com/docker/libnetwork/client"
4
+	"bytes"
5
+	"encoding/json"
6
+	"fmt"
7
+	"io"
8
+	"text/tabwriter"
9
+
10
+	"github.com/docker/docker/api/types"
11
+	Cli "github.com/docker/docker/cli"
12
+	flag "github.com/docker/docker/pkg/mflag"
13
+	"github.com/docker/docker/pkg/stringid"
7 14
 )
8 15
 
9
-// CmdNetwork is used to create, display and configure network endpoints.
16
+// CmdNetwork is the parent subcommand for all network commands
17
+//
18
+// Usage: docker network <COMMAND> [OPTIONS]
10 19
 func (cli *DockerCli) CmdNetwork(args ...string) error {
11
-	nCli := nwclient.NewNetworkCli(cli.out, cli.err, nwclient.CallFunc(cli.callWrapper))
12
-	args = append([]string{"network"}, args...)
13
-	return nCli.Cmd("docker", args...)
20
+	cmd := Cli.Subcmd("network", []string{"COMMAND [OPTIONS]"}, networkUsage(), false)
21
+	cmd.Require(flag.Min, 1)
22
+	err := cmd.ParseFlags(args, true)
23
+	cmd.Usage()
24
+	return err
25
+}
26
+
27
+// CmdNetworkCreate creates a new network with a given name
28
+//
29
+// Usage: docker network create [OPTIONS] <NETWORK-NAME>
30
+func (cli *DockerCli) CmdNetworkCreate(args ...string) error {
31
+	cmd := Cli.Subcmd("network create", []string{"NETWORK-NAME"}, "Creates a new network with a name specified by the user", false)
32
+	flDriver := cmd.String([]string{"d", "-driver"}, "", "Driver to manage the Network")
33
+	cmd.Require(flag.Exact, 1)
34
+	err := cmd.ParseFlags(args, true)
35
+	if err != nil {
36
+		return err
37
+	}
38
+
39
+	// Construct network create request body
40
+	nc := types.NetworkCreate{Name: cmd.Arg(0), Driver: *flDriver, CheckDuplicate: true}
41
+	obj, _, err := readBody(cli.call("POST", "/networks/create", nc, nil))
42
+	if err != nil {
43
+		return err
44
+	}
45
+	var resp types.NetworkCreateResponse
46
+	err = json.Unmarshal(obj, &resp)
47
+	if err != nil {
48
+		return err
49
+	}
50
+	fmt.Fprintf(cli.out, "%s\n", resp.ID)
51
+	return nil
52
+}
53
+
54
+// CmdNetworkRm deletes a network
55
+//
56
+// Usage: docker network rm <NETWORK-NAME | NETWORK-ID>
57
+func (cli *DockerCli) CmdNetworkRm(args ...string) error {
58
+	cmd := Cli.Subcmd("network rm", []string{"NETWORK"}, "Deletes a network", false)
59
+	cmd.Require(flag.Exact, 1)
60
+	err := cmd.ParseFlags(args, true)
61
+	if err != nil {
62
+		return err
63
+	}
64
+	_, _, err = readBody(cli.call("DELETE", "/networks/"+cmd.Arg(0), nil, nil))
65
+	if err != nil {
66
+		return err
67
+	}
68
+	return nil
69
+}
70
+
71
+// CmdNetworkConnect connects a container to a network
72
+//
73
+// Usage: docker network connect <NETWORK> <CONTAINER>
74
+func (cli *DockerCli) CmdNetworkConnect(args ...string) error {
75
+	cmd := Cli.Subcmd("network connect", []string{"NETWORK CONTAINER"}, "Connects a container to a network", false)
76
+	cmd.Require(flag.Exact, 2)
77
+	err := cmd.ParseFlags(args, true)
78
+	if err != nil {
79
+		return err
80
+	}
81
+
82
+	nc := types.NetworkConnect{Container: cmd.Arg(1)}
83
+	_, _, err = readBody(cli.call("POST", "/networks/"+cmd.Arg(0)+"/connect", nc, nil))
84
+	return err
85
+}
86
+
87
+// CmdNetworkDisconnect disconnects a container from a network
88
+//
89
+// Usage: docker network disconnect <NETWORK> <CONTAINER>
90
+func (cli *DockerCli) CmdNetworkDisconnect(args ...string) error {
91
+	cmd := Cli.Subcmd("network disconnect", []string{"NETWORK CONTAINER"}, "Disconnects container from a network", false)
92
+	cmd.Require(flag.Exact, 2)
93
+	err := cmd.ParseFlags(args, true)
94
+	if err != nil {
95
+		return err
96
+	}
97
+
98
+	nc := types.NetworkConnect{Container: cmd.Arg(1)}
99
+	_, _, err = readBody(cli.call("POST", "/networks/"+cmd.Arg(0)+"/disconnect", nc, nil))
100
+	return err
101
+}
102
+
103
+// CmdNetworkLs lists all the netorks managed by docker daemon
104
+//
105
+// Usage: docker network ls [OPTIONS]
106
+func (cli *DockerCli) CmdNetworkLs(args ...string) error {
107
+	cmd := Cli.Subcmd("network ls", []string{""}, "Lists all the networks created by the user", false)
108
+	quiet := cmd.Bool([]string{"q", "-quiet"}, false, "Only display numeric IDs")
109
+	noTrunc := cmd.Bool([]string{"", "-no-trunc"}, false, "Do not truncate the output")
110
+	nLatest := cmd.Bool([]string{"l", "-latest"}, false, "Show the latest network created")
111
+	last := cmd.Int([]string{"n"}, -1, "Show n last created networks")
112
+	err := cmd.ParseFlags(args, true)
113
+	if err != nil {
114
+		return err
115
+	}
116
+	obj, _, err := readBody(cli.call("GET", "/networks", nil, nil))
117
+	if err != nil {
118
+		return err
119
+	}
120
+	if *last == -1 && *nLatest {
121
+		*last = 1
122
+	}
123
+
124
+	var networkResources []types.NetworkResource
125
+	err = json.Unmarshal(obj, &networkResources)
126
+	if err != nil {
127
+		return err
128
+	}
129
+
130
+	wr := tabwriter.NewWriter(cli.out, 20, 1, 3, ' ', 0)
131
+
132
+	// unless quiet (-q) is specified, print field titles
133
+	if !*quiet {
134
+		fmt.Fprintln(wr, "NETWORK ID\tNAME\tDRIVER")
135
+	}
136
+
137
+	for _, networkResource := range networkResources {
138
+		ID := networkResource.ID
139
+		netName := networkResource.Name
140
+		if !*noTrunc {
141
+			ID = stringid.TruncateID(ID)
142
+		}
143
+		if *quiet {
144
+			fmt.Fprintln(wr, ID)
145
+			continue
146
+		}
147
+		driver := networkResource.Driver
148
+		fmt.Fprintf(wr, "%s\t%s\t%s\t",
149
+			ID,
150
+			netName,
151
+			driver)
152
+		fmt.Fprint(wr, "\n")
153
+	}
154
+	wr.Flush()
155
+	return nil
156
+}
157
+
158
+// CmdNetworkInspect inspects the network object for more details
159
+//
160
+// Usage: docker network inspect <NETWORK>
161
+// CmdNetworkInspect handles Network inspect UI
162
+func (cli *DockerCli) CmdNetworkInspect(args ...string) error {
163
+	cmd := Cli.Subcmd("network inspect", []string{"NETWORK"}, "Displays detailed information on a network", false)
164
+	cmd.Require(flag.Exact, 1)
165
+	err := cmd.ParseFlags(args, true)
166
+	if err != nil {
167
+		return err
168
+	}
169
+
170
+	obj, _, err := readBody(cli.call("GET", "/networks/"+cmd.Arg(0), nil, nil))
171
+	if err != nil {
172
+		return err
173
+	}
174
+	networkResource := &types.NetworkResource{}
175
+	if err := json.NewDecoder(bytes.NewReader(obj)).Decode(networkResource); err != nil {
176
+		return err
177
+	}
178
+
179
+	indented := new(bytes.Buffer)
180
+	if err := json.Indent(indented, obj, "", "    "); err != nil {
181
+		return err
182
+	}
183
+	if _, err := io.Copy(cli.out, indented); err != nil {
184
+		return err
185
+	}
186
+	return nil
187
+}
188
+
189
+func networkUsage() string {
190
+	networkCommands := map[string]string{
191
+		"create":     "Create a network",
192
+		"connect":    "Connect container to a network",
193
+		"disconnect": "Disconnect container from a network",
194
+		"inspect":    "Display detailed network information",
195
+		"ls":         "List all networks",
196
+		"rm":         "Remove a network",
197
+	}
198
+
199
+	help := "Commands:\n"
200
+
201
+	for cmd, description := range networkCommands {
202
+		help += fmt.Sprintf("  %-25.25s%s\n", cmd, description)
203
+	}
204
+
205
+	help += fmt.Sprintf("\nRun 'docker network COMMAND --help' for more information on a command.")
206
+	return help
14 207
 }
15 208
deleted file mode 100644
... ...
@@ -1,17 +0,0 @@
1
-// +build experimental
2
-
3
-package client
4
-
5
-import (
6
-	"os"
7
-
8
-	nwclient "github.com/docker/libnetwork/client"
9
-)
10
-
11
-// CmdService is used to manage network services.
12
-// service command is user to publish, attach and list a service from a container.
13
-func (cli *DockerCli) CmdService(args ...string) error {
14
-	nCli := nwclient.NewNetworkCli(cli.out, cli.err, nwclient.CallFunc(cli.callWrapper))
15
-	args = append([]string{"service"}, args...)
16
-	return nCli.Cmd(os.Args[0], args...)
17
-}
18 1
deleted file mode 100644
... ...
@@ -1,113 +0,0 @@
1
-// +build experimental
2
-
3
-package main
4
-
5
-import (
6
-	"encoding/json"
7
-	"fmt"
8
-	"net/http"
9
-
10
-	"github.com/go-check/check"
11
-)
12
-
13
-func isServiceAvailable(c *check.C, name string, network string) bool {
14
-	status, body, err := sockRequest("GET", "/services", nil)
15
-	c.Assert(status, check.Equals, http.StatusOK)
16
-	c.Assert(err, check.IsNil)
17
-
18
-	var inspectJSON []struct {
19
-		Name    string
20
-		ID      string
21
-		Network string
22
-	}
23
-	if err = json.Unmarshal(body, &inspectJSON); err != nil {
24
-		c.Fatalf("unable to unmarshal response body: %v", err)
25
-	}
26
-	for _, s := range inspectJSON {
27
-		if s.Name == name && s.Network == network {
28
-			return true
29
-		}
30
-	}
31
-	return false
32
-
33
-}
34
-
35
-func isServiceNetworkAvailable(c *check.C, name string) bool {
36
-	status, body, err := sockRequest("GET", "/networks", nil)
37
-	c.Assert(status, check.Equals, http.StatusOK)
38
-	c.Assert(err, check.IsNil)
39
-
40
-	var inspectJSON []struct {
41
-		Name string
42
-		ID   string
43
-		Type string
44
-	}
45
-	if err = json.Unmarshal(body, &inspectJSON); err != nil {
46
-		c.Fatalf("unable to unmarshal response body: %v", err)
47
-	}
48
-	for _, n := range inspectJSON {
49
-		if n.Name == name {
50
-			return true
51
-		}
52
-	}
53
-	return false
54
-
55
-}
56
-
57
-func (s *DockerSuite) TestServiceApiCreateDelete(c *check.C) {
58
-	name := "testnetwork"
59
-	config := map[string]interface{}{
60
-		"name":         name,
61
-		"network_type": "bridge",
62
-	}
63
-
64
-	status, resp, err := sockRequest("POST", "/networks", config)
65
-	c.Assert(status, check.Equals, http.StatusCreated)
66
-	c.Assert(err, check.IsNil)
67
-
68
-	if !isServiceNetworkAvailable(c, name) {
69
-		c.Fatalf("Network %s not found", name)
70
-	}
71
-
72
-	var nid string
73
-	err = json.Unmarshal(resp, &nid)
74
-	if err != nil {
75
-		c.Fatal(err)
76
-	}
77
-
78
-	sname := "service1"
79
-	sconfig := map[string]interface{}{
80
-		"name":         sname,
81
-		"network_name": name,
82
-	}
83
-
84
-	status, resp, err = sockRequest("POST", "/services", sconfig)
85
-	c.Assert(status, check.Equals, http.StatusCreated)
86
-	c.Assert(err, check.IsNil)
87
-
88
-	if !isServiceAvailable(c, sname, name) {
89
-		c.Fatalf("Service %s.%s not found", sname, name)
90
-	}
91
-
92
-	var id string
93
-	err = json.Unmarshal(resp, &id)
94
-	if err != nil {
95
-		c.Fatal(err)
96
-	}
97
-
98
-	status, _, err = sockRequest("DELETE", fmt.Sprintf("/services/%s", id), nil)
99
-	c.Assert(status, check.Equals, http.StatusOK)
100
-	c.Assert(err, check.IsNil)
101
-
102
-	if isServiceAvailable(c, sname, name) {
103
-		c.Fatalf("Service %s.%s not deleted", sname, name)
104
-	}
105
-
106
-	status, _, err = sockRequest("DELETE", fmt.Sprintf("/networks/%s", nid), nil)
107
-	c.Assert(status, check.Equals, http.StatusOK)
108
-	c.Assert(err, check.IsNil)
109
-
110
-	if isNetworkAvailable(c, name) {
111
-		c.Fatalf("Network %s not deleted", name)
112
-	}
113
-}
... ...
@@ -1,10 +1,11 @@
1
-// +build experimental
2
-
3 1
 package main
4 2
 
5 3
 import (
4
+	"encoding/json"
5
+	"net"
6 6
 	"strings"
7 7
 
8
+	"github.com/docker/docker/api/types"
8 9
 	"github.com/go-check/check"
9 10
 )
10 11
 
... ...
@@ -31,6 +32,14 @@ func isNwPresent(c *check.C, name string) bool {
31 31
 	return false
32 32
 }
33 33
 
34
+func getNwResource(c *check.C, name string) *types.NetworkResource {
35
+	out, _ := dockerCmd(c, "network", "inspect", name)
36
+	nr := types.NetworkResource{}
37
+	err := json.Unmarshal([]byte(out), &nr)
38
+	c.Assert(err, check.IsNil)
39
+	return &nr
40
+}
41
+
34 42
 func (s *DockerSuite) TestDockerNetworkLsDefault(c *check.C) {
35 43
 	defaults := []string{"bridge", "host", "none"}
36 44
 	for _, nn := range defaults {
... ...
@@ -45,3 +54,45 @@ func (s *DockerSuite) TestDockerNetworkCreateDelete(c *check.C) {
45 45
 	dockerCmd(c, "network", "rm", "test")
46 46
 	assertNwNotAvailable(c, "test")
47 47
 }
48
+
49
+func (s *DockerSuite) TestDockerNetworkConnectDisconnect(c *check.C) {
50
+	dockerCmd(c, "network", "create", "test")
51
+	assertNwIsAvailable(c, "test")
52
+	nr := getNwResource(c, "test")
53
+
54
+	c.Assert(nr.Name, check.Equals, "test")
55
+	c.Assert(len(nr.Containers), check.Equals, 0)
56
+
57
+	// run a container
58
+	out, _ := dockerCmd(c, "run", "-d", "--name", "test", "busybox", "top")
59
+	c.Assert(waitRun("test"), check.IsNil)
60
+	containerID := strings.TrimSpace(out)
61
+
62
+	// connect the container to the test network
63
+	dockerCmd(c, "network", "connect", "test", containerID)
64
+
65
+	// inspect the network to make sure container is connected
66
+	nr = getNetworkResource(c, nr.ID)
67
+	c.Assert(len(nr.Containers), check.Equals, 1)
68
+	c.Assert(nr.Containers[containerID], check.NotNil)
69
+
70
+	// check if container IP matches network inspect
71
+	ip, _, err := net.ParseCIDR(nr.Containers[containerID].IPv4Address)
72
+	c.Assert(err, check.IsNil)
73
+	containerIP := findContainerIP(c, "test")
74
+	c.Assert(ip.String(), check.Equals, containerIP)
75
+
76
+	// disconnect container from the network
77
+	dockerCmd(c, "network", "disconnect", "test", containerID)
78
+	nr = getNwResource(c, "test")
79
+	c.Assert(nr.Name, check.Equals, "test")
80
+	c.Assert(len(nr.Containers), check.Equals, 0)
81
+
82
+	// check if network connect fails for inactive containers
83
+	dockerCmd(c, "stop", containerID)
84
+	_, _, err = dockerCmdWithError("network", "connect", "test", containerID)
85
+	c.Assert(err, check.NotNil)
86
+
87
+	dockerCmd(c, "network", "rm", "test")
88
+	assertNwNotAvailable(c, "test")
89
+}
... ...
@@ -18,7 +18,9 @@ import (
18 18
 	"sync"
19 19
 	"time"
20 20
 
21
+	"github.com/docker/docker/pkg/integration/checker"
21 22
 	"github.com/docker/docker/pkg/nat"
23
+	"github.com/docker/docker/runconfig"
22 24
 	"github.com/docker/libnetwork/resolvconf"
23 25
 	"github.com/go-check/check"
24 26
 )
... ...
@@ -3408,6 +3410,7 @@ func (s *DockerSuite) TestContainersInUserDefinedNetwork(c *check.C) {
3408 3408
 	testRequires(c, DaemonIsLinux)
3409 3409
 	dockerCmd(c, "network", "create", "-d", "bridge", "testnetwork")
3410 3410
 	dockerCmd(c, "run", "-d", "--net=testnetwork", "--name=first", "busybox", "top")
3411
+	c.Assert(waitRun("first"), check.IsNil)
3411 3412
 	dockerCmd(c, "run", "-t", "--net=testnetwork", "--name=second", "busybox", "ping", "-c", "1", "first")
3412 3413
 	dockerCmd(c, "stop", "first")
3413 3414
 	dockerCmd(c, "stop", "second")
... ...
@@ -3421,7 +3424,9 @@ func (s *DockerSuite) TestContainersInMultipleNetworks(c *check.C) {
3421 3421
 	dockerCmd(c, "network", "create", "-d", "bridge", "testnetwork2")
3422 3422
 	// Run and connect containers to testnetwork1
3423 3423
 	dockerCmd(c, "run", "-d", "--net=testnetwork1", "--name=first", "busybox", "top")
3424
+	c.Assert(waitRun("first"), check.IsNil)
3424 3425
 	dockerCmd(c, "run", "-d", "--net=testnetwork1", "--name=second", "busybox", "top")
3426
+	c.Assert(waitRun("second"), check.IsNil)
3425 3427
 	// Check connectivity between containers in testnetwork2
3426 3428
 	dockerCmd(c, "exec", "first", "ping", "-c", "1", "second.testnetwork1")
3427 3429
 	// Connect containers to testnetwork2
... ...
@@ -3440,9 +3445,11 @@ func (s *DockerSuite) TestContainersNetworkIsolation(c *check.C) {
3440 3440
 	// Create 2 networks using bridge driver
3441 3441
 	dockerCmd(c, "network", "create", "-d", "bridge", "testnetwork1")
3442 3442
 	dockerCmd(c, "network", "create", "-d", "bridge", "testnetwork2")
3443
-	// Run 1 containers in testnetwork1 and another in testnetwork2
3443
+	// Run 1 container in testnetwork1 and another in testnetwork2
3444 3444
 	dockerCmd(c, "run", "-d", "--net=testnetwork1", "--name=first", "busybox", "top")
3445
+	c.Assert(waitRun("first"), check.IsNil)
3445 3446
 	dockerCmd(c, "run", "-d", "--net=testnetwork2", "--name=second", "busybox", "top")
3447
+	c.Assert(waitRun("second"), check.IsNil)
3446 3448
 
3447 3449
 	// Check Isolation between containers : ping must fail
3448 3450
 	_, _, err := dockerCmdWithError("exec", "first", "ping", "-c", "1", "second")
... ...
@@ -3471,7 +3478,9 @@ func (s *DockerSuite) TestNetworkRmWithActiveContainers(c *check.C) {
3471 3471
 	dockerCmd(c, "network", "create", "-d", "bridge", "testnetwork1")
3472 3472
 	// Run and connect containers to testnetwork1
3473 3473
 	dockerCmd(c, "run", "-d", "--net=testnetwork1", "--name=first", "busybox", "top")
3474
+	c.Assert(waitRun("first"), check.IsNil)
3474 3475
 	dockerCmd(c, "run", "-d", "--net=testnetwork1", "--name=second", "busybox", "top")
3476
+	c.Assert(waitRun("second"), check.IsNil)
3475 3477
 	// Network delete with active containers must fail
3476 3478
 	_, _, err := dockerCmdWithError("network", "rm", "testnetwork1")
3477 3479
 	c.Assert(err, check.NotNil)
... ...
@@ -3492,7 +3501,9 @@ func (s *DockerSuite) TestContainerRestartInMultipleNetworks(c *check.C) {
3492 3492
 	dockerCmd(c, "network", "create", "-d", "bridge", "testnetwork2")
3493 3493
 	// Run and connect containers to testnetwork1
3494 3494
 	dockerCmd(c, "run", "-d", "--net=testnetwork1", "--name=first", "busybox", "top")
3495
+	c.Assert(waitRun("first"), check.IsNil)
3495 3496
 	dockerCmd(c, "run", "-d", "--net=testnetwork1", "--name=second", "busybox", "top")
3497
+	c.Assert(waitRun("second"), check.IsNil)
3496 3498
 	// Check connectivity between containers in testnetwork2
3497 3499
 	dockerCmd(c, "exec", "first", "ping", "-c", "1", "second.testnetwork1")
3498 3500
 	// Connect containers to testnetwork2
... ...
@@ -3523,6 +3534,7 @@ func (s *DockerSuite) TestContainerWithConflictingHostNetworks(c *check.C) {
3523 3523
 	testRequires(c, DaemonIsLinux)
3524 3524
 	// Run a container with --net=host
3525 3525
 	dockerCmd(c, "run", "-d", "--net=host", "--name=first", "busybox", "top")
3526
+	c.Assert(waitRun("first"), check.IsNil)
3526 3527
 
3527 3528
 	// Create a network using bridge driver
3528 3529
 	dockerCmd(c, "network", "create", "-d", "bridge", "testnetwork1")
... ...
@@ -3537,14 +3549,43 @@ func (s *DockerSuite) TestContainerWithConflictingHostNetworks(c *check.C) {
3537 3537
 func (s *DockerSuite) TestContainerWithConflictingSharedNetwork(c *check.C) {
3538 3538
 	testRequires(c, DaemonIsLinux)
3539 3539
 	dockerCmd(c, "run", "-d", "--name=first", "busybox", "top")
3540
+	c.Assert(waitRun("first"), check.IsNil)
3540 3541
 	// Run second container in first container's network namespace
3541 3542
 	dockerCmd(c, "run", "-d", "--net=container:first", "--name=second", "busybox", "top")
3543
+	c.Assert(waitRun("second"), check.IsNil)
3542 3544
 
3543 3545
 	// Create a network using bridge driver
3544 3546
 	dockerCmd(c, "network", "create", "-d", "bridge", "testnetwork1")
3545 3547
 
3546 3548
 	// Connecting to the user defined network must fail
3547
-	_, _, err := dockerCmdWithError("network", "connect", "testnetwork1", "second")
3549
+	out, _, err := dockerCmdWithError("network", "connect", "testnetwork1", "second")
3550
+	c.Assert(err, check.NotNil)
3551
+	c.Assert(out, checker.Contains, runconfig.ErrConflictSharedNetwork.Error())
3552
+
3553
+	dockerCmd(c, "stop", "first")
3554
+	dockerCmd(c, "stop", "second")
3555
+	dockerCmd(c, "network", "rm", "testnetwork1")
3556
+}
3557
+
3558
+func (s *DockerSuite) TestContainerWithConflictingNoneNetwork(c *check.C) {
3559
+	testRequires(c, DaemonIsLinux)
3560
+	dockerCmd(c, "run", "-d", "--net=none", "--name=first", "busybox", "top")
3561
+	c.Assert(waitRun("first"), check.IsNil)
3562
+
3563
+	// Create a network using bridge driver
3564
+	dockerCmd(c, "network", "create", "-d", "bridge", "testnetwork1")
3565
+
3566
+	// Connecting to the user defined network must fail
3567
+	out, _, err := dockerCmdWithError("network", "connect", "testnetwork1", "first")
3568
+	c.Assert(err, check.NotNil)
3569
+	c.Assert(out, checker.Contains, runconfig.ErrConflictNoNetwork.Error())
3570
+
3571
+	// create a container connected to testnetwork1
3572
+	dockerCmd(c, "run", "-d", "--net=testnetwork1", "--name=second", "busybox", "top")
3573
+	c.Assert(waitRun("second"), check.IsNil)
3574
+
3575
+	// Connect second container to none network. it must fail as well
3576
+	_, _, err = dockerCmdWithError("network", "connect", "none", "second")
3548 3577
 	c.Assert(err, check.NotNil)
3549 3578
 
3550 3579
 	dockerCmd(c, "stop", "first")
3551 3580
deleted file mode 100644
... ...
@@ -1,69 +0,0 @@
1
-// +build experimental
2
-
3
-package main
4
-
5
-import (
6
-	"fmt"
7
-	"strings"
8
-
9
-	"github.com/go-check/check"
10
-)
11
-
12
-func assertSrvIsAvailable(c *check.C, sname, name string) {
13
-	if !isSrvPresent(c, sname, name) {
14
-		c.Fatalf("Service %s on network %s not found in service ls o/p", sname, name)
15
-	}
16
-}
17
-
18
-func assertSrvNotAvailable(c *check.C, sname, name string) {
19
-	if isSrvPresent(c, sname, name) {
20
-		c.Fatalf("Found service %s on network %s in service ls o/p", sname, name)
21
-	}
22
-}
23
-
24
-func isSrvPresent(c *check.C, sname, name string) bool {
25
-	out, _, _ := dockerCmdWithStdoutStderr(c, "service", "ls")
26
-	lines := strings.Split(out, "\n")
27
-	for i := 1; i < len(lines)-1; i++ {
28
-		if strings.Contains(lines[i], sname) && strings.Contains(lines[i], name) {
29
-			return true
30
-		}
31
-	}
32
-	return false
33
-}
34
-
35
-func isCntPresent(c *check.C, cname, sname, name string) bool {
36
-	out, _, _ := dockerCmdWithStdoutStderr(c, "service", "ls", "--no-trunc")
37
-	lines := strings.Split(out, "\n")
38
-	for i := 1; i < len(lines)-1; i++ {
39
-		fmt.Println(lines)
40
-		if strings.Contains(lines[i], name) && strings.Contains(lines[i], sname) && strings.Contains(lines[i], cname) {
41
-			return true
42
-		}
43
-	}
44
-	return false
45
-}
46
-
47
-func (s *DockerSuite) TestDockerServiceCreateDelete(c *check.C) {
48
-	dockerCmdWithStdoutStderr(c, "network", "create", "test")
49
-	assertNwIsAvailable(c, "test")
50
-
51
-	dockerCmdWithStdoutStderr(c, "service", "publish", "s1.test")
52
-	assertSrvIsAvailable(c, "s1", "test")
53
-
54
-	dockerCmdWithStdoutStderr(c, "service", "unpublish", "s1.test")
55
-	assertSrvNotAvailable(c, "s1", "test")
56
-
57
-	dockerCmdWithStdoutStderr(c, "network", "rm", "test")
58
-	assertNwNotAvailable(c, "test")
59
-}
60
-
61
-func (s *DockerSuite) TestDockerPublishServiceFlag(c *check.C) {
62
-	// Run saying the container is the backend for the specified service on the specified network
63
-	out, _ := dockerCmd(c, "run", "-d", "--expose=23", "--publish-service", "telnet.production", "busybox", "top")
64
-	cid := strings.TrimSpace(out)
65
-
66
-	// Verify container is attached in service ps o/p
67
-	assertSrvIsAvailable(c, "telnet", "production")
68
-	dockerCmd(c, "rm", "-f", cid)
69
-}
70 1
deleted file mode 100644
... ...
@@ -1,115 +0,0 @@
1
-package client
2
-
3
-import (
4
-	"fmt"
5
-	"io"
6
-	"io/ioutil"
7
-	"net/http"
8
-	"reflect"
9
-	"strings"
10
-
11
-	flag "github.com/docker/docker/pkg/mflag"
12
-)
13
-
14
-// CallFunc provides environment specific call utility to invoke backend functions from UI
15
-type CallFunc func(string, string, interface{}, map[string][]string) (io.ReadCloser, http.Header, int, error)
16
-
17
-// NetworkCli is the UI object for network subcmds
18
-type NetworkCli struct {
19
-	out  io.Writer
20
-	err  io.Writer
21
-	call CallFunc
22
-}
23
-
24
-// NewNetworkCli is a convenient function to create a NetworkCli object
25
-func NewNetworkCli(out, err io.Writer, call CallFunc) *NetworkCli {
26
-	return &NetworkCli{
27
-		out:  out,
28
-		err:  err,
29
-		call: call,
30
-	}
31
-}
32
-
33
-// getMethod is Borrowed from Docker UI which uses reflection to identify the UI Handler
34
-func (cli *NetworkCli) getMethod(args ...string) (func(string, ...string) error, bool) {
35
-	camelArgs := make([]string, len(args))
36
-	for i, s := range args {
37
-		if len(s) == 0 {
38
-			return nil, false
39
-		}
40
-		camelArgs[i] = strings.ToUpper(s[:1]) + strings.ToLower(s[1:])
41
-	}
42
-	methodName := "Cmd" + strings.Join(camelArgs, "")
43
-	method := reflect.ValueOf(cli).MethodByName(methodName)
44
-	if !method.IsValid() {
45
-		return nil, false
46
-	}
47
-	return method.Interface().(func(string, ...string) error), true
48
-}
49
-
50
-// Cmd is borrowed from Docker UI and acts as the entry point for network UI commands.
51
-// network UI commands are designed to be invoked from multiple parent chains
52
-func (cli *NetworkCli) Cmd(chain string, args ...string) error {
53
-	if len(args) > 2 {
54
-		method, exists := cli.getMethod(args[:3]...)
55
-		if exists {
56
-			return method(chain+" "+args[0]+" "+args[1], args[3:]...)
57
-		}
58
-	}
59
-	if len(args) > 1 {
60
-		method, exists := cli.getMethod(args[:2]...)
61
-		if exists {
62
-			return method(chain+" "+args[0], args[2:]...)
63
-		}
64
-	}
65
-	if len(args) > 0 {
66
-		method, exists := cli.getMethod(args[0])
67
-		if !exists {
68
-			return fmt.Errorf("%s: '%s' is not a %s command. See '%s --help'.\n", chain, args[0], chain, chain)
69
-		}
70
-		return method(chain, args[1:]...)
71
-	}
72
-	flag.Usage()
73
-	return nil
74
-}
75
-
76
-// Subcmd is borrowed from Docker UI and performs the same function of configuring the subCmds
77
-func (cli *NetworkCli) Subcmd(chain, name, signature, description string, exitOnError bool) *flag.FlagSet {
78
-	var errorHandling flag.ErrorHandling
79
-	if exitOnError {
80
-		errorHandling = flag.ExitOnError
81
-	} else {
82
-		errorHandling = flag.ContinueOnError
83
-	}
84
-	flags := flag.NewFlagSet(name, errorHandling)
85
-	flags.Usage = func() {
86
-		flags.ShortUsage()
87
-		flags.PrintDefaults()
88
-	}
89
-	flags.ShortUsage = func() {
90
-		options := ""
91
-		if signature != "" {
92
-			signature = " " + signature
93
-		}
94
-		if flags.FlagCountUndeprecated() > 0 {
95
-			options = " [OPTIONS]"
96
-		}
97
-		fmt.Fprintf(cli.out, "\nUsage: %s %s%s%s\n\n%s\n\n", chain, name, options, signature, description)
98
-		flags.SetOutput(cli.out)
99
-	}
100
-	return flags
101
-}
102
-
103
-func readBody(stream io.ReadCloser, hdr http.Header, statusCode int, err error) ([]byte, int, error) {
104
-	if stream != nil {
105
-		defer stream.Close()
106
-	}
107
-	if err != nil {
108
-		return nil, statusCode, err
109
-	}
110
-	body, err := ioutil.ReadAll(stream)
111
-	if err != nil {
112
-		return nil, -1, err
113
-	}
114
-	return body, statusCode, nil
115
-}
116 1
deleted file mode 100644
... ...
@@ -1,231 +0,0 @@
1
-package client
2
-
3
-import (
4
-	"bytes"
5
-	"encoding/json"
6
-	"fmt"
7
-	"net/http"
8
-	"text/tabwriter"
9
-
10
-	flag "github.com/docker/docker/pkg/mflag"
11
-	"github.com/docker/docker/pkg/stringid"
12
-)
13
-
14
-type command struct {
15
-	name        string
16
-	description string
17
-}
18
-
19
-var (
20
-	networkCommands = []command{
21
-		{"create", "Create a network"},
22
-		{"rm", "Remove a network"},
23
-		{"ls", "List all networks"},
24
-		{"info", "Display information of a network"},
25
-	}
26
-)
27
-
28
-// CmdNetwork handles the root Network UI
29
-func (cli *NetworkCli) CmdNetwork(chain string, args ...string) error {
30
-	cmd := cli.Subcmd(chain, "network", "COMMAND [OPTIONS] [arg...]", networkUsage(chain), false)
31
-	cmd.Require(flag.Min, 1)
32
-	err := cmd.ParseFlags(args, true)
33
-	if err == nil {
34
-		cmd.Usage()
35
-		return fmt.Errorf("invalid command : %v", args)
36
-	}
37
-	return err
38
-}
39
-
40
-// CmdNetworkCreate handles Network Create UI
41
-func (cli *NetworkCli) CmdNetworkCreate(chain string, args ...string) error {
42
-	cmd := cli.Subcmd(chain, "create", "NETWORK-NAME", "Creates a new network with a name specified by the user", false)
43
-	flDriver := cmd.String([]string{"d", "-driver"}, "", "Driver to manage the Network")
44
-	cmd.Require(flag.Exact, 1)
45
-	err := cmd.ParseFlags(args, true)
46
-	if err != nil {
47
-		return err
48
-	}
49
-
50
-	// Construct network create request body
51
-	ops := make(map[string]interface{})
52
-	nc := networkCreate{Name: cmd.Arg(0), NetworkType: *flDriver, Options: ops}
53
-	obj, _, err := readBody(cli.call("POST", "/networks", nc, nil))
54
-	if err != nil {
55
-		return err
56
-	}
57
-	var replyID string
58
-	err = json.Unmarshal(obj, &replyID)
59
-	if err != nil {
60
-		return err
61
-	}
62
-	fmt.Fprintf(cli.out, "%s\n", replyID)
63
-	return nil
64
-}
65
-
66
-// CmdNetworkRm handles Network Delete UI
67
-func (cli *NetworkCli) CmdNetworkRm(chain string, args ...string) error {
68
-	cmd := cli.Subcmd(chain, "rm", "NETWORK", "Deletes a network", false)
69
-	cmd.Require(flag.Exact, 1)
70
-	err := cmd.ParseFlags(args, true)
71
-	if err != nil {
72
-		return err
73
-	}
74
-	id, err := lookupNetworkID(cli, cmd.Arg(0))
75
-	if err != nil {
76
-		return err
77
-	}
78
-	_, _, err = readBody(cli.call("DELETE", "/networks/"+id, nil, nil))
79
-	if err != nil {
80
-		return err
81
-	}
82
-	return nil
83
-}
84
-
85
-// CmdNetworkLs handles Network List UI
86
-func (cli *NetworkCli) CmdNetworkLs(chain string, args ...string) error {
87
-	cmd := cli.Subcmd(chain, "ls", "", "Lists all the networks created by the user", false)
88
-	quiet := cmd.Bool([]string{"q", "-quiet"}, false, "Only display numeric IDs")
89
-	noTrunc := cmd.Bool([]string{"#notrunc", "-no-trunc"}, false, "Do not truncate the output")
90
-	nLatest := cmd.Bool([]string{"l", "-latest"}, false, "Show the latest network created")
91
-	last := cmd.Int([]string{"n"}, -1, "Show n last created networks")
92
-	err := cmd.ParseFlags(args, true)
93
-	if err != nil {
94
-		return err
95
-	}
96
-	obj, _, err := readBody(cli.call("GET", "/networks", nil, nil))
97
-	if err != nil {
98
-		return err
99
-	}
100
-	if *last == -1 && *nLatest {
101
-		*last = 1
102
-	}
103
-
104
-	var networkResources []networkResource
105
-	err = json.Unmarshal(obj, &networkResources)
106
-	if err != nil {
107
-		return err
108
-	}
109
-
110
-	wr := tabwriter.NewWriter(cli.out, 20, 1, 3, ' ', 0)
111
-
112
-	// unless quiet (-q) is specified, print field titles
113
-	if !*quiet {
114
-		fmt.Fprintln(wr, "NETWORK ID\tNAME\tTYPE")
115
-	}
116
-
117
-	for _, networkResource := range networkResources {
118
-		ID := networkResource.ID
119
-		netName := networkResource.Name
120
-		if !*noTrunc {
121
-			ID = stringid.TruncateID(ID)
122
-		}
123
-		if *quiet {
124
-			fmt.Fprintln(wr, ID)
125
-			continue
126
-		}
127
-		netType := networkResource.Type
128
-		fmt.Fprintf(wr, "%s\t%s\t%s\t",
129
-			ID,
130
-			netName,
131
-			netType)
132
-		fmt.Fprint(wr, "\n")
133
-	}
134
-	wr.Flush()
135
-	return nil
136
-}
137
-
138
-// CmdNetworkInfo handles Network Info UI
139
-func (cli *NetworkCli) CmdNetworkInfo(chain string, args ...string) error {
140
-	cmd := cli.Subcmd(chain, "info", "NETWORK", "Displays detailed information on a network", false)
141
-	cmd.Require(flag.Exact, 1)
142
-	err := cmd.ParseFlags(args, true)
143
-	if err != nil {
144
-		return err
145
-	}
146
-
147
-	id, err := lookupNetworkID(cli, cmd.Arg(0))
148
-	if err != nil {
149
-		return err
150
-	}
151
-
152
-	obj, _, err := readBody(cli.call("GET", "/networks/"+id, nil, nil))
153
-	if err != nil {
154
-		return err
155
-	}
156
-	networkResource := &networkResource{}
157
-	if err := json.NewDecoder(bytes.NewReader(obj)).Decode(networkResource); err != nil {
158
-		return err
159
-	}
160
-	fmt.Fprintf(cli.out, "Network Id: %s\n", networkResource.ID)
161
-	fmt.Fprintf(cli.out, "Name: %s\n", networkResource.Name)
162
-	fmt.Fprintf(cli.out, "Type: %s\n", networkResource.Type)
163
-	if networkResource.Services != nil {
164
-		for _, serviceResource := range networkResource.Services {
165
-			fmt.Fprintf(cli.out, "  Service Id: %s\n", serviceResource.ID)
166
-			fmt.Fprintf(cli.out, "\tName: %s\n", serviceResource.Name)
167
-		}
168
-	}
169
-
170
-	return nil
171
-}
172
-
173
-// Helper function to predict if a string is a name or id or partial-id
174
-// This provides a best-effort mechanism to identify a id with the help of GET Filter APIs
175
-// Being a UI, its most likely that name will be used by the user, which is used to lookup
176
-// the corresponding ID. If ID is not found, this function will assume that the passed string
177
-// is an ID by itself.
178
-
179
-func lookupNetworkID(cli *NetworkCli, nameID string) (string, error) {
180
-	obj, statusCode, err := readBody(cli.call("GET", "/networks?name="+nameID, nil, nil))
181
-	if err != nil {
182
-		return "", err
183
-	}
184
-
185
-	if statusCode != http.StatusOK {
186
-		return "", fmt.Errorf("name query failed for %s due to : statuscode(%d) %v", nameID, statusCode, string(obj))
187
-	}
188
-
189
-	var list []*networkResource
190
-	err = json.Unmarshal(obj, &list)
191
-	if err != nil {
192
-		return "", err
193
-	}
194
-	if len(list) > 0 {
195
-		// name query filter will always return a single-element collection
196
-		return list[0].ID, nil
197
-	}
198
-
199
-	// Check for Partial-id
200
-	obj, statusCode, err = readBody(cli.call("GET", "/networks?partial-id="+nameID, nil, nil))
201
-	if err != nil {
202
-		return "", err
203
-	}
204
-
205
-	if statusCode != http.StatusOK {
206
-		return "", fmt.Errorf("partial-id match query failed for %s due to : statuscode(%d) %v", nameID, statusCode, string(obj))
207
-	}
208
-
209
-	err = json.Unmarshal(obj, &list)
210
-	if err != nil {
211
-		return "", err
212
-	}
213
-	if len(list) == 0 {
214
-		return "", fmt.Errorf("resource not found %s", nameID)
215
-	}
216
-	if len(list) > 1 {
217
-		return "", fmt.Errorf("multiple Networks matching the partial identifier (%s). Please use full identifier", nameID)
218
-	}
219
-	return list[0].ID, nil
220
-}
221
-
222
-func networkUsage(chain string) string {
223
-	help := "Commands:\n"
224
-
225
-	for _, cmd := range networkCommands {
226
-		help += fmt.Sprintf("  %-25.25s%s\n", cmd.name, cmd.description)
227
-	}
228
-
229
-	help += fmt.Sprintf("\nRun '%s network COMMAND --help' for more information on a command.", chain)
230
-	return help
231
-}
232 1
deleted file mode 100644
... ...
@@ -1,392 +0,0 @@
1
-package client
2
-
3
-import (
4
-	"bytes"
5
-	"encoding/json"
6
-	"fmt"
7
-	"net/http"
8
-	"strings"
9
-	"text/tabwriter"
10
-
11
-	flag "github.com/docker/docker/pkg/mflag"
12
-	"github.com/docker/docker/pkg/stringid"
13
-)
14
-
15
-var (
16
-	serviceCommands = []command{
17
-		{"publish", "Publish a service"},
18
-		{"unpublish", "Remove a service"},
19
-		{"attach", "Attach a backend (container) to the service"},
20
-		{"detach", "Detach the backend from the service"},
21
-		{"ls", "Lists all services"},
22
-		{"info", "Display information about a service"},
23
-	}
24
-)
25
-
26
-func lookupServiceID(cli *NetworkCli, nwName, svNameID string) (string, error) {
27
-	// Sanity Check
28
-	obj, _, err := readBody(cli.call("GET", fmt.Sprintf("/networks?name=%s", nwName), nil, nil))
29
-	if err != nil {
30
-		return "", err
31
-	}
32
-	var nwList []networkResource
33
-	if err = json.Unmarshal(obj, &nwList); err != nil {
34
-		return "", err
35
-	}
36
-	if len(nwList) == 0 {
37
-		return "", fmt.Errorf("Network %s does not exist", nwName)
38
-	}
39
-
40
-	if nwName == "" {
41
-		obj, _, err := readBody(cli.call("GET", "/networks/"+nwList[0].ID, nil, nil))
42
-		if err != nil {
43
-			return "", err
44
-		}
45
-		networkResource := &networkResource{}
46
-		if err := json.NewDecoder(bytes.NewReader(obj)).Decode(networkResource); err != nil {
47
-			return "", err
48
-		}
49
-		nwName = networkResource.Name
50
-	}
51
-
52
-	// Query service by name
53
-	obj, statusCode, err := readBody(cli.call("GET", fmt.Sprintf("/services?name=%s", svNameID), nil, nil))
54
-	if err != nil {
55
-		return "", err
56
-	}
57
-
58
-	if statusCode != http.StatusOK {
59
-		return "", fmt.Errorf("name query failed for %s due to: (%d) %s", svNameID, statusCode, string(obj))
60
-	}
61
-
62
-	var list []*serviceResource
63
-	if err = json.Unmarshal(obj, &list); err != nil {
64
-		return "", err
65
-	}
66
-	for _, sr := range list {
67
-		if sr.Network == nwName {
68
-			return sr.ID, nil
69
-		}
70
-	}
71
-
72
-	// Query service by Partial-id (this covers full id as well)
73
-	obj, statusCode, err = readBody(cli.call("GET", fmt.Sprintf("/services?partial-id=%s", svNameID), nil, nil))
74
-	if err != nil {
75
-		return "", err
76
-	}
77
-
78
-	if statusCode != http.StatusOK {
79
-		return "", fmt.Errorf("partial-id match query failed for %s due to: (%d) %s", svNameID, statusCode, string(obj))
80
-	}
81
-
82
-	if err = json.Unmarshal(obj, &list); err != nil {
83
-		return "", err
84
-	}
85
-	for _, sr := range list {
86
-		if sr.Network == nwName {
87
-			return sr.ID, nil
88
-		}
89
-	}
90
-
91
-	return "", fmt.Errorf("Service %s not found on network %s", svNameID, nwName)
92
-}
93
-
94
-func lookupContainerID(cli *NetworkCli, cnNameID string) (string, error) {
95
-	// Container is a Docker resource, ask docker about it.
96
-	// In case of connecton error, we assume we are running in dnet and return whatever was passed to us
97
-	obj, _, err := readBody(cli.call("GET", fmt.Sprintf("/containers/%s/json", cnNameID), nil, nil))
98
-	if err != nil {
99
-		// We are probably running outside of docker
100
-		return cnNameID, nil
101
-	}
102
-
103
-	var x map[string]interface{}
104
-	err = json.Unmarshal(obj, &x)
105
-	if err != nil {
106
-		return "", err
107
-	}
108
-	if iid, ok := x["Id"]; ok {
109
-		if id, ok := iid.(string); ok {
110
-			return id, nil
111
-		}
112
-		return "", fmt.Errorf("Unexpected data type for container ID in json response")
113
-	}
114
-	return "", fmt.Errorf("Cannot find container ID in json response")
115
-}
116
-
117
-func lookupSandboxID(cli *NetworkCli, containerID string) (string, error) {
118
-	obj, _, err := readBody(cli.call("GET", fmt.Sprintf("/sandboxes?partial-container-id=%s", containerID), nil, nil))
119
-	if err != nil {
120
-		return "", err
121
-	}
122
-
123
-	var sandboxList []SandboxResource
124
-	err = json.Unmarshal(obj, &sandboxList)
125
-	if err != nil {
126
-		return "", err
127
-	}
128
-
129
-	if len(sandboxList) == 0 {
130
-		return "", fmt.Errorf("cannot find sandbox for container: %s", containerID)
131
-	}
132
-
133
-	return sandboxList[0].ID, nil
134
-}
135
-
136
-// CmdService handles the service UI
137
-func (cli *NetworkCli) CmdService(chain string, args ...string) error {
138
-	cmd := cli.Subcmd(chain, "service", "COMMAND [OPTIONS] [arg...]", serviceUsage(chain), false)
139
-	cmd.Require(flag.Min, 1)
140
-	err := cmd.ParseFlags(args, true)
141
-	if err == nil {
142
-		cmd.Usage()
143
-		return fmt.Errorf("Invalid command : %v", args)
144
-	}
145
-	return err
146
-}
147
-
148
-// Parse service name for "SERVICE[.NETWORK]" format
149
-func parseServiceName(name string) (string, string) {
150
-	s := strings.Split(name, ".")
151
-	var sName, nName string
152
-	if len(s) > 1 {
153
-		nName = s[len(s)-1]
154
-		sName = strings.Join(s[:len(s)-1], ".")
155
-	} else {
156
-		sName = s[0]
157
-	}
158
-	return sName, nName
159
-}
160
-
161
-// CmdServicePublish handles service create UI
162
-func (cli *NetworkCli) CmdServicePublish(chain string, args ...string) error {
163
-	cmd := cli.Subcmd(chain, "publish", "SERVICE[.NETWORK]", "Publish a new service on a network", false)
164
-	cmd.Require(flag.Exact, 1)
165
-	err := cmd.ParseFlags(args, true)
166
-	if err != nil {
167
-		return err
168
-	}
169
-
170
-	sn, nn := parseServiceName(cmd.Arg(0))
171
-	sc := serviceCreate{Name: sn, Network: nn}
172
-	obj, _, err := readBody(cli.call("POST", "/services", sc, nil))
173
-	if err != nil {
174
-		return err
175
-	}
176
-
177
-	var replyID string
178
-	err = json.Unmarshal(obj, &replyID)
179
-	if err != nil {
180
-		return err
181
-	}
182
-
183
-	fmt.Fprintf(cli.out, "%s\n", replyID)
184
-	return nil
185
-}
186
-
187
-// CmdServiceUnpublish handles service delete UI
188
-func (cli *NetworkCli) CmdServiceUnpublish(chain string, args ...string) error {
189
-	cmd := cli.Subcmd(chain, "unpublish", "SERVICE[.NETWORK]", "Removes a service", false)
190
-	cmd.Require(flag.Exact, 1)
191
-	err := cmd.ParseFlags(args, true)
192
-	if err != nil {
193
-		return err
194
-	}
195
-
196
-	sn, nn := parseServiceName(cmd.Arg(0))
197
-	serviceID, err := lookupServiceID(cli, nn, sn)
198
-	if err != nil {
199
-		return err
200
-	}
201
-
202
-	_, _, err = readBody(cli.call("DELETE", "/services/"+serviceID, nil, nil))
203
-
204
-	return err
205
-}
206
-
207
-// CmdServiceLs handles service list UI
208
-func (cli *NetworkCli) CmdServiceLs(chain string, args ...string) error {
209
-	cmd := cli.Subcmd(chain, "ls", "SERVICE", "Lists all the services on a network", false)
210
-	flNetwork := cmd.String([]string{"net", "-network"}, "", "Only show the services that are published on the specified network")
211
-	quiet := cmd.Bool([]string{"q", "-quiet"}, false, "Only display numeric IDs")
212
-	noTrunc := cmd.Bool([]string{"#notrunc", "-no-trunc"}, false, "Do not truncate the output")
213
-
214
-	err := cmd.ParseFlags(args, true)
215
-	if err != nil {
216
-		return err
217
-	}
218
-
219
-	var obj []byte
220
-	if *flNetwork == "" {
221
-		obj, _, err = readBody(cli.call("GET", "/services", nil, nil))
222
-	} else {
223
-		obj, _, err = readBody(cli.call("GET", "/services?network="+*flNetwork, nil, nil))
224
-	}
225
-	if err != nil {
226
-		return err
227
-	}
228
-
229
-	var serviceResources []serviceResource
230
-	err = json.Unmarshal(obj, &serviceResources)
231
-	if err != nil {
232
-		fmt.Println(err)
233
-		return err
234
-	}
235
-
236
-	wr := tabwriter.NewWriter(cli.out, 20, 1, 3, ' ', 0)
237
-	// unless quiet (-q) is specified, print field titles
238
-	if !*quiet {
239
-		fmt.Fprintln(wr, "SERVICE ID\tNAME\tNETWORK\tCONTAINER\tSANDBOX")
240
-	}
241
-
242
-	for _, sr := range serviceResources {
243
-		ID := sr.ID
244
-		bkID, sbID, err := getBackendID(cli, ID)
245
-		if err != nil {
246
-			return err
247
-		}
248
-		if !*noTrunc {
249
-			ID = stringid.TruncateID(ID)
250
-			bkID = stringid.TruncateID(bkID)
251
-			sbID = stringid.TruncateID(sbID)
252
-		}
253
-		if !*quiet {
254
-			fmt.Fprintf(wr, "%s\t%s\t%s\t%s\t%s\n", ID, sr.Name, sr.Network, bkID, sbID)
255
-		} else {
256
-			fmt.Fprintln(wr, ID)
257
-		}
258
-	}
259
-	wr.Flush()
260
-
261
-	return nil
262
-}
263
-
264
-func getBackendID(cli *NetworkCli, servID string) (string, string, error) {
265
-	var (
266
-		obj []byte
267
-		err error
268
-		bk  string
269
-		sb  string
270
-	)
271
-
272
-	if obj, _, err = readBody(cli.call("GET", "/services/"+servID+"/backend", nil, nil)); err == nil {
273
-		var sr SandboxResource
274
-		if err := json.NewDecoder(bytes.NewReader(obj)).Decode(&sr); err == nil {
275
-			bk = sr.ContainerID
276
-			sb = sr.ID
277
-		} else {
278
-			// Only print a message, don't make the caller cli fail for this
279
-			fmt.Fprintf(cli.out, "Failed to retrieve backend list for service %s (%v)\n", servID, err)
280
-		}
281
-	}
282
-
283
-	return bk, sb, err
284
-}
285
-
286
-// CmdServiceInfo handles service info UI
287
-func (cli *NetworkCli) CmdServiceInfo(chain string, args ...string) error {
288
-	cmd := cli.Subcmd(chain, "info", "SERVICE[.NETWORK]", "Displays detailed information about a service", false)
289
-	cmd.Require(flag.Min, 1)
290
-
291
-	err := cmd.ParseFlags(args, true)
292
-	if err != nil {
293
-		return err
294
-	}
295
-
296
-	sn, nn := parseServiceName(cmd.Arg(0))
297
-	serviceID, err := lookupServiceID(cli, nn, sn)
298
-	if err != nil {
299
-		return err
300
-	}
301
-
302
-	obj, _, err := readBody(cli.call("GET", "/services/"+serviceID, nil, nil))
303
-	if err != nil {
304
-		return err
305
-	}
306
-
307
-	sr := &serviceResource{}
308
-	if err := json.NewDecoder(bytes.NewReader(obj)).Decode(sr); err != nil {
309
-		return err
310
-	}
311
-
312
-	fmt.Fprintf(cli.out, "Service Id: %s\n", sr.ID)
313
-	fmt.Fprintf(cli.out, "\tName: %s\n", sr.Name)
314
-	fmt.Fprintf(cli.out, "\tNetwork: %s\n", sr.Network)
315
-
316
-	return nil
317
-}
318
-
319
-// CmdServiceAttach handles service attach UI
320
-func (cli *NetworkCli) CmdServiceAttach(chain string, args ...string) error {
321
-	cmd := cli.Subcmd(chain, "attach", "CONTAINER SERVICE[.NETWORK]", "Sets a container as a service backend", false)
322
-	cmd.Require(flag.Min, 2)
323
-	err := cmd.ParseFlags(args, true)
324
-	if err != nil {
325
-		return err
326
-	}
327
-
328
-	containerID, err := lookupContainerID(cli, cmd.Arg(0))
329
-	if err != nil {
330
-		return err
331
-	}
332
-
333
-	sandboxID, err := lookupSandboxID(cli, containerID)
334
-	if err != nil {
335
-		return err
336
-	}
337
-
338
-	sn, nn := parseServiceName(cmd.Arg(1))
339
-	serviceID, err := lookupServiceID(cli, nn, sn)
340
-	if err != nil {
341
-		return err
342
-	}
343
-
344
-	nc := serviceAttach{SandboxID: sandboxID}
345
-
346
-	_, _, err = readBody(cli.call("POST", "/services/"+serviceID+"/backend", nc, nil))
347
-
348
-	return err
349
-}
350
-
351
-// CmdServiceDetach handles service detach UI
352
-func (cli *NetworkCli) CmdServiceDetach(chain string, args ...string) error {
353
-	cmd := cli.Subcmd(chain, "detach", "CONTAINER SERVICE", "Removes a container from service backend", false)
354
-	cmd.Require(flag.Min, 2)
355
-	err := cmd.ParseFlags(args, true)
356
-	if err != nil {
357
-		return err
358
-	}
359
-
360
-	sn, nn := parseServiceName(cmd.Arg(1))
361
-	containerID, err := lookupContainerID(cli, cmd.Arg(0))
362
-	if err != nil {
363
-		return err
364
-	}
365
-
366
-	sandboxID, err := lookupSandboxID(cli, containerID)
367
-	if err != nil {
368
-		return err
369
-	}
370
-
371
-	serviceID, err := lookupServiceID(cli, nn, sn)
372
-	if err != nil {
373
-		return err
374
-	}
375
-
376
-	_, _, err = readBody(cli.call("DELETE", "/services/"+serviceID+"/backend/"+sandboxID, nil, nil))
377
-	if err != nil {
378
-		return err
379
-	}
380
-	return nil
381
-}
382
-
383
-func serviceUsage(chain string) string {
384
-	help := "Commands:\n"
385
-
386
-	for _, cmd := range serviceCommands {
387
-		help += fmt.Sprintf("    %-10.10s%s\n", cmd.name, cmd.description)
388
-	}
389
-
390
-	help += fmt.Sprintf("\nRun '%s service COMMAND --help' for more information on a command.", chain)
391
-	return help
392
-}
393 1
deleted file mode 100644
... ...
@@ -1,79 +0,0 @@
1
-package client
2
-
3
-import "github.com/docker/libnetwork/types"
4
-
5
-/***********
6
- Resources
7
-************/
8
-
9
-// networkResource is the body of the "get network" http response message
10
-type networkResource struct {
11
-	Name     string             `json:"name"`
12
-	ID       string             `json:"id"`
13
-	Type     string             `json:"type"`
14
-	Services []*serviceResource `json:"services"`
15
-}
16
-
17
-// serviceResource is the body of the "get service" http response message
18
-type serviceResource struct {
19
-	Name    string `json:"name"`
20
-	ID      string `json:"id"`
21
-	Network string `json:"network"`
22
-}
23
-
24
-// SandboxResource is the body of "get service backend" response message
25
-type SandboxResource struct {
26
-	ID          string `json:"id"`
27
-	Key         string `json:"key"`
28
-	ContainerID string `json:"container_id"`
29
-}
30
-
31
-/***********
32
-  Body types
33
-  ************/
34
-
35
-// networkCreate is the expected body of the "create network" http request message
36
-type networkCreate struct {
37
-	Name        string                 `json:"name"`
38
-	NetworkType string                 `json:"network_type"`
39
-	Options     map[string]interface{} `json:"options"`
40
-}
41
-
42
-// serviceCreate represents the body of the "publish service" http request message
43
-type serviceCreate struct {
44
-	Name         string                `json:"name"`
45
-	Network      string                `json:"network_name"`
46
-	ExposedPorts []types.TransportPort `json:"exposed_ports"`
47
-	PortMapping  []types.PortBinding   `json:"port_mapping"`
48
-}
49
-
50
-// serviceAttach represents the expected body of the "attach/detach sandbox to/from service" http request messages
51
-type serviceAttach struct {
52
-	SandboxID string `json:"sandbox_id"`
53
-}
54
-
55
-// SandboxCreate is the body of the "post /sandboxes" http request message
56
-type SandboxCreate struct {
57
-	ContainerID       string      `json:"container_id"`
58
-	HostName          string      `json:"host_name"`
59
-	DomainName        string      `json:"domain_name"`
60
-	HostsPath         string      `json:"hosts_path"`
61
-	ResolvConfPath    string      `json:"resolv_conf_path"`
62
-	DNS               []string    `json:"dns"`
63
-	ExtraHosts        []extraHost `json:"extra_hosts"`
64
-	UseDefaultSandbox bool        `json:"use_default_sandbox"`
65
-}
66
-
67
-// extraHost represents the extra host object
68
-type extraHost struct {
69
-	Name    string `json:"name"`
70
-	Address string `json:"address"`
71
-}
72
-
73
-// sandboxParentUpdate is the object carrying the information about the
74
-// sanbox parent that needs to be updated
75
-type sandboxParentUpdate struct {
76
-	ContainerID string `json:"container_id"`
77
-	Name        string `json:"name"`
78
-	Address     string `json:"address"`
79
-}