github.com/Iqoqo/consul@v1.4.5/agent/agent_test.go (about) 1 package agent 2 3 import ( 4 "bytes" 5 "crypto/tls" 6 "encoding/json" 7 "fmt" 8 "io/ioutil" 9 "net" 10 "net/http" 11 "net/http/httptest" 12 "os" 13 "path/filepath" 14 "reflect" 15 "strings" 16 "testing" 17 "time" 18 19 "github.com/hashicorp/consul/testrpc" 20 21 "github.com/hashicorp/consul/agent/checks" 22 "github.com/hashicorp/consul/agent/config" 23 "github.com/hashicorp/consul/agent/connect" 24 "github.com/hashicorp/consul/agent/structs" 25 "github.com/hashicorp/consul/api" 26 "github.com/hashicorp/consul/testutil" 27 "github.com/hashicorp/consul/testutil/retry" 28 "github.com/hashicorp/consul/types" 29 uuid "github.com/hashicorp/go-uuid" 30 "github.com/pascaldekloe/goe/verify" 31 "github.com/stretchr/testify/assert" 32 "github.com/stretchr/testify/require" 33 ) 34 35 func externalIP() (string, error) { 36 addrs, err := net.InterfaceAddrs() 37 if err != nil { 38 return "", fmt.Errorf("Unable to lookup network interfaces: %v", err) 39 } 40 for _, a := range addrs { 41 if ipnet, ok := a.(*net.IPNet); ok && !ipnet.IP.IsLoopback() { 42 if ipnet.IP.To4() != nil { 43 return ipnet.IP.String(), nil 44 } 45 } 46 } 47 return "", fmt.Errorf("Unable to find a non-loopback interface") 48 } 49 50 func TestAgent_MultiStartStop(t *testing.T) { 51 for i := 0; i < 10; i++ { 52 t.Run("", func(t *testing.T) { 53 t.Parallel() 54 a := NewTestAgent(t, t.Name(), "") 55 time.Sleep(250 * time.Millisecond) 56 a.Shutdown() 57 }) 58 } 59 } 60 61 func TestAgent_ConnectClusterIDConfig(t *testing.T) { 62 tests := []struct { 63 name string 64 hcl string 65 wantClusterID string 66 wantPanic bool 67 }{ 68 { 69 name: "default TestAgent has fixed cluster id", 70 hcl: "", 71 wantClusterID: connect.TestClusterID, 72 }, 73 { 74 name: "no cluster ID specified sets to test ID", 75 hcl: "connect { enabled = true }", 76 wantClusterID: connect.TestClusterID, 77 }, 78 { 79 name: "non-UUID cluster_id is fatal", 80 hcl: `connect { 81 enabled = true 82 ca_config { 83 cluster_id = "fake-id" 84 } 85 }`, 86 wantClusterID: "", 87 wantPanic: true, 88 }, 89 } 90 91 for _, tt := range tests { 92 t.Run(tt.name, func(t *testing.T) { 93 // Indirection to support panic recovery cleanly 94 testFn := func() { 95 a := &TestAgent{Name: "test", HCL: tt.hcl} 96 a.ExpectConfigError = tt.wantPanic 97 a.Start(t) 98 defer a.Shutdown() 99 100 cfg := a.consulConfig() 101 assert.Equal(t, tt.wantClusterID, cfg.CAConfig.ClusterID) 102 } 103 104 if tt.wantPanic { 105 require.Panics(t, testFn) 106 } else { 107 testFn() 108 } 109 }) 110 } 111 } 112 113 func TestAgent_StartStop(t *testing.T) { 114 t.Parallel() 115 a := NewTestAgent(t, t.Name(), "") 116 defer a.Shutdown() 117 118 if err := a.Leave(); err != nil { 119 t.Fatalf("err: %v", err) 120 } 121 if err := a.Shutdown(); err != nil { 122 t.Fatalf("err: %v", err) 123 } 124 125 select { 126 case <-a.ShutdownCh(): 127 default: 128 t.Fatalf("should be closed") 129 } 130 } 131 132 func TestAgent_RPCPing(t *testing.T) { 133 t.Parallel() 134 a := NewTestAgent(t, t.Name(), "") 135 defer a.Shutdown() 136 137 var out struct{} 138 if err := a.RPC("Status.Ping", struct{}{}, &out); err != nil { 139 t.Fatalf("err: %v", err) 140 } 141 } 142 143 func TestAgent_TokenStore(t *testing.T) { 144 t.Parallel() 145 146 a := NewTestAgent(t, t.Name(), ` 147 acl_token = "user" 148 acl_agent_token = "agent" 149 acl_agent_master_token = "master"`, 150 ) 151 defer a.Shutdown() 152 153 if got, want := a.tokens.UserToken(), "user"; got != want { 154 t.Fatalf("got %q want %q", got, want) 155 } 156 if got, want := a.tokens.AgentToken(), "agent"; got != want { 157 t.Fatalf("got %q want %q", got, want) 158 } 159 if got, want := a.tokens.IsAgentMasterToken("master"), true; got != want { 160 t.Fatalf("got %v want %v", got, want) 161 } 162 } 163 164 func TestAgent_ReconnectConfigSettings(t *testing.T) { 165 t.Parallel() 166 func() { 167 a := NewTestAgent(t, t.Name(), "") 168 defer a.Shutdown() 169 170 lan := a.consulConfig().SerfLANConfig.ReconnectTimeout 171 if lan != 3*24*time.Hour { 172 t.Fatalf("bad: %s", lan.String()) 173 } 174 175 wan := a.consulConfig().SerfWANConfig.ReconnectTimeout 176 if wan != 3*24*time.Hour { 177 t.Fatalf("bad: %s", wan.String()) 178 } 179 }() 180 181 func() { 182 a := NewTestAgent(t, t.Name(), ` 183 reconnect_timeout = "24h" 184 reconnect_timeout_wan = "36h" 185 `) 186 defer a.Shutdown() 187 188 lan := a.consulConfig().SerfLANConfig.ReconnectTimeout 189 if lan != 24*time.Hour { 190 t.Fatalf("bad: %s", lan.String()) 191 } 192 193 wan := a.consulConfig().SerfWANConfig.ReconnectTimeout 194 if wan != 36*time.Hour { 195 t.Fatalf("bad: %s", wan.String()) 196 } 197 }() 198 } 199 200 func TestAgent_ReconnectConfigWanDisabled(t *testing.T) { 201 t.Parallel() 202 203 a := NewTestAgent(t, t.Name(), ` 204 ports { serf_wan = -1 } 205 reconnect_timeout_wan = "36h" 206 `) 207 defer a.Shutdown() 208 209 // This is also testing that we dont panic like before #4515 210 require.Nil(t, a.consulConfig().SerfWANConfig) 211 } 212 213 func TestAgent_setupNodeID(t *testing.T) { 214 t.Parallel() 215 a := NewTestAgent(t, t.Name(), ` 216 node_id = "" 217 `) 218 defer a.Shutdown() 219 220 cfg := a.config 221 222 // The auto-assigned ID should be valid. 223 id := a.consulConfig().NodeID 224 if _, err := uuid.ParseUUID(string(id)); err != nil { 225 t.Fatalf("err: %v", err) 226 } 227 228 // Running again should get the same ID (persisted in the file). 229 cfg.NodeID = "" 230 if err := a.setupNodeID(cfg); err != nil { 231 t.Fatalf("err: %v", err) 232 } 233 if newID := a.consulConfig().NodeID; id != newID { 234 t.Fatalf("bad: %q vs %q", id, newID) 235 } 236 237 // Set an invalid ID via.Config. 238 cfg.NodeID = types.NodeID("nope") 239 err := a.setupNodeID(cfg) 240 if err == nil || !strings.Contains(err.Error(), "uuid string is wrong length") { 241 t.Fatalf("err: %v", err) 242 } 243 244 // Set a valid ID via.Config. 245 newID, err := uuid.GenerateUUID() 246 if err != nil { 247 t.Fatalf("err: %v", err) 248 } 249 cfg.NodeID = types.NodeID(strings.ToUpper(newID)) 250 if err := a.setupNodeID(cfg); err != nil { 251 t.Fatalf("err: %v", err) 252 } 253 if id := a.consulConfig().NodeID; string(id) != newID { 254 t.Fatalf("bad: %q vs. %q", id, newID) 255 } 256 257 // Set an invalid ID via the file. 258 fileID := filepath.Join(cfg.DataDir, "node-id") 259 if err := ioutil.WriteFile(fileID, []byte("adf4238a!882b!9ddc!4a9d!5b6758e4159e"), 0600); err != nil { 260 t.Fatalf("err: %v", err) 261 } 262 cfg.NodeID = "" 263 err = a.setupNodeID(cfg) 264 if err == nil || !strings.Contains(err.Error(), "uuid is improperly formatted") { 265 t.Fatalf("err: %v", err) 266 } 267 268 // Set a valid ID via the file. 269 if err := ioutil.WriteFile(fileID, []byte("ADF4238a-882b-9ddc-4a9d-5b6758e4159e"), 0600); err != nil { 270 t.Fatalf("err: %v", err) 271 } 272 cfg.NodeID = "" 273 if err := a.setupNodeID(cfg); err != nil { 274 t.Fatalf("err: %v", err) 275 } 276 if id := a.consulConfig().NodeID; string(id) != "adf4238a-882b-9ddc-4a9d-5b6758e4159e" { 277 t.Fatalf("bad: %q vs. %q", id, newID) 278 } 279 } 280 281 func TestAgent_makeNodeID(t *testing.T) { 282 t.Parallel() 283 a := NewTestAgent(t, t.Name(), ` 284 node_id = "" 285 `) 286 defer a.Shutdown() 287 288 // We should get a valid host-based ID initially. 289 id, err := a.makeNodeID() 290 if err != nil { 291 t.Fatalf("err: %v", err) 292 } 293 if _, err := uuid.ParseUUID(string(id)); err != nil { 294 t.Fatalf("err: %v", err) 295 } 296 297 // Calling again should yield a random ID by default. 298 another, err := a.makeNodeID() 299 if err != nil { 300 t.Fatalf("err: %v", err) 301 } 302 if id == another { 303 t.Fatalf("bad: %s vs %s", id, another) 304 } 305 306 // Turn on host-based IDs and try again. We should get the same ID 307 // each time (and a different one from the random one above). 308 a.Config.DisableHostNodeID = false 309 id, err = a.makeNodeID() 310 if err != nil { 311 t.Fatalf("err: %v", err) 312 } 313 if id == another { 314 t.Fatalf("bad: %s vs %s", id, another) 315 } 316 317 // Calling again should yield the host-based ID. 318 another, err = a.makeNodeID() 319 if err != nil { 320 t.Fatalf("err: %v", err) 321 } 322 if id != another { 323 t.Fatalf("bad: %s vs %s", id, another) 324 } 325 } 326 327 func TestAgent_AddService(t *testing.T) { 328 t.Parallel() 329 a := NewTestAgent(t, t.Name(), ` 330 node_name = "node1" 331 `) 332 defer a.Shutdown() 333 334 tests := []struct { 335 desc string 336 srv *structs.NodeService 337 wantSrv func(ns *structs.NodeService) 338 chkTypes []*structs.CheckType 339 healthChks map[string]*structs.HealthCheck 340 }{ 341 { 342 "one check", 343 &structs.NodeService{ 344 ID: "svcid1", 345 Service: "svcname1", 346 Tags: []string{"tag1"}, 347 Weights: nil, // nil weights... 348 Port: 8100, 349 }, 350 // ... should be populated to avoid "IsSame" returning true during AE. 351 func(ns *structs.NodeService) { 352 ns.Weights = &structs.Weights{ 353 Passing: 1, 354 Warning: 1, 355 } 356 }, 357 []*structs.CheckType{ 358 &structs.CheckType{ 359 CheckID: "check1", 360 Name: "name1", 361 TTL: time.Minute, 362 Notes: "note1", 363 }, 364 }, 365 map[string]*structs.HealthCheck{ 366 "check1": &structs.HealthCheck{ 367 Node: "node1", 368 CheckID: "check1", 369 Name: "name1", 370 Status: "critical", 371 Notes: "note1", 372 ServiceID: "svcid1", 373 ServiceName: "svcname1", 374 ServiceTags: []string{"tag1"}, 375 }, 376 }, 377 }, 378 { 379 "multiple checks", 380 &structs.NodeService{ 381 ID: "svcid2", 382 Service: "svcname2", 383 Weights: &structs.Weights{ 384 Passing: 2, 385 Warning: 1, 386 }, 387 Tags: []string{"tag2"}, 388 Port: 8200, 389 }, 390 nil, // No change expected 391 []*structs.CheckType{ 392 &structs.CheckType{ 393 CheckID: "check1", 394 Name: "name1", 395 TTL: time.Minute, 396 Notes: "note1", 397 }, 398 &structs.CheckType{ 399 CheckID: "check-noname", 400 TTL: time.Minute, 401 }, 402 &structs.CheckType{ 403 Name: "check-noid", 404 TTL: time.Minute, 405 }, 406 &structs.CheckType{ 407 TTL: time.Minute, 408 }, 409 }, 410 map[string]*structs.HealthCheck{ 411 "check1": &structs.HealthCheck{ 412 Node: "node1", 413 CheckID: "check1", 414 Name: "name1", 415 Status: "critical", 416 Notes: "note1", 417 ServiceID: "svcid2", 418 ServiceName: "svcname2", 419 ServiceTags: []string{"tag2"}, 420 }, 421 "check-noname": &structs.HealthCheck{ 422 Node: "node1", 423 CheckID: "check-noname", 424 Name: "Service 'svcname2' check", 425 Status: "critical", 426 ServiceID: "svcid2", 427 ServiceName: "svcname2", 428 ServiceTags: []string{"tag2"}, 429 }, 430 "service:svcid2:3": &structs.HealthCheck{ 431 Node: "node1", 432 CheckID: "service:svcid2:3", 433 Name: "check-noid", 434 Status: "critical", 435 ServiceID: "svcid2", 436 ServiceName: "svcname2", 437 ServiceTags: []string{"tag2"}, 438 }, 439 "service:svcid2:4": &structs.HealthCheck{ 440 Node: "node1", 441 CheckID: "service:svcid2:4", 442 Name: "Service 'svcname2' check", 443 Status: "critical", 444 ServiceID: "svcid2", 445 ServiceName: "svcname2", 446 ServiceTags: []string{"tag2"}, 447 }, 448 }, 449 }, 450 } 451 452 for _, tt := range tests { 453 t.Run(tt.desc, func(t *testing.T) { 454 // check the service registration 455 t.Run(tt.srv.ID, func(t *testing.T) { 456 err := a.AddService(tt.srv, tt.chkTypes, false, "", ConfigSourceLocal) 457 if err != nil { 458 t.Fatalf("err: %v", err) 459 } 460 461 got := a.State.Services()[tt.srv.ID] 462 // Make a copy since the tt.srv points to the one in memory in the local 463 // state still so changing it is a tautology! 464 want := *tt.srv 465 if tt.wantSrv != nil { 466 tt.wantSrv(&want) 467 } 468 require.Equal(t, &want, got) 469 require.True(t, got.IsSame(&want)) 470 }) 471 472 // check the health checks 473 for k, v := range tt.healthChks { 474 t.Run(k, func(t *testing.T) { 475 got := a.State.Checks()[types.CheckID(k)] 476 require.Equal(t, v, got) 477 }) 478 } 479 480 // check the ttl checks 481 for k := range tt.healthChks { 482 t.Run(k+" ttl", func(t *testing.T) { 483 chk := a.checkTTLs[types.CheckID(k)] 484 if chk == nil { 485 t.Fatal("got nil want TTL check") 486 } 487 if got, want := string(chk.CheckID), k; got != want { 488 t.Fatalf("got CheckID %v want %v", got, want) 489 } 490 if got, want := chk.TTL, time.Minute; got != want { 491 t.Fatalf("got TTL %v want %v", got, want) 492 } 493 }) 494 } 495 }) 496 } 497 } 498 499 func TestAgent_AddServiceNoExec(t *testing.T) { 500 t.Parallel() 501 a := NewTestAgent(t, t.Name(), ` 502 node_name = "node1" 503 `) 504 defer a.Shutdown() 505 testrpc.WaitForTestAgent(t, a.RPC, "dc1") 506 507 srv := &structs.NodeService{ 508 ID: "svcid1", 509 Service: "svcname1", 510 Tags: []string{"tag1"}, 511 Port: 8100, 512 } 513 chk := &structs.CheckType{ 514 ScriptArgs: []string{"exit", "0"}, 515 Interval: 15 * time.Second, 516 } 517 518 err := a.AddService(srv, []*structs.CheckType{chk}, false, "", ConfigSourceLocal) 519 if err == nil || !strings.Contains(err.Error(), "Scripts are disabled on this agent") { 520 t.Fatalf("err: %v", err) 521 } 522 523 err = a.AddService(srv, []*structs.CheckType{chk}, false, "", ConfigSourceRemote) 524 if err == nil || !strings.Contains(err.Error(), "Scripts are disabled on this agent") { 525 t.Fatalf("err: %v", err) 526 } 527 } 528 529 func TestAgent_AddServiceNoRemoteExec(t *testing.T) { 530 t.Parallel() 531 a := NewTestAgent(t, t.Name(), ` 532 node_name = "node1" 533 enable_local_script_checks = true 534 `) 535 defer a.Shutdown() 536 testrpc.WaitForTestAgent(t, a.RPC, "dc1") 537 538 srv := &structs.NodeService{ 539 ID: "svcid1", 540 Service: "svcname1", 541 Tags: []string{"tag1"}, 542 Port: 8100, 543 } 544 chk := &structs.CheckType{ 545 ScriptArgs: []string{"exit", "0"}, 546 Interval: 15 * time.Second, 547 } 548 549 err := a.AddService(srv, []*structs.CheckType{chk}, false, "", ConfigSourceRemote) 550 if err == nil || !strings.Contains(err.Error(), "Scripts are disabled on this agent") { 551 t.Fatalf("err: %v", err) 552 } 553 } 554 555 func TestAgent_RemoveService(t *testing.T) { 556 t.Parallel() 557 a := NewTestAgent(t, t.Name(), "") 558 defer a.Shutdown() 559 560 // Remove a service that doesn't exist 561 if err := a.RemoveService("redis", false); err != nil { 562 t.Fatalf("err: %v", err) 563 } 564 565 // Remove without an ID 566 if err := a.RemoveService("", false); err == nil { 567 t.Fatalf("should have errored") 568 } 569 570 // Removing a service with a single check works 571 { 572 srv := &structs.NodeService{ 573 ID: "memcache", 574 Service: "memcache", 575 Port: 8000, 576 } 577 chkTypes := []*structs.CheckType{&structs.CheckType{TTL: time.Minute}} 578 579 if err := a.AddService(srv, chkTypes, false, "", ConfigSourceLocal); err != nil { 580 t.Fatalf("err: %v", err) 581 } 582 583 // Add a check after the fact with a specific check ID 584 check := &structs.CheckDefinition{ 585 ID: "check2", 586 Name: "check2", 587 ServiceID: "memcache", 588 TTL: time.Minute, 589 } 590 hc := check.HealthCheck("node1") 591 if err := a.AddCheck(hc, check.CheckType(), false, "", ConfigSourceLocal); err != nil { 592 t.Fatalf("err: %s", err) 593 } 594 595 if err := a.RemoveService("memcache", false); err != nil { 596 t.Fatalf("err: %s", err) 597 } 598 if _, ok := a.State.Checks()["service:memcache"]; ok { 599 t.Fatalf("have memcache check") 600 } 601 if _, ok := a.State.Checks()["check2"]; ok { 602 t.Fatalf("have check2 check") 603 } 604 } 605 606 // Removing a service with multiple checks works 607 { 608 // add a service to remove 609 srv := &structs.NodeService{ 610 ID: "redis", 611 Service: "redis", 612 Port: 8000, 613 } 614 chkTypes := []*structs.CheckType{ 615 &structs.CheckType{TTL: time.Minute}, 616 &structs.CheckType{TTL: 30 * time.Second}, 617 } 618 if err := a.AddService(srv, chkTypes, false, "", ConfigSourceLocal); err != nil { 619 t.Fatalf("err: %v", err) 620 } 621 622 // add another service that wont be affected 623 srv = &structs.NodeService{ 624 ID: "mysql", 625 Service: "mysql", 626 Port: 3306, 627 } 628 chkTypes = []*structs.CheckType{ 629 &structs.CheckType{TTL: time.Minute}, 630 &structs.CheckType{TTL: 30 * time.Second}, 631 } 632 if err := a.AddService(srv, chkTypes, false, "", ConfigSourceLocal); err != nil { 633 t.Fatalf("err: %v", err) 634 } 635 636 // Remove the service 637 if err := a.RemoveService("redis", false); err != nil { 638 t.Fatalf("err: %v", err) 639 } 640 641 // Ensure we have a state mapping 642 if _, ok := a.State.Services()["redis"]; ok { 643 t.Fatalf("have redis service") 644 } 645 646 // Ensure checks were removed 647 if _, ok := a.State.Checks()["service:redis:1"]; ok { 648 t.Fatalf("check redis:1 should be removed") 649 } 650 if _, ok := a.State.Checks()["service:redis:2"]; ok { 651 t.Fatalf("check redis:2 should be removed") 652 } 653 654 // Ensure the redis checks are removed 655 if _, ok := a.checkTTLs["service:redis:1"]; ok { 656 t.Fatalf("check ttl for redis:1 should be removed") 657 } 658 if check := a.State.Check(types.CheckID("service:redis:1")); check != nil { 659 t.Fatalf("check ttl for redis:1 should be removed") 660 } 661 if _, ok := a.checkTTLs["service:redis:2"]; ok { 662 t.Fatalf("check ttl for redis:2 should be removed") 663 } 664 if check := a.State.Check(types.CheckID("service:redis:2")); check != nil { 665 t.Fatalf("check ttl for redis:2 should be removed") 666 } 667 668 // check the mysql service is unnafected 669 if _, ok := a.checkTTLs["service:mysql:1"]; !ok { 670 t.Fatalf("check ttl for mysql:1 should not be removed") 671 } 672 if check := a.State.Check(types.CheckID("service:mysql:1")); check == nil { 673 t.Fatalf("check ttl for mysql:1 should not be removed") 674 } 675 if _, ok := a.checkTTLs["service:mysql:2"]; !ok { 676 t.Fatalf("check ttl for mysql:2 should not be removed") 677 } 678 if check := a.State.Check(types.CheckID("service:mysql:2")); check == nil { 679 t.Fatalf("check ttl for mysql:2 should not be removed") 680 } 681 } 682 } 683 684 func TestAgent_RemoveServiceRemovesAllChecks(t *testing.T) { 685 t.Parallel() 686 a := NewTestAgent(t, t.Name(), ` 687 node_name = "node1" 688 `) 689 defer a.Shutdown() 690 691 svc := &structs.NodeService{ID: "redis", Service: "redis", Port: 8000} 692 chk1 := &structs.CheckType{CheckID: "chk1", Name: "chk1", TTL: time.Minute} 693 chk2 := &structs.CheckType{CheckID: "chk2", Name: "chk2", TTL: 2 * time.Minute} 694 hchk1 := &structs.HealthCheck{Node: "node1", CheckID: "chk1", Name: "chk1", Status: "critical", ServiceID: "redis", ServiceName: "redis"} 695 hchk2 := &structs.HealthCheck{Node: "node1", CheckID: "chk2", Name: "chk2", Status: "critical", ServiceID: "redis", ServiceName: "redis"} 696 697 // register service with chk1 698 if err := a.AddService(svc, []*structs.CheckType{chk1}, false, "", ConfigSourceLocal); err != nil { 699 t.Fatal("Failed to register service", err) 700 } 701 702 // verify chk1 exists 703 if a.State.Checks()["chk1"] == nil { 704 t.Fatal("Could not find health check chk1") 705 } 706 707 // update the service with chk2 708 if err := a.AddService(svc, []*structs.CheckType{chk2}, false, "", ConfigSourceLocal); err != nil { 709 t.Fatal("Failed to update service", err) 710 } 711 712 // check that both checks are there 713 if got, want := a.State.Checks()["chk1"], hchk1; !verify.Values(t, "", got, want) { 714 t.FailNow() 715 } 716 if got, want := a.State.Checks()["chk2"], hchk2; !verify.Values(t, "", got, want) { 717 t.FailNow() 718 } 719 720 // Remove service 721 if err := a.RemoveService("redis", false); err != nil { 722 t.Fatal("Failed to remove service", err) 723 } 724 725 // Check that both checks are gone 726 if a.State.Checks()["chk1"] != nil { 727 t.Fatal("Found health check chk1 want nil") 728 } 729 if a.State.Checks()["chk2"] != nil { 730 t.Fatal("Found health check chk2 want nil") 731 } 732 } 733 734 // TestAgent_IndexChurn is designed to detect a class of issues where 735 // we would have unnecessary catalog churn from anti-entropy. See issues 736 // #3259, #3642, #3845, and #3866. 737 func TestAgent_IndexChurn(t *testing.T) { 738 t.Parallel() 739 740 t.Run("no tags", func(t *testing.T) { 741 verifyIndexChurn(t, nil) 742 }) 743 744 t.Run("with tags", func(t *testing.T) { 745 verifyIndexChurn(t, []string{"foo", "bar"}) 746 }) 747 } 748 749 // verifyIndexChurn registers some things and runs anti-entropy a bunch of times 750 // in a row to make sure there are no index bumps. 751 func verifyIndexChurn(t *testing.T, tags []string) { 752 t.Helper() 753 754 a := NewTestAgent(t, t.Name(), "") 755 defer a.Shutdown() 756 757 weights := &structs.Weights{ 758 Passing: 1, 759 Warning: 1, 760 } 761 // Ensure we have a leader before we start adding the services 762 testrpc.WaitForLeader(t, a.RPC, "dc1") 763 764 svc := &structs.NodeService{ 765 ID: "redis", 766 Service: "redis", 767 Port: 8000, 768 Tags: tags, 769 Weights: weights, 770 } 771 if err := a.AddService(svc, nil, true, "", ConfigSourceLocal); err != nil { 772 t.Fatalf("err: %v", err) 773 } 774 775 chk := &structs.HealthCheck{ 776 CheckID: "redis-check", 777 Name: "Service-level check", 778 ServiceID: "redis", 779 Status: api.HealthCritical, 780 } 781 chkt := &structs.CheckType{ 782 TTL: time.Hour, 783 } 784 if err := a.AddCheck(chk, chkt, true, "", ConfigSourceLocal); err != nil { 785 t.Fatalf("err: %v", err) 786 } 787 788 chk = &structs.HealthCheck{ 789 CheckID: "node-check", 790 Name: "Node-level check", 791 Status: api.HealthCritical, 792 } 793 chkt = &structs.CheckType{ 794 TTL: time.Hour, 795 } 796 if err := a.AddCheck(chk, chkt, true, "", ConfigSourceLocal); err != nil { 797 t.Fatalf("err: %v", err) 798 } 799 800 if err := a.sync.State.SyncFull(); err != nil { 801 t.Fatalf("err: %v", err) 802 } 803 804 args := &structs.ServiceSpecificRequest{ 805 Datacenter: "dc1", 806 ServiceName: "redis", 807 } 808 var before structs.IndexedCheckServiceNodes 809 810 // This sleep is so that the serfHealth check is added to the agent 811 // A value of 375ms is sufficient enough time to ensure the serfHealth 812 // check is added to an agent. 500ms so that we don't see flakiness ever. 813 time.Sleep(500 * time.Millisecond) 814 815 if err := a.RPC("Health.ServiceNodes", args, &before); err != nil { 816 t.Fatalf("err: %v", err) 817 } 818 for _, name := range before.Nodes[0].Checks { 819 a.logger.Println("[DEBUG] Checks Registered: ", name.Name) 820 } 821 if got, want := len(before.Nodes), 1; got != want { 822 t.Fatalf("got %d want %d", got, want) 823 } 824 if got, want := len(before.Nodes[0].Checks), 3; /* incl. serfHealth */ got != want { 825 t.Fatalf("got %d want %d", got, want) 826 } 827 828 for i := 0; i < 10; i++ { 829 a.logger.Println("[INFO] # ", i+1, "Sync in progress ") 830 if err := a.sync.State.SyncFull(); err != nil { 831 t.Fatalf("err: %v", err) 832 } 833 } 834 // If this test fails here this means that the Consul-X-Index 835 // has changed for the RPC, which means that idempotent ops 836 // are not working as intended. 837 var after structs.IndexedCheckServiceNodes 838 if err := a.RPC("Health.ServiceNodes", args, &after); err != nil { 839 t.Fatalf("err: %v", err) 840 } 841 verify.Values(t, "", after, before) 842 } 843 844 func TestAgent_AddCheck(t *testing.T) { 845 t.Parallel() 846 a := NewTestAgent(t, t.Name(), ` 847 enable_script_checks = true 848 `) 849 defer a.Shutdown() 850 851 health := &structs.HealthCheck{ 852 Node: "foo", 853 CheckID: "mem", 854 Name: "memory util", 855 Status: api.HealthCritical, 856 } 857 chk := &structs.CheckType{ 858 ScriptArgs: []string{"exit", "0"}, 859 Interval: 15 * time.Second, 860 } 861 err := a.AddCheck(health, chk, false, "", ConfigSourceLocal) 862 if err != nil { 863 t.Fatalf("err: %v", err) 864 } 865 866 // Ensure we have a check mapping 867 sChk, ok := a.State.Checks()["mem"] 868 if !ok { 869 t.Fatalf("missing mem check") 870 } 871 872 // Ensure our check is in the right state 873 if sChk.Status != api.HealthCritical { 874 t.Fatalf("check not critical") 875 } 876 877 // Ensure a TTL is setup 878 if _, ok := a.checkMonitors["mem"]; !ok { 879 t.Fatalf("missing mem monitor") 880 } 881 } 882 883 func TestAgent_AddCheck_StartPassing(t *testing.T) { 884 t.Parallel() 885 a := NewTestAgent(t, t.Name(), ` 886 enable_script_checks = true 887 `) 888 defer a.Shutdown() 889 890 health := &structs.HealthCheck{ 891 Node: "foo", 892 CheckID: "mem", 893 Name: "memory util", 894 Status: api.HealthPassing, 895 } 896 chk := &structs.CheckType{ 897 ScriptArgs: []string{"exit", "0"}, 898 Interval: 15 * time.Second, 899 } 900 err := a.AddCheck(health, chk, false, "", ConfigSourceLocal) 901 if err != nil { 902 t.Fatalf("err: %v", err) 903 } 904 905 // Ensure we have a check mapping 906 sChk, ok := a.State.Checks()["mem"] 907 if !ok { 908 t.Fatalf("missing mem check") 909 } 910 911 // Ensure our check is in the right state 912 if sChk.Status != api.HealthPassing { 913 t.Fatalf("check not passing") 914 } 915 916 // Ensure a TTL is setup 917 if _, ok := a.checkMonitors["mem"]; !ok { 918 t.Fatalf("missing mem monitor") 919 } 920 } 921 922 func TestAgent_AddCheck_MinInterval(t *testing.T) { 923 t.Parallel() 924 a := NewTestAgent(t, t.Name(), ` 925 enable_script_checks = true 926 `) 927 defer a.Shutdown() 928 929 health := &structs.HealthCheck{ 930 Node: "foo", 931 CheckID: "mem", 932 Name: "memory util", 933 Status: api.HealthCritical, 934 } 935 chk := &structs.CheckType{ 936 ScriptArgs: []string{"exit", "0"}, 937 Interval: time.Microsecond, 938 } 939 err := a.AddCheck(health, chk, false, "", ConfigSourceLocal) 940 if err != nil { 941 t.Fatalf("err: %v", err) 942 } 943 944 // Ensure we have a check mapping 945 if _, ok := a.State.Checks()["mem"]; !ok { 946 t.Fatalf("missing mem check") 947 } 948 949 // Ensure a TTL is setup 950 if mon, ok := a.checkMonitors["mem"]; !ok { 951 t.Fatalf("missing mem monitor") 952 } else if mon.Interval != checks.MinInterval { 953 t.Fatalf("bad mem monitor interval") 954 } 955 } 956 957 func TestAgent_AddCheck_MissingService(t *testing.T) { 958 t.Parallel() 959 a := NewTestAgent(t, t.Name(), ` 960 enable_script_checks = true 961 `) 962 defer a.Shutdown() 963 964 health := &structs.HealthCheck{ 965 Node: "foo", 966 CheckID: "baz", 967 Name: "baz check 1", 968 ServiceID: "baz", 969 } 970 chk := &structs.CheckType{ 971 ScriptArgs: []string{"exit", "0"}, 972 Interval: time.Microsecond, 973 } 974 err := a.AddCheck(health, chk, false, "", ConfigSourceLocal) 975 if err == nil || err.Error() != `ServiceID "baz" does not exist` { 976 t.Fatalf("expected service id error, got: %v", err) 977 } 978 } 979 980 func TestAgent_AddCheck_RestoreState(t *testing.T) { 981 t.Parallel() 982 a := NewTestAgent(t, t.Name(), "") 983 defer a.Shutdown() 984 985 // Create some state and persist it 986 ttl := &checks.CheckTTL{ 987 CheckID: "baz", 988 TTL: time.Minute, 989 } 990 err := a.persistCheckState(ttl, api.HealthPassing, "yup") 991 if err != nil { 992 t.Fatalf("err: %s", err) 993 } 994 995 // Build and register the check definition and initial state 996 health := &structs.HealthCheck{ 997 Node: "foo", 998 CheckID: "baz", 999 Name: "baz check 1", 1000 } 1001 chk := &structs.CheckType{ 1002 TTL: time.Minute, 1003 } 1004 err = a.AddCheck(health, chk, false, "", ConfigSourceLocal) 1005 if err != nil { 1006 t.Fatalf("err: %s", err) 1007 } 1008 1009 // Ensure the check status was restored during registration 1010 checks := a.State.Checks() 1011 check, ok := checks["baz"] 1012 if !ok { 1013 t.Fatalf("missing check") 1014 } 1015 if check.Status != api.HealthPassing { 1016 t.Fatalf("bad: %#v", check) 1017 } 1018 if check.Output != "yup" { 1019 t.Fatalf("bad: %#v", check) 1020 } 1021 } 1022 1023 func TestAgent_AddCheck_ExecDisable(t *testing.T) { 1024 t.Parallel() 1025 1026 a := NewTestAgent(t, t.Name(), "") 1027 defer a.Shutdown() 1028 1029 health := &structs.HealthCheck{ 1030 Node: "foo", 1031 CheckID: "mem", 1032 Name: "memory util", 1033 Status: api.HealthCritical, 1034 } 1035 chk := &structs.CheckType{ 1036 ScriptArgs: []string{"exit", "0"}, 1037 Interval: 15 * time.Second, 1038 } 1039 err := a.AddCheck(health, chk, false, "", ConfigSourceLocal) 1040 if err == nil || !strings.Contains(err.Error(), "Scripts are disabled on this agent") { 1041 t.Fatalf("err: %v", err) 1042 } 1043 1044 // Ensure we don't have a check mapping 1045 if memChk := a.State.Checks()["mem"]; memChk != nil { 1046 t.Fatalf("should be missing mem check") 1047 } 1048 1049 err = a.AddCheck(health, chk, false, "", ConfigSourceRemote) 1050 if err == nil || !strings.Contains(err.Error(), "Scripts are disabled on this agent") { 1051 t.Fatalf("err: %v", err) 1052 } 1053 1054 // Ensure we don't have a check mapping 1055 if memChk := a.State.Checks()["mem"]; memChk != nil { 1056 t.Fatalf("should be missing mem check") 1057 } 1058 } 1059 1060 func TestAgent_AddCheck_ExecRemoteDisable(t *testing.T) { 1061 t.Parallel() 1062 1063 a := NewTestAgent(t, t.Name(), ` 1064 enable_local_script_checks = true 1065 `) 1066 defer a.Shutdown() 1067 testrpc.WaitForTestAgent(t, a.RPC, "dc1") 1068 1069 health := &structs.HealthCheck{ 1070 Node: "foo", 1071 CheckID: "mem", 1072 Name: "memory util", 1073 Status: api.HealthCritical, 1074 } 1075 chk := &structs.CheckType{ 1076 ScriptArgs: []string{"exit", "0"}, 1077 Interval: 15 * time.Second, 1078 } 1079 err := a.AddCheck(health, chk, false, "", ConfigSourceRemote) 1080 if err == nil || !strings.Contains(err.Error(), "Scripts are disabled on this agent from remote calls") { 1081 t.Fatalf("err: %v", err) 1082 } 1083 1084 // Ensure we don't have a check mapping 1085 if memChk := a.State.Checks()["mem"]; memChk != nil { 1086 t.Fatalf("should be missing mem check") 1087 } 1088 } 1089 1090 func TestAgent_AddCheck_GRPC(t *testing.T) { 1091 t.Parallel() 1092 a := NewTestAgent(t, t.Name(), "") 1093 defer a.Shutdown() 1094 1095 health := &structs.HealthCheck{ 1096 Node: "foo", 1097 CheckID: "grpchealth", 1098 Name: "grpc health checking protocol", 1099 Status: api.HealthCritical, 1100 } 1101 chk := &structs.CheckType{ 1102 GRPC: "localhost:12345/package.Service", 1103 Interval: 15 * time.Second, 1104 } 1105 err := a.AddCheck(health, chk, false, "", ConfigSourceLocal) 1106 if err != nil { 1107 t.Fatalf("err: %v", err) 1108 } 1109 1110 // Ensure we have a check mapping 1111 sChk, ok := a.State.Checks()["grpchealth"] 1112 if !ok { 1113 t.Fatalf("missing grpchealth check") 1114 } 1115 1116 // Ensure our check is in the right state 1117 if sChk.Status != api.HealthCritical { 1118 t.Fatalf("check not critical") 1119 } 1120 1121 // Ensure a check is setup 1122 if _, ok := a.checkGRPCs["grpchealth"]; !ok { 1123 t.Fatalf("missing grpchealth check") 1124 } 1125 } 1126 1127 func TestAgent_AddCheck_Alias(t *testing.T) { 1128 t.Parallel() 1129 1130 require := require.New(t) 1131 a := NewTestAgent(t, t.Name(), "") 1132 defer a.Shutdown() 1133 1134 health := &structs.HealthCheck{ 1135 Node: "foo", 1136 CheckID: "aliashealth", 1137 Name: "Alias health check", 1138 Status: api.HealthCritical, 1139 } 1140 chk := &structs.CheckType{ 1141 AliasService: "foo", 1142 } 1143 err := a.AddCheck(health, chk, false, "", ConfigSourceLocal) 1144 require.NoError(err) 1145 1146 // Ensure we have a check mapping 1147 sChk, ok := a.State.Checks()["aliashealth"] 1148 require.True(ok, "missing aliashealth check") 1149 require.NotNil(sChk) 1150 require.Equal(api.HealthCritical, sChk.Status) 1151 1152 chkImpl, ok := a.checkAliases["aliashealth"] 1153 require.True(ok, "missing aliashealth check") 1154 require.Equal("", chkImpl.RPCReq.Token) 1155 1156 cs := a.State.CheckState("aliashealth") 1157 require.NotNil(cs) 1158 require.Equal("", cs.Token) 1159 } 1160 1161 func TestAgent_AddCheck_Alias_setToken(t *testing.T) { 1162 t.Parallel() 1163 1164 require := require.New(t) 1165 a := NewTestAgent(t, t.Name(), "") 1166 defer a.Shutdown() 1167 1168 health := &structs.HealthCheck{ 1169 Node: "foo", 1170 CheckID: "aliashealth", 1171 Name: "Alias health check", 1172 Status: api.HealthCritical, 1173 } 1174 chk := &structs.CheckType{ 1175 AliasService: "foo", 1176 } 1177 err := a.AddCheck(health, chk, false, "foo", ConfigSourceLocal) 1178 require.NoError(err) 1179 1180 cs := a.State.CheckState("aliashealth") 1181 require.NotNil(cs) 1182 require.Equal("foo", cs.Token) 1183 1184 chkImpl, ok := a.checkAliases["aliashealth"] 1185 require.True(ok, "missing aliashealth check") 1186 require.Equal("foo", chkImpl.RPCReq.Token) 1187 } 1188 1189 func TestAgent_AddCheck_Alias_userToken(t *testing.T) { 1190 t.Parallel() 1191 1192 require := require.New(t) 1193 a := NewTestAgent(t, t.Name(), ` 1194 acl_token = "hello" 1195 `) 1196 defer a.Shutdown() 1197 1198 health := &structs.HealthCheck{ 1199 Node: "foo", 1200 CheckID: "aliashealth", 1201 Name: "Alias health check", 1202 Status: api.HealthCritical, 1203 } 1204 chk := &structs.CheckType{ 1205 AliasService: "foo", 1206 } 1207 err := a.AddCheck(health, chk, false, "", ConfigSourceLocal) 1208 require.NoError(err) 1209 1210 cs := a.State.CheckState("aliashealth") 1211 require.NotNil(cs) 1212 require.Equal("", cs.Token) // State token should still be empty 1213 1214 chkImpl, ok := a.checkAliases["aliashealth"] 1215 require.True(ok, "missing aliashealth check") 1216 require.Equal("hello", chkImpl.RPCReq.Token) // Check should use the token 1217 } 1218 1219 func TestAgent_AddCheck_Alias_userAndSetToken(t *testing.T) { 1220 t.Parallel() 1221 1222 require := require.New(t) 1223 a := NewTestAgent(t, t.Name(), ` 1224 acl_token = "hello" 1225 `) 1226 defer a.Shutdown() 1227 1228 health := &structs.HealthCheck{ 1229 Node: "foo", 1230 CheckID: "aliashealth", 1231 Name: "Alias health check", 1232 Status: api.HealthCritical, 1233 } 1234 chk := &structs.CheckType{ 1235 AliasService: "foo", 1236 } 1237 err := a.AddCheck(health, chk, false, "goodbye", ConfigSourceLocal) 1238 require.NoError(err) 1239 1240 cs := a.State.CheckState("aliashealth") 1241 require.NotNil(cs) 1242 require.Equal("goodbye", cs.Token) 1243 1244 chkImpl, ok := a.checkAliases["aliashealth"] 1245 require.True(ok, "missing aliashealth check") 1246 require.Equal("goodbye", chkImpl.RPCReq.Token) 1247 } 1248 1249 func TestAgent_RemoveCheck(t *testing.T) { 1250 t.Parallel() 1251 a := NewTestAgent(t, t.Name(), ` 1252 enable_script_checks = true 1253 `) 1254 defer a.Shutdown() 1255 1256 // Remove check that doesn't exist 1257 if err := a.RemoveCheck("mem", false); err != nil { 1258 t.Fatalf("err: %v", err) 1259 } 1260 1261 // Remove without an ID 1262 if err := a.RemoveCheck("", false); err == nil { 1263 t.Fatalf("should have errored") 1264 } 1265 1266 health := &structs.HealthCheck{ 1267 Node: "foo", 1268 CheckID: "mem", 1269 Name: "memory util", 1270 Status: api.HealthCritical, 1271 } 1272 chk := &structs.CheckType{ 1273 ScriptArgs: []string{"exit", "0"}, 1274 Interval: 15 * time.Second, 1275 } 1276 err := a.AddCheck(health, chk, false, "", ConfigSourceLocal) 1277 if err != nil { 1278 t.Fatalf("err: %v", err) 1279 } 1280 1281 // Remove check 1282 if err := a.RemoveCheck("mem", false); err != nil { 1283 t.Fatalf("err: %v", err) 1284 } 1285 1286 // Ensure we have a check mapping 1287 if _, ok := a.State.Checks()["mem"]; ok { 1288 t.Fatalf("have mem check") 1289 } 1290 1291 // Ensure a TTL is setup 1292 if _, ok := a.checkMonitors["mem"]; ok { 1293 t.Fatalf("have mem monitor") 1294 } 1295 } 1296 1297 func TestAgent_HTTPCheck_TLSSkipVerify(t *testing.T) { 1298 t.Parallel() 1299 1300 handler := http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) { 1301 fmt.Fprintln(w, "GOOD") 1302 }) 1303 server := httptest.NewTLSServer(handler) 1304 defer server.Close() 1305 1306 a := NewTestAgent(t, t.Name(), "") 1307 defer a.Shutdown() 1308 1309 health := &structs.HealthCheck{ 1310 Node: "foo", 1311 CheckID: "tls", 1312 Name: "tls check", 1313 Status: api.HealthCritical, 1314 } 1315 chk := &structs.CheckType{ 1316 HTTP: server.URL, 1317 Interval: 20 * time.Millisecond, 1318 TLSSkipVerify: true, 1319 } 1320 1321 err := a.AddCheck(health, chk, false, "", ConfigSourceLocal) 1322 if err != nil { 1323 t.Fatalf("err: %v", err) 1324 } 1325 1326 retry.Run(t, func(r *retry.R) { 1327 status := a.State.Checks()["tls"] 1328 if status.Status != api.HealthPassing { 1329 r.Fatalf("bad: %v", status.Status) 1330 } 1331 if !strings.Contains(status.Output, "GOOD") { 1332 r.Fatalf("bad: %v", status.Output) 1333 } 1334 }) 1335 1336 } 1337 1338 func TestAgent_HTTPCheck_EnableAgentTLSForChecks(t *testing.T) { 1339 t.Parallel() 1340 1341 run := func(t *testing.T, ca string) { 1342 a := &TestAgent{ 1343 Name: t.Name(), 1344 UseTLS: true, 1345 HCL: ` 1346 enable_agent_tls_for_checks = true 1347 1348 verify_incoming = true 1349 server_name = "consul.test" 1350 key_file = "../test/client_certs/server.key" 1351 cert_file = "../test/client_certs/server.crt" 1352 ` + ca, 1353 } 1354 a.Start(t) 1355 defer a.Shutdown() 1356 1357 health := &structs.HealthCheck{ 1358 Node: "foo", 1359 CheckID: "tls", 1360 Name: "tls check", 1361 Status: api.HealthCritical, 1362 } 1363 1364 url := fmt.Sprintf("https://%s/v1/agent/self", a.srv.ln.Addr().String()) 1365 chk := &structs.CheckType{ 1366 HTTP: url, 1367 Interval: 20 * time.Millisecond, 1368 } 1369 1370 err := a.AddCheck(health, chk, false, "", ConfigSourceLocal) 1371 if err != nil { 1372 t.Fatalf("err: %v", err) 1373 } 1374 1375 retry.Run(t, func(r *retry.R) { 1376 status := a.State.Checks()["tls"] 1377 if status.Status != api.HealthPassing { 1378 r.Fatalf("bad: %v", status.Status) 1379 } 1380 if !strings.Contains(status.Output, "200 OK") { 1381 r.Fatalf("bad: %v", status.Output) 1382 } 1383 }) 1384 } 1385 1386 // We need to test both methods of passing the CA info to ensure that 1387 // we propagate all the fields correctly. All the other fields are 1388 // covered by the HCL in the test run function. 1389 tests := []struct { 1390 desc string 1391 config string 1392 }{ 1393 {"ca_file", `ca_file = "../test/client_certs/rootca.crt"`}, 1394 {"ca_path", `ca_path = "../test/client_certs/path"`}, 1395 } 1396 for _, tt := range tests { 1397 t.Run(tt.desc, func(t *testing.T) { 1398 run(t, tt.config) 1399 }) 1400 } 1401 } 1402 1403 func TestAgent_updateTTLCheck(t *testing.T) { 1404 t.Parallel() 1405 a := NewTestAgent(t, t.Name(), "") 1406 defer a.Shutdown() 1407 1408 health := &structs.HealthCheck{ 1409 Node: "foo", 1410 CheckID: "mem", 1411 Name: "memory util", 1412 Status: api.HealthCritical, 1413 } 1414 chk := &structs.CheckType{ 1415 TTL: 15 * time.Second, 1416 } 1417 1418 // Add check and update it. 1419 err := a.AddCheck(health, chk, false, "", ConfigSourceLocal) 1420 if err != nil { 1421 t.Fatalf("err: %v", err) 1422 } 1423 if err := a.updateTTLCheck("mem", api.HealthPassing, "foo"); err != nil { 1424 t.Fatalf("err: %v", err) 1425 } 1426 1427 // Ensure we have a check mapping. 1428 status := a.State.Checks()["mem"] 1429 if status.Status != api.HealthPassing { 1430 t.Fatalf("bad: %v", status) 1431 } 1432 if status.Output != "foo" { 1433 t.Fatalf("bad: %v", status) 1434 } 1435 } 1436 1437 func TestAgent_PersistService(t *testing.T) { 1438 t.Parallel() 1439 dataDir := testutil.TempDir(t, "agent") // we manage the data dir 1440 cfg := ` 1441 server = false 1442 bootstrap = false 1443 data_dir = "` + dataDir + `" 1444 ` 1445 a := &TestAgent{Name: t.Name(), HCL: cfg, DataDir: dataDir} 1446 a.Start(t) 1447 defer os.RemoveAll(dataDir) 1448 defer a.Shutdown() 1449 1450 svc := &structs.NodeService{ 1451 ID: "redis", 1452 Service: "redis", 1453 Tags: []string{"foo"}, 1454 Port: 8000, 1455 } 1456 1457 file := filepath.Join(a.Config.DataDir, servicesDir, stringHash(svc.ID)) 1458 1459 // Check is not persisted unless requested 1460 if err := a.AddService(svc, nil, false, "", ConfigSourceLocal); err != nil { 1461 t.Fatalf("err: %v", err) 1462 } 1463 if _, err := os.Stat(file); err == nil { 1464 t.Fatalf("should not persist") 1465 } 1466 1467 // Persists to file if requested 1468 if err := a.AddService(svc, nil, true, "mytoken", ConfigSourceLocal); err != nil { 1469 t.Fatalf("err: %v", err) 1470 } 1471 if _, err := os.Stat(file); err != nil { 1472 t.Fatalf("err: %s", err) 1473 } 1474 expected, err := json.Marshal(persistedService{ 1475 Token: "mytoken", 1476 Service: svc, 1477 }) 1478 if err != nil { 1479 t.Fatalf("err: %s", err) 1480 } 1481 content, err := ioutil.ReadFile(file) 1482 if err != nil { 1483 t.Fatalf("err: %s", err) 1484 } 1485 if !bytes.Equal(expected, content) { 1486 t.Fatalf("bad: %s", string(content)) 1487 } 1488 1489 // Updates service definition on disk 1490 svc.Port = 8001 1491 if err := a.AddService(svc, nil, true, "mytoken", ConfigSourceLocal); err != nil { 1492 t.Fatalf("err: %v", err) 1493 } 1494 expected, err = json.Marshal(persistedService{ 1495 Token: "mytoken", 1496 Service: svc, 1497 }) 1498 if err != nil { 1499 t.Fatalf("err: %s", err) 1500 } 1501 content, err = ioutil.ReadFile(file) 1502 if err != nil { 1503 t.Fatalf("err: %s", err) 1504 } 1505 if !bytes.Equal(expected, content) { 1506 t.Fatalf("bad: %s", string(content)) 1507 } 1508 a.Shutdown() 1509 1510 // Should load it back during later start 1511 a2 := &TestAgent{Name: t.Name(), HCL: cfg, DataDir: dataDir} 1512 a2.Start(t) 1513 defer a2.Shutdown() 1514 1515 restored := a2.State.ServiceState(svc.ID) 1516 if restored == nil { 1517 t.Fatalf("service %q missing", svc.ID) 1518 } 1519 if got, want := restored.Token, "mytoken"; got != want { 1520 t.Fatalf("got token %q want %q", got, want) 1521 } 1522 if got, want := restored.Service.Port, 8001; got != want { 1523 t.Fatalf("got port %d want %d", got, want) 1524 } 1525 } 1526 1527 func TestAgent_persistedService_compat(t *testing.T) { 1528 t.Parallel() 1529 // Tests backwards compatibility of persisted services from pre-0.5.1 1530 a := NewTestAgent(t, t.Name(), "") 1531 defer a.Shutdown() 1532 1533 svc := &structs.NodeService{ 1534 ID: "redis", 1535 Service: "redis", 1536 Tags: []string{"foo"}, 1537 Port: 8000, 1538 Weights: &structs.Weights{Passing: 1, Warning: 1}, 1539 } 1540 1541 // Encode the NodeService directly. This is what previous versions 1542 // would serialize to the file (without the wrapper) 1543 encoded, err := json.Marshal(svc) 1544 if err != nil { 1545 t.Fatalf("err: %s", err) 1546 } 1547 1548 // Write the content to the file 1549 file := filepath.Join(a.Config.DataDir, servicesDir, stringHash(svc.ID)) 1550 if err := os.MkdirAll(filepath.Dir(file), 0700); err != nil { 1551 t.Fatalf("err: %s", err) 1552 } 1553 if err := ioutil.WriteFile(file, encoded, 0600); err != nil { 1554 t.Fatalf("err: %s", err) 1555 } 1556 1557 // Load the services 1558 if err := a.loadServices(a.Config); err != nil { 1559 t.Fatalf("err: %s", err) 1560 } 1561 1562 // Ensure the service was restored 1563 services := a.State.Services() 1564 result, ok := services["redis"] 1565 if !ok { 1566 t.Fatalf("missing service") 1567 } 1568 require.Equal(t, svc, result) 1569 } 1570 1571 func TestAgent_PurgeService(t *testing.T) { 1572 t.Parallel() 1573 a := NewTestAgent(t, t.Name(), "") 1574 defer a.Shutdown() 1575 1576 svc := &structs.NodeService{ 1577 ID: "redis", 1578 Service: "redis", 1579 Tags: []string{"foo"}, 1580 Port: 8000, 1581 } 1582 1583 file := filepath.Join(a.Config.DataDir, servicesDir, stringHash(svc.ID)) 1584 if err := a.AddService(svc, nil, true, "", ConfigSourceLocal); err != nil { 1585 t.Fatalf("err: %v", err) 1586 } 1587 1588 // Not removed 1589 if err := a.RemoveService(svc.ID, false); err != nil { 1590 t.Fatalf("err: %s", err) 1591 } 1592 if _, err := os.Stat(file); err != nil { 1593 t.Fatalf("err: %s", err) 1594 } 1595 1596 // Re-add the service 1597 if err := a.AddService(svc, nil, true, "", ConfigSourceLocal); err != nil { 1598 t.Fatalf("err: %v", err) 1599 } 1600 1601 // Removed 1602 if err := a.RemoveService(svc.ID, true); err != nil { 1603 t.Fatalf("err: %s", err) 1604 } 1605 if _, err := os.Stat(file); !os.IsNotExist(err) { 1606 t.Fatalf("bad: %#v", err) 1607 } 1608 } 1609 1610 func TestAgent_PurgeServiceOnDuplicate(t *testing.T) { 1611 t.Parallel() 1612 dataDir := testutil.TempDir(t, "agent") // we manage the data dir 1613 cfg := ` 1614 data_dir = "` + dataDir + `" 1615 server = false 1616 bootstrap = false 1617 ` 1618 a := &TestAgent{Name: t.Name(), HCL: cfg, DataDir: dataDir} 1619 a.Start(t) 1620 defer a.Shutdown() 1621 defer os.RemoveAll(dataDir) 1622 1623 svc1 := &structs.NodeService{ 1624 ID: "redis", 1625 Service: "redis", 1626 Tags: []string{"foo"}, 1627 Port: 8000, 1628 } 1629 1630 // First persist the service 1631 if err := a.AddService(svc1, nil, true, "", ConfigSourceLocal); err != nil { 1632 t.Fatalf("err: %v", err) 1633 } 1634 a.Shutdown() 1635 1636 // Try bringing the agent back up with the service already 1637 // existing in the config 1638 a2 := &TestAgent{Name: t.Name() + "-a2", HCL: cfg + ` 1639 service = { 1640 id = "redis" 1641 name = "redis" 1642 tags = ["bar"] 1643 port = 9000 1644 } 1645 `, DataDir: dataDir} 1646 a2.Start(t) 1647 defer a2.Shutdown() 1648 1649 file := filepath.Join(a.Config.DataDir, servicesDir, stringHash(svc1.ID)) 1650 if _, err := os.Stat(file); err == nil { 1651 t.Fatalf("should have removed persisted service") 1652 } 1653 result := a2.State.Service("redis") 1654 if result == nil { 1655 t.Fatalf("missing service registration") 1656 } 1657 if !reflect.DeepEqual(result.Tags, []string{"bar"}) || result.Port != 9000 { 1658 t.Fatalf("bad: %#v", result) 1659 } 1660 } 1661 1662 func TestAgent_PersistProxy(t *testing.T) { 1663 t.Parallel() 1664 dataDir := testutil.TempDir(t, "agent") // we manage the data dir 1665 cfg := ` 1666 server = false 1667 bootstrap = false 1668 data_dir = "` + dataDir + `" 1669 ` 1670 a := &TestAgent{Name: t.Name(), HCL: cfg, DataDir: dataDir} 1671 a.Start(t) 1672 defer os.RemoveAll(dataDir) 1673 defer a.Shutdown() 1674 1675 require := require.New(t) 1676 assert := assert.New(t) 1677 1678 // Add a service to proxy (precondition for AddProxy) 1679 svc1 := &structs.NodeService{ 1680 ID: "redis", 1681 Service: "redis", 1682 Tags: []string{"foo"}, 1683 Port: 8000, 1684 } 1685 require.NoError(a.AddService(svc1, nil, true, "", ConfigSourceLocal)) 1686 1687 // Add a proxy for it 1688 proxy := &structs.ConnectManagedProxy{ 1689 TargetServiceID: svc1.ID, 1690 Command: []string{"/bin/sleep", "3600"}, 1691 } 1692 1693 file := filepath.Join(a.Config.DataDir, proxyDir, stringHash("redis-proxy")) 1694 1695 // Proxy is not persisted unless requested 1696 require.NoError(a.AddProxy(proxy, false, false, "", ConfigSourceLocal)) 1697 _, err := os.Stat(file) 1698 require.Error(err, "proxy should not be persisted") 1699 1700 // Proxy is persisted if requested 1701 require.NoError(a.AddProxy(proxy, true, false, "", ConfigSourceLocal)) 1702 _, err = os.Stat(file) 1703 require.NoError(err, "proxy should be persisted") 1704 1705 content, err := ioutil.ReadFile(file) 1706 require.NoError(err) 1707 1708 var gotProxy persistedProxy 1709 require.NoError(json.Unmarshal(content, &gotProxy)) 1710 assert.Equal(proxy.Command, gotProxy.Proxy.Command) 1711 assert.Len(gotProxy.ProxyToken, 36) // sanity check for UUID 1712 1713 // Updates service definition on disk 1714 proxy.Config = map[string]interface{}{ 1715 "foo": "bar", 1716 } 1717 require.NoError(a.AddProxy(proxy, true, false, "", ConfigSourceLocal)) 1718 1719 content, err = ioutil.ReadFile(file) 1720 require.NoError(err) 1721 1722 require.NoError(json.Unmarshal(content, &gotProxy)) 1723 assert.Equal(gotProxy.Proxy.Command, proxy.Command) 1724 assert.Equal(gotProxy.Proxy.Config, proxy.Config) 1725 assert.Len(gotProxy.ProxyToken, 36) // sanity check for UUID 1726 1727 a.Shutdown() 1728 1729 // Should load it back during later start 1730 a2 := &TestAgent{Name: t.Name(), HCL: cfg, DataDir: dataDir} 1731 a2.Start(t) 1732 defer a2.Shutdown() 1733 1734 restored := a2.State.Proxy("redis-proxy") 1735 require.NotNil(restored) 1736 assert.Equal(gotProxy.ProxyToken, restored.ProxyToken) 1737 // Ensure the port that was auto picked at random is the same again 1738 assert.Equal(gotProxy.Proxy.ProxyService.Port, restored.Proxy.ProxyService.Port) 1739 assert.Equal(gotProxy.Proxy.Command, restored.Proxy.Command) 1740 } 1741 1742 func TestAgent_PurgeProxy(t *testing.T) { 1743 t.Parallel() 1744 a := NewTestAgent(t, t.Name(), "") 1745 defer a.Shutdown() 1746 1747 require := require.New(t) 1748 1749 // Add a service to proxy (precondition for AddProxy) 1750 svc1 := &structs.NodeService{ 1751 ID: "redis", 1752 Service: "redis", 1753 Tags: []string{"foo"}, 1754 Port: 8000, 1755 } 1756 require.NoError(a.AddService(svc1, nil, true, "", ConfigSourceLocal)) 1757 1758 // Add a proxy for it 1759 proxy := &structs.ConnectManagedProxy{ 1760 TargetServiceID: svc1.ID, 1761 Command: []string{"/bin/sleep", "3600"}, 1762 } 1763 proxyID := "redis-proxy" 1764 require.NoError(a.AddProxy(proxy, true, false, "", ConfigSourceLocal)) 1765 1766 file := filepath.Join(a.Config.DataDir, proxyDir, stringHash("redis-proxy")) 1767 1768 // Not removed 1769 require.NoError(a.RemoveProxy(proxyID, false)) 1770 _, err := os.Stat(file) 1771 require.NoError(err, "should not be removed") 1772 1773 // Re-add the proxy 1774 require.NoError(a.AddProxy(proxy, true, false, "", ConfigSourceLocal)) 1775 1776 // Removed 1777 require.NoError(a.RemoveProxy(proxyID, true)) 1778 _, err = os.Stat(file) 1779 require.Error(err, "should be removed") 1780 } 1781 1782 func TestAgent_PurgeProxyOnDuplicate(t *testing.T) { 1783 t.Parallel() 1784 dataDir := testutil.TempDir(t, "agent") // we manage the data dir 1785 cfg := ` 1786 data_dir = "` + dataDir + `" 1787 server = false 1788 bootstrap = false 1789 ` 1790 a := &TestAgent{Name: t.Name(), HCL: cfg, DataDir: dataDir} 1791 a.Start(t) 1792 defer a.Shutdown() 1793 defer os.RemoveAll(dataDir) 1794 1795 require := require.New(t) 1796 1797 // Add a service to proxy (precondition for AddProxy) 1798 svc1 := &structs.NodeService{ 1799 ID: "redis", 1800 Service: "redis", 1801 Tags: []string{"foo"}, 1802 Port: 8000, 1803 } 1804 require.NoError(a.AddService(svc1, nil, true, "", ConfigSourceLocal)) 1805 1806 // Add a proxy for it 1807 proxy := &structs.ConnectManagedProxy{ 1808 TargetServiceID: svc1.ID, 1809 Command: []string{"/bin/sleep", "3600"}, 1810 } 1811 proxyID := "redis-proxy" 1812 require.NoError(a.AddProxy(proxy, true, false, "", ConfigSourceLocal)) 1813 1814 a.Shutdown() 1815 1816 // Try bringing the agent back up with the service already 1817 // existing in the config 1818 a2 := &TestAgent{Name: t.Name() + "-a2", HCL: cfg + ` 1819 service = { 1820 id = "redis" 1821 name = "redis" 1822 tags = ["bar"] 1823 port = 9000 1824 connect { 1825 proxy { 1826 command = ["/bin/sleep", "3600"] 1827 } 1828 } 1829 } 1830 `, DataDir: dataDir} 1831 a2.Start(t) 1832 defer a2.Shutdown() 1833 1834 file := filepath.Join(a.Config.DataDir, proxyDir, stringHash(proxyID)) 1835 _, err := os.Stat(file) 1836 require.NoError(err, "Config File based proxies should be persisted too") 1837 1838 result := a2.State.Proxy(proxyID) 1839 require.NotNil(result) 1840 require.Equal(proxy.Command, result.Proxy.Command) 1841 } 1842 1843 func TestAgent_PersistCheck(t *testing.T) { 1844 t.Parallel() 1845 dataDir := testutil.TempDir(t, "agent") // we manage the data dir 1846 cfg := ` 1847 data_dir = "` + dataDir + `" 1848 server = false 1849 bootstrap = false 1850 enable_script_checks = true 1851 ` 1852 a := &TestAgent{Name: t.Name(), HCL: cfg, DataDir: dataDir} 1853 a.Start(t) 1854 defer os.RemoveAll(dataDir) 1855 defer a.Shutdown() 1856 1857 check := &structs.HealthCheck{ 1858 Node: a.config.NodeName, 1859 CheckID: "mem", 1860 Name: "memory check", 1861 Status: api.HealthPassing, 1862 } 1863 chkType := &structs.CheckType{ 1864 ScriptArgs: []string{"/bin/true"}, 1865 Interval: 10 * time.Second, 1866 } 1867 1868 file := filepath.Join(a.Config.DataDir, checksDir, checkIDHash(check.CheckID)) 1869 1870 // Not persisted if not requested 1871 if err := a.AddCheck(check, chkType, false, "", ConfigSourceLocal); err != nil { 1872 t.Fatalf("err: %v", err) 1873 } 1874 if _, err := os.Stat(file); err == nil { 1875 t.Fatalf("should not persist") 1876 } 1877 1878 // Should persist if requested 1879 if err := a.AddCheck(check, chkType, true, "mytoken", ConfigSourceLocal); err != nil { 1880 t.Fatalf("err: %v", err) 1881 } 1882 if _, err := os.Stat(file); err != nil { 1883 t.Fatalf("err: %s", err) 1884 } 1885 expected, err := json.Marshal(persistedCheck{ 1886 Check: check, 1887 ChkType: chkType, 1888 Token: "mytoken", 1889 }) 1890 if err != nil { 1891 t.Fatalf("err: %s", err) 1892 } 1893 content, err := ioutil.ReadFile(file) 1894 if err != nil { 1895 t.Fatalf("err: %s", err) 1896 } 1897 if !bytes.Equal(expected, content) { 1898 t.Fatalf("bad: %s != %s", string(content), expected) 1899 } 1900 1901 // Updates the check definition on disk 1902 check.Name = "mem1" 1903 if err := a.AddCheck(check, chkType, true, "mytoken", ConfigSourceLocal); err != nil { 1904 t.Fatalf("err: %v", err) 1905 } 1906 expected, err = json.Marshal(persistedCheck{ 1907 Check: check, 1908 ChkType: chkType, 1909 Token: "mytoken", 1910 }) 1911 if err != nil { 1912 t.Fatalf("err: %s", err) 1913 } 1914 content, err = ioutil.ReadFile(file) 1915 if err != nil { 1916 t.Fatalf("err: %s", err) 1917 } 1918 if !bytes.Equal(expected, content) { 1919 t.Fatalf("bad: %s", string(content)) 1920 } 1921 a.Shutdown() 1922 1923 // Should load it back during later start 1924 a2 := &TestAgent{Name: t.Name() + "-a2", HCL: cfg, DataDir: dataDir} 1925 a2.Start(t) 1926 defer a2.Shutdown() 1927 1928 result := a2.State.Check(check.CheckID) 1929 if result == nil { 1930 t.Fatalf("bad: %#v", a2.State.Checks()) 1931 } 1932 if result.Status != api.HealthCritical { 1933 t.Fatalf("bad: %#v", result) 1934 } 1935 if result.Name != "mem1" { 1936 t.Fatalf("bad: %#v", result) 1937 } 1938 1939 // Should have restored the monitor 1940 if _, ok := a2.checkMonitors[check.CheckID]; !ok { 1941 t.Fatalf("bad: %#v", a2.checkMonitors) 1942 } 1943 if a2.State.CheckState(check.CheckID).Token != "mytoken" { 1944 t.Fatalf("bad: %s", a2.State.CheckState(check.CheckID).Token) 1945 } 1946 } 1947 1948 func TestAgent_PurgeCheck(t *testing.T) { 1949 t.Parallel() 1950 a := NewTestAgent(t, t.Name(), "") 1951 defer a.Shutdown() 1952 1953 check := &structs.HealthCheck{ 1954 Node: a.Config.NodeName, 1955 CheckID: "mem", 1956 Name: "memory check", 1957 Status: api.HealthPassing, 1958 } 1959 1960 file := filepath.Join(a.Config.DataDir, checksDir, checkIDHash(check.CheckID)) 1961 if err := a.AddCheck(check, nil, true, "", ConfigSourceLocal); err != nil { 1962 t.Fatalf("err: %v", err) 1963 } 1964 1965 // Not removed 1966 if err := a.RemoveCheck(check.CheckID, false); err != nil { 1967 t.Fatalf("err: %s", err) 1968 } 1969 if _, err := os.Stat(file); err != nil { 1970 t.Fatalf("err: %s", err) 1971 } 1972 1973 // Removed 1974 if err := a.RemoveCheck(check.CheckID, true); err != nil { 1975 t.Fatalf("err: %s", err) 1976 } 1977 if _, err := os.Stat(file); !os.IsNotExist(err) { 1978 t.Fatalf("bad: %#v", err) 1979 } 1980 } 1981 1982 func TestAgent_PurgeCheckOnDuplicate(t *testing.T) { 1983 t.Parallel() 1984 nodeID := NodeID() 1985 dataDir := testutil.TempDir(t, "agent") 1986 a := NewTestAgent(t, t.Name(), ` 1987 node_id = "`+nodeID+`" 1988 node_name = "Node `+nodeID+`" 1989 data_dir = "`+dataDir+`" 1990 server = false 1991 bootstrap = false 1992 enable_script_checks = true 1993 `) 1994 defer os.RemoveAll(dataDir) 1995 defer a.Shutdown() 1996 1997 check1 := &structs.HealthCheck{ 1998 Node: a.Config.NodeName, 1999 CheckID: "mem", 2000 Name: "memory check", 2001 Status: api.HealthPassing, 2002 } 2003 2004 // First persist the check 2005 if err := a.AddCheck(check1, nil, true, "", ConfigSourceLocal); err != nil { 2006 t.Fatalf("err: %v", err) 2007 } 2008 a.Shutdown() 2009 2010 // Start again with the check registered in config 2011 a2 := NewTestAgent(t, t.Name()+"-a2", ` 2012 node_id = "`+nodeID+`" 2013 node_name = "Node `+nodeID+`" 2014 data_dir = "`+dataDir+`" 2015 server = false 2016 bootstrap = false 2017 enable_script_checks = true 2018 check = { 2019 id = "mem" 2020 name = "memory check" 2021 notes = "my cool notes" 2022 args = ["/bin/check-redis.py"] 2023 interval = "30s" 2024 } 2025 `) 2026 defer a2.Shutdown() 2027 2028 file := filepath.Join(dataDir, checksDir, checkIDHash(check1.CheckID)) 2029 if _, err := os.Stat(file); err == nil { 2030 t.Fatalf("should have removed persisted check") 2031 } 2032 result := a2.State.Check("mem") 2033 if result == nil { 2034 t.Fatalf("missing check registration") 2035 } 2036 expected := &structs.HealthCheck{ 2037 Node: a2.Config.NodeName, 2038 CheckID: "mem", 2039 Name: "memory check", 2040 Status: api.HealthCritical, 2041 Notes: "my cool notes", 2042 } 2043 if got, want := result, expected; !verify.Values(t, "", got, want) { 2044 t.FailNow() 2045 } 2046 } 2047 2048 func TestAgent_loadChecks_token(t *testing.T) { 2049 t.Parallel() 2050 a := NewTestAgent(t, t.Name(), ` 2051 check = { 2052 id = "rabbitmq" 2053 name = "rabbitmq" 2054 token = "abc123" 2055 ttl = "10s" 2056 } 2057 `) 2058 defer a.Shutdown() 2059 2060 checks := a.State.Checks() 2061 if _, ok := checks["rabbitmq"]; !ok { 2062 t.Fatalf("missing check") 2063 } 2064 if token := a.State.CheckToken("rabbitmq"); token != "abc123" { 2065 t.Fatalf("bad: %s", token) 2066 } 2067 } 2068 2069 func TestAgent_unloadChecks(t *testing.T) { 2070 t.Parallel() 2071 a := NewTestAgent(t, t.Name(), "") 2072 defer a.Shutdown() 2073 2074 // First register a service 2075 svc := &structs.NodeService{ 2076 ID: "redis", 2077 Service: "redis", 2078 Tags: []string{"foo"}, 2079 Port: 8000, 2080 } 2081 if err := a.AddService(svc, nil, false, "", ConfigSourceLocal); err != nil { 2082 t.Fatalf("err: %v", err) 2083 } 2084 2085 // Register a check 2086 check1 := &structs.HealthCheck{ 2087 Node: a.Config.NodeName, 2088 CheckID: "service:redis", 2089 Name: "redischeck", 2090 Status: api.HealthPassing, 2091 ServiceID: "redis", 2092 ServiceName: "redis", 2093 } 2094 if err := a.AddCheck(check1, nil, false, "", ConfigSourceLocal); err != nil { 2095 t.Fatalf("err: %s", err) 2096 } 2097 found := false 2098 for check := range a.State.Checks() { 2099 if check == check1.CheckID { 2100 found = true 2101 break 2102 } 2103 } 2104 if !found { 2105 t.Fatalf("check should have been registered") 2106 } 2107 2108 // Unload all of the checks 2109 if err := a.unloadChecks(); err != nil { 2110 t.Fatalf("err: %s", err) 2111 } 2112 2113 // Make sure it was unloaded 2114 for check := range a.State.Checks() { 2115 if check == check1.CheckID { 2116 t.Fatalf("should have unloaded checks") 2117 } 2118 } 2119 } 2120 2121 func TestAgent_loadServices_token(t *testing.T) { 2122 t.Parallel() 2123 a := NewTestAgent(t, t.Name(), ` 2124 service = { 2125 id = "rabbitmq" 2126 name = "rabbitmq" 2127 port = 5672 2128 token = "abc123" 2129 } 2130 `) 2131 defer a.Shutdown() 2132 2133 services := a.State.Services() 2134 if _, ok := services["rabbitmq"]; !ok { 2135 t.Fatalf("missing service") 2136 } 2137 if token := a.State.ServiceToken("rabbitmq"); token != "abc123" { 2138 t.Fatalf("bad: %s", token) 2139 } 2140 } 2141 2142 func TestAgent_loadServices_sidecar(t *testing.T) { 2143 t.Parallel() 2144 a := NewTestAgent(t, t.Name(), ` 2145 service = { 2146 id = "rabbitmq" 2147 name = "rabbitmq" 2148 port = 5672 2149 token = "abc123" 2150 connect = { 2151 sidecar_service {} 2152 } 2153 } 2154 `) 2155 defer a.Shutdown() 2156 2157 services := a.State.Services() 2158 if _, ok := services["rabbitmq"]; !ok { 2159 t.Fatalf("missing service") 2160 } 2161 if token := a.State.ServiceToken("rabbitmq"); token != "abc123" { 2162 t.Fatalf("bad: %s", token) 2163 } 2164 if _, ok := services["rabbitmq-sidecar-proxy"]; !ok { 2165 t.Fatalf("missing service") 2166 } 2167 if token := a.State.ServiceToken("rabbitmq-sidecar-proxy"); token != "abc123" { 2168 t.Fatalf("bad: %s", token) 2169 } 2170 2171 // Sanity check rabbitmq service should NOT have sidecar info in state since 2172 // it's done it's job and should be a registration syntax sugar only. 2173 assert.Nil(t, services["rabbitmq"].Connect.SidecarService) 2174 } 2175 2176 func TestAgent_loadServices_sidecarSeparateToken(t *testing.T) { 2177 t.Parallel() 2178 a := NewTestAgent(t, t.Name(), ` 2179 service = { 2180 id = "rabbitmq" 2181 name = "rabbitmq" 2182 port = 5672 2183 token = "abc123" 2184 connect = { 2185 sidecar_service { 2186 token = "789xyz" 2187 } 2188 } 2189 } 2190 `) 2191 defer a.Shutdown() 2192 2193 services := a.State.Services() 2194 if _, ok := services["rabbitmq"]; !ok { 2195 t.Fatalf("missing service") 2196 } 2197 if token := a.State.ServiceToken("rabbitmq"); token != "abc123" { 2198 t.Fatalf("bad: %s", token) 2199 } 2200 if _, ok := services["rabbitmq-sidecar-proxy"]; !ok { 2201 t.Fatalf("missing service") 2202 } 2203 if token := a.State.ServiceToken("rabbitmq-sidecar-proxy"); token != "789xyz" { 2204 t.Fatalf("bad: %s", token) 2205 } 2206 } 2207 2208 func TestAgent_loadServices_sidecarInheritMeta(t *testing.T) { 2209 t.Parallel() 2210 2211 a := NewTestAgent(t, t.Name(), ` 2212 service = { 2213 id = "rabbitmq" 2214 name = "rabbitmq" 2215 port = 5672 2216 tags = ["a", "b"], 2217 meta = { 2218 environment = "prod" 2219 } 2220 connect = { 2221 sidecar_service { 2222 2223 } 2224 } 2225 } 2226 `) 2227 defer a.Shutdown() 2228 2229 services := a.State.Services() 2230 2231 svc, ok := services["rabbitmq"] 2232 require.True(t, ok, "missing service") 2233 require.Len(t, svc.Tags, 2) 2234 require.Len(t, svc.Meta, 1) 2235 2236 sidecar, ok := services["rabbitmq-sidecar-proxy"] 2237 require.True(t, ok, "missing sidecar service") 2238 require.ElementsMatch(t, svc.Tags, sidecar.Tags) 2239 require.Len(t, sidecar.Meta, 1) 2240 meta, ok := sidecar.Meta["environment"] 2241 require.True(t, ok, "missing sidecar service meta") 2242 require.Equal(t, "prod", meta) 2243 } 2244 2245 func TestAgent_loadServices_sidecarOverrideMeta(t *testing.T) { 2246 t.Parallel() 2247 2248 a := NewTestAgent(t, t.Name(), ` 2249 service = { 2250 id = "rabbitmq" 2251 name = "rabbitmq" 2252 port = 5672 2253 tags = ["a", "b"], 2254 meta = { 2255 environment = "prod" 2256 } 2257 connect = { 2258 sidecar_service { 2259 tags = ["foo"], 2260 meta = { 2261 environment = "qa" 2262 } 2263 } 2264 } 2265 } 2266 `) 2267 defer a.Shutdown() 2268 2269 services := a.State.Services() 2270 2271 svc, ok := services["rabbitmq"] 2272 require.True(t, ok, "missing service") 2273 require.Len(t, svc.Tags, 2) 2274 require.Len(t, svc.Meta, 1) 2275 2276 sidecar, ok := services["rabbitmq-sidecar-proxy"] 2277 require.True(t, ok, "missing sidecar service") 2278 require.Len(t, sidecar.Tags, 1) 2279 require.Equal(t, "foo", sidecar.Tags[0]) 2280 require.Len(t, sidecar.Meta, 1) 2281 meta, ok := sidecar.Meta["environment"] 2282 require.True(t, ok, "missing sidecar service meta") 2283 require.Equal(t, "qa", meta) 2284 } 2285 2286 func TestAgent_unloadServices(t *testing.T) { 2287 t.Parallel() 2288 a := NewTestAgent(t, t.Name(), "") 2289 defer a.Shutdown() 2290 2291 svc := &structs.NodeService{ 2292 ID: "redis", 2293 Service: "redis", 2294 Tags: []string{"foo"}, 2295 Port: 8000, 2296 } 2297 2298 // Register the service 2299 if err := a.AddService(svc, nil, false, "", ConfigSourceLocal); err != nil { 2300 t.Fatalf("err: %v", err) 2301 } 2302 found := false 2303 for id := range a.State.Services() { 2304 if id == svc.ID { 2305 found = true 2306 break 2307 } 2308 } 2309 if !found { 2310 t.Fatalf("should have registered service") 2311 } 2312 2313 // Unload all services 2314 if err := a.unloadServices(); err != nil { 2315 t.Fatalf("err: %s", err) 2316 } 2317 if len(a.State.Services()) != 0 { 2318 t.Fatalf("should have unloaded services") 2319 } 2320 } 2321 2322 func TestAgent_loadProxies(t *testing.T) { 2323 t.Parallel() 2324 a := NewTestAgent(t, t.Name(), ` 2325 service = { 2326 id = "rabbitmq" 2327 name = "rabbitmq" 2328 port = 5672 2329 token = "abc123" 2330 connect { 2331 proxy { 2332 config { 2333 bind_port = 1234 2334 } 2335 } 2336 } 2337 } 2338 `) 2339 defer a.Shutdown() 2340 2341 services := a.State.Services() 2342 if _, ok := services["rabbitmq"]; !ok { 2343 t.Fatalf("missing service") 2344 } 2345 if token := a.State.ServiceToken("rabbitmq"); token != "abc123" { 2346 t.Fatalf("bad: %s", token) 2347 } 2348 if _, ok := services["rabbitmq-proxy"]; !ok { 2349 t.Fatalf("missing proxy service") 2350 } 2351 if token := a.State.ServiceToken("rabbitmq-proxy"); token != "abc123" { 2352 t.Fatalf("bad: %s", token) 2353 } 2354 proxies := a.State.Proxies() 2355 if _, ok := proxies["rabbitmq-proxy"]; !ok { 2356 t.Fatalf("missing proxy") 2357 } 2358 } 2359 2360 func TestAgent_loadProxies_nilProxy(t *testing.T) { 2361 t.Parallel() 2362 a := NewTestAgent(t, t.Name(), ` 2363 service = { 2364 id = "rabbitmq" 2365 name = "rabbitmq" 2366 port = 5672 2367 token = "abc123" 2368 connect { 2369 } 2370 } 2371 `) 2372 defer a.Shutdown() 2373 2374 services := a.State.Services() 2375 require.Contains(t, services, "rabbitmq") 2376 require.Equal(t, "abc123", a.State.ServiceToken("rabbitmq")) 2377 require.NotContains(t, services, "rabbitme-proxy") 2378 require.Empty(t, a.State.Proxies()) 2379 } 2380 2381 func TestAgent_unloadProxies(t *testing.T) { 2382 t.Parallel() 2383 a := NewTestAgent(t, t.Name(), ` 2384 service = { 2385 id = "rabbitmq" 2386 name = "rabbitmq" 2387 port = 5672 2388 token = "abc123" 2389 connect { 2390 proxy { 2391 config { 2392 bind_port = 1234 2393 } 2394 } 2395 } 2396 } 2397 `) 2398 defer a.Shutdown() 2399 2400 // Sanity check it's there 2401 require.NotNil(t, a.State.Proxy("rabbitmq-proxy")) 2402 2403 // Unload all proxies 2404 if err := a.unloadProxies(); err != nil { 2405 t.Fatalf("err: %s", err) 2406 } 2407 if len(a.State.Proxies()) != 0 { 2408 t.Fatalf("should have unloaded proxies") 2409 } 2410 } 2411 2412 func TestAgent_Service_MaintenanceMode(t *testing.T) { 2413 t.Parallel() 2414 a := NewTestAgent(t, t.Name(), "") 2415 defer a.Shutdown() 2416 2417 svc := &structs.NodeService{ 2418 ID: "redis", 2419 Service: "redis", 2420 Tags: []string{"foo"}, 2421 Port: 8000, 2422 } 2423 2424 // Register the service 2425 if err := a.AddService(svc, nil, false, "", ConfigSourceLocal); err != nil { 2426 t.Fatalf("err: %v", err) 2427 } 2428 2429 // Enter maintenance mode for the service 2430 if err := a.EnableServiceMaintenance("redis", "broken", "mytoken"); err != nil { 2431 t.Fatalf("err: %s", err) 2432 } 2433 2434 // Make sure the critical health check was added 2435 checkID := serviceMaintCheckID("redis") 2436 check, ok := a.State.Checks()[checkID] 2437 if !ok { 2438 t.Fatalf("should have registered critical maintenance check") 2439 } 2440 2441 // Check that the token was used to register the check 2442 if token := a.State.CheckToken(checkID); token != "mytoken" { 2443 t.Fatalf("expected 'mytoken', got: '%s'", token) 2444 } 2445 2446 // Ensure the reason was set in notes 2447 if check.Notes != "broken" { 2448 t.Fatalf("bad: %#v", check) 2449 } 2450 2451 // Leave maintenance mode 2452 if err := a.DisableServiceMaintenance("redis"); err != nil { 2453 t.Fatalf("err: %s", err) 2454 } 2455 2456 // Ensure the check was deregistered 2457 if _, ok := a.State.Checks()[checkID]; ok { 2458 t.Fatalf("should have deregistered maintenance check") 2459 } 2460 2461 // Enter service maintenance mode without providing a reason 2462 if err := a.EnableServiceMaintenance("redis", "", ""); err != nil { 2463 t.Fatalf("err: %s", err) 2464 } 2465 2466 // Ensure the check was registered with the default notes 2467 check, ok = a.State.Checks()[checkID] 2468 if !ok { 2469 t.Fatalf("should have registered critical check") 2470 } 2471 if check.Notes != defaultServiceMaintReason { 2472 t.Fatalf("bad: %#v", check) 2473 } 2474 } 2475 2476 func TestAgent_Service_Reap(t *testing.T) { 2477 // t.Parallel() // timing test. no parallel 2478 a := NewTestAgent(t, t.Name(), ` 2479 check_reap_interval = "50ms" 2480 check_deregister_interval_min = "0s" 2481 `) 2482 defer a.Shutdown() 2483 testrpc.WaitForTestAgent(t, a.RPC, "dc1") 2484 2485 svc := &structs.NodeService{ 2486 ID: "redis", 2487 Service: "redis", 2488 Tags: []string{"foo"}, 2489 Port: 8000, 2490 } 2491 chkTypes := []*structs.CheckType{ 2492 &structs.CheckType{ 2493 Status: api.HealthPassing, 2494 TTL: 25 * time.Millisecond, 2495 DeregisterCriticalServiceAfter: 200 * time.Millisecond, 2496 }, 2497 } 2498 2499 // Register the service. 2500 if err := a.AddService(svc, chkTypes, false, "", ConfigSourceLocal); err != nil { 2501 t.Fatalf("err: %v", err) 2502 } 2503 2504 // Make sure it's there and there's no critical check yet. 2505 if _, ok := a.State.Services()["redis"]; !ok { 2506 t.Fatalf("should have redis service") 2507 } 2508 if checks := a.State.CriticalCheckStates(); len(checks) > 0 { 2509 t.Fatalf("should not have critical checks") 2510 } 2511 2512 // Wait for the check TTL to fail but before the check is reaped. 2513 time.Sleep(100 * time.Millisecond) 2514 if _, ok := a.State.Services()["redis"]; !ok { 2515 t.Fatalf("should have redis service") 2516 } 2517 if checks := a.State.CriticalCheckStates(); len(checks) != 1 { 2518 t.Fatalf("should have a critical check") 2519 } 2520 2521 // Pass the TTL. 2522 if err := a.updateTTLCheck("service:redis", api.HealthPassing, "foo"); err != nil { 2523 t.Fatalf("err: %v", err) 2524 } 2525 if _, ok := a.State.Services()["redis"]; !ok { 2526 t.Fatalf("should have redis service") 2527 } 2528 if checks := a.State.CriticalCheckStates(); len(checks) > 0 { 2529 t.Fatalf("should not have critical checks") 2530 } 2531 2532 // Wait for the check TTL to fail again. 2533 time.Sleep(100 * time.Millisecond) 2534 if _, ok := a.State.Services()["redis"]; !ok { 2535 t.Fatalf("should have redis service") 2536 } 2537 if checks := a.State.CriticalCheckStates(); len(checks) != 1 { 2538 t.Fatalf("should have a critical check") 2539 } 2540 2541 // Wait for the reap. 2542 time.Sleep(400 * time.Millisecond) 2543 if _, ok := a.State.Services()["redis"]; ok { 2544 t.Fatalf("redis service should have been reaped") 2545 } 2546 if checks := a.State.CriticalCheckStates(); len(checks) > 0 { 2547 t.Fatalf("should not have critical checks") 2548 } 2549 } 2550 2551 func TestAgent_Service_NoReap(t *testing.T) { 2552 // t.Parallel() // timing test. no parallel 2553 a := NewTestAgent(t, t.Name(), ` 2554 check_reap_interval = "50ms" 2555 check_deregister_interval_min = "0s" 2556 `) 2557 defer a.Shutdown() 2558 2559 svc := &structs.NodeService{ 2560 ID: "redis", 2561 Service: "redis", 2562 Tags: []string{"foo"}, 2563 Port: 8000, 2564 } 2565 chkTypes := []*structs.CheckType{ 2566 &structs.CheckType{ 2567 Status: api.HealthPassing, 2568 TTL: 25 * time.Millisecond, 2569 }, 2570 } 2571 2572 // Register the service. 2573 if err := a.AddService(svc, chkTypes, false, "", ConfigSourceLocal); err != nil { 2574 t.Fatalf("err: %v", err) 2575 } 2576 2577 // Make sure it's there and there's no critical check yet. 2578 if _, ok := a.State.Services()["redis"]; !ok { 2579 t.Fatalf("should have redis service") 2580 } 2581 if checks := a.State.CriticalCheckStates(); len(checks) > 0 { 2582 t.Fatalf("should not have critical checks") 2583 } 2584 2585 // Wait for the check TTL to fail. 2586 time.Sleep(200 * time.Millisecond) 2587 if _, ok := a.State.Services()["redis"]; !ok { 2588 t.Fatalf("should have redis service") 2589 } 2590 if checks := a.State.CriticalCheckStates(); len(checks) != 1 { 2591 t.Fatalf("should have a critical check") 2592 } 2593 2594 // Wait a while and make sure it doesn't reap. 2595 time.Sleep(200 * time.Millisecond) 2596 if _, ok := a.State.Services()["redis"]; !ok { 2597 t.Fatalf("should have redis service") 2598 } 2599 if checks := a.State.CriticalCheckStates(); len(checks) != 1 { 2600 t.Fatalf("should have a critical check") 2601 } 2602 } 2603 2604 func TestAgent_AddService_restoresSnapshot(t *testing.T) { 2605 t.Parallel() 2606 a := NewTestAgent(t, t.Name(), "") 2607 defer a.Shutdown() 2608 2609 // First register a service 2610 svc := &structs.NodeService{ 2611 ID: "redis", 2612 Service: "redis", 2613 Tags: []string{"foo"}, 2614 Port: 8000, 2615 } 2616 if err := a.AddService(svc, nil, false, "", ConfigSourceLocal); err != nil { 2617 t.Fatalf("err: %v", err) 2618 } 2619 2620 // Register a check 2621 check1 := &structs.HealthCheck{ 2622 Node: a.Config.NodeName, 2623 CheckID: "service:redis", 2624 Name: "redischeck", 2625 Status: api.HealthPassing, 2626 ServiceID: "redis", 2627 ServiceName: "redis", 2628 } 2629 if err := a.AddCheck(check1, nil, false, "", ConfigSourceLocal); err != nil { 2630 t.Fatalf("err: %s", err) 2631 } 2632 2633 // Re-registering the service preserves the state of the check 2634 chkTypes := []*structs.CheckType{&structs.CheckType{TTL: 30 * time.Second}} 2635 if err := a.AddService(svc, chkTypes, false, "", ConfigSourceLocal); err != nil { 2636 t.Fatalf("err: %s", err) 2637 } 2638 check, ok := a.State.Checks()["service:redis"] 2639 if !ok { 2640 t.Fatalf("missing check") 2641 } 2642 if check.Status != api.HealthPassing { 2643 t.Fatalf("bad: %s", check.Status) 2644 } 2645 } 2646 2647 func TestAgent_AddCheck_restoresSnapshot(t *testing.T) { 2648 t.Parallel() 2649 a := NewTestAgent(t, t.Name(), "") 2650 defer a.Shutdown() 2651 2652 // First register a service 2653 svc := &structs.NodeService{ 2654 ID: "redis", 2655 Service: "redis", 2656 Tags: []string{"foo"}, 2657 Port: 8000, 2658 } 2659 if err := a.AddService(svc, nil, false, "", ConfigSourceLocal); err != nil { 2660 t.Fatalf("err: %v", err) 2661 } 2662 2663 // Register a check 2664 check1 := &structs.HealthCheck{ 2665 Node: a.Config.NodeName, 2666 CheckID: "service:redis", 2667 Name: "redischeck", 2668 Status: api.HealthPassing, 2669 ServiceID: "redis", 2670 ServiceName: "redis", 2671 } 2672 if err := a.AddCheck(check1, nil, false, "", ConfigSourceLocal); err != nil { 2673 t.Fatalf("err: %s", err) 2674 } 2675 2676 // Re-registering the check preserves its state 2677 check1.Status = "" 2678 if err := a.AddCheck(check1, &structs.CheckType{TTL: 30 * time.Second}, false, "", ConfigSourceLocal); err != nil { 2679 t.Fatalf("err: %s", err) 2680 } 2681 check, ok := a.State.Checks()["service:redis"] 2682 if !ok { 2683 t.Fatalf("missing check") 2684 } 2685 if check.Status != api.HealthPassing { 2686 t.Fatalf("bad: %s", check.Status) 2687 } 2688 } 2689 2690 func TestAgent_NodeMaintenanceMode(t *testing.T) { 2691 t.Parallel() 2692 a := NewTestAgent(t, t.Name(), "") 2693 defer a.Shutdown() 2694 2695 // Enter maintenance mode for the node 2696 a.EnableNodeMaintenance("broken", "mytoken") 2697 2698 // Make sure the critical health check was added 2699 check, ok := a.State.Checks()[structs.NodeMaint] 2700 if !ok { 2701 t.Fatalf("should have registered critical node check") 2702 } 2703 2704 // Check that the token was used to register the check 2705 if token := a.State.CheckToken(structs.NodeMaint); token != "mytoken" { 2706 t.Fatalf("expected 'mytoken', got: '%s'", token) 2707 } 2708 2709 // Ensure the reason was set in notes 2710 if check.Notes != "broken" { 2711 t.Fatalf("bad: %#v", check) 2712 } 2713 2714 // Leave maintenance mode 2715 a.DisableNodeMaintenance() 2716 2717 // Ensure the check was deregistered 2718 if _, ok := a.State.Checks()[structs.NodeMaint]; ok { 2719 t.Fatalf("should have deregistered critical node check") 2720 } 2721 2722 // Enter maintenance mode without passing a reason 2723 a.EnableNodeMaintenance("", "") 2724 2725 // Make sure the check was registered with the default note 2726 check, ok = a.State.Checks()[structs.NodeMaint] 2727 if !ok { 2728 t.Fatalf("should have registered critical node check") 2729 } 2730 if check.Notes != defaultNodeMaintReason { 2731 t.Fatalf("bad: %#v", check) 2732 } 2733 } 2734 2735 func TestAgent_checkStateSnapshot(t *testing.T) { 2736 t.Parallel() 2737 a := NewTestAgent(t, t.Name(), "") 2738 defer a.Shutdown() 2739 2740 // First register a service 2741 svc := &structs.NodeService{ 2742 ID: "redis", 2743 Service: "redis", 2744 Tags: []string{"foo"}, 2745 Port: 8000, 2746 } 2747 if err := a.AddService(svc, nil, false, "", ConfigSourceLocal); err != nil { 2748 t.Fatalf("err: %v", err) 2749 } 2750 2751 // Register a check 2752 check1 := &structs.HealthCheck{ 2753 Node: a.Config.NodeName, 2754 CheckID: "service:redis", 2755 Name: "redischeck", 2756 Status: api.HealthPassing, 2757 ServiceID: "redis", 2758 ServiceName: "redis", 2759 } 2760 if err := a.AddCheck(check1, nil, true, "", ConfigSourceLocal); err != nil { 2761 t.Fatalf("err: %s", err) 2762 } 2763 2764 // Snapshot the state 2765 snap := a.snapshotCheckState() 2766 2767 // Unload all of the checks 2768 if err := a.unloadChecks(); err != nil { 2769 t.Fatalf("err: %s", err) 2770 } 2771 2772 // Reload the checks 2773 if err := a.loadChecks(a.Config); err != nil { 2774 t.Fatalf("err: %s", err) 2775 } 2776 2777 // Restore the state 2778 a.restoreCheckState(snap) 2779 2780 // Search for the check 2781 out, ok := a.State.Checks()[check1.CheckID] 2782 if !ok { 2783 t.Fatalf("check should have been registered") 2784 } 2785 2786 // Make sure state was restored 2787 if out.Status != api.HealthPassing { 2788 t.Fatalf("should have restored check state") 2789 } 2790 } 2791 2792 func TestAgent_loadChecks_checkFails(t *testing.T) { 2793 t.Parallel() 2794 a := NewTestAgent(t, t.Name(), "") 2795 defer a.Shutdown() 2796 2797 // Persist a health check with an invalid service ID 2798 check := &structs.HealthCheck{ 2799 Node: a.Config.NodeName, 2800 CheckID: "service:redis", 2801 Name: "redischeck", 2802 Status: api.HealthPassing, 2803 ServiceID: "nope", 2804 } 2805 if err := a.persistCheck(check, nil); err != nil { 2806 t.Fatalf("err: %s", err) 2807 } 2808 2809 // Check to make sure the check was persisted 2810 checkHash := checkIDHash(check.CheckID) 2811 checkPath := filepath.Join(a.Config.DataDir, checksDir, checkHash) 2812 if _, err := os.Stat(checkPath); err != nil { 2813 t.Fatalf("err: %s", err) 2814 } 2815 2816 // Try loading the checks from the persisted files 2817 if err := a.loadChecks(a.Config); err != nil { 2818 t.Fatalf("err: %s", err) 2819 } 2820 2821 // Ensure the erroneous check was purged 2822 if _, err := os.Stat(checkPath); err == nil { 2823 t.Fatalf("should have purged check") 2824 } 2825 } 2826 2827 func TestAgent_persistCheckState(t *testing.T) { 2828 t.Parallel() 2829 a := NewTestAgent(t, t.Name(), "") 2830 defer a.Shutdown() 2831 2832 // Create the TTL check to persist 2833 check := &checks.CheckTTL{ 2834 CheckID: "check1", 2835 TTL: 10 * time.Minute, 2836 } 2837 2838 // Persist some check state for the check 2839 err := a.persistCheckState(check, api.HealthCritical, "nope") 2840 if err != nil { 2841 t.Fatalf("err: %s", err) 2842 } 2843 2844 // Check the persisted file exists and has the content 2845 file := filepath.Join(a.Config.DataDir, checkStateDir, stringHash("check1")) 2846 buf, err := ioutil.ReadFile(file) 2847 if err != nil { 2848 t.Fatalf("err: %s", err) 2849 } 2850 2851 // Decode the state 2852 var p persistedCheckState 2853 if err := json.Unmarshal(buf, &p); err != nil { 2854 t.Fatalf("err: %s", err) 2855 } 2856 2857 // Check the fields 2858 if p.CheckID != "check1" { 2859 t.Fatalf("bad: %#v", p) 2860 } 2861 if p.Output != "nope" { 2862 t.Fatalf("bad: %#v", p) 2863 } 2864 if p.Status != api.HealthCritical { 2865 t.Fatalf("bad: %#v", p) 2866 } 2867 2868 // Check the expiration time was set 2869 if p.Expires < time.Now().Unix() { 2870 t.Fatalf("bad: %#v", p) 2871 } 2872 } 2873 2874 func TestAgent_loadCheckState(t *testing.T) { 2875 t.Parallel() 2876 a := NewTestAgent(t, t.Name(), "") 2877 defer a.Shutdown() 2878 2879 // Create a check whose state will expire immediately 2880 check := &checks.CheckTTL{ 2881 CheckID: "check1", 2882 TTL: 0, 2883 } 2884 2885 // Persist the check state 2886 err := a.persistCheckState(check, api.HealthPassing, "yup") 2887 if err != nil { 2888 t.Fatalf("err: %s", err) 2889 } 2890 2891 // Try to load the state 2892 health := &structs.HealthCheck{ 2893 CheckID: "check1", 2894 Status: api.HealthCritical, 2895 } 2896 if err := a.loadCheckState(health); err != nil { 2897 t.Fatalf("err: %s", err) 2898 } 2899 2900 // Should not have restored the status due to expiration 2901 if health.Status != api.HealthCritical { 2902 t.Fatalf("bad: %#v", health) 2903 } 2904 if health.Output != "" { 2905 t.Fatalf("bad: %#v", health) 2906 } 2907 2908 // Should have purged the state 2909 file := filepath.Join(a.Config.DataDir, checksDir, stringHash("check1")) 2910 if _, err := os.Stat(file); !os.IsNotExist(err) { 2911 t.Fatalf("should have purged state") 2912 } 2913 2914 // Set a TTL which will not expire before we check it 2915 check.TTL = time.Minute 2916 err = a.persistCheckState(check, api.HealthPassing, "yup") 2917 if err != nil { 2918 t.Fatalf("err: %s", err) 2919 } 2920 2921 // Try to load 2922 if err := a.loadCheckState(health); err != nil { 2923 t.Fatalf("err: %s", err) 2924 } 2925 2926 // Should have restored 2927 if health.Status != api.HealthPassing { 2928 t.Fatalf("bad: %#v", health) 2929 } 2930 if health.Output != "yup" { 2931 t.Fatalf("bad: %#v", health) 2932 } 2933 } 2934 2935 func TestAgent_purgeCheckState(t *testing.T) { 2936 t.Parallel() 2937 a := NewTestAgent(t, t.Name(), "") 2938 defer a.Shutdown() 2939 2940 // No error if the state does not exist 2941 if err := a.purgeCheckState("check1"); err != nil { 2942 t.Fatalf("err: %s", err) 2943 } 2944 2945 // Persist some state to the data dir 2946 check := &checks.CheckTTL{ 2947 CheckID: "check1", 2948 TTL: time.Minute, 2949 } 2950 err := a.persistCheckState(check, api.HealthPassing, "yup") 2951 if err != nil { 2952 t.Fatalf("err: %s", err) 2953 } 2954 2955 // Purge the check state 2956 if err := a.purgeCheckState("check1"); err != nil { 2957 t.Fatalf("err: %s", err) 2958 } 2959 2960 // Removed the file 2961 file := filepath.Join(a.Config.DataDir, checkStateDir, stringHash("check1")) 2962 if _, err := os.Stat(file); !os.IsNotExist(err) { 2963 t.Fatalf("should have removed file") 2964 } 2965 } 2966 2967 func TestAgent_GetCoordinate(t *testing.T) { 2968 t.Parallel() 2969 check := func(server bool) { 2970 a := NewTestAgent(t, t.Name(), ` 2971 server = true 2972 `) 2973 defer a.Shutdown() 2974 2975 // This doesn't verify the returned coordinate, but it makes 2976 // sure that the agent chooses the correct Serf instance, 2977 // depending on how it's configured as a client or a server. 2978 // If it chooses the wrong one, this will crash. 2979 if _, err := a.GetLANCoordinate(); err != nil { 2980 t.Fatalf("err: %s", err) 2981 } 2982 } 2983 2984 check(true) 2985 check(false) 2986 } 2987 2988 func TestAgent_reloadWatches(t *testing.T) { 2989 t.Parallel() 2990 a := NewTestAgent(t, t.Name(), "") 2991 defer a.Shutdown() 2992 2993 // Normal watch with http addr set, should succeed 2994 newConf := *a.config 2995 newConf.Watches = []map[string]interface{}{ 2996 { 2997 "type": "key", 2998 "key": "asdf", 2999 "args": []interface{}{"ls"}, 3000 }, 3001 } 3002 if err := a.reloadWatches(&newConf); err != nil { 3003 t.Fatalf("bad: %s", err) 3004 } 3005 3006 // Should fail to reload with connect watches 3007 newConf.Watches = []map[string]interface{}{ 3008 { 3009 "type": "connect_roots", 3010 "key": "asdf", 3011 "args": []interface{}{"ls"}, 3012 }, 3013 } 3014 if err := a.reloadWatches(&newConf); err == nil || !strings.Contains(err.Error(), "not allowed in agent config") { 3015 t.Fatalf("bad: %s", err) 3016 } 3017 3018 // Should still succeed with only HTTPS addresses 3019 newConf.HTTPSAddrs = newConf.HTTPAddrs 3020 newConf.HTTPAddrs = make([]net.Addr, 0) 3021 newConf.Watches = []map[string]interface{}{ 3022 { 3023 "type": "key", 3024 "key": "asdf", 3025 "args": []interface{}{"ls"}, 3026 }, 3027 } 3028 if err := a.reloadWatches(&newConf); err != nil { 3029 t.Fatalf("bad: %s", err) 3030 } 3031 3032 // Should fail to reload with no http or https addrs 3033 newConf.HTTPSAddrs = make([]net.Addr, 0) 3034 newConf.Watches = []map[string]interface{}{ 3035 { 3036 "type": "key", 3037 "key": "asdf", 3038 "args": []interface{}{"ls"}, 3039 }, 3040 } 3041 if err := a.reloadWatches(&newConf); err == nil || !strings.Contains(err.Error(), "watch plans require an HTTP or HTTPS endpoint") { 3042 t.Fatalf("bad: %s", err) 3043 } 3044 } 3045 3046 func TestAgent_reloadWatchesHTTPS(t *testing.T) { 3047 t.Parallel() 3048 a := TestAgent{Name: t.Name(), UseTLS: true} 3049 a.Start(t) 3050 defer a.Shutdown() 3051 3052 // Normal watch with http addr set, should succeed 3053 newConf := *a.config 3054 newConf.Watches = []map[string]interface{}{ 3055 { 3056 "type": "key", 3057 "key": "asdf", 3058 "args": []interface{}{"ls"}, 3059 }, 3060 } 3061 if err := a.reloadWatches(&newConf); err != nil { 3062 t.Fatalf("bad: %s", err) 3063 } 3064 } 3065 3066 func TestAgent_AddProxy(t *testing.T) { 3067 t.Parallel() 3068 3069 tests := []struct { 3070 desc string 3071 proxy, wantProxy *structs.ConnectManagedProxy 3072 wantTCPCheck string 3073 wantErr bool 3074 }{ 3075 { 3076 desc: "basic proxy adding, unregistered service", 3077 proxy: &structs.ConnectManagedProxy{ 3078 ExecMode: structs.ProxyExecModeDaemon, 3079 Command: []string{"consul", "connect", "proxy"}, 3080 Config: map[string]interface{}{ 3081 "foo": "bar", 3082 }, 3083 TargetServiceID: "db", // non-existent service. 3084 }, 3085 // Target service must be registered. 3086 wantErr: true, 3087 }, 3088 { 3089 desc: "basic proxy adding, registered service", 3090 proxy: &structs.ConnectManagedProxy{ 3091 ExecMode: structs.ProxyExecModeDaemon, 3092 Command: []string{"consul", "connect", "proxy"}, 3093 Config: map[string]interface{}{ 3094 "foo": "bar", 3095 }, 3096 TargetServiceID: "web", 3097 }, 3098 // Proxy will inherit agent's 0.0.0.0 bind address but we can't check that 3099 // so we should default to localhost in that case. 3100 wantTCPCheck: "127.0.0.1:20000", 3101 wantErr: false, 3102 }, 3103 { 3104 desc: "default global exec mode", 3105 proxy: &structs.ConnectManagedProxy{ 3106 Command: []string{"consul", "connect", "proxy"}, 3107 TargetServiceID: "web", 3108 }, 3109 wantProxy: &structs.ConnectManagedProxy{ 3110 ExecMode: structs.ProxyExecModeScript, 3111 Command: []string{"consul", "connect", "proxy"}, 3112 TargetServiceID: "web", 3113 }, 3114 wantTCPCheck: "127.0.0.1:20000", 3115 wantErr: false, 3116 }, 3117 { 3118 desc: "default daemon command", 3119 proxy: &structs.ConnectManagedProxy{ 3120 ExecMode: structs.ProxyExecModeDaemon, 3121 TargetServiceID: "web", 3122 }, 3123 wantProxy: &structs.ConnectManagedProxy{ 3124 ExecMode: structs.ProxyExecModeDaemon, 3125 Command: []string{"foo", "bar"}, 3126 TargetServiceID: "web", 3127 }, 3128 wantTCPCheck: "127.0.0.1:20000", 3129 wantErr: false, 3130 }, 3131 { 3132 desc: "default script command", 3133 proxy: &structs.ConnectManagedProxy{ 3134 ExecMode: structs.ProxyExecModeScript, 3135 TargetServiceID: "web", 3136 }, 3137 wantProxy: &structs.ConnectManagedProxy{ 3138 ExecMode: structs.ProxyExecModeScript, 3139 Command: []string{"bar", "foo"}, 3140 TargetServiceID: "web", 3141 }, 3142 wantTCPCheck: "127.0.0.1:20000", 3143 wantErr: false, 3144 }, 3145 { 3146 desc: "managed proxy with custom bind port", 3147 proxy: &structs.ConnectManagedProxy{ 3148 ExecMode: structs.ProxyExecModeDaemon, 3149 Command: []string{"consul", "connect", "proxy"}, 3150 Config: map[string]interface{}{ 3151 "foo": "bar", 3152 "bind_address": "127.10.10.10", 3153 "bind_port": 1234, 3154 }, 3155 TargetServiceID: "web", 3156 }, 3157 wantTCPCheck: "127.10.10.10:1234", 3158 wantErr: false, 3159 }, 3160 { 3161 // This test is necessary since JSON and HCL both will parse 3162 // numbers as a float64. 3163 desc: "managed proxy with custom bind port (float64)", 3164 proxy: &structs.ConnectManagedProxy{ 3165 ExecMode: structs.ProxyExecModeDaemon, 3166 Command: []string{"consul", "connect", "proxy"}, 3167 Config: map[string]interface{}{ 3168 "foo": "bar", 3169 "bind_address": "127.10.10.10", 3170 "bind_port": float64(1234), 3171 }, 3172 TargetServiceID: "web", 3173 }, 3174 wantTCPCheck: "127.10.10.10:1234", 3175 wantErr: false, 3176 }, 3177 { 3178 desc: "managed proxy with overridden but unspecified ipv6 bind address", 3179 proxy: &structs.ConnectManagedProxy{ 3180 ExecMode: structs.ProxyExecModeDaemon, 3181 Command: []string{"consul", "connect", "proxy"}, 3182 Config: map[string]interface{}{ 3183 "foo": "bar", 3184 "bind_address": "[::]", 3185 }, 3186 TargetServiceID: "web", 3187 }, 3188 wantTCPCheck: "127.0.0.1:20000", 3189 wantErr: false, 3190 }, 3191 { 3192 desc: "managed proxy with overridden check address", 3193 proxy: &structs.ConnectManagedProxy{ 3194 ExecMode: structs.ProxyExecModeDaemon, 3195 Command: []string{"consul", "connect", "proxy"}, 3196 Config: map[string]interface{}{ 3197 "foo": "bar", 3198 "tcp_check_address": "127.20.20.20", 3199 }, 3200 TargetServiceID: "web", 3201 }, 3202 wantTCPCheck: "127.20.20.20:20000", 3203 wantErr: false, 3204 }, 3205 { 3206 desc: "managed proxy with disabled check", 3207 proxy: &structs.ConnectManagedProxy{ 3208 ExecMode: structs.ProxyExecModeDaemon, 3209 Command: []string{"consul", "connect", "proxy"}, 3210 Config: map[string]interface{}{ 3211 "foo": "bar", 3212 "disable_tcp_check": true, 3213 }, 3214 TargetServiceID: "web", 3215 }, 3216 wantTCPCheck: "", 3217 wantErr: false, 3218 }, 3219 } 3220 3221 for _, tt := range tests { 3222 t.Run(tt.desc, func(t *testing.T) { 3223 require := require.New(t) 3224 3225 a := NewTestAgent(t, t.Name(), ` 3226 node_name = "node1" 3227 3228 # Explicit test because proxies inheriting this value must have a health 3229 # check on a different IP. 3230 bind_addr = "0.0.0.0" 3231 3232 connect { 3233 proxy_defaults { 3234 exec_mode = "script" 3235 daemon_command = ["foo", "bar"] 3236 script_command = ["bar", "foo"] 3237 } 3238 } 3239 3240 ports { 3241 proxy_min_port = 20000 3242 proxy_max_port = 20000 3243 } 3244 `) 3245 defer a.Shutdown() 3246 3247 // Register a target service we can use 3248 reg := &structs.NodeService{ 3249 Service: "web", 3250 Port: 8080, 3251 } 3252 require.NoError(a.AddService(reg, nil, false, "", ConfigSourceLocal)) 3253 3254 err := a.AddProxy(tt.proxy, false, false, "", ConfigSourceLocal) 3255 if tt.wantErr { 3256 require.Error(err) 3257 return 3258 } 3259 require.NoError(err) 3260 3261 // Test the ID was created as we expect. 3262 got := a.State.Proxy("web-proxy") 3263 wantProxy := tt.wantProxy 3264 if wantProxy == nil { 3265 wantProxy = tt.proxy 3266 } 3267 wantProxy.ProxyService = got.Proxy.ProxyService 3268 require.Equal(wantProxy, got.Proxy) 3269 3270 // Ensure a TCP check was created for the service. 3271 gotCheck := a.State.Check("service:web-proxy") 3272 if tt.wantTCPCheck == "" { 3273 require.Nil(gotCheck) 3274 } else { 3275 require.NotNil(gotCheck) 3276 require.Equal("Connect Proxy Listening", gotCheck.Name) 3277 3278 // Confusingly, a.State.Check("service:web-proxy") will return the state 3279 // but it's Definition field will be empty. This appears to be expected 3280 // when adding Checks as part of `AddService`. Notice how `AddService` 3281 // tests in this file don't assert on that state but instead look at the 3282 // agent's check state directly to ensure the right thing was registered. 3283 // We'll do the same for now. 3284 gotTCP, ok := a.checkTCPs["service:web-proxy"] 3285 require.True(ok) 3286 require.Equal(tt.wantTCPCheck, gotTCP.TCP) 3287 require.Equal(10*time.Second, gotTCP.Interval) 3288 } 3289 }) 3290 } 3291 } 3292 3293 func TestAgent_RemoveProxy(t *testing.T) { 3294 t.Parallel() 3295 a := NewTestAgent(t, t.Name(), ` 3296 node_name = "node1" 3297 `) 3298 defer a.Shutdown() 3299 require := require.New(t) 3300 3301 // Register a target service we can use 3302 reg := &structs.NodeService{ 3303 Service: "web", 3304 Port: 8080, 3305 } 3306 require.NoError(a.AddService(reg, nil, false, "", ConfigSourceLocal)) 3307 3308 // Add a proxy for web 3309 pReg := &structs.ConnectManagedProxy{ 3310 TargetServiceID: "web", 3311 ExecMode: structs.ProxyExecModeDaemon, 3312 Command: []string{"foo"}, 3313 } 3314 require.NoError(a.AddProxy(pReg, false, false, "", ConfigSourceLocal)) 3315 3316 // Test the ID was created as we expect. 3317 gotProxy := a.State.Proxy("web-proxy") 3318 require.NotNil(gotProxy) 3319 3320 err := a.RemoveProxy("web-proxy", false) 3321 require.NoError(err) 3322 3323 gotProxy = a.State.Proxy("web-proxy") 3324 require.Nil(gotProxy) 3325 require.Nil(a.State.Service("web-proxy"), "web-proxy service") 3326 3327 // Removing invalid proxy should be an error 3328 err = a.RemoveProxy("foobar", false) 3329 require.Error(err) 3330 } 3331 3332 func TestAgent_ReLoadProxiesFromConfig(t *testing.T) { 3333 t.Parallel() 3334 a := NewTestAgent(t, t.Name(), 3335 `node_name = "node1" 3336 `) 3337 defer a.Shutdown() 3338 require := require.New(t) 3339 3340 // Register a target service we can use 3341 reg := &structs.NodeService{ 3342 Service: "web", 3343 Port: 8080, 3344 } 3345 require.NoError(a.AddService(reg, nil, false, "", ConfigSourceLocal)) 3346 3347 proxies := a.State.Proxies() 3348 require.Len(proxies, 0) 3349 3350 config := config.RuntimeConfig{ 3351 Services: []*structs.ServiceDefinition{ 3352 &structs.ServiceDefinition{ 3353 Name: "web", 3354 Connect: &structs.ServiceConnect{ 3355 Native: false, 3356 Proxy: &structs.ServiceDefinitionConnectProxy{}, 3357 }, 3358 }, 3359 }, 3360 } 3361 3362 require.NoError(a.loadProxies(&config)) 3363 3364 // ensure we loaded the proxy 3365 proxies = a.State.Proxies() 3366 require.Len(proxies, 1) 3367 3368 // store the auto-generated token 3369 ptok := "" 3370 pid := "" 3371 for id := range proxies { 3372 pid = id 3373 ptok = proxies[id].ProxyToken 3374 break 3375 } 3376 3377 // reload the proxies and ensure the proxy token is the same 3378 require.NoError(a.unloadProxies()) 3379 proxies = a.State.Proxies() 3380 require.Len(proxies, 0) 3381 require.NoError(a.loadProxies(&config)) 3382 proxies = a.State.Proxies() 3383 require.Len(proxies, 1) 3384 require.Equal(ptok, proxies[pid].ProxyToken) 3385 3386 // make sure when the config goes away so does the proxy 3387 require.NoError(a.unloadProxies()) 3388 proxies = a.State.Proxies() 3389 require.Len(proxies, 0) 3390 3391 // a.config contains no services or proxies 3392 require.NoError(a.loadProxies(a.config)) 3393 proxies = a.State.Proxies() 3394 require.Len(proxies, 0) 3395 } 3396 3397 func TestAgent_SetupProxyManager(t *testing.T) { 3398 t.Parallel() 3399 dataDir := testutil.TempDir(t, "agent") // we manage the data dir 3400 defer os.RemoveAll(dataDir) 3401 hcl := ` 3402 ports { http = -1 } 3403 data_dir = "` + dataDir + `" 3404 ` 3405 a, err := NewUnstartedAgent(t, t.Name(), hcl) 3406 require.NoError(t, err) 3407 require.Error(t, a.setupProxyManager(), "setupProxyManager should fail with invalid HTTP API config") 3408 3409 hcl = ` 3410 ports { http = 8001 } 3411 data_dir = "` + dataDir + `" 3412 ` 3413 a, err = NewUnstartedAgent(t, t.Name(), hcl) 3414 require.NoError(t, err) 3415 require.NoError(t, a.setupProxyManager()) 3416 } 3417 3418 func TestAgent_loadTokens(t *testing.T) { 3419 t.Parallel() 3420 a := NewTestAgent(t, t.Name(), ` 3421 acl = { 3422 enabled = true 3423 tokens = { 3424 agent = "alfa" 3425 agent_master = "bravo", 3426 default = "charlie" 3427 replication = "delta" 3428 } 3429 } 3430 3431 `) 3432 defer a.Shutdown() 3433 require := require.New(t) 3434 3435 tokensFullPath := filepath.Join(a.config.DataDir, tokensPath) 3436 3437 t.Run("original-configuration", func(t *testing.T) { 3438 require.Equal("alfa", a.tokens.AgentToken()) 3439 require.Equal("bravo", a.tokens.AgentMasterToken()) 3440 require.Equal("charlie", a.tokens.UserToken()) 3441 require.Equal("delta", a.tokens.ReplicationToken()) 3442 }) 3443 3444 t.Run("updated-configuration", func(t *testing.T) { 3445 cfg := &config.RuntimeConfig{ 3446 ACLToken: "echo", 3447 ACLAgentToken: "foxtrot", 3448 ACLAgentMasterToken: "golf", 3449 ACLReplicationToken: "hotel", 3450 } 3451 // ensures no error for missing persisted tokens file 3452 require.NoError(a.loadTokens(cfg)) 3453 require.Equal("echo", a.tokens.UserToken()) 3454 require.Equal("foxtrot", a.tokens.AgentToken()) 3455 require.Equal("golf", a.tokens.AgentMasterToken()) 3456 require.Equal("hotel", a.tokens.ReplicationToken()) 3457 }) 3458 3459 t.Run("persisted-tokens", func(t *testing.T) { 3460 cfg := &config.RuntimeConfig{ 3461 ACLToken: "echo", 3462 ACLAgentToken: "foxtrot", 3463 ACLAgentMasterToken: "golf", 3464 ACLReplicationToken: "hotel", 3465 } 3466 3467 tokens := `{ 3468 "agent" : "india", 3469 "agent_master" : "juliett", 3470 "default": "kilo", 3471 "replication" : "lima" 3472 }` 3473 3474 require.NoError(ioutil.WriteFile(tokensFullPath, []byte(tokens), 0600)) 3475 require.NoError(a.loadTokens(cfg)) 3476 3477 // no updates since token persistence is not enabled 3478 require.Equal("echo", a.tokens.UserToken()) 3479 require.Equal("foxtrot", a.tokens.AgentToken()) 3480 require.Equal("golf", a.tokens.AgentMasterToken()) 3481 require.Equal("hotel", a.tokens.ReplicationToken()) 3482 3483 a.config.ACLEnableTokenPersistence = true 3484 require.NoError(a.loadTokens(cfg)) 3485 3486 require.Equal("india", a.tokens.AgentToken()) 3487 require.Equal("juliett", a.tokens.AgentMasterToken()) 3488 require.Equal("kilo", a.tokens.UserToken()) 3489 require.Equal("lima", a.tokens.ReplicationToken()) 3490 }) 3491 3492 t.Run("persisted-tokens-override", func(t *testing.T) { 3493 tokens := `{ 3494 "agent" : "mike", 3495 "agent_master" : "november", 3496 "default": "oscar", 3497 "replication" : "papa" 3498 }` 3499 3500 cfg := &config.RuntimeConfig{ 3501 ACLToken: "quebec", 3502 ACLAgentToken: "romeo", 3503 ACLAgentMasterToken: "sierra", 3504 ACLReplicationToken: "tango", 3505 } 3506 3507 require.NoError(ioutil.WriteFile(tokensFullPath, []byte(tokens), 0600)) 3508 require.NoError(a.loadTokens(cfg)) 3509 3510 require.Equal("mike", a.tokens.AgentToken()) 3511 require.Equal("november", a.tokens.AgentMasterToken()) 3512 require.Equal("oscar", a.tokens.UserToken()) 3513 require.Equal("papa", a.tokens.ReplicationToken()) 3514 }) 3515 3516 t.Run("partial-persisted", func(t *testing.T) { 3517 tokens := `{ 3518 "agent" : "uniform", 3519 "agent_master" : "victor" 3520 }` 3521 3522 cfg := &config.RuntimeConfig{ 3523 ACLToken: "whiskey", 3524 ACLAgentToken: "xray", 3525 ACLAgentMasterToken: "yankee", 3526 ACLReplicationToken: "zulu", 3527 } 3528 3529 require.NoError(ioutil.WriteFile(tokensFullPath, []byte(tokens), 0600)) 3530 require.NoError(a.loadTokens(cfg)) 3531 3532 require.Equal("uniform", a.tokens.AgentToken()) 3533 require.Equal("victor", a.tokens.AgentMasterToken()) 3534 require.Equal("whiskey", a.tokens.UserToken()) 3535 require.Equal("zulu", a.tokens.ReplicationToken()) 3536 }) 3537 3538 t.Run("persistence-error-not-json", func(t *testing.T) { 3539 cfg := &config.RuntimeConfig{ 3540 ACLToken: "one", 3541 ACLAgentToken: "two", 3542 ACLAgentMasterToken: "three", 3543 ACLReplicationToken: "four", 3544 } 3545 3546 require.NoError(ioutil.WriteFile(tokensFullPath, []byte{0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08}, 0600)) 3547 err := a.loadTokens(cfg) 3548 require.Error(err) 3549 3550 require.Equal("one", a.tokens.UserToken()) 3551 require.Equal("two", a.tokens.AgentToken()) 3552 require.Equal("three", a.tokens.AgentMasterToken()) 3553 require.Equal("four", a.tokens.ReplicationToken()) 3554 }) 3555 3556 t.Run("persistence-error-wrong-top-level", func(t *testing.T) { 3557 cfg := &config.RuntimeConfig{ 3558 ACLToken: "alfa", 3559 ACLAgentToken: "bravo", 3560 ACLAgentMasterToken: "charlie", 3561 ACLReplicationToken: "foxtrot", 3562 } 3563 3564 require.NoError(ioutil.WriteFile(tokensFullPath, []byte("[1,2,3]"), 0600)) 3565 err := a.loadTokens(cfg) 3566 require.Error(err) 3567 3568 require.Equal("alfa", a.tokens.UserToken()) 3569 require.Equal("bravo", a.tokens.AgentToken()) 3570 require.Equal("charlie", a.tokens.AgentMasterToken()) 3571 require.Equal("foxtrot", a.tokens.ReplicationToken()) 3572 }) 3573 } 3574 3575 func TestAgent_ReloadConfigOutgoingRPCConfig(t *testing.T) { 3576 t.Parallel() 3577 dataDir := testutil.TempDir(t, "agent") // we manage the data dir 3578 defer os.RemoveAll(dataDir) 3579 hcl := ` 3580 data_dir = "` + dataDir + `" 3581 verify_outgoing = true 3582 ca_file = "../test/ca/root.cer" 3583 cert_file = "../test/key/ourdomain.cer" 3584 key_file = "../test/key/ourdomain.key" 3585 verify_server_hostname = false 3586 ` 3587 a := NewTestAgent(t, t.Name(), hcl) 3588 defer a.Shutdown() 3589 tlsConf := a.tlsConfigurator.OutgoingRPCConfig() 3590 require.True(t, tlsConf.InsecureSkipVerify) 3591 require.Len(t, tlsConf.ClientCAs.Subjects(), 1) 3592 require.Len(t, tlsConf.RootCAs.Subjects(), 1) 3593 3594 hcl = ` 3595 data_dir = "` + dataDir + `" 3596 verify_outgoing = true 3597 ca_path = "../test/ca_path" 3598 cert_file = "../test/key/ourdomain.cer" 3599 key_file = "../test/key/ourdomain.key" 3600 verify_server_hostname = true 3601 ` 3602 c := TestConfig(config.Source{Name: t.Name(), Format: "hcl", Data: hcl}) 3603 require.NoError(t, a.ReloadConfig(c)) 3604 tlsConf = a.tlsConfigurator.OutgoingRPCConfig() 3605 require.False(t, tlsConf.InsecureSkipVerify) 3606 require.Len(t, tlsConf.RootCAs.Subjects(), 2) 3607 require.Len(t, tlsConf.ClientCAs.Subjects(), 2) 3608 } 3609 3610 func TestAgent_ReloadConfigIncomingRPCConfig(t *testing.T) { 3611 t.Parallel() 3612 dataDir := testutil.TempDir(t, "agent") // we manage the data dir 3613 defer os.RemoveAll(dataDir) 3614 hcl := ` 3615 data_dir = "` + dataDir + `" 3616 verify_outgoing = true 3617 ca_file = "../test/ca/root.cer" 3618 cert_file = "../test/key/ourdomain.cer" 3619 key_file = "../test/key/ourdomain.key" 3620 verify_server_hostname = false 3621 ` 3622 a := NewTestAgent(t, t.Name(), hcl) 3623 defer a.Shutdown() 3624 tlsConf := a.tlsConfigurator.IncomingRPCConfig() 3625 require.NotNil(t, tlsConf.GetConfigForClient) 3626 tlsConf, err := tlsConf.GetConfigForClient(nil) 3627 require.NoError(t, err) 3628 require.NotNil(t, tlsConf) 3629 require.True(t, tlsConf.InsecureSkipVerify) 3630 require.Len(t, tlsConf.ClientCAs.Subjects(), 1) 3631 require.Len(t, tlsConf.RootCAs.Subjects(), 1) 3632 3633 hcl = ` 3634 data_dir = "` + dataDir + `" 3635 verify_outgoing = true 3636 ca_path = "../test/ca_path" 3637 cert_file = "../test/key/ourdomain.cer" 3638 key_file = "../test/key/ourdomain.key" 3639 verify_server_hostname = true 3640 ` 3641 c := TestConfig(config.Source{Name: t.Name(), Format: "hcl", Data: hcl}) 3642 require.NoError(t, a.ReloadConfig(c)) 3643 tlsConf, err = tlsConf.GetConfigForClient(nil) 3644 require.NoError(t, err) 3645 require.False(t, tlsConf.InsecureSkipVerify) 3646 require.Len(t, tlsConf.ClientCAs.Subjects(), 2) 3647 require.Len(t, tlsConf.RootCAs.Subjects(), 2) 3648 } 3649 3650 func TestAgent_ReloadConfigTLSConfigFailure(t *testing.T) { 3651 t.Parallel() 3652 dataDir := testutil.TempDir(t, "agent") // we manage the data dir 3653 defer os.RemoveAll(dataDir) 3654 hcl := ` 3655 data_dir = "` + dataDir + `" 3656 verify_outgoing = true 3657 ca_file = "../test/ca/root.cer" 3658 cert_file = "../test/key/ourdomain.cer" 3659 key_file = "../test/key/ourdomain.key" 3660 verify_server_hostname = false 3661 ` 3662 a := NewTestAgent(t, t.Name(), hcl) 3663 defer a.Shutdown() 3664 tlsConf := a.tlsConfigurator.IncomingRPCConfig() 3665 3666 hcl = ` 3667 data_dir = "` + dataDir + `" 3668 verify_incoming = true 3669 ` 3670 c := TestConfig(config.Source{Name: t.Name(), Format: "hcl", Data: hcl}) 3671 require.Error(t, a.ReloadConfig(c)) 3672 tlsConf, err := tlsConf.GetConfigForClient(nil) 3673 require.NoError(t, err) 3674 require.Equal(t, tls.NoClientCert, tlsConf.ClientAuth) 3675 require.Len(t, tlsConf.ClientCAs.Subjects(), 1) 3676 require.Len(t, tlsConf.RootCAs.Subjects(), 1) 3677 }