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