Signed-off-by: Daniel Nephin <dnephin@docker.com>
| ... | ... |
@@ -69,9 +69,7 @@ func (s *DockerSwarmSuite) TestAPISwarmServicesCreate(c *check.C) {
|
| 69 | 69 |
c.Assert(err, checker.IsNil) |
| 70 | 70 |
defer cli.Close() |
| 71 | 71 |
|
| 72 |
- options := types.ServiceInspectOptions{
|
|
| 73 |
- InsertDefaults: true, |
|
| 74 |
- } |
|
| 72 |
+ options := types.ServiceInspectOptions{InsertDefaults: true}
|
|
| 75 | 73 |
|
| 76 | 74 |
// insertDefaults inserts UpdateConfig when service is fetched by ID |
| 77 | 75 |
resp, _, err := cli.ServiceInspectWithRaw(context.Background(), id, options) |
| ... | ... |
@@ -1534,22 +1534,6 @@ func (s *DockerSwarmSuite) TestSwarmManagerAddress(c *check.C) {
|
| 1534 | 1534 |
c.Assert(out, checker.Contains, expectedOutput) |
| 1535 | 1535 |
} |
| 1536 | 1536 |
|
| 1537 |
-func (s *DockerSwarmSuite) TestSwarmServiceInspectPretty(c *check.C) {
|
|
| 1538 |
- d := s.AddDaemon(c, true, true) |
|
| 1539 |
- |
|
| 1540 |
- name := "top" |
|
| 1541 |
- out, err := d.Cmd("service", "create", "--no-resolve-image", "--name", name, "--limit-cpu=0.5", "busybox", "top")
|
|
| 1542 |
- c.Assert(err, checker.IsNil, check.Commentf(out)) |
|
| 1543 |
- |
|
| 1544 |
- expectedOutput := ` |
|
| 1545 |
-Resources: |
|
| 1546 |
- Limits: |
|
| 1547 |
- CPU: 0.5` |
|
| 1548 |
- out, err = d.Cmd("service", "inspect", "--pretty", name)
|
|
| 1549 |
- c.Assert(err, checker.IsNil, check.Commentf(out)) |
|
| 1550 |
- c.Assert(out, checker.Contains, expectedOutput, check.Commentf(out)) |
|
| 1551 |
-} |
|
| 1552 |
- |
|
| 1553 | 1537 |
func (s *DockerSwarmSuite) TestSwarmNetworkIPAMOptions(c *check.C) {
|
| 1554 | 1538 |
d := s.AddDaemon(c, true, true) |
| 1555 | 1539 |
|
| ... | ... |
@@ -1691,76 +1675,6 @@ func (s *DockerSwarmSuite) TestSwarmNetworkCreateDup(c *check.C) {
|
| 1691 | 1691 |
} |
| 1692 | 1692 |
} |
| 1693 | 1693 |
|
| 1694 |
-func (s *DockerSwarmSuite) TestSwarmServicePsMultipleServiceIDs(c *check.C) {
|
|
| 1695 |
- d := s.AddDaemon(c, true, true) |
|
| 1696 |
- |
|
| 1697 |
- name1 := "top1" |
|
| 1698 |
- out, err := d.Cmd("service", "create", "--no-resolve-image", "--detach=true", "--name", name1, "--replicas=3", "busybox", "top")
|
|
| 1699 |
- c.Assert(err, checker.IsNil) |
|
| 1700 |
- c.Assert(strings.TrimSpace(out), checker.Not(checker.Equals), "") |
|
| 1701 |
- id1 := strings.TrimSpace(out) |
|
| 1702 |
- |
|
| 1703 |
- name2 := "top2" |
|
| 1704 |
- out, err = d.Cmd("service", "create", "--no-resolve-image", "--detach=true", "--name", name2, "--replicas=3", "busybox", "top")
|
|
| 1705 |
- c.Assert(err, checker.IsNil) |
|
| 1706 |
- c.Assert(strings.TrimSpace(out), checker.Not(checker.Equals), "") |
|
| 1707 |
- id2 := strings.TrimSpace(out) |
|
| 1708 |
- |
|
| 1709 |
- // make sure task has been deployed. |
|
| 1710 |
- waitAndAssert(c, defaultReconciliationTimeout, d.CheckActiveContainerCount, checker.Equals, 6) |
|
| 1711 |
- |
|
| 1712 |
- out, err = d.Cmd("service", "ps", name1)
|
|
| 1713 |
- c.Assert(err, checker.IsNil) |
|
| 1714 |
- c.Assert(out, checker.Contains, name1+".1") |
|
| 1715 |
- c.Assert(out, checker.Contains, name1+".2") |
|
| 1716 |
- c.Assert(out, checker.Contains, name1+".3") |
|
| 1717 |
- c.Assert(out, checker.Not(checker.Contains), name2+".1") |
|
| 1718 |
- c.Assert(out, checker.Not(checker.Contains), name2+".2") |
|
| 1719 |
- c.Assert(out, checker.Not(checker.Contains), name2+".3") |
|
| 1720 |
- |
|
| 1721 |
- out, err = d.Cmd("service", "ps", name1, name2)
|
|
| 1722 |
- c.Assert(err, checker.IsNil) |
|
| 1723 |
- c.Assert(out, checker.Contains, name1+".1") |
|
| 1724 |
- c.Assert(out, checker.Contains, name1+".2") |
|
| 1725 |
- c.Assert(out, checker.Contains, name1+".3") |
|
| 1726 |
- c.Assert(out, checker.Contains, name2+".1") |
|
| 1727 |
- c.Assert(out, checker.Contains, name2+".2") |
|
| 1728 |
- c.Assert(out, checker.Contains, name2+".3") |
|
| 1729 |
- |
|
| 1730 |
- // Name Prefix |
|
| 1731 |
- out, err = d.Cmd("service", "ps", "to")
|
|
| 1732 |
- c.Assert(err, checker.IsNil) |
|
| 1733 |
- c.Assert(out, checker.Contains, name1+".1") |
|
| 1734 |
- c.Assert(out, checker.Contains, name1+".2") |
|
| 1735 |
- c.Assert(out, checker.Contains, name1+".3") |
|
| 1736 |
- c.Assert(out, checker.Contains, name2+".1") |
|
| 1737 |
- c.Assert(out, checker.Contains, name2+".2") |
|
| 1738 |
- c.Assert(out, checker.Contains, name2+".3") |
|
| 1739 |
- |
|
| 1740 |
- // Name Prefix (no hit) |
|
| 1741 |
- out, err = d.Cmd("service", "ps", "noname")
|
|
| 1742 |
- c.Assert(err, checker.NotNil) |
|
| 1743 |
- c.Assert(out, checker.Contains, "no such services: noname") |
|
| 1744 |
- |
|
| 1745 |
- out, err = d.Cmd("service", "ps", id1)
|
|
| 1746 |
- c.Assert(err, checker.IsNil) |
|
| 1747 |
- c.Assert(out, checker.Contains, name1+".1") |
|
| 1748 |
- c.Assert(out, checker.Contains, name1+".2") |
|
| 1749 |
- c.Assert(out, checker.Contains, name1+".3") |
|
| 1750 |
- c.Assert(out, checker.Not(checker.Contains), name2+".1") |
|
| 1751 |
- c.Assert(out, checker.Not(checker.Contains), name2+".2") |
|
| 1752 |
- c.Assert(out, checker.Not(checker.Contains), name2+".3") |
|
| 1753 |
- |
|
| 1754 |
- out, err = d.Cmd("service", "ps", id1, id2)
|
|
| 1755 |
- c.Assert(err, checker.IsNil) |
|
| 1756 |
- c.Assert(out, checker.Contains, name1+".1") |
|
| 1757 |
- c.Assert(out, checker.Contains, name1+".2") |
|
| 1758 |
- c.Assert(out, checker.Contains, name1+".3") |
|
| 1759 |
- c.Assert(out, checker.Contains, name2+".1") |
|
| 1760 |
- c.Assert(out, checker.Contains, name2+".2") |
|
| 1761 |
- c.Assert(out, checker.Contains, name2+".3") |
|
| 1762 |
-} |
|
| 1763 |
- |
|
| 1764 | 1694 |
func (s *DockerSwarmSuite) TestSwarmPublishDuplicatePorts(c *check.C) {
|
| 1765 | 1695 |
d := s.AddDaemon(c, true, true) |
| 1766 | 1696 |
|
| 1767 | 1697 |
new file mode 100644 |
| ... | ... |
@@ -0,0 +1,145 @@ |
| 0 |
+package service |
|
| 1 |
+ |
|
| 2 |
+import ( |
|
| 3 |
+ "fmt" |
|
| 4 |
+ "testing" |
|
| 5 |
+ "time" |
|
| 6 |
+ |
|
| 7 |
+ "github.com/docker/docker/api/types" |
|
| 8 |
+ "github.com/docker/docker/api/types/filters" |
|
| 9 |
+ "github.com/docker/docker/api/types/swarm" |
|
| 10 |
+ "github.com/docker/docker/client" |
|
| 11 |
+ "github.com/docker/docker/integration-cli/daemon" |
|
| 12 |
+ "github.com/docker/docker/integration-cli/request" |
|
| 13 |
+ "github.com/gotestyourself/gotestyourself/poll" |
|
| 14 |
+ "github.com/stretchr/testify/assert" |
|
| 15 |
+ "github.com/stretchr/testify/require" |
|
| 16 |
+ "golang.org/x/net/context" |
|
| 17 |
+) |
|
| 18 |
+ |
|
| 19 |
+func TestInspect(t *testing.T) {
|
|
| 20 |
+ d := newSwarm(t) |
|
| 21 |
+ defer d.Stop(t) |
|
| 22 |
+ client, err := request.NewClientForHost(d.Sock()) |
|
| 23 |
+ require.NoError(t, err) |
|
| 24 |
+ |
|
| 25 |
+ var before = time.Now() |
|
| 26 |
+ var instances uint64 = 2 |
|
| 27 |
+ serviceSpec := fullSwarmServiceSpec("test-service-inspect", instances)
|
|
| 28 |
+ |
|
| 29 |
+ ctx := context.Background() |
|
| 30 |
+ resp, err := client.ServiceCreate(ctx, serviceSpec, types.ServiceCreateOptions{
|
|
| 31 |
+ QueryRegistry: false, |
|
| 32 |
+ }) |
|
| 33 |
+ require.NoError(t, err) |
|
| 34 |
+ |
|
| 35 |
+ id := resp.ID |
|
| 36 |
+ poll.WaitOn(t, serviceContainerCount(client, id, instances)) |
|
| 37 |
+ |
|
| 38 |
+ service, _, err := client.ServiceInspectWithRaw(ctx, id, types.ServiceInspectOptions{})
|
|
| 39 |
+ require.NoError(t, err) |
|
| 40 |
+ assert.Equal(t, serviceSpec, service.Spec) |
|
| 41 |
+ assert.Equal(t, uint64(11), service.Meta.Version.Index) |
|
| 42 |
+ assert.Equal(t, id, service.ID) |
|
| 43 |
+ assert.WithinDuration(t, before, service.CreatedAt, 30*time.Second) |
|
| 44 |
+ assert.WithinDuration(t, before, service.UpdatedAt, 30*time.Second) |
|
| 45 |
+} |
|
| 46 |
+ |
|
| 47 |
+func fullSwarmServiceSpec(name string, replicas uint64) swarm.ServiceSpec {
|
|
| 48 |
+ restartDelay := 100 * time.Millisecond |
|
| 49 |
+ maxAttempts := uint64(4) |
|
| 50 |
+ |
|
| 51 |
+ return swarm.ServiceSpec{
|
|
| 52 |
+ Annotations: swarm.Annotations{
|
|
| 53 |
+ Name: name, |
|
| 54 |
+ Labels: map[string]string{
|
|
| 55 |
+ "service-label": "service-label-value", |
|
| 56 |
+ }, |
|
| 57 |
+ }, |
|
| 58 |
+ TaskTemplate: swarm.TaskSpec{
|
|
| 59 |
+ ContainerSpec: &swarm.ContainerSpec{
|
|
| 60 |
+ Image: "busybox:latest", |
|
| 61 |
+ Labels: map[string]string{"container-label": "container-value"},
|
|
| 62 |
+ Command: []string{"/bin/top"},
|
|
| 63 |
+ Args: []string{"-u", "root"},
|
|
| 64 |
+ Hostname: "hostname", |
|
| 65 |
+ Env: []string{"envvar=envvalue"},
|
|
| 66 |
+ Dir: "/work", |
|
| 67 |
+ User: "root", |
|
| 68 |
+ StopSignal: "SIGINT", |
|
| 69 |
+ StopGracePeriod: &restartDelay, |
|
| 70 |
+ Hosts: []string{"8.8.8.8 google"},
|
|
| 71 |
+ DNSConfig: &swarm.DNSConfig{
|
|
| 72 |
+ Nameservers: []string{"8.8.8.8"},
|
|
| 73 |
+ Search: []string{"somedomain"},
|
|
| 74 |
+ }, |
|
| 75 |
+ }, |
|
| 76 |
+ RestartPolicy: &swarm.RestartPolicy{
|
|
| 77 |
+ Delay: &restartDelay, |
|
| 78 |
+ Condition: swarm.RestartPolicyConditionOnFailure, |
|
| 79 |
+ MaxAttempts: &maxAttempts, |
|
| 80 |
+ }, |
|
| 81 |
+ Runtime: swarm.RuntimeContainer, |
|
| 82 |
+ }, |
|
| 83 |
+ Mode: swarm.ServiceMode{
|
|
| 84 |
+ Replicated: &swarm.ReplicatedService{
|
|
| 85 |
+ Replicas: &replicas, |
|
| 86 |
+ }, |
|
| 87 |
+ }, |
|
| 88 |
+ UpdateConfig: &swarm.UpdateConfig{
|
|
| 89 |
+ Parallelism: 2, |
|
| 90 |
+ Delay: 200 * time.Second, |
|
| 91 |
+ FailureAction: swarm.UpdateFailureActionContinue, |
|
| 92 |
+ Monitor: 2 * time.Second, |
|
| 93 |
+ MaxFailureRatio: 0.2, |
|
| 94 |
+ Order: swarm.UpdateOrderStopFirst, |
|
| 95 |
+ }, |
|
| 96 |
+ RollbackConfig: &swarm.UpdateConfig{
|
|
| 97 |
+ Parallelism: 3, |
|
| 98 |
+ Delay: 300 * time.Second, |
|
| 99 |
+ FailureAction: swarm.UpdateFailureActionPause, |
|
| 100 |
+ Monitor: 3 * time.Second, |
|
| 101 |
+ MaxFailureRatio: 0.3, |
|
| 102 |
+ Order: swarm.UpdateOrderStartFirst, |
|
| 103 |
+ }, |
|
| 104 |
+ } |
|
| 105 |
+} |
|
| 106 |
+ |
|
| 107 |
+const defaultSwarmPort = 2477 |
|
| 108 |
+ |
|
| 109 |
+func newSwarm(t *testing.T) *daemon.Swarm {
|
|
| 110 |
+ d := &daemon.Swarm{
|
|
| 111 |
+ Daemon: daemon.New(t, "", dockerdBinary, daemon.Config{
|
|
| 112 |
+ Experimental: testEnv.ExperimentalDaemon(), |
|
| 113 |
+ }), |
|
| 114 |
+ // TODO: better method of finding an unused port |
|
| 115 |
+ Port: defaultSwarmPort, |
|
| 116 |
+ } |
|
| 117 |
+ // TODO: move to a NewSwarm constructor |
|
| 118 |
+ d.ListenAddr = fmt.Sprintf("0.0.0.0:%d", d.Port)
|
|
| 119 |
+ |
|
| 120 |
+ // avoid networking conflicts |
|
| 121 |
+ args := []string{"--iptables=false", "--swarm-default-advertise-addr=lo"}
|
|
| 122 |
+ d.StartWithBusybox(t, args...) |
|
| 123 |
+ |
|
| 124 |
+ require.NoError(t, d.Init(swarm.InitRequest{}))
|
|
| 125 |
+ return d |
|
| 126 |
+} |
|
| 127 |
+ |
|
| 128 |
+func serviceContainerCount(client client.ServiceAPIClient, id string, count uint64) func(log poll.LogT) poll.Result {
|
|
| 129 |
+ return func(log poll.LogT) poll.Result {
|
|
| 130 |
+ filter := filters.NewArgs() |
|
| 131 |
+ filter.Add("service", id)
|
|
| 132 |
+ tasks, err := client.TaskList(context.Background(), types.TaskListOptions{
|
|
| 133 |
+ Filters: filter, |
|
| 134 |
+ }) |
|
| 135 |
+ switch {
|
|
| 136 |
+ case err != nil: |
|
| 137 |
+ return poll.Error(err) |
|
| 138 |
+ case len(tasks) == int(count): |
|
| 139 |
+ return poll.Success() |
|
| 140 |
+ default: |
|
| 141 |
+ return poll.Continue("task count at %d waiting for %d", len(tasks), count)
|
|
| 142 |
+ } |
|
| 143 |
+ } |
|
| 144 |
+} |
| 0 | 145 |
new file mode 100644 |
| ... | ... |
@@ -0,0 +1,37 @@ |
| 0 |
+package service |
|
| 1 |
+ |
|
| 2 |
+import ( |
|
| 3 |
+ "fmt" |
|
| 4 |
+ "os" |
|
| 5 |
+ "testing" |
|
| 6 |
+ |
|
| 7 |
+ "github.com/docker/docker/integration-cli/environment" |
|
| 8 |
+) |
|
| 9 |
+ |
|
| 10 |
+var testEnv *environment.Execution |
|
| 11 |
+ |
|
| 12 |
+const dockerdBinary = "dockerd" |
|
| 13 |
+ |
|
| 14 |
+func TestMain(m *testing.M) {
|
|
| 15 |
+ var err error |
|
| 16 |
+ testEnv, err = environment.New() |
|
| 17 |
+ if err != nil {
|
|
| 18 |
+ fmt.Println(err) |
|
| 19 |
+ os.Exit(1) |
|
| 20 |
+ } |
|
| 21 |
+ |
|
| 22 |
+ // TODO: replace this with `testEnv.Print()` to print the full env |
|
| 23 |
+ if testEnv.LocalDaemon() {
|
|
| 24 |
+ fmt.Println("INFO: Testing against a local daemon")
|
|
| 25 |
+ } else {
|
|
| 26 |
+ fmt.Println("INFO: Testing against a remote daemon")
|
|
| 27 |
+ } |
|
| 28 |
+ |
|
| 29 |
+ res := m.Run() |
|
| 30 |
+ os.Exit(res) |
|
| 31 |
+} |
|
| 32 |
+ |
|
| 33 |
+func setupTest(t *testing.T) func() {
|
|
| 34 |
+ environment.ProtectImages(t, testEnv) |
|
| 35 |
+ return func() { testEnv.Clean(t, testEnv.DockerBinary()) }
|
|
| 36 |
+} |