github.com/hashicorp/go-plugin@v1.6.0/plugin_test.go (about) 1 // Copyright (c) HashiCorp, Inc. 2 // SPDX-License-Identifier: MPL-2.0 3 4 package plugin 5 6 import ( 7 "context" 8 "crypto/tls" 9 "crypto/x509" 10 "errors" 11 "fmt" 12 "io" 13 "io/ioutil" 14 "log" 15 "net/rpc" 16 "os" 17 "os/exec" 18 "testing" 19 "time" 20 21 "github.com/golang/protobuf/ptypes/empty" 22 "github.com/hashicorp/go-hclog" 23 grpctest "github.com/hashicorp/go-plugin/test/grpc" 24 "google.golang.org/grpc" 25 ) 26 27 // Test that NetRPCUnsupportedPlugin implements the correct interfaces. 28 var _ Plugin = new(NetRPCUnsupportedPlugin) 29 30 var testHandshake = HandshakeConfig{ 31 ProtocolVersion: 1, 32 MagicCookieKey: "TEST_MAGIC_COOKIE", 33 MagicCookieValue: "test", 34 } 35 36 var testVersionedHandshake = HandshakeConfig{ 37 MagicCookieKey: "TEST_MAGIC_COOKIE", 38 MagicCookieValue: "test", 39 } 40 41 // testInterface is the test interface we use for plugins. 42 type testInterface interface { 43 Double(int) int 44 PrintKV(string, interface{}) 45 Bidirectional() error 46 PrintStdio(stdout, stderr []byte) 47 } 48 49 // testStreamer is used to test the grpc streaming interface 50 type testStreamer interface { 51 Stream(int32, int32) ([]int32, error) 52 } 53 54 // testInterfacePlugin implements the Plugin interface 55 var _ Plugin = (*testInterfacePlugin)(nil) 56 57 // testInterfacePlugin is the implementation of Plugin to create 58 // RPC client/server implementations for testInterface. 59 type testInterfacePlugin struct { 60 Impl testInterface 61 } 62 63 func (p *testInterfacePlugin) Server(b *MuxBroker) (interface{}, error) { 64 return &testInterfaceServer{Impl: p.impl()}, nil 65 } 66 67 func (p *testInterfacePlugin) Client(b *MuxBroker, c *rpc.Client) (interface{}, error) { 68 return &testInterfaceClient{Client: c}, nil 69 } 70 71 func (p *testInterfacePlugin) impl() testInterface { 72 if p.Impl != nil { 73 return p.Impl 74 } 75 76 return &testInterfaceImpl{ 77 logger: hclog.New(&hclog.LoggerOptions{ 78 Level: hclog.Trace, 79 Output: os.Stderr, 80 JSONFormat: true, 81 }), 82 } 83 } 84 85 // testGRPCInterfacePlugin implements both Plugin and GRPCPlugin interfaces 86 var _ Plugin = (*testGRPCInterfacePlugin)(nil) 87 var _ GRPCPlugin = (*testGRPCInterfacePlugin)(nil) 88 89 // testGRPCInterfacePlugin is a test implementation of the GRPCPlugin interface 90 type testGRPCInterfacePlugin struct { 91 Impl testInterface 92 } 93 94 func (p *testGRPCInterfacePlugin) Server(b *MuxBroker) (interface{}, error) { 95 return &testInterfaceServer{Impl: p.impl()}, nil 96 } 97 98 func (p *testGRPCInterfacePlugin) Client(b *MuxBroker, c *rpc.Client) (interface{}, error) { 99 return &testInterfaceClient{Client: c}, nil 100 } 101 102 func (p *testGRPCInterfacePlugin) GRPCServer(b *GRPCBroker, s *grpc.Server) error { 103 grpctest.RegisterTestServer(s, &testGRPCServer{broker: b, Impl: p.impl()}) 104 return nil 105 } 106 107 func (p *testGRPCInterfacePlugin) GRPCClient(doneCtx context.Context, b *GRPCBroker, c *grpc.ClientConn) (interface{}, error) { 108 return &testGRPCClient{broker: b, Client: grpctest.NewTestClient(c)}, nil 109 } 110 111 func (p *testGRPCInterfacePlugin) impl() testInterface { 112 if p.Impl != nil { 113 return p.Impl 114 } 115 116 return &testInterfaceImpl{ 117 logger: hclog.New(&hclog.LoggerOptions{ 118 Level: hclog.Trace, 119 Output: os.Stderr, 120 JSONFormat: true, 121 }), 122 } 123 } 124 125 // testInterfaceImpl implements testInterface concretely 126 var _ testInterface = (*testInterfaceImpl)(nil) 127 128 type testInterfaceImpl struct { 129 logger hclog.Logger 130 } 131 132 func (i *testInterfaceImpl) Double(v int) int { return v * 2 } 133 134 func (i *testInterfaceImpl) PrintKV(key string, value interface{}) { 135 i.logger.Info("PrintKV called", key, value) 136 } 137 138 func (i *testInterfaceImpl) Bidirectional() error { 139 return nil 140 } 141 142 func (i *testInterfaceImpl) PrintStdio(stdout, stderr []byte) { 143 if len(stdout) > 0 { 144 fmt.Fprint(os.Stdout, string(stdout)) 145 os.Stdout.Sync() 146 } 147 148 if len(stderr) > 0 { 149 fmt.Fprint(os.Stderr, string(stderr)) 150 os.Stderr.Sync() 151 } 152 } 153 154 // testInterfaceClient implements testInterface to communicate over RPC 155 type testInterfaceClient struct { 156 Client *rpc.Client 157 } 158 159 func (impl *testInterfaceClient) Double(v int) int { 160 var resp int 161 err := impl.Client.Call("Plugin.Double", v, &resp) 162 if err != nil { 163 panic(err) 164 } 165 166 return resp 167 } 168 169 func (impl *testInterfaceClient) PrintKV(key string, value interface{}) { 170 err := impl.Client.Call("Plugin.PrintKV", map[string]interface{}{ 171 "key": key, 172 "value": value, 173 }, &struct{}{}) 174 if err != nil { 175 panic(err) 176 } 177 } 178 179 func (impl *testInterfaceClient) Bidirectional() error { 180 return nil 181 } 182 183 func (impl *testInterfaceClient) PrintStdio(stdout, stderr []byte) { 184 // We don't implement this because we test stream syncing another 185 // way (see rpc_client_test.go). We probably should test this way 186 // but very few people use the net/rpc protocol nowadays so we didn' 187 // put in the effort. 188 return 189 } 190 191 // testInterfaceServer is the RPC server for testInterfaceClient 192 type testInterfaceServer struct { 193 Broker *MuxBroker 194 Impl testInterface 195 } 196 197 func (s *testInterfaceServer) Double(arg int, resp *int) error { 198 *resp = s.Impl.Double(arg) 199 return nil 200 } 201 202 func (s *testInterfaceServer) PrintKV(args map[string]interface{}, _ *struct{}) error { 203 s.Impl.PrintKV(args["key"].(string), args["value"]) 204 return nil 205 } 206 207 // testPluginMap can be used for tests as a plugin map 208 var testPluginMap = map[string]Plugin{ 209 "test": new(testInterfacePlugin), 210 } 211 212 // testGRPCPluginMap can be used for tests as that need a GRPC plugin 213 var testGRPCPluginMap = map[string]Plugin{ 214 "test": new(testGRPCInterfacePlugin), 215 } 216 217 // testGRPCServer is the implementation of our GRPC service. 218 type testGRPCServer struct { 219 Impl testInterface 220 broker *GRPCBroker 221 } 222 223 func (s *testGRPCServer) Double( 224 ctx context.Context, 225 req *grpctest.TestRequest) (*grpctest.TestResponse, error) { 226 return &grpctest.TestResponse{ 227 Output: int32(s.Impl.Double(int(req.Input))), 228 }, nil 229 } 230 231 func (s *testGRPCServer) PrintKV( 232 ctx context.Context, 233 req *grpctest.PrintKVRequest) (*grpctest.PrintKVResponse, error) { 234 var v interface{} 235 switch rv := req.Value.(type) { 236 case *grpctest.PrintKVRequest_ValueString: 237 v = rv.ValueString 238 239 case *grpctest.PrintKVRequest_ValueInt: 240 v = rv.ValueInt 241 242 default: 243 panic(fmt.Sprintf("unknown value: %#v", req.Value)) 244 } 245 246 s.Impl.PrintKV(req.Key, v) 247 return &grpctest.PrintKVResponse{}, nil 248 } 249 250 func (s *testGRPCServer) Bidirectional(ctx context.Context, req *grpctest.BidirectionalRequest) (*grpctest.BidirectionalResponse, error) { 251 conn, err := s.broker.Dial(req.Id) 252 if err != nil { 253 return nil, fmt.Errorf("server dial error: %w", err) 254 } 255 256 pingPongClient := grpctest.NewPingPongClient(conn) 257 resp, err := pingPongClient.Ping(ctx, &grpctest.PingRequest{}) 258 if err != nil { 259 return nil, fmt.Errorf("server Ping() error: %w", err) 260 } 261 if resp.Msg != "pong" { 262 return nil, errors.New("server Bad PingPong") 263 } 264 265 nextID := s.broker.NextId() 266 go s.broker.AcceptAndServe(nextID, func(opts []grpc.ServerOption) *grpc.Server { 267 s := grpc.NewServer(opts...) 268 grpctest.RegisterPingPongServer(s, &pingPongServer{}) 269 return s 270 }) 271 272 return &grpctest.BidirectionalResponse{ 273 Id: nextID, 274 }, nil 275 } 276 277 func (s *testGRPCServer) PrintStdio( 278 ctx context.Context, 279 req *grpctest.PrintStdioRequest, 280 ) (*empty.Empty, error) { 281 s.Impl.PrintStdio(req.Stdout, req.Stderr) 282 return &empty.Empty{}, nil 283 } 284 285 type pingPongServer struct{} 286 287 func (p *pingPongServer) Ping(ctx context.Context, req *grpctest.PingRequest) (*grpctest.PongResponse, error) { 288 return &grpctest.PongResponse{ 289 Msg: "pong", 290 }, nil 291 } 292 293 func (s testGRPCServer) Stream(stream grpctest.Test_StreamServer) error { 294 for { 295 req, err := stream.Recv() 296 if err != nil { 297 if err != io.EOF { 298 return err 299 } 300 return nil 301 } 302 303 if err := stream.Send(&grpctest.TestResponse{Output: req.Input}); err != nil { 304 return err 305 } 306 } 307 308 return nil 309 } 310 311 // testGRPCClient is an implementation of TestInterface that communicates 312 // over gRPC. 313 type testGRPCClient struct { 314 Client grpctest.TestClient 315 broker *GRPCBroker 316 } 317 318 func (c *testGRPCClient) Double(v int) int { 319 resp, err := c.Client.Double(context.Background(), &grpctest.TestRequest{ 320 Input: int32(v), 321 }) 322 if err != nil { 323 panic(err) 324 } 325 326 return int(resp.Output) 327 } 328 329 func (c *testGRPCClient) PrintKV(key string, value interface{}) { 330 req := &grpctest.PrintKVRequest{Key: key} 331 switch v := value.(type) { 332 case string: 333 req.Value = &grpctest.PrintKVRequest_ValueString{ 334 ValueString: v, 335 } 336 337 case int: 338 req.Value = &grpctest.PrintKVRequest_ValueInt{ 339 ValueInt: int32(v), 340 } 341 342 default: 343 panic(fmt.Sprintf("unknown type: %T", value)) 344 } 345 346 _, err := c.Client.PrintKV(context.Background(), req) 347 if err != nil { 348 panic(err) 349 } 350 } 351 352 func (c *testGRPCClient) Bidirectional() error { 353 nextID := c.broker.NextId() 354 go c.broker.AcceptAndServe(nextID, func(opts []grpc.ServerOption) *grpc.Server { 355 s := grpc.NewServer(opts...) 356 grpctest.RegisterPingPongServer(s, &pingPongServer{}) 357 return s 358 }) 359 360 resp, err := c.Client.Bidirectional(context.Background(), &grpctest.BidirectionalRequest{ 361 Id: nextID, 362 }) 363 if err != nil { 364 return fmt.Errorf("client Bidirectional() error: %w", err) 365 } 366 367 conn, err := c.broker.Dial(resp.Id) 368 if err != nil { 369 return fmt.Errorf("client dial error: %w", err) 370 } 371 372 pingPongClient := grpctest.NewPingPongClient(conn) 373 pResp, err := pingPongClient.Ping(context.Background(), &grpctest.PingRequest{}) 374 if err != nil { 375 return fmt.Errorf("client Ping() error: %w", err) 376 } 377 if pResp.Msg != "pong" { 378 return errors.New("client Bad PingPong") 379 } 380 return nil 381 } 382 383 // Stream sends a series of requests from [start, stop) using a bidirectional 384 // streaming service, and returns the streamed responses. 385 func (impl *testGRPCClient) Stream(start, stop int32) ([]int32, error) { 386 if stop <= start { 387 return nil, fmt.Errorf("invalid range [%d, %d)", start, stop) 388 } 389 streamClient, err := impl.Client.Stream(context.Background()) 390 if err != nil { 391 return nil, err 392 } 393 394 var resp []int32 395 for i := start; i < stop; i++ { 396 if err := streamClient.Send(&grpctest.TestRequest{Input: i}); err != nil { 397 return resp, err 398 } 399 400 out, err := streamClient.Recv() 401 if err != nil { 402 return resp, err 403 } 404 405 resp = append(resp, out.Output) 406 } 407 408 streamClient.CloseSend() 409 410 return resp, nil 411 } 412 413 func (c *testGRPCClient) PrintStdio(stdout, stderr []byte) { 414 _, err := c.Client.PrintStdio(context.Background(), &grpctest.PrintStdioRequest{ 415 Stdout: stdout, 416 Stderr: stderr, 417 }) 418 if err != nil { 419 panic(err) 420 } 421 } 422 423 func helperProcess(s ...string) *exec.Cmd { 424 cs := []string{"-test.run=TestHelperProcess", "--"} 425 cs = append(cs, s...) 426 env := []string{ 427 "GO_WANT_HELPER_PROCESS=1", 428 } 429 430 cmd := exec.Command(os.Args[0], cs...) 431 cmd.Env = append(env, os.Environ()...) 432 return cmd 433 } 434 435 // This is not a real test. This is just a helper process kicked off by 436 // tests. 437 func TestHelperProcess(*testing.T) { 438 if os.Getenv("GO_WANT_HELPER_PROCESS") != "1" { 439 return 440 } 441 442 defer os.Exit(0) 443 444 args := os.Args 445 for len(args) > 0 { 446 if args[0] == "--" { 447 args = args[1:] 448 break 449 } 450 451 args = args[1:] 452 } 453 454 if len(args) == 0 { 455 fmt.Fprintf(os.Stderr, "No command\n") 456 os.Exit(2) 457 } 458 459 // override testPluginMap with one that uses 460 // hclog logger on its implementation 461 pluginLogger := hclog.New(&hclog.LoggerOptions{ 462 Level: hclog.Trace, 463 Output: os.Stderr, 464 JSONFormat: true, 465 }) 466 467 testPlugin := &testInterfaceImpl{ 468 logger: pluginLogger, 469 } 470 471 testPluginMap := map[string]Plugin{ 472 "test": &testInterfacePlugin{Impl: testPlugin}, 473 } 474 475 testGRPCPluginMap := map[string]Plugin{ 476 "test": &testGRPCInterfacePlugin{Impl: testPlugin}, 477 } 478 479 cmd, args := args[0], args[1:] 480 switch cmd { 481 case "bad-version": 482 // If we have an arg, we write there on start 483 if len(args) > 0 { 484 path := args[0] 485 err := ioutil.WriteFile(path, []byte("foo"), 0644) 486 if err != nil { 487 panic(err) 488 } 489 } 490 491 fmt.Printf("%d|%d1|tcp|:1234\n", CoreProtocolVersion, testHandshake.ProtocolVersion) 492 <-make(chan int) 493 case "invalid-rpc-address": 494 fmt.Println("lolinvalid") 495 case "mock": 496 fmt.Printf("%d|%d|tcp|:1234\n", CoreProtocolVersion, testHandshake.ProtocolVersion) 497 <-make(chan int) 498 case "start-timeout": 499 time.Sleep(1 * time.Minute) 500 os.Exit(1) 501 case "stderr": 502 fmt.Printf("%d|%d|tcp|:1234\n", CoreProtocolVersion, testHandshake.ProtocolVersion) 503 os.Stderr.WriteString("HELLO\n") 504 os.Stderr.WriteString("WORLD\n") 505 case "stderr-json": 506 // write values that might be JSON, but aren't KVs 507 fmt.Printf("%d|%d|tcp|:1234\n", CoreProtocolVersion, testHandshake.ProtocolVersion) 508 os.Stderr.WriteString("[\"HELLO\"]\n") 509 os.Stderr.WriteString("12345\n") 510 os.Stderr.WriteString("{\"a\":1}\n") 511 case "level-warn-text": 512 // write values that might be JSON, but aren't KVs 513 fmt.Printf("%d|%d|tcp|:1234\n", CoreProtocolVersion, testHandshake.ProtocolVersion) 514 os.Stderr.WriteString("[WARN] test line 98765\n") 515 case "stdin": 516 fmt.Printf("%d|%d|tcp|:1234\n", CoreProtocolVersion, testHandshake.ProtocolVersion) 517 data := make([]byte, 5) 518 if _, err := os.Stdin.Read(data); err != nil { 519 log.Printf("stdin read error: %s", err) 520 os.Exit(100) 521 } 522 523 if string(data) == "hello" { 524 os.Exit(0) 525 } 526 527 os.Exit(1) 528 case "cleanup": 529 // Create a defer to write the file. This tests that we get cleaned 530 // up properly versus just calling os.Exit 531 path := args[0] 532 defer func() { 533 err := ioutil.WriteFile(path, []byte("foo"), 0644) 534 if err != nil { 535 panic(err) 536 } 537 }() 538 539 Serve(&ServeConfig{ 540 HandshakeConfig: testHandshake, 541 Plugins: testPluginMap, 542 }) 543 544 // Exit 545 return 546 case "test-grpc": 547 Serve(&ServeConfig{ 548 HandshakeConfig: testHandshake, 549 Plugins: testGRPCPluginMap, 550 GRPCServer: DefaultGRPCServer, 551 }) 552 553 // Shouldn't reach here but make sure we exit anyways 554 os.Exit(0) 555 case "test-grpc-tls": 556 // Serve! 557 Serve(&ServeConfig{ 558 HandshakeConfig: testHandshake, 559 Plugins: testGRPCPluginMap, 560 GRPCServer: DefaultGRPCServer, 561 TLSProvider: helperTLSProvider, 562 }) 563 564 // Shouldn't reach here but make sure we exit anyways 565 os.Exit(0) 566 case "test-interface": 567 Serve(&ServeConfig{ 568 HandshakeConfig: testHandshake, 569 Plugins: testPluginMap, 570 }) 571 572 // Shouldn't reach here but make sure we exit anyways 573 os.Exit(0) 574 case "test-interface-logger-netrpc": 575 Serve(&ServeConfig{ 576 HandshakeConfig: testHandshake, 577 Plugins: testPluginMap, 578 }) 579 // Shouldn't reach here but make sure we exit anyways 580 os.Exit(0) 581 case "test-interface-logger-grpc": 582 Serve(&ServeConfig{ 583 HandshakeConfig: testHandshake, 584 Plugins: testPluginMap, 585 GRPCServer: DefaultGRPCServer, 586 }) 587 // Shouldn't reach here but make sure we exit anyways 588 os.Exit(0) 589 case "test-interface-daemon": 590 // Serve! 591 Serve(&ServeConfig{ 592 HandshakeConfig: testHandshake, 593 Plugins: testPluginMap, 594 }) 595 596 // Shouldn't reach here but make sure we exit anyways 597 os.Exit(0) 598 case "test-interface-tls": 599 // Serve! 600 Serve(&ServeConfig{ 601 HandshakeConfig: testHandshake, 602 Plugins: testPluginMap, 603 TLSProvider: helperTLSProvider, 604 }) 605 606 // Shouldn't reach here but make sure we exit anyways 607 os.Exit(0) 608 609 case "test-interface-mtls": 610 // Serve! 611 Serve(&ServeConfig{ 612 HandshakeConfig: testVersionedHandshake, 613 Plugins: testPluginMap, 614 }) 615 616 // Shouldn't reach here but make sure we exit anyways 617 os.Exit(0) 618 619 case "test-versioned-plugins": 620 // Serve! 621 Serve(&ServeConfig{ 622 HandshakeConfig: testVersionedHandshake, 623 VersionedPlugins: map[int]PluginSet{ 624 2: testGRPCPluginMap, 625 }, 626 GRPCServer: DefaultGRPCServer, 627 TLSProvider: helperTLSProvider, 628 }) 629 630 // Shouldn't reach here but make sure we exit anyways 631 os.Exit(0) 632 case "test-proto-upgraded-plugin": 633 // Serve 2 plugins over different protocols 634 Serve(&ServeConfig{ 635 HandshakeConfig: testVersionedHandshake, 636 VersionedPlugins: map[int]PluginSet{ 637 1: PluginSet{ 638 "old": &testInterfacePlugin{Impl: testPlugin}, 639 }, 640 2: testGRPCPluginMap, 641 }, 642 GRPCServer: DefaultGRPCServer, 643 TLSProvider: helperTLSProvider, 644 }) 645 646 // Shouldn't reach here but make sure we exit anyways 647 os.Exit(0) 648 case "test-proto-upgraded-client": 649 // Serve 2 plugins over different protocols 650 Serve(&ServeConfig{ 651 HandshakeConfig: HandshakeConfig{ 652 ProtocolVersion: 2, 653 MagicCookieKey: "TEST_MAGIC_COOKIE", 654 MagicCookieValue: "test", 655 }, 656 Plugins: testGRPCPluginMap, 657 GRPCServer: DefaultGRPCServer, 658 TLSProvider: helperTLSProvider, 659 }) 660 661 // Shouldn't reach here but make sure we exit anyways 662 os.Exit(0) 663 case "test-mtls": 664 // Serve 2 plugins over different protocols 665 Serve(&ServeConfig{ 666 HandshakeConfig: HandshakeConfig{ 667 ProtocolVersion: 2, 668 MagicCookieKey: "TEST_MAGIC_COOKIE", 669 MagicCookieValue: "test", 670 }, 671 Plugins: testGRPCPluginMap, 672 GRPCServer: DefaultGRPCServer, 673 }) 674 675 // Shouldn't reach here but make sure we exit anyways 676 os.Exit(0) 677 case "test-skip-host-env-true": 678 fmt.Printf("%d|%d|tcp|:1234\n", CoreProtocolVersion, testHandshake.ProtocolVersion) 679 if os.Getenv("PLUGIN_TEST_SKIP_HOST_ENV") == "" { 680 os.Exit(0) 681 } 682 683 os.Exit(1) 684 case "test-skip-host-env-false": 685 fmt.Printf("%d|%d|tcp|:1234\n", CoreProtocolVersion, testHandshake.ProtocolVersion) 686 if os.Getenv("PLUGIN_TEST_SKIP_HOST_ENV") != "" { 687 os.Exit(0) 688 } 689 690 os.Exit(1) 691 case "mux-grpc-with-old-plugin": 692 // gRPC broker multiplexing requested, but plugin has no awareness of the 693 // feature, so just prints 6 segments in the protocol negotiation line. 694 // Client should fail with a helpful error. 695 if os.Getenv(envMultiplexGRPC) == "" { 696 fmt.Println("failed precondition for mux test") 697 os.Exit(1) 698 } 699 fmt.Printf("%d|%d|tcp|:1234|%s|\n", CoreProtocolVersion, testHandshake.ProtocolVersion, ProtocolGRPC) 700 <-make(chan int) 701 case "mux-grpc-with-unsupported-plugin": 702 // gRPC broker multiplexing requested, but plugin explicitly does not 703 // support it. Client should fail with a helpful error. 704 if os.Getenv(envMultiplexGRPC) == "" { 705 fmt.Println("failed precondition for mux test") 706 os.Exit(1) 707 } 708 fmt.Printf("%d|%d|tcp|:1234|%s||false\n", CoreProtocolVersion, testHandshake.ProtocolVersion, ProtocolGRPC) 709 <-make(chan int) 710 default: 711 fmt.Fprintf(os.Stderr, "Unknown command: %q\n", cmd) 712 os.Exit(2) 713 } 714 } 715 716 func helperTLSProvider() (*tls.Config, error) { 717 serverCert, err := tls.X509KeyPair([]byte(TestClusterServerCert), []byte(TestClusterServerKey)) 718 if err != nil { 719 return nil, err 720 } 721 722 rootCAs := x509.NewCertPool() 723 rootCAs.AppendCertsFromPEM([]byte(TestClusterCACert)) 724 tlsConfig := &tls.Config{ 725 Certificates: []tls.Certificate{serverCert}, 726 RootCAs: rootCAs, 727 ClientCAs: rootCAs, 728 ClientAuth: tls.VerifyClientCertIfGiven, 729 ServerName: "127.0.0.1", 730 } 731 tlsConfig.BuildNameToCertificate() 732 733 return tlsConfig, nil 734 } 735 736 const ( 737 TestClusterCACert = `-----BEGIN CERTIFICATE----- 738 MIIDPjCCAiagAwIBAgIUfIKsF2VPT7sdFcKOHJH2Ii6K4MwwDQYJKoZIhvcNAQEL 739 BQAwFjEUMBIGA1UEAxMLbXl2YXVsdC5jb20wIBcNMTYwNTAyMTYwNTQyWhgPMjA2 740 NjA0MjAxNjA2MTJaMBYxFDASBgNVBAMTC215dmF1bHQuY29tMIIBIjANBgkqhkiG 741 9w0BAQEFAAOCAQ8AMIIBCgKCAQEAuOimEXawD2qBoLCFP3Skq5zi1XzzcMAJlfdS 742 xz9hfymuJb+cN8rB91HOdU9wQCwVKnkUtGWxUnMp0tT0uAZj5NzhNfyinf0JGAbP 743 67HDzVZhGBHlHTjPX0638yaiUx90cTnucX0N20SgCYct29dMSgcPl+W78D3Jw3xE 744 JsHQPYS9ASe2eONxG09F/qNw7w/RO5/6WYoV2EmdarMMxq52pPe2chtNMQdSyOUb 745 cCcIZyk4QVFZ1ZLl6jTnUPb+JoCx1uMxXvMek4NF/5IL0Wr9dw2gKXKVKoHDr6SY 746 WrCONRw61A5Zwx1V+kn73YX3USRlkufQv/ih6/xThYDAXDC9cwIDAQABo4GBMH8w 747 DgYDVR0PAQH/BAQDAgEGMA8GA1UdEwEB/wQFMAMBAf8wHQYDVR0OBBYEFOuKvPiU 748 G06iHkRXAOeMiUdBfHFyMB8GA1UdIwQYMBaAFOuKvPiUG06iHkRXAOeMiUdBfHFy 749 MBwGA1UdEQQVMBOCC215dmF1bHQuY29thwR/AAABMA0GCSqGSIb3DQEBCwUAA4IB 750 AQBcN/UdAMzc7UjRdnIpZvO+5keBGhL/vjltnGM1dMWYHa60Y5oh7UIXF+P1RdNW 751 n7g80lOyvkSR15/r1rDkqOK8/4oruXU31EcwGhDOC4hU6yMUy4ltV/nBoodHBXNh 752 MfKiXeOstH1vdI6G0P6W93Bcww6RyV1KH6sT2dbETCw+iq2VN9CrruGIWzd67UT/ 753 spe/kYttr3UYVV3O9kqgffVVgVXg/JoRZ3J7Hy2UEXfh9UtWNanDlRuXaZgE9s/d 754 CpA30CHpNXvKeyNeW2ktv+2nAbSpvNW+e6MecBCTBIoDSkgU8ShbrzmDKVwNN66Q 755 5gn6KxUPBKHEtNzs5DgGM7nq 756 -----END CERTIFICATE-----` 757 758 TestClusterServerCert = `-----BEGIN CERTIFICATE----- 759 MIIDtzCCAp+gAwIBAgIUBLqh6ctGWVDUxFhxJX7m6S/bnrcwDQYJKoZIhvcNAQEL 760 BQAwFjEUMBIGA1UEAxMLbXl2YXVsdC5jb20wIBcNMTYwNTAyMTYwOTI2WhgPMjA2 761 NjA0MjAxNTA5NTZaMBsxGTAXBgNVBAMTEGNlcnQubXl2YXVsdC5jb20wggEiMA0G 762 CSqGSIb3DQEBAQUAA4IBDwAwggEKAoIBAQDY3gPB29kkdbu0mPO6J0efagQhSiXB 763 9OyDuLf5sMk6CVDWVWal5hISkyBmw/lXgF7qC2XFKivpJOrcGQd5Ep9otBqyJLzI 764 b0IWdXuPIrVnXDwcdWr86ybX2iC42zKWfbXgjzGijeAVpl0UJLKBj+fk5q6NvkRL 765 5FUL6TRV7Krn9mrmnrV9J5IqV15pTd9W2aVJ6IqWvIPCACtZKulqWn4707uy2X2W 766 1Stq/5qnp1pDshiGk1VPyxCwQ6yw3iEcgecbYo3vQfhWcv7Q8LpSIM9ZYpXu6OmF 767 +czqRZS9gERl+wipmmrN1MdYVrTuQem21C/PNZ4jo4XUk1SFx6JrcA+lAgMBAAGj 768 gfUwgfIwHQYDVR0lBBYwFAYIKwYBBQUHAwEGCCsGAQUFBwMCMB0GA1UdDgQWBBSe 769 Cl9WV3BjGCwmS/KrDSLRjfwyqjAfBgNVHSMEGDAWgBTrirz4lBtOoh5EVwDnjIlH 770 QXxxcjA7BggrBgEFBQcBAQQvMC0wKwYIKwYBBQUHMAKGH2h0dHA6Ly8xMjcuMC4w 771 LjE6ODIwMC92MS9wa2kvY2EwIQYDVR0RBBowGIIQY2VydC5teXZhdWx0LmNvbYcE 772 fwAAATAxBgNVHR8EKjAoMCagJKAihiBodHRwOi8vMTI3LjAuMC4xOjgyMDAvdjEv 773 cGtpL2NybDANBgkqhkiG9w0BAQsFAAOCAQEAWGholPN8buDYwKbUiDavbzjsxUIX 774 lU4MxEqOHw7CD3qIYIauPboLvB9EldBQwhgOOy607Yvdg3rtyYwyBFwPhHo/hK3Z 775 6mn4hc6TF2V+AUdHBvGzp2dbYLeo8noVoWbQ/lBulggwlIHNNF6+a3kALqsqk1Ch 776 f/hzsjFnDhAlNcYFgG8TgfE2lE/FckvejPqBffo7Q3I+wVAw0buqiz5QL81NOT+D 777 Y2S9LLKLRaCsWo9wRU1Az4Rhd7vK5SEMh16jJ82GyEODWPvuxOTI1MnzfnbWyLYe 778 TTp6YBjGMVf1I6NEcWNur7U17uIOiQjMZ9krNvoMJ1A/cxCoZ98QHgcIPg== 779 -----END CERTIFICATE-----` 780 781 TestClusterServerKey = `-----BEGIN RSA PRIVATE KEY----- 782 MIIEpAIBAAKCAQEA2N4DwdvZJHW7tJjzuidHn2oEIUolwfTsg7i3+bDJOglQ1lVm 783 peYSEpMgZsP5V4Be6gtlxSor6STq3BkHeRKfaLQasiS8yG9CFnV7jyK1Z1w8HHVq 784 /Osm19oguNsyln214I8xoo3gFaZdFCSygY/n5Oaujb5ES+RVC+k0Veyq5/Zq5p61 785 fSeSKldeaU3fVtmlSeiKlryDwgArWSrpalp+O9O7stl9ltUrav+ap6daQ7IYhpNV 786 T8sQsEOssN4hHIHnG2KN70H4VnL+0PC6UiDPWWKV7ujphfnM6kWUvYBEZfsIqZpq 787 zdTHWFa07kHpttQvzzWeI6OF1JNUhceia3APpQIDAQABAoIBAQCH3vEzr+3nreug 788 RoPNCXcSJXXY9X+aeT0FeeGqClzIg7Wl03OwVOjVwl/2gqnhbIgK0oE8eiNwurR6 789 mSPZcxV0oAJpwiKU4T/imlCDaReGXn86xUX2l82KRxthNdQH/VLKEmzij0jpx4Vh 790 bWx5SBPdkbmjDKX1dmTiRYWIn/KjyNPvNvmtwdi8Qluhf4eJcNEUr2BtblnGOmfL 791 FdSu+brPJozpoQ1QdDnbAQRgqnh7Shl0tT85whQi0uquqIj1gEOGVjmBvDDnL3GV 792 WOENTKqsmIIoEzdZrql1pfmYTk7WNaD92bfpN128j8BF7RmAV4/DphH0pvK05y9m 793 tmRhyHGxAoGBAOV2BBocsm6xup575VqmFN+EnIOiTn+haOvfdnVsyQHnth63fOQx 794 PNtMpTPR1OMKGpJ13e2bV0IgcYRsRkScVkUtoa/17VIgqZXffnJJ0A/HT67uKBq3 795 8o7RrtyK5N20otw0lZHyqOPhyCdpSsurDhNON1kPVJVYY4N1RiIxfut/AoGBAPHz 796 HfsJ5ZkyELE9N/r4fce04lprxWH+mQGK0/PfjS9caXPhj/r5ZkVMvzWesF3mmnY8 797 goE5S35TuTvV1+6rKGizwlCFAQlyXJiFpOryNWpLwCmDDSzLcm+sToAlML3tMgWU 798 jM3dWHx3C93c3ft4rSWJaUYI9JbHsMzDW6Yh+GbbAoGBANIbKwxh5Hx5XwEJP2yu 799 kIROYCYkMy6otHLujgBdmPyWl+suZjxoXWoMl2SIqR8vPD+Jj6mmyNJy9J6lqf3f 800 DRuQ+fEuBZ1i7QWfvJ+XuN0JyovJ5Iz6jC58D1pAD+p2IX3y5FXcVQs8zVJRFjzB 801 p0TEJOf2oqORaKWRd6ONoMKvAoGALKu6aVMWdQZtVov6/fdLIcgf0pn7Q3CCR2qe 802 X3Ry2L+zKJYIw0mwvDLDSt8VqQCenB3n6nvtmFFU7ds5lvM67rnhsoQcAOaAehiS 803 rl4xxoJd5Ewx7odRhZTGmZpEOYzFo4odxRSM9c30/u18fqV1Mm0AZtHYds4/sk6P 804 aUj0V+kCgYBMpGrJk8RSez5g0XZ35HfpI4ENoWbiwB59FIpWsLl2LADEh29eC455 805 t9Muq7MprBVBHQo11TMLLFxDIjkuMho/gcKgpYXCt0LfiNm8EZehvLJUXH+3WqUx 806 we6ywrbFCs6LaxaOCtTiLsN+GbZCatITL0UJaeBmTAbiw0KQjUuZPQ== 807 -----END RSA PRIVATE KEY-----` 808 )