github.com/quite/nomad@v0.8.6/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["run_for"] = "30s" 448 alloc.NodeID = s.client.NodeID() 449 state.UpsertJobSummary(998, mock.JobSummary(alloc.JobID)) 450 if err := state.UpsertAllocs(1000, []*structs.Allocation{alloc.Copy()}); err != nil { 451 t.Fatalf("error upserting alloc: %v", err) 452 } 453 454 // Wait for the client to run it 455 testutil.WaitForResult(func() (bool, error) { 456 if _, err := s.client.GetClientAlloc(alloc.ID); err != nil { 457 return false, err 458 } 459 460 serverAlloc, err := state.AllocByID(nil, alloc.ID) 461 if err != nil { 462 return false, err 463 } 464 465 return serverAlloc.ClientStatus == structs.AllocClientStatusRunning, fmt.Errorf(serverAlloc.ClientStatus) 466 }, func(err error) { 467 t.Fatalf("client not running alloc: %v", err) 468 }) 469 470 // Now write to its shared dir 471 allocDirI, err := s.client.GetAllocFS(alloc.ID) 472 if err != nil { 473 t.Fatalf("unable to find alloc dir: %v", err) 474 } 475 allocDir := allocDirI.(*allocdir.AllocDir) 476 477 // Remove the task dir to break Snapshot 478 os.RemoveAll(allocDir.TaskDirs["web"].LocalDir) 479 480 // require Snapshot fails 481 if err := allocDir.Snapshot(ioutil.Discard); err != nil { 482 s.logger.Printf("[DEBUG] agent.test: snapshot returned error: %v", err) 483 } else { 484 t.Errorf("expected Snapshot() to fail but it did not") 485 } 486 487 // Make the HTTP request to ensure the Snapshot error is 488 // propagated through to the HTTP layer. Since the tar is 489 // streamed over a 200 HTTP response the only way to signal an 490 // error is by writing a marker file. 491 respW := httptest.NewRecorder() 492 req, err := http.NewRequest("GET", fmt.Sprintf("/v1/client/allocation/%s/snapshot", alloc.ID), nil) 493 if err != nil { 494 t.Fatalf("err: %v", err) 495 } 496 497 // Make the request via the mux to make sure the error returned 498 // by Snapshot is properly propagated via HTTP 499 s.Server.mux.ServeHTTP(respW, req) 500 resp := respW.Result() 501 r := tar.NewReader(resp.Body) 502 errorFilename := allocdir.SnapshotErrorFilename(alloc.ID) 503 markerFound := false 504 markerContents := "" 505 for { 506 header, err := r.Next() 507 if err != nil { 508 if err != io.EOF { 509 // Huh, I wonder how a non-EOF error can happen? 510 t.Errorf("Unexpected error while streaming: %v", err) 511 } 512 break 513 } 514 515 if markerFound { 516 // No more files should be found after the failure marker 517 t.Errorf("Next file found after error marker: %s", header.Name) 518 break 519 } 520 521 if header.Name == errorFilename { 522 // Found it! 523 markerFound = true 524 buf := make([]byte, int(header.Size)) 525 if _, err := r.Read(buf); err != nil && err != io.EOF { 526 t.Errorf("Unexpected error reading error marker %s: %v", errorFilename, err) 527 } else { 528 markerContents = string(buf) 529 } 530 } 531 } 532 533 if !markerFound { 534 t.Fatalf("marker file %s not written; bad tar will be treated as good!", errorFilename) 535 } 536 if markerContents == "" { 537 t.Fatalf("marker file %s empty", markerContents) 538 } else { 539 t.Logf("EXPECTED snapshot error: %s", markerContents) 540 } 541 }) 542 } 543 544 func TestHTTP_AllocGC(t *testing.T) { 545 t.Parallel() 546 require := require.New(t) 547 path := fmt.Sprintf("/v1/client/allocation/%s/gc", uuid.Generate()) 548 httpTest(t, nil, func(s *TestAgent) { 549 // Local node, local resp 550 { 551 req, err := http.NewRequest("GET", path, nil) 552 if err != nil { 553 t.Fatalf("err: %v", err) 554 } 555 556 respW := httptest.NewRecorder() 557 _, err = s.Server.ClientAllocRequest(respW, req) 558 if !structs.IsErrUnknownAllocation(err) { 559 t.Fatalf("unexpected err: %v", err) 560 } 561 } 562 563 // Local node, server resp 564 { 565 srv := s.server 566 s.server = nil 567 568 req, err := http.NewRequest("GET", path, nil) 569 if err != nil { 570 t.Fatalf("err: %v", err) 571 } 572 573 respW := httptest.NewRecorder() 574 _, err = s.Server.ClientAllocRequest(respW, req) 575 if !structs.IsErrUnknownAllocation(err) { 576 t.Fatalf("unexpected err: %v", err) 577 } 578 579 s.server = srv 580 } 581 582 // no client, server resp 583 { 584 c := s.client 585 s.client = nil 586 587 testutil.WaitForResult(func() (bool, error) { 588 n, err := s.server.State().NodeByID(nil, c.NodeID()) 589 if err != nil { 590 return false, err 591 } 592 return n != nil, nil 593 }, func(err error) { 594 t.Fatalf("should have client: %v", err) 595 }) 596 597 req, err := http.NewRequest("GET", path, nil) 598 if err != nil { 599 t.Fatalf("err: %v", err) 600 } 601 602 respW := httptest.NewRecorder() 603 _, err = s.Server.ClientAllocRequest(respW, req) 604 require.NotNil(err) 605 if !structs.IsErrUnknownAllocation(err) { 606 t.Fatalf("unexpected err: %v", err) 607 } 608 609 s.client = c 610 } 611 }) 612 } 613 614 func TestHTTP_AllocGC_ACL(t *testing.T) { 615 t.Parallel() 616 require := require.New(t) 617 path := fmt.Sprintf("/v1/client/allocation/%s/gc", uuid.Generate()) 618 619 httpACLTest(t, nil, func(s *TestAgent) { 620 state := s.Agent.server.State() 621 622 // Make the HTTP request 623 req, err := http.NewRequest("GET", path, nil) 624 if err != nil { 625 t.Fatalf("err: %v", err) 626 } 627 628 // Try request without a token and expect failure 629 { 630 respW := httptest.NewRecorder() 631 _, err := s.Server.ClientAllocRequest(respW, req) 632 require.NotNil(err) 633 require.Equal(err.Error(), structs.ErrPermissionDenied.Error()) 634 } 635 636 // Try request with an invalid token and expect failure 637 { 638 respW := httptest.NewRecorder() 639 token := mock.CreatePolicyAndToken(t, state, 1005, "invalid", mock.NodePolicy(acl.PolicyWrite)) 640 setToken(req, token) 641 _, err := s.Server.ClientAllocRequest(respW, req) 642 require.NotNil(err) 643 require.Equal(err.Error(), structs.ErrPermissionDenied.Error()) 644 } 645 646 // Try request with a valid token 647 // Still returns an error because the alloc does not exist 648 { 649 respW := httptest.NewRecorder() 650 policy := mock.NamespacePolicy(structs.DefaultNamespace, "", []string{acl.NamespaceCapabilitySubmitJob}) 651 token := mock.CreatePolicyAndToken(t, state, 1007, "valid", policy) 652 setToken(req, token) 653 _, err := s.Server.ClientAllocRequest(respW, req) 654 require.NotNil(err) 655 require.True(structs.IsErrUnknownAllocation(err)) 656 } 657 658 // Try request with a management token 659 // Still returns an error because the alloc does not exist 660 { 661 respW := httptest.NewRecorder() 662 setToken(req, s.RootToken) 663 _, err := s.Server.ClientAllocRequest(respW, req) 664 require.NotNil(err) 665 require.True(structs.IsErrUnknownAllocation(err)) 666 } 667 }) 668 } 669 670 func TestHTTP_AllocAllGC(t *testing.T) { 671 t.Parallel() 672 require := require.New(t) 673 httpTest(t, nil, func(s *TestAgent) { 674 // Local node, local resp 675 { 676 req, err := http.NewRequest("GET", "/v1/client/gc", nil) 677 if err != nil { 678 t.Fatalf("err: %v", err) 679 } 680 681 respW := httptest.NewRecorder() 682 _, err = s.Server.ClientGCRequest(respW, req) 683 if err != nil { 684 t.Fatalf("unexpected err: %v", err) 685 } 686 } 687 688 // Local node, server resp 689 { 690 srv := s.server 691 s.server = nil 692 693 req, err := http.NewRequest("GET", fmt.Sprintf("/v1/client/gc?node_id=%s", uuid.Generate()), nil) 694 require.Nil(err) 695 696 respW := httptest.NewRecorder() 697 _, err = s.Server.ClientGCRequest(respW, req) 698 require.NotNil(err) 699 require.Contains(err.Error(), "Unknown node") 700 701 s.server = srv 702 } 703 704 // client stats from server, should not error 705 { 706 c := s.client 707 s.client = nil 708 709 testutil.WaitForResult(func() (bool, error) { 710 n, err := s.server.State().NodeByID(nil, c.NodeID()) 711 if err != nil { 712 return false, err 713 } 714 return n != nil, nil 715 }, func(err error) { 716 t.Fatalf("should have client: %v", err) 717 }) 718 719 req, err := http.NewRequest("GET", fmt.Sprintf("/v1/client/gc?node_id=%s", c.NodeID()), nil) 720 require.Nil(err) 721 722 respW := httptest.NewRecorder() 723 _, err = s.Server.ClientGCRequest(respW, req) 724 require.Nil(err) 725 726 s.client = c 727 } 728 }) 729 730 } 731 732 func TestHTTP_AllocAllGC_ACL(t *testing.T) { 733 t.Parallel() 734 require := require.New(t) 735 httpACLTest(t, nil, func(s *TestAgent) { 736 state := s.Agent.server.State() 737 738 // Make the HTTP request 739 req, err := http.NewRequest("GET", "/v1/client/gc", nil) 740 require.Nil(err) 741 742 // Try request without a token and expect failure 743 { 744 respW := httptest.NewRecorder() 745 _, err := s.Server.ClientGCRequest(respW, req) 746 require.NotNil(err) 747 require.Equal(err.Error(), structs.ErrPermissionDenied.Error()) 748 } 749 750 // Try request with an invalid token and expect failure 751 { 752 respW := httptest.NewRecorder() 753 token := mock.CreatePolicyAndToken(t, state, 1005, "invalid", mock.NodePolicy(acl.PolicyRead)) 754 setToken(req, token) 755 _, err := s.Server.ClientGCRequest(respW, req) 756 require.NotNil(err) 757 require.Equal(err.Error(), structs.ErrPermissionDenied.Error()) 758 } 759 760 // Try request with a valid token 761 { 762 respW := httptest.NewRecorder() 763 token := mock.CreatePolicyAndToken(t, state, 1007, "valid", mock.NodePolicy(acl.PolicyWrite)) 764 setToken(req, token) 765 _, err := s.Server.ClientGCRequest(respW, req) 766 require.Nil(err) 767 require.Equal(http.StatusOK, respW.Code) 768 } 769 770 // Try request with a management token 771 { 772 respW := httptest.NewRecorder() 773 setToken(req, s.RootToken) 774 _, err := s.Server.ClientGCRequest(respW, req) 775 require.Nil(err) 776 require.Equal(http.StatusOK, respW.Code) 777 } 778 }) 779 }