github.com/yogeshlonkar/moby@v1.13.2-0.20201203103638-c0b64beaea94/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) TestSwarmInitUnspecifiedAdvertiseAddr(c *check.C) { 90 d := s.AddDaemon(c, false, false) 91 out, err := d.Cmd("swarm", "init", "--advertise-addr", "0.0.0.0") 92 c.Assert(err, checker.NotNil) 93 c.Assert(out, checker.Contains, "advertise address must be a non-zero IP address") 94 } 95 96 func (s *DockerSwarmSuite) TestSwarmIncompatibleDaemon(c *check.C) { 97 // init swarm mode and stop a daemon 98 d := s.AddDaemon(c, true, true) 99 info, err := d.info() 100 c.Assert(err, checker.IsNil) 101 c.Assert(info.LocalNodeState, checker.Equals, swarm.LocalNodeStateActive) 102 c.Assert(d.Stop(), checker.IsNil) 103 104 // start a daemon with --cluster-store and --cluster-advertise 105 err = d.Start("--cluster-store=consul://consuladdr:consulport/some/path", "--cluster-advertise=1.1.1.1:2375") 106 c.Assert(err, checker.NotNil) 107 content, _ := ioutil.ReadFile(d.logFile.Name()) 108 c.Assert(string(content), checker.Contains, "--cluster-store and --cluster-advertise daemon configurations are incompatible with swarm mode") 109 110 // start a daemon with --live-restore 111 err = d.Start("--live-restore") 112 c.Assert(err, checker.NotNil) 113 content, _ = ioutil.ReadFile(d.logFile.Name()) 114 c.Assert(string(content), checker.Contains, "--live-restore daemon configuration is incompatible with swarm mode") 115 // restart for teardown 116 c.Assert(d.Start(), checker.IsNil) 117 } 118 119 // Test case for #24090 120 func (s *DockerSwarmSuite) TestSwarmNodeListHostname(c *check.C) { 121 d := s.AddDaemon(c, true, true) 122 123 // The first line should contain "HOSTNAME" 124 out, err := d.Cmd("node", "ls") 125 c.Assert(err, checker.IsNil) 126 c.Assert(strings.Split(out, "\n")[0], checker.Contains, "HOSTNAME") 127 } 128 129 func (s *DockerSwarmSuite) TestSwarmServiceTemplatingHostname(c *check.C) { 130 d := s.AddDaemon(c, true, true) 131 132 out, err := d.Cmd("service", "create", "--name", "test", "--hostname", "{{.Service.Name}}-{{.Task.Slot}}", "busybox", "top") 133 c.Assert(err, checker.IsNil, check.Commentf(out)) 134 135 // make sure task has been deployed. 136 waitAndAssert(c, defaultReconciliationTimeout, d.checkActiveContainerCount, checker.Equals, 1) 137 138 containers := d.activeContainers() 139 out, err = d.Cmd("inspect", "--type", "container", "--format", "{{.Config.Hostname}}", containers[0]) 140 c.Assert(err, checker.IsNil, check.Commentf(out)) 141 c.Assert(strings.Split(out, "\n")[0], checker.Equals, "test-1", check.Commentf("hostname with templating invalid")) 142 } 143 144 // Test case for #24270 145 func (s *DockerSwarmSuite) TestSwarmServiceListFilter(c *check.C) { 146 d := s.AddDaemon(c, true, true) 147 148 name1 := "redis-cluster-md5" 149 name2 := "redis-cluster" 150 name3 := "other-cluster" 151 out, err := d.Cmd("service", "create", "--name", name1, "busybox", "top") 152 c.Assert(err, checker.IsNil) 153 c.Assert(strings.TrimSpace(out), checker.Not(checker.Equals), "") 154 155 out, err = d.Cmd("service", "create", "--name", name2, "busybox", "top") 156 c.Assert(err, checker.IsNil) 157 c.Assert(strings.TrimSpace(out), checker.Not(checker.Equals), "") 158 159 out, err = d.Cmd("service", "create", "--name", name3, "busybox", "top") 160 c.Assert(err, checker.IsNil) 161 c.Assert(strings.TrimSpace(out), checker.Not(checker.Equals), "") 162 163 filter1 := "name=redis-cluster-md5" 164 filter2 := "name=redis-cluster" 165 166 // We search checker.Contains with `name+" "` to prevent prefix only. 167 out, err = d.Cmd("service", "ls", "--filter", filter1) 168 c.Assert(err, checker.IsNil) 169 c.Assert(out, checker.Contains, name1+" ") 170 c.Assert(out, checker.Not(checker.Contains), name2+" ") 171 c.Assert(out, checker.Not(checker.Contains), name3+" ") 172 173 out, err = d.Cmd("service", "ls", "--filter", filter2) 174 c.Assert(err, checker.IsNil) 175 c.Assert(out, checker.Contains, name1+" ") 176 c.Assert(out, checker.Contains, name2+" ") 177 c.Assert(out, checker.Not(checker.Contains), name3+" ") 178 179 out, err = d.Cmd("service", "ls") 180 c.Assert(err, checker.IsNil) 181 c.Assert(out, checker.Contains, name1+" ") 182 c.Assert(out, checker.Contains, name2+" ") 183 c.Assert(out, checker.Contains, name3+" ") 184 } 185 186 func (s *DockerSwarmSuite) TestSwarmNodeListFilter(c *check.C) { 187 d := s.AddDaemon(c, true, true) 188 189 out, err := d.Cmd("node", "inspect", "--format", "{{ .Description.Hostname }}", "self") 190 c.Assert(err, checker.IsNil) 191 c.Assert(strings.TrimSpace(out), checker.Not(checker.Equals), "") 192 name := strings.TrimSpace(out) 193 194 filter := "name=" + name[:4] 195 196 out, err = d.Cmd("node", "ls", "--filter", filter) 197 c.Assert(err, checker.IsNil) 198 c.Assert(out, checker.Contains, name) 199 200 out, err = d.Cmd("node", "ls", "--filter", "name=none") 201 c.Assert(err, checker.IsNil) 202 c.Assert(out, checker.Not(checker.Contains), name) 203 } 204 205 func (s *DockerSwarmSuite) TestSwarmNodeTaskListFilter(c *check.C) { 206 d := s.AddDaemon(c, true, true) 207 208 name := "redis-cluster-md5" 209 out, err := d.Cmd("service", "create", "--name", name, "--replicas=3", "busybox", "top") 210 c.Assert(err, checker.IsNil) 211 c.Assert(strings.TrimSpace(out), checker.Not(checker.Equals), "") 212 213 // make sure task has been deployed. 214 waitAndAssert(c, defaultReconciliationTimeout, d.checkActiveContainerCount, checker.Equals, 3) 215 216 filter := "name=redis-cluster" 217 218 out, err = d.Cmd("node", "ps", "--filter", filter, "self") 219 c.Assert(err, checker.IsNil) 220 c.Assert(out, checker.Contains, name+".1") 221 c.Assert(out, checker.Contains, name+".2") 222 c.Assert(out, checker.Contains, name+".3") 223 224 out, err = d.Cmd("node", "ps", "--filter", "name=none", "self") 225 c.Assert(err, checker.IsNil) 226 c.Assert(out, checker.Not(checker.Contains), name+".1") 227 c.Assert(out, checker.Not(checker.Contains), name+".2") 228 c.Assert(out, checker.Not(checker.Contains), name+".3") 229 } 230 231 // Test case for #25375 232 func (s *DockerSwarmSuite) TestSwarmPublishAdd(c *check.C) { 233 d := s.AddDaemon(c, true, true) 234 235 testCases := []struct { 236 name string 237 publishAdd []string 238 ports string 239 }{ 240 { 241 name: "simple-syntax", 242 publishAdd: []string{ 243 "80:80", 244 "80:80", 245 "80:80", 246 "80:20", 247 }, 248 ports: "[{ tcp 80 80 ingress}]", 249 }, 250 { 251 name: "complex-syntax", 252 publishAdd: []string{ 253 "target=90,published=90,protocol=tcp,mode=ingress", 254 "target=90,published=90,protocol=tcp,mode=ingress", 255 "target=90,published=90,protocol=tcp,mode=ingress", 256 "target=30,published=90,protocol=tcp,mode=ingress", 257 }, 258 ports: "[{ tcp 90 90 ingress}]", 259 }, 260 } 261 262 for _, tc := range testCases { 263 out, err := d.Cmd("service", "create", "--name", tc.name, "--label", "x=y", "busybox", "top") 264 c.Assert(err, checker.IsNil, check.Commentf(out)) 265 c.Assert(strings.TrimSpace(out), checker.Not(checker.Equals), "") 266 267 out, err = d.cmdRetryOutOfSequence("service", "update", "--publish-add", tc.publishAdd[0], tc.name) 268 c.Assert(err, checker.IsNil, check.Commentf(out)) 269 270 out, err = d.cmdRetryOutOfSequence("service", "update", "--publish-add", tc.publishAdd[1], tc.name) 271 c.Assert(err, checker.IsNil, check.Commentf(out)) 272 273 out, err = d.cmdRetryOutOfSequence("service", "update", "--publish-add", tc.publishAdd[2], "--publish-add", tc.publishAdd[3], tc.name) 274 c.Assert(err, checker.NotNil, check.Commentf(out)) 275 276 out, err = d.Cmd("service", "inspect", "--format", "{{ .Spec.EndpointSpec.Ports }}", tc.name) 277 c.Assert(err, checker.IsNil) 278 c.Assert(strings.TrimSpace(out), checker.Equals, tc.ports) 279 } 280 } 281 282 func (s *DockerSwarmSuite) TestSwarmServiceWithGroup(c *check.C) { 283 d := s.AddDaemon(c, true, true) 284 285 name := "top" 286 out, err := d.Cmd("service", "create", "--name", name, "--user", "root:root", "--group", "wheel", "--group", "audio", "--group", "staff", "--group", "777", "busybox", "top") 287 c.Assert(err, checker.IsNil) 288 c.Assert(strings.TrimSpace(out), checker.Not(checker.Equals), "") 289 290 // make sure task has been deployed. 291 waitAndAssert(c, defaultReconciliationTimeout, d.checkActiveContainerCount, checker.Equals, 1) 292 293 out, err = d.Cmd("ps", "-q") 294 c.Assert(err, checker.IsNil) 295 c.Assert(strings.TrimSpace(out), checker.Not(checker.Equals), "") 296 297 container := strings.TrimSpace(out) 298 299 out, err = d.Cmd("exec", container, "id") 300 c.Assert(err, checker.IsNil) 301 c.Assert(strings.TrimSpace(out), checker.Equals, "uid=0(root) gid=0(root) groups=10(wheel),29(audio),50(staff),777") 302 } 303 304 func (s *DockerSwarmSuite) TestSwarmContainerAutoStart(c *check.C) { 305 d := s.AddDaemon(c, true, true) 306 307 out, err := d.Cmd("network", "create", "--attachable", "-d", "overlay", "foo") 308 c.Assert(err, checker.IsNil) 309 c.Assert(strings.TrimSpace(out), checker.Not(checker.Equals), "") 310 311 out, err = d.Cmd("run", "-id", "--restart=always", "--net=foo", "--name=test", "busybox", "top") 312 c.Assert(err, checker.IsNil, check.Commentf(out)) 313 c.Assert(strings.TrimSpace(out), checker.Not(checker.Equals), "") 314 315 out, err = d.Cmd("ps", "-q") 316 c.Assert(err, checker.IsNil, check.Commentf(out)) 317 c.Assert(strings.TrimSpace(out), checker.Not(checker.Equals), "") 318 319 d.Restart() 320 321 out, err = d.Cmd("ps", "-q") 322 c.Assert(err, checker.IsNil, check.Commentf(out)) 323 c.Assert(strings.TrimSpace(out), checker.Not(checker.Equals), "") 324 } 325 326 func (s *DockerSwarmSuite) TestSwarmContainerEndpointOptions(c *check.C) { 327 d := s.AddDaemon(c, true, true) 328 329 out, err := d.Cmd("network", "create", "--attachable", "-d", "overlay", "foo") 330 c.Assert(err, checker.IsNil, check.Commentf(out)) 331 c.Assert(strings.TrimSpace(out), checker.Not(checker.Equals), "") 332 333 _, err = d.Cmd("run", "-d", "--net=foo", "--name=first", "--net-alias=first-alias", "busybox", "top") 334 c.Assert(err, checker.IsNil, check.Commentf(out)) 335 336 _, err = d.Cmd("run", "-d", "--net=foo", "--name=second", "busybox", "top") 337 c.Assert(err, checker.IsNil, check.Commentf(out)) 338 339 // ping first container and its alias 340 _, err = d.Cmd("exec", "second", "ping", "-c", "1", "first") 341 c.Assert(err, check.IsNil, check.Commentf(out)) 342 _, err = d.Cmd("exec", "second", "ping", "-c", "1", "first-alias") 343 c.Assert(err, check.IsNil, check.Commentf(out)) 344 } 345 346 func (s *DockerSwarmSuite) TestSwarmContainerAttachByNetworkId(c *check.C) { 347 d := s.AddDaemon(c, true, true) 348 349 out, err := d.Cmd("network", "create", "--attachable", "-d", "overlay", "testnet") 350 c.Assert(err, checker.IsNil) 351 c.Assert(strings.TrimSpace(out), checker.Not(checker.Equals), "") 352 networkID := strings.TrimSpace(out) 353 354 out, err = d.Cmd("run", "-d", "--net", networkID, "busybox", "top") 355 c.Assert(err, checker.IsNil) 356 cID := strings.TrimSpace(out) 357 d.waitRun(cID) 358 359 _, err = d.Cmd("rm", "-f", cID) 360 c.Assert(err, checker.IsNil) 361 362 out, err = d.Cmd("network", "rm", "testnet") 363 c.Assert(err, checker.IsNil) 364 365 checkNetwork := func(*check.C) (interface{}, check.CommentInterface) { 366 out, err := d.Cmd("network", "ls") 367 c.Assert(err, checker.IsNil) 368 return out, nil 369 } 370 371 waitAndAssert(c, 3*time.Second, checkNetwork, checker.Not(checker.Contains), "testnet") 372 } 373 374 func (s *DockerSwarmSuite) TestOverlayAttachable(c *check.C) { 375 d := s.AddDaemon(c, true, true) 376 377 out, err := d.Cmd("network", "create", "-d", "overlay", "--attachable", "ovnet") 378 c.Assert(err, checker.IsNil, check.Commentf(out)) 379 380 // validate attachable 381 out, err = d.Cmd("network", "inspect", "--format", "{{json .Attachable}}", "ovnet") 382 c.Assert(err, checker.IsNil, check.Commentf(out)) 383 c.Assert(strings.TrimSpace(out), checker.Equals, "true") 384 385 // validate containers can attache to this overlay network 386 out, err = d.Cmd("run", "-d", "--network", "ovnet", "--name", "c1", "busybox", "top") 387 c.Assert(err, checker.IsNil, check.Commentf(out)) 388 389 // redo validation, there was a bug that the value of attachable changes after 390 // containers attach to the network 391 out, err = d.Cmd("network", "inspect", "--format", "{{json .Attachable}}", "ovnet") 392 c.Assert(err, checker.IsNil, check.Commentf(out)) 393 c.Assert(strings.TrimSpace(out), checker.Equals, "true") 394 } 395 396 func (s *DockerSwarmSuite) TestOverlayAttachableOnSwarmLeave(c *check.C) { 397 d := s.AddDaemon(c, true, true) 398 399 // Create an attachable swarm network 400 nwName := "attovl" 401 out, err := d.Cmd("network", "create", "-d", "overlay", "--attachable", nwName) 402 c.Assert(err, checker.IsNil, check.Commentf(out)) 403 404 // Connect a container to the network 405 out, err = d.Cmd("run", "-d", "--network", nwName, "--name", "c1", "busybox", "top") 406 c.Assert(err, checker.IsNil, check.Commentf(out)) 407 408 // Leave the swarm 409 err = d.Leave(true) 410 c.Assert(err, checker.IsNil) 411 412 // Check the container is disconnected 413 out, err = d.Cmd("inspect", "c1", "--format", "{{.NetworkSettings.Networks."+nwName+"}}") 414 c.Assert(err, checker.IsNil) 415 c.Assert(strings.TrimSpace(out), checker.Equals, "<no value>") 416 417 // Check the network is gone 418 out, err = d.Cmd("network", "ls", "--format", "{{.Name}}") 419 c.Assert(err, checker.IsNil) 420 c.Assert(out, checker.Not(checker.Contains), nwName) 421 } 422 423 func (s *DockerSwarmSuite) TestOverlayAttachableReleaseResourcesOnFailure(c *check.C) { 424 d := s.AddDaemon(c, true, true) 425 426 // Create attachable network 427 out, err := d.Cmd("network", "create", "-d", "overlay", "--attachable", "--subnet", "10.10.9.0/24", "ovnet") 428 c.Assert(err, checker.IsNil, check.Commentf(out)) 429 430 // Attach a container with specific IP 431 out, err = d.Cmd("run", "-d", "--network", "ovnet", "--name", "c1", "--ip", "10.10.9.33", "busybox", "top") 432 c.Assert(err, checker.IsNil, check.Commentf(out)) 433 434 // Attempt to attach another contianer with same IP, must fail 435 _, err = d.Cmd("run", "-d", "--network", "ovnet", "--name", "c2", "--ip", "10.10.9.33", "busybox", "top") 436 c.Assert(err, checker.NotNil) 437 438 // Remove first container 439 out, err = d.Cmd("rm", "-f", "c1") 440 c.Assert(err, checker.IsNil, check.Commentf(out)) 441 442 // Verify the network can be removed, no phantom network attachment task left over 443 out, err = d.Cmd("network", "rm", "ovnet") 444 c.Assert(err, checker.IsNil, check.Commentf(out)) 445 } 446 447 func (s *DockerSwarmSuite) TestSwarmRemoveInternalNetwork(c *check.C) { 448 d := s.AddDaemon(c, true, true) 449 450 name := "ingress" 451 out, err := d.Cmd("network", "rm", name) 452 c.Assert(err, checker.NotNil) 453 c.Assert(strings.TrimSpace(out), checker.Contains, name) 454 c.Assert(strings.TrimSpace(out), checker.Contains, "is a pre-defined network and cannot be removed") 455 } 456 457 // Test case for #24108, also the case from: 458 // https://github.com/docker/docker/pull/24620#issuecomment-233715656 459 func (s *DockerSwarmSuite) TestSwarmTaskListFilter(c *check.C) { 460 d := s.AddDaemon(c, true, true) 461 462 name := "redis-cluster-md5" 463 out, err := d.Cmd("service", "create", "--name", name, "--replicas=3", "busybox", "top") 464 c.Assert(err, checker.IsNil) 465 c.Assert(strings.TrimSpace(out), checker.Not(checker.Equals), "") 466 467 filter := "name=redis-cluster" 468 469 checkNumTasks := func(*check.C) (interface{}, check.CommentInterface) { 470 out, err := d.Cmd("service", "ps", "--filter", filter, name) 471 c.Assert(err, checker.IsNil) 472 return len(strings.Split(out, "\n")) - 2, nil // includes header and nl in last line 473 } 474 475 // wait until all tasks have been created 476 waitAndAssert(c, defaultReconciliationTimeout, checkNumTasks, checker.Equals, 3) 477 478 out, err = d.Cmd("service", "ps", "--filter", filter, name) 479 c.Assert(err, checker.IsNil) 480 c.Assert(out, checker.Contains, name+".1") 481 c.Assert(out, checker.Contains, name+".2") 482 c.Assert(out, checker.Contains, name+".3") 483 484 out, err = d.Cmd("service", "ps", "--filter", "name="+name+".1", name) 485 c.Assert(err, checker.IsNil) 486 c.Assert(out, checker.Contains, name+".1") 487 c.Assert(out, checker.Not(checker.Contains), name+".2") 488 c.Assert(out, checker.Not(checker.Contains), name+".3") 489 490 out, err = d.Cmd("service", "ps", "--filter", "name=none", name) 491 c.Assert(err, checker.IsNil) 492 c.Assert(out, checker.Not(checker.Contains), name+".1") 493 c.Assert(out, checker.Not(checker.Contains), name+".2") 494 c.Assert(out, checker.Not(checker.Contains), name+".3") 495 496 name = "redis-cluster-sha1" 497 out, err = d.Cmd("service", "create", "--name", name, "--mode=global", "busybox", "top") 498 c.Assert(err, checker.IsNil) 499 c.Assert(strings.TrimSpace(out), checker.Not(checker.Equals), "") 500 501 waitAndAssert(c, defaultReconciliationTimeout, checkNumTasks, checker.Equals, 1) 502 503 filter = "name=redis-cluster" 504 out, err = d.Cmd("service", "ps", "--filter", filter, name) 505 c.Assert(err, checker.IsNil) 506 c.Assert(out, checker.Contains, name) 507 508 out, err = d.Cmd("service", "ps", "--filter", "name="+name, name) 509 c.Assert(err, checker.IsNil) 510 c.Assert(out, checker.Contains, name) 511 512 out, err = d.Cmd("service", "ps", "--filter", "name=none", name) 513 c.Assert(err, checker.IsNil) 514 c.Assert(out, checker.Not(checker.Contains), name) 515 } 516 517 func (s *DockerSwarmSuite) TestPsListContainersFilterIsTask(c *check.C) { 518 d := s.AddDaemon(c, true, true) 519 520 // Create a bare container 521 out, err := d.Cmd("run", "-d", "--name=bare-container", "busybox", "top") 522 c.Assert(err, checker.IsNil) 523 bareID := strings.TrimSpace(out)[:12] 524 // Create a service 525 name := "busybox-top" 526 out, err = d.Cmd("service", "create", "--name", name, "busybox", "top") 527 c.Assert(err, checker.IsNil) 528 c.Assert(strings.TrimSpace(out), checker.Not(checker.Equals), "") 529 530 // make sure task has been deployed. 531 waitAndAssert(c, defaultReconciliationTimeout, d.checkServiceRunningTasks(name), checker.Equals, 1) 532 533 // Filter non-tasks 534 out, err = d.Cmd("ps", "-a", "-q", "--filter=is-task=false") 535 c.Assert(err, checker.IsNil) 536 psOut := strings.TrimSpace(out) 537 c.Assert(psOut, checker.Equals, bareID, check.Commentf("Expected id %s, got %s for is-task label, output %q", bareID, psOut, out)) 538 539 // Filter tasks 540 out, err = d.Cmd("ps", "-a", "-q", "--filter=is-task=true") 541 c.Assert(err, checker.IsNil) 542 lines := strings.Split(strings.Trim(out, "\n "), "\n") 543 c.Assert(lines, checker.HasLen, 1) 544 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)) 545 } 546 547 const globalNetworkPlugin = "global-network-plugin" 548 const globalIPAMPlugin = "global-ipam-plugin" 549 550 func setupRemoteGlobalNetworkPlugin(c *check.C, mux *http.ServeMux, url, netDrv, ipamDrv string) { 551 552 mux.HandleFunc("/Plugin.Activate", func(w http.ResponseWriter, r *http.Request) { 553 w.Header().Set("Content-Type", "application/vnd.docker.plugins.v1+json") 554 fmt.Fprintf(w, `{"Implements": ["%s", "%s"]}`, driverapi.NetworkPluginEndpointType, ipamapi.PluginEndpointType) 555 }) 556 557 // Network driver implementation 558 mux.HandleFunc(fmt.Sprintf("/%s.GetCapabilities", driverapi.NetworkPluginEndpointType), func(w http.ResponseWriter, r *http.Request) { 559 w.Header().Set("Content-Type", "application/vnd.docker.plugins.v1+json") 560 fmt.Fprintf(w, `{"Scope":"global"}`) 561 }) 562 563 mux.HandleFunc(fmt.Sprintf("/%s.AllocateNetwork", driverapi.NetworkPluginEndpointType), func(w http.ResponseWriter, r *http.Request) { 564 err := json.NewDecoder(r.Body).Decode(&remoteDriverNetworkRequest) 565 if err != nil { 566 http.Error(w, "Unable to decode JSON payload: "+err.Error(), http.StatusBadRequest) 567 return 568 } 569 w.Header().Set("Content-Type", "application/vnd.docker.plugins.v1+json") 570 fmt.Fprintf(w, "null") 571 }) 572 573 mux.HandleFunc(fmt.Sprintf("/%s.FreeNetwork", driverapi.NetworkPluginEndpointType), func(w http.ResponseWriter, r *http.Request) { 574 w.Header().Set("Content-Type", "application/vnd.docker.plugins.v1+json") 575 fmt.Fprintf(w, "null") 576 }) 577 578 mux.HandleFunc(fmt.Sprintf("/%s.CreateNetwork", driverapi.NetworkPluginEndpointType), func(w http.ResponseWriter, r *http.Request) { 579 err := json.NewDecoder(r.Body).Decode(&remoteDriverNetworkRequest) 580 if err != nil { 581 http.Error(w, "Unable to decode JSON payload: "+err.Error(), http.StatusBadRequest) 582 return 583 } 584 w.Header().Set("Content-Type", "application/vnd.docker.plugins.v1+json") 585 fmt.Fprintf(w, "null") 586 }) 587 588 mux.HandleFunc(fmt.Sprintf("/%s.DeleteNetwork", driverapi.NetworkPluginEndpointType), func(w http.ResponseWriter, r *http.Request) { 589 w.Header().Set("Content-Type", "application/vnd.docker.plugins.v1+json") 590 fmt.Fprintf(w, "null") 591 }) 592 593 mux.HandleFunc(fmt.Sprintf("/%s.CreateEndpoint", driverapi.NetworkPluginEndpointType), func(w http.ResponseWriter, r *http.Request) { 594 w.Header().Set("Content-Type", "application/vnd.docker.plugins.v1+json") 595 fmt.Fprintf(w, `{"Interface":{"MacAddress":"a0:b1:c2:d3:e4:f5"}}`) 596 }) 597 598 mux.HandleFunc(fmt.Sprintf("/%s.Join", driverapi.NetworkPluginEndpointType), func(w http.ResponseWriter, r *http.Request) { 599 w.Header().Set("Content-Type", "application/vnd.docker.plugins.v1+json") 600 601 veth := &netlink.Veth{ 602 LinkAttrs: netlink.LinkAttrs{Name: "randomIfName", TxQLen: 0}, PeerName: "cnt0"} 603 if err := netlink.LinkAdd(veth); err != nil { 604 fmt.Fprintf(w, `{"Error":"failed to add veth pair: `+err.Error()+`"}`) 605 } else { 606 fmt.Fprintf(w, `{"InterfaceName":{ "SrcName":"cnt0", "DstPrefix":"veth"}}`) 607 } 608 }) 609 610 mux.HandleFunc(fmt.Sprintf("/%s.Leave", driverapi.NetworkPluginEndpointType), func(w http.ResponseWriter, r *http.Request) { 611 w.Header().Set("Content-Type", "application/vnd.docker.plugins.v1+json") 612 fmt.Fprintf(w, "null") 613 }) 614 615 mux.HandleFunc(fmt.Sprintf("/%s.DeleteEndpoint", driverapi.NetworkPluginEndpointType), func(w http.ResponseWriter, r *http.Request) { 616 w.Header().Set("Content-Type", "application/vnd.docker.plugins.v1+json") 617 if link, err := netlink.LinkByName("cnt0"); err == nil { 618 netlink.LinkDel(link) 619 } 620 fmt.Fprintf(w, "null") 621 }) 622 623 // IPAM Driver implementation 624 var ( 625 poolRequest remoteipam.RequestPoolRequest 626 poolReleaseReq remoteipam.ReleasePoolRequest 627 addressRequest remoteipam.RequestAddressRequest 628 addressReleaseReq remoteipam.ReleaseAddressRequest 629 lAS = "localAS" 630 gAS = "globalAS" 631 pool = "172.28.0.0/16" 632 poolID = lAS + "/" + pool 633 gw = "172.28.255.254/16" 634 ) 635 636 mux.HandleFunc(fmt.Sprintf("/%s.GetDefaultAddressSpaces", ipamapi.PluginEndpointType), func(w http.ResponseWriter, r *http.Request) { 637 w.Header().Set("Content-Type", "application/vnd.docker.plugins.v1+json") 638 fmt.Fprintf(w, `{"LocalDefaultAddressSpace":"`+lAS+`", "GlobalDefaultAddressSpace": "`+gAS+`"}`) 639 }) 640 641 mux.HandleFunc(fmt.Sprintf("/%s.RequestPool", ipamapi.PluginEndpointType), func(w http.ResponseWriter, r *http.Request) { 642 err := json.NewDecoder(r.Body).Decode(&poolRequest) 643 if err != nil { 644 http.Error(w, "Unable to decode JSON payload: "+err.Error(), http.StatusBadRequest) 645 return 646 } 647 w.Header().Set("Content-Type", "application/vnd.docker.plugins.v1+json") 648 if poolRequest.AddressSpace != lAS && poolRequest.AddressSpace != gAS { 649 fmt.Fprintf(w, `{"Error":"Unknown address space in pool request: `+poolRequest.AddressSpace+`"}`) 650 } else if poolRequest.Pool != "" && poolRequest.Pool != pool { 651 fmt.Fprintf(w, `{"Error":"Cannot handle explicit pool requests yet"}`) 652 } else { 653 fmt.Fprintf(w, `{"PoolID":"`+poolID+`", "Pool":"`+pool+`"}`) 654 } 655 }) 656 657 mux.HandleFunc(fmt.Sprintf("/%s.RequestAddress", ipamapi.PluginEndpointType), func(w http.ResponseWriter, r *http.Request) { 658 err := json.NewDecoder(r.Body).Decode(&addressRequest) 659 if err != nil { 660 http.Error(w, "Unable to decode JSON payload: "+err.Error(), http.StatusBadRequest) 661 return 662 } 663 w.Header().Set("Content-Type", "application/vnd.docker.plugins.v1+json") 664 // make sure libnetwork is now querying on the expected pool id 665 if addressRequest.PoolID != poolID { 666 fmt.Fprintf(w, `{"Error":"unknown pool id"}`) 667 } else if addressRequest.Address != "" { 668 fmt.Fprintf(w, `{"Error":"Cannot handle explicit address requests yet"}`) 669 } else { 670 fmt.Fprintf(w, `{"Address":"`+gw+`"}`) 671 } 672 }) 673 674 mux.HandleFunc(fmt.Sprintf("/%s.ReleaseAddress", ipamapi.PluginEndpointType), func(w http.ResponseWriter, r *http.Request) { 675 err := json.NewDecoder(r.Body).Decode(&addressReleaseReq) 676 if err != nil { 677 http.Error(w, "Unable to decode JSON payload: "+err.Error(), http.StatusBadRequest) 678 return 679 } 680 w.Header().Set("Content-Type", "application/vnd.docker.plugins.v1+json") 681 // make sure libnetwork is now asking to release the expected address from the expected poolid 682 if addressRequest.PoolID != poolID { 683 fmt.Fprintf(w, `{"Error":"unknown pool id"}`) 684 } else if addressReleaseReq.Address != gw { 685 fmt.Fprintf(w, `{"Error":"unknown address"}`) 686 } else { 687 fmt.Fprintf(w, "null") 688 } 689 }) 690 691 mux.HandleFunc(fmt.Sprintf("/%s.ReleasePool", ipamapi.PluginEndpointType), func(w http.ResponseWriter, r *http.Request) { 692 err := json.NewDecoder(r.Body).Decode(&poolReleaseReq) 693 if err != nil { 694 http.Error(w, "Unable to decode JSON payload: "+err.Error(), http.StatusBadRequest) 695 return 696 } 697 w.Header().Set("Content-Type", "application/vnd.docker.plugins.v1+json") 698 // make sure libnetwork is now asking to release the expected poolid 699 if addressRequest.PoolID != poolID { 700 fmt.Fprintf(w, `{"Error":"unknown pool id"}`) 701 } else { 702 fmt.Fprintf(w, "null") 703 } 704 }) 705 706 err := os.MkdirAll("/etc/docker/plugins", 0755) 707 c.Assert(err, checker.IsNil) 708 709 fileName := fmt.Sprintf("/etc/docker/plugins/%s.spec", netDrv) 710 err = ioutil.WriteFile(fileName, []byte(url), 0644) 711 c.Assert(err, checker.IsNil) 712 713 ipamFileName := fmt.Sprintf("/etc/docker/plugins/%s.spec", ipamDrv) 714 err = ioutil.WriteFile(ipamFileName, []byte(url), 0644) 715 c.Assert(err, checker.IsNil) 716 } 717 718 func (s *DockerSwarmSuite) TestSwarmNetworkPlugin(c *check.C) { 719 mux := http.NewServeMux() 720 s.server = httptest.NewServer(mux) 721 c.Assert(s.server, check.NotNil, check.Commentf("Failed to start an HTTP Server")) 722 setupRemoteGlobalNetworkPlugin(c, mux, s.server.URL, globalNetworkPlugin, globalIPAMPlugin) 723 defer func() { 724 s.server.Close() 725 err := os.RemoveAll("/etc/docker/plugins") 726 c.Assert(err, checker.IsNil) 727 }() 728 729 d := s.AddDaemon(c, true, true) 730 731 out, err := d.Cmd("network", "create", "-d", globalNetworkPlugin, "foo") 732 c.Assert(err, checker.NotNil) 733 c.Assert(out, checker.Contains, "not supported in swarm mode") 734 } 735 736 // Test case for #24712 737 func (s *DockerSwarmSuite) TestSwarmServiceEnvFile(c *check.C) { 738 d := s.AddDaemon(c, true, true) 739 740 path := filepath.Join(d.folder, "env.txt") 741 err := ioutil.WriteFile(path, []byte("VAR1=A\nVAR2=A\n"), 0644) 742 c.Assert(err, checker.IsNil) 743 744 name := "worker" 745 out, err := d.Cmd("service", "create", "--env-file", path, "--env", "VAR1=B", "--env", "VAR1=C", "--env", "VAR2=", "--env", "VAR2", "--name", name, "busybox", "top") 746 c.Assert(err, checker.IsNil) 747 c.Assert(strings.TrimSpace(out), checker.Not(checker.Equals), "") 748 749 // The complete env is [VAR1=A VAR2=A VAR1=B VAR1=C VAR2= VAR2] and duplicates will be removed => [VAR1=C VAR2] 750 out, err = d.Cmd("inspect", "--format", "{{ .Spec.TaskTemplate.ContainerSpec.Env }}", name) 751 c.Assert(err, checker.IsNil) 752 c.Assert(out, checker.Contains, "[VAR1=C VAR2]") 753 } 754 755 func (s *DockerSwarmSuite) TestSwarmServiceTTY(c *check.C) { 756 d := s.AddDaemon(c, true, true) 757 758 name := "top" 759 760 ttyCheck := "if [ -t 0 ]; then echo TTY > /status && top; else echo none > /status && top; fi" 761 762 // Without --tty 763 expectedOutput := "none" 764 out, err := d.Cmd("service", "create", "--name", name, "busybox", "sh", "-c", ttyCheck) 765 c.Assert(err, checker.IsNil) 766 767 // Make sure task has been deployed. 768 waitAndAssert(c, defaultReconciliationTimeout, d.checkActiveContainerCount, checker.Equals, 1) 769 770 // We need to get the container id. 771 out, err = d.Cmd("ps", "-a", "-q", "--no-trunc") 772 c.Assert(err, checker.IsNil) 773 id := strings.TrimSpace(out) 774 775 out, err = d.Cmd("exec", id, "cat", "/status") 776 c.Assert(err, checker.IsNil) 777 c.Assert(out, checker.Contains, expectedOutput, check.Commentf("Expected '%s', but got %q", expectedOutput, out)) 778 779 // Remove service 780 out, err = d.Cmd("service", "rm", name) 781 c.Assert(err, checker.IsNil) 782 // Make sure container has been destroyed. 783 waitAndAssert(c, defaultReconciliationTimeout, d.checkActiveContainerCount, checker.Equals, 0) 784 785 // With --tty 786 expectedOutput = "TTY" 787 out, err = d.Cmd("service", "create", "--name", name, "--tty", "busybox", "sh", "-c", ttyCheck) 788 c.Assert(err, checker.IsNil) 789 790 // Make sure task has been deployed. 791 waitAndAssert(c, defaultReconciliationTimeout, d.checkActiveContainerCount, checker.Equals, 1) 792 793 // We need to get the container id. 794 out, err = d.Cmd("ps", "-a", "-q", "--no-trunc") 795 c.Assert(err, checker.IsNil) 796 id = strings.TrimSpace(out) 797 798 out, err = d.Cmd("exec", id, "cat", "/status") 799 c.Assert(err, checker.IsNil) 800 c.Assert(out, checker.Contains, expectedOutput, check.Commentf("Expected '%s', but got %q", expectedOutput, out)) 801 } 802 803 func (s *DockerSwarmSuite) TestSwarmServiceTTYUpdate(c *check.C) { 804 d := s.AddDaemon(c, true, true) 805 806 // Create a service 807 name := "top" 808 _, err := d.Cmd("service", "create", "--name", name, "busybox", "top") 809 c.Assert(err, checker.IsNil) 810 811 // Make sure task has been deployed. 812 waitAndAssert(c, defaultReconciliationTimeout, d.checkActiveContainerCount, checker.Equals, 1) 813 814 out, err := d.Cmd("service", "inspect", "--format", "{{ .Spec.TaskTemplate.ContainerSpec.TTY }}", name) 815 c.Assert(err, checker.IsNil) 816 c.Assert(strings.TrimSpace(out), checker.Equals, "false") 817 818 _, err = d.Cmd("service", "update", "--tty", name) 819 c.Assert(err, checker.IsNil) 820 821 out, err = d.Cmd("service", "inspect", "--format", "{{ .Spec.TaskTemplate.ContainerSpec.TTY }}", name) 822 c.Assert(err, checker.IsNil) 823 c.Assert(strings.TrimSpace(out), checker.Equals, "true") 824 } 825 826 func (s *DockerSwarmSuite) TestDNSConfig(c *check.C) { 827 d := s.AddDaemon(c, true, true) 828 829 // Create a service 830 name := "top" 831 _, err := d.Cmd("service", "create", "--name", name, "--dns=1.2.3.4", "--dns-search=example.com", "--dns-option=timeout:3", "busybox", "top") 832 c.Assert(err, checker.IsNil) 833 834 // Make sure task has been deployed. 835 waitAndAssert(c, defaultReconciliationTimeout, d.checkActiveContainerCount, checker.Equals, 1) 836 837 // We need to get the container id. 838 out, err := d.Cmd("ps", "-a", "-q", "--no-trunc") 839 c.Assert(err, checker.IsNil) 840 id := strings.TrimSpace(out) 841 842 // Compare against expected output. 843 expectedOutput1 := "nameserver 1.2.3.4" 844 expectedOutput2 := "search example.com" 845 expectedOutput3 := "options timeout:3" 846 out, err = d.Cmd("exec", id, "cat", "/etc/resolv.conf") 847 c.Assert(err, checker.IsNil) 848 c.Assert(out, checker.Contains, expectedOutput1, check.Commentf("Expected '%s', but got %q", expectedOutput1, out)) 849 c.Assert(out, checker.Contains, expectedOutput2, check.Commentf("Expected '%s', but got %q", expectedOutput2, out)) 850 c.Assert(out, checker.Contains, expectedOutput3, check.Commentf("Expected '%s', but got %q", expectedOutput3, out)) 851 } 852 853 func (s *DockerSwarmSuite) TestDNSConfigUpdate(c *check.C) { 854 d := s.AddDaemon(c, true, true) 855 856 // Create a service 857 name := "top" 858 _, err := d.Cmd("service", "create", "--name", name, "busybox", "top") 859 c.Assert(err, checker.IsNil) 860 861 // Make sure task has been deployed. 862 waitAndAssert(c, defaultReconciliationTimeout, d.checkActiveContainerCount, checker.Equals, 1) 863 864 _, err = d.Cmd("service", "update", "--dns-add=1.2.3.4", "--dns-search-add=example.com", "--dns-option-add=timeout:3", name) 865 c.Assert(err, checker.IsNil) 866 867 out, err := d.Cmd("service", "inspect", "--format", "{{ .Spec.TaskTemplate.ContainerSpec.DNSConfig }}", name) 868 c.Assert(err, checker.IsNil) 869 c.Assert(strings.TrimSpace(out), checker.Equals, "{[1.2.3.4] [example.com] [timeout:3]}") 870 } 871 872 func (s *DockerSwarmSuite) TestSwarmInitLocked(c *check.C) { 873 d := s.AddDaemon(c, false, false) 874 875 outs, err := d.Cmd("swarm", "init", "--autolock") 876 c.Assert(err, checker.IsNil, check.Commentf("out: %v", outs)) 877 878 c.Assert(outs, checker.Contains, "docker swarm unlock") 879 880 var unlockKey string 881 for _, line := range strings.Split(outs, "\n") { 882 if strings.Contains(line, "SWMKEY") { 883 unlockKey = strings.TrimSpace(line) 884 break 885 } 886 } 887 888 c.Assert(unlockKey, checker.Not(checker.Equals), "") 889 890 outs, err = d.Cmd("swarm", "unlock-key", "-q") 891 c.Assert(outs, checker.Equals, unlockKey+"\n") 892 893 info, err := d.info() 894 c.Assert(err, checker.IsNil) 895 c.Assert(info.LocalNodeState, checker.Equals, swarm.LocalNodeStateActive) 896 897 c.Assert(d.Restart(), checker.IsNil) 898 899 info, err = d.info() 900 c.Assert(err, checker.IsNil) 901 c.Assert(info.LocalNodeState, checker.Equals, swarm.LocalNodeStateLocked) 902 903 cmd := d.command("swarm", "unlock") 904 cmd.Stdin = bytes.NewBufferString("wrong-secret-key") 905 out, err := cmd.CombinedOutput() 906 c.Assert(err, checker.NotNil, check.Commentf("out: %v", string(out))) 907 c.Assert(string(out), checker.Contains, "invalid key") 908 909 cmd = d.command("swarm", "unlock") 910 cmd.Stdin = bytes.NewBufferString(unlockKey) 911 out, err = cmd.CombinedOutput() 912 c.Assert(err, checker.IsNil, check.Commentf("out: %v", string(out))) 913 914 info, err = d.info() 915 c.Assert(err, checker.IsNil) 916 c.Assert(info.LocalNodeState, checker.Equals, swarm.LocalNodeStateActive) 917 918 outs, err = d.Cmd("node", "ls") 919 c.Assert(err, checker.IsNil) 920 c.Assert(outs, checker.Not(checker.Contains), "Swarm is encrypted and needs to be unlocked") 921 922 outs, err = d.Cmd("swarm", "update", "--autolock=false") 923 c.Assert(err, checker.IsNil, check.Commentf("out: %v", outs)) 924 925 // Wait for autolock to be turned off 926 time.Sleep(time.Second) 927 928 c.Assert(d.Restart(), checker.IsNil) 929 930 info, err = d.info() 931 c.Assert(err, checker.IsNil) 932 c.Assert(info.LocalNodeState, checker.Equals, swarm.LocalNodeStateActive) 933 934 outs, err = d.Cmd("node", "ls") 935 c.Assert(err, checker.IsNil) 936 c.Assert(outs, checker.Not(checker.Contains), "Swarm is encrypted and needs to be unlocked") 937 } 938 939 func (s *DockerSwarmSuite) TestSwarmLeaveLocked(c *check.C) { 940 d := s.AddDaemon(c, false, false) 941 942 outs, err := d.Cmd("swarm", "init", "--autolock") 943 c.Assert(err, checker.IsNil, check.Commentf("out: %v", outs)) 944 945 c.Assert(d.Restart("--swarm-default-advertise-addr=lo"), checker.IsNil) 946 947 info, err := d.info() 948 c.Assert(err, checker.IsNil) 949 c.Assert(info.LocalNodeState, checker.Equals, swarm.LocalNodeStateLocked) 950 951 outs, _ = d.Cmd("node", "ls") 952 c.Assert(outs, checker.Contains, "Swarm is encrypted and needs to be unlocked") 953 954 outs, err = d.Cmd("swarm", "leave", "--force") 955 c.Assert(err, checker.IsNil, check.Commentf("out: %v", outs)) 956 957 info, err = d.info() 958 c.Assert(err, checker.IsNil) 959 c.Assert(info.LocalNodeState, checker.Equals, swarm.LocalNodeStateInactive) 960 961 outs, err = d.Cmd("swarm", "init") 962 c.Assert(err, checker.IsNil, check.Commentf("out: %v", outs)) 963 964 info, err = d.info() 965 c.Assert(err, checker.IsNil) 966 c.Assert(info.LocalNodeState, checker.Equals, swarm.LocalNodeStateActive) 967 } 968 969 func (s *DockerSwarmSuite) TestSwarmRotateUnlockKey(c *check.C) { 970 d := s.AddDaemon(c, true, true) 971 972 outs, err := d.Cmd("swarm", "update", "--autolock") 973 c.Assert(err, checker.IsNil, check.Commentf("out: %v", outs)) 974 975 c.Assert(outs, checker.Contains, "docker swarm unlock") 976 977 var unlockKey string 978 for _, line := range strings.Split(outs, "\n") { 979 if strings.Contains(line, "SWMKEY") { 980 unlockKey = strings.TrimSpace(line) 981 break 982 } 983 } 984 985 c.Assert(unlockKey, checker.Not(checker.Equals), "") 986 987 outs, err = d.Cmd("swarm", "unlock-key", "-q") 988 c.Assert(outs, checker.Equals, unlockKey+"\n") 989 990 // Rotate multiple times 991 for i := 0; i != 3; i++ { 992 outs, err = d.Cmd("swarm", "unlock-key", "-q", "--rotate") 993 c.Assert(err, checker.IsNil, check.Commentf("out: %v", outs)) 994 // Strip \n 995 newUnlockKey := outs[:len(outs)-1] 996 c.Assert(newUnlockKey, checker.Not(checker.Equals), "") 997 c.Assert(newUnlockKey, checker.Not(checker.Equals), unlockKey) 998 999 c.Assert(d.Restart(), checker.IsNil) 1000 1001 info, err := d.info() 1002 c.Assert(err, checker.IsNil) 1003 c.Assert(info.LocalNodeState, checker.Equals, swarm.LocalNodeStateLocked) 1004 1005 outs, _ = d.Cmd("node", "ls") 1006 c.Assert(outs, checker.Contains, "Swarm is encrypted and needs to be unlocked") 1007 1008 cmd := d.command("swarm", "unlock") 1009 cmd.Stdin = bytes.NewBufferString(unlockKey) 1010 out, err := cmd.CombinedOutput() 1011 1012 if err == nil { 1013 // On occasion, the daemon may not have finished 1014 // rotating the KEK before restarting. The test is 1015 // intentionally written to explore this behavior. 1016 // When this happens, unlocking with the old key will 1017 // succeed. If we wait for the rotation to happen and 1018 // restart again, the new key should be required this 1019 // time. 1020 1021 time.Sleep(3 * time.Second) 1022 1023 c.Assert(d.Restart(), checker.IsNil) 1024 1025 cmd = d.command("swarm", "unlock") 1026 cmd.Stdin = bytes.NewBufferString(unlockKey) 1027 out, err = cmd.CombinedOutput() 1028 } 1029 c.Assert(err, checker.NotNil, check.Commentf("out: %v", string(out))) 1030 c.Assert(string(out), checker.Contains, "invalid key") 1031 1032 outs, _ = d.Cmd("node", "ls") 1033 c.Assert(outs, checker.Contains, "Swarm is encrypted and needs to be unlocked") 1034 1035 cmd = d.command("swarm", "unlock") 1036 cmd.Stdin = bytes.NewBufferString(newUnlockKey) 1037 out, err = cmd.CombinedOutput() 1038 c.Assert(err, checker.IsNil, check.Commentf("out: %v", string(out))) 1039 1040 info, err = d.info() 1041 c.Assert(err, checker.IsNil) 1042 c.Assert(info.LocalNodeState, checker.Equals, swarm.LocalNodeStateActive) 1043 1044 outs, err = d.Cmd("node", "ls") 1045 c.Assert(err, checker.IsNil) 1046 c.Assert(outs, checker.Not(checker.Contains), "Swarm is encrypted and needs to be unlocked") 1047 1048 unlockKey = newUnlockKey 1049 } 1050 } 1051 1052 func (s *DockerSwarmSuite) TestExtraHosts(c *check.C) { 1053 d := s.AddDaemon(c, true, true) 1054 1055 // Create a service 1056 name := "top" 1057 _, err := d.Cmd("service", "create", "--name", name, "--host=example.com:1.2.3.4", "busybox", "top") 1058 c.Assert(err, checker.IsNil) 1059 1060 // Make sure task has been deployed. 1061 waitAndAssert(c, defaultReconciliationTimeout, d.checkActiveContainerCount, checker.Equals, 1) 1062 1063 // We need to get the container id. 1064 out, err := d.Cmd("ps", "-a", "-q", "--no-trunc") 1065 c.Assert(err, checker.IsNil) 1066 id := strings.TrimSpace(out) 1067 1068 // Compare against expected output. 1069 expectedOutput := "1.2.3.4\texample.com" 1070 out, err = d.Cmd("exec", id, "cat", "/etc/hosts") 1071 c.Assert(err, checker.IsNil) 1072 c.Assert(out, checker.Contains, expectedOutput, check.Commentf("Expected '%s', but got %q", expectedOutput, out)) 1073 } 1074 1075 func (s *DockerSwarmSuite) TestSwarmManagerAddress(c *check.C) { 1076 d1 := s.AddDaemon(c, true, true) 1077 d2 := s.AddDaemon(c, true, false) 1078 d3 := s.AddDaemon(c, true, false) 1079 1080 // Manager Addresses will always show Node 1's address 1081 expectedOutput := fmt.Sprintf("Manager Addresses:\n 127.0.0.1:%d\n", d1.port) 1082 1083 out, err := d1.Cmd("info") 1084 c.Assert(err, checker.IsNil) 1085 c.Assert(out, checker.Contains, expectedOutput) 1086 1087 out, err = d2.Cmd("info") 1088 c.Assert(err, checker.IsNil) 1089 c.Assert(out, checker.Contains, expectedOutput) 1090 1091 out, err = d3.Cmd("info") 1092 c.Assert(err, checker.IsNil) 1093 c.Assert(out, checker.Contains, expectedOutput) 1094 } 1095 1096 func (s *DockerSwarmSuite) TestSwarmServiceInspectPretty(c *check.C) { 1097 d := s.AddDaemon(c, true, true) 1098 1099 name := "top" 1100 out, err := d.Cmd("service", "create", "--name", name, "--limit-cpu=0.5", "busybox", "top") 1101 c.Assert(err, checker.IsNil, check.Commentf(out)) 1102 1103 expectedOutput := ` 1104 Resources: 1105 Limits: 1106 CPU: 0.5` 1107 out, err = d.Cmd("service", "inspect", "--pretty", name) 1108 c.Assert(err, checker.IsNil, check.Commentf(out)) 1109 c.Assert(out, checker.Contains, expectedOutput, check.Commentf(out)) 1110 } 1111 1112 func (s *DockerSwarmSuite) TestSwarmNetworkIPAMOptions(c *check.C) { 1113 d := s.AddDaemon(c, true, true) 1114 1115 out, err := d.Cmd("network", "create", "-d", "overlay", "--ipam-opt", "foo=bar", "foo") 1116 c.Assert(err, checker.IsNil, check.Commentf(out)) 1117 c.Assert(strings.TrimSpace(out), checker.Not(checker.Equals), "") 1118 1119 out, err = d.Cmd("network", "inspect", "--format", "{{.IPAM.Options}}", "foo") 1120 c.Assert(err, checker.IsNil, check.Commentf(out)) 1121 c.Assert(strings.TrimSpace(out), checker.Equals, "map[foo:bar]") 1122 1123 out, err = d.Cmd("service", "create", "--network=foo", "--name", "top", "busybox", "top") 1124 c.Assert(err, checker.IsNil, check.Commentf(out)) 1125 1126 // make sure task has been deployed. 1127 waitAndAssert(c, defaultReconciliationTimeout, d.checkActiveContainerCount, checker.Equals, 1) 1128 1129 out, err = d.Cmd("network", "inspect", "--format", "{{.IPAM.Options}}", "foo") 1130 c.Assert(err, checker.IsNil, check.Commentf(out)) 1131 c.Assert(strings.TrimSpace(out), checker.Equals, "map[foo:bar]") 1132 } 1133 1134 // TODO: migrate to a unit test 1135 // This test could be migrated to unit test and save costly integration test, 1136 // once PR #29143 is merged. 1137 func (s *DockerSwarmSuite) TestSwarmUpdateWithoutArgs(c *check.C) { 1138 d := s.AddDaemon(c, true, true) 1139 1140 expectedOutput := ` 1141 Usage: docker swarm update [OPTIONS] 1142 1143 Update the swarm 1144 1145 Options:` 1146 1147 out, err := d.Cmd("swarm", "update") 1148 c.Assert(err, checker.IsNil, check.Commentf("out: %v", out)) 1149 c.Assert(out, checker.Contains, expectedOutput, check.Commentf(out)) 1150 } 1151 1152 func (s *DockerTrustedSwarmSuite) TestTrustedServiceCreate(c *check.C) { 1153 d := s.swarmSuite.AddDaemon(c, true, true) 1154 1155 // Attempt creating a service from an image that is known to notary. 1156 repoName := s.trustSuite.setupTrustedImage(c, "trusted-pull") 1157 1158 name := "trusted" 1159 serviceCmd := d.command("-D", "service", "create", "--name", name, repoName, "top") 1160 s.trustSuite.trustedCmd(serviceCmd) 1161 out, _, err := runCommandWithOutput(serviceCmd) 1162 c.Assert(err, checker.IsNil, check.Commentf(out)) 1163 c.Assert(out, checker.Contains, "resolved image tag to", check.Commentf(out)) 1164 1165 out, err = d.Cmd("service", "inspect", "--pretty", name) 1166 c.Assert(err, checker.IsNil, check.Commentf(out)) 1167 c.Assert(out, checker.Contains, repoName+"@", check.Commentf(out)) 1168 1169 // Try trusted service create on an untrusted tag. 1170 1171 repoName = fmt.Sprintf("%v/untrustedservicecreate/createtest:latest", privateRegistryURL) 1172 // tag the image and upload it to the private registry 1173 dockerCmd(c, "tag", "busybox", repoName) 1174 dockerCmd(c, "push", repoName) 1175 dockerCmd(c, "rmi", repoName) 1176 1177 name = "untrusted" 1178 serviceCmd = d.command("service", "create", "--name", name, repoName, "top") 1179 s.trustSuite.trustedCmd(serviceCmd) 1180 out, _, err = runCommandWithOutput(serviceCmd) 1181 1182 c.Assert(err, check.NotNil, check.Commentf(out)) 1183 c.Assert(string(out), checker.Contains, "Error: remote trust data does not exist", check.Commentf(out)) 1184 1185 out, err = d.Cmd("service", "inspect", "--pretty", name) 1186 c.Assert(err, checker.NotNil, check.Commentf(out)) 1187 } 1188 1189 func (s *DockerTrustedSwarmSuite) TestTrustedServiceUpdate(c *check.C) { 1190 d := s.swarmSuite.AddDaemon(c, true, true) 1191 1192 // Attempt creating a service from an image that is known to notary. 1193 repoName := s.trustSuite.setupTrustedImage(c, "trusted-pull") 1194 1195 name := "myservice" 1196 1197 // Create a service without content trust 1198 _, err := d.Cmd("service", "create", "--name", name, repoName, "top") 1199 c.Assert(err, checker.IsNil) 1200 1201 out, err := d.Cmd("service", "inspect", "--pretty", name) 1202 c.Assert(err, checker.IsNil, check.Commentf(out)) 1203 // Daemon won't insert the digest because this is disabled by 1204 // DOCKER_SERVICE_PREFER_OFFLINE_IMAGE. 1205 c.Assert(out, check.Not(checker.Contains), repoName+"@", check.Commentf(out)) 1206 1207 serviceCmd := d.command("-D", "service", "update", "--image", repoName, name) 1208 s.trustSuite.trustedCmd(serviceCmd) 1209 out, _, err = runCommandWithOutput(serviceCmd) 1210 c.Assert(err, checker.IsNil, check.Commentf(out)) 1211 c.Assert(out, checker.Contains, "resolved image tag to", check.Commentf(out)) 1212 1213 out, err = d.Cmd("service", "inspect", "--pretty", name) 1214 c.Assert(err, checker.IsNil, check.Commentf(out)) 1215 c.Assert(out, checker.Contains, repoName+"@", check.Commentf(out)) 1216 1217 // Try trusted service update on an untrusted tag. 1218 1219 repoName = fmt.Sprintf("%v/untrustedservicecreate/createtest:latest", privateRegistryURL) 1220 // tag the image and upload it to the private registry 1221 dockerCmd(c, "tag", "busybox", repoName) 1222 dockerCmd(c, "push", repoName) 1223 dockerCmd(c, "rmi", repoName) 1224 1225 serviceCmd = d.command("service", "update", "--image", repoName, name) 1226 s.trustSuite.trustedCmd(serviceCmd) 1227 out, _, err = runCommandWithOutput(serviceCmd) 1228 1229 c.Assert(err, check.NotNil, check.Commentf(out)) 1230 c.Assert(string(out), checker.Contains, "Error: remote trust data does not exist", check.Commentf(out)) 1231 } 1232 1233 // Test case for issue #27866, which did not allow NW name that is the prefix of a swarm NW ID. 1234 // e.g. if the ingress ID starts with "n1", it was impossible to create a NW named "n1". 1235 func (s *DockerSwarmSuite) TestSwarmNetworkCreateIssue27866(c *check.C) { 1236 d := s.AddDaemon(c, true, true) 1237 out, err := d.Cmd("network", "inspect", "-f", "{{.Id}}", "ingress") 1238 c.Assert(err, checker.IsNil, check.Commentf("out: %v", out)) 1239 ingressID := strings.TrimSpace(out) 1240 c.Assert(ingressID, checker.Not(checker.Equals), "") 1241 1242 // create a network of which name is the prefix of the ID of an overlay network 1243 // (ingressID in this case) 1244 newNetName := ingressID[0:2] 1245 out, err = d.Cmd("network", "create", "--driver", "overlay", newNetName) 1246 // In #27866, it was failing because of "network with name %s already exists" 1247 c.Assert(err, checker.IsNil, check.Commentf("out: %v", out)) 1248 out, err = d.Cmd("network", "rm", newNetName) 1249 c.Assert(err, checker.IsNil, check.Commentf("out: %v", out)) 1250 } 1251 1252 // Test case for https://github.com/docker/docker/pull/27938#issuecomment-265768303 1253 // This test creates two networks with the same name sequentially, with various drivers. 1254 // Since the operations in this test are done sequentially, the 2nd call should fail with 1255 // "network with name FOO already exists". 1256 // Note that it is to ok have multiple networks with the same name if the operations are done 1257 // in parallel. (#18864) 1258 func (s *DockerSwarmSuite) TestSwarmNetworkCreateDup(c *check.C) { 1259 d := s.AddDaemon(c, true, true) 1260 drivers := []string{"bridge", "overlay"} 1261 for i, driver1 := range drivers { 1262 nwName := fmt.Sprintf("network-test-%d", i) 1263 for _, driver2 := range drivers { 1264 c.Logf("Creating a network named %q with %q, then %q", 1265 nwName, driver1, driver2) 1266 out, err := d.Cmd("network", "create", "--driver", driver1, nwName) 1267 c.Assert(err, checker.IsNil, check.Commentf("out: %v", out)) 1268 out, err = d.Cmd("network", "create", "--driver", driver2, nwName) 1269 c.Assert(out, checker.Contains, 1270 fmt.Sprintf("network with name %s already exists", nwName)) 1271 c.Assert(err, checker.NotNil) 1272 c.Logf("As expected, the attempt to network %q with %q failed: %s", 1273 nwName, driver2, out) 1274 out, err = d.Cmd("network", "rm", nwName) 1275 c.Assert(err, checker.IsNil, check.Commentf("out: %v", out)) 1276 } 1277 } 1278 }