github.com/nullne/docker@v1.13.0-rc1/integration-cli/docker_cli_swarm_test.go (about) 1 // +build !windows 2 3 package main 4 5 import ( 6 "bytes" 7 "encoding/json" 8 "fmt" 9 "io/ioutil" 10 "net/http" 11 "net/http/httptest" 12 "os" 13 "path/filepath" 14 "strings" 15 "time" 16 17 "github.com/docker/docker/api/types/swarm" 18 "github.com/docker/docker/pkg/integration/checker" 19 "github.com/docker/libnetwork/driverapi" 20 "github.com/docker/libnetwork/ipamapi" 21 remoteipam "github.com/docker/libnetwork/ipams/remote/api" 22 "github.com/go-check/check" 23 "github.com/vishvananda/netlink" 24 ) 25 26 func (s *DockerSwarmSuite) TestSwarmUpdate(c *check.C) { 27 d := s.AddDaemon(c, true, true) 28 29 getSpec := func() swarm.Spec { 30 sw := d.getSwarm(c) 31 return sw.Spec 32 } 33 34 out, err := d.Cmd("swarm", "update", "--cert-expiry", "30h", "--dispatcher-heartbeat", "11s") 35 c.Assert(err, checker.IsNil, check.Commentf("out: %v", out)) 36 37 spec := getSpec() 38 c.Assert(spec.CAConfig.NodeCertExpiry, checker.Equals, 30*time.Hour) 39 c.Assert(spec.Dispatcher.HeartbeatPeriod, checker.Equals, 11*time.Second) 40 41 // setting anything under 30m for cert-expiry is not allowed 42 out, err = d.Cmd("swarm", "update", "--cert-expiry", "15m") 43 c.Assert(err, checker.NotNil) 44 c.Assert(out, checker.Contains, "minimum certificate expiry time") 45 spec = getSpec() 46 c.Assert(spec.CAConfig.NodeCertExpiry, checker.Equals, 30*time.Hour) 47 } 48 49 func (s *DockerSwarmSuite) TestSwarmInit(c *check.C) { 50 d := s.AddDaemon(c, false, false) 51 52 getSpec := func() swarm.Spec { 53 sw := d.getSwarm(c) 54 return sw.Spec 55 } 56 57 out, err := d.Cmd("swarm", "init", "--cert-expiry", "30h", "--dispatcher-heartbeat", "11s") 58 c.Assert(err, checker.IsNil, check.Commentf("out: %v", out)) 59 60 spec := getSpec() 61 c.Assert(spec.CAConfig.NodeCertExpiry, checker.Equals, 30*time.Hour) 62 c.Assert(spec.Dispatcher.HeartbeatPeriod, checker.Equals, 11*time.Second) 63 64 c.Assert(d.Leave(true), checker.IsNil) 65 time.Sleep(500 * time.Millisecond) // https://github.com/docker/swarmkit/issues/1421 66 out, err = d.Cmd("swarm", "init") 67 c.Assert(err, checker.IsNil, check.Commentf("out: %v", out)) 68 69 spec = getSpec() 70 c.Assert(spec.CAConfig.NodeCertExpiry, checker.Equals, 90*24*time.Hour) 71 c.Assert(spec.Dispatcher.HeartbeatPeriod, checker.Equals, 5*time.Second) 72 } 73 74 func (s *DockerSwarmSuite) TestSwarmInitIPv6(c *check.C) { 75 testRequires(c, IPv6) 76 d1 := s.AddDaemon(c, false, false) 77 out, err := d1.Cmd("swarm", "init", "--listen-addr", "::1") 78 c.Assert(err, checker.IsNil, check.Commentf("out: %v", out)) 79 80 d2 := s.AddDaemon(c, false, false) 81 out, err = d2.Cmd("swarm", "join", "::1") 82 c.Assert(err, checker.IsNil, check.Commentf("out: %v", out)) 83 84 out, err = d2.Cmd("info") 85 c.Assert(err, checker.IsNil, check.Commentf("out: %v", out)) 86 c.Assert(out, checker.Contains, "Swarm: active") 87 } 88 89 func (s *DockerSwarmSuite) TestSwarmIncompatibleDaemon(c *check.C) { 90 // init swarm mode and stop a daemon 91 d := s.AddDaemon(c, true, true) 92 info, err := d.info() 93 c.Assert(err, checker.IsNil) 94 c.Assert(info.LocalNodeState, checker.Equals, swarm.LocalNodeStateActive) 95 c.Assert(d.Stop(), checker.IsNil) 96 97 // start a daemon with --cluster-store and --cluster-advertise 98 err = d.Start("--cluster-store=consul://consuladdr:consulport/some/path", "--cluster-advertise=1.1.1.1:2375") 99 c.Assert(err, checker.NotNil) 100 content, _ := ioutil.ReadFile(d.logFile.Name()) 101 c.Assert(string(content), checker.Contains, "--cluster-store and --cluster-advertise daemon configurations are incompatible with swarm mode") 102 103 // start a daemon with --live-restore 104 err = d.Start("--live-restore") 105 c.Assert(err, checker.NotNil) 106 content, _ = ioutil.ReadFile(d.logFile.Name()) 107 c.Assert(string(content), checker.Contains, "--live-restore daemon configuration is incompatible with swarm mode") 108 // restart for teardown 109 c.Assert(d.Start(), checker.IsNil) 110 } 111 112 // Test case for #24090 113 func (s *DockerSwarmSuite) TestSwarmNodeListHostname(c *check.C) { 114 d := s.AddDaemon(c, true, true) 115 116 // The first line should contain "HOSTNAME" 117 out, err := d.Cmd("node", "ls") 118 c.Assert(err, checker.IsNil) 119 c.Assert(strings.Split(out, "\n")[0], checker.Contains, "HOSTNAME") 120 } 121 122 func (s *DockerSwarmSuite) TestSwarmServiceTemplatingHostname(c *check.C) { 123 d := s.AddDaemon(c, true, true) 124 125 out, err := d.Cmd("service", "create", "--name", "test", "--hostname", "{{.Service.Name}}-{{.Task.Slot}}", "busybox", "top") 126 c.Assert(err, checker.IsNil, check.Commentf(out)) 127 128 // make sure task has been deployed. 129 waitAndAssert(c, defaultReconciliationTimeout, d.checkActiveContainerCount, checker.Equals, 1) 130 131 containers := d.activeContainers() 132 out, err = d.Cmd("inspect", "--type", "container", "--format", "{{.Config.Hostname}}", containers[0]) 133 c.Assert(err, checker.IsNil, check.Commentf(out)) 134 c.Assert(strings.Split(out, "\n")[0], checker.Equals, "test-1", check.Commentf("hostname with templating invalid")) 135 } 136 137 // Test case for #24270 138 func (s *DockerSwarmSuite) TestSwarmServiceListFilter(c *check.C) { 139 d := s.AddDaemon(c, true, true) 140 141 name1 := "redis-cluster-md5" 142 name2 := "redis-cluster" 143 name3 := "other-cluster" 144 out, err := d.Cmd("service", "create", "--name", name1, "busybox", "top") 145 c.Assert(err, checker.IsNil) 146 c.Assert(strings.TrimSpace(out), checker.Not(checker.Equals), "") 147 148 out, err = d.Cmd("service", "create", "--name", name2, "busybox", "top") 149 c.Assert(err, checker.IsNil) 150 c.Assert(strings.TrimSpace(out), checker.Not(checker.Equals), "") 151 152 out, err = d.Cmd("service", "create", "--name", name3, "busybox", "top") 153 c.Assert(err, checker.IsNil) 154 c.Assert(strings.TrimSpace(out), checker.Not(checker.Equals), "") 155 156 filter1 := "name=redis-cluster-md5" 157 filter2 := "name=redis-cluster" 158 159 // We search checker.Contains with `name+" "` to prevent prefix only. 160 out, err = d.Cmd("service", "ls", "--filter", filter1) 161 c.Assert(err, checker.IsNil) 162 c.Assert(out, checker.Contains, name1+" ") 163 c.Assert(out, checker.Not(checker.Contains), name2+" ") 164 c.Assert(out, checker.Not(checker.Contains), name3+" ") 165 166 out, err = d.Cmd("service", "ls", "--filter", filter2) 167 c.Assert(err, checker.IsNil) 168 c.Assert(out, checker.Contains, name1+" ") 169 c.Assert(out, checker.Contains, name2+" ") 170 c.Assert(out, checker.Not(checker.Contains), name3+" ") 171 172 out, err = d.Cmd("service", "ls") 173 c.Assert(err, checker.IsNil) 174 c.Assert(out, checker.Contains, name1+" ") 175 c.Assert(out, checker.Contains, name2+" ") 176 c.Assert(out, checker.Contains, name3+" ") 177 } 178 179 func (s *DockerSwarmSuite) TestSwarmNodeListFilter(c *check.C) { 180 d := s.AddDaemon(c, true, true) 181 182 out, err := d.Cmd("node", "inspect", "--format", "{{ .Description.Hostname }}", "self") 183 c.Assert(err, checker.IsNil) 184 c.Assert(strings.TrimSpace(out), checker.Not(checker.Equals), "") 185 name := strings.TrimSpace(out) 186 187 filter := "name=" + name[:4] 188 189 out, err = d.Cmd("node", "ls", "--filter", filter) 190 c.Assert(err, checker.IsNil) 191 c.Assert(out, checker.Contains, name) 192 193 out, err = d.Cmd("node", "ls", "--filter", "name=none") 194 c.Assert(err, checker.IsNil) 195 c.Assert(out, checker.Not(checker.Contains), name) 196 } 197 198 func (s *DockerSwarmSuite) TestSwarmNodeTaskListFilter(c *check.C) { 199 d := s.AddDaemon(c, true, true) 200 201 name := "redis-cluster-md5" 202 out, err := d.Cmd("service", "create", "--name", name, "--replicas=3", "busybox", "top") 203 c.Assert(err, checker.IsNil) 204 c.Assert(strings.TrimSpace(out), checker.Not(checker.Equals), "") 205 206 // make sure task has been deployed. 207 waitAndAssert(c, defaultReconciliationTimeout, d.checkActiveContainerCount, checker.Equals, 3) 208 209 filter := "name=redis-cluster" 210 211 out, err = d.Cmd("node", "ps", "--filter", filter, "self") 212 c.Assert(err, checker.IsNil) 213 c.Assert(out, checker.Contains, name+".1") 214 c.Assert(out, checker.Contains, name+".2") 215 c.Assert(out, checker.Contains, name+".3") 216 217 out, err = d.Cmd("node", "ps", "--filter", "name=none", "self") 218 c.Assert(err, checker.IsNil) 219 c.Assert(out, checker.Not(checker.Contains), name+".1") 220 c.Assert(out, checker.Not(checker.Contains), name+".2") 221 c.Assert(out, checker.Not(checker.Contains), name+".3") 222 223 out, err = d.Cmd("node", "ps", "--filter", "desired-state=running", "self") 224 c.Assert(err, checker.IsNil) 225 c.Assert(out, checker.Contains, name+".1") 226 c.Assert(out, checker.Contains, name+".2") 227 c.Assert(out, checker.Contains, name+".3") 228 229 out, err = d.Cmd("node", "ps", "--filter", "desired-state=shutdown", "self") 230 c.Assert(err, checker.IsNil) 231 c.Assert(out, checker.Not(checker.Contains), name+".1") 232 c.Assert(out, checker.Not(checker.Contains), name+".2") 233 c.Assert(out, checker.Not(checker.Contains), name+".3") 234 } 235 236 func (s *DockerSwarmSuite) TestSwarmServiceTaskListAll(c *check.C) { 237 d := s.AddDaemon(c, true, true) 238 239 name := "service-task-list-1" 240 out, err := d.Cmd("service", "create", "--name", name, "--replicas=3", "busybox", "top") 241 c.Assert(err, checker.IsNil) 242 c.Assert(strings.TrimSpace(out), checker.Not(checker.Equals), "") 243 244 // make sure task has been deployed. 245 waitAndAssert(c, defaultReconciliationTimeout, d.checkActiveContainerCount, checker.Equals, 3) 246 247 out, err = d.Cmd("service", "ps", name) 248 c.Assert(err, checker.IsNil) 249 c.Assert(out, checker.Contains, name+".1") 250 c.Assert(out, checker.Contains, name+".2") 251 c.Assert(out, checker.Contains, name+".3") 252 253 // Get the last container id so we can restart it to cause a task error in the history 254 containerID, err := d.Cmd("ps", "-q", "-l") 255 c.Assert(err, checker.IsNil) 256 257 _, err = d.Cmd("stop", strings.TrimSpace(containerID)) 258 c.Assert(err, checker.IsNil) 259 260 waitAndAssert(c, defaultReconciliationTimeout, d.checkActiveContainerCount, checker.Equals, 3) 261 262 out, err = d.Cmd("service", "ps", name) 263 c.Assert(err, checker.IsNil) 264 c.Assert(out, checker.Count, name, 3) 265 266 out, err = d.Cmd("service", "ps", name, "-a") 267 c.Assert(err, checker.IsNil) 268 c.Assert(out, checker.Count, name, 4) 269 } 270 271 func (s *DockerSwarmSuite) TestSwarmNodeTaskListAll(c *check.C) { 272 d := s.AddDaemon(c, true, true) 273 274 name := "node-task-list" 275 out, err := d.Cmd("service", "create", "--name", name, "--replicas=3", "busybox", "top") 276 c.Assert(err, checker.IsNil) 277 c.Assert(strings.TrimSpace(out), checker.Not(checker.Equals), "") 278 279 // make sure task has been deployed. 280 waitAndAssert(c, defaultReconciliationTimeout, d.checkActiveContainerCount, checker.Equals, 3) 281 282 out, err = d.Cmd("service", "ps", name) 283 c.Assert(err, checker.IsNil) 284 c.Assert(out, checker.Contains, name+".1") 285 c.Assert(out, checker.Contains, name+".2") 286 c.Assert(out, checker.Contains, name+".3") 287 288 // Get the last container id so we can restart it to cause a task error in the history 289 containerID, err := d.Cmd("ps", "-q", "-l") 290 c.Assert(err, checker.IsNil) 291 292 _, err = d.Cmd("stop", strings.TrimSpace(containerID)) 293 c.Assert(err, checker.IsNil) 294 295 waitAndAssert(c, defaultReconciliationTimeout, d.checkActiveContainerCount, checker.Equals, 3) 296 297 out, err = d.Cmd("node", "ps", "self") 298 c.Assert(err, checker.IsNil) 299 c.Assert(out, checker.Count, name, 3) 300 301 out, err = d.Cmd("node", "ps", "self", "-a") 302 c.Assert(err, checker.IsNil) 303 c.Assert(out, checker.Count, name, 4) 304 } 305 306 // Test case for #25375 307 func (s *DockerSwarmSuite) TestSwarmPublishAdd(c *check.C) { 308 d := s.AddDaemon(c, true, true) 309 310 name := "top" 311 out, err := d.Cmd("service", "create", "--name", name, "--label", "x=y", "busybox", "top") 312 c.Assert(err, checker.IsNil) 313 c.Assert(strings.TrimSpace(out), checker.Not(checker.Equals), "") 314 315 out, err = d.Cmd("service", "update", "--publish-add", "80:80", name) 316 c.Assert(err, checker.IsNil) 317 318 out, err = d.cmdRetryOutOfSequence("service", "update", "--publish-add", "80:80", name) 319 c.Assert(err, checker.IsNil) 320 321 out, err = d.cmdRetryOutOfSequence("service", "update", "--publish-add", "80:80", "--publish-add", "80:20", name) 322 c.Assert(err, checker.NotNil) 323 324 out, err = d.Cmd("service", "inspect", "--format", "{{ .Spec.EndpointSpec.Ports }}", name) 325 c.Assert(err, checker.IsNil) 326 c.Assert(strings.TrimSpace(out), checker.Equals, "[{ tcp 80 80 ingress}]") 327 } 328 329 func (s *DockerSwarmSuite) TestSwarmServiceWithGroup(c *check.C) { 330 d := s.AddDaemon(c, true, true) 331 332 name := "top" 333 out, err := d.Cmd("service", "create", "--name", name, "--user", "root:root", "--group", "wheel", "--group", "audio", "--group", "staff", "--group", "777", "busybox", "top") 334 c.Assert(err, checker.IsNil) 335 c.Assert(strings.TrimSpace(out), checker.Not(checker.Equals), "") 336 337 // make sure task has been deployed. 338 waitAndAssert(c, defaultReconciliationTimeout, d.checkActiveContainerCount, checker.Equals, 1) 339 340 out, err = d.Cmd("ps", "-q") 341 c.Assert(err, checker.IsNil) 342 c.Assert(strings.TrimSpace(out), checker.Not(checker.Equals), "") 343 344 container := strings.TrimSpace(out) 345 346 out, err = d.Cmd("exec", container, "id") 347 c.Assert(err, checker.IsNil) 348 c.Assert(strings.TrimSpace(out), checker.Equals, "uid=0(root) gid=0(root) groups=10(wheel),29(audio),50(staff),777") 349 } 350 351 func (s *DockerSwarmSuite) TestSwarmContainerAutoStart(c *check.C) { 352 d := s.AddDaemon(c, true, true) 353 354 out, err := d.Cmd("network", "create", "--attachable", "-d", "overlay", "foo") 355 c.Assert(err, checker.IsNil) 356 c.Assert(strings.TrimSpace(out), checker.Not(checker.Equals), "") 357 358 out, err = d.Cmd("run", "-id", "--restart=always", "--net=foo", "--name=test", "busybox", "top") 359 c.Assert(err, checker.IsNil, check.Commentf(out)) 360 c.Assert(strings.TrimSpace(out), checker.Not(checker.Equals), "") 361 362 out, err = d.Cmd("ps", "-q") 363 c.Assert(err, checker.IsNil, check.Commentf(out)) 364 c.Assert(strings.TrimSpace(out), checker.Not(checker.Equals), "") 365 366 d.Restart() 367 368 out, err = d.Cmd("ps", "-q") 369 c.Assert(err, checker.IsNil, check.Commentf(out)) 370 c.Assert(strings.TrimSpace(out), checker.Not(checker.Equals), "") 371 } 372 373 func (s *DockerSwarmSuite) TestSwarmContainerEndpointOptions(c *check.C) { 374 d := s.AddDaemon(c, true, true) 375 376 out, err := d.Cmd("network", "create", "--attachable", "-d", "overlay", "foo") 377 c.Assert(err, checker.IsNil, check.Commentf(out)) 378 c.Assert(strings.TrimSpace(out), checker.Not(checker.Equals), "") 379 380 _, err = d.Cmd("run", "-d", "--net=foo", "--name=first", "--net-alias=first-alias", "busybox", "top") 381 c.Assert(err, checker.IsNil, check.Commentf(out)) 382 383 _, err = d.Cmd("run", "-d", "--net=foo", "--name=second", "busybox", "top") 384 c.Assert(err, checker.IsNil, check.Commentf(out)) 385 386 // ping first container and its alias 387 _, err = d.Cmd("exec", "second", "ping", "-c", "1", "first") 388 c.Assert(err, check.IsNil, check.Commentf(out)) 389 _, err = d.Cmd("exec", "second", "ping", "-c", "1", "first-alias") 390 c.Assert(err, check.IsNil, check.Commentf(out)) 391 } 392 393 func (s *DockerSwarmSuite) TestSwarmContainerAttachByNetworkId(c *check.C) { 394 d := s.AddDaemon(c, true, true) 395 396 out, err := d.Cmd("network", "create", "--attachable", "-d", "overlay", "testnet") 397 c.Assert(err, checker.IsNil) 398 c.Assert(strings.TrimSpace(out), checker.Not(checker.Equals), "") 399 networkID := strings.TrimSpace(out) 400 401 out, err = d.Cmd("run", "-d", "--net", networkID, "busybox", "top") 402 c.Assert(err, checker.IsNil) 403 cID := strings.TrimSpace(out) 404 d.waitRun(cID) 405 406 _, err = d.Cmd("rm", "-f", cID) 407 c.Assert(err, checker.IsNil) 408 409 out, err = d.Cmd("network", "rm", "testnet") 410 c.Assert(err, checker.IsNil) 411 412 checkNetwork := func(*check.C) (interface{}, check.CommentInterface) { 413 out, err := d.Cmd("network", "ls") 414 c.Assert(err, checker.IsNil) 415 return out, nil 416 } 417 418 waitAndAssert(c, 3*time.Second, checkNetwork, checker.Not(checker.Contains), "testnet") 419 } 420 421 func (s *DockerSwarmSuite) TestSwarmRemoveInternalNetwork(c *check.C) { 422 d := s.AddDaemon(c, true, true) 423 424 name := "ingress" 425 out, err := d.Cmd("network", "rm", name) 426 c.Assert(err, checker.NotNil) 427 c.Assert(strings.TrimSpace(out), checker.Contains, name) 428 c.Assert(strings.TrimSpace(out), checker.Contains, "is a pre-defined network and cannot be removed") 429 } 430 431 // Test case for #24108, also the case from: 432 // https://github.com/docker/docker/pull/24620#issuecomment-233715656 433 func (s *DockerSwarmSuite) TestSwarmTaskListFilter(c *check.C) { 434 d := s.AddDaemon(c, true, true) 435 436 name := "redis-cluster-md5" 437 out, err := d.Cmd("service", "create", "--name", name, "--replicas=3", "busybox", "top") 438 c.Assert(err, checker.IsNil) 439 c.Assert(strings.TrimSpace(out), checker.Not(checker.Equals), "") 440 441 filter := "name=redis-cluster" 442 443 checkNumTasks := func(*check.C) (interface{}, check.CommentInterface) { 444 out, err := d.Cmd("service", "ps", "--filter", filter, name) 445 c.Assert(err, checker.IsNil) 446 return len(strings.Split(out, "\n")) - 2, nil // includes header and nl in last line 447 } 448 449 // wait until all tasks have been created 450 waitAndAssert(c, defaultReconciliationTimeout, checkNumTasks, checker.Equals, 3) 451 452 out, err = d.Cmd("service", "ps", "--filter", filter, name) 453 c.Assert(err, checker.IsNil) 454 c.Assert(out, checker.Contains, name+".1") 455 c.Assert(out, checker.Contains, name+".2") 456 c.Assert(out, checker.Contains, name+".3") 457 458 out, err = d.Cmd("service", "ps", "--filter", "name="+name+".1", name) 459 c.Assert(err, checker.IsNil) 460 c.Assert(out, checker.Contains, name+".1") 461 c.Assert(out, checker.Not(checker.Contains), name+".2") 462 c.Assert(out, checker.Not(checker.Contains), name+".3") 463 464 out, err = d.Cmd("service", "ps", "--filter", "name=none", name) 465 c.Assert(err, checker.IsNil) 466 c.Assert(out, checker.Not(checker.Contains), name+".1") 467 c.Assert(out, checker.Not(checker.Contains), name+".2") 468 c.Assert(out, checker.Not(checker.Contains), name+".3") 469 470 name = "redis-cluster-sha1" 471 out, err = d.Cmd("service", "create", "--name", name, "--mode=global", "busybox", "top") 472 c.Assert(err, checker.IsNil) 473 c.Assert(strings.TrimSpace(out), checker.Not(checker.Equals), "") 474 475 waitAndAssert(c, defaultReconciliationTimeout, checkNumTasks, checker.Equals, 1) 476 477 filter = "name=redis-cluster" 478 out, err = d.Cmd("service", "ps", "--filter", filter, name) 479 c.Assert(err, checker.IsNil) 480 c.Assert(out, checker.Contains, name) 481 482 out, err = d.Cmd("service", "ps", "--filter", "name="+name, name) 483 c.Assert(err, checker.IsNil) 484 c.Assert(out, checker.Contains, name) 485 486 out, err = d.Cmd("service", "ps", "--filter", "name=none", name) 487 c.Assert(err, checker.IsNil) 488 c.Assert(out, checker.Not(checker.Contains), name) 489 } 490 491 func (s *DockerSwarmSuite) TestPsListContainersFilterIsTask(c *check.C) { 492 d := s.AddDaemon(c, true, true) 493 494 // Create a bare container 495 out, err := d.Cmd("run", "-d", "--name=bare-container", "busybox", "top") 496 c.Assert(err, checker.IsNil) 497 bareID := strings.TrimSpace(out)[:12] 498 // Create a service 499 name := "busybox-top" 500 out, err = d.Cmd("service", "create", "--name", name, "busybox", "top") 501 c.Assert(err, checker.IsNil) 502 c.Assert(strings.TrimSpace(out), checker.Not(checker.Equals), "") 503 504 // make sure task has been deployed. 505 waitAndAssert(c, defaultReconciliationTimeout, d.checkServiceRunningTasks(name), checker.Equals, 1) 506 507 // Filter non-tasks 508 out, err = d.Cmd("ps", "-a", "-q", "--filter=is-task=false") 509 c.Assert(err, checker.IsNil) 510 psOut := strings.TrimSpace(out) 511 c.Assert(psOut, checker.Equals, bareID, check.Commentf("Expected id %s, got %s for is-task label, output %q", bareID, psOut, out)) 512 513 // Filter tasks 514 out, err = d.Cmd("ps", "-a", "-q", "--filter=is-task=true") 515 c.Assert(err, checker.IsNil) 516 lines := strings.Split(strings.Trim(out, "\n "), "\n") 517 c.Assert(lines, checker.HasLen, 1) 518 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)) 519 } 520 521 const globalNetworkPlugin = "global-network-plugin" 522 const globalIPAMPlugin = "global-ipam-plugin" 523 524 func (s *DockerSwarmSuite) SetUpSuite(c *check.C) { 525 mux := http.NewServeMux() 526 s.server = httptest.NewServer(mux) 527 c.Assert(s.server, check.NotNil, check.Commentf("Failed to start an HTTP Server")) 528 setupRemoteGlobalNetworkPlugin(c, mux, s.server.URL, globalNetworkPlugin, globalIPAMPlugin) 529 } 530 531 func setupRemoteGlobalNetworkPlugin(c *check.C, mux *http.ServeMux, url, netDrv, ipamDrv string) { 532 533 mux.HandleFunc("/Plugin.Activate", func(w http.ResponseWriter, r *http.Request) { 534 w.Header().Set("Content-Type", "application/vnd.docker.plugins.v1+json") 535 fmt.Fprintf(w, `{"Implements": ["%s", "%s"]}`, driverapi.NetworkPluginEndpointType, ipamapi.PluginEndpointType) 536 }) 537 538 // Network driver implementation 539 mux.HandleFunc(fmt.Sprintf("/%s.GetCapabilities", driverapi.NetworkPluginEndpointType), func(w http.ResponseWriter, r *http.Request) { 540 w.Header().Set("Content-Type", "application/vnd.docker.plugins.v1+json") 541 fmt.Fprintf(w, `{"Scope":"global"}`) 542 }) 543 544 mux.HandleFunc(fmt.Sprintf("/%s.AllocateNetwork", driverapi.NetworkPluginEndpointType), func(w http.ResponseWriter, r *http.Request) { 545 err := json.NewDecoder(r.Body).Decode(&remoteDriverNetworkRequest) 546 if err != nil { 547 http.Error(w, "Unable to decode JSON payload: "+err.Error(), http.StatusBadRequest) 548 return 549 } 550 w.Header().Set("Content-Type", "application/vnd.docker.plugins.v1+json") 551 fmt.Fprintf(w, "null") 552 }) 553 554 mux.HandleFunc(fmt.Sprintf("/%s.FreeNetwork", driverapi.NetworkPluginEndpointType), func(w http.ResponseWriter, r *http.Request) { 555 w.Header().Set("Content-Type", "application/vnd.docker.plugins.v1+json") 556 fmt.Fprintf(w, "null") 557 }) 558 559 mux.HandleFunc(fmt.Sprintf("/%s.CreateNetwork", driverapi.NetworkPluginEndpointType), func(w http.ResponseWriter, r *http.Request) { 560 err := json.NewDecoder(r.Body).Decode(&remoteDriverNetworkRequest) 561 if err != nil { 562 http.Error(w, "Unable to decode JSON payload: "+err.Error(), http.StatusBadRequest) 563 return 564 } 565 w.Header().Set("Content-Type", "application/vnd.docker.plugins.v1+json") 566 fmt.Fprintf(w, "null") 567 }) 568 569 mux.HandleFunc(fmt.Sprintf("/%s.DeleteNetwork", driverapi.NetworkPluginEndpointType), func(w http.ResponseWriter, r *http.Request) { 570 w.Header().Set("Content-Type", "application/vnd.docker.plugins.v1+json") 571 fmt.Fprintf(w, "null") 572 }) 573 574 mux.HandleFunc(fmt.Sprintf("/%s.CreateEndpoint", driverapi.NetworkPluginEndpointType), func(w http.ResponseWriter, r *http.Request) { 575 w.Header().Set("Content-Type", "application/vnd.docker.plugins.v1+json") 576 fmt.Fprintf(w, `{"Interface":{"MacAddress":"a0:b1:c2:d3:e4:f5"}}`) 577 }) 578 579 mux.HandleFunc(fmt.Sprintf("/%s.Join", driverapi.NetworkPluginEndpointType), func(w http.ResponseWriter, r *http.Request) { 580 w.Header().Set("Content-Type", "application/vnd.docker.plugins.v1+json") 581 582 veth := &netlink.Veth{ 583 LinkAttrs: netlink.LinkAttrs{Name: "randomIfName", TxQLen: 0}, PeerName: "cnt0"} 584 if err := netlink.LinkAdd(veth); err != nil { 585 fmt.Fprintf(w, `{"Error":"failed to add veth pair: `+err.Error()+`"}`) 586 } else { 587 fmt.Fprintf(w, `{"InterfaceName":{ "SrcName":"cnt0", "DstPrefix":"veth"}}`) 588 } 589 }) 590 591 mux.HandleFunc(fmt.Sprintf("/%s.Leave", driverapi.NetworkPluginEndpointType), func(w http.ResponseWriter, r *http.Request) { 592 w.Header().Set("Content-Type", "application/vnd.docker.plugins.v1+json") 593 fmt.Fprintf(w, "null") 594 }) 595 596 mux.HandleFunc(fmt.Sprintf("/%s.DeleteEndpoint", driverapi.NetworkPluginEndpointType), func(w http.ResponseWriter, r *http.Request) { 597 w.Header().Set("Content-Type", "application/vnd.docker.plugins.v1+json") 598 if link, err := netlink.LinkByName("cnt0"); err == nil { 599 netlink.LinkDel(link) 600 } 601 fmt.Fprintf(w, "null") 602 }) 603 604 // IPAM Driver implementation 605 var ( 606 poolRequest remoteipam.RequestPoolRequest 607 poolReleaseReq remoteipam.ReleasePoolRequest 608 addressRequest remoteipam.RequestAddressRequest 609 addressReleaseReq remoteipam.ReleaseAddressRequest 610 lAS = "localAS" 611 gAS = "globalAS" 612 pool = "172.28.0.0/16" 613 poolID = lAS + "/" + pool 614 gw = "172.28.255.254/16" 615 ) 616 617 mux.HandleFunc(fmt.Sprintf("/%s.GetDefaultAddressSpaces", ipamapi.PluginEndpointType), func(w http.ResponseWriter, r *http.Request) { 618 w.Header().Set("Content-Type", "application/vnd.docker.plugins.v1+json") 619 fmt.Fprintf(w, `{"LocalDefaultAddressSpace":"`+lAS+`", "GlobalDefaultAddressSpace": "`+gAS+`"}`) 620 }) 621 622 mux.HandleFunc(fmt.Sprintf("/%s.RequestPool", ipamapi.PluginEndpointType), func(w http.ResponseWriter, r *http.Request) { 623 err := json.NewDecoder(r.Body).Decode(&poolRequest) 624 if err != nil { 625 http.Error(w, "Unable to decode JSON payload: "+err.Error(), http.StatusBadRequest) 626 return 627 } 628 w.Header().Set("Content-Type", "application/vnd.docker.plugins.v1+json") 629 if poolRequest.AddressSpace != lAS && poolRequest.AddressSpace != gAS { 630 fmt.Fprintf(w, `{"Error":"Unknown address space in pool request: `+poolRequest.AddressSpace+`"}`) 631 } else if poolRequest.Pool != "" && poolRequest.Pool != pool { 632 fmt.Fprintf(w, `{"Error":"Cannot handle explicit pool requests yet"}`) 633 } else { 634 fmt.Fprintf(w, `{"PoolID":"`+poolID+`", "Pool":"`+pool+`"}`) 635 } 636 }) 637 638 mux.HandleFunc(fmt.Sprintf("/%s.RequestAddress", ipamapi.PluginEndpointType), func(w http.ResponseWriter, r *http.Request) { 639 err := json.NewDecoder(r.Body).Decode(&addressRequest) 640 if err != nil { 641 http.Error(w, "Unable to decode JSON payload: "+err.Error(), http.StatusBadRequest) 642 return 643 } 644 w.Header().Set("Content-Type", "application/vnd.docker.plugins.v1+json") 645 // make sure libnetwork is now querying on the expected pool id 646 if addressRequest.PoolID != poolID { 647 fmt.Fprintf(w, `{"Error":"unknown pool id"}`) 648 } else if addressRequest.Address != "" { 649 fmt.Fprintf(w, `{"Error":"Cannot handle explicit address requests yet"}`) 650 } else { 651 fmt.Fprintf(w, `{"Address":"`+gw+`"}`) 652 } 653 }) 654 655 mux.HandleFunc(fmt.Sprintf("/%s.ReleaseAddress", ipamapi.PluginEndpointType), func(w http.ResponseWriter, r *http.Request) { 656 err := json.NewDecoder(r.Body).Decode(&addressReleaseReq) 657 if err != nil { 658 http.Error(w, "Unable to decode JSON payload: "+err.Error(), http.StatusBadRequest) 659 return 660 } 661 w.Header().Set("Content-Type", "application/vnd.docker.plugins.v1+json") 662 // make sure libnetwork is now asking to release the expected address from the expected poolid 663 if addressRequest.PoolID != poolID { 664 fmt.Fprintf(w, `{"Error":"unknown pool id"}`) 665 } else if addressReleaseReq.Address != gw { 666 fmt.Fprintf(w, `{"Error":"unknown address"}`) 667 } else { 668 fmt.Fprintf(w, "null") 669 } 670 }) 671 672 mux.HandleFunc(fmt.Sprintf("/%s.ReleasePool", ipamapi.PluginEndpointType), func(w http.ResponseWriter, r *http.Request) { 673 err := json.NewDecoder(r.Body).Decode(&poolReleaseReq) 674 if err != nil { 675 http.Error(w, "Unable to decode JSON payload: "+err.Error(), http.StatusBadRequest) 676 return 677 } 678 w.Header().Set("Content-Type", "application/vnd.docker.plugins.v1+json") 679 // make sure libnetwork is now asking to release the expected poolid 680 if addressRequest.PoolID != poolID { 681 fmt.Fprintf(w, `{"Error":"unknown pool id"}`) 682 } else { 683 fmt.Fprintf(w, "null") 684 } 685 }) 686 687 err := os.MkdirAll("/etc/docker/plugins", 0755) 688 c.Assert(err, checker.IsNil) 689 690 fileName := fmt.Sprintf("/etc/docker/plugins/%s.spec", netDrv) 691 err = ioutil.WriteFile(fileName, []byte(url), 0644) 692 c.Assert(err, checker.IsNil) 693 694 ipamFileName := fmt.Sprintf("/etc/docker/plugins/%s.spec", ipamDrv) 695 err = ioutil.WriteFile(ipamFileName, []byte(url), 0644) 696 c.Assert(err, checker.IsNil) 697 } 698 699 func (s *DockerSwarmSuite) TestSwarmNetworkPlugin(c *check.C) { 700 d := s.AddDaemon(c, true, true) 701 702 out, err := d.Cmd("network", "create", "-d", globalNetworkPlugin, "foo") 703 c.Assert(err, checker.IsNil) 704 c.Assert(strings.TrimSpace(out), checker.Not(checker.Equals), "") 705 706 name := "top" 707 out, err = d.Cmd("service", "create", "--name", name, "--network", "foo", "busybox", "top") 708 c.Assert(err, checker.IsNil) 709 c.Assert(strings.TrimSpace(out), checker.Not(checker.Equals), "") 710 711 out, err = d.Cmd("service", "inspect", "--format", "{{range .Spec.Networks}}{{.Target}}{{end}}", name) 712 c.Assert(err, checker.IsNil) 713 c.Assert(strings.TrimSpace(out), checker.Equals, "foo") 714 } 715 716 // Test case for #24712 717 func (s *DockerSwarmSuite) TestSwarmServiceEnvFile(c *check.C) { 718 d := s.AddDaemon(c, true, true) 719 720 path := filepath.Join(d.folder, "env.txt") 721 err := ioutil.WriteFile(path, []byte("VAR1=A\nVAR2=A\n"), 0644) 722 c.Assert(err, checker.IsNil) 723 724 name := "worker" 725 out, err := d.Cmd("service", "create", "--env-file", path, "--env", "VAR1=B", "--env", "VAR1=C", "--env", "VAR2=", "--env", "VAR2", "--name", name, "busybox", "top") 726 c.Assert(err, checker.IsNil) 727 c.Assert(strings.TrimSpace(out), checker.Not(checker.Equals), "") 728 729 // The complete env is [VAR1=A VAR2=A VAR1=B VAR1=C VAR2= VAR2] and duplicates will be removed => [VAR1=C VAR2] 730 out, err = d.Cmd("inspect", "--format", "{{ .Spec.TaskTemplate.ContainerSpec.Env }}", name) 731 c.Assert(err, checker.IsNil) 732 c.Assert(out, checker.Contains, "[VAR1=C VAR2]") 733 } 734 735 func (s *DockerSwarmSuite) TestSwarmServiceTTY(c *check.C) { 736 d := s.AddDaemon(c, true, true) 737 738 name := "top" 739 740 ttyCheck := "if [ -t 0 ]; then echo TTY > /status && top; else echo none > /status && top; fi" 741 742 // Without --tty 743 expectedOutput := "none" 744 out, err := d.Cmd("service", "create", "--name", name, "busybox", "sh", "-c", ttyCheck) 745 c.Assert(err, checker.IsNil) 746 747 // Make sure task has been deployed. 748 waitAndAssert(c, defaultReconciliationTimeout, d.checkActiveContainerCount, checker.Equals, 1) 749 750 // We need to get the container id. 751 out, err = d.Cmd("ps", "-a", "-q", "--no-trunc") 752 c.Assert(err, checker.IsNil) 753 id := strings.TrimSpace(out) 754 755 out, err = d.Cmd("exec", id, "cat", "/status") 756 c.Assert(err, checker.IsNil) 757 c.Assert(out, checker.Contains, expectedOutput, check.Commentf("Expected '%s', but got %q", expectedOutput, out)) 758 759 // Remove service 760 out, err = d.Cmd("service", "rm", name) 761 c.Assert(err, checker.IsNil) 762 // Make sure container has been destroyed. 763 waitAndAssert(c, defaultReconciliationTimeout, d.checkActiveContainerCount, checker.Equals, 0) 764 765 // With --tty 766 expectedOutput = "TTY" 767 out, err = d.Cmd("service", "create", "--name", name, "--tty", "busybox", "sh", "-c", ttyCheck) 768 c.Assert(err, checker.IsNil) 769 770 // Make sure task has been deployed. 771 waitAndAssert(c, defaultReconciliationTimeout, d.checkActiveContainerCount, checker.Equals, 1) 772 773 // We need to get the container id. 774 out, err = d.Cmd("ps", "-a", "-q", "--no-trunc") 775 c.Assert(err, checker.IsNil) 776 id = strings.TrimSpace(out) 777 778 out, err = d.Cmd("exec", id, "cat", "/status") 779 c.Assert(err, checker.IsNil) 780 c.Assert(out, checker.Contains, expectedOutput, check.Commentf("Expected '%s', but got %q", expectedOutput, out)) 781 } 782 783 func (s *DockerSwarmSuite) TestSwarmServiceTTYUpdate(c *check.C) { 784 d := s.AddDaemon(c, true, true) 785 786 // Create a service 787 name := "top" 788 _, err := d.Cmd("service", "create", "--name", name, "busybox", "top") 789 c.Assert(err, checker.IsNil) 790 791 // Make sure task has been deployed. 792 waitAndAssert(c, defaultReconciliationTimeout, d.checkActiveContainerCount, checker.Equals, 1) 793 794 out, err := d.Cmd("service", "inspect", "--format", "{{ .Spec.TaskTemplate.ContainerSpec.TTY }}", name) 795 c.Assert(err, checker.IsNil) 796 c.Assert(strings.TrimSpace(out), checker.Equals, "false") 797 798 _, err = d.Cmd("service", "update", "--tty", name) 799 c.Assert(err, checker.IsNil) 800 801 out, err = d.Cmd("service", "inspect", "--format", "{{ .Spec.TaskTemplate.ContainerSpec.TTY }}", name) 802 c.Assert(err, checker.IsNil) 803 c.Assert(strings.TrimSpace(out), checker.Equals, "true") 804 } 805 806 func (s *DockerSwarmSuite) TestDNSConfig(c *check.C) { 807 d := s.AddDaemon(c, true, true) 808 809 // Create a service 810 name := "top" 811 _, err := d.Cmd("service", "create", "--name", name, "--dns=1.2.3.4", "--dns-search=example.com", "--dns-option=timeout:3", "busybox", "top") 812 c.Assert(err, checker.IsNil) 813 814 // Make sure task has been deployed. 815 waitAndAssert(c, defaultReconciliationTimeout, d.checkActiveContainerCount, checker.Equals, 1) 816 817 // We need to get the container id. 818 out, err := d.Cmd("ps", "-a", "-q", "--no-trunc") 819 c.Assert(err, checker.IsNil) 820 id := strings.TrimSpace(out) 821 822 // Compare against expected output. 823 expectedOutput1 := "nameserver 1.2.3.4" 824 expectedOutput2 := "search example.com" 825 expectedOutput3 := "options timeout:3" 826 out, err = d.Cmd("exec", id, "cat", "/etc/resolv.conf") 827 c.Assert(err, checker.IsNil) 828 c.Assert(out, checker.Contains, expectedOutput1, check.Commentf("Expected '%s', but got %q", expectedOutput1, out)) 829 c.Assert(out, checker.Contains, expectedOutput2, check.Commentf("Expected '%s', but got %q", expectedOutput2, out)) 830 c.Assert(out, checker.Contains, expectedOutput3, check.Commentf("Expected '%s', but got %q", expectedOutput3, out)) 831 } 832 833 func (s *DockerSwarmSuite) TestDNSConfigUpdate(c *check.C) { 834 d := s.AddDaemon(c, true, true) 835 836 // Create a service 837 name := "top" 838 _, err := d.Cmd("service", "create", "--name", name, "busybox", "top") 839 c.Assert(err, checker.IsNil) 840 841 // Make sure task has been deployed. 842 waitAndAssert(c, defaultReconciliationTimeout, d.checkActiveContainerCount, checker.Equals, 1) 843 844 _, err = d.Cmd("service", "update", "--dns-add=1.2.3.4", "--dns-search-add=example.com", "--dns-option-add=timeout:3", name) 845 c.Assert(err, checker.IsNil) 846 847 out, err := d.Cmd("service", "inspect", "--format", "{{ .Spec.TaskTemplate.ContainerSpec.DNSConfig }}", name) 848 c.Assert(err, checker.IsNil) 849 c.Assert(strings.TrimSpace(out), checker.Equals, "{[1.2.3.4] [example.com] [timeout:3]}") 850 } 851 852 func (s *DockerSwarmSuite) TestSwarmInitLocked(c *check.C) { 853 d := s.AddDaemon(c, false, false) 854 855 outs, err := d.Cmd("swarm", "init", "--autolock") 856 c.Assert(err, checker.IsNil, check.Commentf("out: %v", outs)) 857 858 c.Assert(outs, checker.Contains, "docker swarm unlock") 859 860 var unlockKey string 861 for _, line := range strings.Split(outs, "\n") { 862 if strings.Contains(line, "SWMKEY") { 863 unlockKey = strings.TrimSpace(line) 864 break 865 } 866 } 867 868 c.Assert(unlockKey, checker.Not(checker.Equals), "") 869 870 outs, err = d.Cmd("swarm", "unlock-key", "-q") 871 c.Assert(outs, checker.Equals, unlockKey+"\n") 872 873 info, err := d.info() 874 c.Assert(err, checker.IsNil) 875 c.Assert(info.LocalNodeState, checker.Equals, swarm.LocalNodeStateActive) 876 877 c.Assert(d.Restart(), checker.IsNil) 878 879 info, err = d.info() 880 c.Assert(err, checker.IsNil) 881 c.Assert(info.LocalNodeState, checker.Equals, swarm.LocalNodeStateLocked) 882 883 cmd := d.command("swarm", "unlock") 884 cmd.Stdin = bytes.NewBufferString("wrong-secret-key") 885 out, err := cmd.CombinedOutput() 886 c.Assert(err, checker.NotNil, check.Commentf("out: %v", string(out))) 887 c.Assert(string(out), checker.Contains, "invalid key") 888 889 cmd = d.command("swarm", "unlock") 890 cmd.Stdin = bytes.NewBufferString(unlockKey) 891 out, err = cmd.CombinedOutput() 892 c.Assert(err, checker.IsNil, check.Commentf("out: %v", string(out))) 893 894 info, err = d.info() 895 c.Assert(err, checker.IsNil) 896 c.Assert(info.LocalNodeState, checker.Equals, swarm.LocalNodeStateActive) 897 898 outs, err = d.Cmd("node", "ls") 899 c.Assert(err, checker.IsNil) 900 c.Assert(outs, checker.Not(checker.Contains), "Swarm is encrypted and needs to be unlocked") 901 902 outs, err = d.Cmd("swarm", "update", "--autolock=false") 903 c.Assert(err, checker.IsNil, check.Commentf("out: %v", outs)) 904 905 // Wait for autolock to be turned off 906 time.Sleep(time.Second) 907 908 c.Assert(d.Restart(), checker.IsNil) 909 910 info, err = d.info() 911 c.Assert(err, checker.IsNil) 912 c.Assert(info.LocalNodeState, checker.Equals, swarm.LocalNodeStateActive) 913 914 outs, err = d.Cmd("node", "ls") 915 c.Assert(err, checker.IsNil) 916 c.Assert(outs, checker.Not(checker.Contains), "Swarm is encrypted and needs to be unlocked") 917 } 918 919 func (s *DockerSwarmSuite) TestSwarmLeaveLocked(c *check.C) { 920 d := s.AddDaemon(c, false, false) 921 922 outs, err := d.Cmd("swarm", "init", "--autolock") 923 c.Assert(err, checker.IsNil, check.Commentf("out: %v", outs)) 924 925 c.Assert(d.Restart("--swarm-default-advertise-addr=lo"), checker.IsNil) 926 927 info, err := d.info() 928 c.Assert(err, checker.IsNil) 929 c.Assert(info.LocalNodeState, checker.Equals, swarm.LocalNodeStateLocked) 930 931 outs, _ = d.Cmd("node", "ls") 932 c.Assert(outs, checker.Contains, "Swarm is encrypted and needs to be unlocked") 933 934 outs, err = d.Cmd("swarm", "leave", "--force") 935 c.Assert(err, checker.IsNil, check.Commentf("out: %v", outs)) 936 937 info, err = d.info() 938 c.Assert(err, checker.IsNil) 939 c.Assert(info.LocalNodeState, checker.Equals, swarm.LocalNodeStateInactive) 940 941 outs, err = d.Cmd("swarm", "init") 942 c.Assert(err, checker.IsNil, check.Commentf("out: %v", outs)) 943 944 info, err = d.info() 945 c.Assert(err, checker.IsNil) 946 c.Assert(info.LocalNodeState, checker.Equals, swarm.LocalNodeStateActive) 947 } 948 949 func (s *DockerSwarmSuite) TestSwarmRotateUnlockKey(c *check.C) { 950 d := s.AddDaemon(c, true, true) 951 952 outs, err := d.Cmd("swarm", "update", "--autolock") 953 c.Assert(err, checker.IsNil, check.Commentf("out: %v", outs)) 954 955 c.Assert(outs, checker.Contains, "docker swarm unlock") 956 957 var unlockKey string 958 for _, line := range strings.Split(outs, "\n") { 959 if strings.Contains(line, "SWMKEY") { 960 unlockKey = strings.TrimSpace(line) 961 break 962 } 963 } 964 965 c.Assert(unlockKey, checker.Not(checker.Equals), "") 966 967 outs, err = d.Cmd("swarm", "unlock-key", "-q") 968 c.Assert(outs, checker.Equals, unlockKey+"\n") 969 970 // Rotate multiple times 971 for i := 0; i != 3; i++ { 972 outs, err = d.Cmd("swarm", "unlock-key", "-q", "--rotate") 973 c.Assert(err, checker.IsNil, check.Commentf("out: %v", outs)) 974 // Strip \n 975 newUnlockKey := outs[:len(outs)-1] 976 c.Assert(newUnlockKey, checker.Not(checker.Equals), "") 977 c.Assert(newUnlockKey, checker.Not(checker.Equals), unlockKey) 978 979 c.Assert(d.Restart(), checker.IsNil) 980 981 info, err := d.info() 982 c.Assert(err, checker.IsNil) 983 c.Assert(info.LocalNodeState, checker.Equals, swarm.LocalNodeStateLocked) 984 985 outs, _ = d.Cmd("node", "ls") 986 c.Assert(outs, checker.Contains, "Swarm is encrypted and needs to be unlocked") 987 988 cmd := d.command("swarm", "unlock") 989 cmd.Stdin = bytes.NewBufferString(unlockKey) 990 out, err := cmd.CombinedOutput() 991 992 if err == nil { 993 // On occasion, the daemon may not have finished 994 // rotating the KEK before restarting. The test is 995 // intentionally written to explore this behavior. 996 // When this happens, unlocking with the old key will 997 // succeed. If we wait for the rotation to happen and 998 // restart again, the new key should be required this 999 // time. 1000 1001 time.Sleep(3 * time.Second) 1002 1003 c.Assert(d.Restart(), checker.IsNil) 1004 1005 cmd = d.command("swarm", "unlock") 1006 cmd.Stdin = bytes.NewBufferString(unlockKey) 1007 out, err = cmd.CombinedOutput() 1008 } 1009 c.Assert(err, checker.NotNil, check.Commentf("out: %v", string(out))) 1010 c.Assert(string(out), checker.Contains, "invalid key") 1011 1012 outs, _ = d.Cmd("node", "ls") 1013 c.Assert(outs, checker.Contains, "Swarm is encrypted and needs to be unlocked") 1014 1015 cmd = d.command("swarm", "unlock") 1016 cmd.Stdin = bytes.NewBufferString(newUnlockKey) 1017 out, err = cmd.CombinedOutput() 1018 c.Assert(err, checker.IsNil, check.Commentf("out: %v", string(out))) 1019 1020 info, err = d.info() 1021 c.Assert(err, checker.IsNil) 1022 c.Assert(info.LocalNodeState, checker.Equals, swarm.LocalNodeStateActive) 1023 1024 outs, err = d.Cmd("node", "ls") 1025 c.Assert(err, checker.IsNil) 1026 c.Assert(outs, checker.Not(checker.Contains), "Swarm is encrypted and needs to be unlocked") 1027 1028 unlockKey = newUnlockKey 1029 } 1030 } 1031 1032 func (s *DockerSwarmSuite) TestExtraHosts(c *check.C) { 1033 d := s.AddDaemon(c, true, true) 1034 1035 // Create a service 1036 name := "top" 1037 _, err := d.Cmd("service", "create", "--name", name, "--host=example.com:1.2.3.4", "busybox", "top") 1038 c.Assert(err, checker.IsNil) 1039 1040 // Make sure task has been deployed. 1041 waitAndAssert(c, defaultReconciliationTimeout, d.checkActiveContainerCount, checker.Equals, 1) 1042 1043 // We need to get the container id. 1044 out, err := d.Cmd("ps", "-a", "-q", "--no-trunc") 1045 c.Assert(err, checker.IsNil) 1046 id := strings.TrimSpace(out) 1047 1048 // Compare against expected output. 1049 expectedOutput := "1.2.3.4\texample.com" 1050 out, err = d.Cmd("exec", id, "cat", "/etc/hosts") 1051 c.Assert(err, checker.IsNil) 1052 c.Assert(out, checker.Contains, expectedOutput, check.Commentf("Expected '%s', but got %q", expectedOutput, out)) 1053 } 1054 1055 func (s *DockerSwarmSuite) TestSwarmManagerAddress(c *check.C) { 1056 d1 := s.AddDaemon(c, true, true) 1057 d2 := s.AddDaemon(c, true, false) 1058 d3 := s.AddDaemon(c, true, false) 1059 1060 // Manager Addresses will always show Node 1's address 1061 expectedOutput := fmt.Sprintf("Manager Addresses:\n 127.0.0.1:%d\n", d1.port) 1062 1063 out, err := d1.Cmd("info") 1064 c.Assert(err, checker.IsNil) 1065 c.Assert(out, checker.Contains, expectedOutput) 1066 1067 out, err = d2.Cmd("info") 1068 c.Assert(err, checker.IsNil) 1069 c.Assert(out, checker.Contains, expectedOutput) 1070 1071 out, err = d3.Cmd("info") 1072 c.Assert(err, checker.IsNil) 1073 c.Assert(out, checker.Contains, expectedOutput) 1074 }