github.com/manicqin/nomad@v0.9.5/command/agent/http_test.go (about) 1 package agent 2 3 import ( 4 "bytes" 5 "crypto/tls" 6 "crypto/x509" 7 "encoding/json" 8 "fmt" 9 "io" 10 "io/ioutil" 11 "net" 12 "net/http" 13 "net/http/httptest" 14 "net/url" 15 "testing" 16 "time" 17 18 "github.com/hashicorp/nomad/nomad/mock" 19 "github.com/hashicorp/nomad/nomad/structs" 20 "github.com/hashicorp/nomad/nomad/structs/config" 21 "github.com/hashicorp/nomad/testutil" 22 "github.com/stretchr/testify/assert" 23 "github.com/stretchr/testify/require" 24 "github.com/ugorji/go/codec" 25 ) 26 27 // makeHTTPServer returns a test server whose logs will be written to 28 // the passed writer. If the writer is nil, the logs are written to stderr. 29 func makeHTTPServer(t testing.TB, cb func(c *Config)) *TestAgent { 30 return NewTestAgent(t, t.Name(), cb) 31 } 32 33 func BenchmarkHTTPRequests(b *testing.B) { 34 s := makeHTTPServer(b, func(c *Config) { 35 c.Client.Enabled = false 36 }) 37 defer s.Shutdown() 38 39 job := mock.Job() 40 var allocs []*structs.Allocation 41 count := 1000 42 for i := 0; i < count; i++ { 43 alloc := mock.Alloc() 44 alloc.Job = job 45 alloc.JobID = job.ID 46 alloc.Name = fmt.Sprintf("my-job.web[%d]", i) 47 allocs = append(allocs, alloc) 48 } 49 50 handler := func(resp http.ResponseWriter, req *http.Request) (interface{}, error) { 51 return allocs[:count], nil 52 } 53 b.ResetTimer() 54 55 b.RunParallel(func(pb *testing.PB) { 56 for pb.Next() { 57 resp := httptest.NewRecorder() 58 req, _ := http.NewRequest("GET", "/v1/kv/key", nil) 59 s.Server.wrap(handler)(resp, req) 60 } 61 }) 62 } 63 64 // TestRootFallthrough tests rootFallthrough handler to 65 // verify redirect and 404 behavior 66 func TestRootFallthrough(t *testing.T) { 67 t.Parallel() 68 69 cases := []struct { 70 desc string 71 path string 72 expectedPath string 73 expectedCode int 74 }{ 75 { 76 desc: "unknown endpoint 404s", 77 path: "/v1/unknown/endpoint", 78 expectedCode: 404, 79 }, 80 { 81 desc: "root path redirects to ui", 82 path: "/", 83 expectedPath: "/ui/", 84 expectedCode: 307, 85 }, 86 } 87 88 s := makeHTTPServer(t, nil) 89 defer s.Shutdown() 90 91 // setup a client that doesn't follow redirects 92 client := &http.Client{ 93 CheckRedirect: func(_ *http.Request, _ []*http.Request) error { 94 return http.ErrUseLastResponse 95 }, 96 } 97 98 for _, tc := range cases { 99 t.Run(tc.desc, func(t *testing.T) { 100 101 reqURL := fmt.Sprintf("http://%s%s", s.Agent.config.AdvertiseAddrs.HTTP, tc.path) 102 103 resp, err := client.Get(reqURL) 104 require.NoError(t, err) 105 require.Equal(t, tc.expectedCode, resp.StatusCode) 106 107 if tc.expectedPath != "" { 108 loc, err := resp.Location() 109 require.NoError(t, err) 110 require.Equal(t, tc.expectedPath, loc.Path) 111 } 112 }) 113 } 114 } 115 116 func TestSetIndex(t *testing.T) { 117 t.Parallel() 118 resp := httptest.NewRecorder() 119 setIndex(resp, 1000) 120 header := resp.Header().Get("X-Nomad-Index") 121 if header != "1000" { 122 t.Fatalf("Bad: %v", header) 123 } 124 setIndex(resp, 2000) 125 if v := resp.Header()["X-Nomad-Index"]; len(v) != 1 { 126 t.Fatalf("bad: %#v", v) 127 } 128 } 129 130 func TestSetKnownLeader(t *testing.T) { 131 t.Parallel() 132 resp := httptest.NewRecorder() 133 setKnownLeader(resp, true) 134 header := resp.Header().Get("X-Nomad-KnownLeader") 135 if header != "true" { 136 t.Fatalf("Bad: %v", header) 137 } 138 resp = httptest.NewRecorder() 139 setKnownLeader(resp, false) 140 header = resp.Header().Get("X-Nomad-KnownLeader") 141 if header != "false" { 142 t.Fatalf("Bad: %v", header) 143 } 144 } 145 146 func TestSetLastContact(t *testing.T) { 147 t.Parallel() 148 resp := httptest.NewRecorder() 149 setLastContact(resp, 123456*time.Microsecond) 150 header := resp.Header().Get("X-Nomad-LastContact") 151 if header != "123" { 152 t.Fatalf("Bad: %v", header) 153 } 154 } 155 156 func TestSetMeta(t *testing.T) { 157 t.Parallel() 158 meta := structs.QueryMeta{ 159 Index: 1000, 160 KnownLeader: true, 161 LastContact: 123456 * time.Microsecond, 162 } 163 resp := httptest.NewRecorder() 164 setMeta(resp, &meta) 165 header := resp.Header().Get("X-Nomad-Index") 166 if header != "1000" { 167 t.Fatalf("Bad: %v", header) 168 } 169 header = resp.Header().Get("X-Nomad-KnownLeader") 170 if header != "true" { 171 t.Fatalf("Bad: %v", header) 172 } 173 header = resp.Header().Get("X-Nomad-LastContact") 174 if header != "123" { 175 t.Fatalf("Bad: %v", header) 176 } 177 } 178 179 func TestSetHeaders(t *testing.T) { 180 t.Parallel() 181 s := makeHTTPServer(t, nil) 182 s.Agent.config.HTTPAPIResponseHeaders = map[string]string{"foo": "bar"} 183 defer s.Shutdown() 184 185 resp := httptest.NewRecorder() 186 handler := func(resp http.ResponseWriter, req *http.Request) (interface{}, error) { 187 return &structs.Job{Name: "foo"}, nil 188 } 189 190 req, _ := http.NewRequest("GET", "/v1/kv/key", nil) 191 s.Server.wrap(handler)(resp, req) 192 header := resp.Header().Get("foo") 193 194 if header != "bar" { 195 t.Fatalf("expected header: %v, actual: %v", "bar", header) 196 } 197 198 } 199 200 func TestContentTypeIsJSON(t *testing.T) { 201 t.Parallel() 202 s := makeHTTPServer(t, nil) 203 defer s.Shutdown() 204 205 resp := httptest.NewRecorder() 206 207 handler := func(resp http.ResponseWriter, req *http.Request) (interface{}, error) { 208 return &structs.Job{Name: "foo"}, nil 209 } 210 211 req, _ := http.NewRequest("GET", "/v1/kv/key", nil) 212 s.Server.wrap(handler)(resp, req) 213 214 contentType := resp.Header().Get("Content-Type") 215 216 if contentType != "application/json" { 217 t.Fatalf("Content-Type header was not 'application/json'") 218 } 219 } 220 221 func TestWrapNonJSON(t *testing.T) { 222 t.Parallel() 223 s := makeHTTPServer(t, nil) 224 defer s.Shutdown() 225 226 resp := httptest.NewRecorder() 227 228 handler := func(resp http.ResponseWriter, req *http.Request) ([]byte, error) { 229 return []byte("test response"), nil 230 } 231 232 req, _ := http.NewRequest("GET", "/v1/kv/key", nil) 233 s.Server.wrapNonJSON(handler)(resp, req) 234 235 respBody, _ := ioutil.ReadAll(resp.Body) 236 require.Equal(t, respBody, []byte("test response")) 237 238 } 239 240 func TestWrapNonJSON_Error(t *testing.T) { 241 t.Parallel() 242 s := makeHTTPServer(t, nil) 243 defer s.Shutdown() 244 245 handlerRPCErr := func(resp http.ResponseWriter, req *http.Request) ([]byte, error) { 246 return nil, structs.NewErrRPCCoded(404, "not found") 247 } 248 249 handlerCodedErr := func(resp http.ResponseWriter, req *http.Request) ([]byte, error) { 250 return nil, CodedError(422, "unprocessable") 251 } 252 253 // RPC coded error 254 { 255 resp := httptest.NewRecorder() 256 req, _ := http.NewRequest("GET", "/v1/kv/key", nil) 257 s.Server.wrapNonJSON(handlerRPCErr)(resp, req) 258 respBody, _ := ioutil.ReadAll(resp.Body) 259 require.Equal(t, []byte("not found"), respBody) 260 require.Equal(t, 404, resp.Code) 261 } 262 263 // CodedError 264 { 265 resp := httptest.NewRecorder() 266 req, _ := http.NewRequest("GET", "/v1/kv/key", nil) 267 s.Server.wrapNonJSON(handlerCodedErr)(resp, req) 268 respBody, _ := ioutil.ReadAll(resp.Body) 269 require.Equal(t, []byte("unprocessable"), respBody) 270 require.Equal(t, 422, resp.Code) 271 } 272 273 } 274 275 func TestPrettyPrint(t *testing.T) { 276 t.Parallel() 277 testPrettyPrint("pretty=1", true, t) 278 } 279 280 func TestPrettyPrintOff(t *testing.T) { 281 t.Parallel() 282 testPrettyPrint("pretty=0", false, t) 283 } 284 285 func TestPrettyPrintBare(t *testing.T) { 286 t.Parallel() 287 testPrettyPrint("pretty", true, t) 288 } 289 290 func testPrettyPrint(pretty string, prettyFmt bool, t *testing.T) { 291 s := makeHTTPServer(t, nil) 292 defer s.Shutdown() 293 294 r := &structs.Job{Name: "foo"} 295 296 resp := httptest.NewRecorder() 297 handler := func(resp http.ResponseWriter, req *http.Request) (interface{}, error) { 298 return r, nil 299 } 300 301 urlStr := "/v1/job/foo?" + pretty 302 req, _ := http.NewRequest("GET", urlStr, nil) 303 s.Server.wrap(handler)(resp, req) 304 305 var expected bytes.Buffer 306 var err error 307 if prettyFmt { 308 enc := codec.NewEncoder(&expected, structs.JsonHandlePretty) 309 err = enc.Encode(r) 310 expected.WriteByte('\n') 311 } else { 312 enc := codec.NewEncoder(&expected, structs.JsonHandle) 313 err = enc.Encode(r) 314 } 315 if err != nil { 316 t.Fatalf("failed to encode: %v", err) 317 } 318 actual, err := ioutil.ReadAll(resp.Body) 319 if err != nil { 320 t.Fatalf("err: %s", err) 321 } 322 323 if !bytes.Equal(expected.Bytes(), actual) { 324 t.Fatalf("bad:\nexpected:\t%q\nactual:\t\t%q", expected.String(), string(actual)) 325 } 326 } 327 328 func TestPermissionDenied(t *testing.T) { 329 s := makeHTTPServer(t, func(c *Config) { 330 c.ACL.Enabled = true 331 }) 332 defer s.Shutdown() 333 334 { 335 resp := httptest.NewRecorder() 336 handler := func(resp http.ResponseWriter, req *http.Request) (interface{}, error) { 337 return nil, structs.ErrPermissionDenied 338 } 339 340 req, _ := http.NewRequest("GET", "/v1/job/foo", nil) 341 s.Server.wrap(handler)(resp, req) 342 assert.Equal(t, resp.Code, 403) 343 } 344 345 // When remote RPC is used the errors have "rpc error: " prependend 346 { 347 resp := httptest.NewRecorder() 348 handler := func(resp http.ResponseWriter, req *http.Request) (interface{}, error) { 349 return nil, fmt.Errorf("rpc error: %v", structs.ErrPermissionDenied) 350 } 351 352 req, _ := http.NewRequest("GET", "/v1/job/foo", nil) 353 s.Server.wrap(handler)(resp, req) 354 assert.Equal(t, resp.Code, 403) 355 } 356 } 357 358 func TestTokenNotFound(t *testing.T) { 359 s := makeHTTPServer(t, func(c *Config) { 360 c.ACL.Enabled = true 361 }) 362 defer s.Shutdown() 363 364 resp := httptest.NewRecorder() 365 handler := func(resp http.ResponseWriter, req *http.Request) (interface{}, error) { 366 return nil, structs.ErrTokenNotFound 367 } 368 369 urlStr := "/v1/job/foo" 370 req, _ := http.NewRequest("GET", urlStr, nil) 371 s.Server.wrap(handler)(resp, req) 372 assert.Equal(t, resp.Code, 403) 373 } 374 375 func TestParseWait(t *testing.T) { 376 t.Parallel() 377 resp := httptest.NewRecorder() 378 var b structs.QueryOptions 379 380 req, err := http.NewRequest("GET", 381 "/v1/catalog/nodes?wait=60s&index=1000", nil) 382 if err != nil { 383 t.Fatalf("err: %v", err) 384 } 385 386 if d := parseWait(resp, req, &b); d { 387 t.Fatalf("unexpected done") 388 } 389 390 if b.MinQueryIndex != 1000 { 391 t.Fatalf("Bad: %v", b) 392 } 393 if b.MaxQueryTime != 60*time.Second { 394 t.Fatalf("Bad: %v", b) 395 } 396 } 397 398 func TestParseWait_InvalidTime(t *testing.T) { 399 t.Parallel() 400 resp := httptest.NewRecorder() 401 var b structs.QueryOptions 402 403 req, err := http.NewRequest("GET", 404 "/v1/catalog/nodes?wait=60foo&index=1000", nil) 405 if err != nil { 406 t.Fatalf("err: %v", err) 407 } 408 409 if d := parseWait(resp, req, &b); !d { 410 t.Fatalf("expected done") 411 } 412 413 if resp.Code != 400 { 414 t.Fatalf("bad code: %v", resp.Code) 415 } 416 } 417 418 func TestParseWait_InvalidIndex(t *testing.T) { 419 t.Parallel() 420 resp := httptest.NewRecorder() 421 var b structs.QueryOptions 422 423 req, err := http.NewRequest("GET", 424 "/v1/catalog/nodes?wait=60s&index=foo", nil) 425 if err != nil { 426 t.Fatalf("err: %v", err) 427 } 428 429 if d := parseWait(resp, req, &b); !d { 430 t.Fatalf("expected done") 431 } 432 433 if resp.Code != 400 { 434 t.Fatalf("bad code: %v", resp.Code) 435 } 436 } 437 438 func TestParseConsistency(t *testing.T) { 439 t.Parallel() 440 var b structs.QueryOptions 441 442 req, err := http.NewRequest("GET", 443 "/v1/catalog/nodes?stale", nil) 444 if err != nil { 445 t.Fatalf("err: %v", err) 446 } 447 448 parseConsistency(req, &b) 449 if !b.AllowStale { 450 t.Fatalf("Bad: %v", b) 451 } 452 453 b = structs.QueryOptions{} 454 req, err = http.NewRequest("GET", 455 "/v1/catalog/nodes?consistent", nil) 456 if err != nil { 457 t.Fatalf("err: %v", err) 458 } 459 460 parseConsistency(req, &b) 461 if b.AllowStale { 462 t.Fatalf("Bad: %v", b) 463 } 464 } 465 466 func TestParseRegion(t *testing.T) { 467 t.Parallel() 468 s := makeHTTPServer(t, nil) 469 defer s.Shutdown() 470 471 req, err := http.NewRequest("GET", 472 "/v1/jobs?region=foo", nil) 473 if err != nil { 474 t.Fatalf("err: %v", err) 475 } 476 477 var region string 478 s.Server.parseRegion(req, ®ion) 479 if region != "foo" { 480 t.Fatalf("bad %s", region) 481 } 482 483 region = "" 484 req, err = http.NewRequest("GET", "/v1/jobs", nil) 485 if err != nil { 486 t.Fatalf("err: %v", err) 487 } 488 489 s.Server.parseRegion(req, ®ion) 490 if region != "global" { 491 t.Fatalf("bad %s", region) 492 } 493 } 494 495 func TestParseToken(t *testing.T) { 496 t.Parallel() 497 s := makeHTTPServer(t, nil) 498 defer s.Shutdown() 499 500 req, err := http.NewRequest("GET", "/v1/jobs", nil) 501 req.Header.Add("X-Nomad-Token", "foobar") 502 if err != nil { 503 t.Fatalf("err: %v", err) 504 } 505 506 var token string 507 s.Server.parseToken(req, &token) 508 if token != "foobar" { 509 t.Fatalf("bad %s", token) 510 } 511 } 512 513 // TestHTTP_VerifyHTTPSClient asserts that a client certificate signed by the 514 // appropriate CA is required when VerifyHTTPSClient=true. 515 func TestHTTP_VerifyHTTPSClient(t *testing.T) { 516 t.Parallel() 517 const ( 518 cafile = "../../helper/tlsutil/testdata/ca.pem" 519 foocert = "../../helper/tlsutil/testdata/nomad-foo.pem" 520 fookey = "../../helper/tlsutil/testdata/nomad-foo-key.pem" 521 ) 522 s := makeHTTPServer(t, func(c *Config) { 523 c.Region = "foo" // match the region on foocert 524 c.TLSConfig = &config.TLSConfig{ 525 EnableHTTP: true, 526 VerifyHTTPSClient: true, 527 CAFile: cafile, 528 CertFile: foocert, 529 KeyFile: fookey, 530 } 531 }) 532 defer s.Shutdown() 533 534 reqURL := fmt.Sprintf("https://%s/v1/agent/self", s.Agent.config.AdvertiseAddrs.HTTP) 535 536 // FAIL: Requests that expect 127.0.0.1 as the name should fail 537 resp, err := http.Get(reqURL) 538 if err == nil { 539 resp.Body.Close() 540 t.Fatalf("expected non-nil error but received: %v", resp.StatusCode) 541 } 542 urlErr, ok := err.(*url.Error) 543 if !ok { 544 t.Fatalf("expected a *url.Error but received: %T -> %v", err, err) 545 } 546 hostErr, ok := urlErr.Err.(x509.HostnameError) 547 if !ok { 548 t.Fatalf("expected a x509.HostnameError but received: %T -> %v", urlErr.Err, urlErr.Err) 549 } 550 if expected := "127.0.0.1"; hostErr.Host != expected { 551 t.Fatalf("expected hostname on error to be %q but found %q", expected, hostErr.Host) 552 } 553 554 // FAIL: Requests that specify a valid hostname but not the CA should 555 // fail 556 tlsConf := &tls.Config{ 557 ServerName: "client.regionFoo.nomad", 558 } 559 transport := &http.Transport{TLSClientConfig: tlsConf} 560 client := &http.Client{Transport: transport} 561 req, err := http.NewRequest("GET", reqURL, nil) 562 if err != nil { 563 t.Fatalf("error creating request: %v", err) 564 } 565 resp, err = client.Do(req) 566 if err == nil { 567 resp.Body.Close() 568 t.Fatalf("expected non-nil error but received: %v", resp.StatusCode) 569 } 570 urlErr, ok = err.(*url.Error) 571 if !ok { 572 t.Fatalf("expected a *url.Error but received: %T -> %v", err, err) 573 } 574 _, ok = urlErr.Err.(x509.UnknownAuthorityError) 575 if !ok { 576 t.Fatalf("expected a x509.UnknownAuthorityError but received: %T -> %v", urlErr.Err, urlErr.Err) 577 } 578 579 // FAIL: Requests that specify a valid hostname and CA cert but lack a 580 // client certificate should fail 581 cacertBytes, err := ioutil.ReadFile(cafile) 582 if err != nil { 583 t.Fatalf("error reading cacert: %v", err) 584 } 585 tlsConf.RootCAs = x509.NewCertPool() 586 tlsConf.RootCAs.AppendCertsFromPEM(cacertBytes) 587 req, err = http.NewRequest("GET", reqURL, nil) 588 if err != nil { 589 t.Fatalf("error creating request: %v", err) 590 } 591 resp, err = client.Do(req) 592 if err == nil { 593 resp.Body.Close() 594 t.Fatalf("expected non-nil error but received: %v", resp.StatusCode) 595 } 596 urlErr, ok = err.(*url.Error) 597 if !ok { 598 t.Fatalf("expected a *url.Error but received: %T -> %v", err, err) 599 } 600 opErr, ok := urlErr.Err.(*net.OpError) 601 if !ok { 602 t.Fatalf("expected a *net.OpErr but received: %T -> %v", urlErr.Err, urlErr.Err) 603 } 604 const badCertificate = "tls: bad certificate" // from crypto/tls/alert.go:52 and RFC 5246 ยง A.3 605 if opErr.Err.Error() != badCertificate { 606 t.Fatalf("expected tls.alert bad_certificate but received: %q", opErr.Err.Error()) 607 } 608 609 // PASS: Requests that specify a valid hostname, CA cert, and client 610 // certificate succeed. 611 tlsConf.GetClientCertificate = func(*tls.CertificateRequestInfo) (*tls.Certificate, error) { 612 c, err := tls.LoadX509KeyPair(foocert, fookey) 613 if err != nil { 614 return nil, err 615 } 616 return &c, nil 617 } 618 transport = &http.Transport{TLSClientConfig: tlsConf} 619 client = &http.Client{Transport: transport} 620 req, err = http.NewRequest("GET", reqURL, nil) 621 if err != nil { 622 t.Fatalf("error creating request: %v", err) 623 } 624 resp, err = client.Do(req) 625 if err != nil { 626 t.Fatalf("unexpected error: %v", err) 627 } 628 resp.Body.Close() 629 if resp.StatusCode != 200 { 630 t.Fatalf("expected 200 status code but got: %d", resp.StatusCode) 631 } 632 } 633 634 func TestHTTP_VerifyHTTPSClient_AfterConfigReload(t *testing.T) { 635 t.Parallel() 636 assert := assert.New(t) 637 638 const ( 639 cafile = "../../helper/tlsutil/testdata/ca.pem" 640 foocert = "../../helper/tlsutil/testdata/nomad-bad.pem" 641 fookey = "../../helper/tlsutil/testdata/nomad-bad-key.pem" 642 foocert2 = "../../helper/tlsutil/testdata/nomad-foo.pem" 643 fookey2 = "../../helper/tlsutil/testdata/nomad-foo-key.pem" 644 ) 645 646 agentConfig := &Config{ 647 TLSConfig: &config.TLSConfig{ 648 EnableHTTP: true, 649 VerifyHTTPSClient: true, 650 CAFile: cafile, 651 CertFile: foocert, 652 KeyFile: fookey, 653 }, 654 } 655 656 newConfig := &Config{ 657 TLSConfig: &config.TLSConfig{ 658 EnableHTTP: true, 659 VerifyHTTPSClient: true, 660 CAFile: cafile, 661 CertFile: foocert2, 662 KeyFile: fookey2, 663 }, 664 } 665 666 s := makeHTTPServer(t, func(c *Config) { 667 c.TLSConfig = agentConfig.TLSConfig 668 }) 669 defer s.Shutdown() 670 671 // Make an initial request that should fail. 672 // Requests that specify a valid hostname, CA cert, and client 673 // certificate succeed. 674 tlsConf := &tls.Config{ 675 ServerName: "client.regionFoo.nomad", 676 RootCAs: x509.NewCertPool(), 677 GetClientCertificate: func(*tls.CertificateRequestInfo) (*tls.Certificate, error) { 678 c, err := tls.LoadX509KeyPair(foocert, fookey) 679 if err != nil { 680 return nil, err 681 } 682 return &c, nil 683 }, 684 } 685 686 // HTTPS request should succeed 687 httpsReqURL := fmt.Sprintf("https://%s/v1/agent/self", s.Agent.config.AdvertiseAddrs.HTTP) 688 689 cacertBytes, err := ioutil.ReadFile(cafile) 690 assert.Nil(err) 691 tlsConf.RootCAs.AppendCertsFromPEM(cacertBytes) 692 693 transport := &http.Transport{TLSClientConfig: tlsConf} 694 client := &http.Client{Transport: transport} 695 req, err := http.NewRequest("GET", httpsReqURL, nil) 696 assert.Nil(err) 697 698 // Check that we get an error that the certificate isn't valid for the 699 // region we are contacting. 700 _, err = client.Do(req) 701 assert.Contains(err.Error(), "certificate is valid for") 702 703 // Reload the TLS configuration== 704 assert.Nil(s.Agent.Reload(newConfig)) 705 706 // Requests that specify a valid hostname, CA cert, and client 707 // certificate succeed. 708 tlsConf = &tls.Config{ 709 ServerName: "client.regionFoo.nomad", 710 RootCAs: x509.NewCertPool(), 711 GetClientCertificate: func(*tls.CertificateRequestInfo) (*tls.Certificate, error) { 712 c, err := tls.LoadX509KeyPair(foocert2, fookey2) 713 if err != nil { 714 return nil, err 715 } 716 return &c, nil 717 }, 718 } 719 720 cacertBytes, err = ioutil.ReadFile(cafile) 721 assert.Nil(err) 722 tlsConf.RootCAs.AppendCertsFromPEM(cacertBytes) 723 724 transport = &http.Transport{TLSClientConfig: tlsConf} 725 client = &http.Client{Transport: transport} 726 req, err = http.NewRequest("GET", httpsReqURL, nil) 727 assert.Nil(err) 728 729 resp, err := client.Do(req) 730 if assert.Nil(err) { 731 resp.Body.Close() 732 assert.Equal(resp.StatusCode, 200) 733 } 734 } 735 736 func httpTest(t testing.TB, cb func(c *Config), f func(srv *TestAgent)) { 737 s := makeHTTPServer(t, cb) 738 defer s.Shutdown() 739 testutil.WaitForLeader(t, s.Agent.RPC) 740 f(s) 741 } 742 743 func httpACLTest(t testing.TB, cb func(c *Config), f func(srv *TestAgent)) { 744 s := makeHTTPServer(t, func(c *Config) { 745 c.ACL.Enabled = true 746 if cb != nil { 747 cb(c) 748 } 749 }) 750 defer s.Shutdown() 751 testutil.WaitForLeader(t, s.Agent.RPC) 752 f(s) 753 } 754 755 func setToken(req *http.Request, token *structs.ACLToken) { 756 req.Header.Set("X-Nomad-Token", token.SecretID) 757 } 758 759 func encodeReq(obj interface{}) io.ReadCloser { 760 buf := bytes.NewBuffer(nil) 761 enc := json.NewEncoder(buf) 762 enc.Encode(obj) 763 return ioutil.NopCloser(buf) 764 }