github.com/brandon-bethke-neudesic/moby@v1.13.1/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) TestSwarmRemoveInternalNetwork(c *check.C) { 424 d := s.AddDaemon(c, true, true) 425 426 name := "ingress" 427 out, err := d.Cmd("network", "rm", name) 428 c.Assert(err, checker.NotNil) 429 c.Assert(strings.TrimSpace(out), checker.Contains, name) 430 c.Assert(strings.TrimSpace(out), checker.Contains, "is a pre-defined network and cannot be removed") 431 } 432 433 // Test case for #24108, also the case from: 434 // https://github.com/docker/docker/pull/24620#issuecomment-233715656 435 func (s *DockerSwarmSuite) TestSwarmTaskListFilter(c *check.C) { 436 d := s.AddDaemon(c, true, true) 437 438 name := "redis-cluster-md5" 439 out, err := d.Cmd("service", "create", "--name", name, "--replicas=3", "busybox", "top") 440 c.Assert(err, checker.IsNil) 441 c.Assert(strings.TrimSpace(out), checker.Not(checker.Equals), "") 442 443 filter := "name=redis-cluster" 444 445 checkNumTasks := func(*check.C) (interface{}, check.CommentInterface) { 446 out, err := d.Cmd("service", "ps", "--filter", filter, name) 447 c.Assert(err, checker.IsNil) 448 return len(strings.Split(out, "\n")) - 2, nil // includes header and nl in last line 449 } 450 451 // wait until all tasks have been created 452 waitAndAssert(c, defaultReconciliationTimeout, checkNumTasks, checker.Equals, 3) 453 454 out, err = d.Cmd("service", "ps", "--filter", filter, name) 455 c.Assert(err, checker.IsNil) 456 c.Assert(out, checker.Contains, name+".1") 457 c.Assert(out, checker.Contains, name+".2") 458 c.Assert(out, checker.Contains, name+".3") 459 460 out, err = d.Cmd("service", "ps", "--filter", "name="+name+".1", name) 461 c.Assert(err, checker.IsNil) 462 c.Assert(out, checker.Contains, name+".1") 463 c.Assert(out, checker.Not(checker.Contains), name+".2") 464 c.Assert(out, checker.Not(checker.Contains), name+".3") 465 466 out, err = d.Cmd("service", "ps", "--filter", "name=none", name) 467 c.Assert(err, checker.IsNil) 468 c.Assert(out, checker.Not(checker.Contains), name+".1") 469 c.Assert(out, checker.Not(checker.Contains), name+".2") 470 c.Assert(out, checker.Not(checker.Contains), name+".3") 471 472 name = "redis-cluster-sha1" 473 out, err = d.Cmd("service", "create", "--name", name, "--mode=global", "busybox", "top") 474 c.Assert(err, checker.IsNil) 475 c.Assert(strings.TrimSpace(out), checker.Not(checker.Equals), "") 476 477 waitAndAssert(c, defaultReconciliationTimeout, checkNumTasks, checker.Equals, 1) 478 479 filter = "name=redis-cluster" 480 out, err = d.Cmd("service", "ps", "--filter", filter, name) 481 c.Assert(err, checker.IsNil) 482 c.Assert(out, checker.Contains, name) 483 484 out, err = d.Cmd("service", "ps", "--filter", "name="+name, name) 485 c.Assert(err, checker.IsNil) 486 c.Assert(out, checker.Contains, name) 487 488 out, err = d.Cmd("service", "ps", "--filter", "name=none", name) 489 c.Assert(err, checker.IsNil) 490 c.Assert(out, checker.Not(checker.Contains), name) 491 } 492 493 func (s *DockerSwarmSuite) TestPsListContainersFilterIsTask(c *check.C) { 494 d := s.AddDaemon(c, true, true) 495 496 // Create a bare container 497 out, err := d.Cmd("run", "-d", "--name=bare-container", "busybox", "top") 498 c.Assert(err, checker.IsNil) 499 bareID := strings.TrimSpace(out)[:12] 500 // Create a service 501 name := "busybox-top" 502 out, err = d.Cmd("service", "create", "--name", name, "busybox", "top") 503 c.Assert(err, checker.IsNil) 504 c.Assert(strings.TrimSpace(out), checker.Not(checker.Equals), "") 505 506 // make sure task has been deployed. 507 waitAndAssert(c, defaultReconciliationTimeout, d.checkServiceRunningTasks(name), checker.Equals, 1) 508 509 // Filter non-tasks 510 out, err = d.Cmd("ps", "-a", "-q", "--filter=is-task=false") 511 c.Assert(err, checker.IsNil) 512 psOut := strings.TrimSpace(out) 513 c.Assert(psOut, checker.Equals, bareID, check.Commentf("Expected id %s, got %s for is-task label, output %q", bareID, psOut, out)) 514 515 // Filter tasks 516 out, err = d.Cmd("ps", "-a", "-q", "--filter=is-task=true") 517 c.Assert(err, checker.IsNil) 518 lines := strings.Split(strings.Trim(out, "\n "), "\n") 519 c.Assert(lines, checker.HasLen, 1) 520 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)) 521 } 522 523 const globalNetworkPlugin = "global-network-plugin" 524 const globalIPAMPlugin = "global-ipam-plugin" 525 526 func setupRemoteGlobalNetworkPlugin(c *check.C, mux *http.ServeMux, url, netDrv, ipamDrv string) { 527 528 mux.HandleFunc("/Plugin.Activate", func(w http.ResponseWriter, r *http.Request) { 529 w.Header().Set("Content-Type", "application/vnd.docker.plugins.v1+json") 530 fmt.Fprintf(w, `{"Implements": ["%s", "%s"]}`, driverapi.NetworkPluginEndpointType, ipamapi.PluginEndpointType) 531 }) 532 533 // Network driver implementation 534 mux.HandleFunc(fmt.Sprintf("/%s.GetCapabilities", driverapi.NetworkPluginEndpointType), func(w http.ResponseWriter, r *http.Request) { 535 w.Header().Set("Content-Type", "application/vnd.docker.plugins.v1+json") 536 fmt.Fprintf(w, `{"Scope":"global"}`) 537 }) 538 539 mux.HandleFunc(fmt.Sprintf("/%s.AllocateNetwork", driverapi.NetworkPluginEndpointType), func(w http.ResponseWriter, r *http.Request) { 540 err := json.NewDecoder(r.Body).Decode(&remoteDriverNetworkRequest) 541 if err != nil { 542 http.Error(w, "Unable to decode JSON payload: "+err.Error(), http.StatusBadRequest) 543 return 544 } 545 w.Header().Set("Content-Type", "application/vnd.docker.plugins.v1+json") 546 fmt.Fprintf(w, "null") 547 }) 548 549 mux.HandleFunc(fmt.Sprintf("/%s.FreeNetwork", driverapi.NetworkPluginEndpointType), func(w http.ResponseWriter, r *http.Request) { 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.CreateNetwork", driverapi.NetworkPluginEndpointType), func(w http.ResponseWriter, r *http.Request) { 555 err := json.NewDecoder(r.Body).Decode(&remoteDriverNetworkRequest) 556 if err != nil { 557 http.Error(w, "Unable to decode JSON payload: "+err.Error(), http.StatusBadRequest) 558 return 559 } 560 w.Header().Set("Content-Type", "application/vnd.docker.plugins.v1+json") 561 fmt.Fprintf(w, "null") 562 }) 563 564 mux.HandleFunc(fmt.Sprintf("/%s.DeleteNetwork", driverapi.NetworkPluginEndpointType), func(w http.ResponseWriter, r *http.Request) { 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.CreateEndpoint", 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, `{"Interface":{"MacAddress":"a0:b1:c2:d3:e4:f5"}}`) 572 }) 573 574 mux.HandleFunc(fmt.Sprintf("/%s.Join", driverapi.NetworkPluginEndpointType), func(w http.ResponseWriter, r *http.Request) { 575 w.Header().Set("Content-Type", "application/vnd.docker.plugins.v1+json") 576 577 veth := &netlink.Veth{ 578 LinkAttrs: netlink.LinkAttrs{Name: "randomIfName", TxQLen: 0}, PeerName: "cnt0"} 579 if err := netlink.LinkAdd(veth); err != nil { 580 fmt.Fprintf(w, `{"Error":"failed to add veth pair: `+err.Error()+`"}`) 581 } else { 582 fmt.Fprintf(w, `{"InterfaceName":{ "SrcName":"cnt0", "DstPrefix":"veth"}}`) 583 } 584 }) 585 586 mux.HandleFunc(fmt.Sprintf("/%s.Leave", driverapi.NetworkPluginEndpointType), func(w http.ResponseWriter, r *http.Request) { 587 w.Header().Set("Content-Type", "application/vnd.docker.plugins.v1+json") 588 fmt.Fprintf(w, "null") 589 }) 590 591 mux.HandleFunc(fmt.Sprintf("/%s.DeleteEndpoint", driverapi.NetworkPluginEndpointType), func(w http.ResponseWriter, r *http.Request) { 592 w.Header().Set("Content-Type", "application/vnd.docker.plugins.v1+json") 593 if link, err := netlink.LinkByName("cnt0"); err == nil { 594 netlink.LinkDel(link) 595 } 596 fmt.Fprintf(w, "null") 597 }) 598 599 // IPAM Driver implementation 600 var ( 601 poolRequest remoteipam.RequestPoolRequest 602 poolReleaseReq remoteipam.ReleasePoolRequest 603 addressRequest remoteipam.RequestAddressRequest 604 addressReleaseReq remoteipam.ReleaseAddressRequest 605 lAS = "localAS" 606 gAS = "globalAS" 607 pool = "172.28.0.0/16" 608 poolID = lAS + "/" + pool 609 gw = "172.28.255.254/16" 610 ) 611 612 mux.HandleFunc(fmt.Sprintf("/%s.GetDefaultAddressSpaces", ipamapi.PluginEndpointType), func(w http.ResponseWriter, r *http.Request) { 613 w.Header().Set("Content-Type", "application/vnd.docker.plugins.v1+json") 614 fmt.Fprintf(w, `{"LocalDefaultAddressSpace":"`+lAS+`", "GlobalDefaultAddressSpace": "`+gAS+`"}`) 615 }) 616 617 mux.HandleFunc(fmt.Sprintf("/%s.RequestPool", ipamapi.PluginEndpointType), func(w http.ResponseWriter, r *http.Request) { 618 err := json.NewDecoder(r.Body).Decode(&poolRequest) 619 if err != nil { 620 http.Error(w, "Unable to decode JSON payload: "+err.Error(), http.StatusBadRequest) 621 return 622 } 623 w.Header().Set("Content-Type", "application/vnd.docker.plugins.v1+json") 624 if poolRequest.AddressSpace != lAS && poolRequest.AddressSpace != gAS { 625 fmt.Fprintf(w, `{"Error":"Unknown address space in pool request: `+poolRequest.AddressSpace+`"}`) 626 } else if poolRequest.Pool != "" && poolRequest.Pool != pool { 627 fmt.Fprintf(w, `{"Error":"Cannot handle explicit pool requests yet"}`) 628 } else { 629 fmt.Fprintf(w, `{"PoolID":"`+poolID+`", "Pool":"`+pool+`"}`) 630 } 631 }) 632 633 mux.HandleFunc(fmt.Sprintf("/%s.RequestAddress", ipamapi.PluginEndpointType), func(w http.ResponseWriter, r *http.Request) { 634 err := json.NewDecoder(r.Body).Decode(&addressRequest) 635 if err != nil { 636 http.Error(w, "Unable to decode JSON payload: "+err.Error(), http.StatusBadRequest) 637 return 638 } 639 w.Header().Set("Content-Type", "application/vnd.docker.plugins.v1+json") 640 // make sure libnetwork is now querying on the expected pool id 641 if addressRequest.PoolID != poolID { 642 fmt.Fprintf(w, `{"Error":"unknown pool id"}`) 643 } else if addressRequest.Address != "" { 644 fmt.Fprintf(w, `{"Error":"Cannot handle explicit address requests yet"}`) 645 } else { 646 fmt.Fprintf(w, `{"Address":"`+gw+`"}`) 647 } 648 }) 649 650 mux.HandleFunc(fmt.Sprintf("/%s.ReleaseAddress", ipamapi.PluginEndpointType), func(w http.ResponseWriter, r *http.Request) { 651 err := json.NewDecoder(r.Body).Decode(&addressReleaseReq) 652 if err != nil { 653 http.Error(w, "Unable to decode JSON payload: "+err.Error(), http.StatusBadRequest) 654 return 655 } 656 w.Header().Set("Content-Type", "application/vnd.docker.plugins.v1+json") 657 // make sure libnetwork is now asking to release the expected address from the expected poolid 658 if addressRequest.PoolID != poolID { 659 fmt.Fprintf(w, `{"Error":"unknown pool id"}`) 660 } else if addressReleaseReq.Address != gw { 661 fmt.Fprintf(w, `{"Error":"unknown address"}`) 662 } else { 663 fmt.Fprintf(w, "null") 664 } 665 }) 666 667 mux.HandleFunc(fmt.Sprintf("/%s.ReleasePool", ipamapi.PluginEndpointType), func(w http.ResponseWriter, r *http.Request) { 668 err := json.NewDecoder(r.Body).Decode(&poolReleaseReq) 669 if err != nil { 670 http.Error(w, "Unable to decode JSON payload: "+err.Error(), http.StatusBadRequest) 671 return 672 } 673 w.Header().Set("Content-Type", "application/vnd.docker.plugins.v1+json") 674 // make sure libnetwork is now asking to release the expected poolid 675 if addressRequest.PoolID != poolID { 676 fmt.Fprintf(w, `{"Error":"unknown pool id"}`) 677 } else { 678 fmt.Fprintf(w, "null") 679 } 680 }) 681 682 err := os.MkdirAll("/etc/docker/plugins", 0755) 683 c.Assert(err, checker.IsNil) 684 685 fileName := fmt.Sprintf("/etc/docker/plugins/%s.spec", netDrv) 686 err = ioutil.WriteFile(fileName, []byte(url), 0644) 687 c.Assert(err, checker.IsNil) 688 689 ipamFileName := fmt.Sprintf("/etc/docker/plugins/%s.spec", ipamDrv) 690 err = ioutil.WriteFile(ipamFileName, []byte(url), 0644) 691 c.Assert(err, checker.IsNil) 692 } 693 694 func (s *DockerSwarmSuite) TestSwarmNetworkPlugin(c *check.C) { 695 mux := http.NewServeMux() 696 s.server = httptest.NewServer(mux) 697 c.Assert(s.server, check.NotNil, check.Commentf("Failed to start an HTTP Server")) 698 setupRemoteGlobalNetworkPlugin(c, mux, s.server.URL, globalNetworkPlugin, globalIPAMPlugin) 699 defer func() { 700 s.server.Close() 701 err := os.RemoveAll("/etc/docker/plugins") 702 c.Assert(err, checker.IsNil) 703 }() 704 705 d := s.AddDaemon(c, true, true) 706 707 out, err := d.Cmd("network", "create", "-d", globalNetworkPlugin, "foo") 708 c.Assert(err, checker.NotNil) 709 c.Assert(out, checker.Contains, "not supported in swarm mode") 710 } 711 712 // Test case for #24712 713 func (s *DockerSwarmSuite) TestSwarmServiceEnvFile(c *check.C) { 714 d := s.AddDaemon(c, true, true) 715 716 path := filepath.Join(d.folder, "env.txt") 717 err := ioutil.WriteFile(path, []byte("VAR1=A\nVAR2=A\n"), 0644) 718 c.Assert(err, checker.IsNil) 719 720 name := "worker" 721 out, err := d.Cmd("service", "create", "--env-file", path, "--env", "VAR1=B", "--env", "VAR1=C", "--env", "VAR2=", "--env", "VAR2", "--name", name, "busybox", "top") 722 c.Assert(err, checker.IsNil) 723 c.Assert(strings.TrimSpace(out), checker.Not(checker.Equals), "") 724 725 // The complete env is [VAR1=A VAR2=A VAR1=B VAR1=C VAR2= VAR2] and duplicates will be removed => [VAR1=C VAR2] 726 out, err = d.Cmd("inspect", "--format", "{{ .Spec.TaskTemplate.ContainerSpec.Env }}", name) 727 c.Assert(err, checker.IsNil) 728 c.Assert(out, checker.Contains, "[VAR1=C VAR2]") 729 } 730 731 func (s *DockerSwarmSuite) TestSwarmServiceTTY(c *check.C) { 732 d := s.AddDaemon(c, true, true) 733 734 name := "top" 735 736 ttyCheck := "if [ -t 0 ]; then echo TTY > /status && top; else echo none > /status && top; fi" 737 738 // Without --tty 739 expectedOutput := "none" 740 out, err := d.Cmd("service", "create", "--name", name, "busybox", "sh", "-c", ttyCheck) 741 c.Assert(err, checker.IsNil) 742 743 // Make sure task has been deployed. 744 waitAndAssert(c, defaultReconciliationTimeout, d.checkActiveContainerCount, checker.Equals, 1) 745 746 // We need to get the container id. 747 out, err = d.Cmd("ps", "-a", "-q", "--no-trunc") 748 c.Assert(err, checker.IsNil) 749 id := strings.TrimSpace(out) 750 751 out, err = d.Cmd("exec", id, "cat", "/status") 752 c.Assert(err, checker.IsNil) 753 c.Assert(out, checker.Contains, expectedOutput, check.Commentf("Expected '%s', but got %q", expectedOutput, out)) 754 755 // Remove service 756 out, err = d.Cmd("service", "rm", name) 757 c.Assert(err, checker.IsNil) 758 // Make sure container has been destroyed. 759 waitAndAssert(c, defaultReconciliationTimeout, d.checkActiveContainerCount, checker.Equals, 0) 760 761 // With --tty 762 expectedOutput = "TTY" 763 out, err = d.Cmd("service", "create", "--name", name, "--tty", "busybox", "sh", "-c", ttyCheck) 764 c.Assert(err, checker.IsNil) 765 766 // Make sure task has been deployed. 767 waitAndAssert(c, defaultReconciliationTimeout, d.checkActiveContainerCount, checker.Equals, 1) 768 769 // We need to get the container id. 770 out, err = d.Cmd("ps", "-a", "-q", "--no-trunc") 771 c.Assert(err, checker.IsNil) 772 id = strings.TrimSpace(out) 773 774 out, err = d.Cmd("exec", id, "cat", "/status") 775 c.Assert(err, checker.IsNil) 776 c.Assert(out, checker.Contains, expectedOutput, check.Commentf("Expected '%s', but got %q", expectedOutput, out)) 777 } 778 779 func (s *DockerSwarmSuite) TestSwarmServiceTTYUpdate(c *check.C) { 780 d := s.AddDaemon(c, true, true) 781 782 // Create a service 783 name := "top" 784 _, err := d.Cmd("service", "create", "--name", name, "busybox", "top") 785 c.Assert(err, checker.IsNil) 786 787 // Make sure task has been deployed. 788 waitAndAssert(c, defaultReconciliationTimeout, d.checkActiveContainerCount, checker.Equals, 1) 789 790 out, err := d.Cmd("service", "inspect", "--format", "{{ .Spec.TaskTemplate.ContainerSpec.TTY }}", name) 791 c.Assert(err, checker.IsNil) 792 c.Assert(strings.TrimSpace(out), checker.Equals, "false") 793 794 _, err = d.Cmd("service", "update", "--tty", name) 795 c.Assert(err, checker.IsNil) 796 797 out, err = d.Cmd("service", "inspect", "--format", "{{ .Spec.TaskTemplate.ContainerSpec.TTY }}", name) 798 c.Assert(err, checker.IsNil) 799 c.Assert(strings.TrimSpace(out), checker.Equals, "true") 800 } 801 802 func (s *DockerSwarmSuite) TestDNSConfig(c *check.C) { 803 d := s.AddDaemon(c, true, true) 804 805 // Create a service 806 name := "top" 807 _, err := d.Cmd("service", "create", "--name", name, "--dns=1.2.3.4", "--dns-search=example.com", "--dns-option=timeout:3", "busybox", "top") 808 c.Assert(err, checker.IsNil) 809 810 // Make sure task has been deployed. 811 waitAndAssert(c, defaultReconciliationTimeout, d.checkActiveContainerCount, checker.Equals, 1) 812 813 // We need to get the container id. 814 out, err := d.Cmd("ps", "-a", "-q", "--no-trunc") 815 c.Assert(err, checker.IsNil) 816 id := strings.TrimSpace(out) 817 818 // Compare against expected output. 819 expectedOutput1 := "nameserver 1.2.3.4" 820 expectedOutput2 := "search example.com" 821 expectedOutput3 := "options timeout:3" 822 out, err = d.Cmd("exec", id, "cat", "/etc/resolv.conf") 823 c.Assert(err, checker.IsNil) 824 c.Assert(out, checker.Contains, expectedOutput1, check.Commentf("Expected '%s', but got %q", expectedOutput1, out)) 825 c.Assert(out, checker.Contains, expectedOutput2, check.Commentf("Expected '%s', but got %q", expectedOutput2, out)) 826 c.Assert(out, checker.Contains, expectedOutput3, check.Commentf("Expected '%s', but got %q", expectedOutput3, out)) 827 } 828 829 func (s *DockerSwarmSuite) TestDNSConfigUpdate(c *check.C) { 830 d := s.AddDaemon(c, true, true) 831 832 // Create a service 833 name := "top" 834 _, err := d.Cmd("service", "create", "--name", name, "busybox", "top") 835 c.Assert(err, checker.IsNil) 836 837 // Make sure task has been deployed. 838 waitAndAssert(c, defaultReconciliationTimeout, d.checkActiveContainerCount, checker.Equals, 1) 839 840 _, err = d.Cmd("service", "update", "--dns-add=1.2.3.4", "--dns-search-add=example.com", "--dns-option-add=timeout:3", name) 841 c.Assert(err, checker.IsNil) 842 843 out, err := d.Cmd("service", "inspect", "--format", "{{ .Spec.TaskTemplate.ContainerSpec.DNSConfig }}", name) 844 c.Assert(err, checker.IsNil) 845 c.Assert(strings.TrimSpace(out), checker.Equals, "{[1.2.3.4] [example.com] [timeout:3]}") 846 } 847 848 func (s *DockerSwarmSuite) TestSwarmInitLocked(c *check.C) { 849 d := s.AddDaemon(c, false, false) 850 851 outs, err := d.Cmd("swarm", "init", "--autolock") 852 c.Assert(err, checker.IsNil, check.Commentf("out: %v", outs)) 853 854 c.Assert(outs, checker.Contains, "docker swarm unlock") 855 856 var unlockKey string 857 for _, line := range strings.Split(outs, "\n") { 858 if strings.Contains(line, "SWMKEY") { 859 unlockKey = strings.TrimSpace(line) 860 break 861 } 862 } 863 864 c.Assert(unlockKey, checker.Not(checker.Equals), "") 865 866 outs, err = d.Cmd("swarm", "unlock-key", "-q") 867 c.Assert(outs, checker.Equals, unlockKey+"\n") 868 869 info, err := d.info() 870 c.Assert(err, checker.IsNil) 871 c.Assert(info.LocalNodeState, checker.Equals, swarm.LocalNodeStateActive) 872 873 c.Assert(d.Restart(), checker.IsNil) 874 875 info, err = d.info() 876 c.Assert(err, checker.IsNil) 877 c.Assert(info.LocalNodeState, checker.Equals, swarm.LocalNodeStateLocked) 878 879 cmd := d.command("swarm", "unlock") 880 cmd.Stdin = bytes.NewBufferString("wrong-secret-key") 881 out, err := cmd.CombinedOutput() 882 c.Assert(err, checker.NotNil, check.Commentf("out: %v", string(out))) 883 c.Assert(string(out), checker.Contains, "invalid key") 884 885 cmd = d.command("swarm", "unlock") 886 cmd.Stdin = bytes.NewBufferString(unlockKey) 887 out, err = cmd.CombinedOutput() 888 c.Assert(err, checker.IsNil, check.Commentf("out: %v", string(out))) 889 890 info, err = d.info() 891 c.Assert(err, checker.IsNil) 892 c.Assert(info.LocalNodeState, checker.Equals, swarm.LocalNodeStateActive) 893 894 outs, err = d.Cmd("node", "ls") 895 c.Assert(err, checker.IsNil) 896 c.Assert(outs, checker.Not(checker.Contains), "Swarm is encrypted and needs to be unlocked") 897 898 outs, err = d.Cmd("swarm", "update", "--autolock=false") 899 c.Assert(err, checker.IsNil, check.Commentf("out: %v", outs)) 900 901 // Wait for autolock to be turned off 902 time.Sleep(time.Second) 903 904 c.Assert(d.Restart(), checker.IsNil) 905 906 info, err = d.info() 907 c.Assert(err, checker.IsNil) 908 c.Assert(info.LocalNodeState, checker.Equals, swarm.LocalNodeStateActive) 909 910 outs, err = d.Cmd("node", "ls") 911 c.Assert(err, checker.IsNil) 912 c.Assert(outs, checker.Not(checker.Contains), "Swarm is encrypted and needs to be unlocked") 913 } 914 915 func (s *DockerSwarmSuite) TestSwarmLeaveLocked(c *check.C) { 916 d := s.AddDaemon(c, false, false) 917 918 outs, err := d.Cmd("swarm", "init", "--autolock") 919 c.Assert(err, checker.IsNil, check.Commentf("out: %v", outs)) 920 921 c.Assert(d.Restart("--swarm-default-advertise-addr=lo"), checker.IsNil) 922 923 info, err := d.info() 924 c.Assert(err, checker.IsNil) 925 c.Assert(info.LocalNodeState, checker.Equals, swarm.LocalNodeStateLocked) 926 927 outs, _ = d.Cmd("node", "ls") 928 c.Assert(outs, checker.Contains, "Swarm is encrypted and needs to be unlocked") 929 930 outs, err = d.Cmd("swarm", "leave", "--force") 931 c.Assert(err, checker.IsNil, check.Commentf("out: %v", outs)) 932 933 info, err = d.info() 934 c.Assert(err, checker.IsNil) 935 c.Assert(info.LocalNodeState, checker.Equals, swarm.LocalNodeStateInactive) 936 937 outs, err = d.Cmd("swarm", "init") 938 c.Assert(err, checker.IsNil, check.Commentf("out: %v", outs)) 939 940 info, err = d.info() 941 c.Assert(err, checker.IsNil) 942 c.Assert(info.LocalNodeState, checker.Equals, swarm.LocalNodeStateActive) 943 } 944 945 func (s *DockerSwarmSuite) TestSwarmRotateUnlockKey(c *check.C) { 946 d := s.AddDaemon(c, true, true) 947 948 outs, err := d.Cmd("swarm", "update", "--autolock") 949 c.Assert(err, checker.IsNil, check.Commentf("out: %v", outs)) 950 951 c.Assert(outs, checker.Contains, "docker swarm unlock") 952 953 var unlockKey string 954 for _, line := range strings.Split(outs, "\n") { 955 if strings.Contains(line, "SWMKEY") { 956 unlockKey = strings.TrimSpace(line) 957 break 958 } 959 } 960 961 c.Assert(unlockKey, checker.Not(checker.Equals), "") 962 963 outs, err = d.Cmd("swarm", "unlock-key", "-q") 964 c.Assert(outs, checker.Equals, unlockKey+"\n") 965 966 // Rotate multiple times 967 for i := 0; i != 3; i++ { 968 outs, err = d.Cmd("swarm", "unlock-key", "-q", "--rotate") 969 c.Assert(err, checker.IsNil, check.Commentf("out: %v", outs)) 970 // Strip \n 971 newUnlockKey := outs[:len(outs)-1] 972 c.Assert(newUnlockKey, checker.Not(checker.Equals), "") 973 c.Assert(newUnlockKey, checker.Not(checker.Equals), unlockKey) 974 975 c.Assert(d.Restart(), checker.IsNil) 976 977 info, err := d.info() 978 c.Assert(err, checker.IsNil) 979 c.Assert(info.LocalNodeState, checker.Equals, swarm.LocalNodeStateLocked) 980 981 outs, _ = d.Cmd("node", "ls") 982 c.Assert(outs, checker.Contains, "Swarm is encrypted and needs to be unlocked") 983 984 cmd := d.command("swarm", "unlock") 985 cmd.Stdin = bytes.NewBufferString(unlockKey) 986 out, err := cmd.CombinedOutput() 987 988 if err == nil { 989 // On occasion, the daemon may not have finished 990 // rotating the KEK before restarting. The test is 991 // intentionally written to explore this behavior. 992 // When this happens, unlocking with the old key will 993 // succeed. If we wait for the rotation to happen and 994 // restart again, the new key should be required this 995 // time. 996 997 time.Sleep(3 * time.Second) 998 999 c.Assert(d.Restart(), checker.IsNil) 1000 1001 cmd = d.command("swarm", "unlock") 1002 cmd.Stdin = bytes.NewBufferString(unlockKey) 1003 out, err = cmd.CombinedOutput() 1004 } 1005 c.Assert(err, checker.NotNil, check.Commentf("out: %v", string(out))) 1006 c.Assert(string(out), checker.Contains, "invalid key") 1007 1008 outs, _ = d.Cmd("node", "ls") 1009 c.Assert(outs, checker.Contains, "Swarm is encrypted and needs to be unlocked") 1010 1011 cmd = d.command("swarm", "unlock") 1012 cmd.Stdin = bytes.NewBufferString(newUnlockKey) 1013 out, err = cmd.CombinedOutput() 1014 c.Assert(err, checker.IsNil, check.Commentf("out: %v", string(out))) 1015 1016 info, err = d.info() 1017 c.Assert(err, checker.IsNil) 1018 c.Assert(info.LocalNodeState, checker.Equals, swarm.LocalNodeStateActive) 1019 1020 outs, err = d.Cmd("node", "ls") 1021 c.Assert(err, checker.IsNil) 1022 c.Assert(outs, checker.Not(checker.Contains), "Swarm is encrypted and needs to be unlocked") 1023 1024 unlockKey = newUnlockKey 1025 } 1026 } 1027 1028 func (s *DockerSwarmSuite) TestExtraHosts(c *check.C) { 1029 d := s.AddDaemon(c, true, true) 1030 1031 // Create a service 1032 name := "top" 1033 _, err := d.Cmd("service", "create", "--name", name, "--host=example.com:1.2.3.4", "busybox", "top") 1034 c.Assert(err, checker.IsNil) 1035 1036 // Make sure task has been deployed. 1037 waitAndAssert(c, defaultReconciliationTimeout, d.checkActiveContainerCount, checker.Equals, 1) 1038 1039 // We need to get the container id. 1040 out, err := d.Cmd("ps", "-a", "-q", "--no-trunc") 1041 c.Assert(err, checker.IsNil) 1042 id := strings.TrimSpace(out) 1043 1044 // Compare against expected output. 1045 expectedOutput := "1.2.3.4\texample.com" 1046 out, err = d.Cmd("exec", id, "cat", "/etc/hosts") 1047 c.Assert(err, checker.IsNil) 1048 c.Assert(out, checker.Contains, expectedOutput, check.Commentf("Expected '%s', but got %q", expectedOutput, out)) 1049 } 1050 1051 func (s *DockerSwarmSuite) TestSwarmManagerAddress(c *check.C) { 1052 d1 := s.AddDaemon(c, true, true) 1053 d2 := s.AddDaemon(c, true, false) 1054 d3 := s.AddDaemon(c, true, false) 1055 1056 // Manager Addresses will always show Node 1's address 1057 expectedOutput := fmt.Sprintf("Manager Addresses:\n 127.0.0.1:%d\n", d1.port) 1058 1059 out, err := d1.Cmd("info") 1060 c.Assert(err, checker.IsNil) 1061 c.Assert(out, checker.Contains, expectedOutput) 1062 1063 out, err = d2.Cmd("info") 1064 c.Assert(err, checker.IsNil) 1065 c.Assert(out, checker.Contains, expectedOutput) 1066 1067 out, err = d3.Cmd("info") 1068 c.Assert(err, checker.IsNil) 1069 c.Assert(out, checker.Contains, expectedOutput) 1070 } 1071 1072 func (s *DockerSwarmSuite) TestSwarmServiceInspectPretty(c *check.C) { 1073 d := s.AddDaemon(c, true, true) 1074 1075 name := "top" 1076 out, err := d.Cmd("service", "create", "--name", name, "--limit-cpu=0.5", "busybox", "top") 1077 c.Assert(err, checker.IsNil, check.Commentf(out)) 1078 1079 expectedOutput := ` 1080 Resources: 1081 Limits: 1082 CPU: 0.5` 1083 out, err = d.Cmd("service", "inspect", "--pretty", name) 1084 c.Assert(err, checker.IsNil, check.Commentf(out)) 1085 c.Assert(out, checker.Contains, expectedOutput, check.Commentf(out)) 1086 } 1087 1088 func (s *DockerSwarmSuite) TestSwarmNetworkIPAMOptions(c *check.C) { 1089 d := s.AddDaemon(c, true, true) 1090 1091 out, err := d.Cmd("network", "create", "-d", "overlay", "--ipam-opt", "foo=bar", "foo") 1092 c.Assert(err, checker.IsNil, check.Commentf(out)) 1093 c.Assert(strings.TrimSpace(out), checker.Not(checker.Equals), "") 1094 1095 out, err = d.Cmd("network", "inspect", "--format", "{{.IPAM.Options}}", "foo") 1096 c.Assert(err, checker.IsNil, check.Commentf(out)) 1097 c.Assert(strings.TrimSpace(out), checker.Equals, "map[foo:bar]") 1098 1099 out, err = d.Cmd("service", "create", "--network=foo", "--name", "top", "busybox", "top") 1100 c.Assert(err, checker.IsNil, check.Commentf(out)) 1101 1102 // make sure task has been deployed. 1103 waitAndAssert(c, defaultReconciliationTimeout, d.checkActiveContainerCount, checker.Equals, 1) 1104 1105 out, err = d.Cmd("network", "inspect", "--format", "{{.IPAM.Options}}", "foo") 1106 c.Assert(err, checker.IsNil, check.Commentf(out)) 1107 c.Assert(strings.TrimSpace(out), checker.Equals, "map[foo:bar]") 1108 } 1109 1110 // TODO: migrate to a unit test 1111 // This test could be migrated to unit test and save costly integration test, 1112 // once PR #29143 is merged. 1113 func (s *DockerSwarmSuite) TestSwarmUpdateWithoutArgs(c *check.C) { 1114 d := s.AddDaemon(c, true, true) 1115 1116 expectedOutput := ` 1117 Usage: docker swarm update [OPTIONS] 1118 1119 Update the swarm 1120 1121 Options:` 1122 1123 out, err := d.Cmd("swarm", "update") 1124 c.Assert(err, checker.IsNil, check.Commentf("out: %v", out)) 1125 c.Assert(out, checker.Contains, expectedOutput, check.Commentf(out)) 1126 } 1127 1128 func (s *DockerTrustedSwarmSuite) TestTrustedServiceCreate(c *check.C) { 1129 d := s.swarmSuite.AddDaemon(c, true, true) 1130 1131 // Attempt creating a service from an image that is known to notary. 1132 repoName := s.trustSuite.setupTrustedImage(c, "trusted-pull") 1133 1134 name := "trusted" 1135 serviceCmd := d.command("-D", "service", "create", "--name", name, repoName, "top") 1136 s.trustSuite.trustedCmd(serviceCmd) 1137 out, _, err := runCommandWithOutput(serviceCmd) 1138 c.Assert(err, checker.IsNil, check.Commentf(out)) 1139 c.Assert(out, checker.Contains, "resolved image tag to", check.Commentf(out)) 1140 1141 out, err = d.Cmd("service", "inspect", "--pretty", name) 1142 c.Assert(err, checker.IsNil, check.Commentf(out)) 1143 c.Assert(out, checker.Contains, repoName+"@", check.Commentf(out)) 1144 1145 // Try trusted service create on an untrusted tag. 1146 1147 repoName = fmt.Sprintf("%v/untrustedservicecreate/createtest:latest", privateRegistryURL) 1148 // tag the image and upload it to the private registry 1149 dockerCmd(c, "tag", "busybox", repoName) 1150 dockerCmd(c, "push", repoName) 1151 dockerCmd(c, "rmi", repoName) 1152 1153 name = "untrusted" 1154 serviceCmd = d.command("service", "create", "--name", name, repoName, "top") 1155 s.trustSuite.trustedCmd(serviceCmd) 1156 out, _, err = runCommandWithOutput(serviceCmd) 1157 1158 c.Assert(err, check.NotNil, check.Commentf(out)) 1159 c.Assert(string(out), checker.Contains, "Error: remote trust data does not exist", check.Commentf(out)) 1160 1161 out, err = d.Cmd("service", "inspect", "--pretty", name) 1162 c.Assert(err, checker.NotNil, check.Commentf(out)) 1163 } 1164 1165 func (s *DockerTrustedSwarmSuite) TestTrustedServiceUpdate(c *check.C) { 1166 d := s.swarmSuite.AddDaemon(c, true, true) 1167 1168 // Attempt creating a service from an image that is known to notary. 1169 repoName := s.trustSuite.setupTrustedImage(c, "trusted-pull") 1170 1171 name := "myservice" 1172 1173 // Create a service without content trust 1174 _, err := d.Cmd("service", "create", "--name", name, repoName, "top") 1175 c.Assert(err, checker.IsNil) 1176 1177 out, err := d.Cmd("service", "inspect", "--pretty", name) 1178 c.Assert(err, checker.IsNil, check.Commentf(out)) 1179 // Daemon won't insert the digest because this is disabled by 1180 // DOCKER_SERVICE_PREFER_OFFLINE_IMAGE. 1181 c.Assert(out, check.Not(checker.Contains), repoName+"@", check.Commentf(out)) 1182 1183 serviceCmd := d.command("-D", "service", "update", "--image", repoName, name) 1184 s.trustSuite.trustedCmd(serviceCmd) 1185 out, _, err = runCommandWithOutput(serviceCmd) 1186 c.Assert(err, checker.IsNil, check.Commentf(out)) 1187 c.Assert(out, checker.Contains, "resolved image tag to", check.Commentf(out)) 1188 1189 out, err = d.Cmd("service", "inspect", "--pretty", name) 1190 c.Assert(err, checker.IsNil, check.Commentf(out)) 1191 c.Assert(out, checker.Contains, repoName+"@", check.Commentf(out)) 1192 1193 // Try trusted service update on an untrusted tag. 1194 1195 repoName = fmt.Sprintf("%v/untrustedservicecreate/createtest:latest", privateRegistryURL) 1196 // tag the image and upload it to the private registry 1197 dockerCmd(c, "tag", "busybox", repoName) 1198 dockerCmd(c, "push", repoName) 1199 dockerCmd(c, "rmi", repoName) 1200 1201 serviceCmd = d.command("service", "update", "--image", repoName, name) 1202 s.trustSuite.trustedCmd(serviceCmd) 1203 out, _, err = runCommandWithOutput(serviceCmd) 1204 1205 c.Assert(err, check.NotNil, check.Commentf(out)) 1206 c.Assert(string(out), checker.Contains, "Error: remote trust data does not exist", check.Commentf(out)) 1207 } 1208 1209 // Test case for issue #27866, which did not allow NW name that is the prefix of a swarm NW ID. 1210 // e.g. if the ingress ID starts with "n1", it was impossible to create a NW named "n1". 1211 func (s *DockerSwarmSuite) TestSwarmNetworkCreateIssue27866(c *check.C) { 1212 d := s.AddDaemon(c, true, true) 1213 out, err := d.Cmd("network", "inspect", "-f", "{{.Id}}", "ingress") 1214 c.Assert(err, checker.IsNil, check.Commentf("out: %v", out)) 1215 ingressID := strings.TrimSpace(out) 1216 c.Assert(ingressID, checker.Not(checker.Equals), "") 1217 1218 // create a network of which name is the prefix of the ID of an overlay network 1219 // (ingressID in this case) 1220 newNetName := ingressID[0:2] 1221 out, err = d.Cmd("network", "create", "--driver", "overlay", newNetName) 1222 // In #27866, it was failing because of "network with name %s already exists" 1223 c.Assert(err, checker.IsNil, check.Commentf("out: %v", out)) 1224 out, err = d.Cmd("network", "rm", newNetName) 1225 c.Assert(err, checker.IsNil, check.Commentf("out: %v", out)) 1226 } 1227 1228 // Test case for https://github.com/docker/docker/pull/27938#issuecomment-265768303 1229 // This test creates two networks with the same name sequentially, with various drivers. 1230 // Since the operations in this test are done sequentially, the 2nd call should fail with 1231 // "network with name FOO already exists". 1232 // Note that it is to ok have multiple networks with the same name if the operations are done 1233 // in parallel. (#18864) 1234 func (s *DockerSwarmSuite) TestSwarmNetworkCreateDup(c *check.C) { 1235 d := s.AddDaemon(c, true, true) 1236 drivers := []string{"bridge", "overlay"} 1237 for i, driver1 := range drivers { 1238 nwName := fmt.Sprintf("network-test-%d", i) 1239 for _, driver2 := range drivers { 1240 c.Logf("Creating a network named %q with %q, then %q", 1241 nwName, driver1, driver2) 1242 out, err := d.Cmd("network", "create", "--driver", driver1, nwName) 1243 c.Assert(err, checker.IsNil, check.Commentf("out: %v", out)) 1244 out, err = d.Cmd("network", "create", "--driver", driver2, nwName) 1245 c.Assert(out, checker.Contains, 1246 fmt.Sprintf("network with name %s already exists", nwName)) 1247 c.Assert(err, checker.NotNil) 1248 c.Logf("As expected, the attempt to network %q with %q failed: %s", 1249 nwName, driver2, out) 1250 out, err = d.Cmd("network", "rm", nwName) 1251 c.Assert(err, checker.IsNil, check.Commentf("out: %v", out)) 1252 } 1253 } 1254 }