github.com/zoomfoo/nomad@v0.8.5-0.20180907175415-f28fd3a1a056/nomad/server_test.go (about) 1 package nomad 2 3 import ( 4 "fmt" 5 "io/ioutil" 6 "os" 7 "path" 8 "strings" 9 "testing" 10 "time" 11 12 msgpackrpc "github.com/hashicorp/net-rpc-msgpackrpc" 13 "github.com/hashicorp/nomad/helper/testlog" 14 "github.com/hashicorp/nomad/helper/uuid" 15 "github.com/hashicorp/nomad/nomad/mock" 16 "github.com/hashicorp/nomad/nomad/structs" 17 "github.com/hashicorp/nomad/nomad/structs/config" 18 "github.com/hashicorp/nomad/testutil" 19 "github.com/stretchr/testify/assert" 20 "github.com/stretchr/testify/require" 21 ) 22 23 func tmpDir(t *testing.T) string { 24 t.Helper() 25 dir, err := ioutil.TempDir("", "nomad") 26 if err != nil { 27 t.Fatalf("err: %v", err) 28 } 29 return dir 30 } 31 32 func TestServer_RPC(t *testing.T) { 33 t.Parallel() 34 s1 := TestServer(t, nil) 35 defer s1.Shutdown() 36 37 var out struct{} 38 if err := s1.RPC("Status.Ping", struct{}{}, &out); err != nil { 39 t.Fatalf("err: %v", err) 40 } 41 } 42 43 func TestServer_RPC_TLS(t *testing.T) { 44 t.Parallel() 45 const ( 46 cafile = "../helper/tlsutil/testdata/ca.pem" 47 foocert = "../helper/tlsutil/testdata/nomad-foo.pem" 48 fookey = "../helper/tlsutil/testdata/nomad-foo-key.pem" 49 ) 50 dir := tmpDir(t) 51 defer os.RemoveAll(dir) 52 s1 := TestServer(t, func(c *Config) { 53 c.Region = "regionFoo" 54 c.BootstrapExpect = 3 55 c.DevMode = false 56 c.DevDisableBootstrap = true 57 c.DataDir = path.Join(dir, "node1") 58 c.TLSConfig = &config.TLSConfig{ 59 EnableHTTP: true, 60 EnableRPC: true, 61 VerifyServerHostname: true, 62 CAFile: cafile, 63 CertFile: foocert, 64 KeyFile: fookey, 65 } 66 }) 67 defer s1.Shutdown() 68 69 s2 := TestServer(t, func(c *Config) { 70 c.Region = "regionFoo" 71 c.BootstrapExpect = 3 72 c.DevMode = false 73 c.DevDisableBootstrap = true 74 c.DataDir = path.Join(dir, "node2") 75 c.TLSConfig = &config.TLSConfig{ 76 EnableHTTP: true, 77 EnableRPC: true, 78 VerifyServerHostname: true, 79 CAFile: cafile, 80 CertFile: foocert, 81 KeyFile: fookey, 82 } 83 }) 84 defer s2.Shutdown() 85 s3 := TestServer(t, func(c *Config) { 86 c.Region = "regionFoo" 87 c.BootstrapExpect = 3 88 c.DevMode = false 89 c.DevDisableBootstrap = true 90 c.DataDir = path.Join(dir, "node3") 91 c.TLSConfig = &config.TLSConfig{ 92 EnableHTTP: true, 93 EnableRPC: true, 94 VerifyServerHostname: true, 95 CAFile: cafile, 96 CertFile: foocert, 97 KeyFile: fookey, 98 } 99 }) 100 defer s3.Shutdown() 101 102 TestJoin(t, s1, s2, s3) 103 testutil.WaitForLeader(t, s1.RPC) 104 105 // Part of a server joining is making an RPC request, so just by testing 106 // that there is a leader we verify that the RPCs are working over TLS. 107 } 108 109 func TestServer_RPC_MixedTLS(t *testing.T) { 110 t.Parallel() 111 const ( 112 cafile = "../helper/tlsutil/testdata/ca.pem" 113 foocert = "../helper/tlsutil/testdata/nomad-foo.pem" 114 fookey = "../helper/tlsutil/testdata/nomad-foo-key.pem" 115 ) 116 dir := tmpDir(t) 117 defer os.RemoveAll(dir) 118 s1 := TestServer(t, func(c *Config) { 119 c.Region = "regionFoo" 120 c.BootstrapExpect = 3 121 c.DevMode = false 122 c.DevDisableBootstrap = true 123 c.DataDir = path.Join(dir, "node1") 124 c.TLSConfig = &config.TLSConfig{ 125 EnableHTTP: true, 126 EnableRPC: true, 127 VerifyServerHostname: true, 128 CAFile: cafile, 129 CertFile: foocert, 130 KeyFile: fookey, 131 } 132 }) 133 defer s1.Shutdown() 134 135 s2 := TestServer(t, func(c *Config) { 136 c.Region = "regionFoo" 137 c.BootstrapExpect = 3 138 c.DevMode = false 139 c.DevDisableBootstrap = true 140 c.DataDir = path.Join(dir, "node2") 141 c.TLSConfig = &config.TLSConfig{ 142 EnableHTTP: true, 143 EnableRPC: true, 144 VerifyServerHostname: true, 145 CAFile: cafile, 146 CertFile: foocert, 147 KeyFile: fookey, 148 } 149 }) 150 defer s2.Shutdown() 151 s3 := TestServer(t, func(c *Config) { 152 c.Region = "regionFoo" 153 c.BootstrapExpect = 3 154 c.DevMode = false 155 c.DevDisableBootstrap = true 156 c.DataDir = path.Join(dir, "node3") 157 }) 158 defer s3.Shutdown() 159 160 TestJoin(t, s1, s2, s3) 161 162 // Ensure that we do not form a quorum 163 start := time.Now() 164 for { 165 if time.Now().After(start.Add(2 * time.Second)) { 166 break 167 } 168 169 args := &structs.GenericRequest{} 170 var leader string 171 err := s1.RPC("Status.Leader", args, &leader) 172 if err == nil || leader != "" { 173 t.Fatalf("Got leader or no error: %q %v", leader, err) 174 } 175 } 176 } 177 178 func TestServer_Regions(t *testing.T) { 179 t.Parallel() 180 // Make the servers 181 s1 := TestServer(t, func(c *Config) { 182 c.Region = "region1" 183 }) 184 defer s1.Shutdown() 185 186 s2 := TestServer(t, func(c *Config) { 187 c.Region = "region2" 188 }) 189 defer s2.Shutdown() 190 191 // Join them together 192 s2Addr := fmt.Sprintf("127.0.0.1:%d", 193 s2.config.SerfConfig.MemberlistConfig.BindPort) 194 if n, err := s1.Join([]string{s2Addr}); err != nil || n != 1 { 195 t.Fatalf("Failed joining: %v (%d joined)", err, n) 196 } 197 198 // Try listing the regions 199 testutil.WaitForResult(func() (bool, error) { 200 out := s1.Regions() 201 if len(out) != 2 || out[0] != "region1" || out[1] != "region2" { 202 return false, fmt.Errorf("unexpected regions: %v", out) 203 } 204 return true, nil 205 }, func(err error) { 206 t.Fatalf("err: %v", err) 207 }) 208 } 209 210 func TestServer_Reload_Vault(t *testing.T) { 211 t.Parallel() 212 s1 := TestServer(t, func(c *Config) { 213 c.Region = "region1" 214 }) 215 defer s1.Shutdown() 216 217 if s1.vault.Running() { 218 t.Fatalf("Vault client should not be running") 219 } 220 221 tr := true 222 config := DefaultConfig() 223 config.VaultConfig.Enabled = &tr 224 config.VaultConfig.Token = uuid.Generate() 225 226 if err := s1.Reload(config); err != nil { 227 t.Fatalf("Reload failed: %v", err) 228 } 229 230 if !s1.vault.Running() { 231 t.Fatalf("Vault client should be running") 232 } 233 } 234 235 func connectionReset(msg string) bool { 236 return strings.Contains(msg, "EOF") || strings.Contains(msg, "connection reset by peer") 237 } 238 239 // Tests that the server will successfully reload its network connections, 240 // upgrading from plaintext to TLS if the server's TLS configuration changes. 241 func TestServer_Reload_TLSConnections_PlaintextToTLS(t *testing.T) { 242 t.Parallel() 243 assert := assert.New(t) 244 245 const ( 246 cafile = "../helper/tlsutil/testdata/ca.pem" 247 foocert = "../helper/tlsutil/testdata/nomad-foo.pem" 248 fookey = "../helper/tlsutil/testdata/nomad-foo-key.pem" 249 ) 250 dir := tmpDir(t) 251 defer os.RemoveAll(dir) 252 253 s1 := TestServer(t, func(c *Config) { 254 c.DataDir = path.Join(dir, "nodeA") 255 }) 256 defer s1.Shutdown() 257 258 // assert that the server started in plaintext mode 259 assert.Equal(s1.config.TLSConfig.CertFile, "") 260 261 newTLSConfig := &config.TLSConfig{ 262 EnableHTTP: true, 263 EnableRPC: true, 264 VerifyServerHostname: true, 265 CAFile: cafile, 266 CertFile: foocert, 267 KeyFile: fookey, 268 } 269 270 err := s1.reloadTLSConnections(newTLSConfig) 271 assert.Nil(err) 272 assert.True(s1.config.TLSConfig.CertificateInfoIsEqual(newTLSConfig)) 273 274 codec := rpcClient(t, s1) 275 276 node := mock.Node() 277 req := &structs.NodeRegisterRequest{ 278 Node: node, 279 WriteRequest: structs.WriteRequest{Region: "global"}, 280 } 281 282 var resp structs.GenericResponse 283 err = msgpackrpc.CallWithCodec(codec, "Node.Register", req, &resp) 284 assert.NotNil(err) 285 assert.True(connectionReset(err.Error())) 286 } 287 288 // Tests that the server will successfully reload its network connections, 289 // downgrading from TLS to plaintext if the server's TLS configuration changes. 290 func TestServer_Reload_TLSConnections_TLSToPlaintext_RPC(t *testing.T) { 291 t.Parallel() 292 assert := assert.New(t) 293 294 const ( 295 cafile = "../helper/tlsutil/testdata/ca.pem" 296 foocert = "../helper/tlsutil/testdata/nomad-foo.pem" 297 fookey = "../helper/tlsutil/testdata/nomad-foo-key.pem" 298 ) 299 300 dir := tmpDir(t) 301 defer os.RemoveAll(dir) 302 303 s1 := TestServer(t, func(c *Config) { 304 c.DataDir = path.Join(dir, "nodeB") 305 c.TLSConfig = &config.TLSConfig{ 306 EnableHTTP: true, 307 EnableRPC: true, 308 VerifyServerHostname: true, 309 CAFile: cafile, 310 CertFile: foocert, 311 KeyFile: fookey, 312 } 313 }) 314 defer s1.Shutdown() 315 316 newTLSConfig := &config.TLSConfig{} 317 318 err := s1.reloadTLSConnections(newTLSConfig) 319 assert.Nil(err) 320 assert.True(s1.config.TLSConfig.CertificateInfoIsEqual(newTLSConfig)) 321 322 codec := rpcClient(t, s1) 323 324 node := mock.Node() 325 req := &structs.NodeRegisterRequest{ 326 Node: node, 327 WriteRequest: structs.WriteRequest{Region: "global"}, 328 } 329 330 var resp structs.GenericResponse 331 err = msgpackrpc.CallWithCodec(codec, "Node.Register", req, &resp) 332 assert.Nil(err) 333 } 334 335 // Tests that the server will successfully reload its network connections, 336 // downgrading only RPC connections 337 func TestServer_Reload_TLSConnections_TLSToPlaintext_OnlyRPC(t *testing.T) { 338 t.Parallel() 339 assert := assert.New(t) 340 341 const ( 342 cafile = "../helper/tlsutil/testdata/ca.pem" 343 foocert = "../helper/tlsutil/testdata/nomad-foo.pem" 344 fookey = "../helper/tlsutil/testdata/nomad-foo-key.pem" 345 ) 346 347 dir := tmpDir(t) 348 defer os.RemoveAll(dir) 349 350 s1 := TestServer(t, func(c *Config) { 351 c.DataDir = path.Join(dir, "nodeB") 352 c.TLSConfig = &config.TLSConfig{ 353 EnableHTTP: true, 354 EnableRPC: true, 355 VerifyServerHostname: true, 356 CAFile: cafile, 357 CertFile: foocert, 358 KeyFile: fookey, 359 } 360 }) 361 defer s1.Shutdown() 362 363 newTLSConfig := &config.TLSConfig{ 364 EnableHTTP: true, 365 EnableRPC: false, 366 VerifyServerHostname: true, 367 CAFile: cafile, 368 CertFile: foocert, 369 KeyFile: fookey, 370 } 371 372 err := s1.reloadTLSConnections(newTLSConfig) 373 assert.Nil(err) 374 assert.True(s1.config.TLSConfig.CertificateInfoIsEqual(newTLSConfig)) 375 376 codec := rpcClient(t, s1) 377 378 node := mock.Node() 379 req := &structs.NodeRegisterRequest{ 380 Node: node, 381 WriteRequest: structs.WriteRequest{Region: "global"}, 382 } 383 384 var resp structs.GenericResponse 385 err = msgpackrpc.CallWithCodec(codec, "Node.Register", req, &resp) 386 assert.Nil(err) 387 } 388 389 // Tests that the server will successfully reload its network connections, 390 // upgrading only RPC connections 391 func TestServer_Reload_TLSConnections_PlaintextToTLS_OnlyRPC(t *testing.T) { 392 t.Parallel() 393 assert := assert.New(t) 394 395 const ( 396 cafile = "../helper/tlsutil/testdata/ca.pem" 397 foocert = "../helper/tlsutil/testdata/nomad-foo.pem" 398 fookey = "../helper/tlsutil/testdata/nomad-foo-key.pem" 399 ) 400 401 dir := tmpDir(t) 402 defer os.RemoveAll(dir) 403 404 s1 := TestServer(t, func(c *Config) { 405 c.DataDir = path.Join(dir, "nodeB") 406 c.TLSConfig = &config.TLSConfig{ 407 EnableHTTP: true, 408 EnableRPC: false, 409 VerifyServerHostname: true, 410 CAFile: cafile, 411 CertFile: foocert, 412 KeyFile: fookey, 413 } 414 }) 415 defer s1.Shutdown() 416 417 newTLSConfig := &config.TLSConfig{ 418 EnableHTTP: true, 419 EnableRPC: true, 420 VerifyServerHostname: true, 421 CAFile: cafile, 422 CertFile: foocert, 423 KeyFile: fookey, 424 } 425 426 err := s1.reloadTLSConnections(newTLSConfig) 427 assert.Nil(err) 428 assert.True(s1.config.TLSConfig.EnableRPC) 429 assert.True(s1.config.TLSConfig.CertificateInfoIsEqual(newTLSConfig)) 430 431 codec := rpcClient(t, s1) 432 433 node := mock.Node() 434 req := &structs.NodeRegisterRequest{ 435 Node: node, 436 WriteRequest: structs.WriteRequest{Region: "global"}, 437 } 438 439 var resp structs.GenericResponse 440 err = msgpackrpc.CallWithCodec(codec, "Node.Register", req, &resp) 441 assert.NotNil(err) 442 assert.True(connectionReset(err.Error())) 443 } 444 445 // Test that Raft connections are reloaded as expected when a Nomad server is 446 // upgraded from plaintext to TLS 447 func TestServer_Reload_TLSConnections_Raft(t *testing.T) { 448 assert := assert.New(t) 449 t.Parallel() 450 const ( 451 cafile = "../../helper/tlsutil/testdata/ca.pem" 452 foocert = "../../helper/tlsutil/testdata/nomad-foo.pem" 453 fookey = "../../helper/tlsutil/testdata/nomad-foo-key.pem" 454 barcert = "../dev/tls_cluster/certs/nomad.pem" 455 barkey = "../dev/tls_cluster/certs/nomad-key.pem" 456 ) 457 dir := tmpDir(t) 458 defer os.RemoveAll(dir) 459 460 s1 := TestServer(t, func(c *Config) { 461 c.BootstrapExpect = 2 462 c.DevMode = false 463 c.DevDisableBootstrap = true 464 c.DataDir = path.Join(dir, "node1") 465 c.NodeName = "node1" 466 c.Region = "regionFoo" 467 }) 468 defer s1.Shutdown() 469 470 s2 := TestServer(t, func(c *Config) { 471 c.BootstrapExpect = 2 472 c.DevMode = false 473 c.DevDisableBootstrap = true 474 c.DataDir = path.Join(dir, "node2") 475 c.NodeName = "node2" 476 c.Region = "regionFoo" 477 }) 478 defer s2.Shutdown() 479 480 TestJoin(t, s1, s2) 481 servers := []*Server{s1, s2} 482 483 testutil.WaitForLeader(t, s1.RPC) 484 485 newTLSConfig := &config.TLSConfig{ 486 EnableHTTP: true, 487 VerifyHTTPSClient: true, 488 CAFile: cafile, 489 CertFile: foocert, 490 KeyFile: fookey, 491 } 492 493 err := s1.reloadTLSConnections(newTLSConfig) 494 assert.Nil(err) 495 496 { 497 for _, serv := range servers { 498 testutil.WaitForResult(func() (bool, error) { 499 args := &structs.GenericRequest{} 500 var leader string 501 err := serv.RPC("Status.Leader", args, &leader) 502 if leader != "" && err != nil { 503 return false, fmt.Errorf("Should not have found leader but got %s", leader) 504 } 505 return true, nil 506 }, func(err error) { 507 t.Fatalf("err: %v", err) 508 }) 509 } 510 } 511 512 secondNewTLSConfig := &config.TLSConfig{ 513 EnableHTTP: true, 514 VerifyHTTPSClient: true, 515 CAFile: cafile, 516 CertFile: barcert, 517 KeyFile: barkey, 518 } 519 520 // Now, transition the other server to TLS, which should restore their 521 // ability to communicate. 522 err = s2.reloadTLSConnections(secondNewTLSConfig) 523 assert.Nil(err) 524 525 testutil.WaitForLeader(t, s2.RPC) 526 } 527 528 func TestServer_InvalidSchedulers(t *testing.T) { 529 t.Parallel() 530 require := require.New(t) 531 532 // Set the config to not have the core scheduler 533 config := DefaultConfig() 534 logger := testlog.Logger(t) 535 s := &Server{ 536 config: config, 537 logger: logger, 538 } 539 540 config.EnabledSchedulers = []string{"batch"} 541 err := s.setupWorkers() 542 require.NotNil(err) 543 require.Contains(err.Error(), "scheduler not enabled") 544 545 // Set the config to have an unknown scheduler 546 config.EnabledSchedulers = []string{"batch", structs.JobTypeCore, "foo"} 547 err = s.setupWorkers() 548 require.NotNil(err) 549 require.Contains(err.Error(), "foo") 550 }