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