github.com/pdmccormick/importable-docker-buildx@v0.0.0-20240426161518-e47091289030/driver/remote/driver.go (about)

     1  package remote
     2  
     3  import (
     4  	"context"
     5  	"crypto/tls"
     6  	"crypto/x509"
     7  	"net"
     8  	"os"
     9  	"strings"
    10  	"time"
    11  
    12  	"github.com/docker/buildx/driver"
    13  	util "github.com/docker/buildx/driver/remote/util"
    14  	"github.com/docker/buildx/util/progress"
    15  	"github.com/moby/buildkit/client"
    16  	"github.com/moby/buildkit/client/connhelper"
    17  	"github.com/pkg/errors"
    18  )
    19  
    20  type Driver struct {
    21  	factory driver.Factory
    22  	driver.InitConfig
    23  
    24  	// if you add fields, remember to update docs:
    25  	// https://github.com/docker/docs/blob/main/content/build/drivers/remote.md
    26  	*tlsOpts
    27  	defaultLoad bool
    28  }
    29  
    30  type tlsOpts struct {
    31  	serverName string
    32  	caCert     string
    33  	cert       string
    34  	key        string
    35  }
    36  
    37  func (d *Driver) Bootstrap(ctx context.Context, l progress.Logger) error {
    38  	c, err := d.Client(ctx)
    39  	if err != nil {
    40  		return err
    41  	}
    42  	return progress.Wrap("[internal] waiting for connection", l, func(_ progress.SubLogger) error {
    43  		ctx, cancel := context.WithTimeout(ctx, 20*time.Second)
    44  		defer cancel()
    45  		return c.Wait(ctx)
    46  	})
    47  }
    48  
    49  func (d *Driver) Info(ctx context.Context) (*driver.Info, error) {
    50  	c, err := d.Client(ctx)
    51  	if err != nil {
    52  		return &driver.Info{
    53  			Status: driver.Inactive,
    54  		}, nil
    55  	}
    56  
    57  	if _, err := c.ListWorkers(ctx); err != nil {
    58  		return &driver.Info{
    59  			Status: driver.Inactive,
    60  		}, nil
    61  	}
    62  
    63  	return &driver.Info{
    64  		Status: driver.Running,
    65  	}, nil
    66  }
    67  
    68  func (d *Driver) Version(ctx context.Context) (string, error) {
    69  	return "", nil
    70  }
    71  
    72  func (d *Driver) Stop(ctx context.Context, force bool) error {
    73  	return nil
    74  }
    75  
    76  func (d *Driver) Rm(ctx context.Context, force, rmVolume, rmDaemon bool) error {
    77  	return nil
    78  }
    79  
    80  func (d *Driver) Client(ctx context.Context, opts ...client.ClientOpt) (*client.Client, error) {
    81  	opts = append([]client.ClientOpt{
    82  		client.WithContextDialer(func(ctx context.Context, _ string) (net.Conn, error) {
    83  			return d.Dial(ctx)
    84  		}),
    85  	}, opts...)
    86  	return client.New(ctx, "", opts...)
    87  }
    88  
    89  func (d *Driver) Dial(ctx context.Context) (net.Conn, error) {
    90  	addr := d.InitConfig.EndpointAddr
    91  	ch, err := connhelper.GetConnectionHelper(addr)
    92  	if err != nil {
    93  		return nil, err
    94  	}
    95  	if ch != nil {
    96  		return ch.ContextDialer(ctx, addr)
    97  	}
    98  
    99  	network, addr, ok := strings.Cut(addr, "://")
   100  	if !ok {
   101  		return nil, errors.Errorf("invalid endpoint address: %s", d.InitConfig.EndpointAddr)
   102  	}
   103  
   104  	conn, err := util.DialContext(ctx, network, addr)
   105  
   106  	if err != nil {
   107  		return nil, errors.WithStack(err)
   108  	}
   109  
   110  	if d.tlsOpts != nil {
   111  		cfg, err := loadTLS(d.tlsOpts)
   112  		if err != nil {
   113  			return nil, errors.Wrap(err, "error loading tls config")
   114  		}
   115  		conn = tls.Client(conn, cfg)
   116  	}
   117  	return conn, nil
   118  }
   119  
   120  func loadTLS(opts *tlsOpts) (*tls.Config, error) {
   121  	cfg := &tls.Config{
   122  		ServerName: opts.serverName,
   123  		RootCAs:    x509.NewCertPool(),
   124  	}
   125  
   126  	if opts.caCert != "" {
   127  		ca, err := os.ReadFile(opts.caCert)
   128  		if err != nil {
   129  			return nil, errors.Wrap(err, "could not read ca certificate")
   130  		}
   131  		if ok := cfg.RootCAs.AppendCertsFromPEM(ca); !ok {
   132  			return nil, errors.New("failed to append ca certs")
   133  		}
   134  	}
   135  
   136  	if opts.cert != "" || opts.key != "" {
   137  		cert, err := tls.LoadX509KeyPair(opts.cert, opts.key)
   138  		if err != nil {
   139  			return nil, errors.Wrap(err, "could not read certificate/key")
   140  		}
   141  		cfg.Certificates = append(cfg.Certificates, cert)
   142  	}
   143  
   144  	return cfg, nil
   145  }
   146  
   147  func (d *Driver) Features(ctx context.Context) map[driver.Feature]bool {
   148  	return map[driver.Feature]bool{
   149  		driver.OCIExporter:    true,
   150  		driver.DockerExporter: true,
   151  		driver.CacheExport:    true,
   152  		driver.MultiPlatform:  true,
   153  		driver.DefaultLoad:    d.defaultLoad,
   154  	}
   155  }
   156  
   157  func (d *Driver) HostGatewayIP(ctx context.Context) (net.IP, error) {
   158  	return nil, errors.New("host-gateway is not supported by the remote driver")
   159  }
   160  
   161  func (d *Driver) Factory() driver.Factory {
   162  	return d.factory
   163  }
   164  
   165  func (d *Driver) IsMobyDriver() bool {
   166  	return false
   167  }
   168  
   169  func (d *Driver) Config() driver.InitConfig {
   170  	return d.InitConfig
   171  }