github.com/rohankumardubey/nomad@v0.11.8/command/agent/agent_test.go (about) 1 package agent 2 3 import ( 4 "io/ioutil" 5 "os" 6 "path/filepath" 7 "strings" 8 "testing" 9 "time" 10 11 cstructs "github.com/hashicorp/nomad/client/structs" 12 "github.com/hashicorp/nomad/helper" 13 "github.com/hashicorp/nomad/helper/testlog" 14 "github.com/hashicorp/nomad/nomad/structs" 15 "github.com/hashicorp/nomad/nomad/structs/config" 16 sconfig "github.com/hashicorp/nomad/nomad/structs/config" 17 "github.com/stretchr/testify/assert" 18 "github.com/stretchr/testify/require" 19 ) 20 21 func tmpDir(t testing.TB) string { 22 dir, err := ioutil.TempDir("", "nomad") 23 if err != nil { 24 t.Fatalf("err: %v", err) 25 } 26 return dir 27 } 28 29 func TestAgent_RPC_Ping(t *testing.T) { 30 t.Parallel() 31 agent := NewTestAgent(t, t.Name(), nil) 32 defer agent.Shutdown() 33 34 var out struct{} 35 if err := agent.RPC("Status.Ping", struct{}{}, &out); err != nil { 36 t.Fatalf("err: %v", err) 37 } 38 } 39 40 func TestAgent_ServerConfig(t *testing.T) { 41 t.Parallel() 42 conf := DefaultConfig() 43 conf.DevMode = true // allow localhost for advertise addrs 44 conf.Server.Enabled = true 45 a := &Agent{config: conf} 46 47 conf.AdvertiseAddrs.Serf = "127.0.0.1:4000" 48 conf.AdvertiseAddrs.RPC = "127.0.0.1:4001" 49 conf.AdvertiseAddrs.HTTP = "10.10.11.1:4005" 50 conf.ACL.Enabled = true 51 52 // Parses the advertise addrs correctly 53 if err := conf.normalizeAddrs(); err != nil { 54 t.Fatalf("error normalizing config: %v", err) 55 } 56 out, err := a.serverConfig() 57 require.NoError(t, err) 58 59 serfAddr := out.SerfConfig.MemberlistConfig.AdvertiseAddr 60 require.Equal(t, "127.0.0.1", serfAddr) 61 62 serfPort := out.SerfConfig.MemberlistConfig.AdvertisePort 63 require.Equal(t, 4000, serfPort) 64 65 require.Equal(t, "global", out.AuthoritativeRegion) 66 require.True(t, out.ACLEnabled) 67 68 // Assert addresses weren't changed 69 require.Equal(t, "127.0.0.1:4001", conf.AdvertiseAddrs.RPC) 70 require.Equal(t, "10.10.11.1:4005", conf.AdvertiseAddrs.HTTP) 71 require.Equal(t, "0.0.0.0", conf.Addresses.RPC) 72 73 // Sets up the ports properly 74 conf.Addresses.RPC = "" 75 conf.Addresses.Serf = "" 76 conf.Ports.RPC = 4003 77 conf.Ports.Serf = 4004 78 79 require.NoError(t, conf.normalizeAddrs()) 80 81 out, err = a.serverConfig() 82 require.NoError(t, err) 83 require.Equal(t, 4003, out.RPCAddr.Port) 84 require.Equal(t, 4004, out.SerfConfig.MemberlistConfig.BindPort) 85 86 // Prefers advertise over bind addr 87 conf.BindAddr = "127.0.0.3" 88 conf.Addresses.HTTP = "127.0.0.2" 89 conf.Addresses.RPC = "127.0.0.2" 90 conf.Addresses.Serf = "127.0.0.2" 91 conf.AdvertiseAddrs.HTTP = "10.0.0.10" 92 conf.AdvertiseAddrs.RPC = "" 93 conf.AdvertiseAddrs.Serf = "10.0.0.12:4004" 94 95 require.NoError(t, conf.normalizeAddrs()) 96 97 out, err = a.serverConfig() 98 require.Equal(t, "127.0.0.2", out.RPCAddr.IP.String()) 99 require.Equal(t, 4003, out.RPCAddr.Port) 100 require.Equal(t, "127.0.0.2", out.SerfConfig.MemberlistConfig.BindAddr) 101 require.Equal(t, 4004, out.SerfConfig.MemberlistConfig.BindPort) 102 require.Equal(t, "127.0.0.2", conf.Addresses.HTTP) 103 require.Equal(t, "127.0.0.2", conf.Addresses.RPC) 104 require.Equal(t, "127.0.0.2", conf.Addresses.Serf) 105 require.Equal(t, "127.0.0.2:4646", conf.normalizedAddrs.HTTP) 106 require.Equal(t, "127.0.0.2:4003", conf.normalizedAddrs.RPC) 107 require.Equal(t, "127.0.0.2:4004", conf.normalizedAddrs.Serf) 108 require.Equal(t, "10.0.0.10:4646", conf.AdvertiseAddrs.HTTP) 109 require.Equal(t, "127.0.0.2:4003", conf.AdvertiseAddrs.RPC) 110 require.Equal(t, "10.0.0.12:4004", conf.AdvertiseAddrs.Serf) 111 112 conf.Server.NodeGCThreshold = "42g" 113 require.NoError(t, conf.normalizeAddrs()) 114 115 _, err = a.serverConfig() 116 if err == nil || !strings.Contains(err.Error(), "unknown unit") { 117 t.Fatalf("expected unknown unit error, got: %#v", err) 118 } 119 120 conf.Server.NodeGCThreshold = "10s" 121 require.NoError(t, conf.normalizeAddrs()) 122 out, err = a.serverConfig() 123 require.NoError(t, err) 124 require.Equal(t, 10*time.Second, out.NodeGCThreshold) 125 126 conf.Server.HeartbeatGrace = 37 * time.Second 127 out, err = a.serverConfig() 128 require.NoError(t, err) 129 require.Equal(t, 37*time.Second, out.HeartbeatGrace) 130 131 conf.Server.MinHeartbeatTTL = 37 * time.Second 132 out, err = a.serverConfig() 133 require.NoError(t, err) 134 require.Equal(t, 37*time.Second, out.MinHeartbeatTTL) 135 136 conf.Server.MaxHeartbeatsPerSecond = 11.0 137 out, err = a.serverConfig() 138 require.NoError(t, err) 139 require.Equal(t, float64(11.0), out.MaxHeartbeatsPerSecond) 140 141 // Defaults to the global bind addr 142 conf.Addresses.RPC = "" 143 conf.Addresses.Serf = "" 144 conf.Addresses.HTTP = "" 145 conf.AdvertiseAddrs.RPC = "" 146 conf.AdvertiseAddrs.HTTP = "" 147 conf.AdvertiseAddrs.Serf = "" 148 conf.Ports.HTTP = 4646 149 conf.Ports.RPC = 4647 150 conf.Ports.Serf = 4648 151 require.NoError(t, conf.normalizeAddrs()) 152 153 out, err = a.serverConfig() 154 require.NoError(t, err) 155 156 require.Equal(t, "127.0.0.3", out.RPCAddr.IP.String()) 157 require.Equal(t, "127.0.0.3", out.SerfConfig.MemberlistConfig.BindAddr) 158 require.Equal(t, "127.0.0.3", conf.Addresses.HTTP) 159 require.Equal(t, "127.0.0.3", conf.Addresses.RPC) 160 require.Equal(t, "127.0.0.3", conf.Addresses.Serf) 161 require.Equal(t, "127.0.0.3:4646", conf.normalizedAddrs.HTTP) 162 require.Equal(t, "127.0.0.3:4647", conf.normalizedAddrs.RPC) 163 require.Equal(t, "127.0.0.3:4648", conf.normalizedAddrs.Serf) 164 165 // Properly handles the bootstrap flags 166 conf.Server.BootstrapExpect = 1 167 out, err = a.serverConfig() 168 require.NoError(t, err) 169 require.Equal(t, 1, out.BootstrapExpect) 170 171 conf.Server.BootstrapExpect = 3 172 out, err = a.serverConfig() 173 require.NoError(t, err) 174 require.Equal(t, 3, out.BootstrapExpect) 175 } 176 177 func TestAgent_ServerConfig_SchedulerFlags(t *testing.T) { 178 cases := []struct { 179 name string 180 input *structs.SchedulerConfiguration 181 expected structs.SchedulerConfiguration 182 }{ 183 { 184 "default case", 185 nil, 186 structs.SchedulerConfiguration{ 187 SchedulerAlgorithm: "binpack", 188 PreemptionConfig: structs.PreemptionConfig{ 189 SystemSchedulerEnabled: true, 190 }, 191 }, 192 }, 193 { 194 "empty value: preemption is disabled", 195 &structs.SchedulerConfiguration{}, 196 structs.SchedulerConfiguration{ 197 PreemptionConfig: structs.PreemptionConfig{ 198 SystemSchedulerEnabled: false, 199 }, 200 }, 201 }, 202 { 203 "all explicitly set", 204 &structs.SchedulerConfiguration{ 205 PreemptionConfig: structs.PreemptionConfig{ 206 SystemSchedulerEnabled: true, 207 BatchSchedulerEnabled: true, 208 ServiceSchedulerEnabled: true, 209 }, 210 }, 211 structs.SchedulerConfiguration{ 212 PreemptionConfig: structs.PreemptionConfig{ 213 SystemSchedulerEnabled: true, 214 BatchSchedulerEnabled: true, 215 ServiceSchedulerEnabled: true, 216 }, 217 }, 218 }, 219 } 220 221 for _, c := range cases { 222 t.Run(c.name, func(t *testing.T) { 223 conf := DefaultConfig() 224 conf.Server.DefaultSchedulerConfig = c.input 225 226 a := &Agent{config: conf} 227 conf.AdvertiseAddrs.Serf = "127.0.0.1:4000" 228 conf.AdvertiseAddrs.RPC = "127.0.0.1:4001" 229 conf.AdvertiseAddrs.HTTP = "10.10.11.1:4005" 230 conf.ACL.Enabled = true 231 require.NoError(t, conf.normalizeAddrs()) 232 233 out, err := a.serverConfig() 234 require.NoError(t, err) 235 require.Equal(t, c.expected, out.DefaultSchedulerConfig) 236 }) 237 } 238 } 239 240 // TestAgent_ServerConfig_Limits_Errors asserts invalid Limits configurations 241 // cause errors. This is the server-only (RPC) counterpart to 242 // TestHTTPServer_Limits_Error. 243 func TestAgent_ServerConfig_Limits_Error(t *testing.T) { 244 t.Parallel() 245 246 cases := []struct { 247 name string 248 expectedErr string 249 limits sconfig.Limits 250 }{ 251 { 252 name: "Negative Timeout", 253 expectedErr: "rpc_handshake_timeout must be >= 0", 254 limits: sconfig.Limits{ 255 RPCHandshakeTimeout: "-5s", 256 RPCMaxConnsPerClient: helper.IntToPtr(100), 257 }, 258 }, 259 { 260 name: "Invalid Timeout", 261 expectedErr: "error parsing rpc_handshake_timeout", 262 limits: sconfig.Limits{ 263 RPCHandshakeTimeout: "s", 264 RPCMaxConnsPerClient: helper.IntToPtr(100), 265 }, 266 }, 267 { 268 name: "Missing Timeout", 269 expectedErr: "error parsing rpc_handshake_timeout", 270 limits: sconfig.Limits{ 271 RPCHandshakeTimeout: "", 272 RPCMaxConnsPerClient: helper.IntToPtr(100), 273 }, 274 }, 275 { 276 name: "Negative Connection Limit", 277 expectedErr: "rpc_max_conns_per_client must be > 25; found: -100", 278 limits: sconfig.Limits{ 279 RPCHandshakeTimeout: "5s", 280 RPCMaxConnsPerClient: helper.IntToPtr(-100), 281 }, 282 }, 283 { 284 name: "Low Connection Limit", 285 expectedErr: "rpc_max_conns_per_client must be > 25; found: 20", 286 limits: sconfig.Limits{ 287 RPCHandshakeTimeout: "5s", 288 RPCMaxConnsPerClient: helper.IntToPtr(sconfig.LimitsNonStreamingConnsPerClient), 289 }, 290 }, 291 } 292 293 for i := range cases { 294 tc := cases[i] 295 t.Run(tc.name, func(t *testing.T) { 296 conf := DevConfig(nil) 297 require.NoError(t, conf.normalizeAddrs()) 298 299 conf.Limits = tc.limits 300 serverConf, err := convertServerConfig(conf) 301 assert.Nil(t, serverConf) 302 require.Contains(t, err.Error(), tc.expectedErr) 303 }) 304 } 305 } 306 307 // TestAgent_ServerConfig_Limits_OK asserts valid Limits configurations do not 308 // cause errors. This is the server-only (RPC) counterpart to 309 // TestHTTPServer_Limits_OK. 310 func TestAgent_ServerConfig_Limits_OK(t *testing.T) { 311 t.Parallel() 312 313 cases := []struct { 314 name string 315 limits sconfig.Limits 316 }{ 317 { 318 name: "Default", 319 limits: config.DefaultLimits(), 320 }, 321 { 322 name: "Zero+nil is valid to disable", 323 limits: sconfig.Limits{ 324 RPCHandshakeTimeout: "0", 325 RPCMaxConnsPerClient: nil, 326 }, 327 }, 328 { 329 name: "Zeros are valid", 330 limits: sconfig.Limits{ 331 RPCHandshakeTimeout: "0s", 332 RPCMaxConnsPerClient: helper.IntToPtr(0), 333 }, 334 }, 335 { 336 name: "Low limits are valid", 337 limits: sconfig.Limits{ 338 RPCHandshakeTimeout: "1ms", 339 RPCMaxConnsPerClient: helper.IntToPtr(26), 340 }, 341 }, 342 { 343 name: "High limits are valid", 344 limits: sconfig.Limits{ 345 RPCHandshakeTimeout: "5h", 346 RPCMaxConnsPerClient: helper.IntToPtr(100000), 347 }, 348 }, 349 } 350 351 for i := range cases { 352 tc := cases[i] 353 t.Run(tc.name, func(t *testing.T) { 354 conf := DevConfig(nil) 355 require.NoError(t, conf.normalizeAddrs()) 356 357 conf.Limits = tc.limits 358 serverConf, err := convertServerConfig(conf) 359 assert.NoError(t, err) 360 require.NotNil(t, serverConf) 361 }) 362 } 363 } 364 365 func TestAgent_ClientConfig(t *testing.T) { 366 t.Parallel() 367 conf := DefaultConfig() 368 conf.Client.Enabled = true 369 370 // For Clients HTTP and RPC must be set (Serf can be skipped) 371 conf.Addresses.HTTP = "169.254.0.1" 372 conf.Addresses.RPC = "169.254.0.1" 373 conf.Ports.HTTP = 5678 374 a := &Agent{config: conf} 375 376 if err := conf.normalizeAddrs(); err != nil { 377 t.Fatalf("error normalizing config: %v", err) 378 } 379 c, err := a.clientConfig() 380 if err != nil { 381 t.Fatalf("got err: %v", err) 382 } 383 384 expectedHttpAddr := "169.254.0.1:5678" 385 if c.Node.HTTPAddr != expectedHttpAddr { 386 t.Fatalf("Expected http addr: %v, got: %v", expectedHttpAddr, c.Node.HTTPAddr) 387 } 388 389 conf = DefaultConfig() 390 conf.DevMode = true 391 a = &Agent{config: conf} 392 conf.Client.Enabled = true 393 conf.Addresses.HTTP = "169.254.0.1" 394 395 if err := conf.normalizeAddrs(); err != nil { 396 t.Fatalf("error normalizing config: %v", err) 397 } 398 c, err = a.clientConfig() 399 if err != nil { 400 t.Fatalf("got err: %v", err) 401 } 402 403 expectedHttpAddr = "169.254.0.1:4646" 404 if c.Node.HTTPAddr != expectedHttpAddr { 405 t.Fatalf("Expected http addr: %v, got: %v", expectedHttpAddr, c.Node.HTTPAddr) 406 } 407 } 408 409 // Clients should inherit telemetry configuration 410 func TestAgent_Client_TelemetryConfiguration(t *testing.T) { 411 assert := assert.New(t) 412 413 conf := DefaultConfig() 414 conf.DevMode = true 415 conf.Telemetry.DisableTaggedMetrics = true 416 conf.Telemetry.BackwardsCompatibleMetrics = true 417 418 a := &Agent{config: conf} 419 420 c, err := a.clientConfig() 421 assert.Nil(err) 422 423 telemetry := conf.Telemetry 424 425 assert.Equal(c.StatsCollectionInterval, telemetry.collectionInterval) 426 assert.Equal(c.PublishNodeMetrics, telemetry.PublishNodeMetrics) 427 assert.Equal(c.PublishAllocationMetrics, telemetry.PublishAllocationMetrics) 428 assert.Equal(c.DisableTaggedMetrics, telemetry.DisableTaggedMetrics) 429 assert.Equal(c.BackwardsCompatibleMetrics, telemetry.BackwardsCompatibleMetrics) 430 } 431 432 // TestAgent_HTTPCheck asserts Agent.agentHTTPCheck properly alters the HTTP 433 // API health check depending on configuration. 434 func TestAgent_HTTPCheck(t *testing.T) { 435 t.Parallel() 436 logger := testlog.HCLogger(t) 437 agent := func() *Agent { 438 return &Agent{ 439 logger: logger, 440 config: &Config{ 441 AdvertiseAddrs: &AdvertiseAddrs{HTTP: "advertise:4646"}, 442 normalizedAddrs: &Addresses{HTTP: "normalized:4646"}, 443 Consul: &sconfig.ConsulConfig{ 444 ChecksUseAdvertise: helper.BoolToPtr(false), 445 }, 446 TLSConfig: &sconfig.TLSConfig{EnableHTTP: false}, 447 }, 448 } 449 } 450 451 t.Run("Plain HTTP Check", func(t *testing.T) { 452 a := agent() 453 check := a.agentHTTPCheck(false) 454 if check == nil { 455 t.Fatalf("expected non-nil check") 456 } 457 if check.Type != "http" { 458 t.Errorf("expected http check not: %q", check.Type) 459 } 460 if expected := "/v1/agent/health?type=client"; check.Path != expected { 461 t.Errorf("expected %q path not: %q", expected, check.Path) 462 } 463 if check.Protocol != "http" { 464 t.Errorf("expected http proto not: %q", check.Protocol) 465 } 466 if expected := a.config.normalizedAddrs.HTTP; check.PortLabel != expected { 467 t.Errorf("expected normalized addr not %q", check.PortLabel) 468 } 469 }) 470 471 t.Run("Plain HTTP + ChecksUseAdvertise", func(t *testing.T) { 472 a := agent() 473 a.config.Consul.ChecksUseAdvertise = helper.BoolToPtr(true) 474 check := a.agentHTTPCheck(false) 475 if check == nil { 476 t.Fatalf("expected non-nil check") 477 } 478 if expected := a.config.AdvertiseAddrs.HTTP; check.PortLabel != expected { 479 t.Errorf("expected advertise addr not %q", check.PortLabel) 480 } 481 }) 482 483 t.Run("HTTPS", func(t *testing.T) { 484 a := agent() 485 a.config.TLSConfig.EnableHTTP = true 486 487 check := a.agentHTTPCheck(false) 488 if check == nil { 489 t.Fatalf("expected non-nil check") 490 } 491 if !check.TLSSkipVerify { 492 t.Errorf("expected tls skip verify") 493 } 494 if check.Protocol != "https" { 495 t.Errorf("expected https not: %q", check.Protocol) 496 } 497 }) 498 499 t.Run("HTTPS + VerifyHTTPSClient", func(t *testing.T) { 500 a := agent() 501 a.config.TLSConfig.EnableHTTP = true 502 a.config.TLSConfig.VerifyHTTPSClient = true 503 504 if check := a.agentHTTPCheck(false); check != nil { 505 t.Fatalf("expected nil check not: %#v", check) 506 } 507 }) 508 } 509 510 // TestAgent_HTTPCheckPath asserts clients and servers use different endpoints 511 // for healthchecks. 512 func TestAgent_HTTPCheckPath(t *testing.T) { 513 t.Parallel() 514 // Agent.agentHTTPCheck only needs a config and logger 515 a := &Agent{ 516 config: DevConfig(nil), 517 logger: testlog.HCLogger(t), 518 } 519 if err := a.config.normalizeAddrs(); err != nil { 520 t.Fatalf("error normalizing config: %v", err) 521 } 522 523 // Assert server check uses /v1/agent/health?type=server 524 isServer := true 525 check := a.agentHTTPCheck(isServer) 526 if expected := "Nomad Server HTTP Check"; check.Name != expected { 527 t.Errorf("expected server check name to be %q but found %q", expected, check.Name) 528 } 529 if expected := "/v1/agent/health?type=server"; check.Path != expected { 530 t.Errorf("expected server check path to be %q but found %q", expected, check.Path) 531 } 532 533 // Assert client check uses /v1/agent/health?type=client 534 isServer = false 535 check = a.agentHTTPCheck(isServer) 536 if expected := "Nomad Client HTTP Check"; check.Name != expected { 537 t.Errorf("expected client check name to be %q but found %q", expected, check.Name) 538 } 539 if expected := "/v1/agent/health?type=client"; check.Path != expected { 540 t.Errorf("expected client check path to be %q but found %q", expected, check.Path) 541 } 542 } 543 544 // Here we validate that log levels get updated when the configuration is 545 // reloaded. I can't find a good way to fetch this from the logger itself, so 546 // we pull it only from the agents configuration struct, not the logger. 547 func TestAgent_Reload_LogLevel(t *testing.T) { 548 t.Parallel() 549 assert := assert.New(t) 550 551 agent := NewTestAgent(t, t.Name(), func(c *Config) { 552 c.LogLevel = "INFO" 553 }) 554 defer agent.Shutdown() 555 556 assert.Equal("INFO", agent.GetConfig().LogLevel) 557 558 newConfig := &Config{ 559 LogLevel: "TRACE", 560 } 561 562 assert.Nil(agent.Reload(newConfig)) 563 assert.Equal("TRACE", agent.GetConfig().LogLevel) 564 } 565 566 // This test asserts that the keyloader embedded in the TLS config is shared 567 // across the Agent, Server, and Client. This is essential for certificate 568 // reloading to work. 569 func TestServer_Reload_TLS_Shared_Keyloader(t *testing.T) { 570 t.Parallel() 571 assert := assert.New(t) 572 573 // We will start out with a bad cert and then reload with a good one. 574 const ( 575 cafile = "../../helper/tlsutil/testdata/ca.pem" 576 foocert = "../../helper/tlsutil/testdata/nomad-bad.pem" 577 fookey = "../../helper/tlsutil/testdata/nomad-bad-key.pem" 578 foocert2 = "../../helper/tlsutil/testdata/nomad-foo.pem" 579 fookey2 = "../../helper/tlsutil/testdata/nomad-foo-key.pem" 580 ) 581 582 agent := NewTestAgent(t, t.Name(), func(c *Config) { 583 c.TLSConfig = &sconfig.TLSConfig{ 584 EnableHTTP: true, 585 EnableRPC: true, 586 VerifyServerHostname: true, 587 CAFile: cafile, 588 CertFile: foocert, 589 KeyFile: fookey, 590 } 591 }) 592 defer agent.Shutdown() 593 594 originalKeyloader := agent.Config.TLSConfig.GetKeyLoader() 595 originalCert, err := originalKeyloader.GetOutgoingCertificate(nil) 596 assert.NotNil(originalKeyloader) 597 if assert.Nil(err) { 598 assert.NotNil(originalCert) 599 } 600 601 // Switch to the correct certificates and reload 602 newConfig := &Config{ 603 TLSConfig: &sconfig.TLSConfig{ 604 EnableHTTP: true, 605 EnableRPC: true, 606 VerifyServerHostname: true, 607 CAFile: cafile, 608 CertFile: foocert2, 609 KeyFile: fookey2, 610 }, 611 } 612 613 assert.Nil(agent.Reload(newConfig)) 614 assert.Equal(agent.Config.TLSConfig.CertFile, newConfig.TLSConfig.CertFile) 615 assert.Equal(agent.Config.TLSConfig.KeyFile, newConfig.TLSConfig.KeyFile) 616 assert.Equal(agent.Config.TLSConfig.GetKeyLoader(), originalKeyloader) 617 618 // Assert is passed through on the server correctly 619 if assert.NotNil(agent.server.GetConfig().TLSConfig) { 620 serverKeyloader := agent.server.GetConfig().TLSConfig.GetKeyLoader() 621 assert.Equal(serverKeyloader, originalKeyloader) 622 newCert, err := serverKeyloader.GetOutgoingCertificate(nil) 623 assert.Nil(err) 624 assert.NotEqual(originalCert, newCert) 625 } 626 627 // Assert is passed through on the client correctly 628 if assert.NotNil(agent.client.GetConfig().TLSConfig) { 629 clientKeyloader := agent.client.GetConfig().TLSConfig.GetKeyLoader() 630 assert.Equal(clientKeyloader, originalKeyloader) 631 newCert, err := clientKeyloader.GetOutgoingCertificate(nil) 632 assert.Nil(err) 633 assert.NotEqual(originalCert, newCert) 634 } 635 } 636 637 func TestServer_Reload_TLS_Certificate(t *testing.T) { 638 t.Parallel() 639 assert := assert.New(t) 640 641 const ( 642 cafile = "../../helper/tlsutil/testdata/ca.pem" 643 foocert = "../../helper/tlsutil/testdata/nomad-bad.pem" 644 fookey = "../../helper/tlsutil/testdata/nomad-bad-key.pem" 645 foocert2 = "../../helper/tlsutil/testdata/nomad-foo.pem" 646 fookey2 = "../../helper/tlsutil/testdata/nomad-foo-key.pem" 647 ) 648 649 agentConfig := &Config{ 650 TLSConfig: &sconfig.TLSConfig{ 651 EnableHTTP: true, 652 EnableRPC: true, 653 VerifyServerHostname: true, 654 CAFile: cafile, 655 CertFile: foocert, 656 KeyFile: fookey, 657 }, 658 } 659 660 agent := &Agent{ 661 auditor: &noOpAuditor{}, 662 config: agentConfig, 663 } 664 665 newConfig := &Config{ 666 TLSConfig: &sconfig.TLSConfig{ 667 EnableHTTP: true, 668 EnableRPC: true, 669 VerifyServerHostname: true, 670 CAFile: cafile, 671 CertFile: foocert2, 672 KeyFile: fookey2, 673 }, 674 } 675 676 originalKeyloader := agentConfig.TLSConfig.GetKeyLoader() 677 assert.NotNil(originalKeyloader) 678 679 err := agent.Reload(newConfig) 680 assert.Nil(err) 681 assert.Equal(agent.config.TLSConfig.CertFile, newConfig.TLSConfig.CertFile) 682 assert.Equal(agent.config.TLSConfig.KeyFile, newConfig.TLSConfig.KeyFile) 683 assert.Equal(agent.config.TLSConfig.GetKeyLoader(), originalKeyloader) 684 } 685 686 func TestServer_Reload_TLS_Certificate_Invalid(t *testing.T) { 687 t.Parallel() 688 assert := assert.New(t) 689 690 const ( 691 cafile = "../../helper/tlsutil/testdata/ca.pem" 692 foocert = "../../helper/tlsutil/testdata/nomad-bad.pem" 693 fookey = "../../helper/tlsutil/testdata/nomad-bad-key.pem" 694 foocert2 = "invalid_cert_path" 695 fookey2 = "invalid_key_path" 696 ) 697 698 agentConfig := &Config{ 699 TLSConfig: &sconfig.TLSConfig{ 700 EnableHTTP: true, 701 EnableRPC: true, 702 VerifyServerHostname: true, 703 CAFile: cafile, 704 CertFile: foocert, 705 KeyFile: fookey, 706 }, 707 } 708 709 agent := &Agent{ 710 auditor: &noOpAuditor{}, 711 config: agentConfig, 712 } 713 714 newConfig := &Config{ 715 TLSConfig: &sconfig.TLSConfig{ 716 EnableHTTP: true, 717 EnableRPC: true, 718 VerifyServerHostname: true, 719 CAFile: cafile, 720 CertFile: foocert2, 721 KeyFile: fookey2, 722 }, 723 } 724 725 err := agent.Reload(newConfig) 726 assert.NotNil(err) 727 assert.NotEqual(agent.config.TLSConfig.CertFile, newConfig.TLSConfig.CertFile) 728 assert.NotEqual(agent.config.TLSConfig.KeyFile, newConfig.TLSConfig.KeyFile) 729 } 730 731 func Test_GetConfig(t *testing.T) { 732 assert := assert.New(t) 733 734 agentConfig := &Config{ 735 Telemetry: &Telemetry{}, 736 Client: &ClientConfig{}, 737 Server: &ServerConfig{}, 738 ACL: &ACLConfig{}, 739 Ports: &Ports{}, 740 Addresses: &Addresses{}, 741 AdvertiseAddrs: &AdvertiseAddrs{}, 742 Vault: &sconfig.VaultConfig{}, 743 Consul: &sconfig.ConsulConfig{}, 744 Sentinel: &sconfig.SentinelConfig{}, 745 } 746 747 agent := &Agent{ 748 config: agentConfig, 749 } 750 751 actualAgentConfig := agent.GetConfig() 752 assert.Equal(actualAgentConfig, agentConfig) 753 } 754 755 func TestServer_Reload_TLS_WithNilConfiguration(t *testing.T) { 756 t.Parallel() 757 assert := assert.New(t) 758 759 logger := testlog.HCLogger(t) 760 761 agent := &Agent{ 762 logger: logger, 763 config: &Config{}, 764 } 765 766 err := agent.Reload(nil) 767 assert.NotNil(err) 768 assert.Equal(err.Error(), "cannot reload agent with nil configuration") 769 } 770 771 func TestServer_Reload_TLS_UpgradeToTLS(t *testing.T) { 772 t.Parallel() 773 assert := assert.New(t) 774 775 const ( 776 cafile = "../../helper/tlsutil/testdata/ca.pem" 777 foocert = "../../helper/tlsutil/testdata/nomad-foo.pem" 778 fookey = "../../helper/tlsutil/testdata/nomad-foo-key.pem" 779 ) 780 dir := tmpDir(t) 781 defer os.RemoveAll(dir) 782 783 logger := testlog.HCLogger(t) 784 785 agentConfig := &Config{ 786 TLSConfig: &sconfig.TLSConfig{}, 787 } 788 789 agent := &Agent{ 790 auditor: &noOpAuditor{}, 791 logger: logger, 792 config: agentConfig, 793 } 794 795 newConfig := &Config{ 796 TLSConfig: &sconfig.TLSConfig{ 797 EnableHTTP: true, 798 EnableRPC: true, 799 VerifyServerHostname: true, 800 CAFile: cafile, 801 CertFile: foocert, 802 KeyFile: fookey, 803 }, 804 } 805 806 err := agent.Reload(newConfig) 807 assert.Nil(err) 808 809 assert.Equal(agent.config.TLSConfig.CAFile, newConfig.TLSConfig.CAFile) 810 assert.Equal(agent.config.TLSConfig.CertFile, newConfig.TLSConfig.CertFile) 811 assert.Equal(agent.config.TLSConfig.KeyFile, newConfig.TLSConfig.KeyFile) 812 } 813 814 func TestServer_Reload_TLS_DowngradeFromTLS(t *testing.T) { 815 t.Parallel() 816 assert := assert.New(t) 817 818 const ( 819 cafile = "../../helper/tlsutil/testdata/ca.pem" 820 foocert = "../../helper/tlsutil/testdata/nomad-foo.pem" 821 fookey = "../../helper/tlsutil/testdata/nomad-foo-key.pem" 822 ) 823 dir := tmpDir(t) 824 defer os.RemoveAll(dir) 825 826 logger := testlog.HCLogger(t) 827 828 agentConfig := &Config{ 829 TLSConfig: &sconfig.TLSConfig{ 830 EnableHTTP: true, 831 EnableRPC: true, 832 VerifyServerHostname: true, 833 CAFile: cafile, 834 CertFile: foocert, 835 KeyFile: fookey, 836 }, 837 } 838 839 agent := &Agent{ 840 logger: logger, 841 config: agentConfig, 842 auditor: &noOpAuditor{}, 843 } 844 845 newConfig := &Config{ 846 TLSConfig: &sconfig.TLSConfig{}, 847 } 848 849 assert.False(agentConfig.TLSConfig.IsEmpty()) 850 851 err := agent.Reload(newConfig) 852 assert.Nil(err) 853 854 assert.True(agentConfig.TLSConfig.IsEmpty()) 855 } 856 857 func TestServer_ShouldReload_ReturnFalseForNoChanges(t *testing.T) { 858 t.Parallel() 859 assert := assert.New(t) 860 861 const ( 862 cafile = "../../helper/tlsutil/testdata/ca.pem" 863 foocert = "../../helper/tlsutil/testdata/nomad-foo.pem" 864 fookey = "../../helper/tlsutil/testdata/nomad-foo-key.pem" 865 ) 866 dir := tmpDir(t) 867 defer os.RemoveAll(dir) 868 869 sameAgentConfig := &Config{ 870 TLSConfig: &sconfig.TLSConfig{ 871 EnableHTTP: true, 872 EnableRPC: true, 873 VerifyServerHostname: true, 874 CAFile: cafile, 875 CertFile: foocert, 876 KeyFile: fookey, 877 }, 878 } 879 880 agent := NewTestAgent(t, t.Name(), func(c *Config) { 881 c.TLSConfig = &sconfig.TLSConfig{ 882 EnableHTTP: true, 883 EnableRPC: true, 884 VerifyServerHostname: true, 885 CAFile: cafile, 886 CertFile: foocert, 887 KeyFile: fookey, 888 } 889 }) 890 defer agent.Shutdown() 891 892 shouldReloadAgent, shouldReloadHTTP := agent.ShouldReload(sameAgentConfig) 893 assert.False(shouldReloadAgent) 894 assert.False(shouldReloadHTTP) 895 } 896 897 func TestServer_ShouldReload_ReturnTrueForOnlyHTTPChanges(t *testing.T) { 898 t.Parallel() 899 require := require.New(t) 900 901 const ( 902 cafile = "../../helper/tlsutil/testdata/ca.pem" 903 foocert = "../../helper/tlsutil/testdata/nomad-foo.pem" 904 fookey = "../../helper/tlsutil/testdata/nomad-foo-key.pem" 905 ) 906 dir := tmpDir(t) 907 defer os.RemoveAll(dir) 908 909 sameAgentConfig := &Config{ 910 TLSConfig: &sconfig.TLSConfig{ 911 EnableHTTP: false, 912 EnableRPC: true, 913 VerifyServerHostname: true, 914 CAFile: cafile, 915 CertFile: foocert, 916 KeyFile: fookey, 917 }, 918 } 919 920 agent := NewTestAgent(t, t.Name(), func(c *Config) { 921 c.TLSConfig = &sconfig.TLSConfig{ 922 EnableHTTP: true, 923 EnableRPC: true, 924 VerifyServerHostname: true, 925 CAFile: cafile, 926 CertFile: foocert, 927 KeyFile: fookey, 928 } 929 }) 930 defer agent.Shutdown() 931 932 shouldReloadAgent, shouldReloadHTTP := agent.ShouldReload(sameAgentConfig) 933 require.True(shouldReloadAgent) 934 require.True(shouldReloadHTTP) 935 } 936 937 func TestServer_ShouldReload_ReturnTrueForOnlyRPCChanges(t *testing.T) { 938 t.Parallel() 939 assert := assert.New(t) 940 941 const ( 942 cafile = "../../helper/tlsutil/testdata/ca.pem" 943 foocert = "../../helper/tlsutil/testdata/nomad-foo.pem" 944 fookey = "../../helper/tlsutil/testdata/nomad-foo-key.pem" 945 ) 946 dir := tmpDir(t) 947 defer os.RemoveAll(dir) 948 949 sameAgentConfig := &Config{ 950 TLSConfig: &sconfig.TLSConfig{ 951 EnableHTTP: true, 952 EnableRPC: true, 953 VerifyServerHostname: true, 954 CAFile: cafile, 955 CertFile: foocert, 956 KeyFile: fookey, 957 }, 958 } 959 960 agent := NewTestAgent(t, t.Name(), func(c *Config) { 961 c.TLSConfig = &sconfig.TLSConfig{ 962 EnableHTTP: true, 963 EnableRPC: false, 964 VerifyServerHostname: true, 965 CAFile: cafile, 966 CertFile: foocert, 967 KeyFile: fookey, 968 } 969 }) 970 defer agent.Shutdown() 971 972 shouldReloadAgent, shouldReloadHTTP := agent.ShouldReload(sameAgentConfig) 973 assert.True(shouldReloadAgent) 974 assert.False(shouldReloadHTTP) 975 } 976 977 func TestServer_ShouldReload_ReturnTrueForConfigChanges(t *testing.T) { 978 t.Parallel() 979 assert := assert.New(t) 980 981 const ( 982 cafile = "../../helper/tlsutil/testdata/ca.pem" 983 foocert = "../../helper/tlsutil/testdata/nomad-foo.pem" 984 fookey = "../../helper/tlsutil/testdata/nomad-foo-key.pem" 985 foocert2 = "../../helper/tlsutil/testdata/nomad-bad.pem" 986 fookey2 = "../../helper/tlsutil/testdata/nomad-bad-key.pem" 987 ) 988 dir := tmpDir(t) 989 defer os.RemoveAll(dir) 990 991 agent := NewTestAgent(t, t.Name(), func(c *Config) { 992 c.TLSConfig = &sconfig.TLSConfig{ 993 EnableHTTP: true, 994 EnableRPC: true, 995 VerifyServerHostname: true, 996 CAFile: cafile, 997 CertFile: foocert, 998 KeyFile: fookey, 999 } 1000 }) 1001 defer agent.Shutdown() 1002 1003 newConfig := &Config{ 1004 TLSConfig: &sconfig.TLSConfig{ 1005 EnableHTTP: true, 1006 EnableRPC: true, 1007 VerifyServerHostname: true, 1008 CAFile: cafile, 1009 CertFile: foocert2, 1010 KeyFile: fookey2, 1011 }, 1012 } 1013 1014 shouldReloadAgent, shouldReloadHTTP := agent.ShouldReload(newConfig) 1015 assert.True(shouldReloadAgent) 1016 assert.True(shouldReloadHTTP) 1017 } 1018 1019 func TestServer_ShouldReload_ReturnTrueForFileChanges(t *testing.T) { 1020 t.Parallel() 1021 require := require.New(t) 1022 1023 oldCertificate := ` 1024 -----BEGIN CERTIFICATE----- 1025 MIICrzCCAlagAwIBAgIUN+4rYZ6wqQCIBzYYd0sfX2e8hDowCgYIKoZIzj0EAwIw 1026 eDELMAkGA1UEBhMCVVMxEzARBgNVBAgTCkNhbGlmb3JuaWExFjAUBgNVBAcTDVNh 1027 biBGcmFuY2lzY28xEjAQBgNVBAoTCUhhc2hpQ29ycDEOMAwGA1UECxMFTm9tYWQx 1028 GDAWBgNVBAMTD25vbWFkLmhhc2hpY29ycDAgFw0xNjExMTAxOTU2MDBaGA8yMTE2 1029 MTAxNzE5NTYwMFoweDELMAkGA1UEBhMCVVMxEzARBgNVBAgTCkNhbGlmb3JuaWEx 1030 FjAUBgNVBAcTDVNhbiBGcmFuY2lzY28xEjAQBgNVBAoTCUhhc2hpQ29ycDEOMAwG 1031 A1UECxMFTm9tYWQxGDAWBgNVBAMTD3JlZ2lvbkZvby5ub21hZDBZMBMGByqGSM49 1032 AgEGCCqGSM49AwEHA0IABOqGSFNjm+EBlLYlxmIP6SQTdX8U/6hbPWObB0ffkEO/ 1033 CFweeYIVWb3FKNPqYAlhMqg1K0ileD0FbhEzarP0sL6jgbswgbgwDgYDVR0PAQH/ 1034 BAQDAgWgMB0GA1UdJQQWMBQGCCsGAQUFBwMBBggrBgEFBQcDAjAMBgNVHRMBAf8E 1035 AjAAMB0GA1UdDgQWBBQnMcjU4yI3k0AoMtapACpO+w9QMTAfBgNVHSMEGDAWgBQ6 1036 NWr8F5y2eFwqfoQdQPg0kWb9QDA5BgNVHREEMjAwghZzZXJ2ZXIucmVnaW9uRm9v 1037 Lm5vbWFkghZjbGllbnQucmVnaW9uRm9vLm5vbWFkMAoGCCqGSM49BAMCA0cAMEQC 1038 ICrvzc5NzqhdT/HkazAx5OOUU8hqoptnmhRmwn6X+0y9AiA8bNvMUxHz3ZLjGBiw 1039 PLBDC2UaSDqJqiiYpYegLhbQtw== 1040 -----END CERTIFICATE----- 1041 ` 1042 1043 content := []byte(oldCertificate) 1044 dir, err := ioutil.TempDir("", "certificate") 1045 if err != nil { 1046 t.Fatal(err) 1047 } 1048 defer os.RemoveAll(dir) // clean up 1049 1050 tmpfn := filepath.Join(dir, "testcert") 1051 err = ioutil.WriteFile(tmpfn, content, 0666) 1052 require.Nil(err) 1053 1054 const ( 1055 cafile = "../../helper/tlsutil/testdata/ca.pem" 1056 key = "../../helper/tlsutil/testdata/nomad-foo-key.pem" 1057 ) 1058 1059 logger := testlog.HCLogger(t) 1060 1061 agentConfig := &Config{ 1062 TLSConfig: &sconfig.TLSConfig{ 1063 EnableHTTP: true, 1064 EnableRPC: true, 1065 VerifyServerHostname: true, 1066 CAFile: cafile, 1067 CertFile: tmpfn, 1068 KeyFile: key, 1069 }, 1070 } 1071 1072 agent := &Agent{ 1073 logger: logger, 1074 config: agentConfig, 1075 } 1076 agent.config.TLSConfig.SetChecksum() 1077 1078 shouldReloadAgent, shouldReloadHTTP := agent.ShouldReload(agentConfig) 1079 require.False(shouldReloadAgent) 1080 require.False(shouldReloadHTTP) 1081 1082 newCertificate := ` 1083 -----BEGIN CERTIFICATE----- 1084 MIICtTCCAlqgAwIBAgIUQp/L2szbgE4b1ASlPOZMReFE27owCgYIKoZIzj0EAwIw 1085 fDELMAkGA1UEBhMCVVMxEzARBgNVBAgTCkNhbGlmb3JuaWExFjAUBgNVBAcTDVNh 1086 biBGcmFuY2lzY28xEjAQBgNVBAoTCUhhc2hpQ29ycDEOMAwGA1UECxMFTm9tYWQx 1087 HDAaBgNVBAMTE2JhZC5ub21hZC5oYXNoaWNvcnAwIBcNMTYxMTEwMjAxMDAwWhgP 1088 MjExNjEwMTcyMDEwMDBaMHgxCzAJBgNVBAYTAlVTMRMwEQYDVQQIEwpDYWxpZm9y 1089 bmlhMRYwFAYDVQQHEw1TYW4gRnJhbmNpc2NvMRIwEAYDVQQKEwlIYXNoaUNvcnAx 1090 DjAMBgNVBAsTBU5vbWFkMRgwFgYDVQQDEw9yZWdpb25CYWQubm9tYWQwWTATBgcq 1091 hkjOPQIBBggqhkjOPQMBBwNCAAQk6oXJwlxNrKvl6kpeeR4NJc5EYFI2b3y7odjY 1092 u55Jp4sI91JVDqnpyatkyGmavdAWa4t0U6HkeaWqKk16/ZcYo4G7MIG4MA4GA1Ud 1093 DwEB/wQEAwIFoDAdBgNVHSUEFjAUBggrBgEFBQcDAQYIKwYBBQUHAwIwDAYDVR0T 1094 AQH/BAIwADAdBgNVHQ4EFgQUxhzOftFR2L0QAPx8LOuP99WPbpgwHwYDVR0jBBgw 1095 FoAUHPDLSgzlHqBEh+c4A7HeT0GWygIwOQYDVR0RBDIwMIIWc2VydmVyLnJlZ2lv 1096 bkJhZC5ub21hZIIWY2xpZW50LnJlZ2lvbkJhZC5ub21hZDAKBggqhkjOPQQDAgNJ 1097 ADBGAiEAq2rnBeX/St/8i9Cab7Yw0C7pjcaE+mrFYeQByng1Uc0CIQD/o4BrZdkX 1098 Nm7QGTRZbUFZTHYZr0ULz08Iaz2aHQ6Mcw== 1099 -----END CERTIFICATE----- 1100 ` 1101 1102 os.Remove(tmpfn) 1103 err = ioutil.WriteFile(tmpfn, []byte(newCertificate), 0666) 1104 require.Nil(err) 1105 1106 newAgentConfig := &Config{ 1107 TLSConfig: &sconfig.TLSConfig{ 1108 EnableHTTP: true, 1109 EnableRPC: true, 1110 VerifyServerHostname: true, 1111 CAFile: cafile, 1112 CertFile: tmpfn, 1113 KeyFile: key, 1114 }, 1115 } 1116 1117 shouldReloadAgent, shouldReloadHTTP = agent.ShouldReload(newAgentConfig) 1118 require.True(shouldReloadAgent) 1119 require.True(shouldReloadHTTP) 1120 } 1121 1122 func TestServer_ShouldReload_ShouldHandleMultipleChanges(t *testing.T) { 1123 t.Parallel() 1124 require := require.New(t) 1125 1126 const ( 1127 cafile = "../../helper/tlsutil/testdata/ca.pem" 1128 foocert = "../../helper/tlsutil/testdata/nomad-foo.pem" 1129 fookey = "../../helper/tlsutil/testdata/nomad-foo-key.pem" 1130 foocert2 = "../../helper/tlsutil/testdata/nomad-bad.pem" 1131 fookey2 = "../../helper/tlsutil/testdata/nomad-bad-key.pem" 1132 ) 1133 dir := tmpDir(t) 1134 defer os.RemoveAll(dir) 1135 1136 sameAgentConfig := &Config{ 1137 TLSConfig: &sconfig.TLSConfig{ 1138 EnableHTTP: true, 1139 EnableRPC: true, 1140 VerifyServerHostname: true, 1141 CAFile: cafile, 1142 CertFile: foocert, 1143 KeyFile: fookey, 1144 }, 1145 } 1146 1147 agent := NewTestAgent(t, t.Name(), func(c *Config) { 1148 c.TLSConfig = &sconfig.TLSConfig{ 1149 EnableHTTP: true, 1150 EnableRPC: true, 1151 VerifyServerHostname: true, 1152 CAFile: cafile, 1153 CertFile: foocert2, 1154 KeyFile: fookey2, 1155 } 1156 }) 1157 defer agent.Shutdown() 1158 1159 { 1160 shouldReloadAgent, shouldReloadHTTP := agent.ShouldReload(sameAgentConfig) 1161 require.True(shouldReloadAgent) 1162 require.True(shouldReloadHTTP) 1163 } 1164 1165 err := agent.Reload(sameAgentConfig) 1166 require.Nil(err) 1167 1168 { 1169 shouldReloadAgent, shouldReloadHTTP := agent.ShouldReload(sameAgentConfig) 1170 require.False(shouldReloadAgent) 1171 require.False(shouldReloadHTTP) 1172 } 1173 } 1174 1175 func TestAgent_ProxyRPC_Dev(t *testing.T) { 1176 t.Parallel() 1177 agent := NewTestAgent(t, t.Name(), nil) 1178 defer agent.Shutdown() 1179 1180 id := agent.client.NodeID() 1181 req := &structs.NodeSpecificRequest{ 1182 NodeID: id, 1183 QueryOptions: structs.QueryOptions{ 1184 Region: agent.server.Region(), 1185 }, 1186 } 1187 1188 time.Sleep(100 * time.Millisecond) 1189 1190 var resp cstructs.ClientStatsResponse 1191 if err := agent.RPC("ClientStats.Stats", req, &resp); err != nil { 1192 t.Fatalf("err: %v", err) 1193 } 1194 }