1package provision 2 3import ( 4 "fmt" 5 "regexp" 6 "strings" 7 "testing" 8 9 "github.com/docker/machine/drivers/fakedriver" 10 "github.com/docker/machine/libmachine/auth" 11 "github.com/docker/machine/libmachine/engine" 12 "github.com/docker/machine/libmachine/provision/pkgaction" 13 "github.com/docker/machine/libmachine/provision/provisiontest" 14 "github.com/docker/machine/libmachine/provision/serviceaction" 15 "github.com/docker/machine/libmachine/swarm" 16 "github.com/stretchr/testify/assert" 17) 18 19var ( 20 reDaemonListening = ":2376\\s+.*:.*" 21) 22 23func TestMatchNetstatOutMissing(t *testing.T) { 24 nsOut := `Active Internet connections (servers and established) 25Proto Recv-Q Send-Q Local Address Foreign Address State 26tcp 0 0 0.0.0.0:22 0.0.0.0:* LISTEN 27tcp 0 0 0.0.0.0:237 0.0.0.0:* LISTEN 28tcp6 0 0 :::22 :::* LISTEN 29tcp6 0 0 :::23760 :::* LISTEN` 30 if matchNetstatOut(reDaemonListening, nsOut) { 31 t.Fatal("Expected not to match the netstat output as showing the daemon listening but got a match") 32 } 33} 34 35func TestMatchNetstatOutPresent(t *testing.T) { 36 nsOut := `Active Internet connections (servers and established) 37Proto Recv-Q Send-Q Local Address Foreign Address State 38tcp 0 0 0.0.0.0:22 0.0.0.0:* LISTEN 39tcp6 0 0 :::2376 :::* LISTEN 40tcp6 0 0 :::22 :::* LISTEN` 41 if !matchNetstatOut(reDaemonListening, nsOut) { 42 t.Fatal("Expected to match the netstat output as showing the daemon listening but didn't") 43 } 44} 45 46func TestMatchSsOutMissing(t *testing.T) { 47 ssOut := `State Recv-Q Send-Q Local Address:Port Peer Address:Port 48LISTEN 0 128 *:22 *:* 49LISTEN 0 128 :::22 :::* 50LISTEN 0 128 :::23760 :::* ` 51 if matchNetstatOut(reDaemonListening, ssOut) { 52 t.Fatal("Expected not to match the ss output as showing the daemon listening but got a match") 53 } 54} 55 56func TestMatchSsOutPresent(t *testing.T) { 57 ssOut := `State Recv-Q Send-Q Local Address:Port Peer Address:Port 58LISTEN 0 128 *:22 *:* 59LISTEN 0 128 :::22 :::* 60LISTEN 0 128 :::2376 :::* ` 61 if !matchNetstatOut(reDaemonListening, ssOut) { 62 t.Fatal("Expected to match the ss output as showing the daemon listening but didn't") 63 } 64} 65 66func TestGenerateDockerOptionsBoot2Docker(t *testing.T) { 67 p := &Boot2DockerProvisioner{ 68 Driver: &fakedriver.Driver{}, 69 } 70 dockerPort := 1234 71 p.AuthOptions = auth.Options{ 72 CaCertRemotePath: "/test/ca-cert", 73 ServerKeyRemotePath: "/test/server-key", 74 ServerCertRemotePath: "/test/server-cert", 75 } 76 engineConfigPath := "/var/lib/boot2docker/profile" 77 78 dockerCfg, err := p.GenerateDockerOptions(dockerPort) 79 if err != nil { 80 t.Fatal(err) 81 } 82 83 if dockerCfg.EngineOptionsPath != engineConfigPath { 84 t.Fatalf("expected engine path %s; received %s", engineConfigPath, dockerCfg.EngineOptionsPath) 85 } 86 87 if strings.Index(dockerCfg.EngineOptions, fmt.Sprintf("-H tcp://0.0.0.0:%d", dockerPort)) == -1 { 88 t.Fatalf("-H docker port invalid; expected %d", dockerPort) 89 } 90 91 if strings.Index(dockerCfg.EngineOptions, fmt.Sprintf("CACERT=%s", p.AuthOptions.CaCertRemotePath)) == -1 { 92 t.Fatalf("CACERT option invalid; expected %s", p.AuthOptions.CaCertRemotePath) 93 } 94 95 if strings.Index(dockerCfg.EngineOptions, fmt.Sprintf("SERVERKEY=%s", p.AuthOptions.ServerKeyRemotePath)) == -1 { 96 t.Fatalf("SERVERKEY option invalid; expected %s", p.AuthOptions.ServerKeyRemotePath) 97 } 98 99 if strings.Index(dockerCfg.EngineOptions, fmt.Sprintf("SERVERCERT=%s", p.AuthOptions.ServerCertRemotePath)) == -1 { 100 t.Fatalf("SERVERCERT option invalid; expected %s", p.AuthOptions.ServerCertRemotePath) 101 } 102} 103 104func TestMachinePortBoot2Docker(t *testing.T) { 105 p := &Boot2DockerProvisioner{ 106 Driver: &fakedriver.Driver{}, 107 } 108 dockerPort := engine.DefaultPort 109 bindURL := fmt.Sprintf("tcp://0.0.0.0:%d", dockerPort) 110 p.AuthOptions = auth.Options{ 111 CaCertRemotePath: "/test/ca-cert", 112 ServerKeyRemotePath: "/test/server-key", 113 ServerCertRemotePath: "/test/server-cert", 114 } 115 116 cfg, err := p.GenerateDockerOptions(dockerPort) 117 if err != nil { 118 t.Fatal(err) 119 } 120 re := regexp.MustCompile("-H tcp://.*:(.+)") 121 m := re.FindStringSubmatch(cfg.EngineOptions) 122 if len(m) == 0 { 123 t.Errorf("could not find port %d in engine config", dockerPort) 124 } 125 126 b := m[0] 127 u := strings.Split(b, " ") 128 url := u[1] 129 url = strings.Replace(url, "'", "", -1) 130 url = strings.Replace(url, "\\\"", "", -1) 131 if url != bindURL { 132 t.Errorf("expected url %s; received %s", bindURL, url) 133 } 134} 135 136func TestMachineCustomPortBoot2Docker(t *testing.T) { 137 p := &Boot2DockerProvisioner{ 138 Driver: &fakedriver.Driver{}, 139 } 140 dockerPort := 3376 141 bindURL := fmt.Sprintf("tcp://0.0.0.0:%d", dockerPort) 142 p.AuthOptions = auth.Options{ 143 CaCertRemotePath: "/test/ca-cert", 144 ServerKeyRemotePath: "/test/server-key", 145 ServerCertRemotePath: "/test/server-cert", 146 } 147 148 cfg, err := p.GenerateDockerOptions(dockerPort) 149 if err != nil { 150 t.Fatal(err) 151 } 152 153 re := regexp.MustCompile("-H tcp://.*:(.+)") 154 m := re.FindStringSubmatch(cfg.EngineOptions) 155 if len(m) == 0 { 156 t.Errorf("could not find port %d in engine config", dockerPort) 157 } 158 159 b := m[0] 160 u := strings.Split(b, " ") 161 url := u[1] 162 url = strings.Replace(url, "'", "", -1) 163 url = strings.Replace(url, "\\\"", "", -1) 164 if url != bindURL { 165 t.Errorf("expected url %s; received %s", bindURL, url) 166 } 167} 168 169func TestUbuntuSystemdDaemonBinary(t *testing.T) { 170 p := NewUbuntuSystemdProvisioner(&fakedriver.Driver{}).(*UbuntuSystemdProvisioner) 171 cases := []struct { 172 output, want string 173 }{ 174 {"Docker version 1.9.1\n", "docker daemon"}, 175 {"Docker version 1.11.2\n", "docker daemon"}, 176 {"Docker version 1.12.0\n", "dockerd"}, 177 {"Docker version 1.13.0\n", "dockerd"}, 178 } 179 180 sshCmder := &provisiontest.FakeSSHCommander{ 181 Responses: make(map[string]string), 182 } 183 p.SSHCommander = sshCmder 184 185 for _, tc := range cases { 186 sshCmder.Responses["docker --version"] = tc.output 187 opts, err := p.GenerateDockerOptions(1234) 188 if err != nil { 189 t.Fatal(err) 190 } 191 if !strings.Contains(opts.EngineOptions, tc.want) { 192 t.Fatal("incorrect docker daemon binary in engine options") 193 } 194 } 195} 196 197type fakeProvisioner struct { 198 GenericProvisioner 199} 200 201func (provisioner *fakeProvisioner) Package(name string, action pkgaction.PackageAction) error { 202 return nil 203} 204 205func (provisioner *fakeProvisioner) Provision(swarmOptions swarm.Options, authOptions auth.Options, engineOptions engine.Options) error { 206 return nil 207} 208 209func (provisioner *fakeProvisioner) Service(name string, action serviceaction.ServiceAction) error { 210 return nil 211} 212 213func (provisioner *fakeProvisioner) String() string { 214 return "fake" 215} 216 217func TestDecideStorageDriver(t *testing.T) { 218 var tests = []struct { 219 suppliedDriver string 220 defaultDriver string 221 remoteFilesystemType string 222 expectedDriver string 223 }{ 224 {"", "aufs", "ext4", "aufs"}, 225 {"", "aufs", "btrfs", "btrfs"}, 226 {"", "overlay", "btrfs", "overlay"}, 227 {"devicemapper", "aufs", "ext4", "devicemapper"}, 228 {"devicemapper", "aufs", "btrfs", "devicemapper"}, 229 } 230 231 p := &fakeProvisioner{GenericProvisioner{ 232 Driver: &fakedriver.Driver{}, 233 }} 234 for _, test := range tests { 235 p.SSHCommander = provisiontest.NewFakeSSHCommander( 236 provisiontest.FakeSSHCommanderOptions{ 237 FilesystemType: test.remoteFilesystemType, 238 }, 239 ) 240 storageDriver, err := decideStorageDriver(p, test.defaultDriver, test.suppliedDriver) 241 assert.NoError(t, err) 242 assert.Equal(t, test.expectedDriver, storageDriver) 243 } 244} 245 246func TestGetFilesystemType(t *testing.T) { 247 p := &fakeProvisioner{GenericProvisioner{ 248 Driver: &fakedriver.Driver{}, 249 }} 250 p.SSHCommander = &provisiontest.FakeSSHCommander{ 251 Responses: map[string]string{ 252 "stat -f -c %T /var/lib": "btrfs\n", 253 }, 254 } 255 fsType, err := getFilesystemType(p, "/var/lib") 256 assert.NoError(t, err) 257 assert.Equal(t, "btrfs", fsType) 258} 259 260func TestDockerClientVersion(t *testing.T) { 261 cases := []struct { 262 output, want string 263 }{ 264 {"Docker version 1.9.1, build a34a1d5\n", "1.9.1"}, 265 {"Docker version 1.9.1\n", "1.9.1"}, 266 {"Docker version 1.13.0-rc1, build deadbeef\n", "1.13.0-rc1"}, 267 {"Docker version 1.13.0-dev, build deadbeef\n", "1.13.0-dev"}, 268 } 269 270 sshCmder := &provisiontest.FakeSSHCommander{ 271 Responses: make(map[string]string), 272 } 273 274 for _, tc := range cases { 275 sshCmder.Responses["docker --version"] = tc.output 276 got, err := DockerClientVersion(sshCmder) 277 if err != nil { 278 t.Fatal(err) 279 } 280 if got != tc.want { 281 t.Errorf("Unexpected version string from %q; got %q, want %q", tc.output, tc.want, got) 282 } 283 } 284} 285