github.com/rita33cool1/iot-system-gateway@v0.0.0-20200911033302-e65bde238cc5/docker-engine/integration-cli/docker_cli_swarm_test.go (about) 1 // +build !windows 2 3 package main 4 5 import ( 6 "bytes" 7 "encoding/json" 8 "encoding/pem" 9 "fmt" 10 "io/ioutil" 11 "net/http" 12 "net/http/httptest" 13 "os" 14 "path/filepath" 15 "strings" 16 "time" 17 18 "github.com/cloudflare/cfssl/helpers" 19 "github.com/docker/docker/api/types" 20 "github.com/docker/docker/api/types/swarm" 21 "github.com/docker/docker/integration-cli/checker" 22 "github.com/docker/docker/integration-cli/cli" 23 "github.com/docker/docker/integration-cli/daemon" 24 "github.com/docker/libnetwork/driverapi" 25 "github.com/docker/libnetwork/ipamapi" 26 remoteipam "github.com/docker/libnetwork/ipams/remote/api" 27 "github.com/docker/swarmkit/ca/keyutils" 28 "github.com/go-check/check" 29 "github.com/gotestyourself/gotestyourself/fs" 30 "github.com/gotestyourself/gotestyourself/icmd" 31 "github.com/vishvananda/netlink" 32 "golang.org/x/net/context" 33 ) 34 35 func (s *DockerSwarmSuite) TestSwarmUpdate(c *check.C) { 36 d := s.AddDaemon(c, true, true) 37 38 getSpec := func() swarm.Spec { 39 sw := d.GetSwarm(c) 40 return sw.Spec 41 } 42 43 out, err := d.Cmd("swarm", "update", "--cert-expiry", "30h", "--dispatcher-heartbeat", "11s") 44 c.Assert(err, checker.IsNil, check.Commentf("out: %v", out)) 45 46 spec := getSpec() 47 c.Assert(spec.CAConfig.NodeCertExpiry, checker.Equals, 30*time.Hour) 48 c.Assert(spec.Dispatcher.HeartbeatPeriod, checker.Equals, 11*time.Second) 49 50 // setting anything under 30m for cert-expiry is not allowed 51 out, err = d.Cmd("swarm", "update", "--cert-expiry", "15m") 52 c.Assert(err, checker.NotNil) 53 c.Assert(out, checker.Contains, "minimum certificate expiry time") 54 spec = getSpec() 55 c.Assert(spec.CAConfig.NodeCertExpiry, checker.Equals, 30*time.Hour) 56 57 // passing an external CA (this is without starting a root rotation) does not fail 58 cli.Docker(cli.Args("swarm", "update", "--external-ca", "protocol=cfssl,url=https://something.org", 59 "--external-ca", "protocol=cfssl,url=https://somethingelse.org,cacert=fixtures/https/ca.pem"), 60 cli.Daemon(d)).Assert(c, icmd.Success) 61 62 expected, err := ioutil.ReadFile("fixtures/https/ca.pem") 63 c.Assert(err, checker.IsNil) 64 65 spec = getSpec() 66 c.Assert(spec.CAConfig.ExternalCAs, checker.HasLen, 2) 67 c.Assert(spec.CAConfig.ExternalCAs[0].CACert, checker.Equals, "") 68 c.Assert(spec.CAConfig.ExternalCAs[1].CACert, checker.Equals, string(expected)) 69 70 // passing an invalid external CA fails 71 tempFile := fs.NewFile(c, "testfile", fs.WithContent("fakecert")) 72 defer tempFile.Remove() 73 74 result := cli.Docker(cli.Args("swarm", "update", 75 "--external-ca", fmt.Sprintf("protocol=cfssl,url=https://something.org,cacert=%s", tempFile.Path())), 76 cli.Daemon(d)) 77 result.Assert(c, icmd.Expected{ 78 ExitCode: 125, 79 Err: "must be in PEM format", 80 }) 81 } 82 83 func (s *DockerSwarmSuite) TestSwarmInit(c *check.C) { 84 d := s.AddDaemon(c, false, false) 85 86 getSpec := func() swarm.Spec { 87 sw := d.GetSwarm(c) 88 return sw.Spec 89 } 90 91 // passing an invalid external CA fails 92 tempFile := fs.NewFile(c, "testfile", fs.WithContent("fakecert")) 93 defer tempFile.Remove() 94 95 result := cli.Docker(cli.Args("swarm", "init", "--cert-expiry", "30h", "--dispatcher-heartbeat", "11s", 96 "--external-ca", fmt.Sprintf("protocol=cfssl,url=https://somethingelse.org,cacert=%s", tempFile.Path())), 97 cli.Daemon(d)) 98 result.Assert(c, icmd.Expected{ 99 ExitCode: 125, 100 Err: "must be in PEM format", 101 }) 102 103 cli.Docker(cli.Args("swarm", "init", "--cert-expiry", "30h", "--dispatcher-heartbeat", "11s", 104 "--external-ca", "protocol=cfssl,url=https://something.org", 105 "--external-ca", "protocol=cfssl,url=https://somethingelse.org,cacert=fixtures/https/ca.pem"), 106 cli.Daemon(d)).Assert(c, icmd.Success) 107 108 expected, err := ioutil.ReadFile("fixtures/https/ca.pem") 109 c.Assert(err, checker.IsNil) 110 111 spec := getSpec() 112 c.Assert(spec.CAConfig.NodeCertExpiry, checker.Equals, 30*time.Hour) 113 c.Assert(spec.Dispatcher.HeartbeatPeriod, checker.Equals, 11*time.Second) 114 c.Assert(spec.CAConfig.ExternalCAs, checker.HasLen, 2) 115 c.Assert(spec.CAConfig.ExternalCAs[0].CACert, checker.Equals, "") 116 c.Assert(spec.CAConfig.ExternalCAs[1].CACert, checker.Equals, string(expected)) 117 118 c.Assert(d.SwarmLeave(true), checker.IsNil) 119 cli.Docker(cli.Args("swarm", "init"), cli.Daemon(d)).Assert(c, icmd.Success) 120 121 spec = getSpec() 122 c.Assert(spec.CAConfig.NodeCertExpiry, checker.Equals, 90*24*time.Hour) 123 c.Assert(spec.Dispatcher.HeartbeatPeriod, checker.Equals, 5*time.Second) 124 } 125 126 func (s *DockerSwarmSuite) TestSwarmInitIPv6(c *check.C) { 127 testRequires(c, IPv6) 128 d1 := s.AddDaemon(c, false, false) 129 cli.Docker(cli.Args("swarm", "init", "--listen-add", "::1"), cli.Daemon(d1)).Assert(c, icmd.Success) 130 131 d2 := s.AddDaemon(c, false, false) 132 cli.Docker(cli.Args("swarm", "join", "::1"), cli.Daemon(d2)).Assert(c, icmd.Success) 133 134 out := cli.Docker(cli.Args("info"), cli.Daemon(d2)).Assert(c, icmd.Success).Combined() 135 c.Assert(out, checker.Contains, "Swarm: active") 136 } 137 138 func (s *DockerSwarmSuite) TestSwarmInitUnspecifiedAdvertiseAddr(c *check.C) { 139 d := s.AddDaemon(c, false, false) 140 out, err := d.Cmd("swarm", "init", "--advertise-addr", "0.0.0.0") 141 c.Assert(err, checker.NotNil) 142 c.Assert(out, checker.Contains, "advertise address must be a non-zero IP address") 143 } 144 145 func (s *DockerSwarmSuite) TestSwarmIncompatibleDaemon(c *check.C) { 146 // init swarm mode and stop a daemon 147 d := s.AddDaemon(c, true, true) 148 info := d.SwarmInfo(c) 149 c.Assert(info.LocalNodeState, checker.Equals, swarm.LocalNodeStateActive) 150 d.Stop(c) 151 152 // start a daemon with --cluster-store and --cluster-advertise 153 err := d.StartWithError("--cluster-store=consul://consuladdr:consulport/some/path", "--cluster-advertise=1.1.1.1:2375") 154 c.Assert(err, checker.NotNil) 155 content, err := d.ReadLogFile() 156 c.Assert(err, checker.IsNil) 157 c.Assert(string(content), checker.Contains, "--cluster-store and --cluster-advertise daemon configurations are incompatible with swarm mode") 158 159 // start a daemon with --live-restore 160 err = d.StartWithError("--live-restore") 161 c.Assert(err, checker.NotNil) 162 content, err = d.ReadLogFile() 163 c.Assert(err, checker.IsNil) 164 c.Assert(string(content), checker.Contains, "--live-restore daemon configuration is incompatible with swarm mode") 165 // restart for teardown 166 d.Start(c) 167 } 168 169 func (s *DockerSwarmSuite) TestSwarmServiceTemplatingHostname(c *check.C) { 170 d := s.AddDaemon(c, true, true) 171 hostname, err := d.Cmd("node", "inspect", "--format", "{{.Description.Hostname}}", "self") 172 c.Assert(err, checker.IsNil, check.Commentf(hostname)) 173 174 out, err := d.Cmd("service", "create", "--detach", "--no-resolve-image", "--name", "test", "--hostname", "{{.Service.Name}}-{{.Task.Slot}}-{{.Node.Hostname}}", "busybox", "top") 175 c.Assert(err, checker.IsNil, check.Commentf(out)) 176 177 // make sure task has been deployed. 178 waitAndAssert(c, defaultReconciliationTimeout, d.CheckActiveContainerCount, checker.Equals, 1) 179 180 containers := d.ActiveContainers() 181 out, err = d.Cmd("inspect", "--type", "container", "--format", "{{.Config.Hostname}}", containers[0]) 182 c.Assert(err, checker.IsNil, check.Commentf(out)) 183 c.Assert(strings.Split(out, "\n")[0], checker.Equals, "test-1-"+strings.Split(hostname, "\n")[0], check.Commentf("hostname with templating invalid")) 184 } 185 186 // Test case for #24270 187 func (s *DockerSwarmSuite) TestSwarmServiceListFilter(c *check.C) { 188 d := s.AddDaemon(c, true, true) 189 190 name1 := "redis-cluster-md5" 191 name2 := "redis-cluster" 192 name3 := "other-cluster" 193 out, err := d.Cmd("service", "create", "--detach", "--no-resolve-image", "--name", name1, "busybox", "top") 194 c.Assert(err, checker.IsNil) 195 c.Assert(strings.TrimSpace(out), checker.Not(checker.Equals), "") 196 197 out, err = d.Cmd("service", "create", "--detach", "--no-resolve-image", "--name", name2, "busybox", "top") 198 c.Assert(err, checker.IsNil) 199 c.Assert(strings.TrimSpace(out), checker.Not(checker.Equals), "") 200 201 out, err = d.Cmd("service", "create", "--detach", "--no-resolve-image", "--name", name3, "busybox", "top") 202 c.Assert(err, checker.IsNil) 203 c.Assert(strings.TrimSpace(out), checker.Not(checker.Equals), "") 204 205 filter1 := "name=redis-cluster-md5" 206 filter2 := "name=redis-cluster" 207 208 // We search checker.Contains with `name+" "` to prevent prefix only. 209 out, err = d.Cmd("service", "ls", "--filter", filter1) 210 c.Assert(err, checker.IsNil) 211 c.Assert(out, checker.Contains, name1+" ") 212 c.Assert(out, checker.Not(checker.Contains), name2+" ") 213 c.Assert(out, checker.Not(checker.Contains), name3+" ") 214 215 out, err = d.Cmd("service", "ls", "--filter", filter2) 216 c.Assert(err, checker.IsNil) 217 c.Assert(out, checker.Contains, name1+" ") 218 c.Assert(out, checker.Contains, name2+" ") 219 c.Assert(out, checker.Not(checker.Contains), name3+" ") 220 221 out, err = d.Cmd("service", "ls") 222 c.Assert(err, checker.IsNil) 223 c.Assert(out, checker.Contains, name1+" ") 224 c.Assert(out, checker.Contains, name2+" ") 225 c.Assert(out, checker.Contains, name3+" ") 226 } 227 228 func (s *DockerSwarmSuite) TestSwarmNodeListFilter(c *check.C) { 229 d := s.AddDaemon(c, true, true) 230 231 out, err := d.Cmd("node", "inspect", "--format", "{{ .Description.Hostname }}", "self") 232 c.Assert(err, checker.IsNil) 233 c.Assert(strings.TrimSpace(out), checker.Not(checker.Equals), "") 234 name := strings.TrimSpace(out) 235 236 filter := "name=" + name[:4] 237 238 out, err = d.Cmd("node", "ls", "--filter", filter) 239 c.Assert(err, checker.IsNil) 240 c.Assert(out, checker.Contains, name) 241 242 out, err = d.Cmd("node", "ls", "--filter", "name=none") 243 c.Assert(err, checker.IsNil) 244 c.Assert(out, checker.Not(checker.Contains), name) 245 } 246 247 func (s *DockerSwarmSuite) TestSwarmNodeTaskListFilter(c *check.C) { 248 d := s.AddDaemon(c, true, true) 249 250 name := "redis-cluster-md5" 251 out, err := d.Cmd("service", "create", "--detach", "--no-resolve-image", "--name", name, "--replicas=3", "busybox", "top") 252 c.Assert(err, checker.IsNil) 253 c.Assert(strings.TrimSpace(out), checker.Not(checker.Equals), "") 254 255 // make sure task has been deployed. 256 waitAndAssert(c, defaultReconciliationTimeout, d.CheckActiveContainerCount, checker.Equals, 3) 257 258 filter := "name=redis-cluster" 259 260 out, err = d.Cmd("node", "ps", "--filter", filter, "self") 261 c.Assert(err, checker.IsNil) 262 c.Assert(out, checker.Contains, name+".1") 263 c.Assert(out, checker.Contains, name+".2") 264 c.Assert(out, checker.Contains, name+".3") 265 266 out, err = d.Cmd("node", "ps", "--filter", "name=none", "self") 267 c.Assert(err, checker.IsNil) 268 c.Assert(out, checker.Not(checker.Contains), name+".1") 269 c.Assert(out, checker.Not(checker.Contains), name+".2") 270 c.Assert(out, checker.Not(checker.Contains), name+".3") 271 } 272 273 // Test case for #25375 274 func (s *DockerSwarmSuite) TestSwarmPublishAdd(c *check.C) { 275 d := s.AddDaemon(c, true, true) 276 277 name := "top" 278 out, err := d.Cmd("service", "create", "--detach", "--no-resolve-image", "--name", name, "--label", "x=y", "busybox", "top") 279 c.Assert(err, checker.IsNil) 280 c.Assert(strings.TrimSpace(out), checker.Not(checker.Equals), "") 281 282 out, err = d.Cmd("service", "update", "--detach", "--publish-add", "80:80", name) 283 c.Assert(err, checker.IsNil) 284 285 out, err = d.Cmd("service", "update", "--detach", "--publish-add", "80:80", name) 286 c.Assert(err, checker.IsNil) 287 288 out, err = d.Cmd("service", "update", "--detach", "--publish-add", "80:80", "--publish-add", "80:20", name) 289 c.Assert(err, checker.NotNil) 290 291 out, err = d.Cmd("service", "inspect", "--format", "{{ .Spec.EndpointSpec.Ports }}", name) 292 c.Assert(err, checker.IsNil) 293 c.Assert(strings.TrimSpace(out), checker.Equals, "[{ tcp 80 80 ingress}]") 294 } 295 296 func (s *DockerSwarmSuite) TestSwarmServiceWithGroup(c *check.C) { 297 d := s.AddDaemon(c, true, true) 298 299 name := "top" 300 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") 301 c.Assert(err, checker.IsNil) 302 c.Assert(strings.TrimSpace(out), checker.Not(checker.Equals), "") 303 304 // make sure task has been deployed. 305 waitAndAssert(c, defaultReconciliationTimeout, d.CheckActiveContainerCount, checker.Equals, 1) 306 307 out, err = d.Cmd("ps", "-q") 308 c.Assert(err, checker.IsNil) 309 c.Assert(strings.TrimSpace(out), checker.Not(checker.Equals), "") 310 311 container := strings.TrimSpace(out) 312 313 out, err = d.Cmd("exec", container, "id") 314 c.Assert(err, checker.IsNil) 315 c.Assert(strings.TrimSpace(out), checker.Equals, "uid=0(root) gid=0(root) groups=10(wheel),29(audio),50(staff),777") 316 } 317 318 func (s *DockerSwarmSuite) TestSwarmContainerAutoStart(c *check.C) { 319 d := s.AddDaemon(c, true, true) 320 321 out, err := d.Cmd("network", "create", "--attachable", "-d", "overlay", "foo") 322 c.Assert(err, checker.IsNil) 323 c.Assert(strings.TrimSpace(out), checker.Not(checker.Equals), "") 324 325 out, err = d.Cmd("run", "-id", "--restart=always", "--net=foo", "--name=test", "busybox", "top") 326 c.Assert(err, checker.IsNil, check.Commentf(out)) 327 c.Assert(strings.TrimSpace(out), checker.Not(checker.Equals), "") 328 329 out, err = d.Cmd("ps", "-q") 330 c.Assert(err, checker.IsNil, check.Commentf(out)) 331 c.Assert(strings.TrimSpace(out), checker.Not(checker.Equals), "") 332 333 d.Restart(c) 334 335 out, err = d.Cmd("ps", "-q") 336 c.Assert(err, checker.IsNil, check.Commentf(out)) 337 c.Assert(strings.TrimSpace(out), checker.Not(checker.Equals), "") 338 } 339 340 func (s *DockerSwarmSuite) TestSwarmContainerEndpointOptions(c *check.C) { 341 d := s.AddDaemon(c, true, true) 342 343 out, err := d.Cmd("network", "create", "--attachable", "-d", "overlay", "foo") 344 c.Assert(err, checker.IsNil, check.Commentf(out)) 345 c.Assert(strings.TrimSpace(out), checker.Not(checker.Equals), "") 346 347 _, err = d.Cmd("run", "-d", "--net=foo", "--name=first", "--net-alias=first-alias", "busybox:glibc", "top") 348 c.Assert(err, checker.IsNil, check.Commentf(out)) 349 350 _, err = d.Cmd("run", "-d", "--net=foo", "--name=second", "busybox:glibc", "top") 351 c.Assert(err, checker.IsNil, check.Commentf(out)) 352 353 _, err = d.Cmd("run", "-d", "--net=foo", "--net-alias=third-alias", "busybox:glibc", "top") 354 c.Assert(err, checker.IsNil, check.Commentf(out)) 355 356 // ping first container and its alias, also ping third and anonymous container by its alias 357 _, err = d.Cmd("exec", "second", "ping", "-c", "1", "first") 358 c.Assert(err, check.IsNil, check.Commentf(out)) 359 _, err = d.Cmd("exec", "second", "ping", "-c", "1", "first-alias") 360 c.Assert(err, check.IsNil, check.Commentf(out)) 361 _, err = d.Cmd("exec", "second", "ping", "-c", "1", "third-alias") 362 c.Assert(err, check.IsNil, check.Commentf(out)) 363 } 364 365 func (s *DockerSwarmSuite) TestSwarmContainerAttachByNetworkId(c *check.C) { 366 d := s.AddDaemon(c, true, true) 367 368 out, err := d.Cmd("network", "create", "--attachable", "-d", "overlay", "testnet") 369 c.Assert(err, checker.IsNil) 370 c.Assert(strings.TrimSpace(out), checker.Not(checker.Equals), "") 371 networkID := strings.TrimSpace(out) 372 373 out, err = d.Cmd("run", "-d", "--net", networkID, "busybox", "top") 374 c.Assert(err, checker.IsNil) 375 cID := strings.TrimSpace(out) 376 d.WaitRun(cID) 377 378 _, err = d.Cmd("rm", "-f", cID) 379 c.Assert(err, checker.IsNil) 380 381 _, err = d.Cmd("network", "rm", "testnet") 382 c.Assert(err, checker.IsNil) 383 384 checkNetwork := func(*check.C) (interface{}, check.CommentInterface) { 385 out, err := d.Cmd("network", "ls") 386 c.Assert(err, checker.IsNil) 387 return out, nil 388 } 389 390 waitAndAssert(c, 3*time.Second, checkNetwork, checker.Not(checker.Contains), "testnet") 391 } 392 393 func (s *DockerSwarmSuite) TestOverlayAttachable(c *check.C) { 394 d := s.AddDaemon(c, true, true) 395 396 out, err := d.Cmd("network", "create", "-d", "overlay", "--attachable", "ovnet") 397 c.Assert(err, checker.IsNil, check.Commentf(out)) 398 399 // validate attachable 400 out, err = d.Cmd("network", "inspect", "--format", "{{json .Attachable}}", "ovnet") 401 c.Assert(err, checker.IsNil, check.Commentf(out)) 402 c.Assert(strings.TrimSpace(out), checker.Equals, "true") 403 404 // validate containers can attache to this overlay network 405 out, err = d.Cmd("run", "-d", "--network", "ovnet", "--name", "c1", "busybox", "top") 406 c.Assert(err, checker.IsNil, check.Commentf(out)) 407 408 // redo validation, there was a bug that the value of attachable changes after 409 // containers attach to the network 410 out, err = d.Cmd("network", "inspect", "--format", "{{json .Attachable}}", "ovnet") 411 c.Assert(err, checker.IsNil, check.Commentf(out)) 412 c.Assert(strings.TrimSpace(out), checker.Equals, "true") 413 } 414 415 func (s *DockerSwarmSuite) TestOverlayAttachableOnSwarmLeave(c *check.C) { 416 d := s.AddDaemon(c, true, true) 417 418 // Create an attachable swarm network 419 nwName := "attovl" 420 out, err := d.Cmd("network", "create", "-d", "overlay", "--attachable", nwName) 421 c.Assert(err, checker.IsNil, check.Commentf(out)) 422 423 // Connect a container to the network 424 out, err = d.Cmd("run", "-d", "--network", nwName, "--name", "c1", "busybox", "top") 425 c.Assert(err, checker.IsNil, check.Commentf(out)) 426 427 // Leave the swarm 428 err = d.SwarmLeave(true) 429 c.Assert(err, 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) 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) 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(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(out)) 452 453 // Attempt to attach another container with same IP, must fail 454 _, err = d.Cmd("run", "-d", "--network", "ovnet", "--name", "c2", "--ip", "10.10.9.33", "busybox", "top") 455 c.Assert(err, checker.NotNil) 456 457 // Remove first container 458 out, err = d.Cmd("rm", "-f", "c1") 459 c.Assert(err, checker.IsNil, check.Commentf(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(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(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(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(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(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(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(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) 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) 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) 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) 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) 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) 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) 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) 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) 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) 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) 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) 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) 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.Commentf("Failed to start an HTTP Server")) 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) 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) 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) 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) 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) 853 id := strings.TrimSpace(out) 854 855 out, err = d.Cmd("exec", id, "cat", "/status") 856 c.Assert(err, checker.IsNil) 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) 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) 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) 876 id = strings.TrimSpace(out) 877 878 out, err = d.Cmd("exec", id, "cat", "/status") 879 c.Assert(err, checker.IsNil) 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 _, err := d.Cmd("service", "create", "--detach", "--no-resolve-image", "--name", name, "busybox", "top") 889 c.Assert(err, checker.IsNil) 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) 896 c.Assert(strings.TrimSpace(out), checker.Equals, "false") 897 898 _, err = d.Cmd("service", "update", "--detach", "--tty", name) 899 c.Assert(err, checker.IsNil) 900 901 out, err = d.Cmd("service", "inspect", "--format", "{{ .Spec.TaskTemplate.ContainerSpec.TTY }}", name) 902 c.Assert(err, checker.IsNil) 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 _, 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) 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) 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) 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 _, err := d.Cmd("service", "create", "--detach", "--no-resolve-image", "--name", name, "busybox", "top") 978 c.Assert(err, checker.IsNil) 979 980 // Make sure task has been deployed. 981 waitAndAssert(c, defaultReconciliationTimeout, d.CheckActiveContainerCount, checker.Equals, 1) 982 983 _, 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) 985 986 out, err := d.Cmd("service", "inspect", "--format", "{{ .Spec.TaskTemplate.ContainerSpec.DNSConfig }}", name) 987 c.Assert(err, checker.IsNil) 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, unlockKey string) { 1013 // Wait for the PEM file to become unencrypted 1014 waitAndAssert(c, defaultReconciliationTimeout, checkKeyIsEncrypted(d), checker.Equals, false) 1015 1016 d.Restart(c) 1017 c.Assert(getNodeStatus(c, d), 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.Restart(c) 1025 c.Assert(getNodeStatus(c, d), 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 _, err := d.Cmd("swarm", "init") 1041 c.Assert(err, checker.IsNil) 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("out: %v", outs)) 1058 1059 c.Assert(outs, checker.Contains, "docker swarm unlock") 1060 1061 var unlockKey string 1062 for _, line := range strings.Split(outs, "\n") { 1063 if strings.Contains(line, "SWMKEY") { 1064 unlockKey = strings.TrimSpace(line) 1065 break 1066 } 1067 } 1068 1069 c.Assert(unlockKey, checker.Not(checker.Equals), "") 1070 1071 outs, err = d.Cmd("swarm", "unlock-key", "-q") 1072 c.Assert(outs, checker.Equals, unlockKey+"\n") 1073 1074 c.Assert(getNodeStatus(c, d), checker.Equals, swarm.LocalNodeStateActive) 1075 1076 // It starts off locked 1077 d.Restart(c) 1078 c.Assert(getNodeStatus(c, d), checker.Equals, swarm.LocalNodeStateLocked) 1079 1080 cmd := d.Command("swarm", "unlock") 1081 cmd.Stdin = bytes.NewBufferString("wrong-secret-key") 1082 icmd.RunCmd(cmd).Assert(c, icmd.Expected{ 1083 ExitCode: 1, 1084 Err: "invalid key", 1085 }) 1086 1087 c.Assert(getNodeStatus(c, d), checker.Equals, swarm.LocalNodeStateLocked) 1088 1089 cmd = d.Command("swarm", "unlock") 1090 cmd.Stdin = bytes.NewBufferString(unlockKey) 1091 icmd.RunCmd(cmd).Assert(c, icmd.Success) 1092 1093 c.Assert(getNodeStatus(c, d), checker.Equals, swarm.LocalNodeStateActive) 1094 1095 outs, err = d.Cmd("node", "ls") 1096 c.Assert(err, checker.IsNil) 1097 c.Assert(outs, checker.Not(checker.Contains), "Swarm is encrypted and needs to be unlocked") 1098 1099 outs, err = d.Cmd("swarm", "update", "--autolock=false") 1100 c.Assert(err, checker.IsNil, check.Commentf("out: %v", outs)) 1101 1102 checkSwarmLockedToUnlocked(c, d, unlockKey) 1103 1104 outs, err = d.Cmd("node", "ls") 1105 c.Assert(err, checker.IsNil) 1106 c.Assert(outs, checker.Not(checker.Contains), "Swarm is encrypted and needs to be unlocked") 1107 } 1108 1109 func (s *DockerSwarmSuite) TestSwarmLeaveLocked(c *check.C) { 1110 d := s.AddDaemon(c, false, false) 1111 1112 outs, err := d.Cmd("swarm", "init", "--autolock") 1113 c.Assert(err, checker.IsNil, check.Commentf("out: %v", outs)) 1114 1115 // It starts off locked 1116 d.Restart(c, "--swarm-default-advertise-addr=lo") 1117 1118 info := d.SwarmInfo(c) 1119 c.Assert(info.LocalNodeState, checker.Equals, swarm.LocalNodeStateLocked) 1120 1121 outs, _ = d.Cmd("node", "ls") 1122 c.Assert(outs, checker.Contains, "Swarm is encrypted and needs to be unlocked") 1123 1124 // `docker swarm leave` a locked swarm without --force will return an error 1125 outs, _ = d.Cmd("swarm", "leave") 1126 c.Assert(outs, checker.Contains, "Swarm is encrypted and locked.") 1127 1128 // It is OK for user to leave a locked swarm with --force 1129 outs, err = d.Cmd("swarm", "leave", "--force") 1130 c.Assert(err, checker.IsNil, check.Commentf("out: %v", outs)) 1131 1132 info = d.SwarmInfo(c) 1133 c.Assert(info.LocalNodeState, checker.Equals, swarm.LocalNodeStateInactive) 1134 1135 outs, err = d.Cmd("swarm", "init") 1136 c.Assert(err, checker.IsNil, check.Commentf("out: %v", outs)) 1137 1138 info = d.SwarmInfo(c) 1139 c.Assert(info.LocalNodeState, checker.Equals, swarm.LocalNodeStateActive) 1140 } 1141 1142 func (s *DockerSwarmSuite) TestSwarmLockUnlockCluster(c *check.C) { 1143 d1 := s.AddDaemon(c, true, true) 1144 d2 := s.AddDaemon(c, true, true) 1145 d3 := s.AddDaemon(c, true, true) 1146 1147 // they start off unlocked 1148 d2.Restart(c) 1149 c.Assert(getNodeStatus(c, d2), checker.Equals, swarm.LocalNodeStateActive) 1150 1151 // stop this one so it does not get autolock info 1152 d2.Stop(c) 1153 1154 // enable autolock 1155 outs, err := d1.Cmd("swarm", "update", "--autolock") 1156 c.Assert(err, checker.IsNil, check.Commentf("out: %v", outs)) 1157 1158 c.Assert(outs, checker.Contains, "docker swarm unlock") 1159 1160 var unlockKey string 1161 for _, line := range strings.Split(outs, "\n") { 1162 if strings.Contains(line, "SWMKEY") { 1163 unlockKey = strings.TrimSpace(line) 1164 break 1165 } 1166 } 1167 1168 c.Assert(unlockKey, checker.Not(checker.Equals), "") 1169 1170 outs, err = d1.Cmd("swarm", "unlock-key", "-q") 1171 c.Assert(outs, checker.Equals, unlockKey+"\n") 1172 1173 // The ones that got the cluster update should be set to locked 1174 for _, d := range []*daemon.Daemon{d1, d3} { 1175 checkSwarmUnlockedToLocked(c, d) 1176 1177 cmd := d.Command("swarm", "unlock") 1178 cmd.Stdin = bytes.NewBufferString(unlockKey) 1179 icmd.RunCmd(cmd).Assert(c, icmd.Success) 1180 c.Assert(getNodeStatus(c, d), checker.Equals, swarm.LocalNodeStateActive) 1181 } 1182 1183 // d2 never got the cluster update, so it is still set to unlocked 1184 d2.Start(c) 1185 c.Assert(getNodeStatus(c, d2), checker.Equals, swarm.LocalNodeStateActive) 1186 1187 // d2 is now set to lock 1188 checkSwarmUnlockedToLocked(c, d2) 1189 1190 // leave it locked, and set the cluster to no longer autolock 1191 outs, err = d1.Cmd("swarm", "update", "--autolock=false") 1192 c.Assert(err, checker.IsNil, check.Commentf("out: %v", outs)) 1193 1194 // the ones that got the update are now set to unlocked 1195 for _, d := range []*daemon.Daemon{d1, d3} { 1196 checkSwarmLockedToUnlocked(c, d, unlockKey) 1197 } 1198 1199 // d2 still locked 1200 c.Assert(getNodeStatus(c, d2), checker.Equals, swarm.LocalNodeStateLocked) 1201 1202 // unlock it 1203 cmd := d2.Command("swarm", "unlock") 1204 cmd.Stdin = bytes.NewBufferString(unlockKey) 1205 icmd.RunCmd(cmd).Assert(c, icmd.Success) 1206 c.Assert(getNodeStatus(c, d2), checker.Equals, swarm.LocalNodeStateActive) 1207 1208 // once it's caught up, d2 is set to not be locked 1209 checkSwarmLockedToUnlocked(c, d2, unlockKey) 1210 1211 // managers who join now are never set to locked in the first place 1212 d4 := s.AddDaemon(c, true, true) 1213 d4.Restart(c) 1214 c.Assert(getNodeStatus(c, d4), checker.Equals, swarm.LocalNodeStateActive) 1215 } 1216 1217 func (s *DockerSwarmSuite) TestSwarmJoinPromoteLocked(c *check.C) { 1218 d1 := s.AddDaemon(c, true, true) 1219 1220 // enable autolock 1221 outs, err := d1.Cmd("swarm", "update", "--autolock") 1222 c.Assert(err, checker.IsNil, check.Commentf("out: %v", outs)) 1223 1224 c.Assert(outs, checker.Contains, "docker swarm unlock") 1225 1226 var unlockKey string 1227 for _, line := range strings.Split(outs, "\n") { 1228 if strings.Contains(line, "SWMKEY") { 1229 unlockKey = strings.TrimSpace(line) 1230 break 1231 } 1232 } 1233 1234 c.Assert(unlockKey, checker.Not(checker.Equals), "") 1235 1236 outs, err = d1.Cmd("swarm", "unlock-key", "-q") 1237 c.Assert(outs, checker.Equals, unlockKey+"\n") 1238 1239 // joined workers start off unlocked 1240 d2 := s.AddDaemon(c, true, false) 1241 d2.Restart(c) 1242 c.Assert(getNodeStatus(c, d2), checker.Equals, swarm.LocalNodeStateActive) 1243 1244 // promote worker 1245 outs, err = d1.Cmd("node", "promote", d2.NodeID()) 1246 c.Assert(err, checker.IsNil) 1247 c.Assert(outs, checker.Contains, "promoted to a manager in the swarm") 1248 1249 // join new manager node 1250 d3 := s.AddDaemon(c, true, true) 1251 1252 // both new nodes are locked 1253 for _, d := range []*daemon.Daemon{d2, d3} { 1254 checkSwarmUnlockedToLocked(c, d) 1255 1256 cmd := d.Command("swarm", "unlock") 1257 cmd.Stdin = bytes.NewBufferString(unlockKey) 1258 icmd.RunCmd(cmd).Assert(c, icmd.Success) 1259 c.Assert(getNodeStatus(c, d), checker.Equals, swarm.LocalNodeStateActive) 1260 } 1261 1262 // demote manager back to worker - workers are not locked 1263 outs, err = d1.Cmd("node", "demote", d3.NodeID()) 1264 c.Assert(err, checker.IsNil) 1265 c.Assert(outs, checker.Contains, "demoted in the swarm") 1266 1267 // Wait for it to actually be demoted, for the key and cert to be replaced. 1268 // Then restart and assert that the node is not locked. If we don't wait for the cert 1269 // to be replaced, then the node still has the manager TLS key which is still locked 1270 // (because we never want a manager TLS key to be on disk unencrypted if the cluster 1271 // is set to autolock) 1272 waitAndAssert(c, defaultReconciliationTimeout, d3.CheckControlAvailable, checker.False) 1273 waitAndAssert(c, defaultReconciliationTimeout, func(c *check.C) (interface{}, check.CommentInterface) { 1274 certBytes, err := ioutil.ReadFile(filepath.Join(d3.Folder, "root", "swarm", "certificates", "swarm-node.crt")) 1275 if err != nil { 1276 return "", check.Commentf("error: %v", err) 1277 } 1278 certs, err := helpers.ParseCertificatesPEM(certBytes) 1279 if err == nil && len(certs) > 0 && len(certs[0].Subject.OrganizationalUnit) > 0 { 1280 return certs[0].Subject.OrganizationalUnit[0], nil 1281 } 1282 return "", check.Commentf("could not get organizational unit from certificate") 1283 }, checker.Equals, "swarm-worker") 1284 1285 // by now, it should *never* be locked on restart 1286 d3.Restart(c) 1287 c.Assert(getNodeStatus(c, d3), checker.Equals, swarm.LocalNodeStateActive) 1288 } 1289 1290 func (s *DockerSwarmSuite) TestSwarmRotateUnlockKey(c *check.C) { 1291 d := s.AddDaemon(c, true, true) 1292 1293 outs, err := d.Cmd("swarm", "update", "--autolock") 1294 c.Assert(err, checker.IsNil, check.Commentf("out: %v", outs)) 1295 1296 c.Assert(outs, checker.Contains, "docker swarm unlock") 1297 1298 var unlockKey string 1299 for _, line := range strings.Split(outs, "\n") { 1300 if strings.Contains(line, "SWMKEY") { 1301 unlockKey = strings.TrimSpace(line) 1302 break 1303 } 1304 } 1305 1306 c.Assert(unlockKey, checker.Not(checker.Equals), "") 1307 1308 outs, err = d.Cmd("swarm", "unlock-key", "-q") 1309 c.Assert(outs, checker.Equals, unlockKey+"\n") 1310 1311 // Rotate multiple times 1312 for i := 0; i != 3; i++ { 1313 outs, err = d.Cmd("swarm", "unlock-key", "-q", "--rotate") 1314 c.Assert(err, checker.IsNil, check.Commentf("out: %v", outs)) 1315 // Strip \n 1316 newUnlockKey := outs[:len(outs)-1] 1317 c.Assert(newUnlockKey, checker.Not(checker.Equals), "") 1318 c.Assert(newUnlockKey, checker.Not(checker.Equals), unlockKey) 1319 1320 d.Restart(c) 1321 c.Assert(getNodeStatus(c, d), checker.Equals, swarm.LocalNodeStateLocked) 1322 1323 outs, _ = d.Cmd("node", "ls") 1324 c.Assert(outs, checker.Contains, "Swarm is encrypted and needs to be unlocked") 1325 1326 cmd := d.Command("swarm", "unlock") 1327 cmd.Stdin = bytes.NewBufferString(unlockKey) 1328 result := icmd.RunCmd(cmd) 1329 1330 if result.Error == nil { 1331 // On occasion, the daemon may not have finished 1332 // rotating the KEK before restarting. The test is 1333 // intentionally written to explore this behavior. 1334 // When this happens, unlocking with the old key will 1335 // succeed. If we wait for the rotation to happen and 1336 // restart again, the new key should be required this 1337 // time. 1338 1339 time.Sleep(3 * time.Second) 1340 1341 d.Restart(c) 1342 1343 cmd = d.Command("swarm", "unlock") 1344 cmd.Stdin = bytes.NewBufferString(unlockKey) 1345 result = icmd.RunCmd(cmd) 1346 } 1347 result.Assert(c, icmd.Expected{ 1348 ExitCode: 1, 1349 Err: "invalid key", 1350 }) 1351 1352 outs, _ = d.Cmd("node", "ls") 1353 c.Assert(outs, checker.Contains, "Swarm is encrypted and needs to be unlocked") 1354 1355 cmd = d.Command("swarm", "unlock") 1356 cmd.Stdin = bytes.NewBufferString(newUnlockKey) 1357 icmd.RunCmd(cmd).Assert(c, icmd.Success) 1358 1359 c.Assert(getNodeStatus(c, d), checker.Equals, swarm.LocalNodeStateActive) 1360 1361 outs, err = d.Cmd("node", "ls") 1362 c.Assert(err, checker.IsNil) 1363 c.Assert(outs, checker.Not(checker.Contains), "Swarm is encrypted and needs to be unlocked") 1364 1365 unlockKey = newUnlockKey 1366 } 1367 } 1368 1369 // This differs from `TestSwarmRotateUnlockKey` because that one rotates a single node, which is the leader. 1370 // This one keeps the leader up, and asserts that other manager nodes in the cluster also have their unlock 1371 // key rotated. 1372 func (s *DockerSwarmSuite) TestSwarmClusterRotateUnlockKey(c *check.C) { 1373 d1 := s.AddDaemon(c, true, true) // leader - don't restart this one, we don't want leader election delays 1374 d2 := s.AddDaemon(c, true, true) 1375 d3 := s.AddDaemon(c, true, true) 1376 1377 outs, err := d1.Cmd("swarm", "update", "--autolock") 1378 c.Assert(err, checker.IsNil, check.Commentf("out: %v", outs)) 1379 1380 c.Assert(outs, checker.Contains, "docker swarm unlock") 1381 1382 var unlockKey string 1383 for _, line := range strings.Split(outs, "\n") { 1384 if strings.Contains(line, "SWMKEY") { 1385 unlockKey = strings.TrimSpace(line) 1386 break 1387 } 1388 } 1389 1390 c.Assert(unlockKey, checker.Not(checker.Equals), "") 1391 1392 outs, err = d1.Cmd("swarm", "unlock-key", "-q") 1393 c.Assert(outs, checker.Equals, unlockKey+"\n") 1394 1395 // Rotate multiple times 1396 for i := 0; i != 3; i++ { 1397 outs, err = d1.Cmd("swarm", "unlock-key", "-q", "--rotate") 1398 c.Assert(err, checker.IsNil, check.Commentf("out: %v", outs)) 1399 // Strip \n 1400 newUnlockKey := outs[:len(outs)-1] 1401 c.Assert(newUnlockKey, checker.Not(checker.Equals), "") 1402 c.Assert(newUnlockKey, checker.Not(checker.Equals), unlockKey) 1403 1404 d2.Restart(c) 1405 d3.Restart(c) 1406 1407 for _, d := range []*daemon.Daemon{d2, d3} { 1408 c.Assert(getNodeStatus(c, d), checker.Equals, swarm.LocalNodeStateLocked) 1409 1410 outs, _ := d.Cmd("node", "ls") 1411 c.Assert(outs, checker.Contains, "Swarm is encrypted and needs to be unlocked") 1412 1413 cmd := d.Command("swarm", "unlock") 1414 cmd.Stdin = bytes.NewBufferString(unlockKey) 1415 result := icmd.RunCmd(cmd) 1416 1417 if result.Error == nil { 1418 // On occasion, the daemon may not have finished 1419 // rotating the KEK before restarting. The test is 1420 // intentionally written to explore this behavior. 1421 // When this happens, unlocking with the old key will 1422 // succeed. If we wait for the rotation to happen and 1423 // restart again, the new key should be required this 1424 // time. 1425 1426 time.Sleep(3 * time.Second) 1427 1428 d.Restart(c) 1429 1430 cmd = d.Command("swarm", "unlock") 1431 cmd.Stdin = bytes.NewBufferString(unlockKey) 1432 result = icmd.RunCmd(cmd) 1433 } 1434 result.Assert(c, icmd.Expected{ 1435 ExitCode: 1, 1436 Err: "invalid key", 1437 }) 1438 1439 outs, _ = d.Cmd("node", "ls") 1440 c.Assert(outs, checker.Contains, "Swarm is encrypted and needs to be unlocked") 1441 1442 cmd = d.Command("swarm", "unlock") 1443 cmd.Stdin = bytes.NewBufferString(newUnlockKey) 1444 icmd.RunCmd(cmd).Assert(c, icmd.Success) 1445 1446 c.Assert(getNodeStatus(c, d), checker.Equals, swarm.LocalNodeStateActive) 1447 1448 outs, err = d.Cmd("node", "ls") 1449 c.Assert(err, checker.IsNil) 1450 c.Assert(outs, checker.Not(checker.Contains), "Swarm is encrypted and needs to be unlocked") 1451 } 1452 1453 unlockKey = newUnlockKey 1454 } 1455 } 1456 1457 func (s *DockerSwarmSuite) TestSwarmAlternateLockUnlock(c *check.C) { 1458 d := s.AddDaemon(c, true, true) 1459 1460 var unlockKey string 1461 for i := 0; i < 2; i++ { 1462 // set to lock 1463 outs, err := d.Cmd("swarm", "update", "--autolock") 1464 c.Assert(err, checker.IsNil, check.Commentf("out: %v", outs)) 1465 c.Assert(outs, checker.Contains, "docker swarm unlock") 1466 1467 for _, line := range strings.Split(outs, "\n") { 1468 if strings.Contains(line, "SWMKEY") { 1469 unlockKey = strings.TrimSpace(line) 1470 break 1471 } 1472 } 1473 1474 c.Assert(unlockKey, checker.Not(checker.Equals), "") 1475 checkSwarmUnlockedToLocked(c, d) 1476 1477 cmd := d.Command("swarm", "unlock") 1478 cmd.Stdin = bytes.NewBufferString(unlockKey) 1479 icmd.RunCmd(cmd).Assert(c, icmd.Success) 1480 1481 c.Assert(getNodeStatus(c, d), checker.Equals, swarm.LocalNodeStateActive) 1482 1483 outs, err = d.Cmd("swarm", "update", "--autolock=false") 1484 c.Assert(err, checker.IsNil, check.Commentf("out: %v", outs)) 1485 1486 checkSwarmLockedToUnlocked(c, d, unlockKey) 1487 } 1488 } 1489 1490 func (s *DockerSwarmSuite) TestExtraHosts(c *check.C) { 1491 d := s.AddDaemon(c, true, true) 1492 1493 // Create a service 1494 name := "top" 1495 _, err := d.Cmd("service", "create", "--detach", "--no-resolve-image", "--name", name, "--host=example.com:1.2.3.4", "busybox", "top") 1496 c.Assert(err, checker.IsNil) 1497 1498 // Make sure task has been deployed. 1499 waitAndAssert(c, defaultReconciliationTimeout, d.CheckActiveContainerCount, checker.Equals, 1) 1500 1501 // We need to get the container id. 1502 out, err := d.Cmd("ps", "-a", "-q", "--no-trunc") 1503 c.Assert(err, checker.IsNil) 1504 id := strings.TrimSpace(out) 1505 1506 // Compare against expected output. 1507 expectedOutput := "1.2.3.4\texample.com" 1508 out, err = d.Cmd("exec", id, "cat", "/etc/hosts") 1509 c.Assert(err, checker.IsNil) 1510 c.Assert(out, checker.Contains, expectedOutput, check.Commentf("Expected '%s', but got %q", expectedOutput, out)) 1511 } 1512 1513 func (s *DockerSwarmSuite) TestSwarmManagerAddress(c *check.C) { 1514 d1 := s.AddDaemon(c, true, true) 1515 d2 := s.AddDaemon(c, true, false) 1516 d3 := s.AddDaemon(c, true, false) 1517 1518 // Manager Addresses will always show Node 1's address 1519 expectedOutput := fmt.Sprintf("Manager Addresses:\n 127.0.0.1:%d\n", d1.SwarmPort) 1520 1521 out, err := d1.Cmd("info") 1522 c.Assert(err, checker.IsNil) 1523 c.Assert(out, checker.Contains, expectedOutput) 1524 1525 out, err = d2.Cmd("info") 1526 c.Assert(err, checker.IsNil) 1527 c.Assert(out, checker.Contains, expectedOutput) 1528 1529 out, err = d3.Cmd("info") 1530 c.Assert(err, checker.IsNil) 1531 c.Assert(out, checker.Contains, expectedOutput) 1532 } 1533 1534 func (s *DockerSwarmSuite) TestSwarmNetworkIPAMOptions(c *check.C) { 1535 d := s.AddDaemon(c, true, true) 1536 1537 out, err := d.Cmd("network", "create", "-d", "overlay", "--ipam-opt", "foo=bar", "foo") 1538 c.Assert(err, checker.IsNil, check.Commentf(out)) 1539 c.Assert(strings.TrimSpace(out), checker.Not(checker.Equals), "") 1540 1541 out, err = d.Cmd("network", "inspect", "--format", "{{.IPAM.Options}}", "foo") 1542 c.Assert(err, checker.IsNil, check.Commentf(out)) 1543 c.Assert(strings.TrimSpace(out), checker.Contains, "foo:bar") 1544 c.Assert(strings.TrimSpace(out), checker.Contains, "com.docker.network.ipam.serial:true") 1545 1546 out, err = d.Cmd("service", "create", "--detach", "--no-resolve-image", "--network=foo", "--name", "top", "busybox", "top") 1547 c.Assert(err, checker.IsNil, check.Commentf(out)) 1548 1549 // make sure task has been deployed. 1550 waitAndAssert(c, defaultReconciliationTimeout, d.CheckActiveContainerCount, checker.Equals, 1) 1551 1552 out, err = d.Cmd("network", "inspect", "--format", "{{.IPAM.Options}}", "foo") 1553 c.Assert(err, checker.IsNil, check.Commentf(out)) 1554 c.Assert(strings.TrimSpace(out), checker.Contains, "foo:bar") 1555 c.Assert(strings.TrimSpace(out), checker.Contains, "com.docker.network.ipam.serial:true") 1556 } 1557 1558 // Test case for issue #27866, which did not allow NW name that is the prefix of a swarm NW ID. 1559 // e.g. if the ingress ID starts with "n1", it was impossible to create a NW named "n1". 1560 func (s *DockerSwarmSuite) TestSwarmNetworkCreateIssue27866(c *check.C) { 1561 d := s.AddDaemon(c, true, true) 1562 out, err := d.Cmd("network", "inspect", "-f", "{{.Id}}", "ingress") 1563 c.Assert(err, checker.IsNil, check.Commentf("out: %v", out)) 1564 ingressID := strings.TrimSpace(out) 1565 c.Assert(ingressID, checker.Not(checker.Equals), "") 1566 1567 // create a network of which name is the prefix of the ID of an overlay network 1568 // (ingressID in this case) 1569 newNetName := ingressID[0:2] 1570 out, err = d.Cmd("network", "create", "--driver", "overlay", newNetName) 1571 // In #27866, it was failing because of "network with name %s already exists" 1572 c.Assert(err, checker.IsNil, check.Commentf("out: %v", out)) 1573 out, err = d.Cmd("network", "rm", newNetName) 1574 c.Assert(err, checker.IsNil, check.Commentf("out: %v", out)) 1575 } 1576 1577 // Test case for https://github.com/docker/docker/pull/27938#issuecomment-265768303 1578 // This test creates two networks with the same name sequentially, with various drivers. 1579 // Since the operations in this test are done sequentially, the 2nd call should fail with 1580 // "network with name FOO already exists". 1581 // Note that it is to ok have multiple networks with the same name if the operations are done 1582 // in parallel. (#18864) 1583 func (s *DockerSwarmSuite) TestSwarmNetworkCreateDup(c *check.C) { 1584 d := s.AddDaemon(c, true, true) 1585 drivers := []string{"bridge", "overlay"} 1586 for i, driver1 := range drivers { 1587 nwName := fmt.Sprintf("network-test-%d", i) 1588 for _, driver2 := range drivers { 1589 c.Logf("Creating a network named %q with %q, then %q", 1590 nwName, driver1, driver2) 1591 out, err := d.Cmd("network", "create", "--driver", driver1, nwName) 1592 c.Assert(err, checker.IsNil, check.Commentf("out: %v", out)) 1593 out, err = d.Cmd("network", "create", "--driver", driver2, nwName) 1594 c.Assert(out, checker.Contains, 1595 fmt.Sprintf("network with name %s already exists", nwName)) 1596 c.Assert(err, checker.NotNil) 1597 c.Logf("As expected, the attempt to network %q with %q failed: %s", 1598 nwName, driver2, out) 1599 out, err = d.Cmd("network", "rm", nwName) 1600 c.Assert(err, checker.IsNil, check.Commentf("out: %v", out)) 1601 } 1602 } 1603 } 1604 1605 func (s *DockerSwarmSuite) TestSwarmPublishDuplicatePorts(c *check.C) { 1606 d := s.AddDaemon(c, true, true) 1607 1608 out, err := d.Cmd("service", "create", "--no-resolve-image", "--detach=true", "--publish", "5005:80", "--publish", "5006:80", "--publish", "80", "--publish", "80", "busybox", "top") 1609 c.Assert(err, check.IsNil, check.Commentf(out)) 1610 id := strings.TrimSpace(out) 1611 1612 // make sure task has been deployed. 1613 waitAndAssert(c, defaultReconciliationTimeout, d.CheckActiveContainerCount, checker.Equals, 1) 1614 1615 // Total len = 4, with 2 dynamic ports and 2 non-dynamic ports 1616 // Dynamic ports are likely to be 30000 and 30001 but doesn't matter 1617 out, err = d.Cmd("service", "inspect", "--format", "{{.Endpoint.Ports}} len={{len .Endpoint.Ports}}", id) 1618 c.Assert(err, check.IsNil, check.Commentf(out)) 1619 c.Assert(out, checker.Contains, "len=4") 1620 c.Assert(out, checker.Contains, "{ tcp 80 5005 ingress}") 1621 c.Assert(out, checker.Contains, "{ tcp 80 5006 ingress}") 1622 } 1623 1624 func (s *DockerSwarmSuite) TestSwarmJoinWithDrain(c *check.C) { 1625 d := s.AddDaemon(c, true, true) 1626 1627 out, err := d.Cmd("node", "ls") 1628 c.Assert(err, checker.IsNil) 1629 c.Assert(out, checker.Not(checker.Contains), "Drain") 1630 1631 out, err = d.Cmd("swarm", "join-token", "-q", "manager") 1632 c.Assert(err, checker.IsNil) 1633 c.Assert(strings.TrimSpace(out), checker.Not(checker.Equals), "") 1634 1635 token := strings.TrimSpace(out) 1636 1637 d1 := s.AddDaemon(c, false, false) 1638 1639 out, err = d1.Cmd("swarm", "join", "--availability=drain", "--token", token, d.SwarmListenAddr()) 1640 c.Assert(err, checker.IsNil) 1641 c.Assert(strings.TrimSpace(out), checker.Not(checker.Equals), "") 1642 1643 out, err = d.Cmd("node", "ls") 1644 c.Assert(err, checker.IsNil) 1645 c.Assert(out, checker.Contains, "Drain") 1646 1647 out, err = d1.Cmd("node", "ls") 1648 c.Assert(err, checker.IsNil) 1649 c.Assert(out, checker.Contains, "Drain") 1650 } 1651 1652 func (s *DockerSwarmSuite) TestSwarmInitWithDrain(c *check.C) { 1653 d := s.AddDaemon(c, false, false) 1654 1655 out, err := d.Cmd("swarm", "init", "--availability", "drain") 1656 c.Assert(err, checker.IsNil, check.Commentf("out: %v", out)) 1657 1658 out, err = d.Cmd("node", "ls") 1659 c.Assert(err, checker.IsNil) 1660 c.Assert(out, checker.Contains, "Drain") 1661 } 1662 1663 func (s *DockerSwarmSuite) TestSwarmReadonlyRootfs(c *check.C) { 1664 testRequires(c, DaemonIsLinux, UserNamespaceROMount) 1665 1666 d := s.AddDaemon(c, true, true) 1667 1668 out, err := d.Cmd("service", "create", "--detach", "--no-resolve-image", "--name", "top", "--read-only", "busybox", "top") 1669 c.Assert(err, checker.IsNil, check.Commentf(out)) 1670 1671 // make sure task has been deployed. 1672 waitAndAssert(c, defaultReconciliationTimeout, d.CheckActiveContainerCount, checker.Equals, 1) 1673 1674 out, err = d.Cmd("service", "inspect", "--format", "{{ .Spec.TaskTemplate.ContainerSpec.ReadOnly }}", "top") 1675 c.Assert(err, checker.IsNil, check.Commentf(out)) 1676 c.Assert(strings.TrimSpace(out), checker.Equals, "true") 1677 1678 containers := d.ActiveContainers() 1679 out, err = d.Cmd("inspect", "--type", "container", "--format", "{{.HostConfig.ReadonlyRootfs}}", containers[0]) 1680 c.Assert(err, checker.IsNil, check.Commentf(out)) 1681 c.Assert(strings.TrimSpace(out), checker.Equals, "true") 1682 } 1683 1684 func (s *DockerSwarmSuite) TestNetworkInspectWithDuplicateNames(c *check.C) { 1685 d := s.AddDaemon(c, true, true) 1686 1687 name := "foo" 1688 options := types.NetworkCreate{ 1689 CheckDuplicate: false, 1690 Driver: "bridge", 1691 } 1692 1693 cli, err := d.NewClient() 1694 c.Assert(err, checker.IsNil) 1695 defer cli.Close() 1696 1697 n1, err := cli.NetworkCreate(context.Background(), name, options) 1698 c.Assert(err, checker.IsNil) 1699 1700 // Full ID always works 1701 out, err := d.Cmd("network", "inspect", "--format", "{{.ID}}", n1.ID) 1702 c.Assert(err, checker.IsNil, check.Commentf(out)) 1703 c.Assert(strings.TrimSpace(out), checker.Equals, n1.ID) 1704 1705 // Name works if it is unique 1706 out, err = d.Cmd("network", "inspect", "--format", "{{.ID}}", name) 1707 c.Assert(err, checker.IsNil, check.Commentf(out)) 1708 c.Assert(strings.TrimSpace(out), checker.Equals, n1.ID) 1709 1710 n2, err := cli.NetworkCreate(context.Background(), name, options) 1711 c.Assert(err, checker.IsNil) 1712 // Full ID always works 1713 out, err = d.Cmd("network", "inspect", "--format", "{{.ID}}", n1.ID) 1714 c.Assert(err, checker.IsNil, check.Commentf(out)) 1715 c.Assert(strings.TrimSpace(out), checker.Equals, n1.ID) 1716 1717 out, err = d.Cmd("network", "inspect", "--format", "{{.ID}}", n2.ID) 1718 c.Assert(err, checker.IsNil, check.Commentf(out)) 1719 c.Assert(strings.TrimSpace(out), checker.Equals, n2.ID) 1720 1721 // Name with duplicates 1722 out, err = d.Cmd("network", "inspect", "--format", "{{.ID}}", name) 1723 c.Assert(err, checker.NotNil, check.Commentf(out)) 1724 c.Assert(out, checker.Contains, "2 matches found based on name") 1725 1726 out, err = d.Cmd("network", "rm", n2.ID) 1727 c.Assert(err, checker.IsNil, check.Commentf(out)) 1728 1729 // Dupliates with name but with different driver 1730 options.Driver = "overlay" 1731 1732 n2, err = cli.NetworkCreate(context.Background(), name, options) 1733 c.Assert(err, checker.IsNil) 1734 1735 // Full ID always works 1736 out, err = d.Cmd("network", "inspect", "--format", "{{.ID}}", n1.ID) 1737 c.Assert(err, checker.IsNil, check.Commentf(out)) 1738 c.Assert(strings.TrimSpace(out), checker.Equals, n1.ID) 1739 1740 out, err = d.Cmd("network", "inspect", "--format", "{{.ID}}", n2.ID) 1741 c.Assert(err, checker.IsNil, check.Commentf(out)) 1742 c.Assert(strings.TrimSpace(out), checker.Equals, n2.ID) 1743 1744 // Name with duplicates 1745 out, err = d.Cmd("network", "inspect", "--format", "{{.ID}}", name) 1746 c.Assert(err, checker.NotNil, check.Commentf(out)) 1747 c.Assert(out, checker.Contains, "2 matches found based on name") 1748 } 1749 1750 func (s *DockerSwarmSuite) TestSwarmStopSignal(c *check.C) { 1751 testRequires(c, DaemonIsLinux, UserNamespaceROMount) 1752 1753 d := s.AddDaemon(c, true, true) 1754 1755 out, err := d.Cmd("service", "create", "--detach", "--no-resolve-image", "--name", "top", "--stop-signal=SIGHUP", "busybox", "top") 1756 c.Assert(err, checker.IsNil, check.Commentf(out)) 1757 1758 // make sure task has been deployed. 1759 waitAndAssert(c, defaultReconciliationTimeout, d.CheckActiveContainerCount, checker.Equals, 1) 1760 1761 out, err = d.Cmd("service", "inspect", "--format", "{{ .Spec.TaskTemplate.ContainerSpec.StopSignal }}", "top") 1762 c.Assert(err, checker.IsNil, check.Commentf(out)) 1763 c.Assert(strings.TrimSpace(out), checker.Equals, "SIGHUP") 1764 1765 containers := d.ActiveContainers() 1766 out, err = d.Cmd("inspect", "--type", "container", "--format", "{{.Config.StopSignal}}", containers[0]) 1767 c.Assert(err, checker.IsNil, check.Commentf(out)) 1768 c.Assert(strings.TrimSpace(out), checker.Equals, "SIGHUP") 1769 1770 out, err = d.Cmd("service", "update", "--detach", "--stop-signal=SIGUSR1", "top") 1771 c.Assert(err, checker.IsNil, check.Commentf(out)) 1772 1773 out, err = d.Cmd("service", "inspect", "--format", "{{ .Spec.TaskTemplate.ContainerSpec.StopSignal }}", "top") 1774 c.Assert(err, checker.IsNil, check.Commentf(out)) 1775 c.Assert(strings.TrimSpace(out), checker.Equals, "SIGUSR1") 1776 } 1777 1778 func (s *DockerSwarmSuite) TestSwarmServiceLsFilterMode(c *check.C) { 1779 d := s.AddDaemon(c, true, true) 1780 1781 out, err := d.Cmd("service", "create", "--detach", "--no-resolve-image", "--name", "top1", "busybox", "top") 1782 c.Assert(err, checker.IsNil, check.Commentf(out)) 1783 c.Assert(strings.TrimSpace(out), checker.Not(checker.Equals), "") 1784 1785 out, err = d.Cmd("service", "create", "--detach", "--no-resolve-image", "--name", "top2", "--mode=global", "busybox", "top") 1786 c.Assert(err, checker.IsNil, check.Commentf(out)) 1787 c.Assert(strings.TrimSpace(out), checker.Not(checker.Equals), "") 1788 1789 // make sure task has been deployed. 1790 waitAndAssert(c, defaultReconciliationTimeout, d.CheckActiveContainerCount, checker.Equals, 2) 1791 1792 out, err = d.Cmd("service", "ls") 1793 c.Assert(err, checker.IsNil, check.Commentf(out)) 1794 c.Assert(out, checker.Contains, "top1") 1795 c.Assert(out, checker.Contains, "top2") 1796 c.Assert(out, checker.Not(checker.Contains), "localnet") 1797 1798 out, err = d.Cmd("service", "ls", "--filter", "mode=global") 1799 c.Assert(out, checker.Not(checker.Contains), "top1") 1800 c.Assert(out, checker.Contains, "top2") 1801 c.Assert(err, checker.IsNil, check.Commentf(out)) 1802 1803 out, err = d.Cmd("service", "ls", "--filter", "mode=replicated") 1804 c.Assert(err, checker.IsNil, check.Commentf(out)) 1805 c.Assert(out, checker.Contains, "top1") 1806 c.Assert(out, checker.Not(checker.Contains), "top2") 1807 } 1808 1809 func (s *DockerSwarmSuite) TestSwarmInitUnspecifiedDataPathAddr(c *check.C) { 1810 d := s.AddDaemon(c, false, false) 1811 1812 out, err := d.Cmd("swarm", "init", "--data-path-addr", "0.0.0.0") 1813 c.Assert(err, checker.NotNil) 1814 c.Assert(out, checker.Contains, "data path address must be a non-zero IP") 1815 1816 out, err = d.Cmd("swarm", "init", "--data-path-addr", "0.0.0.0:2000") 1817 c.Assert(err, checker.NotNil) 1818 c.Assert(out, checker.Contains, "data path address must be a non-zero IP") 1819 } 1820 1821 func (s *DockerSwarmSuite) TestSwarmJoinLeave(c *check.C) { 1822 d := s.AddDaemon(c, true, true) 1823 1824 out, err := d.Cmd("swarm", "join-token", "-q", "worker") 1825 c.Assert(err, checker.IsNil) 1826 c.Assert(strings.TrimSpace(out), checker.Not(checker.Equals), "") 1827 1828 token := strings.TrimSpace(out) 1829 1830 // Verify that back to back join/leave does not cause panics 1831 d1 := s.AddDaemon(c, false, false) 1832 for i := 0; i < 10; i++ { 1833 out, err = d1.Cmd("swarm", "join", "--token", token, d.SwarmListenAddr()) 1834 c.Assert(err, checker.IsNil) 1835 c.Assert(strings.TrimSpace(out), checker.Not(checker.Equals), "") 1836 1837 _, err = d1.Cmd("swarm", "leave") 1838 c.Assert(err, checker.IsNil) 1839 } 1840 } 1841 1842 const defaultRetryCount = 10 1843 1844 func waitForEvent(c *check.C, d *daemon.Daemon, since string, filter string, event string, retry int) string { 1845 if retry < 1 { 1846 c.Fatalf("retry count %d is invalid. It should be no less than 1", retry) 1847 return "" 1848 } 1849 var out string 1850 for i := 0; i < retry; i++ { 1851 until := daemonUnixTime(c) 1852 var err error 1853 if len(filter) > 0 { 1854 out, err = d.Cmd("events", "--since", since, "--until", until, filter) 1855 } else { 1856 out, err = d.Cmd("events", "--since", since, "--until", until) 1857 } 1858 c.Assert(err, checker.IsNil, check.Commentf(out)) 1859 if strings.Contains(out, event) { 1860 return strings.TrimSpace(out) 1861 } 1862 // no need to sleep after last retry 1863 if i < retry-1 { 1864 time.Sleep(200 * time.Millisecond) 1865 } 1866 } 1867 c.Fatalf("docker events output '%s' doesn't contain event '%s'", out, event) 1868 return "" 1869 } 1870 1871 func (s *DockerSwarmSuite) TestSwarmClusterEventsSource(c *check.C) { 1872 d1 := s.AddDaemon(c, true, true) 1873 d2 := s.AddDaemon(c, true, true) 1874 d3 := s.AddDaemon(c, true, false) 1875 1876 // create a network 1877 out, err := d1.Cmd("network", "create", "--attachable", "-d", "overlay", "foo") 1878 c.Assert(err, checker.IsNil, check.Commentf(out)) 1879 networkID := strings.TrimSpace(out) 1880 c.Assert(networkID, checker.Not(checker.Equals), "") 1881 1882 // d1, d2 are managers that can get swarm events 1883 waitForEvent(c, d1, "0", "-f scope=swarm", "network create "+networkID, defaultRetryCount) 1884 waitForEvent(c, d2, "0", "-f scope=swarm", "network create "+networkID, defaultRetryCount) 1885 1886 // d3 is a worker, not able to get cluster events 1887 out = waitForEvent(c, d3, "0", "-f scope=swarm", "", 1) 1888 c.Assert(out, checker.Not(checker.Contains), "network create ") 1889 } 1890 1891 func (s *DockerSwarmSuite) TestSwarmClusterEventsScope(c *check.C) { 1892 d := s.AddDaemon(c, true, true) 1893 1894 // create a service 1895 out, err := d.Cmd("service", "create", "--no-resolve-image", "--name", "test", "--detach=false", "busybox", "top") 1896 c.Assert(err, checker.IsNil, check.Commentf(out)) 1897 serviceID := strings.Split(out, "\n")[0] 1898 1899 // scope swarm filters cluster events 1900 out = waitForEvent(c, d, "0", "-f scope=swarm", "service create "+serviceID, defaultRetryCount) 1901 c.Assert(out, checker.Not(checker.Contains), "container create ") 1902 1903 // all events are returned if scope is not specified 1904 waitForEvent(c, d, "0", "", "service create "+serviceID, 1) 1905 waitForEvent(c, d, "0", "", "container create ", defaultRetryCount) 1906 1907 // scope local only shows non-cluster events 1908 out = waitForEvent(c, d, "0", "-f scope=local", "container create ", 1) 1909 c.Assert(out, checker.Not(checker.Contains), "service create ") 1910 } 1911 1912 func (s *DockerSwarmSuite) TestSwarmClusterEventsType(c *check.C) { 1913 d := s.AddDaemon(c, true, true) 1914 1915 // create a service 1916 out, err := d.Cmd("service", "create", "--no-resolve-image", "--name", "test", "--detach=false", "busybox", "top") 1917 c.Assert(err, checker.IsNil, check.Commentf(out)) 1918 serviceID := strings.Split(out, "\n")[0] 1919 1920 // create a network 1921 out, err = d.Cmd("network", "create", "--attachable", "-d", "overlay", "foo") 1922 c.Assert(err, checker.IsNil, check.Commentf(out)) 1923 networkID := strings.TrimSpace(out) 1924 c.Assert(networkID, checker.Not(checker.Equals), "") 1925 1926 // filter by service 1927 out = waitForEvent(c, d, "0", "-f type=service", "service create "+serviceID, defaultRetryCount) 1928 c.Assert(out, checker.Not(checker.Contains), "network create") 1929 1930 // filter by network 1931 out = waitForEvent(c, d, "0", "-f type=network", "network create "+networkID, defaultRetryCount) 1932 c.Assert(out, checker.Not(checker.Contains), "service create") 1933 } 1934 1935 func (s *DockerSwarmSuite) TestSwarmClusterEventsService(c *check.C) { 1936 d := s.AddDaemon(c, true, true) 1937 1938 // create a service 1939 out, err := d.Cmd("service", "create", "--no-resolve-image", "--name", "test", "--detach=false", "busybox", "top") 1940 c.Assert(err, checker.IsNil, check.Commentf(out)) 1941 serviceID := strings.Split(out, "\n")[0] 1942 1943 // validate service create event 1944 waitForEvent(c, d, "0", "-f scope=swarm", "service create "+serviceID, defaultRetryCount) 1945 1946 t1 := daemonUnixTime(c) 1947 out, err = d.Cmd("service", "update", "--force", "--detach=false", "test") 1948 c.Assert(err, checker.IsNil, check.Commentf(out)) 1949 1950 // wait for service update start 1951 out = waitForEvent(c, d, t1, "-f scope=swarm", "service update "+serviceID, defaultRetryCount) 1952 c.Assert(out, checker.Contains, "updatestate.new=updating") 1953 1954 // allow service update complete. This is a service with 1 instance 1955 time.Sleep(400 * time.Millisecond) 1956 out = waitForEvent(c, d, t1, "-f scope=swarm", "service update "+serviceID, defaultRetryCount) 1957 c.Assert(out, checker.Contains, "updatestate.new=completed, updatestate.old=updating") 1958 1959 // scale service 1960 t2 := daemonUnixTime(c) 1961 out, err = d.Cmd("service", "scale", "test=3") 1962 c.Assert(err, checker.IsNil, check.Commentf(out)) 1963 1964 out = waitForEvent(c, d, t2, "-f scope=swarm", "service update "+serviceID, defaultRetryCount) 1965 c.Assert(out, checker.Contains, "replicas.new=3, replicas.old=1") 1966 1967 // remove service 1968 t3 := daemonUnixTime(c) 1969 out, err = d.Cmd("service", "rm", "test") 1970 c.Assert(err, checker.IsNil, check.Commentf(out)) 1971 1972 waitForEvent(c, d, t3, "-f scope=swarm", "service remove "+serviceID, defaultRetryCount) 1973 } 1974 1975 func (s *DockerSwarmSuite) TestSwarmClusterEventsNode(c *check.C) { 1976 d1 := s.AddDaemon(c, true, true) 1977 s.AddDaemon(c, true, true) 1978 d3 := s.AddDaemon(c, true, true) 1979 1980 d3ID := d3.NodeID() 1981 waitForEvent(c, d1, "0", "-f scope=swarm", "node create "+d3ID, defaultRetryCount) 1982 1983 t1 := daemonUnixTime(c) 1984 out, err := d1.Cmd("node", "update", "--availability=pause", d3ID) 1985 c.Assert(err, checker.IsNil, check.Commentf(out)) 1986 1987 // filter by type 1988 out = waitForEvent(c, d1, t1, "-f type=node", "node update "+d3ID, defaultRetryCount) 1989 c.Assert(out, checker.Contains, "availability.new=pause, availability.old=active") 1990 1991 t2 := daemonUnixTime(c) 1992 out, err = d1.Cmd("node", "demote", d3ID) 1993 c.Assert(err, checker.IsNil, check.Commentf(out)) 1994 1995 waitForEvent(c, d1, t2, "-f type=node", "node update "+d3ID, defaultRetryCount) 1996 1997 t3 := daemonUnixTime(c) 1998 out, err = d1.Cmd("node", "rm", "-f", d3ID) 1999 c.Assert(err, checker.IsNil, check.Commentf(out)) 2000 2001 // filter by scope 2002 waitForEvent(c, d1, t3, "-f scope=swarm", "node remove "+d3ID, defaultRetryCount) 2003 } 2004 2005 func (s *DockerSwarmSuite) TestSwarmClusterEventsNetwork(c *check.C) { 2006 d := s.AddDaemon(c, true, true) 2007 2008 // create a network 2009 out, err := d.Cmd("network", "create", "--attachable", "-d", "overlay", "foo") 2010 c.Assert(err, checker.IsNil, check.Commentf(out)) 2011 networkID := strings.TrimSpace(out) 2012 2013 waitForEvent(c, d, "0", "-f scope=swarm", "network create "+networkID, defaultRetryCount) 2014 2015 // remove network 2016 t1 := daemonUnixTime(c) 2017 out, err = d.Cmd("network", "rm", "foo") 2018 c.Assert(err, checker.IsNil, check.Commentf(out)) 2019 2020 // filtered by network 2021 waitForEvent(c, d, t1, "-f type=network", "network remove "+networkID, defaultRetryCount) 2022 } 2023 2024 func (s *DockerSwarmSuite) TestSwarmClusterEventsSecret(c *check.C) { 2025 d := s.AddDaemon(c, true, true) 2026 2027 testName := "test_secret" 2028 id := d.CreateSecret(c, swarm.SecretSpec{ 2029 Annotations: swarm.Annotations{ 2030 Name: testName, 2031 }, 2032 Data: []byte("TESTINGDATA"), 2033 }) 2034 c.Assert(id, checker.Not(checker.Equals), "", check.Commentf("secrets: %s", id)) 2035 2036 waitForEvent(c, d, "0", "-f scope=swarm", "secret create "+id, defaultRetryCount) 2037 2038 t1 := daemonUnixTime(c) 2039 d.DeleteSecret(c, id) 2040 // filtered by secret 2041 waitForEvent(c, d, t1, "-f type=secret", "secret remove "+id, defaultRetryCount) 2042 } 2043 2044 func (s *DockerSwarmSuite) TestSwarmClusterEventsConfig(c *check.C) { 2045 d := s.AddDaemon(c, true, true) 2046 2047 testName := "test_config" 2048 id := d.CreateConfig(c, swarm.ConfigSpec{ 2049 Annotations: swarm.Annotations{ 2050 Name: testName, 2051 }, 2052 Data: []byte("TESTINGDATA"), 2053 }) 2054 c.Assert(id, checker.Not(checker.Equals), "", check.Commentf("configs: %s", id)) 2055 2056 waitForEvent(c, d, "0", "-f scope=swarm", "config create "+id, defaultRetryCount) 2057 2058 t1 := daemonUnixTime(c) 2059 d.DeleteConfig(c, id) 2060 // filtered by config 2061 waitForEvent(c, d, t1, "-f type=config", "config remove "+id, defaultRetryCount) 2062 }