client.go 3.4 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132
  1. package client
  2. import (
  3. "context"
  4. "crypto/tls"
  5. "crypto/x509"
  6. "io/ioutil"
  7. "github.com/grpc-ecosystem/grpc-opentracing/go/otgrpc"
  8. controlapi "github.com/moby/buildkit/api/services/control"
  9. "github.com/moby/buildkit/util/appdefaults"
  10. opentracing "github.com/opentracing/opentracing-go"
  11. "github.com/pkg/errors"
  12. "google.golang.org/grpc"
  13. "google.golang.org/grpc/credentials"
  14. )
  15. type Client struct {
  16. conn *grpc.ClientConn
  17. }
  18. type ClientOpt interface{}
  19. // New returns a new buildkit client. Address can be empty for the system-default address.
  20. func New(ctx context.Context, address string, opts ...ClientOpt) (*Client, error) {
  21. gopts := []grpc.DialOption{
  22. grpc.WithDialer(dialer),
  23. grpc.FailOnNonTempDialError(true),
  24. }
  25. needWithInsecure := true
  26. for _, o := range opts {
  27. if _, ok := o.(*withBlockOpt); ok {
  28. gopts = append(gopts, grpc.WithBlock(), grpc.FailOnNonTempDialError(true))
  29. }
  30. if credInfo, ok := o.(*withCredentials); ok {
  31. opt, err := loadCredentials(credInfo)
  32. if err != nil {
  33. return nil, err
  34. }
  35. gopts = append(gopts, opt)
  36. needWithInsecure = false
  37. }
  38. if wt, ok := o.(*withTracer); ok {
  39. gopts = append(gopts,
  40. grpc.WithUnaryInterceptor(otgrpc.OpenTracingClientInterceptor(wt.tracer, otgrpc.LogPayloads())),
  41. grpc.WithStreamInterceptor(otgrpc.OpenTracingStreamClientInterceptor(wt.tracer)))
  42. }
  43. }
  44. if needWithInsecure {
  45. gopts = append(gopts, grpc.WithInsecure())
  46. }
  47. if address == "" {
  48. address = appdefaults.Address
  49. }
  50. conn, err := grpc.DialContext(ctx, address, gopts...)
  51. if err != nil {
  52. return nil, errors.Wrapf(err, "failed to dial %q . make sure buildkitd is running", address)
  53. }
  54. c := &Client{
  55. conn: conn,
  56. }
  57. return c, nil
  58. }
  59. func (c *Client) controlClient() controlapi.ControlClient {
  60. return controlapi.NewControlClient(c.conn)
  61. }
  62. func (c *Client) Close() error {
  63. return c.conn.Close()
  64. }
  65. type withBlockOpt struct{}
  66. func WithBlock() ClientOpt {
  67. return &withBlockOpt{}
  68. }
  69. type withCredentials struct {
  70. ServerName string
  71. CACert string
  72. Cert string
  73. Key string
  74. }
  75. // WithCredentials configures the TLS parameters of the client.
  76. // Arguments:
  77. // * serverName: specifies the name of the target server
  78. // * ca: specifies the filepath of the CA certificate to use for verification
  79. // * cert: specifies the filepath of the client certificate
  80. // * key: specifies the filepath of the client key
  81. func WithCredentials(serverName, ca, cert, key string) ClientOpt {
  82. return &withCredentials{serverName, ca, cert, key}
  83. }
  84. func loadCredentials(opts *withCredentials) (grpc.DialOption, error) {
  85. ca, err := ioutil.ReadFile(opts.CACert)
  86. if err != nil {
  87. return nil, errors.Wrap(err, "could not read ca certificate")
  88. }
  89. certPool := x509.NewCertPool()
  90. if ok := certPool.AppendCertsFromPEM(ca); !ok {
  91. return nil, errors.New("failed to append ca certs")
  92. }
  93. cfg := &tls.Config{
  94. ServerName: opts.ServerName,
  95. RootCAs: certPool,
  96. }
  97. // we will produce an error if the user forgot about either cert or key if at least one is specified
  98. if opts.Cert != "" || opts.Key != "" {
  99. cert, err := tls.LoadX509KeyPair(opts.Cert, opts.Key)
  100. if err != nil {
  101. return nil, errors.Wrap(err, "could not read certificate/key")
  102. }
  103. cfg.Certificates = []tls.Certificate{cert}
  104. cfg.BuildNameToCertificate()
  105. }
  106. return grpc.WithTransportCredentials(credentials.NewTLS(cfg)), nil
  107. }
  108. func WithTracer(t opentracing.Tracer) ClientOpt {
  109. return &withTracer{t}
  110. }
  111. type withTracer struct {
  112. tracer opentracing.Tracer
  113. }