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