github.com/djenriquez/nomad-1@v0.8.1/command/agent/alloc_endpoint_test.go (about) 1 package agent 2 3 import ( 4 "archive/tar" 5 "fmt" 6 "io" 7 "io/ioutil" 8 "net/http" 9 "net/http/httptest" 10 "os" 11 "reflect" 12 "strings" 13 "testing" 14 15 "github.com/golang/snappy" 16 "github.com/hashicorp/nomad/acl" 17 "github.com/hashicorp/nomad/client/allocdir" 18 "github.com/hashicorp/nomad/helper/uuid" 19 "github.com/hashicorp/nomad/nomad/mock" 20 "github.com/hashicorp/nomad/nomad/structs" 21 "github.com/hashicorp/nomad/testutil" 22 "github.com/stretchr/testify/require" 23 ) 24 25 func TestHTTP_AllocsList(t *testing.T) { 26 t.Parallel() 27 httpTest(t, nil, func(s *TestAgent) { 28 // Directly manipulate the state 29 state := s.Agent.server.State() 30 alloc1 := mock.Alloc() 31 testEvent := structs.NewTaskEvent(structs.TaskSiblingFailed) 32 var events1 []*structs.TaskEvent 33 events1 = append(events1, testEvent) 34 taskState := &structs.TaskState{Events: events1} 35 alloc1.TaskStates = make(map[string]*structs.TaskState) 36 alloc1.TaskStates["test"] = taskState 37 38 alloc2 := mock.Alloc() 39 alloc2.TaskStates = make(map[string]*structs.TaskState) 40 alloc2.TaskStates["test"] = taskState 41 42 state.UpsertJobSummary(998, mock.JobSummary(alloc1.JobID)) 43 state.UpsertJobSummary(999, mock.JobSummary(alloc2.JobID)) 44 err := state.UpsertAllocs(1000, 45 []*structs.Allocation{alloc1, alloc2}) 46 if err != nil { 47 t.Fatalf("err: %v", err) 48 } 49 50 // Make the HTTP request 51 req, err := http.NewRequest("GET", "/v1/allocations", nil) 52 if err != nil { 53 t.Fatalf("err: %v", err) 54 } 55 respW := httptest.NewRecorder() 56 57 // Make the request 58 obj, err := s.Server.AllocsRequest(respW, req) 59 if err != nil { 60 t.Fatalf("err: %v", err) 61 } 62 63 // Check for the index 64 if respW.HeaderMap.Get("X-Nomad-Index") == "" { 65 t.Fatalf("missing index") 66 } 67 if respW.HeaderMap.Get("X-Nomad-KnownLeader") != "true" { 68 t.Fatalf("missing known leader") 69 } 70 if respW.HeaderMap.Get("X-Nomad-LastContact") == "" { 71 t.Fatalf("missing last contact") 72 } 73 74 // Check the alloc 75 allocs := obj.([]*structs.AllocListStub) 76 if len(allocs) != 2 { 77 t.Fatalf("bad: %#v", allocs) 78 } 79 expectedMsg := "Task's sibling failed" 80 displayMsg1 := allocs[0].TaskStates["test"].Events[0].DisplayMessage 81 require.Equal(t, expectedMsg, displayMsg1, "DisplayMessage should be set") 82 displayMsg2 := allocs[0].TaskStates["test"].Events[0].DisplayMessage 83 require.Equal(t, expectedMsg, displayMsg2, "DisplayMessage should be set") 84 }) 85 } 86 87 func TestHTTP_AllocsPrefixList(t *testing.T) { 88 t.Parallel() 89 httpTest(t, nil, func(s *TestAgent) { 90 // Directly manipulate the state 91 state := s.Agent.server.State() 92 93 alloc1 := mock.Alloc() 94 alloc1.ID = "aaaaaaaa-e8f7-fd38-c855-ab94ceb89706" 95 alloc2 := mock.Alloc() 96 alloc2.ID = "aaabbbbb-e8f7-fd38-c855-ab94ceb89706" 97 98 testEvent := structs.NewTaskEvent(structs.TaskSiblingFailed) 99 var events1 []*structs.TaskEvent 100 events1 = append(events1, testEvent) 101 taskState := &structs.TaskState{Events: events1} 102 alloc2.TaskStates = make(map[string]*structs.TaskState) 103 alloc2.TaskStates["test"] = taskState 104 105 summary1 := mock.JobSummary(alloc1.JobID) 106 summary2 := mock.JobSummary(alloc2.JobID) 107 if err := state.UpsertJobSummary(998, summary1); err != nil { 108 t.Fatal(err) 109 } 110 if err := state.UpsertJobSummary(999, summary2); err != nil { 111 t.Fatal(err) 112 } 113 if err := state.UpsertAllocs(1000, 114 []*structs.Allocation{alloc1, alloc2}); err != nil { 115 t.Fatalf("err: %v", err) 116 } 117 118 // Make the HTTP request 119 req, err := http.NewRequest("GET", "/v1/allocations?prefix=aaab", nil) 120 if err != nil { 121 t.Fatalf("err: %v", err) 122 } 123 respW := httptest.NewRecorder() 124 125 // Make the request 126 obj, err := s.Server.AllocsRequest(respW, req) 127 if err != nil { 128 t.Fatalf("err: %v", err) 129 } 130 131 // Check for the index 132 if respW.HeaderMap.Get("X-Nomad-Index") == "" { 133 t.Fatalf("missing index") 134 } 135 if respW.HeaderMap.Get("X-Nomad-KnownLeader") != "true" { 136 t.Fatalf("missing known leader") 137 } 138 if respW.HeaderMap.Get("X-Nomad-LastContact") == "" { 139 t.Fatalf("missing last contact") 140 } 141 142 // Check the alloc 143 n := obj.([]*structs.AllocListStub) 144 if len(n) != 1 { 145 t.Fatalf("bad: %#v", n) 146 } 147 148 // Check the identifier 149 if n[0].ID != alloc2.ID { 150 t.Fatalf("expected alloc ID: %v, Actual: %v", alloc2.ID, n[0].ID) 151 } 152 expectedMsg := "Task's sibling failed" 153 displayMsg1 := n[0].TaskStates["test"].Events[0].DisplayMessage 154 require.Equal(t, expectedMsg, displayMsg1, "DisplayMessage should be set") 155 156 }) 157 } 158 159 func TestHTTP_AllocQuery(t *testing.T) { 160 t.Parallel() 161 httpTest(t, nil, func(s *TestAgent) { 162 // Directly manipulate the state 163 state := s.Agent.server.State() 164 alloc := mock.Alloc() 165 if err := state.UpsertJobSummary(999, mock.JobSummary(alloc.JobID)); err != nil { 166 t.Fatal(err) 167 } 168 err := state.UpsertAllocs(1000, 169 []*structs.Allocation{alloc}) 170 if err != nil { 171 t.Fatalf("err: %v", err) 172 } 173 174 // Make the HTTP request 175 req, err := http.NewRequest("GET", "/v1/allocation/"+alloc.ID, nil) 176 if err != nil { 177 t.Fatalf("err: %v", err) 178 } 179 respW := httptest.NewRecorder() 180 181 // Make the request 182 obj, err := s.Server.AllocSpecificRequest(respW, req) 183 if err != nil { 184 t.Fatalf("err: %v", err) 185 } 186 187 // Check for the index 188 if respW.HeaderMap.Get("X-Nomad-Index") == "" { 189 t.Fatalf("missing index") 190 } 191 if respW.HeaderMap.Get("X-Nomad-KnownLeader") != "true" { 192 t.Fatalf("missing known leader") 193 } 194 if respW.HeaderMap.Get("X-Nomad-LastContact") == "" { 195 t.Fatalf("missing last contact") 196 } 197 198 // Check the job 199 a := obj.(*structs.Allocation) 200 if a.ID != alloc.ID { 201 t.Fatalf("bad: %#v", a) 202 } 203 }) 204 } 205 206 func TestHTTP_AllocQuery_Payload(t *testing.T) { 207 t.Parallel() 208 httpTest(t, nil, func(s *TestAgent) { 209 // Directly manipulate the state 210 state := s.Agent.server.State() 211 alloc := mock.Alloc() 212 if err := state.UpsertJobSummary(999, mock.JobSummary(alloc.JobID)); err != nil { 213 t.Fatal(err) 214 } 215 216 // Insert Payload compressed 217 expected := []byte("hello world") 218 compressed := snappy.Encode(nil, expected) 219 alloc.Job.Payload = compressed 220 221 err := state.UpsertAllocs(1000, []*structs.Allocation{alloc}) 222 if err != nil { 223 t.Fatalf("err: %v", err) 224 } 225 226 // Make the HTTP request 227 req, err := http.NewRequest("GET", "/v1/allocation/"+alloc.ID, nil) 228 if err != nil { 229 t.Fatalf("err: %v", err) 230 } 231 respW := httptest.NewRecorder() 232 233 // Make the request 234 obj, err := s.Server.AllocSpecificRequest(respW, req) 235 if err != nil { 236 t.Fatalf("err: %v", err) 237 } 238 239 // Check for the index 240 if respW.HeaderMap.Get("X-Nomad-Index") == "" { 241 t.Fatalf("missing index") 242 } 243 if respW.HeaderMap.Get("X-Nomad-KnownLeader") != "true" { 244 t.Fatalf("missing known leader") 245 } 246 if respW.HeaderMap.Get("X-Nomad-LastContact") == "" { 247 t.Fatalf("missing last contact") 248 } 249 250 // Check the job 251 a := obj.(*structs.Allocation) 252 if a.ID != alloc.ID { 253 t.Fatalf("bad: %#v", a) 254 } 255 256 // Check the payload is decompressed 257 if !reflect.DeepEqual(a.Job.Payload, expected) { 258 t.Fatalf("Payload not decompressed properly; got %#v; want %#v", a.Job.Payload, expected) 259 } 260 }) 261 } 262 263 func TestHTTP_AllocStats(t *testing.T) { 264 t.Parallel() 265 require := require.New(t) 266 267 httpTest(t, nil, func(s *TestAgent) { 268 // Local node, local resp 269 { 270 // Make the HTTP request 271 req, err := http.NewRequest("GET", fmt.Sprintf("/v1/client/allocation/%s/stats", uuid.Generate()), nil) 272 if err != nil { 273 t.Fatalf("err: %v", err) 274 } 275 respW := httptest.NewRecorder() 276 277 // Make the request 278 _, err = s.Server.ClientAllocRequest(respW, req) 279 require.NotNil(err) 280 require.True(structs.IsErrUnknownAllocation(err)) 281 } 282 283 // Local node, server resp 284 { 285 srv := s.server 286 s.server = nil 287 288 req, err := http.NewRequest("GET", fmt.Sprintf("/v1/client/allocation/%s/stats", uuid.Generate()), nil) 289 require.Nil(err) 290 291 respW := httptest.NewRecorder() 292 _, err = s.Server.ClientAllocRequest(respW, req) 293 require.NotNil(err) 294 require.True(structs.IsErrUnknownAllocation(err)) 295 296 s.server = srv 297 } 298 299 // no client, server resp 300 { 301 c := s.client 302 s.client = nil 303 304 testutil.WaitForResult(func() (bool, error) { 305 n, err := s.server.State().NodeByID(nil, c.NodeID()) 306 if err != nil { 307 return false, err 308 } 309 return n != nil, nil 310 }, func(err error) { 311 t.Fatalf("should have client: %v", err) 312 }) 313 314 req, err := http.NewRequest("GET", fmt.Sprintf("/v1/client/allocation/%s/stats", uuid.Generate()), nil) 315 require.Nil(err) 316 317 respW := httptest.NewRecorder() 318 _, err = s.Server.ClientAllocRequest(respW, req) 319 require.NotNil(err) 320 require.True(structs.IsErrUnknownAllocation(err)) 321 322 s.client = c 323 } 324 }) 325 } 326 327 func TestHTTP_AllocStats_ACL(t *testing.T) { 328 t.Parallel() 329 require := require.New(t) 330 331 httpACLTest(t, nil, func(s *TestAgent) { 332 state := s.Agent.server.State() 333 334 // Make the HTTP request 335 req, err := http.NewRequest("GET", fmt.Sprintf("/v1/client/allocation/%s/stats", uuid.Generate()), nil) 336 if err != nil { 337 t.Fatalf("err: %v", err) 338 } 339 340 // Try request without a token and expect failure 341 { 342 respW := httptest.NewRecorder() 343 _, err := s.Server.ClientAllocRequest(respW, req) 344 require.NotNil(err) 345 require.Equal(err.Error(), structs.ErrPermissionDenied.Error()) 346 } 347 348 // Try request with an invalid token and expect failure 349 { 350 respW := httptest.NewRecorder() 351 token := mock.CreatePolicyAndToken(t, state, 1005, "invalid", mock.NodePolicy(acl.PolicyWrite)) 352 setToken(req, token) 353 _, err := s.Server.ClientAllocRequest(respW, req) 354 require.NotNil(err) 355 require.Equal(err.Error(), structs.ErrPermissionDenied.Error()) 356 } 357 358 // Try request with a valid token 359 // Still returns an error because the alloc does not exist 360 { 361 respW := httptest.NewRecorder() 362 policy := mock.NamespacePolicy(structs.DefaultNamespace, "", []string{acl.NamespaceCapabilityReadJob}) 363 token := mock.CreatePolicyAndToken(t, state, 1007, "valid", policy) 364 setToken(req, token) 365 _, err := s.Server.ClientAllocRequest(respW, req) 366 require.NotNil(err) 367 require.True(structs.IsErrUnknownAllocation(err)) 368 } 369 370 // Try request with a management token 371 // Still returns an error because the alloc does not exist 372 { 373 respW := httptest.NewRecorder() 374 setToken(req, s.RootToken) 375 _, err := s.Server.ClientAllocRequest(respW, req) 376 require.NotNil(err) 377 require.True(structs.IsErrUnknownAllocation(err)) 378 } 379 }) 380 } 381 382 func TestHTTP_AllocSnapshot(t *testing.T) { 383 t.Parallel() 384 httpTest(t, nil, func(s *TestAgent) { 385 // Make the HTTP request 386 req, err := http.NewRequest("GET", "/v1/client/allocation/123/snapshot", nil) 387 if err != nil { 388 t.Fatalf("err: %v", err) 389 } 390 respW := httptest.NewRecorder() 391 392 // Make the request 393 _, err = s.Server.ClientAllocRequest(respW, req) 394 if !strings.Contains(err.Error(), allocNotFoundErr) { 395 t.Fatalf("err: %v", err) 396 } 397 }) 398 } 399 400 func TestHTTP_AllocSnapshot_WithMigrateToken(t *testing.T) { 401 t.Parallel() 402 require := require.New(t) 403 httpACLTest(t, nil, func(s *TestAgent) { 404 // Request without a token fails 405 req, err := http.NewRequest("GET", "/v1/client/allocation/123/snapshot", nil) 406 require.Nil(err) 407 408 // Make the unauthorized request 409 respW := httptest.NewRecorder() 410 _, err = s.Server.ClientAllocRequest(respW, req) 411 require.NotNil(err) 412 require.EqualError(err, structs.ErrPermissionDenied.Error()) 413 414 // Create an allocation 415 alloc := mock.Alloc() 416 417 validMigrateToken, err := structs.GenerateMigrateToken(alloc.ID, s.Agent.Client().Node().SecretID) 418 require.Nil(err) 419 420 // Request with a token succeeds 421 url := fmt.Sprintf("/v1/client/allocation/%s/snapshot", alloc.ID) 422 req, err = http.NewRequest("GET", url, nil) 423 require.Nil(err) 424 425 req.Header.Set("X-Nomad-Token", validMigrateToken) 426 427 // Make the unauthorized request 428 respW = httptest.NewRecorder() 429 _, err = s.Server.ClientAllocRequest(respW, req) 430 require.NotContains(err.Error(), structs.ErrPermissionDenied.Error()) 431 }) 432 } 433 434 // TestHTTP_AllocSnapshot_Atomic ensures that when a client encounters an error 435 // snapshotting a valid tar is not returned. 436 func TestHTTP_AllocSnapshot_Atomic(t *testing.T) { 437 t.Parallel() 438 httpTest(t, nil, func(s *TestAgent) { 439 // Create an alloc 440 state := s.server.State() 441 alloc := mock.Alloc() 442 alloc.Job.TaskGroups[0].Tasks[0].Driver = "mock_driver" 443 alloc.Job.TaskGroups[0].Tasks[0].Config["run_for"] = "30s" 444 alloc.NodeID = s.client.NodeID() 445 state.UpsertJobSummary(998, mock.JobSummary(alloc.JobID)) 446 if err := state.UpsertAllocs(1000, []*structs.Allocation{alloc.Copy()}); err != nil { 447 t.Fatalf("error upserting alloc: %v", err) 448 } 449 450 // Wait for the client to run it 451 testutil.WaitForResult(func() (bool, error) { 452 if _, err := s.client.GetClientAlloc(alloc.ID); err != nil { 453 return false, err 454 } 455 456 serverAlloc, err := state.AllocByID(nil, alloc.ID) 457 if err != nil { 458 return false, err 459 } 460 461 return serverAlloc.ClientStatus == structs.AllocClientStatusRunning, fmt.Errorf(serverAlloc.ClientStatus) 462 }, func(err error) { 463 t.Fatalf("client not running alloc: %v", err) 464 }) 465 466 // Now write to its shared dir 467 allocDirI, err := s.client.GetAllocFS(alloc.ID) 468 if err != nil { 469 t.Fatalf("unable to find alloc dir: %v", err) 470 } 471 allocDir := allocDirI.(*allocdir.AllocDir) 472 473 // Remove the task dir to break Snapshot 474 os.RemoveAll(allocDir.TaskDirs["web"].LocalDir) 475 476 // require Snapshot fails 477 if err := allocDir.Snapshot(ioutil.Discard); err != nil { 478 s.logger.Printf("[DEBUG] agent.test: snapshot returned error: %v", err) 479 } else { 480 t.Errorf("expected Snapshot() to fail but it did not") 481 } 482 483 // Make the HTTP request to ensure the Snapshot error is 484 // propagated through to the HTTP layer. Since the tar is 485 // streamed over a 200 HTTP response the only way to signal an 486 // error is by writing a marker file. 487 respW := httptest.NewRecorder() 488 req, err := http.NewRequest("GET", fmt.Sprintf("/v1/client/allocation/%s/snapshot", alloc.ID), nil) 489 if err != nil { 490 t.Fatalf("err: %v", err) 491 } 492 493 // Make the request via the mux to make sure the error returned 494 // by Snapshot is properly propagated via HTTP 495 s.Server.mux.ServeHTTP(respW, req) 496 resp := respW.Result() 497 r := tar.NewReader(resp.Body) 498 errorFilename := allocdir.SnapshotErrorFilename(alloc.ID) 499 markerFound := false 500 markerContents := "" 501 for { 502 header, err := r.Next() 503 if err != nil { 504 if err != io.EOF { 505 // Huh, I wonder how a non-EOF error can happen? 506 t.Errorf("Unexpected error while streaming: %v", err) 507 } 508 break 509 } 510 511 if markerFound { 512 // No more files should be found after the failure marker 513 t.Errorf("Next file found after error marker: %s", header.Name) 514 break 515 } 516 517 if header.Name == errorFilename { 518 // Found it! 519 markerFound = true 520 buf := make([]byte, int(header.Size)) 521 if _, err := r.Read(buf); err != nil && err != io.EOF { 522 t.Errorf("Unexpected error reading error marker %s: %v", errorFilename, err) 523 } else { 524 markerContents = string(buf) 525 } 526 } 527 } 528 529 if !markerFound { 530 t.Fatalf("marker file %s not written; bad tar will be treated as good!", errorFilename) 531 } 532 if markerContents == "" { 533 t.Fatalf("marker file %s empty", markerContents) 534 } else { 535 t.Logf("EXPECTED snapshot error: %s", markerContents) 536 } 537 }) 538 } 539 540 func TestHTTP_AllocGC(t *testing.T) { 541 t.Parallel() 542 require := require.New(t) 543 path := fmt.Sprintf("/v1/client/allocation/%s/gc", uuid.Generate()) 544 httpTest(t, nil, func(s *TestAgent) { 545 // Local node, local resp 546 { 547 req, err := http.NewRequest("GET", path, nil) 548 if err != nil { 549 t.Fatalf("err: %v", err) 550 } 551 552 respW := httptest.NewRecorder() 553 _, err = s.Server.ClientAllocRequest(respW, req) 554 if !structs.IsErrUnknownAllocation(err) { 555 t.Fatalf("unexpected err: %v", err) 556 } 557 } 558 559 // Local node, server resp 560 { 561 srv := s.server 562 s.server = nil 563 564 req, err := http.NewRequest("GET", path, nil) 565 if err != nil { 566 t.Fatalf("err: %v", err) 567 } 568 569 respW := httptest.NewRecorder() 570 _, err = s.Server.ClientAllocRequest(respW, req) 571 if !structs.IsErrUnknownAllocation(err) { 572 t.Fatalf("unexpected err: %v", err) 573 } 574 575 s.server = srv 576 } 577 578 // no client, server resp 579 { 580 c := s.client 581 s.client = nil 582 583 testutil.WaitForResult(func() (bool, error) { 584 n, err := s.server.State().NodeByID(nil, c.NodeID()) 585 if err != nil { 586 return false, err 587 } 588 return n != nil, nil 589 }, func(err error) { 590 t.Fatalf("should have client: %v", err) 591 }) 592 593 req, err := http.NewRequest("GET", path, nil) 594 if err != nil { 595 t.Fatalf("err: %v", err) 596 } 597 598 respW := httptest.NewRecorder() 599 _, err = s.Server.ClientAllocRequest(respW, req) 600 require.NotNil(err) 601 if !structs.IsErrUnknownAllocation(err) { 602 t.Fatalf("unexpected err: %v", err) 603 } 604 605 s.client = c 606 } 607 }) 608 } 609 610 func TestHTTP_AllocGC_ACL(t *testing.T) { 611 t.Parallel() 612 require := require.New(t) 613 path := fmt.Sprintf("/v1/client/allocation/%s/gc", uuid.Generate()) 614 615 httpACLTest(t, nil, func(s *TestAgent) { 616 state := s.Agent.server.State() 617 618 // Make the HTTP request 619 req, err := http.NewRequest("GET", path, nil) 620 if err != nil { 621 t.Fatalf("err: %v", err) 622 } 623 624 // Try request without a token and expect failure 625 { 626 respW := httptest.NewRecorder() 627 _, err := s.Server.ClientAllocRequest(respW, req) 628 require.NotNil(err) 629 require.Equal(err.Error(), structs.ErrPermissionDenied.Error()) 630 } 631 632 // Try request with an invalid token and expect failure 633 { 634 respW := httptest.NewRecorder() 635 token := mock.CreatePolicyAndToken(t, state, 1005, "invalid", mock.NodePolicy(acl.PolicyWrite)) 636 setToken(req, token) 637 _, err := s.Server.ClientAllocRequest(respW, req) 638 require.NotNil(err) 639 require.Equal(err.Error(), structs.ErrPermissionDenied.Error()) 640 } 641 642 // Try request with a valid token 643 // Still returns an error because the alloc does not exist 644 { 645 respW := httptest.NewRecorder() 646 policy := mock.NamespacePolicy(structs.DefaultNamespace, "", []string{acl.NamespaceCapabilitySubmitJob}) 647 token := mock.CreatePolicyAndToken(t, state, 1007, "valid", policy) 648 setToken(req, token) 649 _, err := s.Server.ClientAllocRequest(respW, req) 650 require.NotNil(err) 651 require.True(structs.IsErrUnknownAllocation(err)) 652 } 653 654 // Try request with a management token 655 // Still returns an error because the alloc does not exist 656 { 657 respW := httptest.NewRecorder() 658 setToken(req, s.RootToken) 659 _, err := s.Server.ClientAllocRequest(respW, req) 660 require.NotNil(err) 661 require.True(structs.IsErrUnknownAllocation(err)) 662 } 663 }) 664 } 665 666 func TestHTTP_AllocAllGC(t *testing.T) { 667 t.Parallel() 668 require := require.New(t) 669 httpTest(t, nil, func(s *TestAgent) { 670 // Local node, local resp 671 { 672 req, err := http.NewRequest("GET", "/v1/client/gc", nil) 673 if err != nil { 674 t.Fatalf("err: %v", err) 675 } 676 677 respW := httptest.NewRecorder() 678 _, err = s.Server.ClientGCRequest(respW, req) 679 if err != nil { 680 t.Fatalf("unexpected err: %v", err) 681 } 682 } 683 684 // Local node, server resp 685 { 686 srv := s.server 687 s.server = nil 688 689 req, err := http.NewRequest("GET", fmt.Sprintf("/v1/client/gc?node_id=%s", uuid.Generate()), nil) 690 require.Nil(err) 691 692 respW := httptest.NewRecorder() 693 _, err = s.Server.ClientGCRequest(respW, req) 694 require.NotNil(err) 695 require.Contains(err.Error(), "Unknown node") 696 697 s.server = srv 698 } 699 700 // no client, server resp 701 { 702 c := s.client 703 s.client = nil 704 705 testutil.WaitForResult(func() (bool, error) { 706 n, err := s.server.State().NodeByID(nil, c.NodeID()) 707 if err != nil { 708 return false, err 709 } 710 return n != nil, nil 711 }, func(err error) { 712 t.Fatalf("should have client: %v", err) 713 }) 714 715 req, err := http.NewRequest("GET", fmt.Sprintf("/v1/client/gc?node_id=%s", c.NodeID()), nil) 716 require.Nil(err) 717 718 respW := httptest.NewRecorder() 719 _, err = s.Server.ClientGCRequest(respW, req) 720 require.NotNil(err) 721 722 // The dev agent uses in-mem RPC so just assert the no route error 723 require.Contains(err.Error(), structs.ErrNoNodeConn.Error()) 724 725 s.client = c 726 } 727 }) 728 729 } 730 731 func TestHTTP_AllocAllGC_ACL(t *testing.T) { 732 t.Parallel() 733 require := require.New(t) 734 httpACLTest(t, nil, func(s *TestAgent) { 735 state := s.Agent.server.State() 736 737 // Make the HTTP request 738 req, err := http.NewRequest("GET", "/v1/client/gc", nil) 739 require.Nil(err) 740 741 // Try request without a token and expect failure 742 { 743 respW := httptest.NewRecorder() 744 _, err := s.Server.ClientGCRequest(respW, req) 745 require.NotNil(err) 746 require.Equal(err.Error(), structs.ErrPermissionDenied.Error()) 747 } 748 749 // Try request with an invalid token and expect failure 750 { 751 respW := httptest.NewRecorder() 752 token := mock.CreatePolicyAndToken(t, state, 1005, "invalid", mock.NodePolicy(acl.PolicyRead)) 753 setToken(req, token) 754 _, err := s.Server.ClientGCRequest(respW, req) 755 require.NotNil(err) 756 require.Equal(err.Error(), structs.ErrPermissionDenied.Error()) 757 } 758 759 // Try request with a valid token 760 { 761 respW := httptest.NewRecorder() 762 token := mock.CreatePolicyAndToken(t, state, 1007, "valid", mock.NodePolicy(acl.PolicyWrite)) 763 setToken(req, token) 764 _, err := s.Server.ClientGCRequest(respW, req) 765 require.Nil(err) 766 require.Equal(http.StatusOK, respW.Code) 767 } 768 769 // Try request with a management token 770 { 771 respW := httptest.NewRecorder() 772 setToken(req, s.RootToken) 773 _, err := s.Server.ClientGCRequest(respW, req) 774 require.Nil(err) 775 require.Equal(http.StatusOK, respW.Code) 776 } 777 }) 778 }