2016-06-16 20:04:56 -04:00
// +build !windows
package main
import (
2016-10-24 17:44:51 -04:00
"bytes"
2018-04-19 18:30:59 -04:00
"context"
2016-10-15 13:20:34 -04:00
"encoding/json"
2017-06-06 09:28:40 -04:00
"encoding/pem"
2016-10-15 13:20:34 -04:00
"fmt"
2016-06-28 17:20:52 -04:00
"io/ioutil"
2016-10-15 13:20:34 -04:00
"net/http"
"net/http/httptest"
"os"
2016-07-20 02:58:32 -04:00
"path/filepath"
2018-12-23 06:39:58 -05:00
"runtime"
2016-06-29 22:48:53 -04:00
"strings"
2016-06-16 20:04:56 -04:00
"time"
2017-04-16 15:40:11 -04:00
"github.com/cloudflare/cfssl/helpers"
2017-01-19 06:04:26 -05:00
"github.com/docker/docker/api/types"
2016-09-06 14:18:12 -04:00
"github.com/docker/docker/api/types/swarm"
2016-12-30 12:23:00 -05:00
"github.com/docker/docker/integration-cli/checker"
2017-03-23 13:35:22 -04:00
"github.com/docker/docker/integration-cli/cli"
2016-12-09 04:17:53 -05:00
"github.com/docker/docker/integration-cli/daemon"
2016-10-15 13:20:34 -04:00
"github.com/docker/libnetwork/driverapi"
"github.com/docker/libnetwork/ipamapi"
remoteipam "github.com/docker/libnetwork/ipams/remote/api"
2018-02-12 17:25:51 -05:00
"github.com/docker/swarmkit/ca/keyutils"
2016-06-16 20:04:56 -04:00
"github.com/go-check/check"
2016-10-15 13:20:34 -04:00
"github.com/vishvananda/netlink"
2019-04-04 09:23:19 -04:00
"gotest.tools/assert"
2018-06-11 09:32:11 -04:00
"gotest.tools/fs"
"gotest.tools/icmd"
2016-06-16 20:04:56 -04:00
)
2019-09-09 17:05:55 -04:00
func ( s * DockerSwarmSuite ) TestSwarmUpdate ( c * testing . T ) {
2016-06-16 20:04:56 -04:00
d := s . AddDaemon ( c , true , true )
getSpec := func ( ) swarm . Spec {
2016-12-09 04:17:53 -05:00
sw := d . GetSwarm ( c )
2016-07-24 04:53:52 -04:00
return sw . Spec
2016-06-16 20:04:56 -04:00
}
2016-07-20 14:15:08 -04:00
out , err := d . Cmd ( "swarm" , "update" , "--cert-expiry" , "30h" , "--dispatcher-heartbeat" , "11s" )
2019-04-04 09:23:19 -04:00
assert . NilError ( c , err , out )
2016-06-16 20:04:56 -04:00
spec := getSpec ( )
2019-09-09 17:05:55 -04:00
assert . Assert ( c , spec . CAConfig . NodeCertExpiry , checker . Equals , 30 * time . Hour )
assert . Assert ( c , spec . Dispatcher . HeartbeatPeriod , checker . Equals , 11 * time . Second )
2016-06-16 20:04:56 -04:00
// setting anything under 30m for cert-expiry is not allowed
out , err = d . Cmd ( "swarm" , "update" , "--cert-expiry" , "15m" )
2019-04-04 09:23:19 -04:00
assert . ErrorContains ( c , err , "" )
2019-09-09 17:05:55 -04:00
assert . Assert ( c , out , checker . Contains , "minimum certificate expiry time" )
2016-06-16 20:04:56 -04:00
spec = getSpec ( )
2019-09-09 17:05:55 -04:00
assert . Assert ( c , spec . CAConfig . NodeCertExpiry , checker . Equals , 30 * time . Hour )
2017-04-12 18:10:18 -04:00
// passing an external CA (this is without starting a root rotation) does not fail
2017-04-25 18:40:46 -04:00
cli . Docker ( cli . Args ( "swarm" , "update" , "--external-ca" , "protocol=cfssl,url=https://something.org" ,
"--external-ca" , "protocol=cfssl,url=https://somethingelse.org,cacert=fixtures/https/ca.pem" ) ,
2018-04-11 06:10:17 -04:00
cli . Daemon ( d ) ) . Assert ( c , icmd . Success )
2017-04-25 18:40:46 -04:00
expected , err := ioutil . ReadFile ( "fixtures/https/ca.pem" )
2019-04-04 09:23:19 -04:00
assert . NilError ( c , err )
2017-04-12 18:10:18 -04:00
spec = getSpec ( )
2019-09-09 17:05:55 -04:00
assert . Assert ( c , spec . CAConfig . ExternalCAs , checker . HasLen , 2 )
assert . Assert ( c , spec . CAConfig . ExternalCAs [ 0 ] . CACert , checker . Equals , "" )
assert . Assert ( c , spec . CAConfig . ExternalCAs [ 1 ] . CACert , checker . Equals , string ( expected ) )
2017-04-25 18:40:46 -04:00
// passing an invalid external CA fails
2017-08-23 17:25:00 -04:00
tempFile := fs . NewFile ( c , "testfile" , fs . WithContent ( "fakecert" ) )
2017-04-25 18:40:46 -04:00
defer tempFile . Remove ( )
result := cli . Docker ( cli . Args ( "swarm" , "update" ,
2017-08-23 17:25:00 -04:00
"--external-ca" , fmt . Sprintf ( "protocol=cfssl,url=https://something.org,cacert=%s" , tempFile . Path ( ) ) ) ,
2018-04-11 06:10:17 -04:00
cli . Daemon ( d ) )
2017-04-25 18:40:46 -04:00
result . Assert ( c , icmd . Expected {
ExitCode : 125 ,
Err : "must be in PEM format" ,
} )
2016-06-16 20:04:56 -04:00
}
2016-06-21 17:27:04 -04:00
2019-09-09 17:05:55 -04:00
func ( s * DockerSwarmSuite ) TestSwarmInit ( c * testing . T ) {
2016-06-21 17:27:04 -04:00
d := s . AddDaemon ( c , false , false )
getSpec := func ( ) swarm . Spec {
2016-12-09 04:17:53 -05:00
sw := d . GetSwarm ( c )
2016-07-24 04:53:52 -04:00
return sw . Spec
2016-06-21 17:27:04 -04:00
}
2017-04-25 18:40:46 -04:00
// passing an invalid external CA fails
2017-08-23 17:25:00 -04:00
tempFile := fs . NewFile ( c , "testfile" , fs . WithContent ( "fakecert" ) )
2017-04-25 18:40:46 -04:00
defer tempFile . Remove ( )
result := cli . Docker ( cli . Args ( "swarm" , "init" , "--cert-expiry" , "30h" , "--dispatcher-heartbeat" , "11s" ,
2017-08-23 17:25:00 -04:00
"--external-ca" , fmt . Sprintf ( "protocol=cfssl,url=https://somethingelse.org,cacert=%s" , tempFile . Path ( ) ) ) ,
2018-04-11 06:10:17 -04:00
cli . Daemon ( d ) )
2017-04-25 18:40:46 -04:00
result . Assert ( c , icmd . Expected {
ExitCode : 125 ,
Err : "must be in PEM format" ,
} )
2017-04-12 18:10:18 -04:00
cli . Docker ( cli . Args ( "swarm" , "init" , "--cert-expiry" , "30h" , "--dispatcher-heartbeat" , "11s" ,
2017-04-25 18:40:46 -04:00
"--external-ca" , "protocol=cfssl,url=https://something.org" ,
"--external-ca" , "protocol=cfssl,url=https://somethingelse.org,cacert=fixtures/https/ca.pem" ) ,
2018-04-11 06:10:17 -04:00
cli . Daemon ( d ) ) . Assert ( c , icmd . Success )
2016-06-21 17:27:04 -04:00
2017-04-25 18:40:46 -04:00
expected , err := ioutil . ReadFile ( "fixtures/https/ca.pem" )
2019-04-04 09:23:19 -04:00
assert . NilError ( c , err )
2017-04-25 18:40:46 -04:00
2016-06-21 17:27:04 -04:00
spec := getSpec ( )
2019-09-09 17:05:55 -04:00
assert . Assert ( c , spec . CAConfig . NodeCertExpiry , checker . Equals , 30 * time . Hour )
assert . Assert ( c , spec . Dispatcher . HeartbeatPeriod , checker . Equals , 11 * time . Second )
assert . Assert ( c , spec . CAConfig . ExternalCAs , checker . HasLen , 2 )
assert . Assert ( c , spec . CAConfig . ExternalCAs [ 0 ] . CACert , checker . Equals , "" )
assert . Assert ( c , spec . CAConfig . ExternalCAs [ 1 ] . CACert , checker . Equals , string ( expected ) )
2016-06-21 17:27:04 -04:00
2019-09-09 17:05:55 -04:00
assert . Assert ( c , d . SwarmLeave ( c , true ) , checker . IsNil )
2018-04-11 06:10:17 -04:00
cli . Docker ( cli . Args ( "swarm" , "init" ) , cli . Daemon ( d ) ) . Assert ( c , icmd . Success )
2016-06-21 17:27:04 -04:00
spec = getSpec ( )
2019-09-09 17:05:55 -04:00
assert . Assert ( c , spec . CAConfig . NodeCertExpiry , checker . Equals , 90 * 24 * time . Hour )
assert . Assert ( c , spec . Dispatcher . HeartbeatPeriod , checker . Equals , 5 * time . Second )
2016-06-21 17:27:04 -04:00
}
2019-09-09 17:05:55 -04:00
func ( s * DockerSwarmSuite ) TestSwarmInitIPv6 ( c * testing . T ) {
2016-06-21 17:27:04 -04:00
testRequires ( c , IPv6 )
d1 := s . AddDaemon ( c , false , false )
2018-04-11 06:10:17 -04:00
cli . Docker ( cli . Args ( "swarm" , "init" , "--listen-add" , "::1" ) , cli . Daemon ( d1 ) ) . Assert ( c , icmd . Success )
2016-06-21 17:27:04 -04:00
d2 := s . AddDaemon ( c , false , false )
2018-04-11 06:10:17 -04:00
cli . Docker ( cli . Args ( "swarm" , "join" , "::1" ) , cli . Daemon ( d2 ) ) . Assert ( c , icmd . Success )
2016-06-21 17:27:04 -04:00
2018-04-11 06:10:17 -04:00
out := cli . Docker ( cli . Args ( "info" ) , cli . Daemon ( d2 ) ) . Assert ( c , icmd . Success ) . Combined ( )
2019-09-09 17:05:55 -04:00
assert . Assert ( c , out , checker . Contains , "Swarm: active" )
2016-06-21 17:27:04 -04:00
}
2016-06-28 17:20:52 -04:00
2019-09-09 17:05:55 -04:00
func ( s * DockerSwarmSuite ) TestSwarmInitUnspecifiedAdvertiseAddr ( c * testing . T ) {
2016-11-28 18:16:59 -05:00
d := s . AddDaemon ( c , false , false )
out , err := d . Cmd ( "swarm" , "init" , "--advertise-addr" , "0.0.0.0" )
2019-04-04 09:23:19 -04:00
assert . ErrorContains ( c , err , "" )
2019-09-09 17:05:55 -04:00
assert . Assert ( c , out , checker . Contains , "advertise address must be a non-zero IP address" )
2016-11-28 18:16:59 -05:00
}
2019-09-09 17:05:55 -04:00
func ( s * DockerSwarmSuite ) TestSwarmIncompatibleDaemon ( c * testing . T ) {
2016-06-28 17:20:52 -04:00
// init swarm mode and stop a daemon
d := s . AddDaemon ( c , true , true )
2018-04-11 06:10:17 -04:00
info := d . SwarmInfo ( c )
2019-04-04 09:23:19 -04:00
assert . Equal ( c , info . LocalNodeState , swarm . LocalNodeStateActive )
2016-12-09 17:20:14 -05:00
d . Stop ( c )
2016-06-28 17:20:52 -04:00
// start a daemon with --cluster-store and --cluster-advertise
2018-04-11 06:10:17 -04:00
err := d . StartWithError ( "--cluster-store=consul://consuladdr:consulport/some/path" , "--cluster-advertise=1.1.1.1:2375" )
2019-04-04 09:23:19 -04:00
assert . ErrorContains ( c , err , "" )
2016-12-09 04:17:53 -05:00
content , err := d . ReadLogFile ( )
2019-04-04 09:23:19 -04:00
assert . NilError ( c , err )
2019-09-09 17:05:55 -04:00
assert . Assert ( c , string ( content ) , checker . Contains , "--cluster-store and --cluster-advertise daemon configurations are incompatible with swarm mode" )
2016-06-28 17:20:52 -04:00
// start a daemon with --live-restore
2016-12-09 17:20:14 -05:00
err = d . StartWithError ( "--live-restore" )
2019-04-04 09:23:19 -04:00
assert . ErrorContains ( c , err , "" )
2016-12-09 04:17:53 -05:00
content , err = d . ReadLogFile ( )
2019-04-04 09:23:19 -04:00
assert . NilError ( c , err )
2019-09-09 17:05:55 -04:00
assert . Assert ( c , string ( content ) , checker . Contains , "--live-restore daemon configuration is incompatible with swarm mode" )
2016-06-28 17:20:52 -04:00
// restart for teardown
2018-10-25 14:47:56 -04:00
d . StartNode ( c )
2016-06-28 17:20:52 -04:00
}
2016-06-29 22:48:53 -04:00
2019-09-09 17:05:55 -04:00
func ( s * DockerSwarmSuite ) TestSwarmServiceTemplatingHostname ( c * testing . T ) {
2016-11-09 17:28:06 -05:00
d := s . AddDaemon ( c , true , true )
2017-08-30 15:45:05 -04:00
hostname , err := d . Cmd ( "node" , "inspect" , "--format" , "{{.Description.Hostname}}" , "self" )
2019-09-09 17:05:55 -04:00
assert . Assert ( c , err , checker . IsNil , check . Commentf ( "%s" , hostname ) )
2016-11-09 17:28:06 -05:00
2017-09-27 19:17:55 -04:00
out , err := d . Cmd ( "service" , "create" , "--detach" , "--no-resolve-image" , "--name" , "test" , "--hostname" , "{{.Service.Name}}-{{.Task.Slot}}-{{.Node.Hostname}}" , "busybox" , "top" )
2019-04-04 09:23:19 -04:00
assert . NilError ( c , err , out )
2016-11-09 17:28:06 -05:00
// make sure task has been deployed.
2016-12-09 04:17:53 -05:00
waitAndAssert ( c , defaultReconciliationTimeout , d . CheckActiveContainerCount , checker . Equals , 1 )
2016-11-09 17:28:06 -05:00
2018-04-11 09:52:13 -04:00
containers := d . ActiveContainers ( c )
2016-11-09 17:28:06 -05:00
out , err = d . Cmd ( "inspect" , "--type" , "container" , "--format" , "{{.Config.Hostname}}" , containers [ 0 ] )
2019-04-04 09:23:19 -04:00
assert . NilError ( c , err , out )
2019-09-09 17:05:55 -04:00
assert . Assert ( c , strings . Split ( out , "\n" ) [ 0 ] , checker . Equals , "test-1-" + strings . Split ( hostname , "\n" ) [ 0 ] , check . Commentf ( "hostname with templating invalid" ) )
2016-11-09 17:28:06 -05:00
}
2016-07-13 22:09:07 -04:00
// Test case for #24270
2019-09-09 17:05:55 -04:00
func ( s * DockerSwarmSuite ) TestSwarmServiceListFilter ( c * testing . T ) {
2016-07-13 22:09:07 -04:00
d := s . AddDaemon ( c , true , true )
name1 := "redis-cluster-md5"
name2 := "redis-cluster"
name3 := "other-cluster"
2017-09-27 19:17:55 -04:00
out , err := d . Cmd ( "service" , "create" , "--detach" , "--no-resolve-image" , "--name" , name1 , "busybox" , "top" )
2019-04-04 09:23:19 -04:00
assert . NilError ( c , err , out )
assert . Assert ( c , strings . TrimSpace ( out ) != "" )
2016-07-13 22:09:07 -04:00
2017-09-27 19:17:55 -04:00
out , err = d . Cmd ( "service" , "create" , "--detach" , "--no-resolve-image" , "--name" , name2 , "busybox" , "top" )
2019-04-04 09:23:19 -04:00
assert . NilError ( c , err , out )
assert . Assert ( c , strings . TrimSpace ( out ) != "" )
2016-07-13 22:09:07 -04:00
2017-09-27 19:17:55 -04:00
out , err = d . Cmd ( "service" , "create" , "--detach" , "--no-resolve-image" , "--name" , name3 , "busybox" , "top" )
2019-04-04 09:23:19 -04:00
assert . NilError ( c , err , out )
assert . Assert ( c , strings . TrimSpace ( out ) != "" )
2016-07-13 22:09:07 -04:00
filter1 := "name=redis-cluster-md5"
filter2 := "name=redis-cluster"
// We search checker.Contains with `name+" "` to prevent prefix only.
out , err = d . Cmd ( "service" , "ls" , "--filter" , filter1 )
2019-04-04 09:23:19 -04:00
assert . NilError ( c , err , out )
2019-09-09 17:05:55 -04:00
assert . Assert ( c , out , checker . Contains , name1 + " " )
assert . Assert ( c , out , checker . Not ( checker . Contains ) , name2 + " " )
assert . Assert ( c , out , checker . Not ( checker . Contains ) , name3 + " " )
2016-07-13 22:09:07 -04:00
out , err = d . Cmd ( "service" , "ls" , "--filter" , filter2 )
2019-04-04 09:23:19 -04:00
assert . NilError ( c , err , out )
2019-09-09 17:05:55 -04:00
assert . Assert ( c , out , checker . Contains , name1 + " " )
assert . Assert ( c , out , checker . Contains , name2 + " " )
assert . Assert ( c , out , checker . Not ( checker . Contains ) , name3 + " " )
2016-07-13 22:09:07 -04:00
out , err = d . Cmd ( "service" , "ls" )
2019-04-04 09:23:19 -04:00
assert . NilError ( c , err , out )
2019-09-09 17:05:55 -04:00
assert . Assert ( c , out , checker . Contains , name1 + " " )
assert . Assert ( c , out , checker . Contains , name2 + " " )
assert . Assert ( c , out , checker . Contains , name3 + " " )
2016-07-13 22:09:07 -04:00
}
2016-07-17 16:21:29 -04:00
2019-09-09 17:05:55 -04:00
func ( s * DockerSwarmSuite ) TestSwarmNodeListFilter ( c * testing . T ) {
2016-07-17 16:21:29 -04:00
d := s . AddDaemon ( c , true , true )
out , err := d . Cmd ( "node" , "inspect" , "--format" , "{{ .Description.Hostname }}" , "self" )
2019-04-04 09:23:19 -04:00
assert . NilError ( c , err , out )
assert . Assert ( c , strings . TrimSpace ( out ) != "" )
2016-07-17 16:21:29 -04:00
name := strings . TrimSpace ( out )
filter := "name=" + name [ : 4 ]
out , err = d . Cmd ( "node" , "ls" , "--filter" , filter )
2019-04-04 09:23:19 -04:00
assert . NilError ( c , err , out )
2019-09-09 17:05:55 -04:00
assert . Assert ( c , out , checker . Contains , name )
2016-07-17 16:21:29 -04:00
out , err = d . Cmd ( "node" , "ls" , "--filter" , "name=none" )
2019-04-04 09:23:19 -04:00
assert . NilError ( c , err , out )
2019-09-09 17:05:55 -04:00
assert . Assert ( c , out , checker . Not ( checker . Contains ) , name )
2016-07-17 16:21:29 -04:00
}
2019-09-09 17:05:55 -04:00
func ( s * DockerSwarmSuite ) TestSwarmNodeTaskListFilter ( c * testing . T ) {
2016-07-17 16:21:29 -04:00
d := s . AddDaemon ( c , true , true )
name := "redis-cluster-md5"
2017-09-27 19:17:55 -04:00
out , err := d . Cmd ( "service" , "create" , "--detach" , "--no-resolve-image" , "--name" , name , "--replicas=3" , "busybox" , "top" )
2019-04-04 09:23:19 -04:00
assert . NilError ( c , err , out )
assert . Assert ( c , strings . TrimSpace ( out ) != "" )
2016-07-17 16:21:29 -04:00
2016-07-26 14:40:15 -04:00
// make sure task has been deployed.
2016-12-09 04:17:53 -05:00
waitAndAssert ( c , defaultReconciliationTimeout , d . CheckActiveContainerCount , checker . Equals , 3 )
2016-07-26 14:40:15 -04:00
2016-07-17 16:21:29 -04:00
filter := "name=redis-cluster"
2016-07-19 17:01:31 -04:00
out , err = d . Cmd ( "node" , "ps" , "--filter" , filter , "self" )
2019-04-04 09:23:19 -04:00
assert . NilError ( c , err , out )
2019-09-09 17:05:55 -04:00
assert . Assert ( c , out , checker . Contains , name + ".1" )
assert . Assert ( c , out , checker . Contains , name + ".2" )
assert . Assert ( c , out , checker . Contains , name + ".3" )
2016-07-17 16:21:29 -04:00
2016-07-19 17:01:31 -04:00
out , err = d . Cmd ( "node" , "ps" , "--filter" , "name=none" , "self" )
2019-04-04 09:23:19 -04:00
assert . NilError ( c , err , out )
2019-09-09 17:05:55 -04:00
assert . Assert ( c , out , checker . Not ( checker . Contains ) , name + ".1" )
assert . Assert ( c , out , checker . Not ( checker . Contains ) , name + ".2" )
assert . Assert ( c , out , checker . Not ( checker . Contains ) , name + ".3" )
2016-07-17 16:21:29 -04:00
}
2016-08-04 23:51:28 -04:00
// Test case for #25375
2019-09-09 17:05:55 -04:00
func ( s * DockerSwarmSuite ) TestSwarmPublishAdd ( c * testing . T ) {
2016-08-04 23:51:28 -04:00
d := s . AddDaemon ( c , true , true )
2016-12-25 16:23:35 -05:00
name := "top"
2019-07-18 13:58:21 -04:00
// this first command does not have to be retried because service creates
// don't return out of sequence errors.
2017-09-27 19:17:55 -04:00
out , err := d . Cmd ( "service" , "create" , "--detach" , "--no-resolve-image" , "--name" , name , "--label" , "x=y" , "busybox" , "top" )
2019-04-04 09:23:19 -04:00
assert . NilError ( c , err , out )
assert . Assert ( c , strings . TrimSpace ( out ) != "" )
2016-08-04 23:51:28 -04:00
2019-07-18 13:58:21 -04:00
out , err = d . CmdRetryOutOfSequence ( "service" , "update" , "--detach" , "--publish-add" , "80:80" , name )
2019-04-04 09:23:19 -04:00
assert . NilError ( c , err , out )
2016-08-04 23:51:28 -04:00
2019-07-18 13:58:21 -04:00
out , err = d . CmdRetryOutOfSequence ( "service" , "update" , "--detach" , "--publish-add" , "80:80" , name )
2019-04-04 09:23:19 -04:00
assert . NilError ( c , err , out )
2016-08-04 23:51:28 -04:00
2019-07-18 13:58:21 -04:00
_ , err = d . CmdRetryOutOfSequence ( "service" , "update" , "--detach" , "--publish-add" , "80:80" , "--publish-add" , "80:20" , name )
2019-04-04 09:23:19 -04:00
assert . ErrorContains ( c , err , "" )
2016-12-08 16:32:10 -05:00
2019-07-18 13:58:21 -04:00
// this last command does not have to be retried because service inspect
// does not return out of sequence errors.
2016-12-25 16:23:35 -05:00
out , err = d . Cmd ( "service" , "inspect" , "--format" , "{{ .Spec.EndpointSpec.Ports }}" , name )
2019-04-04 09:23:19 -04:00
assert . NilError ( c , err , out )
assert . Equal ( c , strings . TrimSpace ( out ) , "[{ tcp 80 80 ingress}]" )
2016-08-04 23:51:28 -04:00
}
2016-08-01 21:34:51 -04:00
2019-09-09 17:05:55 -04:00
func ( s * DockerSwarmSuite ) TestSwarmServiceWithGroup ( c * testing . T ) {
2016-08-01 21:34:51 -04:00
d := s . AddDaemon ( c , true , true )
name := "top"
2017-09-27 19:17:55 -04:00
out , err := d . Cmd ( "service" , "create" , "--detach" , "--no-resolve-image" , "--name" , name , "--user" , "root:root" , "--group" , "wheel" , "--group" , "audio" , "--group" , "staff" , "--group" , "777" , "busybox" , "top" )
2019-04-04 09:23:19 -04:00
assert . NilError ( c , err , out )
assert . Assert ( c , strings . TrimSpace ( out ) != "" )
2016-08-01 21:34:51 -04:00
// make sure task has been deployed.
2016-12-09 04:17:53 -05:00
waitAndAssert ( c , defaultReconciliationTimeout , d . CheckActiveContainerCount , checker . Equals , 1 )
2016-08-01 21:34:51 -04:00
out , err = d . Cmd ( "ps" , "-q" )
2019-04-04 09:23:19 -04:00
assert . NilError ( c , err , out )
assert . Assert ( c , strings . TrimSpace ( out ) != "" )
2016-08-01 21:34:51 -04:00
container := strings . TrimSpace ( out )
2016-09-20 15:07:30 -04:00
out , err = d . Cmd ( "exec" , container , "id" )
2019-04-04 09:23:19 -04:00
assert . NilError ( c , err , out )
assert . Equal ( c , strings . TrimSpace ( out ) , "uid=0(root) gid=0(root) groups=10(wheel),29(audio),50(staff),777" )
2016-08-01 21:34:51 -04:00
}
2016-09-09 12:55:57 -04:00
2019-09-09 17:05:55 -04:00
func ( s * DockerSwarmSuite ) TestSwarmContainerAutoStart ( c * testing . T ) {
2016-09-09 12:55:57 -04:00
d := s . AddDaemon ( c , true , true )
out , err := d . Cmd ( "network" , "create" , "--attachable" , "-d" , "overlay" , "foo" )
2019-04-04 09:23:19 -04:00
assert . NilError ( c , err , out )
assert . Assert ( c , strings . TrimSpace ( out ) != "" )
2016-09-09 12:55:57 -04:00
out , err = d . Cmd ( "run" , "-id" , "--restart=always" , "--net=foo" , "--name=test" , "busybox" , "top" )
2019-04-04 09:23:19 -04:00
assert . NilError ( c , err , out )
assert . Assert ( c , strings . TrimSpace ( out ) != "" )
2016-09-09 12:55:57 -04:00
out , err = d . Cmd ( "ps" , "-q" )
2019-04-04 09:23:19 -04:00
assert . NilError ( c , err , out )
assert . Assert ( c , strings . TrimSpace ( out ) != "" )
2016-09-09 12:55:57 -04:00
2018-10-25 14:47:56 -04:00
d . RestartNode ( c )
2016-09-09 12:55:57 -04:00
out , err = d . Cmd ( "ps" , "-q" )
2019-04-04 09:23:19 -04:00
assert . NilError ( c , err , out )
assert . Assert ( c , strings . TrimSpace ( out ) != "" )
2016-09-09 12:55:57 -04:00
}
2016-09-14 22:16:08 -04:00
2019-09-09 17:05:55 -04:00
func ( s * DockerSwarmSuite ) TestSwarmContainerEndpointOptions ( c * testing . T ) {
2016-10-29 18:02:15 -04:00
d := s . AddDaemon ( c , true , true )
out , err := d . Cmd ( "network" , "create" , "--attachable" , "-d" , "overlay" , "foo" )
2019-04-04 09:23:19 -04:00
assert . NilError ( c , err , out )
assert . Assert ( c , strings . TrimSpace ( out ) != "" )
2016-10-29 18:02:15 -04:00
2018-10-03 02:38:47 -04:00
out , err = d . Cmd ( "run" , "-d" , "--net=foo" , "--name=first" , "--net-alias=first-alias" , "busybox:glibc" , "top" )
2019-04-04 09:23:19 -04:00
assert . NilError ( c , err , out )
2016-10-29 18:02:15 -04:00
2018-10-03 02:38:47 -04:00
out , err = d . Cmd ( "run" , "-d" , "--net=foo" , "--name=second" , "busybox:glibc" , "top" )
2019-04-04 09:23:19 -04:00
assert . NilError ( c , err , out )
2016-10-29 18:02:15 -04:00
2018-10-03 02:38:47 -04:00
out , err = d . Cmd ( "run" , "-d" , "--net=foo" , "--net-alias=third-alias" , "busybox:glibc" , "top" )
2019-04-04 09:23:19 -04:00
assert . NilError ( c , err , out )
2017-03-03 16:04:04 -05:00
// ping first container and its alias, also ping third and anonymous container by its alias
2018-10-03 02:38:47 -04:00
out , err = d . Cmd ( "exec" , "second" , "ping" , "-c" , "1" , "first" )
2019-04-04 09:23:19 -04:00
assert . NilError ( c , err , out )
2018-10-03 02:38:47 -04:00
out , err = d . Cmd ( "exec" , "second" , "ping" , "-c" , "1" , "first-alias" )
2019-04-04 09:23:19 -04:00
assert . NilError ( c , err , out )
2018-10-03 02:38:47 -04:00
out , err = d . Cmd ( "exec" , "second" , "ping" , "-c" , "1" , "third-alias" )
2019-04-04 09:23:19 -04:00
assert . NilError ( c , err , out )
2016-10-29 18:02:15 -04:00
}
2019-09-09 17:05:55 -04:00
func ( s * DockerSwarmSuite ) TestSwarmContainerAttachByNetworkId ( c * testing . T ) {
2016-11-03 18:44:45 -04:00
d := s . AddDaemon ( c , true , true )
out , err := d . Cmd ( "network" , "create" , "--attachable" , "-d" , "overlay" , "testnet" )
2019-04-04 09:23:19 -04:00
assert . NilError ( c , err , out )
assert . Assert ( c , strings . TrimSpace ( out ) != "" )
2016-11-03 18:44:45 -04:00
networkID := strings . TrimSpace ( out )
out , err = d . Cmd ( "run" , "-d" , "--net" , networkID , "busybox" , "top" )
2019-04-04 09:23:19 -04:00
assert . NilError ( c , err , out )
2016-11-03 18:44:45 -04:00
cID := strings . TrimSpace ( out )
2016-12-09 04:17:53 -05:00
d . WaitRun ( cID )
2016-11-03 18:44:45 -04:00
2018-08-14 03:51:22 -04:00
out , err = d . Cmd ( "rm" , "-f" , cID )
2019-04-04 09:23:19 -04:00
assert . NilError ( c , err , out )
2016-11-03 18:44:45 -04:00
2018-08-14 03:51:22 -04:00
out , err = d . Cmd ( "network" , "rm" , "testnet" )
2019-04-04 09:23:19 -04:00
assert . NilError ( c , err , out )
2016-11-03 18:44:45 -04:00
2019-09-09 17:05:55 -04:00
checkNetwork := func ( * testing . T ) ( interface { } , check . CommentInterface ) {
2016-11-03 18:44:45 -04:00
out , err := d . Cmd ( "network" , "ls" )
2019-04-04 09:23:19 -04:00
assert . NilError ( c , err )
2016-11-03 18:44:45 -04:00
return out , nil
}
waitAndAssert ( c , 3 * time . Second , checkNetwork , checker . Not ( checker . Contains ) , "testnet" )
}
2019-09-09 17:05:55 -04:00
func ( s * DockerSwarmSuite ) TestOverlayAttachable ( c * testing . T ) {
2016-11-29 17:05:12 -05:00
d := s . AddDaemon ( c , true , true )
2016-11-22 14:33:00 -05:00
2016-11-29 17:05:12 -05:00
out , err := d . Cmd ( "network" , "create" , "-d" , "overlay" , "--attachable" , "ovnet" )
2019-04-04 09:23:19 -04:00
assert . NilError ( c , err , out )
2016-11-22 14:33:00 -05:00
// validate attachable
2016-11-29 17:05:12 -05:00
out , err = d . Cmd ( "network" , "inspect" , "--format" , "{{json .Attachable}}" , "ovnet" )
2019-04-04 09:23:19 -04:00
assert . NilError ( c , err , out )
assert . Equal ( c , strings . TrimSpace ( out ) , "true" )
2016-11-22 14:33:00 -05:00
2018-10-05 14:43:14 -04:00
// validate containers can attach to this overlay network
2016-11-29 17:05:12 -05:00
out , err = d . Cmd ( "run" , "-d" , "--network" , "ovnet" , "--name" , "c1" , "busybox" , "top" )
2019-04-04 09:23:19 -04:00
assert . NilError ( c , err , out )
2016-11-22 14:33:00 -05:00
// redo validation, there was a bug that the value of attachable changes after
// containers attach to the network
2016-11-29 17:05:12 -05:00
out , err = d . Cmd ( "network" , "inspect" , "--format" , "{{json .Attachable}}" , "ovnet" )
2019-04-04 09:23:19 -04:00
assert . NilError ( c , err , out )
assert . Equal ( c , strings . TrimSpace ( out ) , "true" )
2016-11-22 14:33:00 -05:00
}
2019-09-09 17:05:55 -04:00
func ( s * DockerSwarmSuite ) TestOverlayAttachableOnSwarmLeave ( c * testing . T ) {
2017-01-13 23:14:03 -05:00
d := s . AddDaemon ( c , true , true )
// Create an attachable swarm network
nwName := "attovl"
out , err := d . Cmd ( "network" , "create" , "-d" , "overlay" , "--attachable" , nwName )
2019-04-04 09:23:19 -04:00
assert . NilError ( c , err , out )
2017-01-13 23:14:03 -05:00
// Connect a container to the network
out , err = d . Cmd ( "run" , "-d" , "--network" , nwName , "--name" , "c1" , "busybox" , "top" )
2019-04-04 09:23:19 -04:00
assert . NilError ( c , err , out )
2017-01-13 23:14:03 -05:00
// Leave the swarm
2019-09-09 17:05:55 -04:00
assert . Assert ( c , d . SwarmLeave ( c , true ) , checker . IsNil )
2017-01-13 23:14:03 -05:00
// Check the container is disconnected
out , err = d . Cmd ( "inspect" , "c1" , "--format" , "{{.NetworkSettings.Networks." + nwName + "}}" )
2019-04-04 09:23:19 -04:00
assert . NilError ( c , err , out )
assert . Equal ( c , strings . TrimSpace ( out ) , "<no value>" )
2017-01-13 23:14:03 -05:00
// Check the network is gone
out , err = d . Cmd ( "network" , "ls" , "--format" , "{{.Name}}" )
2019-04-04 09:23:19 -04:00
assert . NilError ( c , err , out )
2019-09-09 17:05:55 -04:00
assert . Assert ( c , out , checker . Not ( checker . Contains ) , nwName )
2017-01-13 23:14:03 -05:00
}
2019-09-09 17:05:55 -04:00
func ( s * DockerSwarmSuite ) TestOverlayAttachableReleaseResourcesOnFailure ( c * testing . T ) {
2017-02-15 22:53:51 -05:00
d := s . AddDaemon ( c , true , true )
// Create attachable network
out , err := d . Cmd ( "network" , "create" , "-d" , "overlay" , "--attachable" , "--subnet" , "10.10.9.0/24" , "ovnet" )
2019-04-04 09:23:19 -04:00
assert . NilError ( c , err , out )
2017-02-15 22:53:51 -05:00
// Attach a container with specific IP
out , err = d . Cmd ( "run" , "-d" , "--network" , "ovnet" , "--name" , "c1" , "--ip" , "10.10.9.33" , "busybox" , "top" )
2019-04-04 09:23:19 -04:00
assert . NilError ( c , err , out )
2017-02-15 22:53:51 -05:00
2017-06-01 07:21:01 -04:00
// Attempt to attach another container with same IP, must fail
2018-08-14 03:51:22 -04:00
out , err = d . Cmd ( "run" , "-d" , "--network" , "ovnet" , "--name" , "c2" , "--ip" , "10.10.9.33" , "busybox" , "top" )
2019-04-04 09:23:19 -04:00
assert . ErrorContains ( c , err , "" , out )
2017-02-15 22:53:51 -05:00
// Remove first container
out , err = d . Cmd ( "rm" , "-f" , "c1" )
2019-04-04 09:23:19 -04:00
assert . NilError ( c , err , out )
2017-02-15 22:53:51 -05:00
// Verify the network can be removed, no phantom network attachment task left over
out , err = d . Cmd ( "network" , "rm" , "ovnet" )
2019-04-04 09:23:19 -04:00
assert . NilError ( c , err , out )
2017-02-15 22:53:51 -05:00
}
2019-09-09 17:05:55 -04:00
func ( s * DockerSwarmSuite ) TestSwarmIngressNetwork ( c * testing . T ) {
2016-09-14 22:16:08 -04:00
d := s . AddDaemon ( c , true , true )
2017-03-09 14:52:25 -05:00
// Ingress network can be removed
2017-08-22 17:07:52 -04:00
removeNetwork := func ( name string ) * icmd . Result {
return cli . Docker (
cli . Args ( "-H" , d . Sock ( ) , "network" , "rm" , name ) ,
cli . WithStdin ( strings . NewReader ( "Y" ) ) )
}
result := removeNetwork ( "ingress" )
result . Assert ( c , icmd . Success )
2017-03-09 14:52:25 -05:00
// And recreated
2017-08-22 17:07:52 -04:00
out , err := d . Cmd ( "network" , "create" , "-d" , "overlay" , "--ingress" , "new-ingress" )
2019-04-04 09:23:19 -04:00
assert . NilError ( c , err , out )
2017-03-09 14:52:25 -05:00
// But only one is allowed
out , err = d . Cmd ( "network" , "create" , "-d" , "overlay" , "--ingress" , "another-ingress" )
2019-04-04 09:23:19 -04:00
assert . ErrorContains ( c , err , "" )
2019-09-09 17:05:55 -04:00
assert . Assert ( c , strings . TrimSpace ( out ) , checker . Contains , "is already present" )
2017-03-09 14:52:25 -05:00
// It cannot be removed if it is being used
2017-09-27 19:17:55 -04:00
out , err = d . Cmd ( "service" , "create" , "--detach" , "--no-resolve-image" , "--name" , "srv1" , "-p" , "9000:8000" , "busybox" , "top" )
2019-04-04 09:23:19 -04:00
assert . NilError ( c , err , out )
2017-08-22 17:07:52 -04:00
result = removeNetwork ( "new-ingress" )
result . Assert ( c , icmd . Expected {
ExitCode : 1 ,
Err : "ingress network cannot be removed because service" ,
} )
2017-03-09 14:52:25 -05:00
// But it can be removed once no more services depend on it
2017-09-27 19:17:55 -04:00
out , err = d . Cmd ( "service" , "update" , "--detach" , "--publish-rm" , "9000:8000" , "srv1" )
2019-04-04 09:23:19 -04:00
assert . NilError ( c , err , out )
2017-08-22 17:07:52 -04:00
result = removeNetwork ( "new-ingress" )
result . Assert ( c , icmd . Success )
2017-03-09 14:52:25 -05:00
// A service which needs the ingress network cannot be created if no ingress is present
2017-09-27 19:17:55 -04:00
out , err = d . Cmd ( "service" , "create" , "--detach" , "--no-resolve-image" , "--name" , "srv2" , "-p" , "500:500" , "busybox" , "top" )
2019-04-04 09:23:19 -04:00
assert . ErrorContains ( c , err , "" )
2019-09-09 17:05:55 -04:00
assert . Assert ( c , strings . TrimSpace ( out ) , checker . Contains , "no ingress network is present" )
2017-03-09 14:52:25 -05:00
// An existing service cannot be updated to use the ingress nw if the nw is not present
2017-09-27 19:17:55 -04:00
out , err = d . Cmd ( "service" , "update" , "--detach" , "--publish-add" , "9000:8000" , "srv1" )
2019-04-04 09:23:19 -04:00
assert . ErrorContains ( c , err , "" )
2019-09-09 17:05:55 -04:00
assert . Assert ( c , strings . TrimSpace ( out ) , checker . Contains , "no ingress network is present" )
2017-03-09 14:52:25 -05:00
// But services which do not need routing mesh can be created regardless
2017-09-27 19:17:55 -04:00
out , err = d . Cmd ( "service" , "create" , "--detach" , "--no-resolve-image" , "--name" , "srv3" , "--endpoint-mode" , "dnsrr" , "busybox" , "top" )
2019-04-04 09:23:19 -04:00
assert . NilError ( c , err , out )
2016-09-14 22:16:08 -04:00
}
2016-07-23 12:58:58 -04:00
2019-09-09 17:05:55 -04:00
func ( s * DockerSwarmSuite ) TestSwarmCreateServiceWithNoIngressNetwork ( c * testing . T ) {
2017-03-30 19:12:48 -04:00
d := s . AddDaemon ( c , true , true )
// Remove ingress network
2017-08-22 17:07:52 -04:00
result := cli . Docker (
cli . Args ( "-H" , d . Sock ( ) , "network" , "rm" , "ingress" ) ,
cli . WithStdin ( strings . NewReader ( "Y" ) ) )
result . Assert ( c , icmd . Success )
2017-03-30 19:12:48 -04:00
// Create a overlay network and launch a service on it
// Make sure nothing panics because ingress network is missing
2017-08-22 17:07:52 -04:00
out , err := d . Cmd ( "network" , "create" , "-d" , "overlay" , "another-network" )
2019-04-04 09:23:19 -04:00
assert . NilError ( c , err , out )
2017-09-27 19:17:55 -04:00
out , err = d . Cmd ( "service" , "create" , "--detach" , "--no-resolve-image" , "--name" , "srv4" , "--network" , "another-network" , "busybox" , "top" )
2019-04-04 09:23:19 -04:00
assert . NilError ( c , err , out )
2017-03-30 19:12:48 -04:00
}
2016-07-23 12:58:58 -04:00
// Test case for #24108, also the case from:
// https://github.com/docker/docker/pull/24620#issuecomment-233715656
2019-09-09 17:05:55 -04:00
func ( s * DockerSwarmSuite ) TestSwarmTaskListFilter ( c * testing . T ) {
2016-07-23 12:58:58 -04:00
d := s . AddDaemon ( c , true , true )
name := "redis-cluster-md5"
2017-09-27 19:17:55 -04:00
out , err := d . Cmd ( "service" , "create" , "--detach" , "--no-resolve-image" , "--name" , name , "--replicas=3" , "busybox" , "top" )
2019-04-04 09:23:19 -04:00
assert . NilError ( c , err , out )
assert . Assert ( c , strings . TrimSpace ( out ) != "" )
2016-07-23 12:58:58 -04:00
filter := "name=redis-cluster"
2019-09-09 17:05:55 -04:00
checkNumTasks := func ( * testing . T ) ( interface { } , check . CommentInterface ) {
2016-10-11 14:50:35 -04:00
out , err := d . Cmd ( "service" , "ps" , "--filter" , filter , name )
2019-04-04 09:23:19 -04:00
assert . NilError ( c , err , out )
2016-10-11 14:50:35 -04:00
return len ( strings . Split ( out , "\n" ) ) - 2 , nil // includes header and nl in last line
}
// wait until all tasks have been created
waitAndAssert ( c , defaultReconciliationTimeout , checkNumTasks , checker . Equals , 3 )
2016-07-23 12:58:58 -04:00
out , err = d . Cmd ( "service" , "ps" , "--filter" , filter , name )
2019-04-04 09:23:19 -04:00
assert . NilError ( c , err , out )
2019-09-09 17:05:55 -04:00
assert . Assert ( c , out , checker . Contains , name + ".1" )
assert . Assert ( c , out , checker . Contains , name + ".2" )
assert . Assert ( c , out , checker . Contains , name + ".3" )
2016-07-23 12:58:58 -04:00
out , err = d . Cmd ( "service" , "ps" , "--filter" , "name=" + name + ".1" , name )
2019-04-04 09:23:19 -04:00
assert . NilError ( c , err , out )
2019-09-09 17:05:55 -04:00
assert . Assert ( c , out , checker . Contains , name + ".1" )
assert . Assert ( c , out , checker . Not ( checker . Contains ) , name + ".2" )
assert . Assert ( c , out , checker . Not ( checker . Contains ) , name + ".3" )
2016-07-23 12:58:58 -04:00
out , err = d . Cmd ( "service" , "ps" , "--filter" , "name=none" , name )
2019-04-04 09:23:19 -04:00
assert . NilError ( c , err , out )
2019-09-09 17:05:55 -04:00
assert . Assert ( c , out , checker . Not ( checker . Contains ) , name + ".1" )
assert . Assert ( c , out , checker . Not ( checker . Contains ) , name + ".2" )
assert . Assert ( c , out , checker . Not ( checker . Contains ) , name + ".3" )
2016-07-23 12:58:58 -04:00
name = "redis-cluster-sha1"
2017-09-27 19:17:55 -04:00
out , err = d . Cmd ( "service" , "create" , "--detach" , "--no-resolve-image" , "--name" , name , "--mode=global" , "busybox" , "top" )
2019-04-04 09:23:19 -04:00
assert . NilError ( c , err , out )
assert . Assert ( c , strings . TrimSpace ( out ) != "" )
2016-07-23 12:58:58 -04:00
2016-10-11 14:50:35 -04:00
waitAndAssert ( c , defaultReconciliationTimeout , checkNumTasks , checker . Equals , 1 )
2016-07-23 12:58:58 -04:00
filter = "name=redis-cluster"
out , err = d . Cmd ( "service" , "ps" , "--filter" , filter , name )
2019-04-04 09:23:19 -04:00
assert . NilError ( c , err , out )
2019-09-09 17:05:55 -04:00
assert . Assert ( c , out , checker . Contains , name )
2016-07-23 12:58:58 -04:00
out , err = d . Cmd ( "service" , "ps" , "--filter" , "name=" + name , name )
2019-04-04 09:23:19 -04:00
assert . NilError ( c , err , out )
2019-09-09 17:05:55 -04:00
assert . Assert ( c , out , checker . Contains , name )
2016-07-23 12:58:58 -04:00
out , err = d . Cmd ( "service" , "ps" , "--filter" , "name=none" , name )
2019-04-04 09:23:19 -04:00
assert . NilError ( c , err , out )
2019-09-09 17:05:55 -04:00
assert . Assert ( c , out , checker . Not ( checker . Contains ) , name )
2016-07-23 12:58:58 -04:00
}
2016-09-28 06:45:30 -04:00
2019-09-09 17:05:55 -04:00
func ( s * DockerSwarmSuite ) TestPsListContainersFilterIsTask ( c * testing . T ) {
2016-09-28 06:45:30 -04:00
d := s . AddDaemon ( c , true , true )
// Create a bare container
out , err := d . Cmd ( "run" , "-d" , "--name=bare-container" , "busybox" , "top" )
2019-04-04 09:23:19 -04:00
assert . NilError ( c , err , out )
2016-09-28 06:45:30 -04:00
bareID := strings . TrimSpace ( out ) [ : 12 ]
// Create a service
name := "busybox-top"
2017-09-27 19:17:55 -04:00
out , err = d . Cmd ( "service" , "create" , "--detach" , "--no-resolve-image" , "--name" , name , "busybox" , "top" )
2019-04-04 09:23:19 -04:00
assert . NilError ( c , err , out )
assert . Assert ( c , strings . TrimSpace ( out ) != "" )
2016-09-28 06:45:30 -04:00
// make sure task has been deployed.
2016-12-09 04:17:53 -05:00
waitAndAssert ( c , defaultReconciliationTimeout , d . CheckServiceRunningTasks ( name ) , checker . Equals , 1 )
2016-09-28 06:45:30 -04:00
// Filter non-tasks
out , err = d . Cmd ( "ps" , "-a" , "-q" , "--filter=is-task=false" )
2019-04-04 09:23:19 -04:00
assert . NilError ( c , err , out )
2016-09-28 06:45:30 -04:00
psOut := strings . TrimSpace ( out )
2019-09-09 17:05:55 -04:00
assert . Assert ( c , psOut , checker . Equals , bareID , check . Commentf ( "Expected id %s, got %s for is-task label, output %q" , bareID , psOut , out ) )
2016-09-28 06:45:30 -04:00
// Filter tasks
out , err = d . Cmd ( "ps" , "-a" , "-q" , "--filter=is-task=true" )
2019-04-04 09:23:19 -04:00
assert . NilError ( c , err , out )
2016-09-28 06:45:30 -04:00
lines := strings . Split ( strings . Trim ( out , "\n " ) , "\n" )
2019-04-04 09:23:19 -04:00
assert . Equal ( c , len ( lines ) , 1 )
2019-09-09 17:05:56 -04:00
assert . Assert ( c , lines [ 0 ] != bareID , check . Commentf ( "Expected not %s, but got it for is-task label, output %q" , bareID , out ) )
2016-09-28 06:45:30 -04:00
}
2016-10-15 13:20:34 -04:00
const globalNetworkPlugin = "global-network-plugin"
const globalIPAMPlugin = "global-ipam-plugin"
2019-09-09 17:05:55 -04:00
func setupRemoteGlobalNetworkPlugin ( c * testing . T , mux * http . ServeMux , url , netDrv , ipamDrv string ) {
2016-10-15 13:20:34 -04:00
mux . HandleFunc ( "/Plugin.Activate" , func ( w http . ResponseWriter , r * http . Request ) {
w . Header ( ) . Set ( "Content-Type" , "application/vnd.docker.plugins.v1+json" )
fmt . Fprintf ( w , ` { "Implements": ["%s", "%s"]} ` , driverapi . NetworkPluginEndpointType , ipamapi . PluginEndpointType )
} )
// Network driver implementation
mux . HandleFunc ( fmt . Sprintf ( "/%s.GetCapabilities" , driverapi . NetworkPluginEndpointType ) , func ( w http . ResponseWriter , r * http . Request ) {
w . Header ( ) . Set ( "Content-Type" , "application/vnd.docker.plugins.v1+json" )
fmt . Fprintf ( w , ` { "Scope":"global"} ` )
} )
mux . HandleFunc ( fmt . Sprintf ( "/%s.AllocateNetwork" , driverapi . NetworkPluginEndpointType ) , func ( w http . ResponseWriter , r * http . Request ) {
err := json . NewDecoder ( r . Body ) . Decode ( & remoteDriverNetworkRequest )
if err != nil {
http . Error ( w , "Unable to decode JSON payload: " + err . Error ( ) , http . StatusBadRequest )
return
}
w . Header ( ) . Set ( "Content-Type" , "application/vnd.docker.plugins.v1+json" )
fmt . Fprintf ( w , "null" )
} )
mux . HandleFunc ( fmt . Sprintf ( "/%s.FreeNetwork" , driverapi . NetworkPluginEndpointType ) , func ( w http . ResponseWriter , r * http . Request ) {
w . Header ( ) . Set ( "Content-Type" , "application/vnd.docker.plugins.v1+json" )
fmt . Fprintf ( w , "null" )
} )
mux . HandleFunc ( fmt . Sprintf ( "/%s.CreateNetwork" , driverapi . NetworkPluginEndpointType ) , func ( w http . ResponseWriter , r * http . Request ) {
err := json . NewDecoder ( r . Body ) . Decode ( & remoteDriverNetworkRequest )
if err != nil {
http . Error ( w , "Unable to decode JSON payload: " + err . Error ( ) , http . StatusBadRequest )
return
}
w . Header ( ) . Set ( "Content-Type" , "application/vnd.docker.plugins.v1+json" )
fmt . Fprintf ( w , "null" )
} )
mux . HandleFunc ( fmt . Sprintf ( "/%s.DeleteNetwork" , driverapi . NetworkPluginEndpointType ) , func ( w http . ResponseWriter , r * http . Request ) {
w . Header ( ) . Set ( "Content-Type" , "application/vnd.docker.plugins.v1+json" )
fmt . Fprintf ( w , "null" )
} )
mux . HandleFunc ( fmt . Sprintf ( "/%s.CreateEndpoint" , driverapi . NetworkPluginEndpointType ) , func ( w http . ResponseWriter , r * http . Request ) {
w . Header ( ) . Set ( "Content-Type" , "application/vnd.docker.plugins.v1+json" )
fmt . Fprintf ( w , ` { "Interface": { "MacAddress":"a0:b1:c2:d3:e4:f5"}} ` )
} )
mux . HandleFunc ( fmt . Sprintf ( "/%s.Join" , driverapi . NetworkPluginEndpointType ) , func ( w http . ResponseWriter , r * http . Request ) {
w . Header ( ) . Set ( "Content-Type" , "application/vnd.docker.plugins.v1+json" )
veth := & netlink . Veth {
LinkAttrs : netlink . LinkAttrs { Name : "randomIfName" , TxQLen : 0 } , PeerName : "cnt0" }
if err := netlink . LinkAdd ( veth ) ; err != nil {
fmt . Fprintf ( w , ` { "Error":"failed to add veth pair: ` + err . Error ( ) + ` "} ` )
} else {
fmt . Fprintf ( w , ` { "InterfaceName": { "SrcName":"cnt0", "DstPrefix":"veth"}} ` )
}
} )
mux . HandleFunc ( fmt . Sprintf ( "/%s.Leave" , driverapi . NetworkPluginEndpointType ) , func ( w http . ResponseWriter , r * http . Request ) {
w . Header ( ) . Set ( "Content-Type" , "application/vnd.docker.plugins.v1+json" )
fmt . Fprintf ( w , "null" )
} )
mux . HandleFunc ( fmt . Sprintf ( "/%s.DeleteEndpoint" , driverapi . NetworkPluginEndpointType ) , func ( w http . ResponseWriter , r * http . Request ) {
w . Header ( ) . Set ( "Content-Type" , "application/vnd.docker.plugins.v1+json" )
if link , err := netlink . LinkByName ( "cnt0" ) ; err == nil {
netlink . LinkDel ( link )
}
fmt . Fprintf ( w , "null" )
} )
// IPAM Driver implementation
var (
poolRequest remoteipam . RequestPoolRequest
poolReleaseReq remoteipam . ReleasePoolRequest
addressRequest remoteipam . RequestAddressRequest
addressReleaseReq remoteipam . ReleaseAddressRequest
lAS = "localAS"
gAS = "globalAS"
pool = "172.28.0.0/16"
poolID = lAS + "/" + pool
gw = "172.28.255.254/16"
)
mux . HandleFunc ( fmt . Sprintf ( "/%s.GetDefaultAddressSpaces" , ipamapi . PluginEndpointType ) , func ( w http . ResponseWriter , r * http . Request ) {
w . Header ( ) . Set ( "Content-Type" , "application/vnd.docker.plugins.v1+json" )
fmt . Fprintf ( w , ` { "LocalDefaultAddressSpace":" ` + lAS + ` ", "GlobalDefaultAddressSpace": " ` + gAS + ` "} ` )
} )
mux . HandleFunc ( fmt . Sprintf ( "/%s.RequestPool" , ipamapi . PluginEndpointType ) , func ( w http . ResponseWriter , r * http . Request ) {
err := json . NewDecoder ( r . Body ) . Decode ( & poolRequest )
if err != nil {
http . Error ( w , "Unable to decode JSON payload: " + err . Error ( ) , http . StatusBadRequest )
return
}
w . Header ( ) . Set ( "Content-Type" , "application/vnd.docker.plugins.v1+json" )
if poolRequest . AddressSpace != lAS && poolRequest . AddressSpace != gAS {
fmt . Fprintf ( w , ` { "Error":"Unknown address space in pool request: ` + poolRequest . AddressSpace + ` "} ` )
} else if poolRequest . Pool != "" && poolRequest . Pool != pool {
fmt . Fprintf ( w , ` { "Error":"Cannot handle explicit pool requests yet"} ` )
} else {
fmt . Fprintf ( w , ` { "PoolID":" ` + poolID + ` ", "Pool":" ` + pool + ` "} ` )
}
} )
mux . HandleFunc ( fmt . Sprintf ( "/%s.RequestAddress" , ipamapi . PluginEndpointType ) , func ( w http . ResponseWriter , r * http . Request ) {
err := json . NewDecoder ( r . Body ) . Decode ( & addressRequest )
if err != nil {
http . Error ( w , "Unable to decode JSON payload: " + err . Error ( ) , http . StatusBadRequest )
return
}
w . Header ( ) . Set ( "Content-Type" , "application/vnd.docker.plugins.v1+json" )
// make sure libnetwork is now querying on the expected pool id
if addressRequest . PoolID != poolID {
fmt . Fprintf ( w , ` { "Error":"unknown pool id"} ` )
} else if addressRequest . Address != "" {
fmt . Fprintf ( w , ` { "Error":"Cannot handle explicit address requests yet"} ` )
} else {
fmt . Fprintf ( w , ` { "Address":" ` + gw + ` "} ` )
}
} )
mux . HandleFunc ( fmt . Sprintf ( "/%s.ReleaseAddress" , ipamapi . PluginEndpointType ) , func ( w http . ResponseWriter , r * http . Request ) {
err := json . NewDecoder ( r . Body ) . Decode ( & addressReleaseReq )
if err != nil {
http . Error ( w , "Unable to decode JSON payload: " + err . Error ( ) , http . StatusBadRequest )
return
}
w . Header ( ) . Set ( "Content-Type" , "application/vnd.docker.plugins.v1+json" )
// make sure libnetwork is now asking to release the expected address from the expected poolid
if addressRequest . PoolID != poolID {
fmt . Fprintf ( w , ` { "Error":"unknown pool id"} ` )
} else if addressReleaseReq . Address != gw {
fmt . Fprintf ( w , ` { "Error":"unknown address"} ` )
} else {
fmt . Fprintf ( w , "null" )
}
} )
mux . HandleFunc ( fmt . Sprintf ( "/%s.ReleasePool" , ipamapi . PluginEndpointType ) , func ( w http . ResponseWriter , r * http . Request ) {
err := json . NewDecoder ( r . Body ) . Decode ( & poolReleaseReq )
if err != nil {
http . Error ( w , "Unable to decode JSON payload: " + err . Error ( ) , http . StatusBadRequest )
return
}
w . Header ( ) . Set ( "Content-Type" , "application/vnd.docker.plugins.v1+json" )
// make sure libnetwork is now asking to release the expected poolid
if addressRequest . PoolID != poolID {
fmt . Fprintf ( w , ` { "Error":"unknown pool id"} ` )
} else {
fmt . Fprintf ( w , "null" )
}
} )
err := os . MkdirAll ( "/etc/docker/plugins" , 0755 )
2019-04-04 09:23:19 -04:00
assert . NilError ( c , err )
2016-10-15 13:20:34 -04:00
fileName := fmt . Sprintf ( "/etc/docker/plugins/%s.spec" , netDrv )
err = ioutil . WriteFile ( fileName , [ ] byte ( url ) , 0644 )
2019-04-04 09:23:19 -04:00
assert . NilError ( c , err )
2016-10-15 13:20:34 -04:00
ipamFileName := fmt . Sprintf ( "/etc/docker/plugins/%s.spec" , ipamDrv )
err = ioutil . WriteFile ( ipamFileName , [ ] byte ( url ) , 0644 )
2019-04-04 09:23:19 -04:00
assert . NilError ( c , err )
2016-10-15 13:20:34 -04:00
}
2019-09-09 17:05:55 -04:00
func ( s * DockerSwarmSuite ) TestSwarmNetworkPlugin ( c * testing . T ) {
2016-12-21 18:21:55 -05:00
mux := http . NewServeMux ( )
s . server = httptest . NewServer ( mux )
2019-09-09 17:05:56 -04:00
assert . Assert ( c , s . server , checker . NotNil ) // check that HTTP server has started
2016-12-21 18:21:55 -05:00
setupRemoteGlobalNetworkPlugin ( c , mux , s . server . URL , globalNetworkPlugin , globalIPAMPlugin )
defer func ( ) {
s . server . Close ( )
err := os . RemoveAll ( "/etc/docker/plugins" )
2019-04-04 09:23:19 -04:00
assert . NilError ( c , err )
2016-12-21 18:21:55 -05:00
} ( )
2016-10-15 13:20:34 -04:00
d := s . AddDaemon ( c , true , true )
out , err := d . Cmd ( "network" , "create" , "-d" , globalNetworkPlugin , "foo" )
2019-04-04 09:23:19 -04:00
assert . ErrorContains ( c , err , "" , out )
2019-09-09 17:05:55 -04:00
assert . Assert ( c , out , checker . Contains , "not supported in swarm mode" )
2016-10-15 13:20:34 -04:00
}
2016-07-20 02:58:32 -04:00
// Test case for #24712
2019-09-09 17:05:55 -04:00
func ( s * DockerSwarmSuite ) TestSwarmServiceEnvFile ( c * testing . T ) {
2016-07-20 02:58:32 -04:00
d := s . AddDaemon ( c , true , true )
2016-12-09 04:17:53 -05:00
path := filepath . Join ( d . Folder , "env.txt" )
2016-07-20 02:58:32 -04:00
err := ioutil . WriteFile ( path , [ ] byte ( "VAR1=A\nVAR2=A\n" ) , 0644 )
2019-04-04 09:23:19 -04:00
assert . NilError ( c , err )
2016-07-20 02:58:32 -04:00
name := "worker"
2017-09-27 19:17:55 -04:00
out , err := d . Cmd ( "service" , "create" , "--detach" , "--no-resolve-image" , "--env-file" , path , "--env" , "VAR1=B" , "--env" , "VAR1=C" , "--env" , "VAR2=" , "--env" , "VAR2" , "--name" , name , "busybox" , "top" )
2019-04-04 09:23:19 -04:00
assert . NilError ( c , err , out )
assert . Assert ( c , strings . TrimSpace ( out ) != "" )
2016-07-20 02:58:32 -04:00
// The complete env is [VAR1=A VAR2=A VAR1=B VAR1=C VAR2= VAR2] and duplicates will be removed => [VAR1=C VAR2]
out , err = d . Cmd ( "inspect" , "--format" , "{{ .Spec.TaskTemplate.ContainerSpec.Env }}" , name )
2019-04-04 09:23:19 -04:00
assert . NilError ( c , err , out )
2019-09-09 17:05:55 -04:00
assert . Assert ( c , out , checker . Contains , "[VAR1=C VAR2]" )
2016-07-20 02:58:32 -04:00
}
2016-11-04 14:31:44 -04:00
2019-09-09 17:05:55 -04:00
func ( s * DockerSwarmSuite ) TestSwarmServiceTTY ( c * testing . T ) {
2016-11-04 14:31:44 -04:00
d := s . AddDaemon ( c , true , true )
name := "top"
2019-09-09 13:44:11 -04:00
ttyCheck := "if [ -t 0 ]; then echo TTY > /status; else echo none > /status; fi; exec top"
2016-11-04 14:31:44 -04:00
// Without --tty
expectedOutput := "none"
2018-08-14 03:51:22 -04:00
out , err := d . Cmd ( "service" , "create" , "--detach" , "--no-resolve-image" , "--name" , name , "busybox" , "sh" , "-c" , ttyCheck )
2019-04-04 09:23:19 -04:00
assert . NilError ( c , err , out )
2016-11-04 14:31:44 -04:00
// Make sure task has been deployed.
2016-12-09 04:17:53 -05:00
waitAndAssert ( c , defaultReconciliationTimeout , d . CheckActiveContainerCount , checker . Equals , 1 )
2016-11-04 14:31:44 -04:00
// We need to get the container id.
2018-08-14 03:51:22 -04:00
out , err = d . Cmd ( "ps" , "-q" , "--no-trunc" )
2019-04-04 09:23:19 -04:00
assert . NilError ( c , err , out )
2016-11-04 14:31:44 -04:00
id := strings . TrimSpace ( out )
out , err = d . Cmd ( "exec" , id , "cat" , "/status" )
2019-04-04 09:23:19 -04:00
assert . NilError ( c , err , out )
2019-09-09 17:05:55 -04:00
assert . Assert ( c , out , checker . Contains , expectedOutput , check . Commentf ( "Expected '%s', but got %q" , expectedOutput , out ) )
2016-11-04 14:31:44 -04:00
// Remove service
2018-08-14 03:51:22 -04:00
out , err = d . Cmd ( "service" , "rm" , name )
2019-04-04 09:23:19 -04:00
assert . NilError ( c , err , out )
2016-11-04 14:31:44 -04:00
// Make sure container has been destroyed.
2016-12-09 04:17:53 -05:00
waitAndAssert ( c , defaultReconciliationTimeout , d . CheckActiveContainerCount , checker . Equals , 0 )
2016-11-04 14:31:44 -04:00
// With --tty
expectedOutput = "TTY"
2018-08-14 03:51:22 -04:00
out , err = d . Cmd ( "service" , "create" , "--detach" , "--no-resolve-image" , "--name" , name , "--tty" , "busybox" , "sh" , "-c" , ttyCheck )
2019-04-04 09:23:19 -04:00
assert . NilError ( c , err , out )
2016-11-04 14:31:44 -04:00
// Make sure task has been deployed.
2016-12-09 04:17:53 -05:00
waitAndAssert ( c , defaultReconciliationTimeout , d . CheckActiveContainerCount , checker . Equals , 1 )
2016-11-04 14:31:44 -04:00
// We need to get the container id.
2017-12-05 17:30:16 -05:00
out , err = d . Cmd ( "ps" , "-q" , "--no-trunc" )
2019-04-04 09:23:19 -04:00
assert . NilError ( c , err , out )
2016-11-04 14:31:44 -04:00
id = strings . TrimSpace ( out )
out , err = d . Cmd ( "exec" , id , "cat" , "/status" )
2019-04-04 09:23:19 -04:00
assert . NilError ( c , err , out )
2019-09-09 17:05:55 -04:00
assert . Assert ( c , out , checker . Contains , expectedOutput , check . Commentf ( "Expected '%s', but got %q" , expectedOutput , out ) )
2016-11-04 14:31:44 -04:00
}
2019-09-09 17:05:55 -04:00
func ( s * DockerSwarmSuite ) TestSwarmServiceTTYUpdate ( c * testing . T ) {
2016-11-04 14:31:44 -04:00
d := s . AddDaemon ( c , true , true )
// Create a service
name := "top"
2018-08-14 03:51:22 -04:00
out , err := d . Cmd ( "service" , "create" , "--detach" , "--no-resolve-image" , "--name" , name , "busybox" , "top" )
2019-04-04 09:23:19 -04:00
assert . NilError ( c , err , out )
2016-11-04 14:31:44 -04:00
// Make sure task has been deployed.
2016-12-09 04:17:53 -05:00
waitAndAssert ( c , defaultReconciliationTimeout , d . CheckActiveContainerCount , checker . Equals , 1 )
2016-11-04 14:31:44 -04:00
2018-08-14 03:51:22 -04:00
out , err = d . Cmd ( "service" , "inspect" , "--format" , "{{ .Spec.TaskTemplate.ContainerSpec.TTY }}" , name )
2019-04-04 09:23:19 -04:00
assert . NilError ( c , err , out )
assert . Equal ( c , strings . TrimSpace ( out ) , "false" )
2016-11-04 14:31:44 -04:00
2018-08-14 03:51:22 -04:00
out , err = d . Cmd ( "service" , "update" , "--detach" , "--tty" , name )
2019-04-04 09:23:19 -04:00
assert . NilError ( c , err , out )
2016-11-04 14:31:44 -04:00
out , err = d . Cmd ( "service" , "inspect" , "--format" , "{{ .Spec.TaskTemplate.ContainerSpec.TTY }}" , name )
2019-04-04 09:23:19 -04:00
assert . NilError ( c , err , out )
assert . Equal ( c , strings . TrimSpace ( out ) , "true" )
2016-11-04 14:31:44 -04:00
}
2016-10-19 20:07:44 -04:00
2019-09-09 17:05:55 -04:00
func ( s * DockerSwarmSuite ) TestSwarmServiceNetworkUpdate ( c * testing . T ) {
2017-03-23 20:51:57 -04:00
d := s . AddDaemon ( c , true , true )
result := icmd . RunCmd ( d . Command ( "network" , "create" , "-d" , "overlay" , "foo" ) )
result . Assert ( c , icmd . Success )
fooNetwork := strings . TrimSpace ( string ( result . Combined ( ) ) )
result = icmd . RunCmd ( d . Command ( "network" , "create" , "-d" , "overlay" , "bar" ) )
result . Assert ( c , icmd . Success )
barNetwork := strings . TrimSpace ( string ( result . Combined ( ) ) )
result = icmd . RunCmd ( d . Command ( "network" , "create" , "-d" , "overlay" , "baz" ) )
result . Assert ( c , icmd . Success )
bazNetwork := strings . TrimSpace ( string ( result . Combined ( ) ) )
// Create a service
name := "top"
2017-09-27 19:17:55 -04:00
result = icmd . RunCmd ( d . Command ( "service" , "create" , "--detach" , "--no-resolve-image" , "--network" , "foo" , "--network" , "bar" , "--name" , name , "busybox" , "top" ) )
2017-03-23 20:51:57 -04:00
result . Assert ( c , icmd . Success )
// Make sure task has been deployed.
waitAndAssert ( c , defaultReconciliationTimeout , d . CheckRunningTaskNetworks , checker . DeepEquals ,
map [ string ] int { fooNetwork : 1 , barNetwork : 1 } )
// Remove a network
2017-09-27 19:17:55 -04:00
result = icmd . RunCmd ( d . Command ( "service" , "update" , "--detach" , "--network-rm" , "foo" , name ) )
2017-03-23 20:51:57 -04:00
result . Assert ( c , icmd . Success )
waitAndAssert ( c , defaultReconciliationTimeout , d . CheckRunningTaskNetworks , checker . DeepEquals ,
map [ string ] int { barNetwork : 1 } )
// Add a network
2017-09-27 19:17:55 -04:00
result = icmd . RunCmd ( d . Command ( "service" , "update" , "--detach" , "--network-add" , "baz" , name ) )
2017-03-23 20:51:57 -04:00
result . Assert ( c , icmd . Success )
waitAndAssert ( c , defaultReconciliationTimeout , d . CheckRunningTaskNetworks , checker . DeepEquals ,
map [ string ] int { barNetwork : 1 , bazNetwork : 1 } )
}
2019-09-09 17:05:55 -04:00
func ( s * DockerSwarmSuite ) TestDNSConfig ( c * testing . T ) {
2016-10-19 20:07:44 -04:00
d := s . AddDaemon ( c , true , true )
// Create a service
name := "top"
2018-08-14 03:51:22 -04:00
out , err := d . Cmd ( "service" , "create" , "--detach" , "--no-resolve-image" , "--name" , name , "--dns=1.2.3.4" , "--dns-search=example.com" , "--dns-option=timeout:3" , "busybox" , "top" )
2019-04-04 09:23:19 -04:00
assert . NilError ( c , err , out )
2016-10-19 20:07:44 -04:00
// Make sure task has been deployed.
2016-12-09 04:17:53 -05:00
waitAndAssert ( c , defaultReconciliationTimeout , d . CheckActiveContainerCount , checker . Equals , 1 )
2016-10-19 20:07:44 -04:00
// We need to get the container id.
2018-08-14 03:51:22 -04:00
out , err = d . Cmd ( "ps" , "-a" , "-q" , "--no-trunc" )
2019-04-04 09:23:19 -04:00
assert . NilError ( c , err , out )
2016-10-19 20:07:44 -04:00
id := strings . TrimSpace ( out )
// Compare against expected output.
expectedOutput1 := "nameserver 1.2.3.4"
expectedOutput2 := "search example.com"
expectedOutput3 := "options timeout:3"
out , err = d . Cmd ( "exec" , id , "cat" , "/etc/resolv.conf" )
2019-04-04 09:23:19 -04:00
assert . NilError ( c , err , out )
2019-09-09 17:05:55 -04:00
assert . Assert ( c , out , checker . Contains , expectedOutput1 , check . Commentf ( "Expected '%s', but got %q" , expectedOutput1 , out ) )
assert . Assert ( c , out , checker . Contains , expectedOutput2 , check . Commentf ( "Expected '%s', but got %q" , expectedOutput2 , out ) )
assert . Assert ( c , out , checker . Contains , expectedOutput3 , check . Commentf ( "Expected '%s', but got %q" , expectedOutput3 , out ) )
2016-10-19 20:07:44 -04:00
}
2016-10-26 23:05:39 -04:00
2019-09-09 17:05:55 -04:00
func ( s * DockerSwarmSuite ) TestDNSConfigUpdate ( c * testing . T ) {
2016-10-26 23:05:39 -04:00
d := s . AddDaemon ( c , true , true )
// Create a service
name := "top"
2018-08-14 03:51:22 -04:00
out , err := d . Cmd ( "service" , "create" , "--detach" , "--no-resolve-image" , "--name" , name , "busybox" , "top" )
2019-04-04 09:23:19 -04:00
assert . NilError ( c , err , out )
2016-10-26 23:05:39 -04:00
// Make sure task has been deployed.
2016-12-09 04:17:53 -05:00
waitAndAssert ( c , defaultReconciliationTimeout , d . CheckActiveContainerCount , checker . Equals , 1 )
2016-10-26 23:05:39 -04:00
2018-08-14 03:51:22 -04:00
out , err = d . Cmd ( "service" , "update" , "--detach" , "--dns-add=1.2.3.4" , "--dns-search-add=example.com" , "--dns-option-add=timeout:3" , name )
2019-04-04 09:23:19 -04:00
assert . NilError ( c , err , out )
2016-10-26 23:05:39 -04:00
2018-08-14 03:51:22 -04:00
out , err = d . Cmd ( "service" , "inspect" , "--format" , "{{ .Spec.TaskTemplate.ContainerSpec.DNSConfig }}" , name )
2019-04-04 09:23:19 -04:00
assert . NilError ( c , err , out )
assert . Equal ( c , strings . TrimSpace ( out ) , "{[1.2.3.4] [example.com] [timeout:3]}" )
2016-10-26 23:05:39 -04:00
}
2016-10-24 17:44:51 -04:00
2019-09-09 17:05:55 -04:00
func getNodeStatus ( c * testing . T , d * daemon . Daemon ) swarm . LocalNodeState {
2018-04-11 06:10:17 -04:00
info := d . SwarmInfo ( c )
2016-11-17 19:51:33 -05:00
return info . LocalNodeState
}
2019-09-09 17:05:55 -04:00
func checkKeyIsEncrypted ( d * daemon . Daemon ) func ( * testing . T ) ( interface { } , check . CommentInterface ) {
return func ( c * testing . T ) ( interface { } , check . CommentInterface ) {
2017-06-06 09:28:40 -04:00
keyBytes , err := ioutil . ReadFile ( filepath . Join ( d . Folder , "root" , "swarm" , "certificates" , "swarm-node.key" ) )
if err != nil {
return fmt . Errorf ( "error reading key: %v" , err ) , nil
}
2016-11-30 14:14:01 -05:00
2017-06-06 09:28:40 -04:00
keyBlock , _ := pem . Decode ( keyBytes )
if keyBlock == nil {
return fmt . Errorf ( "invalid PEM-encoded private key" ) , nil
}
2016-11-30 14:14:01 -05:00
2018-02-12 17:25:51 -05:00
return keyutils . IsEncryptedPEMBlock ( keyBlock ) , nil
2016-11-30 14:14:01 -05:00
}
2017-06-06 09:28:40 -04:00
}
2016-11-30 14:14:01 -05:00
2019-09-09 17:05:55 -04:00
func checkSwarmLockedToUnlocked ( c * testing . T , d * daemon . Daemon ) {
2017-06-06 09:28:40 -04:00
// Wait for the PEM file to become unencrypted
waitAndAssert ( c , defaultReconciliationTimeout , checkKeyIsEncrypted ( d ) , checker . Equals , false )
2018-10-25 14:47:56 -04:00
d . RestartNode ( c )
2019-01-12 13:55:20 -05:00
waitAndAssert ( c , time . Second , d . CheckLocalNodeState , checker . Equals , swarm . LocalNodeStateActive )
2016-11-30 14:14:01 -05:00
}
2019-09-09 17:05:55 -04:00
func checkSwarmUnlockedToLocked ( c * testing . T , d * daemon . Daemon ) {
2017-06-06 09:28:40 -04:00
// Wait for the PEM file to become encrypted
waitAndAssert ( c , defaultReconciliationTimeout , checkKeyIsEncrypted ( d ) , checker . Equals , true )
2018-10-25 14:47:56 -04:00
d . RestartNode ( c )
2019-01-12 13:55:20 -05:00
waitAndAssert ( c , time . Second , d . CheckLocalNodeState , checker . Equals , swarm . LocalNodeStateLocked )
2016-11-30 14:14:01 -05:00
}
2019-09-09 17:05:55 -04:00
func ( s * DockerSwarmSuite ) TestUnlockEngineAndUnlockedSwarm ( c * testing . T ) {
2016-12-07 00:48:01 -05:00
d := s . AddDaemon ( c , false , false )
2016-12-15 21:36:37 -05:00
// unlocking a normal engine should return an error - it does not even ask for the key
2016-12-07 00:48:01 -05:00
cmd := d . Command ( "swarm" , "unlock" )
2017-01-16 10:39:12 -05:00
result := icmd . RunCmd ( cmd )
result . Assert ( c , icmd . Expected {
ExitCode : 1 ,
} )
2019-09-09 17:05:55 -04:00
assert . Assert ( c , result . Combined ( ) , checker . Contains , "Error: This node is not part of a swarm" )
assert . Assert ( c , result . Combined ( ) , checker . Not ( checker . Contains ) , "Please enter unlock key" )
2016-12-07 00:48:01 -05:00
2018-08-14 03:51:22 -04:00
out , err := d . Cmd ( "swarm" , "init" )
2019-04-04 09:23:19 -04:00
assert . NilError ( c , err , out )
2016-12-07 00:48:01 -05:00
2016-12-15 21:36:37 -05:00
// unlocking an unlocked swarm should return an error - it does not even ask for the key
2016-12-07 00:48:01 -05:00
cmd = d . Command ( "swarm" , "unlock" )
2017-01-16 10:39:12 -05:00
result = icmd . RunCmd ( cmd )
result . Assert ( c , icmd . Expected {
ExitCode : 1 ,
} )
2019-09-09 17:05:55 -04:00
assert . Assert ( c , result . Combined ( ) , checker . Contains , "Error: swarm is not locked" )
assert . Assert ( c , result . Combined ( ) , checker . Not ( checker . Contains ) , "Please enter unlock key" )
2016-12-07 00:48:01 -05:00
}
2019-09-09 17:05:55 -04:00
func ( s * DockerSwarmSuite ) TestSwarmInitLocked ( c * testing . T ) {
2016-10-24 17:44:51 -04:00
d := s . AddDaemon ( c , false , false )
2016-10-31 18:02:34 -04:00
outs , err := d . Cmd ( "swarm" , "init" , "--autolock" )
2019-09-09 17:05:55 -04:00
assert . Assert ( c , err , checker . IsNil , check . Commentf ( "%s" , outs ) )
2018-10-29 16:46:21 -04:00
unlockKey := getUnlockKey ( d , c , outs )
2016-10-24 17:44:51 -04:00
2019-09-09 17:05:55 -04:00
assert . Assert ( c , getNodeStatus ( c , d ) , checker . Equals , swarm . LocalNodeStateActive )
2016-10-24 17:44:51 -04:00
2016-11-30 14:14:01 -05:00
// It starts off locked
2018-10-25 14:47:56 -04:00
d . RestartNode ( c )
2019-09-09 17:05:55 -04:00
assert . Assert ( c , getNodeStatus ( c , d ) , checker . Equals , swarm . LocalNodeStateLocked )
2016-10-24 17:44:51 -04:00
2016-12-09 04:17:53 -05:00
cmd := d . Command ( "swarm" , "unlock" )
2016-10-24 17:44:51 -04:00
cmd . Stdin = bytes . NewBufferString ( "wrong-secret-key" )
2017-01-16 10:39:12 -05:00
icmd . RunCmd ( cmd ) . Assert ( c , icmd . Expected {
ExitCode : 1 ,
Err : "invalid key" ,
} )
2016-10-24 17:44:51 -04:00
2019-09-09 17:05:55 -04:00
assert . Assert ( c , getNodeStatus ( c , d ) , checker . Equals , swarm . LocalNodeStateLocked )
2016-11-17 19:51:33 -05:00
2016-12-09 04:17:53 -05:00
cmd = d . Command ( "swarm" , "unlock" )
2016-10-31 18:02:34 -04:00
cmd . Stdin = bytes . NewBufferString ( unlockKey )
2017-01-16 10:39:12 -05:00
icmd . RunCmd ( cmd ) . Assert ( c , icmd . Success )
2016-10-24 17:44:51 -04:00
2019-09-09 17:05:55 -04:00
assert . Assert ( c , getNodeStatus ( c , d ) , checker . Equals , swarm . LocalNodeStateActive )
2016-10-31 18:02:34 -04:00
outs , err = d . Cmd ( "node" , "ls" )
2019-09-09 17:05:55 -04:00
assert . Assert ( c , err , checker . IsNil , check . Commentf ( "%s" , outs ) )
assert . Assert ( c , outs , checker . Not ( checker . Contains ) , "Swarm is encrypted and needs to be unlocked" )
2016-10-31 18:02:34 -04:00
outs , err = d . Cmd ( "swarm" , "update" , "--autolock=false" )
2019-09-09 17:05:55 -04:00
assert . Assert ( c , err , checker . IsNil , check . Commentf ( "%s" , outs ) )
2016-10-31 18:02:34 -04:00
2018-10-25 01:49:33 -04:00
checkSwarmLockedToUnlocked ( c , d )
2016-10-31 18:02:34 -04:00
outs , err = d . Cmd ( "node" , "ls" )
2019-09-09 17:05:55 -04:00
assert . Assert ( c , err , checker . IsNil , check . Commentf ( "%s" , outs ) )
assert . Assert ( c , outs , checker . Not ( checker . Contains ) , "Swarm is encrypted and needs to be unlocked" )
2016-10-24 17:44:51 -04:00
}
2019-09-09 17:05:55 -04:00
func ( s * DockerSwarmSuite ) TestSwarmLeaveLocked ( c * testing . T ) {
2016-10-24 17:44:51 -04:00
d := s . AddDaemon ( c , false , false )
2016-10-31 18:02:34 -04:00
outs , err := d . Cmd ( "swarm" , "init" , "--autolock" )
2019-09-09 17:05:55 -04:00
assert . Assert ( c , err , checker . IsNil , check . Commentf ( "%s" , outs ) )
2016-10-24 17:44:51 -04:00
2016-11-30 14:14:01 -05:00
// It starts off locked
2018-10-25 14:47:56 -04:00
d . RestartNode ( c )
2016-10-24 17:44:51 -04:00
2018-04-11 06:10:17 -04:00
info := d . SwarmInfo ( c )
2019-04-04 09:23:19 -04:00
assert . Equal ( c , info . LocalNodeState , swarm . LocalNodeStateLocked )
2016-10-24 17:44:51 -04:00
2016-10-31 18:02:34 -04:00
outs , _ = d . Cmd ( "node" , "ls" )
2019-09-09 17:05:55 -04:00
assert . Assert ( c , outs , checker . Contains , "Swarm is encrypted and needs to be unlocked" )
2016-10-31 18:02:34 -04:00
2016-12-02 04:14:32 -05:00
// `docker swarm leave` a locked swarm without --force will return an error
outs , _ = d . Cmd ( "swarm" , "leave" )
2019-09-09 17:05:55 -04:00
assert . Assert ( c , outs , checker . Contains , "Swarm is encrypted and locked." )
2016-12-02 04:14:32 -05:00
// It is OK for user to leave a locked swarm with --force
2016-10-31 18:02:34 -04:00
outs , err = d . Cmd ( "swarm" , "leave" , "--force" )
2019-09-09 17:05:55 -04:00
assert . Assert ( c , err , checker . IsNil , check . Commentf ( "%s" , outs ) )
2016-10-24 17:44:51 -04:00
2018-04-11 06:10:17 -04:00
info = d . SwarmInfo ( c )
2019-04-04 09:23:19 -04:00
assert . Equal ( c , info . LocalNodeState , swarm . LocalNodeStateInactive )
2016-10-24 17:44:51 -04:00
outs , err = d . Cmd ( "swarm" , "init" )
2019-09-09 17:05:55 -04:00
assert . Assert ( c , err , checker . IsNil , check . Commentf ( "%s" , outs ) )
2016-10-24 17:44:51 -04:00
2018-04-11 06:10:17 -04:00
info = d . SwarmInfo ( c )
2019-04-04 09:23:19 -04:00
assert . Equal ( c , info . LocalNodeState , swarm . LocalNodeStateActive )
2016-10-24 17:44:51 -04:00
}
2016-10-31 18:02:34 -04:00
2019-09-09 17:05:55 -04:00
func ( s * DockerSwarmSuite ) TestSwarmLockUnlockCluster ( c * testing . T ) {
2016-11-17 19:51:33 -05:00
d1 := s . AddDaemon ( c , true , true )
d2 := s . AddDaemon ( c , true , true )
d3 := s . AddDaemon ( c , true , true )
// they start off unlocked
2018-10-25 14:47:56 -04:00
d2 . RestartNode ( c )
2019-09-09 17:05:55 -04:00
assert . Assert ( c , getNodeStatus ( c , d2 ) , checker . Equals , swarm . LocalNodeStateActive )
2016-11-17 19:51:33 -05:00
// stop this one so it does not get autolock info
2016-12-09 17:20:14 -05:00
d2 . Stop ( c )
2016-11-17 19:51:33 -05:00
// enable autolock
outs , err := d1 . Cmd ( "swarm" , "update" , "--autolock" )
2019-09-09 17:05:55 -04:00
assert . Assert ( c , err , checker . IsNil , check . Commentf ( "%s" , outs ) )
2018-10-29 16:46:21 -04:00
unlockKey := getUnlockKey ( d1 , c , outs )
2016-11-17 19:51:33 -05:00
// The ones that got the cluster update should be set to locked
2018-04-11 06:10:17 -04:00
for _ , d := range [ ] * daemon . Daemon { d1 , d3 } {
2016-11-30 14:14:01 -05:00
checkSwarmUnlockedToLocked ( c , d )
2016-11-17 19:51:33 -05:00
2016-12-09 04:17:53 -05:00
cmd := d . Command ( "swarm" , "unlock" )
2016-11-17 19:51:33 -05:00
cmd . Stdin = bytes . NewBufferString ( unlockKey )
2017-01-16 10:39:12 -05:00
icmd . RunCmd ( cmd ) . Assert ( c , icmd . Success )
2019-09-09 17:05:55 -04:00
assert . Assert ( c , getNodeStatus ( c , d ) , checker . Equals , swarm . LocalNodeStateActive )
2016-11-17 19:51:33 -05:00
}
// d2 never got the cluster update, so it is still set to unlocked
2018-10-25 14:47:56 -04:00
d2 . StartNode ( c )
2019-09-09 17:05:55 -04:00
assert . Assert ( c , getNodeStatus ( c , d2 ) , checker . Equals , swarm . LocalNodeStateActive )
2016-11-17 19:51:33 -05:00
// d2 is now set to lock
2016-11-30 14:14:01 -05:00
checkSwarmUnlockedToLocked ( c , d2 )
2016-11-17 19:51:33 -05:00
// leave it locked, and set the cluster to no longer autolock
outs , err = d1 . Cmd ( "swarm" , "update" , "--autolock=false" )
2019-09-09 17:05:55 -04:00
assert . Assert ( c , err , checker . IsNil , check . Commentf ( "out: %v" , outs ) )
2016-11-17 19:51:33 -05:00
// the ones that got the update are now set to unlocked
2018-04-11 06:10:17 -04:00
for _ , d := range [ ] * daemon . Daemon { d1 , d3 } {
2018-10-25 01:49:33 -04:00
checkSwarmLockedToUnlocked ( c , d )
2016-11-17 19:51:33 -05:00
}
// d2 still locked
2019-09-09 17:05:55 -04:00
assert . Assert ( c , getNodeStatus ( c , d2 ) , checker . Equals , swarm . LocalNodeStateLocked )
2016-11-17 19:51:33 -05:00
// unlock it
2016-12-09 04:17:53 -05:00
cmd := d2 . Command ( "swarm" , "unlock" )
2016-11-17 19:51:33 -05:00
cmd . Stdin = bytes . NewBufferString ( unlockKey )
2017-01-16 10:39:12 -05:00
icmd . RunCmd ( cmd ) . Assert ( c , icmd . Success )
2019-09-09 17:05:55 -04:00
assert . Assert ( c , getNodeStatus ( c , d2 ) , checker . Equals , swarm . LocalNodeStateActive )
2016-11-17 19:51:33 -05:00
// once it's caught up, d2 is set to not be locked
2018-10-25 01:49:33 -04:00
checkSwarmLockedToUnlocked ( c , d2 )
2016-11-17 19:51:33 -05:00
2016-11-30 14:14:01 -05:00
// managers who join now are never set to locked in the first place
2016-11-17 19:51:33 -05:00
d4 := s . AddDaemon ( c , true , true )
2018-10-25 14:47:56 -04:00
d4 . RestartNode ( c )
2019-09-09 17:05:55 -04:00
assert . Assert ( c , getNodeStatus ( c , d4 ) , checker . Equals , swarm . LocalNodeStateActive )
2016-11-17 19:51:33 -05:00
}
2019-09-09 17:05:55 -04:00
func ( s * DockerSwarmSuite ) TestSwarmJoinPromoteLocked ( c * testing . T ) {
2016-11-17 19:51:33 -05:00
d1 := s . AddDaemon ( c , true , true )
// enable autolock
outs , err := d1 . Cmd ( "swarm" , "update" , "--autolock" )
2019-09-09 17:05:55 -04:00
assert . Assert ( c , err , checker . IsNil , check . Commentf ( "out: %v" , outs ) )
2018-10-29 16:46:21 -04:00
unlockKey := getUnlockKey ( d1 , c , outs )
2016-11-17 19:51:33 -05:00
// joined workers start off unlocked
d2 := s . AddDaemon ( c , true , false )
2018-10-25 14:47:56 -04:00
d2 . RestartNode ( c )
2019-01-12 13:55:20 -05:00
waitAndAssert ( c , time . Second , d2 . CheckLocalNodeState , checker . Equals , swarm . LocalNodeStateActive )
2016-11-17 19:51:33 -05:00
// promote worker
2018-04-11 06:10:17 -04:00
outs , err = d1 . Cmd ( "node" , "promote" , d2 . NodeID ( ) )
2019-04-04 09:23:19 -04:00
assert . NilError ( c , err )
2019-09-09 17:05:55 -04:00
assert . Assert ( c , outs , checker . Contains , "promoted to a manager in the swarm" )
2016-11-17 19:51:33 -05:00
// join new manager node
d3 := s . AddDaemon ( c , true , true )
// both new nodes are locked
2018-04-11 06:10:17 -04:00
for _ , d := range [ ] * daemon . Daemon { d2 , d3 } {
2016-11-30 14:14:01 -05:00
checkSwarmUnlockedToLocked ( c , d )
2016-11-17 19:51:33 -05:00
2016-12-09 04:17:53 -05:00
cmd := d . Command ( "swarm" , "unlock" )
2016-11-17 19:51:33 -05:00
cmd . Stdin = bytes . NewBufferString ( unlockKey )
2017-01-16 10:39:12 -05:00
icmd . RunCmd ( cmd ) . Assert ( c , icmd . Success )
2019-09-09 17:05:55 -04:00
assert . Assert ( c , getNodeStatus ( c , d ) , checker . Equals , swarm . LocalNodeStateActive )
2016-11-17 19:51:33 -05:00
}
// demote manager back to worker - workers are not locked
2018-04-11 06:10:17 -04:00
outs , err = d1 . Cmd ( "node" , "demote" , d3 . NodeID ( ) )
2019-04-04 09:23:19 -04:00
assert . NilError ( c , err )
2019-09-09 17:05:55 -04:00
assert . Assert ( c , outs , checker . Contains , "demoted in the swarm" )
2016-11-17 19:51:33 -05:00
2016-12-02 19:28:27 -05:00
// Wait for it to actually be demoted, for the key and cert to be replaced.
// Then restart and assert that the node is not locked. If we don't wait for the cert
// to be replaced, then the node still has the manager TLS key which is still locked
// (because we never want a manager TLS key to be on disk unencrypted if the cluster
// is set to autolock)
2016-12-09 04:17:53 -05:00
waitAndAssert ( c , defaultReconciliationTimeout , d3 . CheckControlAvailable , checker . False )
2019-09-09 17:05:55 -04:00
waitAndAssert ( c , defaultReconciliationTimeout , func ( c * testing . T ) ( interface { } , check . CommentInterface ) {
2017-04-16 15:40:11 -04:00
certBytes , err := ioutil . ReadFile ( filepath . Join ( d3 . Folder , "root" , "swarm" , "certificates" , "swarm-node.crt" ) )
2016-12-02 19:28:27 -05:00
if err != nil {
return "" , check . Commentf ( "error: %v" , err )
}
2017-04-16 15:40:11 -04:00
certs , err := helpers . ParseCertificatesPEM ( certBytes )
if err == nil && len ( certs ) > 0 && len ( certs [ 0 ] . Subject . OrganizationalUnit ) > 0 {
return certs [ 0 ] . Subject . OrganizationalUnit [ 0 ] , nil
}
return "" , check . Commentf ( "could not get organizational unit from certificate" )
} , checker . Equals , "swarm-worker" )
2016-11-17 19:51:33 -05:00
2016-12-02 19:28:27 -05:00
// by now, it should *never* be locked on restart
2018-10-25 14:47:56 -04:00
d3 . RestartNode ( c )
2019-01-12 13:55:20 -05:00
waitAndAssert ( c , time . Second , d3 . CheckLocalNodeState , checker . Equals , swarm . LocalNodeStateActive )
2016-11-17 19:51:33 -05:00
}
2019-09-09 17:05:55 -04:00
func ( s * DockerSwarmSuite ) TestSwarmRotateUnlockKey ( c * testing . T ) {
2016-10-31 18:02:34 -04:00
d := s . AddDaemon ( c , true , true )
outs , err := d . Cmd ( "swarm" , "update" , "--autolock" )
2019-09-09 17:05:55 -04:00
assert . Assert ( c , err , checker . IsNil , check . Commentf ( "out: %v" , outs ) )
2018-10-29 16:46:21 -04:00
unlockKey := getUnlockKey ( d , c , outs )
2016-10-31 18:02:34 -04:00
// Rotate multiple times
for i := 0 ; i != 3 ; i ++ {
outs , err = d . Cmd ( "swarm" , "unlock-key" , "-q" , "--rotate" )
2019-09-09 17:05:55 -04:00
assert . Assert ( c , err , checker . IsNil , check . Commentf ( "out: %v" , outs ) )
2016-10-31 18:02:34 -04:00
// Strip \n
newUnlockKey := outs [ : len ( outs ) - 1 ]
2019-09-09 17:05:56 -04:00
assert . Assert ( c , newUnlockKey != "" )
assert . Assert ( c , newUnlockKey != unlockKey )
2016-10-31 18:02:34 -04:00
2018-10-25 14:47:56 -04:00
d . RestartNode ( c )
2019-09-09 17:05:55 -04:00
assert . Assert ( c , getNodeStatus ( c , d ) , checker . Equals , swarm . LocalNodeStateLocked )
2016-10-31 18:02:34 -04:00
outs , _ = d . Cmd ( "node" , "ls" )
2019-09-09 17:05:55 -04:00
assert . Assert ( c , outs , checker . Contains , "Swarm is encrypted and needs to be unlocked" )
2016-10-31 18:02:34 -04:00
2016-12-09 04:17:53 -05:00
cmd := d . Command ( "swarm" , "unlock" )
2016-10-31 18:02:34 -04:00
cmd . Stdin = bytes . NewBufferString ( unlockKey )
2017-01-16 10:39:12 -05:00
result := icmd . RunCmd ( cmd )
2016-10-31 18:02:34 -04:00
2017-01-16 10:39:12 -05:00
if result . Error == nil {
2016-10-31 18:02:34 -04:00
// On occasion, the daemon may not have finished
// rotating the KEK before restarting. The test is
// intentionally written to explore this behavior.
// When this happens, unlocking with the old key will
// succeed. If we wait for the rotation to happen and
// restart again, the new key should be required this
// time.
time . Sleep ( 3 * time . Second )
2018-10-25 14:47:56 -04:00
d . RestartNode ( c )
2016-10-31 18:02:34 -04:00
2016-12-09 04:17:53 -05:00
cmd = d . Command ( "swarm" , "unlock" )
2016-10-31 18:02:34 -04:00
cmd . Stdin = bytes . NewBufferString ( unlockKey )
2017-01-16 10:39:12 -05:00
result = icmd . RunCmd ( cmd )
2016-10-31 18:02:34 -04:00
}
2017-01-16 10:39:12 -05:00
result . Assert ( c , icmd . Expected {
ExitCode : 1 ,
Err : "invalid key" ,
} )
2016-10-31 18:02:34 -04:00
outs , _ = d . Cmd ( "node" , "ls" )
2019-09-09 17:05:55 -04:00
assert . Assert ( c , outs , checker . Contains , "Swarm is encrypted and needs to be unlocked" )
2016-10-31 18:02:34 -04:00
2016-12-09 04:17:53 -05:00
cmd = d . Command ( "swarm" , "unlock" )
2016-10-31 18:02:34 -04:00
cmd . Stdin = bytes . NewBufferString ( newUnlockKey )
2017-01-16 10:39:12 -05:00
icmd . RunCmd ( cmd ) . Assert ( c , icmd . Success )
2016-10-31 18:02:34 -04:00
2019-09-09 17:05:55 -04:00
assert . Assert ( c , getNodeStatus ( c , d ) , checker . Equals , swarm . LocalNodeStateActive )
2016-10-31 18:02:34 -04:00
2019-07-16 17:07:26 -04:00
retry := 0
for {
// an issue sometimes prevents leader to be available right away
outs , err = d . Cmd ( "node" , "ls" )
if err != nil && retry < 5 {
2019-07-26 14:05:00 -04:00
if strings . Contains ( outs , "swarm does not have a leader" ) {
2019-07-16 17:07:26 -04:00
retry ++
time . Sleep ( 3 * time . Second )
continue
}
}
assert . NilError ( c , err )
2019-09-09 17:05:55 -04:00
assert . Assert ( c , outs , checker . Not ( checker . Contains ) , "Swarm is encrypted and needs to be unlocked" )
2019-07-16 17:07:26 -04:00
break
}
2016-11-10 13:39:14 -05:00
unlockKey = newUnlockKey
2016-10-31 18:02:34 -04:00
}
}
2016-11-03 11:05:00 -04:00
2016-11-17 19:51:33 -05:00
// This differs from `TestSwarmRotateUnlockKey` because that one rotates a single node, which is the leader.
// This one keeps the leader up, and asserts that other manager nodes in the cluster also have their unlock
// key rotated.
2019-09-09 17:05:55 -04:00
func ( s * DockerSwarmSuite ) TestSwarmClusterRotateUnlockKey ( c * testing . T ) {
2018-12-23 06:39:58 -05:00
if runtime . GOARCH == "s390x" {
c . Skip ( "Disabled on s390x" )
}
if runtime . GOARCH == "ppc64le" {
c . Skip ( "Disabled on ppc64le" )
}
2016-11-17 19:51:33 -05:00
d1 := s . AddDaemon ( c , true , true ) // leader - don't restart this one, we don't want leader election delays
d2 := s . AddDaemon ( c , true , true )
d3 := s . AddDaemon ( c , true , true )
outs , err := d1 . Cmd ( "swarm" , "update" , "--autolock" )
2019-09-09 17:05:55 -04:00
assert . Assert ( c , err , checker . IsNil , check . Commentf ( "%s" , outs ) )
2018-10-29 16:46:21 -04:00
unlockKey := getUnlockKey ( d1 , c , outs )
2016-11-17 19:51:33 -05:00
// Rotate multiple times
for i := 0 ; i != 3 ; i ++ {
outs , err = d1 . Cmd ( "swarm" , "unlock-key" , "-q" , "--rotate" )
2019-09-09 17:05:55 -04:00
assert . Assert ( c , err , checker . IsNil , check . Commentf ( "%s" , outs ) )
2016-11-17 19:51:33 -05:00
// Strip \n
newUnlockKey := outs [ : len ( outs ) - 1 ]
2019-09-09 17:05:56 -04:00
assert . Assert ( c , newUnlockKey != "" )
assert . Assert ( c , newUnlockKey != unlockKey )
2016-11-17 19:51:33 -05:00
2018-10-25 14:47:56 -04:00
d2 . RestartNode ( c )
d3 . RestartNode ( c )
2016-11-17 19:51:33 -05:00
2018-04-11 06:10:17 -04:00
for _ , d := range [ ] * daemon . Daemon { d2 , d3 } {
2019-09-09 17:05:55 -04:00
assert . Assert ( c , getNodeStatus ( c , d ) , checker . Equals , swarm . LocalNodeStateLocked )
2016-11-17 19:51:33 -05:00
outs , _ := d . Cmd ( "node" , "ls" )
2019-09-09 17:05:55 -04:00
assert . Assert ( c , outs , checker . Contains , "Swarm is encrypted and needs to be unlocked" )
2016-11-17 19:51:33 -05:00
2016-12-09 04:17:53 -05:00
cmd := d . Command ( "swarm" , "unlock" )
2016-11-17 19:51:33 -05:00
cmd . Stdin = bytes . NewBufferString ( unlockKey )
2017-01-16 10:39:12 -05:00
result := icmd . RunCmd ( cmd )
2016-11-17 19:51:33 -05:00
2017-01-16 10:39:12 -05:00
if result . Error == nil {
2016-11-17 19:51:33 -05:00
// On occasion, the daemon may not have finished
// rotating the KEK before restarting. The test is
// intentionally written to explore this behavior.
// When this happens, unlocking with the old key will
// succeed. If we wait for the rotation to happen and
// restart again, the new key should be required this
// time.
time . Sleep ( 3 * time . Second )
2018-10-25 14:47:56 -04:00
d . RestartNode ( c )
2016-11-17 19:51:33 -05:00
2016-12-09 04:17:53 -05:00
cmd = d . Command ( "swarm" , "unlock" )
2016-11-17 19:51:33 -05:00
cmd . Stdin = bytes . NewBufferString ( unlockKey )
2017-01-16 10:39:12 -05:00
result = icmd . RunCmd ( cmd )
2016-11-17 19:51:33 -05:00
}
2017-01-16 10:39:12 -05:00
result . Assert ( c , icmd . Expected {
ExitCode : 1 ,
Err : "invalid key" ,
} )
2016-11-17 19:51:33 -05:00
outs , _ = d . Cmd ( "node" , "ls" )
2019-09-09 17:05:55 -04:00
assert . Assert ( c , outs , checker . Contains , "Swarm is encrypted and needs to be unlocked" )
2016-11-17 19:51:33 -05:00
2016-12-09 04:17:53 -05:00
cmd = d . Command ( "swarm" , "unlock" )
2016-11-17 19:51:33 -05:00
cmd . Stdin = bytes . NewBufferString ( newUnlockKey )
2017-01-16 10:39:12 -05:00
icmd . RunCmd ( cmd ) . Assert ( c , icmd . Success )
2016-11-17 19:51:33 -05:00
2019-09-09 17:05:55 -04:00
assert . Assert ( c , getNodeStatus ( c , d ) , checker . Equals , swarm . LocalNodeStateActive )
2016-11-17 19:51:33 -05:00
2019-07-16 17:07:26 -04:00
retry := 0
for {
// an issue sometimes prevents leader to be available right away
outs , err = d . Cmd ( "node" , "ls" )
if err != nil && retry < 5 {
2019-07-26 14:05:00 -04:00
if strings . Contains ( outs , "swarm does not have a leader" ) {
2019-07-16 17:07:26 -04:00
retry ++
time . Sleep ( 3 * time . Second )
continue
}
}
2019-09-09 17:05:55 -04:00
assert . Assert ( c , err , checker . IsNil , check . Commentf ( "%s" , outs ) )
assert . Assert ( c , outs , checker . Not ( checker . Contains ) , "Swarm is encrypted and needs to be unlocked" )
2019-07-16 17:07:26 -04:00
break
}
2016-11-17 19:51:33 -05:00
}
unlockKey = newUnlockKey
}
}
2019-09-09 17:05:55 -04:00
func ( s * DockerSwarmSuite ) TestSwarmAlternateLockUnlock ( c * testing . T ) {
2016-11-17 19:51:33 -05:00
d := s . AddDaemon ( c , true , true )
for i := 0 ; i < 2 ; i ++ {
// set to lock
outs , err := d . Cmd ( "swarm" , "update" , "--autolock" )
2019-09-09 17:05:55 -04:00
assert . Assert ( c , err , checker . IsNil , check . Commentf ( "out: %v" , outs ) )
assert . Assert ( c , outs , checker . Contains , "docker swarm unlock" )
2018-10-29 16:46:21 -04:00
unlockKey := getUnlockKey ( d , c , outs )
2016-11-17 19:51:33 -05:00
2016-11-30 14:14:01 -05:00
checkSwarmUnlockedToLocked ( c , d )
2016-11-17 19:51:33 -05:00
2016-12-09 04:17:53 -05:00
cmd := d . Command ( "swarm" , "unlock" )
2016-11-17 19:51:33 -05:00
cmd . Stdin = bytes . NewBufferString ( unlockKey )
2017-01-16 10:39:12 -05:00
icmd . RunCmd ( cmd ) . Assert ( c , icmd . Success )
2016-11-17 19:51:33 -05:00
2019-09-09 17:05:55 -04:00
assert . Assert ( c , getNodeStatus ( c , d ) , checker . Equals , swarm . LocalNodeStateActive )
2016-11-17 19:51:33 -05:00
outs , err = d . Cmd ( "swarm" , "update" , "--autolock=false" )
2019-09-09 17:05:55 -04:00
assert . Assert ( c , err , checker . IsNil , check . Commentf ( "out: %v" , outs ) )
2016-11-17 19:51:33 -05:00
2018-10-25 01:49:33 -04:00
checkSwarmLockedToUnlocked ( c , d )
2016-11-17 19:51:33 -05:00
}
}
2019-09-09 17:05:55 -04:00
func ( s * DockerSwarmSuite ) TestExtraHosts ( c * testing . T ) {
2016-11-03 11:05:00 -04:00
d := s . AddDaemon ( c , true , true )
// Create a service
name := "top"
2018-08-14 03:51:22 -04:00
out , err := d . Cmd ( "service" , "create" , "--detach" , "--no-resolve-image" , "--name" , name , "--host=example.com:1.2.3.4" , "busybox" , "top" )
2019-04-04 09:23:19 -04:00
assert . NilError ( c , err , out )
2016-11-03 11:05:00 -04:00
// Make sure task has been deployed.
2016-12-09 04:17:53 -05:00
waitAndAssert ( c , defaultReconciliationTimeout , d . CheckActiveContainerCount , checker . Equals , 1 )
2016-11-03 11:05:00 -04:00
// We need to get the container id.
2018-08-14 03:51:22 -04:00
out , err = d . Cmd ( "ps" , "-a" , "-q" , "--no-trunc" )
2019-04-04 09:23:19 -04:00
assert . NilError ( c , err , out )
2016-11-03 11:05:00 -04:00
id := strings . TrimSpace ( out )
// Compare against expected output.
expectedOutput := "1.2.3.4\texample.com"
out , err = d . Cmd ( "exec" , id , "cat" , "/etc/hosts" )
2019-04-04 09:23:19 -04:00
assert . NilError ( c , err , out )
2019-09-09 17:05:55 -04:00
assert . Assert ( c , out , checker . Contains , expectedOutput , check . Commentf ( "Expected '%s', but got %q" , expectedOutput , out ) )
2016-11-03 11:05:00 -04:00
}
2016-11-03 14:23:58 -04:00
2019-09-09 17:05:55 -04:00
func ( s * DockerSwarmSuite ) TestSwarmManagerAddress ( c * testing . T ) {
2016-11-03 14:23:58 -04:00
d1 := s . AddDaemon ( c , true , true )
d2 := s . AddDaemon ( c , true , false )
d3 := s . AddDaemon ( c , true , false )
// Manager Addresses will always show Node 1's address
2018-04-11 06:10:17 -04:00
expectedOutput := fmt . Sprintf ( "Manager Addresses:\n 127.0.0.1:%d\n" , d1 . SwarmPort )
2016-11-03 14:23:58 -04:00
out , err := d1 . Cmd ( "info" )
2019-04-04 09:23:19 -04:00
assert . NilError ( c , err , out )
assert . Assert ( c , strings . Contains ( out , expectedOutput ) )
2016-11-03 14:23:58 -04:00
out , err = d2 . Cmd ( "info" )
2019-04-04 09:23:19 -04:00
assert . NilError ( c , err , out )
assert . Assert ( c , strings . Contains ( out , expectedOutput ) )
2016-11-03 14:23:58 -04:00
out , err = d3 . Cmd ( "info" )
2019-04-04 09:23:19 -04:00
assert . NilError ( c , err , out )
assert . Assert ( c , strings . Contains ( out , expectedOutput ) )
2016-11-03 14:23:58 -04:00
}
2016-11-16 19:46:31 -05:00
2019-09-09 17:05:55 -04:00
func ( s * DockerSwarmSuite ) TestSwarmNetworkIPAMOptions ( c * testing . T ) {
2016-12-02 11:11:30 -05:00
d := s . AddDaemon ( c , true , true )
out , err := d . Cmd ( "network" , "create" , "-d" , "overlay" , "--ipam-opt" , "foo=bar" , "foo" )
2019-04-04 09:23:19 -04:00
assert . NilError ( c , err , out )
assert . Assert ( c , strings . TrimSpace ( out ) != "" )
2016-12-02 11:11:30 -05:00
out , err = d . Cmd ( "network" , "inspect" , "--format" , "{{.IPAM.Options}}" , "foo" )
2019-04-04 09:23:19 -04:00
assert . NilError ( c , err , out )
2019-09-09 17:05:55 -04:00
assert . Assert ( c , strings . TrimSpace ( out ) , checker . Contains , "foo:bar" )
assert . Assert ( c , strings . TrimSpace ( out ) , checker . Contains , "com.docker.network.ipam.serial:true" )
2016-12-02 11:11:30 -05:00
2017-09-27 19:17:55 -04:00
out , err = d . Cmd ( "service" , "create" , "--detach" , "--no-resolve-image" , "--network=foo" , "--name" , "top" , "busybox" , "top" )
2019-04-04 09:23:19 -04:00
assert . NilError ( c , err , out )
2016-12-02 11:11:30 -05:00
// make sure task has been deployed.
waitAndAssert ( c , defaultReconciliationTimeout , d . CheckActiveContainerCount , checker . Equals , 1 )
out , err = d . Cmd ( "network" , "inspect" , "--format" , "{{.IPAM.Options}}" , "foo" )
2019-04-04 09:23:19 -04:00
assert . NilError ( c , err , out )
2019-09-09 17:05:55 -04:00
assert . Assert ( c , strings . TrimSpace ( out ) , checker . Contains , "foo:bar" )
assert . Assert ( c , strings . TrimSpace ( out ) , checker . Contains , "com.docker.network.ipam.serial:true" )
2016-12-02 11:11:30 -05:00
}
2016-11-30 16:23:18 -05:00
2016-11-01 01:49:39 -04:00
// Test case for issue #27866, which did not allow NW name that is the prefix of a swarm NW ID.
// e.g. if the ingress ID starts with "n1", it was impossible to create a NW named "n1".
2019-09-09 17:05:55 -04:00
func ( s * DockerSwarmSuite ) TestSwarmNetworkCreateIssue27866 ( c * testing . T ) {
2016-11-01 01:49:39 -04:00
d := s . AddDaemon ( c , true , true )
out , err := d . Cmd ( "network" , "inspect" , "-f" , "{{.Id}}" , "ingress" )
2019-04-04 09:23:19 -04:00
assert . NilError ( c , err , "out: %v" , out )
2016-11-01 01:49:39 -04:00
ingressID := strings . TrimSpace ( out )
2019-09-09 17:05:56 -04:00
assert . Assert ( c , ingressID != "" )
2016-11-01 01:49:39 -04:00
// create a network of which name is the prefix of the ID of an overlay network
// (ingressID in this case)
newNetName := ingressID [ 0 : 2 ]
out , err = d . Cmd ( "network" , "create" , "--driver" , "overlay" , newNetName )
// In #27866, it was failing because of "network with name %s already exists"
2019-04-04 09:23:19 -04:00
assert . NilError ( c , err , "out: %v" , out )
2016-11-01 01:49:39 -04:00
out , err = d . Cmd ( "network" , "rm" , newNetName )
2019-04-04 09:23:19 -04:00
assert . NilError ( c , err , "out: %v" , out )
2016-11-01 01:49:39 -04:00
}
// Test case for https://github.com/docker/docker/pull/27938#issuecomment-265768303
// This test creates two networks with the same name sequentially, with various drivers.
// Since the operations in this test are done sequentially, the 2nd call should fail with
// "network with name FOO already exists".
// Note that it is to ok have multiple networks with the same name if the operations are done
// in parallel. (#18864)
2019-09-09 17:05:55 -04:00
func ( s * DockerSwarmSuite ) TestSwarmNetworkCreateDup ( c * testing . T ) {
2016-11-01 01:49:39 -04:00
d := s . AddDaemon ( c , true , true )
drivers := [ ] string { "bridge" , "overlay" }
for i , driver1 := range drivers {
nwName := fmt . Sprintf ( "network-test-%d" , i )
for _ , driver2 := range drivers {
c . Logf ( "Creating a network named %q with %q, then %q" ,
nwName , driver1 , driver2 )
out , err := d . Cmd ( "network" , "create" , "--driver" , driver1 , nwName )
2019-04-04 09:23:19 -04:00
assert . NilError ( c , err , "out: %v" , out )
2016-11-01 01:49:39 -04:00
out , err = d . Cmd ( "network" , "create" , "--driver" , driver2 , nwName )
2019-09-09 17:05:55 -04:00
assert . Assert ( c , out , checker . Contains , fmt . Sprintf ( "network with name %s already exists" , nwName ) )
2019-04-04 09:23:19 -04:00
assert . ErrorContains ( c , err , "" )
2016-11-01 01:49:39 -04:00
c . Logf ( "As expected, the attempt to network %q with %q failed: %s" ,
nwName , driver2 , out )
out , err = d . Cmd ( "network" , "rm" , nwName )
2019-04-04 09:23:19 -04:00
assert . NilError ( c , err , "out: %v" , out )
2016-11-01 01:49:39 -04:00
}
}
}
2016-07-29 11:20:03 -04:00
2019-09-09 17:05:55 -04:00
func ( s * DockerSwarmSuite ) TestSwarmPublishDuplicatePorts ( c * testing . T ) {
2016-12-27 16:43:21 -05:00
d := s . AddDaemon ( c , true , true )
2017-05-18 15:23:28 -04:00
out , err := d . Cmd ( "service" , "create" , "--no-resolve-image" , "--detach=true" , "--publish" , "5005:80" , "--publish" , "5006:80" , "--publish" , "80" , "--publish" , "80" , "busybox" , "top" )
2019-04-04 09:23:19 -04:00
assert . NilError ( c , err , out )
2016-12-27 16:43:21 -05:00
id := strings . TrimSpace ( out )
// make sure task has been deployed.
waitAndAssert ( c , defaultReconciliationTimeout , d . CheckActiveContainerCount , checker . Equals , 1 )
// Total len = 4, with 2 dynamic ports and 2 non-dynamic ports
// Dynamic ports are likely to be 30000 and 30001 but doesn't matter
out , err = d . Cmd ( "service" , "inspect" , "--format" , "{{.Endpoint.Ports}} len={{len .Endpoint.Ports}}" , id )
2019-04-04 09:23:19 -04:00
assert . NilError ( c , err , out )
2019-09-09 17:05:55 -04:00
assert . Assert ( c , out , checker . Contains , "len=4" )
assert . Assert ( c , out , checker . Contains , "{ tcp 80 5005 ingress}" )
assert . Assert ( c , out , checker . Contains , "{ tcp 80 5006 ingress}" )
2016-12-27 16:43:21 -05:00
}
2016-12-21 21:06:16 -05:00
2019-09-09 17:05:55 -04:00
func ( s * DockerSwarmSuite ) TestSwarmJoinWithDrain ( c * testing . T ) {
2016-12-21 21:06:16 -05:00
d := s . AddDaemon ( c , true , true )
out , err := d . Cmd ( "node" , "ls" )
2019-04-04 09:23:19 -04:00
assert . NilError ( c , err )
2019-09-09 17:05:55 -04:00
assert . Assert ( c , out , checker . Not ( checker . Contains ) , "Drain" )
2016-12-21 21:06:16 -05:00
out , err = d . Cmd ( "swarm" , "join-token" , "-q" , "manager" )
2019-04-04 09:23:19 -04:00
assert . NilError ( c , err )
assert . Assert ( c , strings . TrimSpace ( out ) != "" )
2016-12-21 21:06:16 -05:00
token := strings . TrimSpace ( out )
d1 := s . AddDaemon ( c , false , false )
2018-04-11 06:10:17 -04:00
out , err = d1 . Cmd ( "swarm" , "join" , "--availability=drain" , "--token" , token , d . SwarmListenAddr ( ) )
2019-04-04 09:23:19 -04:00
assert . NilError ( c , err )
assert . Assert ( c , strings . TrimSpace ( out ) != "" )
2016-12-21 21:06:16 -05:00
out , err = d . Cmd ( "node" , "ls" )
2019-04-04 09:23:19 -04:00
assert . NilError ( c , err )
2019-09-09 17:05:55 -04:00
assert . Assert ( c , out , checker . Contains , "Drain" )
2016-12-21 21:06:16 -05:00
out , err = d1 . Cmd ( "node" , "ls" )
2019-04-04 09:23:19 -04:00
assert . NilError ( c , err )
2019-09-09 17:05:55 -04:00
assert . Assert ( c , out , checker . Contains , "Drain" )
2016-12-21 21:06:16 -05:00
}
2016-12-21 21:13:31 -05:00
2019-09-09 17:05:55 -04:00
func ( s * DockerSwarmSuite ) TestSwarmInitWithDrain ( c * testing . T ) {
2016-12-21 21:13:31 -05:00
d := s . AddDaemon ( c , false , false )
out , err := d . Cmd ( "swarm" , "init" , "--availability" , "drain" )
2019-04-04 09:23:19 -04:00
assert . NilError ( c , err , "out: %v" , out )
2016-12-21 21:13:31 -05:00
out , err = d . Cmd ( "node" , "ls" )
2019-04-04 09:23:19 -04:00
assert . NilError ( c , err )
2019-09-09 17:05:55 -04:00
assert . Assert ( c , out , checker . Contains , "Drain" )
2016-12-21 21:13:31 -05:00
}
2017-01-14 03:12:19 -05:00
2019-09-09 17:05:55 -04:00
func ( s * DockerSwarmSuite ) TestSwarmReadonlyRootfs ( c * testing . T ) {
2017-01-14 03:12:19 -05:00
testRequires ( c , DaemonIsLinux , UserNamespaceROMount )
d := s . AddDaemon ( c , true , true )
2017-09-27 19:17:55 -04:00
out , err := d . Cmd ( "service" , "create" , "--detach" , "--no-resolve-image" , "--name" , "top" , "--read-only" , "busybox" , "top" )
2019-04-04 09:23:19 -04:00
assert . NilError ( c , err , out )
2017-01-14 03:12:19 -05:00
// make sure task has been deployed.
waitAndAssert ( c , defaultReconciliationTimeout , d . CheckActiveContainerCount , checker . Equals , 1 )
out , err = d . Cmd ( "service" , "inspect" , "--format" , "{{ .Spec.TaskTemplate.ContainerSpec.ReadOnly }}" , "top" )
2019-04-04 09:23:19 -04:00
assert . NilError ( c , err , out )
assert . Equal ( c , strings . TrimSpace ( out ) , "true" )
2017-01-14 03:12:19 -05:00
2018-04-11 09:52:13 -04:00
containers := d . ActiveContainers ( c )
2017-01-14 03:12:19 -05:00
out , err = d . Cmd ( "inspect" , "--type" , "container" , "--format" , "{{.HostConfig.ReadonlyRootfs}}" , containers [ 0 ] )
2019-04-04 09:23:19 -04:00
assert . NilError ( c , err , out )
assert . Equal ( c , strings . TrimSpace ( out ) , "true" )
2017-01-14 03:12:19 -05:00
}
2017-01-19 06:04:26 -05:00
2019-09-09 17:05:55 -04:00
func ( s * DockerSwarmSuite ) TestNetworkInspectWithDuplicateNames ( c * testing . T ) {
2017-01-19 06:04:26 -05:00
d := s . AddDaemon ( c , true , true )
name := "foo"
2017-05-23 23:56:26 -04:00
options := types . NetworkCreate {
CheckDuplicate : false ,
Driver : "bridge" ,
2017-01-19 06:04:26 -05:00
}
2018-12-22 09:53:02 -05:00
cli := d . NewClientT ( c )
2017-05-23 23:56:26 -04:00
defer cli . Close ( )
n1 , err := cli . NetworkCreate ( context . Background ( ) , name , options )
2019-04-04 09:23:19 -04:00
assert . NilError ( c , err )
2017-01-19 06:04:26 -05:00
// Full ID always works
out , err := d . Cmd ( "network" , "inspect" , "--format" , "{{.ID}}" , n1 . ID )
2019-04-04 09:23:19 -04:00
assert . NilError ( c , err , out )
assert . Equal ( c , strings . TrimSpace ( out ) , n1 . ID )
2017-01-19 06:04:26 -05:00
// Name works if it is unique
out , err = d . Cmd ( "network" , "inspect" , "--format" , "{{.ID}}" , name )
2019-04-04 09:23:19 -04:00
assert . NilError ( c , err , out )
assert . Equal ( c , strings . TrimSpace ( out ) , n1 . ID )
2017-01-19 06:04:26 -05:00
2017-05-23 23:56:26 -04:00
n2 , err := cli . NetworkCreate ( context . Background ( ) , name , options )
2019-04-04 09:23:19 -04:00
assert . NilError ( c , err )
2017-01-19 06:04:26 -05:00
// Full ID always works
out , err = d . Cmd ( "network" , "inspect" , "--format" , "{{.ID}}" , n1 . ID )
2019-04-04 09:23:19 -04:00
assert . NilError ( c , err , out )
assert . Equal ( c , strings . TrimSpace ( out ) , n1 . ID )
2017-01-19 06:04:26 -05:00
out , err = d . Cmd ( "network" , "inspect" , "--format" , "{{.ID}}" , n2 . ID )
2019-04-04 09:23:19 -04:00
assert . NilError ( c , err , out )
assert . Equal ( c , strings . TrimSpace ( out ) , n2 . ID )
2017-01-19 06:04:26 -05:00
// Name with duplicates
out , err = d . Cmd ( "network" , "inspect" , "--format" , "{{.ID}}" , name )
2019-04-04 09:23:19 -04:00
assert . ErrorContains ( c , err , "" , out )
2019-09-09 17:05:55 -04:00
assert . Assert ( c , out , checker . Contains , "2 matches found based on name" )
2017-01-19 06:04:26 -05:00
out , err = d . Cmd ( "network" , "rm" , n2 . ID )
2019-04-04 09:23:19 -04:00
assert . NilError ( c , err , out )
2017-01-19 06:04:26 -05:00
2018-09-27 11:51:03 -04:00
// Duplicates with name but with different driver
2017-05-23 23:56:26 -04:00
options . Driver = "overlay"
2017-01-19 06:04:26 -05:00
2017-05-23 23:56:26 -04:00
n2 , err = cli . NetworkCreate ( context . Background ( ) , name , options )
2019-04-04 09:23:19 -04:00
assert . NilError ( c , err )
2017-01-19 06:04:26 -05:00
// Full ID always works
out , err = d . Cmd ( "network" , "inspect" , "--format" , "{{.ID}}" , n1 . ID )
2019-04-04 09:23:19 -04:00
assert . NilError ( c , err , out )
assert . Equal ( c , strings . TrimSpace ( out ) , n1 . ID )
2017-01-19 06:04:26 -05:00
out , err = d . Cmd ( "network" , "inspect" , "--format" , "{{.ID}}" , n2 . ID )
2019-04-04 09:23:19 -04:00
assert . NilError ( c , err , out )
assert . Equal ( c , strings . TrimSpace ( out ) , n2 . ID )
2017-01-19 06:04:26 -05:00
// Name with duplicates
out , err = d . Cmd ( "network" , "inspect" , "--format" , "{{.ID}}" , name )
2019-04-04 09:23:19 -04:00
assert . ErrorContains ( c , err , "" , out )
2019-09-09 17:05:55 -04:00
assert . Assert ( c , out , checker . Contains , "2 matches found based on name" )
2017-01-19 06:04:26 -05:00
}
2017-02-06 00:22:57 -05:00
2019-09-09 17:05:55 -04:00
func ( s * DockerSwarmSuite ) TestSwarmStopSignal ( c * testing . T ) {
2017-02-06 00:22:57 -05:00
testRequires ( c , DaemonIsLinux , UserNamespaceROMount )
d := s . AddDaemon ( c , true , true )
2017-09-27 19:17:55 -04:00
out , err := d . Cmd ( "service" , "create" , "--detach" , "--no-resolve-image" , "--name" , "top" , "--stop-signal=SIGHUP" , "busybox" , "top" )
2019-04-04 09:23:19 -04:00
assert . NilError ( c , err , out )
2017-02-06 00:22:57 -05:00
// make sure task has been deployed.
waitAndAssert ( c , defaultReconciliationTimeout , d . CheckActiveContainerCount , checker . Equals , 1 )
out , err = d . Cmd ( "service" , "inspect" , "--format" , "{{ .Spec.TaskTemplate.ContainerSpec.StopSignal }}" , "top" )
2019-04-04 09:23:19 -04:00
assert . NilError ( c , err , out )
assert . Equal ( c , strings . TrimSpace ( out ) , "SIGHUP" )
2017-02-06 00:22:57 -05:00
2018-04-11 09:52:13 -04:00
containers := d . ActiveContainers ( c )
2017-02-06 00:22:57 -05:00
out , err = d . Cmd ( "inspect" , "--type" , "container" , "--format" , "{{.Config.StopSignal}}" , containers [ 0 ] )
2019-04-04 09:23:19 -04:00
assert . NilError ( c , err , out )
assert . Equal ( c , strings . TrimSpace ( out ) , "SIGHUP" )
2017-02-06 00:22:57 -05:00
2017-09-27 19:17:55 -04:00
out , err = d . Cmd ( "service" , "update" , "--detach" , "--stop-signal=SIGUSR1" , "top" )
2019-04-04 09:23:19 -04:00
assert . NilError ( c , err , out )
2017-02-06 00:22:57 -05:00
out , err = d . Cmd ( "service" , "inspect" , "--format" , "{{ .Spec.TaskTemplate.ContainerSpec.StopSignal }}" , "top" )
2019-04-04 09:23:19 -04:00
assert . NilError ( c , err , out )
assert . Equal ( c , strings . TrimSpace ( out ) , "SIGUSR1" )
2017-02-06 00:22:57 -05:00
}
2017-03-03 17:08:49 -05:00
2019-09-09 17:05:55 -04:00
func ( s * DockerSwarmSuite ) TestSwarmServiceLsFilterMode ( c * testing . T ) {
2017-03-03 17:08:49 -05:00
d := s . AddDaemon ( c , true , true )
2017-09-27 19:17:55 -04:00
out , err := d . Cmd ( "service" , "create" , "--detach" , "--no-resolve-image" , "--name" , "top1" , "busybox" , "top" )
2019-04-04 09:23:19 -04:00
assert . NilError ( c , err , out )
assert . Assert ( c , strings . TrimSpace ( out ) != "" )
2017-03-03 17:08:49 -05:00
2017-09-27 19:17:55 -04:00
out , err = d . Cmd ( "service" , "create" , "--detach" , "--no-resolve-image" , "--name" , "top2" , "--mode=global" , "busybox" , "top" )
2019-04-04 09:23:19 -04:00
assert . NilError ( c , err , out )
assert . Assert ( c , strings . TrimSpace ( out ) != "" )
2017-03-03 17:08:49 -05:00
// make sure task has been deployed.
waitAndAssert ( c , defaultReconciliationTimeout , d . CheckActiveContainerCount , checker . Equals , 2 )
out , err = d . Cmd ( "service" , "ls" )
2019-04-04 09:23:19 -04:00
assert . NilError ( c , err , out )
2019-09-09 17:05:55 -04:00
assert . Assert ( c , out , checker . Contains , "top1" )
assert . Assert ( c , out , checker . Contains , "top2" )
assert . Assert ( c , out , checker . Not ( checker . Contains ) , "localnet" )
2017-03-03 17:08:49 -05:00
out , err = d . Cmd ( "service" , "ls" , "--filter" , "mode=global" )
2019-09-09 17:05:55 -04:00
assert . Assert ( c , out , checker . Not ( checker . Contains ) , "top1" )
assert . Assert ( c , out , checker . Contains , "top2" )
2019-04-04 09:23:19 -04:00
assert . NilError ( c , err , out )
2017-03-03 17:08:49 -05:00
out , err = d . Cmd ( "service" , "ls" , "--filter" , "mode=replicated" )
2019-04-04 09:23:19 -04:00
assert . NilError ( c , err , out )
2019-09-09 17:05:55 -04:00
assert . Assert ( c , out , checker . Contains , "top1" )
assert . Assert ( c , out , checker . Not ( checker . Contains ) , "top2" )
2017-03-03 17:08:49 -05:00
}
2017-04-14 19:54:17 -04:00
2019-09-09 17:05:55 -04:00
func ( s * DockerSwarmSuite ) TestSwarmInitUnspecifiedDataPathAddr ( c * testing . T ) {
2017-04-14 19:54:17 -04:00
d := s . AddDaemon ( c , false , false )
out , err := d . Cmd ( "swarm" , "init" , "--data-path-addr" , "0.0.0.0" )
2019-04-04 09:23:19 -04:00
assert . ErrorContains ( c , err , "" )
2019-09-09 17:05:55 -04:00
assert . Assert ( c , out , checker . Contains , "data path address must be a non-zero IP" )
2017-04-14 19:54:17 -04:00
out , err = d . Cmd ( "swarm" , "init" , "--data-path-addr" , "0.0.0.0:2000" )
2019-04-04 09:23:19 -04:00
assert . ErrorContains ( c , err , "" )
2019-09-09 17:05:55 -04:00
assert . Assert ( c , out , checker . Contains , "data path address must be a non-zero IP" )
2017-04-14 19:54:17 -04:00
}
2017-04-30 17:51:43 -04:00
2019-09-09 17:05:55 -04:00
func ( s * DockerSwarmSuite ) TestSwarmJoinLeave ( c * testing . T ) {
2017-04-30 17:51:43 -04:00
d := s . AddDaemon ( c , true , true )
out , err := d . Cmd ( "swarm" , "join-token" , "-q" , "worker" )
2019-04-04 09:23:19 -04:00
assert . NilError ( c , err )
assert . Assert ( c , strings . TrimSpace ( out ) != "" )
2017-04-30 17:51:43 -04:00
token := strings . TrimSpace ( out )
// Verify that back to back join/leave does not cause panics
d1 := s . AddDaemon ( c , false , false )
for i := 0 ; i < 10 ; i ++ {
2018-04-11 06:10:17 -04:00
out , err = d1 . Cmd ( "swarm" , "join" , "--token" , token , d . SwarmListenAddr ( ) )
2019-04-04 09:23:19 -04:00
assert . NilError ( c , err )
assert . Assert ( c , strings . TrimSpace ( out ) != "" )
2017-04-30 17:51:43 -04:00
_ , err = d1 . Cmd ( "swarm" , "leave" )
2019-04-04 09:23:19 -04:00
assert . NilError ( c , err )
2017-04-30 17:51:43 -04:00
}
}
2017-04-02 18:21:56 -04:00
2017-05-19 06:25:14 -04:00
const defaultRetryCount = 10
2019-09-09 17:05:55 -04:00
func waitForEvent ( c * testing . T , d * daemon . Daemon , since string , filter string , event string , retry int ) string {
2017-05-19 06:25:14 -04:00
if retry < 1 {
c . Fatalf ( "retry count %d is invalid. It should be no less than 1" , retry )
return ""
}
var out string
for i := 0 ; i < retry ; i ++ {
until := daemonUnixTime ( c )
var err error
if len ( filter ) > 0 {
out , err = d . Cmd ( "events" , "--since" , since , "--until" , until , filter )
} else {
out , err = d . Cmd ( "events" , "--since" , since , "--until" , until )
}
2019-04-04 09:23:19 -04:00
assert . NilError ( c , err , out )
2017-05-19 06:25:14 -04:00
if strings . Contains ( out , event ) {
return strings . TrimSpace ( out )
}
// no need to sleep after last retry
if i < retry - 1 {
time . Sleep ( 200 * time . Millisecond )
}
}
c . Fatalf ( "docker events output '%s' doesn't contain event '%s'" , out , event )
return ""
}
2019-09-09 17:05:55 -04:00
func ( s * DockerSwarmSuite ) TestSwarmClusterEventsSource ( c * testing . T ) {
2017-04-02 18:21:56 -04:00
d1 := s . AddDaemon ( c , true , true )
d2 := s . AddDaemon ( c , true , true )
d3 := s . AddDaemon ( c , true , false )
// create a network
out , err := d1 . Cmd ( "network" , "create" , "--attachable" , "-d" , "overlay" , "foo" )
2019-04-04 09:23:19 -04:00
assert . NilError ( c , err , out )
2017-04-02 18:21:56 -04:00
networkID := strings . TrimSpace ( out )
2019-09-09 17:05:56 -04:00
assert . Assert ( c , networkID != "" )
2017-04-02 18:21:56 -04:00
2017-05-19 06:25:14 -04:00
// d1, d2 are managers that can get swarm events
waitForEvent ( c , d1 , "0" , "-f scope=swarm" , "network create " + networkID , defaultRetryCount )
waitForEvent ( c , d2 , "0" , "-f scope=swarm" , "network create " + networkID , defaultRetryCount )
2017-04-02 18:21:56 -04:00
// d3 is a worker, not able to get cluster events
2017-05-19 06:25:14 -04:00
out = waitForEvent ( c , d3 , "0" , "-f scope=swarm" , "" , 1 )
2019-09-09 17:05:55 -04:00
assert . Assert ( c , out , checker . Not ( checker . Contains ) , "network create " )
2017-04-02 18:21:56 -04:00
}
2019-09-09 17:05:55 -04:00
func ( s * DockerSwarmSuite ) TestSwarmClusterEventsScope ( c * testing . T ) {
2017-04-02 18:21:56 -04:00
d := s . AddDaemon ( c , true , true )
// create a service
2017-05-18 15:23:28 -04:00
out , err := d . Cmd ( "service" , "create" , "--no-resolve-image" , "--name" , "test" , "--detach=false" , "busybox" , "top" )
2019-04-04 09:23:19 -04:00
assert . NilError ( c , err , out )
2017-04-02 18:21:56 -04:00
serviceID := strings . Split ( out , "\n" ) [ 0 ]
// scope swarm filters cluster events
2017-05-19 06:25:14 -04:00
out = waitForEvent ( c , d , "0" , "-f scope=swarm" , "service create " + serviceID , defaultRetryCount )
2019-09-09 17:05:55 -04:00
assert . Assert ( c , out , checker . Not ( checker . Contains ) , "container create " )
2017-04-02 18:21:56 -04:00
2017-05-19 06:25:14 -04:00
// all events are returned if scope is not specified
waitForEvent ( c , d , "0" , "" , "service create " + serviceID , 1 )
waitForEvent ( c , d , "0" , "" , "container create " , defaultRetryCount )
2017-04-02 18:21:56 -04:00
2017-05-19 06:25:14 -04:00
// scope local only shows non-cluster events
out = waitForEvent ( c , d , "0" , "-f scope=local" , "container create " , 1 )
2019-09-09 17:05:55 -04:00
assert . Assert ( c , out , checker . Not ( checker . Contains ) , "service create " )
2017-04-02 18:21:56 -04:00
}
2019-09-09 17:05:55 -04:00
func ( s * DockerSwarmSuite ) TestSwarmClusterEventsType ( c * testing . T ) {
2017-04-02 18:21:56 -04:00
d := s . AddDaemon ( c , true , true )
// create a service
2017-05-18 15:23:28 -04:00
out , err := d . Cmd ( "service" , "create" , "--no-resolve-image" , "--name" , "test" , "--detach=false" , "busybox" , "top" )
2019-04-04 09:23:19 -04:00
assert . NilError ( c , err , out )
2017-04-02 18:21:56 -04:00
serviceID := strings . Split ( out , "\n" ) [ 0 ]
// create a network
out , err = d . Cmd ( "network" , "create" , "--attachable" , "-d" , "overlay" , "foo" )
2019-04-04 09:23:19 -04:00
assert . NilError ( c , err , out )
2017-04-02 18:21:56 -04:00
networkID := strings . TrimSpace ( out )
2019-09-09 17:05:56 -04:00
assert . Assert ( c , networkID != "" )
2017-04-02 18:21:56 -04:00
// filter by service
2017-05-19 06:25:14 -04:00
out = waitForEvent ( c , d , "0" , "-f type=service" , "service create " + serviceID , defaultRetryCount )
2019-09-09 17:05:55 -04:00
assert . Assert ( c , out , checker . Not ( checker . Contains ) , "network create" )
2017-04-02 18:21:56 -04:00
// filter by network
2017-05-19 06:25:14 -04:00
out = waitForEvent ( c , d , "0" , "-f type=network" , "network create " + networkID , defaultRetryCount )
2019-09-09 17:05:55 -04:00
assert . Assert ( c , out , checker . Not ( checker . Contains ) , "service create" )
2017-04-02 18:21:56 -04:00
}
2019-09-09 17:05:55 -04:00
func ( s * DockerSwarmSuite ) TestSwarmClusterEventsService ( c * testing . T ) {
2017-04-02 18:21:56 -04:00
d := s . AddDaemon ( c , true , true )
// create a service
2017-05-18 15:23:28 -04:00
out , err := d . Cmd ( "service" , "create" , "--no-resolve-image" , "--name" , "test" , "--detach=false" , "busybox" , "top" )
2019-04-04 09:23:19 -04:00
assert . NilError ( c , err , out )
2017-04-02 18:21:56 -04:00
serviceID := strings . Split ( out , "\n" ) [ 0 ]
// validate service create event
2017-05-19 06:25:14 -04:00
waitForEvent ( c , d , "0" , "-f scope=swarm" , "service create " + serviceID , defaultRetryCount )
2017-04-02 18:21:56 -04:00
2017-05-19 06:25:14 -04:00
t1 := daemonUnixTime ( c )
2017-04-02 18:21:56 -04:00
out , err = d . Cmd ( "service" , "update" , "--force" , "--detach=false" , "test" )
2019-04-04 09:23:19 -04:00
assert . NilError ( c , err , out )
2017-04-02 18:21:56 -04:00
2017-05-19 06:25:14 -04:00
// wait for service update start
out = waitForEvent ( c , d , t1 , "-f scope=swarm" , "service update " + serviceID , defaultRetryCount )
2019-09-09 17:05:55 -04:00
assert . Assert ( c , out , checker . Contains , "updatestate.new=updating" )
2017-05-19 06:25:14 -04:00
// allow service update complete. This is a service with 1 instance
time . Sleep ( 400 * time . Millisecond )
out = waitForEvent ( c , d , t1 , "-f scope=swarm" , "service update " + serviceID , defaultRetryCount )
2019-09-09 17:05:55 -04:00
assert . Assert ( c , out , checker . Contains , "updatestate.new=completed, updatestate.old=updating" )
2017-04-02 18:21:56 -04:00
// scale service
2017-05-19 06:25:14 -04:00
t2 := daemonUnixTime ( c )
2017-09-27 20:47:51 -04:00
out , err = d . Cmd ( "service" , "scale" , "test=3" )
2019-04-04 09:23:19 -04:00
assert . NilError ( c , err , out )
2017-04-02 18:21:56 -04:00
2017-05-19 06:25:14 -04:00
out = waitForEvent ( c , d , t2 , "-f scope=swarm" , "service update " + serviceID , defaultRetryCount )
2019-09-09 17:05:55 -04:00
assert . Assert ( c , out , checker . Contains , "replicas.new=3, replicas.old=1" )
2017-04-02 18:21:56 -04:00
// remove service
2017-05-19 06:25:14 -04:00
t3 := daemonUnixTime ( c )
2017-04-02 18:21:56 -04:00
out , err = d . Cmd ( "service" , "rm" , "test" )
2019-04-04 09:23:19 -04:00
assert . NilError ( c , err , out )
2017-04-02 18:21:56 -04:00
2017-05-19 06:25:14 -04:00
waitForEvent ( c , d , t3 , "-f scope=swarm" , "service remove " + serviceID , defaultRetryCount )
2017-04-02 18:21:56 -04:00
}
2019-09-09 17:05:55 -04:00
func ( s * DockerSwarmSuite ) TestSwarmClusterEventsNode ( c * testing . T ) {
2017-04-02 18:21:56 -04:00
d1 := s . AddDaemon ( c , true , true )
s . AddDaemon ( c , true , true )
d3 := s . AddDaemon ( c , true , true )
2018-04-11 06:10:17 -04:00
d3ID := d3 . NodeID ( )
2017-05-19 06:25:14 -04:00
waitForEvent ( c , d1 , "0" , "-f scope=swarm" , "node create " + d3ID , defaultRetryCount )
2017-04-02 18:21:56 -04:00
2017-05-19 06:25:14 -04:00
t1 := daemonUnixTime ( c )
out , err := d1 . Cmd ( "node" , "update" , "--availability=pause" , d3ID )
2019-04-04 09:23:19 -04:00
assert . NilError ( c , err , out )
2017-04-02 18:21:56 -04:00
// filter by type
2017-05-19 06:25:14 -04:00
out = waitForEvent ( c , d1 , t1 , "-f type=node" , "node update " + d3ID , defaultRetryCount )
2019-09-09 17:05:55 -04:00
assert . Assert ( c , out , checker . Contains , "availability.new=pause, availability.old=active" )
2017-04-02 18:21:56 -04:00
2017-05-19 06:25:14 -04:00
t2 := daemonUnixTime ( c )
2017-04-02 18:21:56 -04:00
out , err = d1 . Cmd ( "node" , "demote" , d3ID )
2019-04-04 09:23:19 -04:00
assert . NilError ( c , err , out )
2017-04-02 18:21:56 -04:00
2017-05-19 06:25:14 -04:00
waitForEvent ( c , d1 , t2 , "-f type=node" , "node update " + d3ID , defaultRetryCount )
2017-04-02 18:21:56 -04:00
2017-05-19 06:25:14 -04:00
t3 := daemonUnixTime ( c )
2017-04-02 18:21:56 -04:00
out , err = d1 . Cmd ( "node" , "rm" , "-f" , d3ID )
2019-04-04 09:23:19 -04:00
assert . NilError ( c , err , out )
2017-04-02 18:21:56 -04:00
2017-05-19 06:25:14 -04:00
// filter by scope
waitForEvent ( c , d1 , t3 , "-f scope=swarm" , "node remove " + d3ID , defaultRetryCount )
2017-04-02 18:21:56 -04:00
}
2019-09-09 17:05:55 -04:00
func ( s * DockerSwarmSuite ) TestSwarmClusterEventsNetwork ( c * testing . T ) {
2017-04-02 18:21:56 -04:00
d := s . AddDaemon ( c , true , true )
// create a network
out , err := d . Cmd ( "network" , "create" , "--attachable" , "-d" , "overlay" , "foo" )
2019-04-04 09:23:19 -04:00
assert . NilError ( c , err , out )
2017-04-02 18:21:56 -04:00
networkID := strings . TrimSpace ( out )
2017-05-19 06:25:14 -04:00
waitForEvent ( c , d , "0" , "-f scope=swarm" , "network create " + networkID , defaultRetryCount )
2017-04-02 18:21:56 -04:00
// remove network
2017-05-19 06:25:14 -04:00
t1 := daemonUnixTime ( c )
2017-04-02 18:21:56 -04:00
out , err = d . Cmd ( "network" , "rm" , "foo" )
2019-04-04 09:23:19 -04:00
assert . NilError ( c , err , out )
2017-04-02 18:21:56 -04:00
// filtered by network
2017-05-19 06:25:14 -04:00
waitForEvent ( c , d , t1 , "-f type=network" , "network remove " + networkID , defaultRetryCount )
2017-04-02 18:21:56 -04:00
}
2019-09-09 17:05:55 -04:00
func ( s * DockerSwarmSuite ) TestSwarmClusterEventsSecret ( c * testing . T ) {
2017-04-02 18:21:56 -04:00
d := s . AddDaemon ( c , true , true )
testName := "test_secret"
id := d . CreateSecret ( c , swarm . SecretSpec {
Annotations : swarm . Annotations {
Name : testName ,
} ,
Data : [ ] byte ( "TESTINGDATA" ) ,
} )
2019-09-09 17:05:56 -04:00
assert . Assert ( c , id != "" , check . Commentf ( "secrets: %s" , id ) )
2017-04-02 18:21:56 -04:00
2017-05-19 06:25:14 -04:00
waitForEvent ( c , d , "0" , "-f scope=swarm" , "secret create " + id , defaultRetryCount )
2017-04-02 18:21:56 -04:00
2017-05-19 06:25:14 -04:00
t1 := daemonUnixTime ( c )
2017-04-02 18:21:56 -04:00
d . DeleteSecret ( c , id )
// filtered by secret
2017-05-19 06:25:14 -04:00
waitForEvent ( c , d , t1 , "-f type=secret" , "secret remove " + id , defaultRetryCount )
2017-04-02 18:21:56 -04:00
}
2017-07-09 23:41:25 -04:00
2019-09-09 17:05:55 -04:00
func ( s * DockerSwarmSuite ) TestSwarmClusterEventsConfig ( c * testing . T ) {
2017-07-09 23:41:25 -04:00
d := s . AddDaemon ( c , true , true )
testName := "test_config"
id := d . CreateConfig ( c , swarm . ConfigSpec {
Annotations : swarm . Annotations {
Name : testName ,
} ,
Data : [ ] byte ( "TESTINGDATA" ) ,
} )
2019-09-09 17:05:56 -04:00
assert . Assert ( c , id != "" , check . Commentf ( "configs: %s" , id ) )
2017-07-09 23:41:25 -04:00
waitForEvent ( c , d , "0" , "-f scope=swarm" , "config create " + id , defaultRetryCount )
t1 := daemonUnixTime ( c )
d . DeleteConfig ( c , id )
// filtered by config
waitForEvent ( c , d , t1 , "-f type=config" , "config remove " + id , defaultRetryCount )
}
2018-10-29 16:46:21 -04:00
2019-09-09 17:05:55 -04:00
func getUnlockKey ( d * daemon . Daemon , c * testing . T , autolockOutput string ) string {
2018-10-29 16:46:21 -04:00
unlockKey , err := d . Cmd ( "swarm" , "unlock-key" , "-q" )
2019-09-09 17:05:55 -04:00
assert . Assert ( c , err , checker . IsNil , check . Commentf ( "%s" , unlockKey ) )
2018-10-29 16:46:21 -04:00
unlockKey = strings . TrimSuffix ( unlockKey , "\n" )
// Check that "docker swarm init --autolock" or "docker swarm update --autolock"
// contains all the expected strings, including the unlock key
2019-09-09 17:05:55 -04:00
assert . Assert ( c , autolockOutput , checker . Contains , "docker swarm unlock" )
assert . Assert ( c , autolockOutput , checker . Contains , unlockKey )
2018-10-29 16:46:21 -04:00
return unlockKey
}