github.com/jwhonce/docker@v0.6.7-0.20190327063223-da823cf3a5a3/integration-cli/docker_cli_swarm_test.go (about) 1 // +build !windows 2 3 package main 4 5 import ( 6 "bytes" 7 "context" 8 "encoding/json" 9 "encoding/pem" 10 "fmt" 11 "io/ioutil" 12 "net/http" 13 "net/http/httptest" 14 "os" 15 "path/filepath" 16 "runtime" 17 "strings" 18 "time" 19 20 "github.com/cloudflare/cfssl/helpers" 21 "github.com/docker/docker/api/types" 22 "github.com/docker/docker/api/types/swarm" 23 "github.com/docker/docker/integration-cli/checker" 24 "github.com/docker/docker/integration-cli/cli" 25 "github.com/docker/docker/integration-cli/daemon" 26 "github.com/docker/libnetwork/driverapi" 27 "github.com/docker/libnetwork/ipamapi" 28 remoteipam "github.com/docker/libnetwork/ipams/remote/api" 29 "github.com/docker/swarmkit/ca/keyutils" 30 "github.com/go-check/check" 31 "github.com/vishvananda/netlink" 32 "gotest.tools/fs" 33 "gotest.tools/icmd" 34 ) 35 36 func (s *DockerSwarmSuite) TestSwarmUpdate(c *check.C) { 37 d := s.AddDaemon(c, true, true) 38 39 getSpec := func() swarm.Spec { 40 sw := d.GetSwarm(c) 41 return sw.Spec 42 } 43 44 out, err := d.Cmd("swarm", "update", "--cert-expiry", "30h", "--dispatcher-heartbeat", "11s") 45 c.Assert(err, checker.IsNil, check.Commentf("%s", out)) 46 47 spec := getSpec() 48 c.Assert(spec.CAConfig.NodeCertExpiry, checker.Equals, 30*time.Hour) 49 c.Assert(spec.Dispatcher.HeartbeatPeriod, checker.Equals, 11*time.Second) 50 51 // setting anything under 30m for cert-expiry is not allowed 52 out, err = d.Cmd("swarm", "update", "--cert-expiry", "15m") 53 c.Assert(err, checker.NotNil) 54 c.Assert(out, checker.Contains, "minimum certificate expiry time") 55 spec = getSpec() 56 c.Assert(spec.CAConfig.NodeCertExpiry, checker.Equals, 30*time.Hour) 57 58 // passing an external CA (this is without starting a root rotation) does not fail 59 cli.Docker(cli.Args("swarm", "update", "--external-ca", "protocol=cfssl,url=https://something.org", 60 "--external-ca", "protocol=cfssl,url=https://somethingelse.org,cacert=fixtures/https/ca.pem"), 61 cli.Daemon(d)).Assert(c, icmd.Success) 62 63 expected, err := ioutil.ReadFile("fixtures/https/ca.pem") 64 c.Assert(err, checker.IsNil) 65 66 spec = getSpec() 67 c.Assert(spec.CAConfig.ExternalCAs, checker.HasLen, 2) 68 c.Assert(spec.CAConfig.ExternalCAs[0].CACert, checker.Equals, "") 69 c.Assert(spec.CAConfig.ExternalCAs[1].CACert, checker.Equals, string(expected)) 70 71 // passing an invalid external CA fails 72 tempFile := fs.NewFile(c, "testfile", fs.WithContent("fakecert")) 73 defer tempFile.Remove() 74 75 result := cli.Docker(cli.Args("swarm", "update", 76 "--external-ca", fmt.Sprintf("protocol=cfssl,url=https://something.org,cacert=%s", tempFile.Path())), 77 cli.Daemon(d)) 78 result.Assert(c, icmd.Expected{ 79 ExitCode: 125, 80 Err: "must be in PEM format", 81 }) 82 } 83 84 func (s *DockerSwarmSuite) TestSwarmInit(c *check.C) { 85 d := s.AddDaemon(c, false, false) 86 87 getSpec := func() swarm.Spec { 88 sw := d.GetSwarm(c) 89 return sw.Spec 90 } 91 92 // passing an invalid external CA fails 93 tempFile := fs.NewFile(c, "testfile", fs.WithContent("fakecert")) 94 defer tempFile.Remove() 95 96 result := cli.Docker(cli.Args("swarm", "init", "--cert-expiry", "30h", "--dispatcher-heartbeat", "11s", 97 "--external-ca", fmt.Sprintf("protocol=cfssl,url=https://somethingelse.org,cacert=%s", tempFile.Path())), 98 cli.Daemon(d)) 99 result.Assert(c, icmd.Expected{ 100 ExitCode: 125, 101 Err: "must be in PEM format", 102 }) 103 104 cli.Docker(cli.Args("swarm", "init", "--cert-expiry", "30h", "--dispatcher-heartbeat", "11s", 105 "--external-ca", "protocol=cfssl,url=https://something.org", 106 "--external-ca", "protocol=cfssl,url=https://somethingelse.org,cacert=fixtures/https/ca.pem"), 107 cli.Daemon(d)).Assert(c, icmd.Success) 108 109 expected, err := ioutil.ReadFile("fixtures/https/ca.pem") 110 c.Assert(err, checker.IsNil) 111 112 spec := getSpec() 113 c.Assert(spec.CAConfig.NodeCertExpiry, checker.Equals, 30*time.Hour) 114 c.Assert(spec.Dispatcher.HeartbeatPeriod, checker.Equals, 11*time.Second) 115 c.Assert(spec.CAConfig.ExternalCAs, checker.HasLen, 2) 116 c.Assert(spec.CAConfig.ExternalCAs[0].CACert, checker.Equals, "") 117 c.Assert(spec.CAConfig.ExternalCAs[1].CACert, checker.Equals, string(expected)) 118 119 c.Assert(d.SwarmLeave(c, true), checker.IsNil) 120 cli.Docker(cli.Args("swarm", "init"), cli.Daemon(d)).Assert(c, icmd.Success) 121 122 spec = getSpec() 123 c.Assert(spec.CAConfig.NodeCertExpiry, checker.Equals, 90*24*time.Hour) 124 c.Assert(spec.Dispatcher.HeartbeatPeriod, checker.Equals, 5*time.Second) 125 } 126 127 func (s *DockerSwarmSuite) TestSwarmInitIPv6(c *check.C) { 128 testRequires(c, IPv6) 129 d1 := s.AddDaemon(c, false, false) 130 cli.Docker(cli.Args("swarm", "init", "--listen-add", "::1"), cli.Daemon(d1)).Assert(c, icmd.Success) 131 132 d2 := s.AddDaemon(c, false, false) 133 cli.Docker(cli.Args("swarm", "join", "::1"), cli.Daemon(d2)).Assert(c, icmd.Success) 134 135 out := cli.Docker(cli.Args("info"), cli.Daemon(d2)).Assert(c, icmd.Success).Combined() 136 c.Assert(out, checker.Contains, "Swarm: active") 137 } 138 139 func (s *DockerSwarmSuite) TestSwarmInitUnspecifiedAdvertiseAddr(c *check.C) { 140 d := s.AddDaemon(c, false, false) 141 out, err := d.Cmd("swarm", "init", "--advertise-addr", "0.0.0.0") 142 c.Assert(err, checker.NotNil) 143 c.Assert(out, checker.Contains, "advertise address must be a non-zero IP address") 144 } 145 146 func (s *DockerSwarmSuite) TestSwarmIncompatibleDaemon(c *check.C) { 147 // init swarm mode and stop a daemon 148 d := s.AddDaemon(c, true, true) 149 info := d.SwarmInfo(c) 150 c.Assert(info.LocalNodeState, checker.Equals, swarm.LocalNodeStateActive) 151 d.Stop(c) 152 153 // start a daemon with --cluster-store and --cluster-advertise 154 err := d.StartWithError("--cluster-store=consul://consuladdr:consulport/some/path", "--cluster-advertise=1.1.1.1:2375") 155 c.Assert(err, checker.NotNil) 156 content, err := d.ReadLogFile() 157 c.Assert(err, checker.IsNil) 158 c.Assert(string(content), checker.Contains, "--cluster-store and --cluster-advertise daemon configurations are incompatible with swarm mode") 159 160 // start a daemon with --live-restore 161 err = d.StartWithError("--live-restore") 162 c.Assert(err, checker.NotNil) 163 content, err = d.ReadLogFile() 164 c.Assert(err, checker.IsNil) 165 c.Assert(string(content), checker.Contains, "--live-restore daemon configuration is incompatible with swarm mode") 166 // restart for teardown 167 d.StartNode(c) 168 } 169 170 func (s *DockerSwarmSuite) TestSwarmServiceTemplatingHostname(c *check.C) { 171 d := s.AddDaemon(c, true, true) 172 hostname, err := d.Cmd("node", "inspect", "--format", "{{.Description.Hostname}}", "self") 173 c.Assert(err, checker.IsNil, check.Commentf("%s", hostname)) 174 175 out, err := d.Cmd("service", "create", "--detach", "--no-resolve-image", "--name", "test", "--hostname", "{{.Service.Name}}-{{.Task.Slot}}-{{.Node.Hostname}}", "busybox", "top") 176 c.Assert(err, checker.IsNil, check.Commentf("%s", out)) 177 178 // make sure task has been deployed. 179 waitAndAssert(c, defaultReconciliationTimeout, d.CheckActiveContainerCount, checker.Equals, 1) 180 181 containers := d.ActiveContainers(c) 182 out, err = d.Cmd("inspect", "--type", "container", "--format", "{{.Config.Hostname}}", containers[0]) 183 c.Assert(err, checker.IsNil, check.Commentf("%s", out)) 184 c.Assert(strings.Split(out, "\n")[0], checker.Equals, "test-1-"+strings.Split(hostname, "\n")[0], check.Commentf("hostname with templating invalid")) 185 } 186 187 // Test case for #24270 188 func (s *DockerSwarmSuite) TestSwarmServiceListFilter(c *check.C) { 189 d := s.AddDaemon(c, true, true) 190 191 name1 := "redis-cluster-md5" 192 name2 := "redis-cluster" 193 name3 := "other-cluster" 194 out, err := d.Cmd("service", "create", "--detach", "--no-resolve-image", "--name", name1, "busybox", "top") 195 c.Assert(err, checker.IsNil, check.Commentf("%s", out)) 196 c.Assert(strings.TrimSpace(out), checker.Not(checker.Equals), "") 197 198 out, err = d.Cmd("service", "create", "--detach", "--no-resolve-image", "--name", name2, "busybox", "top") 199 c.Assert(err, checker.IsNil, check.Commentf("%s", out)) 200 c.Assert(strings.TrimSpace(out), checker.Not(checker.Equals), "") 201 202 out, err = d.Cmd("service", "create", "--detach", "--no-resolve-image", "--name", name3, "busybox", "top") 203 c.Assert(err, checker.IsNil, check.Commentf("%s", out)) 204 c.Assert(strings.TrimSpace(out), checker.Not(checker.Equals), "") 205 206 filter1 := "name=redis-cluster-md5" 207 filter2 := "name=redis-cluster" 208 209 // We search checker.Contains with `name+" "` to prevent prefix only. 210 out, err = d.Cmd("service", "ls", "--filter", filter1) 211 c.Assert(err, checker.IsNil, check.Commentf("%s", out)) 212 c.Assert(out, checker.Contains, name1+" ") 213 c.Assert(out, checker.Not(checker.Contains), name2+" ") 214 c.Assert(out, checker.Not(checker.Contains), name3+" ") 215 216 out, err = d.Cmd("service", "ls", "--filter", filter2) 217 c.Assert(err, checker.IsNil, check.Commentf("%s", out)) 218 c.Assert(out, checker.Contains, name1+" ") 219 c.Assert(out, checker.Contains, name2+" ") 220 c.Assert(out, checker.Not(checker.Contains), name3+" ") 221 222 out, err = d.Cmd("service", "ls") 223 c.Assert(err, checker.IsNil, check.Commentf("%s", out)) 224 c.Assert(out, checker.Contains, name1+" ") 225 c.Assert(out, checker.Contains, name2+" ") 226 c.Assert(out, checker.Contains, name3+" ") 227 } 228 229 func (s *DockerSwarmSuite) TestSwarmNodeListFilter(c *check.C) { 230 d := s.AddDaemon(c, true, true) 231 232 out, err := d.Cmd("node", "inspect", "--format", "{{ .Description.Hostname }}", "self") 233 c.Assert(err, checker.IsNil, check.Commentf("%s", out)) 234 c.Assert(strings.TrimSpace(out), checker.Not(checker.Equals), "") 235 name := strings.TrimSpace(out) 236 237 filter := "name=" + name[:4] 238 239 out, err = d.Cmd("node", "ls", "--filter", filter) 240 c.Assert(err, checker.IsNil, check.Commentf("%s", out)) 241 c.Assert(out, checker.Contains, name) 242 243 out, err = d.Cmd("node", "ls", "--filter", "name=none") 244 c.Assert(err, checker.IsNil, check.Commentf("%s", out)) 245 c.Assert(out, checker.Not(checker.Contains), name) 246 } 247 248 func (s *DockerSwarmSuite) TestSwarmNodeTaskListFilter(c *check.C) { 249 d := s.AddDaemon(c, true, true) 250 251 name := "redis-cluster-md5" 252 out, err := d.Cmd("service", "create", "--detach", "--no-resolve-image", "--name", name, "--replicas=3", "busybox", "top") 253 c.Assert(err, checker.IsNil, check.Commentf("%s", out)) 254 c.Assert(strings.TrimSpace(out), checker.Not(checker.Equals), "") 255 256 // make sure task has been deployed. 257 waitAndAssert(c, defaultReconciliationTimeout, d.CheckActiveContainerCount, checker.Equals, 3) 258 259 filter := "name=redis-cluster" 260 261 out, err = d.Cmd("node", "ps", "--filter", filter, "self") 262 c.Assert(err, checker.IsNil, check.Commentf("%s", out)) 263 c.Assert(out, checker.Contains, name+".1") 264 c.Assert(out, checker.Contains, name+".2") 265 c.Assert(out, checker.Contains, name+".3") 266 267 out, err = d.Cmd("node", "ps", "--filter", "name=none", "self") 268 c.Assert(err, checker.IsNil, check.Commentf("%s", out)) 269 c.Assert(out, checker.Not(checker.Contains), name+".1") 270 c.Assert(out, checker.Not(checker.Contains), name+".2") 271 c.Assert(out, checker.Not(checker.Contains), name+".3") 272 } 273 274 // Test case for #25375 275 func (s *DockerSwarmSuite) TestSwarmPublishAdd(c *check.C) { 276 d := s.AddDaemon(c, true, true) 277 278 name := "top" 279 out, err := d.Cmd("service", "create", "--detach", "--no-resolve-image", "--name", name, "--label", "x=y", "busybox", "top") 280 c.Assert(err, checker.IsNil, check.Commentf("%s", out)) 281 c.Assert(strings.TrimSpace(out), checker.Not(checker.Equals), "") 282 283 out, err = d.Cmd("service", "update", "--detach", "--publish-add", "80:80", name) 284 c.Assert(err, checker.IsNil, check.Commentf("%s", out)) 285 286 out, err = d.Cmd("service", "update", "--detach", "--publish-add", "80:80", name) 287 c.Assert(err, checker.IsNil, check.Commentf("%s", out)) 288 289 _, err = d.Cmd("service", "update", "--detach", "--publish-add", "80:80", "--publish-add", "80:20", name) 290 c.Assert(err, checker.NotNil) 291 292 out, err = d.Cmd("service", "inspect", "--format", "{{ .Spec.EndpointSpec.Ports }}", name) 293 c.Assert(err, checker.IsNil, check.Commentf("%s", out)) 294 c.Assert(strings.TrimSpace(out), checker.Equals, "[{ tcp 80 80 ingress}]") 295 } 296 297 func (s *DockerSwarmSuite) TestSwarmServiceWithGroup(c *check.C) { 298 d := s.AddDaemon(c, true, true) 299 300 name := "top" 301 out, err := d.Cmd("service", "create", "--detach", "--no-resolve-image", "--name", name, "--user", "root:root", "--group", "wheel", "--group", "audio", "--group", "staff", "--group", "777", "busybox", "top") 302 c.Assert(err, checker.IsNil, check.Commentf("%s", out)) 303 c.Assert(strings.TrimSpace(out), checker.Not(checker.Equals), "") 304 305 // make sure task has been deployed. 306 waitAndAssert(c, defaultReconciliationTimeout, d.CheckActiveContainerCount, checker.Equals, 1) 307 308 out, err = d.Cmd("ps", "-q") 309 c.Assert(err, checker.IsNil, check.Commentf("%s", out)) 310 c.Assert(strings.TrimSpace(out), checker.Not(checker.Equals), "") 311 312 container := strings.TrimSpace(out) 313 314 out, err = d.Cmd("exec", container, "id") 315 c.Assert(err, checker.IsNil, check.Commentf("%s", out)) 316 c.Assert(strings.TrimSpace(out), checker.Equals, "uid=0(root) gid=0(root) groups=10(wheel),29(audio),50(staff),777") 317 } 318 319 func (s *DockerSwarmSuite) TestSwarmContainerAutoStart(c *check.C) { 320 d := s.AddDaemon(c, true, true) 321 322 out, err := d.Cmd("network", "create", "--attachable", "-d", "overlay", "foo") 323 c.Assert(err, checker.IsNil, check.Commentf("%s", out)) 324 c.Assert(strings.TrimSpace(out), checker.Not(checker.Equals), "") 325 326 out, err = d.Cmd("run", "-id", "--restart=always", "--net=foo", "--name=test", "busybox", "top") 327 c.Assert(err, checker.IsNil, check.Commentf("%s", out)) 328 c.Assert(strings.TrimSpace(out), checker.Not(checker.Equals), "") 329 330 out, err = d.Cmd("ps", "-q") 331 c.Assert(err, checker.IsNil, check.Commentf("%s", out)) 332 c.Assert(strings.TrimSpace(out), checker.Not(checker.Equals), "") 333 334 d.RestartNode(c) 335 336 out, err = d.Cmd("ps", "-q") 337 c.Assert(err, checker.IsNil, check.Commentf("%s", out)) 338 c.Assert(strings.TrimSpace(out), checker.Not(checker.Equals), "") 339 } 340 341 func (s *DockerSwarmSuite) TestSwarmContainerEndpointOptions(c *check.C) { 342 d := s.AddDaemon(c, true, true) 343 344 out, err := d.Cmd("network", "create", "--attachable", "-d", "overlay", "foo") 345 c.Assert(err, checker.IsNil, check.Commentf("%s", out)) 346 c.Assert(strings.TrimSpace(out), checker.Not(checker.Equals), "") 347 348 out, err = d.Cmd("run", "-d", "--net=foo", "--name=first", "--net-alias=first-alias", "busybox:glibc", "top") 349 c.Assert(err, checker.IsNil, check.Commentf("%s", out)) 350 351 out, err = d.Cmd("run", "-d", "--net=foo", "--name=second", "busybox:glibc", "top") 352 c.Assert(err, checker.IsNil, check.Commentf("%s", out)) 353 354 out, err = d.Cmd("run", "-d", "--net=foo", "--net-alias=third-alias", "busybox:glibc", "top") 355 c.Assert(err, checker.IsNil, check.Commentf("%s", out)) 356 357 // ping first container and its alias, also ping third and anonymous container by its alias 358 out, err = d.Cmd("exec", "second", "ping", "-c", "1", "first") 359 c.Assert(err, check.IsNil, check.Commentf("%s", out)) 360 out, err = d.Cmd("exec", "second", "ping", "-c", "1", "first-alias") 361 c.Assert(err, check.IsNil, check.Commentf("%s", out)) 362 out, err = d.Cmd("exec", "second", "ping", "-c", "1", "third-alias") 363 c.Assert(err, check.IsNil, check.Commentf("%s", out)) 364 } 365 366 func (s *DockerSwarmSuite) TestSwarmContainerAttachByNetworkId(c *check.C) { 367 d := s.AddDaemon(c, true, true) 368 369 out, err := d.Cmd("network", "create", "--attachable", "-d", "overlay", "testnet") 370 c.Assert(err, checker.IsNil, check.Commentf("%s", out)) 371 c.Assert(strings.TrimSpace(out), checker.Not(checker.Equals), "") 372 networkID := strings.TrimSpace(out) 373 374 out, err = d.Cmd("run", "-d", "--net", networkID, "busybox", "top") 375 c.Assert(err, checker.IsNil, check.Commentf("%s", out)) 376 cID := strings.TrimSpace(out) 377 d.WaitRun(cID) 378 379 out, err = d.Cmd("rm", "-f", cID) 380 c.Assert(err, checker.IsNil, check.Commentf("%s", out)) 381 382 out, err = d.Cmd("network", "rm", "testnet") 383 c.Assert(err, checker.IsNil, check.Commentf("%s", out)) 384 385 checkNetwork := func(*check.C) (interface{}, check.CommentInterface) { 386 out, err := d.Cmd("network", "ls") 387 c.Assert(err, checker.IsNil) 388 return out, nil 389 } 390 391 waitAndAssert(c, 3*time.Second, checkNetwork, checker.Not(checker.Contains), "testnet") 392 } 393 394 func (s *DockerSwarmSuite) TestOverlayAttachable(c *check.C) { 395 d := s.AddDaemon(c, true, true) 396 397 out, err := d.Cmd("network", "create", "-d", "overlay", "--attachable", "ovnet") 398 c.Assert(err, checker.IsNil, check.Commentf("%s", out)) 399 400 // validate attachable 401 out, err = d.Cmd("network", "inspect", "--format", "{{json .Attachable}}", "ovnet") 402 c.Assert(err, checker.IsNil, check.Commentf("%s", out)) 403 c.Assert(strings.TrimSpace(out), checker.Equals, "true") 404 405 // validate containers can attach to this overlay network 406 out, err = d.Cmd("run", "-d", "--network", "ovnet", "--name", "c1", "busybox", "top") 407 c.Assert(err, checker.IsNil, check.Commentf("%s", out)) 408 409 // redo validation, there was a bug that the value of attachable changes after 410 // containers attach to the network 411 out, err = d.Cmd("network", "inspect", "--format", "{{json .Attachable}}", "ovnet") 412 c.Assert(err, checker.IsNil, check.Commentf("%s", out)) 413 c.Assert(strings.TrimSpace(out), checker.Equals, "true") 414 } 415 416 func (s *DockerSwarmSuite) TestOverlayAttachableOnSwarmLeave(c *check.C) { 417 d := s.AddDaemon(c, true, true) 418 419 // Create an attachable swarm network 420 nwName := "attovl" 421 out, err := d.Cmd("network", "create", "-d", "overlay", "--attachable", nwName) 422 c.Assert(err, checker.IsNil, check.Commentf("%s", out)) 423 424 // Connect a container to the network 425 out, err = d.Cmd("run", "-d", "--network", nwName, "--name", "c1", "busybox", "top") 426 c.Assert(err, checker.IsNil, check.Commentf("%s", out)) 427 428 // Leave the swarm 429 c.Assert(d.SwarmLeave(c, true), checker.IsNil) 430 431 // Check the container is disconnected 432 out, err = d.Cmd("inspect", "c1", "--format", "{{.NetworkSettings.Networks."+nwName+"}}") 433 c.Assert(err, checker.IsNil, check.Commentf("%s", out)) 434 c.Assert(strings.TrimSpace(out), checker.Equals, "<no value>") 435 436 // Check the network is gone 437 out, err = d.Cmd("network", "ls", "--format", "{{.Name}}") 438 c.Assert(err, checker.IsNil, check.Commentf("%s", out)) 439 c.Assert(out, checker.Not(checker.Contains), nwName) 440 } 441 442 func (s *DockerSwarmSuite) TestOverlayAttachableReleaseResourcesOnFailure(c *check.C) { 443 d := s.AddDaemon(c, true, true) 444 445 // Create attachable network 446 out, err := d.Cmd("network", "create", "-d", "overlay", "--attachable", "--subnet", "10.10.9.0/24", "ovnet") 447 c.Assert(err, checker.IsNil, check.Commentf("%s", out)) 448 449 // Attach a container with specific IP 450 out, err = d.Cmd("run", "-d", "--network", "ovnet", "--name", "c1", "--ip", "10.10.9.33", "busybox", "top") 451 c.Assert(err, checker.IsNil, check.Commentf("%s", out)) 452 453 // Attempt to attach another container with same IP, must fail 454 out, err = d.Cmd("run", "-d", "--network", "ovnet", "--name", "c2", "--ip", "10.10.9.33", "busybox", "top") 455 c.Assert(err, checker.NotNil, check.Commentf("%s", out)) 456 457 // Remove first container 458 out, err = d.Cmd("rm", "-f", "c1") 459 c.Assert(err, checker.IsNil, check.Commentf("%s", out)) 460 461 // Verify the network can be removed, no phantom network attachment task left over 462 out, err = d.Cmd("network", "rm", "ovnet") 463 c.Assert(err, checker.IsNil, check.Commentf("%s", out)) 464 } 465 466 func (s *DockerSwarmSuite) TestSwarmIngressNetwork(c *check.C) { 467 d := s.AddDaemon(c, true, true) 468 469 // Ingress network can be removed 470 removeNetwork := func(name string) *icmd.Result { 471 return cli.Docker( 472 cli.Args("-H", d.Sock(), "network", "rm", name), 473 cli.WithStdin(strings.NewReader("Y"))) 474 } 475 476 result := removeNetwork("ingress") 477 result.Assert(c, icmd.Success) 478 479 // And recreated 480 out, err := d.Cmd("network", "create", "-d", "overlay", "--ingress", "new-ingress") 481 c.Assert(err, checker.IsNil, check.Commentf("%s", out)) 482 483 // But only one is allowed 484 out, err = d.Cmd("network", "create", "-d", "overlay", "--ingress", "another-ingress") 485 c.Assert(err, checker.NotNil) 486 c.Assert(strings.TrimSpace(out), checker.Contains, "is already present") 487 488 // It cannot be removed if it is being used 489 out, err = d.Cmd("service", "create", "--detach", "--no-resolve-image", "--name", "srv1", "-p", "9000:8000", "busybox", "top") 490 c.Assert(err, checker.IsNil, check.Commentf("%s", out)) 491 492 result = removeNetwork("new-ingress") 493 result.Assert(c, icmd.Expected{ 494 ExitCode: 1, 495 Err: "ingress network cannot be removed because service", 496 }) 497 498 // But it can be removed once no more services depend on it 499 out, err = d.Cmd("service", "update", "--detach", "--publish-rm", "9000:8000", "srv1") 500 c.Assert(err, checker.IsNil, check.Commentf("%s", out)) 501 502 result = removeNetwork("new-ingress") 503 result.Assert(c, icmd.Success) 504 505 // A service which needs the ingress network cannot be created if no ingress is present 506 out, err = d.Cmd("service", "create", "--detach", "--no-resolve-image", "--name", "srv2", "-p", "500:500", "busybox", "top") 507 c.Assert(err, checker.NotNil) 508 c.Assert(strings.TrimSpace(out), checker.Contains, "no ingress network is present") 509 510 // An existing service cannot be updated to use the ingress nw if the nw is not present 511 out, err = d.Cmd("service", "update", "--detach", "--publish-add", "9000:8000", "srv1") 512 c.Assert(err, checker.NotNil) 513 c.Assert(strings.TrimSpace(out), checker.Contains, "no ingress network is present") 514 515 // But services which do not need routing mesh can be created regardless 516 out, err = d.Cmd("service", "create", "--detach", "--no-resolve-image", "--name", "srv3", "--endpoint-mode", "dnsrr", "busybox", "top") 517 c.Assert(err, checker.IsNil, check.Commentf("%s", out)) 518 } 519 520 func (s *DockerSwarmSuite) TestSwarmCreateServiceWithNoIngressNetwork(c *check.C) { 521 d := s.AddDaemon(c, true, true) 522 523 // Remove ingress network 524 result := cli.Docker( 525 cli.Args("-H", d.Sock(), "network", "rm", "ingress"), 526 cli.WithStdin(strings.NewReader("Y"))) 527 result.Assert(c, icmd.Success) 528 529 // Create a overlay network and launch a service on it 530 // Make sure nothing panics because ingress network is missing 531 out, err := d.Cmd("network", "create", "-d", "overlay", "another-network") 532 c.Assert(err, checker.IsNil, check.Commentf("%s", out)) 533 out, err = d.Cmd("service", "create", "--detach", "--no-resolve-image", "--name", "srv4", "--network", "another-network", "busybox", "top") 534 c.Assert(err, checker.IsNil, check.Commentf("%s", out)) 535 } 536 537 // Test case for #24108, also the case from: 538 // https://github.com/docker/docker/pull/24620#issuecomment-233715656 539 func (s *DockerSwarmSuite) TestSwarmTaskListFilter(c *check.C) { 540 d := s.AddDaemon(c, true, true) 541 542 name := "redis-cluster-md5" 543 out, err := d.Cmd("service", "create", "--detach", "--no-resolve-image", "--name", name, "--replicas=3", "busybox", "top") 544 c.Assert(err, checker.IsNil, check.Commentf("%s", out)) 545 c.Assert(strings.TrimSpace(out), checker.Not(checker.Equals), "") 546 547 filter := "name=redis-cluster" 548 549 checkNumTasks := func(*check.C) (interface{}, check.CommentInterface) { 550 out, err := d.Cmd("service", "ps", "--filter", filter, name) 551 c.Assert(err, checker.IsNil, check.Commentf("%s", out)) 552 return len(strings.Split(out, "\n")) - 2, nil // includes header and nl in last line 553 } 554 555 // wait until all tasks have been created 556 waitAndAssert(c, defaultReconciliationTimeout, checkNumTasks, checker.Equals, 3) 557 558 out, err = d.Cmd("service", "ps", "--filter", filter, name) 559 c.Assert(err, checker.IsNil, check.Commentf("%s", out)) 560 c.Assert(out, checker.Contains, name+".1") 561 c.Assert(out, checker.Contains, name+".2") 562 c.Assert(out, checker.Contains, name+".3") 563 564 out, err = d.Cmd("service", "ps", "--filter", "name="+name+".1", name) 565 c.Assert(err, checker.IsNil, check.Commentf("%s", out)) 566 c.Assert(out, checker.Contains, name+".1") 567 c.Assert(out, checker.Not(checker.Contains), name+".2") 568 c.Assert(out, checker.Not(checker.Contains), name+".3") 569 570 out, err = d.Cmd("service", "ps", "--filter", "name=none", name) 571 c.Assert(err, checker.IsNil, check.Commentf("%s", out)) 572 c.Assert(out, checker.Not(checker.Contains), name+".1") 573 c.Assert(out, checker.Not(checker.Contains), name+".2") 574 c.Assert(out, checker.Not(checker.Contains), name+".3") 575 576 name = "redis-cluster-sha1" 577 out, err = d.Cmd("service", "create", "--detach", "--no-resolve-image", "--name", name, "--mode=global", "busybox", "top") 578 c.Assert(err, checker.IsNil, check.Commentf("%s", out)) 579 c.Assert(strings.TrimSpace(out), checker.Not(checker.Equals), "") 580 581 waitAndAssert(c, defaultReconciliationTimeout, checkNumTasks, checker.Equals, 1) 582 583 filter = "name=redis-cluster" 584 out, err = d.Cmd("service", "ps", "--filter", filter, name) 585 c.Assert(err, checker.IsNil, check.Commentf("%s", out)) 586 c.Assert(out, checker.Contains, name) 587 588 out, err = d.Cmd("service", "ps", "--filter", "name="+name, name) 589 c.Assert(err, checker.IsNil, check.Commentf("%s", out)) 590 c.Assert(out, checker.Contains, name) 591 592 out, err = d.Cmd("service", "ps", "--filter", "name=none", name) 593 c.Assert(err, checker.IsNil, check.Commentf("%s", out)) 594 c.Assert(out, checker.Not(checker.Contains), name) 595 } 596 597 func (s *DockerSwarmSuite) TestPsListContainersFilterIsTask(c *check.C) { 598 d := s.AddDaemon(c, true, true) 599 600 // Create a bare container 601 out, err := d.Cmd("run", "-d", "--name=bare-container", "busybox", "top") 602 c.Assert(err, checker.IsNil, check.Commentf("%s", out)) 603 bareID := strings.TrimSpace(out)[:12] 604 // Create a service 605 name := "busybox-top" 606 out, err = d.Cmd("service", "create", "--detach", "--no-resolve-image", "--name", name, "busybox", "top") 607 c.Assert(err, checker.IsNil, check.Commentf("%s", out)) 608 c.Assert(strings.TrimSpace(out), checker.Not(checker.Equals), "") 609 610 // make sure task has been deployed. 611 waitAndAssert(c, defaultReconciliationTimeout, d.CheckServiceRunningTasks(name), checker.Equals, 1) 612 613 // Filter non-tasks 614 out, err = d.Cmd("ps", "-a", "-q", "--filter=is-task=false") 615 c.Assert(err, checker.IsNil, check.Commentf("%s", out)) 616 psOut := strings.TrimSpace(out) 617 c.Assert(psOut, checker.Equals, bareID, check.Commentf("Expected id %s, got %s for is-task label, output %q", bareID, psOut, out)) 618 619 // Filter tasks 620 out, err = d.Cmd("ps", "-a", "-q", "--filter=is-task=true") 621 c.Assert(err, checker.IsNil, check.Commentf("%s", out)) 622 lines := strings.Split(strings.Trim(out, "\n "), "\n") 623 c.Assert(lines, checker.HasLen, 1) 624 c.Assert(lines[0], checker.Not(checker.Equals), bareID, check.Commentf("Expected not %s, but got it for is-task label, output %q", bareID, out)) 625 } 626 627 const globalNetworkPlugin = "global-network-plugin" 628 const globalIPAMPlugin = "global-ipam-plugin" 629 630 func setupRemoteGlobalNetworkPlugin(c *check.C, mux *http.ServeMux, url, netDrv, ipamDrv string) { 631 632 mux.HandleFunc("/Plugin.Activate", func(w http.ResponseWriter, r *http.Request) { 633 w.Header().Set("Content-Type", "application/vnd.docker.plugins.v1+json") 634 fmt.Fprintf(w, `{"Implements": ["%s", "%s"]}`, driverapi.NetworkPluginEndpointType, ipamapi.PluginEndpointType) 635 }) 636 637 // Network driver implementation 638 mux.HandleFunc(fmt.Sprintf("/%s.GetCapabilities", driverapi.NetworkPluginEndpointType), func(w http.ResponseWriter, r *http.Request) { 639 w.Header().Set("Content-Type", "application/vnd.docker.plugins.v1+json") 640 fmt.Fprintf(w, `{"Scope":"global"}`) 641 }) 642 643 mux.HandleFunc(fmt.Sprintf("/%s.AllocateNetwork", driverapi.NetworkPluginEndpointType), func(w http.ResponseWriter, r *http.Request) { 644 err := json.NewDecoder(r.Body).Decode(&remoteDriverNetworkRequest) 645 if err != nil { 646 http.Error(w, "Unable to decode JSON payload: "+err.Error(), http.StatusBadRequest) 647 return 648 } 649 w.Header().Set("Content-Type", "application/vnd.docker.plugins.v1+json") 650 fmt.Fprintf(w, "null") 651 }) 652 653 mux.HandleFunc(fmt.Sprintf("/%s.FreeNetwork", driverapi.NetworkPluginEndpointType), func(w http.ResponseWriter, r *http.Request) { 654 w.Header().Set("Content-Type", "application/vnd.docker.plugins.v1+json") 655 fmt.Fprintf(w, "null") 656 }) 657 658 mux.HandleFunc(fmt.Sprintf("/%s.CreateNetwork", driverapi.NetworkPluginEndpointType), func(w http.ResponseWriter, r *http.Request) { 659 err := json.NewDecoder(r.Body).Decode(&remoteDriverNetworkRequest) 660 if err != nil { 661 http.Error(w, "Unable to decode JSON payload: "+err.Error(), http.StatusBadRequest) 662 return 663 } 664 w.Header().Set("Content-Type", "application/vnd.docker.plugins.v1+json") 665 fmt.Fprintf(w, "null") 666 }) 667 668 mux.HandleFunc(fmt.Sprintf("/%s.DeleteNetwork", driverapi.NetworkPluginEndpointType), func(w http.ResponseWriter, r *http.Request) { 669 w.Header().Set("Content-Type", "application/vnd.docker.plugins.v1+json") 670 fmt.Fprintf(w, "null") 671 }) 672 673 mux.HandleFunc(fmt.Sprintf("/%s.CreateEndpoint", driverapi.NetworkPluginEndpointType), func(w http.ResponseWriter, r *http.Request) { 674 w.Header().Set("Content-Type", "application/vnd.docker.plugins.v1+json") 675 fmt.Fprintf(w, `{"Interface":{"MacAddress":"a0:b1:c2:d3:e4:f5"}}`) 676 }) 677 678 mux.HandleFunc(fmt.Sprintf("/%s.Join", driverapi.NetworkPluginEndpointType), func(w http.ResponseWriter, r *http.Request) { 679 w.Header().Set("Content-Type", "application/vnd.docker.plugins.v1+json") 680 681 veth := &netlink.Veth{ 682 LinkAttrs: netlink.LinkAttrs{Name: "randomIfName", TxQLen: 0}, PeerName: "cnt0"} 683 if err := netlink.LinkAdd(veth); err != nil { 684 fmt.Fprintf(w, `{"Error":"failed to add veth pair: `+err.Error()+`"}`) 685 } else { 686 fmt.Fprintf(w, `{"InterfaceName":{ "SrcName":"cnt0", "DstPrefix":"veth"}}`) 687 } 688 }) 689 690 mux.HandleFunc(fmt.Sprintf("/%s.Leave", driverapi.NetworkPluginEndpointType), func(w http.ResponseWriter, r *http.Request) { 691 w.Header().Set("Content-Type", "application/vnd.docker.plugins.v1+json") 692 fmt.Fprintf(w, "null") 693 }) 694 695 mux.HandleFunc(fmt.Sprintf("/%s.DeleteEndpoint", driverapi.NetworkPluginEndpointType), func(w http.ResponseWriter, r *http.Request) { 696 w.Header().Set("Content-Type", "application/vnd.docker.plugins.v1+json") 697 if link, err := netlink.LinkByName("cnt0"); err == nil { 698 netlink.LinkDel(link) 699 } 700 fmt.Fprintf(w, "null") 701 }) 702 703 // IPAM Driver implementation 704 var ( 705 poolRequest remoteipam.RequestPoolRequest 706 poolReleaseReq remoteipam.ReleasePoolRequest 707 addressRequest remoteipam.RequestAddressRequest 708 addressReleaseReq remoteipam.ReleaseAddressRequest 709 lAS = "localAS" 710 gAS = "globalAS" 711 pool = "172.28.0.0/16" 712 poolID = lAS + "/" + pool 713 gw = "172.28.255.254/16" 714 ) 715 716 mux.HandleFunc(fmt.Sprintf("/%s.GetDefaultAddressSpaces", ipamapi.PluginEndpointType), func(w http.ResponseWriter, r *http.Request) { 717 w.Header().Set("Content-Type", "application/vnd.docker.plugins.v1+json") 718 fmt.Fprintf(w, `{"LocalDefaultAddressSpace":"`+lAS+`", "GlobalDefaultAddressSpace": "`+gAS+`"}`) 719 }) 720 721 mux.HandleFunc(fmt.Sprintf("/%s.RequestPool", ipamapi.PluginEndpointType), func(w http.ResponseWriter, r *http.Request) { 722 err := json.NewDecoder(r.Body).Decode(&poolRequest) 723 if err != nil { 724 http.Error(w, "Unable to decode JSON payload: "+err.Error(), http.StatusBadRequest) 725 return 726 } 727 w.Header().Set("Content-Type", "application/vnd.docker.plugins.v1+json") 728 if poolRequest.AddressSpace != lAS && poolRequest.AddressSpace != gAS { 729 fmt.Fprintf(w, `{"Error":"Unknown address space in pool request: `+poolRequest.AddressSpace+`"}`) 730 } else if poolRequest.Pool != "" && poolRequest.Pool != pool { 731 fmt.Fprintf(w, `{"Error":"Cannot handle explicit pool requests yet"}`) 732 } else { 733 fmt.Fprintf(w, `{"PoolID":"`+poolID+`", "Pool":"`+pool+`"}`) 734 } 735 }) 736 737 mux.HandleFunc(fmt.Sprintf("/%s.RequestAddress", ipamapi.PluginEndpointType), func(w http.ResponseWriter, r *http.Request) { 738 err := json.NewDecoder(r.Body).Decode(&addressRequest) 739 if err != nil { 740 http.Error(w, "Unable to decode JSON payload: "+err.Error(), http.StatusBadRequest) 741 return 742 } 743 w.Header().Set("Content-Type", "application/vnd.docker.plugins.v1+json") 744 // make sure libnetwork is now querying on the expected pool id 745 if addressRequest.PoolID != poolID { 746 fmt.Fprintf(w, `{"Error":"unknown pool id"}`) 747 } else if addressRequest.Address != "" { 748 fmt.Fprintf(w, `{"Error":"Cannot handle explicit address requests yet"}`) 749 } else { 750 fmt.Fprintf(w, `{"Address":"`+gw+`"}`) 751 } 752 }) 753 754 mux.HandleFunc(fmt.Sprintf("/%s.ReleaseAddress", ipamapi.PluginEndpointType), func(w http.ResponseWriter, r *http.Request) { 755 err := json.NewDecoder(r.Body).Decode(&addressReleaseReq) 756 if err != nil { 757 http.Error(w, "Unable to decode JSON payload: "+err.Error(), http.StatusBadRequest) 758 return 759 } 760 w.Header().Set("Content-Type", "application/vnd.docker.plugins.v1+json") 761 // make sure libnetwork is now asking to release the expected address from the expected poolid 762 if addressRequest.PoolID != poolID { 763 fmt.Fprintf(w, `{"Error":"unknown pool id"}`) 764 } else if addressReleaseReq.Address != gw { 765 fmt.Fprintf(w, `{"Error":"unknown address"}`) 766 } else { 767 fmt.Fprintf(w, "null") 768 } 769 }) 770 771 mux.HandleFunc(fmt.Sprintf("/%s.ReleasePool", ipamapi.PluginEndpointType), func(w http.ResponseWriter, r *http.Request) { 772 err := json.NewDecoder(r.Body).Decode(&poolReleaseReq) 773 if err != nil { 774 http.Error(w, "Unable to decode JSON payload: "+err.Error(), http.StatusBadRequest) 775 return 776 } 777 w.Header().Set("Content-Type", "application/vnd.docker.plugins.v1+json") 778 // make sure libnetwork is now asking to release the expected poolid 779 if addressRequest.PoolID != poolID { 780 fmt.Fprintf(w, `{"Error":"unknown pool id"}`) 781 } else { 782 fmt.Fprintf(w, "null") 783 } 784 }) 785 786 err := os.MkdirAll("/etc/docker/plugins", 0755) 787 c.Assert(err, checker.IsNil) 788 789 fileName := fmt.Sprintf("/etc/docker/plugins/%s.spec", netDrv) 790 err = ioutil.WriteFile(fileName, []byte(url), 0644) 791 c.Assert(err, checker.IsNil) 792 793 ipamFileName := fmt.Sprintf("/etc/docker/plugins/%s.spec", ipamDrv) 794 err = ioutil.WriteFile(ipamFileName, []byte(url), 0644) 795 c.Assert(err, checker.IsNil) 796 } 797 798 func (s *DockerSwarmSuite) TestSwarmNetworkPlugin(c *check.C) { 799 mux := http.NewServeMux() 800 s.server = httptest.NewServer(mux) 801 c.Assert(s.server, check.NotNil) // check that HTTP server has started 802 setupRemoteGlobalNetworkPlugin(c, mux, s.server.URL, globalNetworkPlugin, globalIPAMPlugin) 803 defer func() { 804 s.server.Close() 805 err := os.RemoveAll("/etc/docker/plugins") 806 c.Assert(err, checker.IsNil) 807 }() 808 809 d := s.AddDaemon(c, true, true) 810 811 out, err := d.Cmd("network", "create", "-d", globalNetworkPlugin, "foo") 812 c.Assert(err, checker.NotNil, check.Commentf("%s", out)) 813 c.Assert(out, checker.Contains, "not supported in swarm mode") 814 } 815 816 // Test case for #24712 817 func (s *DockerSwarmSuite) TestSwarmServiceEnvFile(c *check.C) { 818 d := s.AddDaemon(c, true, true) 819 820 path := filepath.Join(d.Folder, "env.txt") 821 err := ioutil.WriteFile(path, []byte("VAR1=A\nVAR2=A\n"), 0644) 822 c.Assert(err, checker.IsNil) 823 824 name := "worker" 825 out, err := d.Cmd("service", "create", "--detach", "--no-resolve-image", "--env-file", path, "--env", "VAR1=B", "--env", "VAR1=C", "--env", "VAR2=", "--env", "VAR2", "--name", name, "busybox", "top") 826 c.Assert(err, checker.IsNil, check.Commentf("%s", out)) 827 c.Assert(strings.TrimSpace(out), checker.Not(checker.Equals), "") 828 829 // The complete env is [VAR1=A VAR2=A VAR1=B VAR1=C VAR2= VAR2] and duplicates will be removed => [VAR1=C VAR2] 830 out, err = d.Cmd("inspect", "--format", "{{ .Spec.TaskTemplate.ContainerSpec.Env }}", name) 831 c.Assert(err, checker.IsNil, check.Commentf("%s", out)) 832 c.Assert(out, checker.Contains, "[VAR1=C VAR2]") 833 } 834 835 func (s *DockerSwarmSuite) TestSwarmServiceTTY(c *check.C) { 836 d := s.AddDaemon(c, true, true) 837 838 name := "top" 839 840 ttyCheck := "if [ -t 0 ]; then echo TTY > /status && top; else echo none > /status && top; fi" 841 842 // Without --tty 843 expectedOutput := "none" 844 out, err := d.Cmd("service", "create", "--detach", "--no-resolve-image", "--name", name, "busybox", "sh", "-c", ttyCheck) 845 c.Assert(err, checker.IsNil, check.Commentf("%s", out)) 846 847 // Make sure task has been deployed. 848 waitAndAssert(c, defaultReconciliationTimeout, d.CheckActiveContainerCount, checker.Equals, 1) 849 850 // We need to get the container id. 851 out, err = d.Cmd("ps", "-q", "--no-trunc") 852 c.Assert(err, checker.IsNil, check.Commentf("%s", out)) 853 id := strings.TrimSpace(out) 854 855 out, err = d.Cmd("exec", id, "cat", "/status") 856 c.Assert(err, checker.IsNil, check.Commentf("%s", out)) 857 c.Assert(out, checker.Contains, expectedOutput, check.Commentf("Expected '%s', but got %q", expectedOutput, out)) 858 859 // Remove service 860 out, err = d.Cmd("service", "rm", name) 861 c.Assert(err, checker.IsNil, check.Commentf("%s", out)) 862 // Make sure container has been destroyed. 863 waitAndAssert(c, defaultReconciliationTimeout, d.CheckActiveContainerCount, checker.Equals, 0) 864 865 // With --tty 866 expectedOutput = "TTY" 867 out, err = d.Cmd("service", "create", "--detach", "--no-resolve-image", "--name", name, "--tty", "busybox", "sh", "-c", ttyCheck) 868 c.Assert(err, checker.IsNil, check.Commentf("%s", out)) 869 870 // Make sure task has been deployed. 871 waitAndAssert(c, defaultReconciliationTimeout, d.CheckActiveContainerCount, checker.Equals, 1) 872 873 // We need to get the container id. 874 out, err = d.Cmd("ps", "-q", "--no-trunc") 875 c.Assert(err, checker.IsNil, check.Commentf("%s", out)) 876 id = strings.TrimSpace(out) 877 878 out, err = d.Cmd("exec", id, "cat", "/status") 879 c.Assert(err, checker.IsNil, check.Commentf("%s", out)) 880 c.Assert(out, checker.Contains, expectedOutput, check.Commentf("Expected '%s', but got %q", expectedOutput, out)) 881 } 882 883 func (s *DockerSwarmSuite) TestSwarmServiceTTYUpdate(c *check.C) { 884 d := s.AddDaemon(c, true, true) 885 886 // Create a service 887 name := "top" 888 out, err := d.Cmd("service", "create", "--detach", "--no-resolve-image", "--name", name, "busybox", "top") 889 c.Assert(err, checker.IsNil, check.Commentf("%s", out)) 890 891 // Make sure task has been deployed. 892 waitAndAssert(c, defaultReconciliationTimeout, d.CheckActiveContainerCount, checker.Equals, 1) 893 894 out, err = d.Cmd("service", "inspect", "--format", "{{ .Spec.TaskTemplate.ContainerSpec.TTY }}", name) 895 c.Assert(err, checker.IsNil, check.Commentf("%s", out)) 896 c.Assert(strings.TrimSpace(out), checker.Equals, "false") 897 898 out, err = d.Cmd("service", "update", "--detach", "--tty", name) 899 c.Assert(err, checker.IsNil, check.Commentf("%s", out)) 900 901 out, err = d.Cmd("service", "inspect", "--format", "{{ .Spec.TaskTemplate.ContainerSpec.TTY }}", name) 902 c.Assert(err, checker.IsNil, check.Commentf("%s", out)) 903 c.Assert(strings.TrimSpace(out), checker.Equals, "true") 904 } 905 906 func (s *DockerSwarmSuite) TestSwarmServiceNetworkUpdate(c *check.C) { 907 d := s.AddDaemon(c, true, true) 908 909 result := icmd.RunCmd(d.Command("network", "create", "-d", "overlay", "foo")) 910 result.Assert(c, icmd.Success) 911 fooNetwork := strings.TrimSpace(string(result.Combined())) 912 913 result = icmd.RunCmd(d.Command("network", "create", "-d", "overlay", "bar")) 914 result.Assert(c, icmd.Success) 915 barNetwork := strings.TrimSpace(string(result.Combined())) 916 917 result = icmd.RunCmd(d.Command("network", "create", "-d", "overlay", "baz")) 918 result.Assert(c, icmd.Success) 919 bazNetwork := strings.TrimSpace(string(result.Combined())) 920 921 // Create a service 922 name := "top" 923 result = icmd.RunCmd(d.Command("service", "create", "--detach", "--no-resolve-image", "--network", "foo", "--network", "bar", "--name", name, "busybox", "top")) 924 result.Assert(c, icmd.Success) 925 926 // Make sure task has been deployed. 927 waitAndAssert(c, defaultReconciliationTimeout, d.CheckRunningTaskNetworks, checker.DeepEquals, 928 map[string]int{fooNetwork: 1, barNetwork: 1}) 929 930 // Remove a network 931 result = icmd.RunCmd(d.Command("service", "update", "--detach", "--network-rm", "foo", name)) 932 result.Assert(c, icmd.Success) 933 934 waitAndAssert(c, defaultReconciliationTimeout, d.CheckRunningTaskNetworks, checker.DeepEquals, 935 map[string]int{barNetwork: 1}) 936 937 // Add a network 938 result = icmd.RunCmd(d.Command("service", "update", "--detach", "--network-add", "baz", name)) 939 result.Assert(c, icmd.Success) 940 941 waitAndAssert(c, defaultReconciliationTimeout, d.CheckRunningTaskNetworks, checker.DeepEquals, 942 map[string]int{barNetwork: 1, bazNetwork: 1}) 943 } 944 945 func (s *DockerSwarmSuite) TestDNSConfig(c *check.C) { 946 d := s.AddDaemon(c, true, true) 947 948 // Create a service 949 name := "top" 950 out, err := d.Cmd("service", "create", "--detach", "--no-resolve-image", "--name", name, "--dns=1.2.3.4", "--dns-search=example.com", "--dns-option=timeout:3", "busybox", "top") 951 c.Assert(err, checker.IsNil, check.Commentf("%s", out)) 952 953 // Make sure task has been deployed. 954 waitAndAssert(c, defaultReconciliationTimeout, d.CheckActiveContainerCount, checker.Equals, 1) 955 956 // We need to get the container id. 957 out, err = d.Cmd("ps", "-a", "-q", "--no-trunc") 958 c.Assert(err, checker.IsNil, check.Commentf("%s", out)) 959 id := strings.TrimSpace(out) 960 961 // Compare against expected output. 962 expectedOutput1 := "nameserver 1.2.3.4" 963 expectedOutput2 := "search example.com" 964 expectedOutput3 := "options timeout:3" 965 out, err = d.Cmd("exec", id, "cat", "/etc/resolv.conf") 966 c.Assert(err, checker.IsNil, check.Commentf("%s", out)) 967 c.Assert(out, checker.Contains, expectedOutput1, check.Commentf("Expected '%s', but got %q", expectedOutput1, out)) 968 c.Assert(out, checker.Contains, expectedOutput2, check.Commentf("Expected '%s', but got %q", expectedOutput2, out)) 969 c.Assert(out, checker.Contains, expectedOutput3, check.Commentf("Expected '%s', but got %q", expectedOutput3, out)) 970 } 971 972 func (s *DockerSwarmSuite) TestDNSConfigUpdate(c *check.C) { 973 d := s.AddDaemon(c, true, true) 974 975 // Create a service 976 name := "top" 977 out, err := d.Cmd("service", "create", "--detach", "--no-resolve-image", "--name", name, "busybox", "top") 978 c.Assert(err, checker.IsNil, check.Commentf("%s", out)) 979 980 // Make sure task has been deployed. 981 waitAndAssert(c, defaultReconciliationTimeout, d.CheckActiveContainerCount, checker.Equals, 1) 982 983 out, err = d.Cmd("service", "update", "--detach", "--dns-add=1.2.3.4", "--dns-search-add=example.com", "--dns-option-add=timeout:3", name) 984 c.Assert(err, checker.IsNil, check.Commentf("%s", out)) 985 986 out, err = d.Cmd("service", "inspect", "--format", "{{ .Spec.TaskTemplate.ContainerSpec.DNSConfig }}", name) 987 c.Assert(err, checker.IsNil, check.Commentf("%s", out)) 988 c.Assert(strings.TrimSpace(out), checker.Equals, "{[1.2.3.4] [example.com] [timeout:3]}") 989 } 990 991 func getNodeStatus(c *check.C, d *daemon.Daemon) swarm.LocalNodeState { 992 info := d.SwarmInfo(c) 993 return info.LocalNodeState 994 } 995 996 func checkKeyIsEncrypted(d *daemon.Daemon) func(*check.C) (interface{}, check.CommentInterface) { 997 return func(c *check.C) (interface{}, check.CommentInterface) { 998 keyBytes, err := ioutil.ReadFile(filepath.Join(d.Folder, "root", "swarm", "certificates", "swarm-node.key")) 999 if err != nil { 1000 return fmt.Errorf("error reading key: %v", err), nil 1001 } 1002 1003 keyBlock, _ := pem.Decode(keyBytes) 1004 if keyBlock == nil { 1005 return fmt.Errorf("invalid PEM-encoded private key"), nil 1006 } 1007 1008 return keyutils.IsEncryptedPEMBlock(keyBlock), nil 1009 } 1010 } 1011 1012 func checkSwarmLockedToUnlocked(c *check.C, d *daemon.Daemon) { 1013 // Wait for the PEM file to become unencrypted 1014 waitAndAssert(c, defaultReconciliationTimeout, checkKeyIsEncrypted(d), checker.Equals, false) 1015 1016 d.RestartNode(c) 1017 waitAndAssert(c, time.Second, d.CheckLocalNodeState, checker.Equals, swarm.LocalNodeStateActive) 1018 } 1019 1020 func checkSwarmUnlockedToLocked(c *check.C, d *daemon.Daemon) { 1021 // Wait for the PEM file to become encrypted 1022 waitAndAssert(c, defaultReconciliationTimeout, checkKeyIsEncrypted(d), checker.Equals, true) 1023 1024 d.RestartNode(c) 1025 waitAndAssert(c, time.Second, d.CheckLocalNodeState, checker.Equals, swarm.LocalNodeStateLocked) 1026 } 1027 1028 func (s *DockerSwarmSuite) TestUnlockEngineAndUnlockedSwarm(c *check.C) { 1029 d := s.AddDaemon(c, false, false) 1030 1031 // unlocking a normal engine should return an error - it does not even ask for the key 1032 cmd := d.Command("swarm", "unlock") 1033 result := icmd.RunCmd(cmd) 1034 result.Assert(c, icmd.Expected{ 1035 ExitCode: 1, 1036 }) 1037 c.Assert(result.Combined(), checker.Contains, "Error: This node is not part of a swarm") 1038 c.Assert(result.Combined(), checker.Not(checker.Contains), "Please enter unlock key") 1039 1040 out, err := d.Cmd("swarm", "init") 1041 c.Assert(err, checker.IsNil, check.Commentf("%s", out)) 1042 1043 // unlocking an unlocked swarm should return an error - it does not even ask for the key 1044 cmd = d.Command("swarm", "unlock") 1045 result = icmd.RunCmd(cmd) 1046 result.Assert(c, icmd.Expected{ 1047 ExitCode: 1, 1048 }) 1049 c.Assert(result.Combined(), checker.Contains, "Error: swarm is not locked") 1050 c.Assert(result.Combined(), checker.Not(checker.Contains), "Please enter unlock key") 1051 } 1052 1053 func (s *DockerSwarmSuite) TestSwarmInitLocked(c *check.C) { 1054 d := s.AddDaemon(c, false, false) 1055 1056 outs, err := d.Cmd("swarm", "init", "--autolock") 1057 c.Assert(err, checker.IsNil, check.Commentf("%s", outs)) 1058 unlockKey := getUnlockKey(d, c, outs) 1059 1060 c.Assert(getNodeStatus(c, d), checker.Equals, swarm.LocalNodeStateActive) 1061 1062 // It starts off locked 1063 d.RestartNode(c) 1064 c.Assert(getNodeStatus(c, d), checker.Equals, swarm.LocalNodeStateLocked) 1065 1066 cmd := d.Command("swarm", "unlock") 1067 cmd.Stdin = bytes.NewBufferString("wrong-secret-key") 1068 icmd.RunCmd(cmd).Assert(c, icmd.Expected{ 1069 ExitCode: 1, 1070 Err: "invalid key", 1071 }) 1072 1073 c.Assert(getNodeStatus(c, d), checker.Equals, swarm.LocalNodeStateLocked) 1074 1075 cmd = d.Command("swarm", "unlock") 1076 cmd.Stdin = bytes.NewBufferString(unlockKey) 1077 icmd.RunCmd(cmd).Assert(c, icmd.Success) 1078 1079 c.Assert(getNodeStatus(c, d), checker.Equals, swarm.LocalNodeStateActive) 1080 1081 outs, err = d.Cmd("node", "ls") 1082 c.Assert(err, checker.IsNil, check.Commentf("%s", outs)) 1083 c.Assert(outs, checker.Not(checker.Contains), "Swarm is encrypted and needs to be unlocked") 1084 1085 outs, err = d.Cmd("swarm", "update", "--autolock=false") 1086 c.Assert(err, checker.IsNil, check.Commentf("%s", outs)) 1087 1088 checkSwarmLockedToUnlocked(c, d) 1089 1090 outs, err = d.Cmd("node", "ls") 1091 c.Assert(err, checker.IsNil, check.Commentf("%s", outs)) 1092 c.Assert(outs, checker.Not(checker.Contains), "Swarm is encrypted and needs to be unlocked") 1093 } 1094 1095 func (s *DockerSwarmSuite) TestSwarmLeaveLocked(c *check.C) { 1096 d := s.AddDaemon(c, false, false) 1097 1098 outs, err := d.Cmd("swarm", "init", "--autolock") 1099 c.Assert(err, checker.IsNil, check.Commentf("%s", outs)) 1100 1101 // It starts off locked 1102 d.RestartNode(c) 1103 1104 info := d.SwarmInfo(c) 1105 c.Assert(info.LocalNodeState, checker.Equals, swarm.LocalNodeStateLocked) 1106 1107 outs, _ = d.Cmd("node", "ls") 1108 c.Assert(outs, checker.Contains, "Swarm is encrypted and needs to be unlocked") 1109 1110 // `docker swarm leave` a locked swarm without --force will return an error 1111 outs, _ = d.Cmd("swarm", "leave") 1112 c.Assert(outs, checker.Contains, "Swarm is encrypted and locked.") 1113 1114 // It is OK for user to leave a locked swarm with --force 1115 outs, err = d.Cmd("swarm", "leave", "--force") 1116 c.Assert(err, checker.IsNil, check.Commentf("%s", outs)) 1117 1118 info = d.SwarmInfo(c) 1119 c.Assert(info.LocalNodeState, checker.Equals, swarm.LocalNodeStateInactive) 1120 1121 outs, err = d.Cmd("swarm", "init") 1122 c.Assert(err, checker.IsNil, check.Commentf("%s", outs)) 1123 1124 info = d.SwarmInfo(c) 1125 c.Assert(info.LocalNodeState, checker.Equals, swarm.LocalNodeStateActive) 1126 } 1127 1128 func (s *DockerSwarmSuite) TestSwarmLockUnlockCluster(c *check.C) { 1129 d1 := s.AddDaemon(c, true, true) 1130 d2 := s.AddDaemon(c, true, true) 1131 d3 := s.AddDaemon(c, true, true) 1132 1133 // they start off unlocked 1134 d2.RestartNode(c) 1135 c.Assert(getNodeStatus(c, d2), checker.Equals, swarm.LocalNodeStateActive) 1136 1137 // stop this one so it does not get autolock info 1138 d2.Stop(c) 1139 1140 // enable autolock 1141 outs, err := d1.Cmd("swarm", "update", "--autolock") 1142 c.Assert(err, checker.IsNil, check.Commentf("%s", outs)) 1143 unlockKey := getUnlockKey(d1, c, outs) 1144 1145 // The ones that got the cluster update should be set to locked 1146 for _, d := range []*daemon.Daemon{d1, d3} { 1147 checkSwarmUnlockedToLocked(c, d) 1148 1149 cmd := d.Command("swarm", "unlock") 1150 cmd.Stdin = bytes.NewBufferString(unlockKey) 1151 icmd.RunCmd(cmd).Assert(c, icmd.Success) 1152 c.Assert(getNodeStatus(c, d), checker.Equals, swarm.LocalNodeStateActive) 1153 } 1154 1155 // d2 never got the cluster update, so it is still set to unlocked 1156 d2.StartNode(c) 1157 c.Assert(getNodeStatus(c, d2), checker.Equals, swarm.LocalNodeStateActive) 1158 1159 // d2 is now set to lock 1160 checkSwarmUnlockedToLocked(c, d2) 1161 1162 // leave it locked, and set the cluster to no longer autolock 1163 outs, err = d1.Cmd("swarm", "update", "--autolock=false") 1164 c.Assert(err, checker.IsNil, check.Commentf("out: %v", outs)) 1165 1166 // the ones that got the update are now set to unlocked 1167 for _, d := range []*daemon.Daemon{d1, d3} { 1168 checkSwarmLockedToUnlocked(c, d) 1169 } 1170 1171 // d2 still locked 1172 c.Assert(getNodeStatus(c, d2), checker.Equals, swarm.LocalNodeStateLocked) 1173 1174 // unlock it 1175 cmd := d2.Command("swarm", "unlock") 1176 cmd.Stdin = bytes.NewBufferString(unlockKey) 1177 icmd.RunCmd(cmd).Assert(c, icmd.Success) 1178 c.Assert(getNodeStatus(c, d2), checker.Equals, swarm.LocalNodeStateActive) 1179 1180 // once it's caught up, d2 is set to not be locked 1181 checkSwarmLockedToUnlocked(c, d2) 1182 1183 // managers who join now are never set to locked in the first place 1184 d4 := s.AddDaemon(c, true, true) 1185 d4.RestartNode(c) 1186 c.Assert(getNodeStatus(c, d4), checker.Equals, swarm.LocalNodeStateActive) 1187 } 1188 1189 func (s *DockerSwarmSuite) TestSwarmJoinPromoteLocked(c *check.C) { 1190 d1 := s.AddDaemon(c, true, true) 1191 1192 // enable autolock 1193 outs, err := d1.Cmd("swarm", "update", "--autolock") 1194 c.Assert(err, checker.IsNil, check.Commentf("out: %v", outs)) 1195 unlockKey := getUnlockKey(d1, c, outs) 1196 1197 // joined workers start off unlocked 1198 d2 := s.AddDaemon(c, true, false) 1199 d2.RestartNode(c) 1200 waitAndAssert(c, time.Second, d2.CheckLocalNodeState, checker.Equals, swarm.LocalNodeStateActive) 1201 1202 // promote worker 1203 outs, err = d1.Cmd("node", "promote", d2.NodeID()) 1204 c.Assert(err, checker.IsNil) 1205 c.Assert(outs, checker.Contains, "promoted to a manager in the swarm") 1206 1207 // join new manager node 1208 d3 := s.AddDaemon(c, true, true) 1209 1210 // both new nodes are locked 1211 for _, d := range []*daemon.Daemon{d2, d3} { 1212 checkSwarmUnlockedToLocked(c, d) 1213 1214 cmd := d.Command("swarm", "unlock") 1215 cmd.Stdin = bytes.NewBufferString(unlockKey) 1216 icmd.RunCmd(cmd).Assert(c, icmd.Success) 1217 c.Assert(getNodeStatus(c, d), checker.Equals, swarm.LocalNodeStateActive) 1218 } 1219 1220 // demote manager back to worker - workers are not locked 1221 outs, err = d1.Cmd("node", "demote", d3.NodeID()) 1222 c.Assert(err, checker.IsNil) 1223 c.Assert(outs, checker.Contains, "demoted in the swarm") 1224 1225 // Wait for it to actually be demoted, for the key and cert to be replaced. 1226 // Then restart and assert that the node is not locked. If we don't wait for the cert 1227 // to be replaced, then the node still has the manager TLS key which is still locked 1228 // (because we never want a manager TLS key to be on disk unencrypted if the cluster 1229 // is set to autolock) 1230 waitAndAssert(c, defaultReconciliationTimeout, d3.CheckControlAvailable, checker.False) 1231 waitAndAssert(c, defaultReconciliationTimeout, func(c *check.C) (interface{}, check.CommentInterface) { 1232 certBytes, err := ioutil.ReadFile(filepath.Join(d3.Folder, "root", "swarm", "certificates", "swarm-node.crt")) 1233 if err != nil { 1234 return "", check.Commentf("error: %v", err) 1235 } 1236 certs, err := helpers.ParseCertificatesPEM(certBytes) 1237 if err == nil && len(certs) > 0 && len(certs[0].Subject.OrganizationalUnit) > 0 { 1238 return certs[0].Subject.OrganizationalUnit[0], nil 1239 } 1240 return "", check.Commentf("could not get organizational unit from certificate") 1241 }, checker.Equals, "swarm-worker") 1242 1243 // by now, it should *never* be locked on restart 1244 d3.RestartNode(c) 1245 waitAndAssert(c, time.Second, d3.CheckLocalNodeState, checker.Equals, swarm.LocalNodeStateActive) 1246 } 1247 1248 func (s *DockerSwarmSuite) TestSwarmRotateUnlockKey(c *check.C) { 1249 d := s.AddDaemon(c, true, true) 1250 1251 outs, err := d.Cmd("swarm", "update", "--autolock") 1252 c.Assert(err, checker.IsNil, check.Commentf("out: %v", outs)) 1253 unlockKey := getUnlockKey(d, c, outs) 1254 1255 // Rotate multiple times 1256 for i := 0; i != 3; i++ { 1257 outs, err = d.Cmd("swarm", "unlock-key", "-q", "--rotate") 1258 c.Assert(err, checker.IsNil, check.Commentf("out: %v", outs)) 1259 // Strip \n 1260 newUnlockKey := outs[:len(outs)-1] 1261 c.Assert(newUnlockKey, checker.Not(checker.Equals), "") 1262 c.Assert(newUnlockKey, checker.Not(checker.Equals), unlockKey) 1263 1264 d.RestartNode(c) 1265 c.Assert(getNodeStatus(c, d), checker.Equals, swarm.LocalNodeStateLocked) 1266 1267 outs, _ = d.Cmd("node", "ls") 1268 c.Assert(outs, checker.Contains, "Swarm is encrypted and needs to be unlocked") 1269 1270 cmd := d.Command("swarm", "unlock") 1271 cmd.Stdin = bytes.NewBufferString(unlockKey) 1272 result := icmd.RunCmd(cmd) 1273 1274 if result.Error == nil { 1275 // On occasion, the daemon may not have finished 1276 // rotating the KEK before restarting. The test is 1277 // intentionally written to explore this behavior. 1278 // When this happens, unlocking with the old key will 1279 // succeed. If we wait for the rotation to happen and 1280 // restart again, the new key should be required this 1281 // time. 1282 1283 time.Sleep(3 * time.Second) 1284 1285 d.RestartNode(c) 1286 1287 cmd = d.Command("swarm", "unlock") 1288 cmd.Stdin = bytes.NewBufferString(unlockKey) 1289 result = icmd.RunCmd(cmd) 1290 } 1291 result.Assert(c, icmd.Expected{ 1292 ExitCode: 1, 1293 Err: "invalid key", 1294 }) 1295 1296 outs, _ = d.Cmd("node", "ls") 1297 c.Assert(outs, checker.Contains, "Swarm is encrypted and needs to be unlocked") 1298 1299 cmd = d.Command("swarm", "unlock") 1300 cmd.Stdin = bytes.NewBufferString(newUnlockKey) 1301 icmd.RunCmd(cmd).Assert(c, icmd.Success) 1302 1303 c.Assert(getNodeStatus(c, d), checker.Equals, swarm.LocalNodeStateActive) 1304 1305 outs, err = d.Cmd("node", "ls") 1306 c.Assert(err, checker.IsNil) 1307 c.Assert(outs, checker.Not(checker.Contains), "Swarm is encrypted and needs to be unlocked") 1308 1309 unlockKey = newUnlockKey 1310 } 1311 } 1312 1313 // This differs from `TestSwarmRotateUnlockKey` because that one rotates a single node, which is the leader. 1314 // This one keeps the leader up, and asserts that other manager nodes in the cluster also have their unlock 1315 // key rotated. 1316 func (s *DockerSwarmSuite) TestSwarmClusterRotateUnlockKey(c *check.C) { 1317 if runtime.GOARCH == "s390x" { 1318 c.Skip("Disabled on s390x") 1319 } 1320 if runtime.GOARCH == "ppc64le" { 1321 c.Skip("Disabled on ppc64le") 1322 } 1323 1324 d1 := s.AddDaemon(c, true, true) // leader - don't restart this one, we don't want leader election delays 1325 d2 := s.AddDaemon(c, true, true) 1326 d3 := s.AddDaemon(c, true, true) 1327 1328 outs, err := d1.Cmd("swarm", "update", "--autolock") 1329 c.Assert(err, checker.IsNil, check.Commentf("%s", outs)) 1330 unlockKey := getUnlockKey(d1, c, outs) 1331 1332 // Rotate multiple times 1333 for i := 0; i != 3; i++ { 1334 outs, err = d1.Cmd("swarm", "unlock-key", "-q", "--rotate") 1335 c.Assert(err, checker.IsNil, check.Commentf("%s", outs)) 1336 // Strip \n 1337 newUnlockKey := outs[:len(outs)-1] 1338 c.Assert(newUnlockKey, checker.Not(checker.Equals), "") 1339 c.Assert(newUnlockKey, checker.Not(checker.Equals), unlockKey) 1340 1341 d2.RestartNode(c) 1342 d3.RestartNode(c) 1343 1344 for _, d := range []*daemon.Daemon{d2, d3} { 1345 c.Assert(getNodeStatus(c, d), checker.Equals, swarm.LocalNodeStateLocked) 1346 1347 outs, _ := d.Cmd("node", "ls") 1348 c.Assert(outs, checker.Contains, "Swarm is encrypted and needs to be unlocked") 1349 1350 cmd := d.Command("swarm", "unlock") 1351 cmd.Stdin = bytes.NewBufferString(unlockKey) 1352 result := icmd.RunCmd(cmd) 1353 1354 if result.Error == nil { 1355 // On occasion, the daemon may not have finished 1356 // rotating the KEK before restarting. The test is 1357 // intentionally written to explore this behavior. 1358 // When this happens, unlocking with the old key will 1359 // succeed. If we wait for the rotation to happen and 1360 // restart again, the new key should be required this 1361 // time. 1362 1363 time.Sleep(3 * time.Second) 1364 1365 d.RestartNode(c) 1366 1367 cmd = d.Command("swarm", "unlock") 1368 cmd.Stdin = bytes.NewBufferString(unlockKey) 1369 result = icmd.RunCmd(cmd) 1370 } 1371 result.Assert(c, icmd.Expected{ 1372 ExitCode: 1, 1373 Err: "invalid key", 1374 }) 1375 1376 outs, _ = d.Cmd("node", "ls") 1377 c.Assert(outs, checker.Contains, "Swarm is encrypted and needs to be unlocked") 1378 1379 cmd = d.Command("swarm", "unlock") 1380 cmd.Stdin = bytes.NewBufferString(newUnlockKey) 1381 icmd.RunCmd(cmd).Assert(c, icmd.Success) 1382 1383 c.Assert(getNodeStatus(c, d), checker.Equals, swarm.LocalNodeStateActive) 1384 1385 outs, err = d.Cmd("node", "ls") 1386 c.Assert(err, checker.IsNil, check.Commentf("%s", outs)) 1387 c.Assert(outs, checker.Not(checker.Contains), "Swarm is encrypted and needs to be unlocked") 1388 } 1389 1390 unlockKey = newUnlockKey 1391 } 1392 } 1393 1394 func (s *DockerSwarmSuite) TestSwarmAlternateLockUnlock(c *check.C) { 1395 d := s.AddDaemon(c, true, true) 1396 1397 for i := 0; i < 2; i++ { 1398 // set to lock 1399 outs, err := d.Cmd("swarm", "update", "--autolock") 1400 c.Assert(err, checker.IsNil, check.Commentf("out: %v", outs)) 1401 c.Assert(outs, checker.Contains, "docker swarm unlock") 1402 unlockKey := getUnlockKey(d, c, outs) 1403 1404 checkSwarmUnlockedToLocked(c, d) 1405 1406 cmd := d.Command("swarm", "unlock") 1407 cmd.Stdin = bytes.NewBufferString(unlockKey) 1408 icmd.RunCmd(cmd).Assert(c, icmd.Success) 1409 1410 c.Assert(getNodeStatus(c, d), checker.Equals, swarm.LocalNodeStateActive) 1411 1412 outs, err = d.Cmd("swarm", "update", "--autolock=false") 1413 c.Assert(err, checker.IsNil, check.Commentf("out: %v", outs)) 1414 1415 checkSwarmLockedToUnlocked(c, d) 1416 } 1417 } 1418 1419 func (s *DockerSwarmSuite) TestExtraHosts(c *check.C) { 1420 d := s.AddDaemon(c, true, true) 1421 1422 // Create a service 1423 name := "top" 1424 out, err := d.Cmd("service", "create", "--detach", "--no-resolve-image", "--name", name, "--host=example.com:1.2.3.4", "busybox", "top") 1425 c.Assert(err, checker.IsNil, check.Commentf("%s", out)) 1426 1427 // Make sure task has been deployed. 1428 waitAndAssert(c, defaultReconciliationTimeout, d.CheckActiveContainerCount, checker.Equals, 1) 1429 1430 // We need to get the container id. 1431 out, err = d.Cmd("ps", "-a", "-q", "--no-trunc") 1432 c.Assert(err, checker.IsNil, check.Commentf("%s", out)) 1433 id := strings.TrimSpace(out) 1434 1435 // Compare against expected output. 1436 expectedOutput := "1.2.3.4\texample.com" 1437 out, err = d.Cmd("exec", id, "cat", "/etc/hosts") 1438 c.Assert(err, checker.IsNil, check.Commentf("%s", out)) 1439 c.Assert(out, checker.Contains, expectedOutput, check.Commentf("Expected '%s', but got %q", expectedOutput, out)) 1440 } 1441 1442 func (s *DockerSwarmSuite) TestSwarmManagerAddress(c *check.C) { 1443 d1 := s.AddDaemon(c, true, true) 1444 d2 := s.AddDaemon(c, true, false) 1445 d3 := s.AddDaemon(c, true, false) 1446 1447 // Manager Addresses will always show Node 1's address 1448 expectedOutput := fmt.Sprintf("Manager Addresses:\n 127.0.0.1:%d\n", d1.SwarmPort) 1449 1450 out, err := d1.Cmd("info") 1451 c.Assert(err, checker.IsNil, check.Commentf("%s", out)) 1452 c.Assert(out, checker.Contains, expectedOutput) 1453 1454 out, err = d2.Cmd("info") 1455 c.Assert(err, checker.IsNil, check.Commentf("%s", out)) 1456 c.Assert(out, checker.Contains, expectedOutput) 1457 1458 out, err = d3.Cmd("info") 1459 c.Assert(err, checker.IsNil, check.Commentf("%s", out)) 1460 c.Assert(out, checker.Contains, expectedOutput) 1461 } 1462 1463 func (s *DockerSwarmSuite) TestSwarmNetworkIPAMOptions(c *check.C) { 1464 d := s.AddDaemon(c, true, true) 1465 1466 out, err := d.Cmd("network", "create", "-d", "overlay", "--ipam-opt", "foo=bar", "foo") 1467 c.Assert(err, checker.IsNil, check.Commentf("%s", out)) 1468 c.Assert(strings.TrimSpace(out), checker.Not(checker.Equals), "") 1469 1470 out, err = d.Cmd("network", "inspect", "--format", "{{.IPAM.Options}}", "foo") 1471 c.Assert(err, checker.IsNil, check.Commentf("%s", out)) 1472 c.Assert(strings.TrimSpace(out), checker.Contains, "foo:bar") 1473 c.Assert(strings.TrimSpace(out), checker.Contains, "com.docker.network.ipam.serial:true") 1474 1475 out, err = d.Cmd("service", "create", "--detach", "--no-resolve-image", "--network=foo", "--name", "top", "busybox", "top") 1476 c.Assert(err, checker.IsNil, check.Commentf("%s", out)) 1477 1478 // make sure task has been deployed. 1479 waitAndAssert(c, defaultReconciliationTimeout, d.CheckActiveContainerCount, checker.Equals, 1) 1480 1481 out, err = d.Cmd("network", "inspect", "--format", "{{.IPAM.Options}}", "foo") 1482 c.Assert(err, checker.IsNil, check.Commentf("%s", out)) 1483 c.Assert(strings.TrimSpace(out), checker.Contains, "foo:bar") 1484 c.Assert(strings.TrimSpace(out), checker.Contains, "com.docker.network.ipam.serial:true") 1485 } 1486 1487 // Test case for issue #27866, which did not allow NW name that is the prefix of a swarm NW ID. 1488 // e.g. if the ingress ID starts with "n1", it was impossible to create a NW named "n1". 1489 func (s *DockerSwarmSuite) TestSwarmNetworkCreateIssue27866(c *check.C) { 1490 d := s.AddDaemon(c, true, true) 1491 out, err := d.Cmd("network", "inspect", "-f", "{{.Id}}", "ingress") 1492 c.Assert(err, checker.IsNil, check.Commentf("out: %v", out)) 1493 ingressID := strings.TrimSpace(out) 1494 c.Assert(ingressID, checker.Not(checker.Equals), "") 1495 1496 // create a network of which name is the prefix of the ID of an overlay network 1497 // (ingressID in this case) 1498 newNetName := ingressID[0:2] 1499 out, err = d.Cmd("network", "create", "--driver", "overlay", newNetName) 1500 // In #27866, it was failing because of "network with name %s already exists" 1501 c.Assert(err, checker.IsNil, check.Commentf("out: %v", out)) 1502 out, err = d.Cmd("network", "rm", newNetName) 1503 c.Assert(err, checker.IsNil, check.Commentf("out: %v", out)) 1504 } 1505 1506 // Test case for https://github.com/docker/docker/pull/27938#issuecomment-265768303 1507 // This test creates two networks with the same name sequentially, with various drivers. 1508 // Since the operations in this test are done sequentially, the 2nd call should fail with 1509 // "network with name FOO already exists". 1510 // Note that it is to ok have multiple networks with the same name if the operations are done 1511 // in parallel. (#18864) 1512 func (s *DockerSwarmSuite) TestSwarmNetworkCreateDup(c *check.C) { 1513 d := s.AddDaemon(c, true, true) 1514 drivers := []string{"bridge", "overlay"} 1515 for i, driver1 := range drivers { 1516 nwName := fmt.Sprintf("network-test-%d", i) 1517 for _, driver2 := range drivers { 1518 c.Logf("Creating a network named %q with %q, then %q", 1519 nwName, driver1, driver2) 1520 out, err := d.Cmd("network", "create", "--driver", driver1, nwName) 1521 c.Assert(err, checker.IsNil, check.Commentf("out: %v", out)) 1522 out, err = d.Cmd("network", "create", "--driver", driver2, nwName) 1523 c.Assert(out, checker.Contains, 1524 fmt.Sprintf("network with name %s already exists", nwName)) 1525 c.Assert(err, checker.NotNil) 1526 c.Logf("As expected, the attempt to network %q with %q failed: %s", 1527 nwName, driver2, out) 1528 out, err = d.Cmd("network", "rm", nwName) 1529 c.Assert(err, checker.IsNil, check.Commentf("out: %v", out)) 1530 } 1531 } 1532 } 1533 1534 func (s *DockerSwarmSuite) TestSwarmPublishDuplicatePorts(c *check.C) { 1535 d := s.AddDaemon(c, true, true) 1536 1537 out, err := d.Cmd("service", "create", "--no-resolve-image", "--detach=true", "--publish", "5005:80", "--publish", "5006:80", "--publish", "80", "--publish", "80", "busybox", "top") 1538 c.Assert(err, check.IsNil, check.Commentf("%s", out)) 1539 id := strings.TrimSpace(out) 1540 1541 // make sure task has been deployed. 1542 waitAndAssert(c, defaultReconciliationTimeout, d.CheckActiveContainerCount, checker.Equals, 1) 1543 1544 // Total len = 4, with 2 dynamic ports and 2 non-dynamic ports 1545 // Dynamic ports are likely to be 30000 and 30001 but doesn't matter 1546 out, err = d.Cmd("service", "inspect", "--format", "{{.Endpoint.Ports}} len={{len .Endpoint.Ports}}", id) 1547 c.Assert(err, check.IsNil, check.Commentf("%s", out)) 1548 c.Assert(out, checker.Contains, "len=4") 1549 c.Assert(out, checker.Contains, "{ tcp 80 5005 ingress}") 1550 c.Assert(out, checker.Contains, "{ tcp 80 5006 ingress}") 1551 } 1552 1553 func (s *DockerSwarmSuite) TestSwarmJoinWithDrain(c *check.C) { 1554 d := s.AddDaemon(c, true, true) 1555 1556 out, err := d.Cmd("node", "ls") 1557 c.Assert(err, checker.IsNil) 1558 c.Assert(out, checker.Not(checker.Contains), "Drain") 1559 1560 out, err = d.Cmd("swarm", "join-token", "-q", "manager") 1561 c.Assert(err, checker.IsNil) 1562 c.Assert(strings.TrimSpace(out), checker.Not(checker.Equals), "") 1563 1564 token := strings.TrimSpace(out) 1565 1566 d1 := s.AddDaemon(c, false, false) 1567 1568 out, err = d1.Cmd("swarm", "join", "--availability=drain", "--token", token, d.SwarmListenAddr()) 1569 c.Assert(err, checker.IsNil) 1570 c.Assert(strings.TrimSpace(out), checker.Not(checker.Equals), "") 1571 1572 out, err = d.Cmd("node", "ls") 1573 c.Assert(err, checker.IsNil) 1574 c.Assert(out, checker.Contains, "Drain") 1575 1576 out, err = d1.Cmd("node", "ls") 1577 c.Assert(err, checker.IsNil) 1578 c.Assert(out, checker.Contains, "Drain") 1579 } 1580 1581 func (s *DockerSwarmSuite) TestSwarmInitWithDrain(c *check.C) { 1582 d := s.AddDaemon(c, false, false) 1583 1584 out, err := d.Cmd("swarm", "init", "--availability", "drain") 1585 c.Assert(err, checker.IsNil, check.Commentf("out: %v", out)) 1586 1587 out, err = d.Cmd("node", "ls") 1588 c.Assert(err, checker.IsNil) 1589 c.Assert(out, checker.Contains, "Drain") 1590 } 1591 1592 func (s *DockerSwarmSuite) TestSwarmReadonlyRootfs(c *check.C) { 1593 testRequires(c, DaemonIsLinux, UserNamespaceROMount) 1594 1595 d := s.AddDaemon(c, true, true) 1596 1597 out, err := d.Cmd("service", "create", "--detach", "--no-resolve-image", "--name", "top", "--read-only", "busybox", "top") 1598 c.Assert(err, checker.IsNil, check.Commentf("%s", out)) 1599 1600 // make sure task has been deployed. 1601 waitAndAssert(c, defaultReconciliationTimeout, d.CheckActiveContainerCount, checker.Equals, 1) 1602 1603 out, err = d.Cmd("service", "inspect", "--format", "{{ .Spec.TaskTemplate.ContainerSpec.ReadOnly }}", "top") 1604 c.Assert(err, checker.IsNil, check.Commentf("%s", out)) 1605 c.Assert(strings.TrimSpace(out), checker.Equals, "true") 1606 1607 containers := d.ActiveContainers(c) 1608 out, err = d.Cmd("inspect", "--type", "container", "--format", "{{.HostConfig.ReadonlyRootfs}}", containers[0]) 1609 c.Assert(err, checker.IsNil, check.Commentf("%s", out)) 1610 c.Assert(strings.TrimSpace(out), checker.Equals, "true") 1611 } 1612 1613 func (s *DockerSwarmSuite) TestNetworkInspectWithDuplicateNames(c *check.C) { 1614 d := s.AddDaemon(c, true, true) 1615 1616 name := "foo" 1617 options := types.NetworkCreate{ 1618 CheckDuplicate: false, 1619 Driver: "bridge", 1620 } 1621 1622 cli := d.NewClientT(c) 1623 defer cli.Close() 1624 1625 n1, err := cli.NetworkCreate(context.Background(), name, options) 1626 c.Assert(err, checker.IsNil) 1627 1628 // Full ID always works 1629 out, err := d.Cmd("network", "inspect", "--format", "{{.ID}}", n1.ID) 1630 c.Assert(err, checker.IsNil, check.Commentf("%s", out)) 1631 c.Assert(strings.TrimSpace(out), checker.Equals, n1.ID) 1632 1633 // Name works if it is unique 1634 out, err = d.Cmd("network", "inspect", "--format", "{{.ID}}", name) 1635 c.Assert(err, checker.IsNil, check.Commentf("%s", out)) 1636 c.Assert(strings.TrimSpace(out), checker.Equals, n1.ID) 1637 1638 n2, err := cli.NetworkCreate(context.Background(), name, options) 1639 c.Assert(err, checker.IsNil) 1640 // Full ID always works 1641 out, err = d.Cmd("network", "inspect", "--format", "{{.ID}}", n1.ID) 1642 c.Assert(err, checker.IsNil, check.Commentf("%s", out)) 1643 c.Assert(strings.TrimSpace(out), checker.Equals, n1.ID) 1644 1645 out, err = d.Cmd("network", "inspect", "--format", "{{.ID}}", n2.ID) 1646 c.Assert(err, checker.IsNil, check.Commentf("%s", out)) 1647 c.Assert(strings.TrimSpace(out), checker.Equals, n2.ID) 1648 1649 // Name with duplicates 1650 out, err = d.Cmd("network", "inspect", "--format", "{{.ID}}", name) 1651 c.Assert(err, checker.NotNil, check.Commentf("%s", out)) 1652 c.Assert(out, checker.Contains, "2 matches found based on name") 1653 1654 out, err = d.Cmd("network", "rm", n2.ID) 1655 c.Assert(err, checker.IsNil, check.Commentf("%s", out)) 1656 1657 // Duplicates with name but with different driver 1658 options.Driver = "overlay" 1659 1660 n2, err = cli.NetworkCreate(context.Background(), name, options) 1661 c.Assert(err, checker.IsNil) 1662 1663 // Full ID always works 1664 out, err = d.Cmd("network", "inspect", "--format", "{{.ID}}", n1.ID) 1665 c.Assert(err, checker.IsNil, check.Commentf("%s", out)) 1666 c.Assert(strings.TrimSpace(out), checker.Equals, n1.ID) 1667 1668 out, err = d.Cmd("network", "inspect", "--format", "{{.ID}}", n2.ID) 1669 c.Assert(err, checker.IsNil, check.Commentf("%s", out)) 1670 c.Assert(strings.TrimSpace(out), checker.Equals, n2.ID) 1671 1672 // Name with duplicates 1673 out, err = d.Cmd("network", "inspect", "--format", "{{.ID}}", name) 1674 c.Assert(err, checker.NotNil, check.Commentf("%s", out)) 1675 c.Assert(out, checker.Contains, "2 matches found based on name") 1676 } 1677 1678 func (s *DockerSwarmSuite) TestSwarmStopSignal(c *check.C) { 1679 testRequires(c, DaemonIsLinux, UserNamespaceROMount) 1680 1681 d := s.AddDaemon(c, true, true) 1682 1683 out, err := d.Cmd("service", "create", "--detach", "--no-resolve-image", "--name", "top", "--stop-signal=SIGHUP", "busybox", "top") 1684 c.Assert(err, checker.IsNil, check.Commentf("%s", out)) 1685 1686 // make sure task has been deployed. 1687 waitAndAssert(c, defaultReconciliationTimeout, d.CheckActiveContainerCount, checker.Equals, 1) 1688 1689 out, err = d.Cmd("service", "inspect", "--format", "{{ .Spec.TaskTemplate.ContainerSpec.StopSignal }}", "top") 1690 c.Assert(err, checker.IsNil, check.Commentf("%s", out)) 1691 c.Assert(strings.TrimSpace(out), checker.Equals, "SIGHUP") 1692 1693 containers := d.ActiveContainers(c) 1694 out, err = d.Cmd("inspect", "--type", "container", "--format", "{{.Config.StopSignal}}", containers[0]) 1695 c.Assert(err, checker.IsNil, check.Commentf("%s", out)) 1696 c.Assert(strings.TrimSpace(out), checker.Equals, "SIGHUP") 1697 1698 out, err = d.Cmd("service", "update", "--detach", "--stop-signal=SIGUSR1", "top") 1699 c.Assert(err, checker.IsNil, check.Commentf("%s", out)) 1700 1701 out, err = d.Cmd("service", "inspect", "--format", "{{ .Spec.TaskTemplate.ContainerSpec.StopSignal }}", "top") 1702 c.Assert(err, checker.IsNil, check.Commentf("%s", out)) 1703 c.Assert(strings.TrimSpace(out), checker.Equals, "SIGUSR1") 1704 } 1705 1706 func (s *DockerSwarmSuite) TestSwarmServiceLsFilterMode(c *check.C) { 1707 d := s.AddDaemon(c, true, true) 1708 1709 out, err := d.Cmd("service", "create", "--detach", "--no-resolve-image", "--name", "top1", "busybox", "top") 1710 c.Assert(err, checker.IsNil, check.Commentf("%s", out)) 1711 c.Assert(strings.TrimSpace(out), checker.Not(checker.Equals), "") 1712 1713 out, err = d.Cmd("service", "create", "--detach", "--no-resolve-image", "--name", "top2", "--mode=global", "busybox", "top") 1714 c.Assert(err, checker.IsNil, check.Commentf("%s", out)) 1715 c.Assert(strings.TrimSpace(out), checker.Not(checker.Equals), "") 1716 1717 // make sure task has been deployed. 1718 waitAndAssert(c, defaultReconciliationTimeout, d.CheckActiveContainerCount, checker.Equals, 2) 1719 1720 out, err = d.Cmd("service", "ls") 1721 c.Assert(err, checker.IsNil, check.Commentf("%s", out)) 1722 c.Assert(out, checker.Contains, "top1") 1723 c.Assert(out, checker.Contains, "top2") 1724 c.Assert(out, checker.Not(checker.Contains), "localnet") 1725 1726 out, err = d.Cmd("service", "ls", "--filter", "mode=global") 1727 c.Assert(out, checker.Not(checker.Contains), "top1") 1728 c.Assert(out, checker.Contains, "top2") 1729 c.Assert(err, checker.IsNil, check.Commentf("%s", out)) 1730 1731 out, err = d.Cmd("service", "ls", "--filter", "mode=replicated") 1732 c.Assert(err, checker.IsNil, check.Commentf("%s", out)) 1733 c.Assert(out, checker.Contains, "top1") 1734 c.Assert(out, checker.Not(checker.Contains), "top2") 1735 } 1736 1737 func (s *DockerSwarmSuite) TestSwarmInitUnspecifiedDataPathAddr(c *check.C) { 1738 d := s.AddDaemon(c, false, false) 1739 1740 out, err := d.Cmd("swarm", "init", "--data-path-addr", "0.0.0.0") 1741 c.Assert(err, checker.NotNil) 1742 c.Assert(out, checker.Contains, "data path address must be a non-zero IP") 1743 1744 out, err = d.Cmd("swarm", "init", "--data-path-addr", "0.0.0.0:2000") 1745 c.Assert(err, checker.NotNil) 1746 c.Assert(out, checker.Contains, "data path address must be a non-zero IP") 1747 } 1748 1749 func (s *DockerSwarmSuite) TestSwarmJoinLeave(c *check.C) { 1750 d := s.AddDaemon(c, true, true) 1751 1752 out, err := d.Cmd("swarm", "join-token", "-q", "worker") 1753 c.Assert(err, checker.IsNil) 1754 c.Assert(strings.TrimSpace(out), checker.Not(checker.Equals), "") 1755 1756 token := strings.TrimSpace(out) 1757 1758 // Verify that back to back join/leave does not cause panics 1759 d1 := s.AddDaemon(c, false, false) 1760 for i := 0; i < 10; i++ { 1761 out, err = d1.Cmd("swarm", "join", "--token", token, d.SwarmListenAddr()) 1762 c.Assert(err, checker.IsNil) 1763 c.Assert(strings.TrimSpace(out), checker.Not(checker.Equals), "") 1764 1765 _, err = d1.Cmd("swarm", "leave") 1766 c.Assert(err, checker.IsNil) 1767 } 1768 } 1769 1770 const defaultRetryCount = 10 1771 1772 func waitForEvent(c *check.C, d *daemon.Daemon, since string, filter string, event string, retry int) string { 1773 if retry < 1 { 1774 c.Fatalf("retry count %d is invalid. It should be no less than 1", retry) 1775 return "" 1776 } 1777 var out string 1778 for i := 0; i < retry; i++ { 1779 until := daemonUnixTime(c) 1780 var err error 1781 if len(filter) > 0 { 1782 out, err = d.Cmd("events", "--since", since, "--until", until, filter) 1783 } else { 1784 out, err = d.Cmd("events", "--since", since, "--until", until) 1785 } 1786 c.Assert(err, checker.IsNil, check.Commentf("%s", out)) 1787 if strings.Contains(out, event) { 1788 return strings.TrimSpace(out) 1789 } 1790 // no need to sleep after last retry 1791 if i < retry-1 { 1792 time.Sleep(200 * time.Millisecond) 1793 } 1794 } 1795 c.Fatalf("docker events output '%s' doesn't contain event '%s'", out, event) 1796 return "" 1797 } 1798 1799 func (s *DockerSwarmSuite) TestSwarmClusterEventsSource(c *check.C) { 1800 d1 := s.AddDaemon(c, true, true) 1801 d2 := s.AddDaemon(c, true, true) 1802 d3 := s.AddDaemon(c, true, false) 1803 1804 // create a network 1805 out, err := d1.Cmd("network", "create", "--attachable", "-d", "overlay", "foo") 1806 c.Assert(err, checker.IsNil, check.Commentf("%s", out)) 1807 networkID := strings.TrimSpace(out) 1808 c.Assert(networkID, checker.Not(checker.Equals), "") 1809 1810 // d1, d2 are managers that can get swarm events 1811 waitForEvent(c, d1, "0", "-f scope=swarm", "network create "+networkID, defaultRetryCount) 1812 waitForEvent(c, d2, "0", "-f scope=swarm", "network create "+networkID, defaultRetryCount) 1813 1814 // d3 is a worker, not able to get cluster events 1815 out = waitForEvent(c, d3, "0", "-f scope=swarm", "", 1) 1816 c.Assert(out, checker.Not(checker.Contains), "network create ") 1817 } 1818 1819 func (s *DockerSwarmSuite) TestSwarmClusterEventsScope(c *check.C) { 1820 d := s.AddDaemon(c, true, true) 1821 1822 // create a service 1823 out, err := d.Cmd("service", "create", "--no-resolve-image", "--name", "test", "--detach=false", "busybox", "top") 1824 c.Assert(err, checker.IsNil, check.Commentf("%s", out)) 1825 serviceID := strings.Split(out, "\n")[0] 1826 1827 // scope swarm filters cluster events 1828 out = waitForEvent(c, d, "0", "-f scope=swarm", "service create "+serviceID, defaultRetryCount) 1829 c.Assert(out, checker.Not(checker.Contains), "container create ") 1830 1831 // all events are returned if scope is not specified 1832 waitForEvent(c, d, "0", "", "service create "+serviceID, 1) 1833 waitForEvent(c, d, "0", "", "container create ", defaultRetryCount) 1834 1835 // scope local only shows non-cluster events 1836 out = waitForEvent(c, d, "0", "-f scope=local", "container create ", 1) 1837 c.Assert(out, checker.Not(checker.Contains), "service create ") 1838 } 1839 1840 func (s *DockerSwarmSuite) TestSwarmClusterEventsType(c *check.C) { 1841 d := s.AddDaemon(c, true, true) 1842 1843 // create a service 1844 out, err := d.Cmd("service", "create", "--no-resolve-image", "--name", "test", "--detach=false", "busybox", "top") 1845 c.Assert(err, checker.IsNil, check.Commentf("%s", out)) 1846 serviceID := strings.Split(out, "\n")[0] 1847 1848 // create a network 1849 out, err = d.Cmd("network", "create", "--attachable", "-d", "overlay", "foo") 1850 c.Assert(err, checker.IsNil, check.Commentf("%s", out)) 1851 networkID := strings.TrimSpace(out) 1852 c.Assert(networkID, checker.Not(checker.Equals), "") 1853 1854 // filter by service 1855 out = waitForEvent(c, d, "0", "-f type=service", "service create "+serviceID, defaultRetryCount) 1856 c.Assert(out, checker.Not(checker.Contains), "network create") 1857 1858 // filter by network 1859 out = waitForEvent(c, d, "0", "-f type=network", "network create "+networkID, defaultRetryCount) 1860 c.Assert(out, checker.Not(checker.Contains), "service create") 1861 } 1862 1863 func (s *DockerSwarmSuite) TestSwarmClusterEventsService(c *check.C) { 1864 d := s.AddDaemon(c, true, true) 1865 1866 // create a service 1867 out, err := d.Cmd("service", "create", "--no-resolve-image", "--name", "test", "--detach=false", "busybox", "top") 1868 c.Assert(err, checker.IsNil, check.Commentf("%s", out)) 1869 serviceID := strings.Split(out, "\n")[0] 1870 1871 // validate service create event 1872 waitForEvent(c, d, "0", "-f scope=swarm", "service create "+serviceID, defaultRetryCount) 1873 1874 t1 := daemonUnixTime(c) 1875 out, err = d.Cmd("service", "update", "--force", "--detach=false", "test") 1876 c.Assert(err, checker.IsNil, check.Commentf("%s", out)) 1877 1878 // wait for service update start 1879 out = waitForEvent(c, d, t1, "-f scope=swarm", "service update "+serviceID, defaultRetryCount) 1880 c.Assert(out, checker.Contains, "updatestate.new=updating") 1881 1882 // allow service update complete. This is a service with 1 instance 1883 time.Sleep(400 * time.Millisecond) 1884 out = waitForEvent(c, d, t1, "-f scope=swarm", "service update "+serviceID, defaultRetryCount) 1885 c.Assert(out, checker.Contains, "updatestate.new=completed, updatestate.old=updating") 1886 1887 // scale service 1888 t2 := daemonUnixTime(c) 1889 out, err = d.Cmd("service", "scale", "test=3") 1890 c.Assert(err, checker.IsNil, check.Commentf("%s", out)) 1891 1892 out = waitForEvent(c, d, t2, "-f scope=swarm", "service update "+serviceID, defaultRetryCount) 1893 c.Assert(out, checker.Contains, "replicas.new=3, replicas.old=1") 1894 1895 // remove service 1896 t3 := daemonUnixTime(c) 1897 out, err = d.Cmd("service", "rm", "test") 1898 c.Assert(err, checker.IsNil, check.Commentf("%s", out)) 1899 1900 waitForEvent(c, d, t3, "-f scope=swarm", "service remove "+serviceID, defaultRetryCount) 1901 } 1902 1903 func (s *DockerSwarmSuite) TestSwarmClusterEventsNode(c *check.C) { 1904 d1 := s.AddDaemon(c, true, true) 1905 s.AddDaemon(c, true, true) 1906 d3 := s.AddDaemon(c, true, true) 1907 1908 d3ID := d3.NodeID() 1909 waitForEvent(c, d1, "0", "-f scope=swarm", "node create "+d3ID, defaultRetryCount) 1910 1911 t1 := daemonUnixTime(c) 1912 out, err := d1.Cmd("node", "update", "--availability=pause", d3ID) 1913 c.Assert(err, checker.IsNil, check.Commentf("%s", out)) 1914 1915 // filter by type 1916 out = waitForEvent(c, d1, t1, "-f type=node", "node update "+d3ID, defaultRetryCount) 1917 c.Assert(out, checker.Contains, "availability.new=pause, availability.old=active") 1918 1919 t2 := daemonUnixTime(c) 1920 out, err = d1.Cmd("node", "demote", d3ID) 1921 c.Assert(err, checker.IsNil, check.Commentf("%s", out)) 1922 1923 waitForEvent(c, d1, t2, "-f type=node", "node update "+d3ID, defaultRetryCount) 1924 1925 t3 := daemonUnixTime(c) 1926 out, err = d1.Cmd("node", "rm", "-f", d3ID) 1927 c.Assert(err, checker.IsNil, check.Commentf("%s", out)) 1928 1929 // filter by scope 1930 waitForEvent(c, d1, t3, "-f scope=swarm", "node remove "+d3ID, defaultRetryCount) 1931 } 1932 1933 func (s *DockerSwarmSuite) TestSwarmClusterEventsNetwork(c *check.C) { 1934 d := s.AddDaemon(c, true, true) 1935 1936 // create a network 1937 out, err := d.Cmd("network", "create", "--attachable", "-d", "overlay", "foo") 1938 c.Assert(err, checker.IsNil, check.Commentf("%s", out)) 1939 networkID := strings.TrimSpace(out) 1940 1941 waitForEvent(c, d, "0", "-f scope=swarm", "network create "+networkID, defaultRetryCount) 1942 1943 // remove network 1944 t1 := daemonUnixTime(c) 1945 out, err = d.Cmd("network", "rm", "foo") 1946 c.Assert(err, checker.IsNil, check.Commentf("%s", out)) 1947 1948 // filtered by network 1949 waitForEvent(c, d, t1, "-f type=network", "network remove "+networkID, defaultRetryCount) 1950 } 1951 1952 func (s *DockerSwarmSuite) TestSwarmClusterEventsSecret(c *check.C) { 1953 d := s.AddDaemon(c, true, true) 1954 1955 testName := "test_secret" 1956 id := d.CreateSecret(c, swarm.SecretSpec{ 1957 Annotations: swarm.Annotations{ 1958 Name: testName, 1959 }, 1960 Data: []byte("TESTINGDATA"), 1961 }) 1962 c.Assert(id, checker.Not(checker.Equals), "", check.Commentf("secrets: %s", id)) 1963 1964 waitForEvent(c, d, "0", "-f scope=swarm", "secret create "+id, defaultRetryCount) 1965 1966 t1 := daemonUnixTime(c) 1967 d.DeleteSecret(c, id) 1968 // filtered by secret 1969 waitForEvent(c, d, t1, "-f type=secret", "secret remove "+id, defaultRetryCount) 1970 } 1971 1972 func (s *DockerSwarmSuite) TestSwarmClusterEventsConfig(c *check.C) { 1973 d := s.AddDaemon(c, true, true) 1974 1975 testName := "test_config" 1976 id := d.CreateConfig(c, swarm.ConfigSpec{ 1977 Annotations: swarm.Annotations{ 1978 Name: testName, 1979 }, 1980 Data: []byte("TESTINGDATA"), 1981 }) 1982 c.Assert(id, checker.Not(checker.Equals), "", check.Commentf("configs: %s", id)) 1983 1984 waitForEvent(c, d, "0", "-f scope=swarm", "config create "+id, defaultRetryCount) 1985 1986 t1 := daemonUnixTime(c) 1987 d.DeleteConfig(c, id) 1988 // filtered by config 1989 waitForEvent(c, d, t1, "-f type=config", "config remove "+id, defaultRetryCount) 1990 } 1991 1992 func getUnlockKey(d *daemon.Daemon, c *check.C, autolockOutput string) string { 1993 unlockKey, err := d.Cmd("swarm", "unlock-key", "-q") 1994 c.Assert(err, checker.IsNil, check.Commentf("%s", unlockKey)) 1995 unlockKey = strings.TrimSuffix(unlockKey, "\n") 1996 1997 // Check that "docker swarm init --autolock" or "docker swarm update --autolock" 1998 // contains all the expected strings, including the unlock key 1999 c.Assert(autolockOutput, checker.Contains, "docker swarm unlock") 2000 c.Assert(autolockOutput, checker.Contains, unlockKey) 2001 2002 return unlockKey 2003 }