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