github.com/tilt-dev/tilt@v0.36.0/internal/docker/switch.go (about)

     1  package docker
     2  
     3  import (
     4  	"context"
     5  	"io"
     6  	"sync"
     7  
     8  	"github.com/distribution/reference"
     9  	"github.com/docker/docker/api/types"
    10  	typescontainer "github.com/docker/docker/api/types/container"
    11  	"github.com/docker/docker/api/types/filters"
    12  	typesimage "github.com/docker/docker/api/types/image"
    13  	"golang.org/x/sync/errgroup"
    14  
    15  	"github.com/tilt-dev/tilt/internal/container"
    16  	"github.com/tilt-dev/tilt/pkg/apis/core/v1alpha1"
    17  	"github.com/tilt-dev/tilt/pkg/model"
    18  )
    19  
    20  // A Cli implementation that lets us switch back and forth between a local
    21  // Docker instance and one that lives in our K8s cluster.
    22  
    23  type switchCli struct {
    24  	localCli   LocalClient
    25  	clusterCli ClusterClient
    26  	orc        model.Orchestrator
    27  	mu         sync.Mutex
    28  }
    29  
    30  var _ Client = &switchCli{}
    31  var _ CompositeClient = &switchCli{}
    32  
    33  func ProvideSwitchCli(clusterCli ClusterClient, localCli LocalClient) CompositeClient {
    34  	return &switchCli{
    35  		localCli:   localCli,
    36  		clusterCli: clusterCli,
    37  		orc:        model.OrchestratorK8s,
    38  	}
    39  }
    40  
    41  var orcKey model.Orchestrator
    42  
    43  // WithOrchestrator returns a Context with the current orchestrator set.
    44  func WithOrchestrator(ctx context.Context, orc model.Orchestrator) context.Context {
    45  	return context.WithValue(ctx, orcKey, orc)
    46  }
    47  
    48  func (c *switchCli) client(ctx context.Context) Client {
    49  	c.mu.Lock()
    50  	defer c.mu.Unlock()
    51  	orc, ok := ctx.Value(orcKey).(model.Orchestrator)
    52  	if ok {
    53  		return c.ForOrchestrator(orc)
    54  	}
    55  	return c.ForOrchestrator(c.orc)
    56  }
    57  
    58  func (c *switchCli) SetOrchestrator(orc model.Orchestrator) {
    59  	c.mu.Lock()
    60  	defer c.mu.Unlock()
    61  	c.orc = orc
    62  }
    63  func (c *switchCli) ForOrchestrator(orc model.Orchestrator) Client {
    64  	if orc == model.OrchestratorK8s {
    65  		return c.clusterCli
    66  	}
    67  	return c.localCli
    68  }
    69  
    70  func (c *switchCli) CheckConnected() error {
    71  	return c.client(context.Background()).CheckConnected()
    72  }
    73  func (c *switchCli) Env() Env {
    74  	return c.client(context.Background()).Env()
    75  }
    76  func (c *switchCli) BuilderVersion(ctx context.Context) (types.BuilderVersion, error) {
    77  	return c.client(ctx).BuilderVersion(ctx)
    78  }
    79  func (c *switchCli) ServerVersion(ctx context.Context) (types.Version, error) {
    80  	return c.client(ctx).ServerVersion(ctx)
    81  }
    82  func (c *switchCli) ContainerLogs(ctx context.Context, containerID string, options typescontainer.LogsOptions) (io.ReadCloser, error) {
    83  	return c.client(ctx).ContainerLogs(ctx, containerID, options)
    84  }
    85  func (c *switchCli) ContainerInspect(ctx context.Context, containerID string) (types.ContainerJSON, error) {
    86  	return c.client(ctx).ContainerInspect(ctx, containerID)
    87  }
    88  func (c *switchCli) ContainerList(ctx context.Context, options typescontainer.ListOptions) ([]types.Container, error) {
    89  	return c.client(ctx).ContainerList(ctx, options)
    90  }
    91  func (c *switchCli) ContainerRestartNoWait(ctx context.Context, containerID string) error {
    92  	return c.client(ctx).ContainerRestartNoWait(ctx, containerID)
    93  }
    94  func (c *switchCli) Run(ctx context.Context, opts RunConfig) (RunResult, error) {
    95  	return c.client(ctx).Run(ctx, opts)
    96  }
    97  func (c *switchCli) ExecInContainer(ctx context.Context, cID container.ID, cmd model.Cmd, in io.Reader, out io.Writer) error {
    98  	return c.client(ctx).ExecInContainer(ctx, cID, cmd, in, out)
    99  }
   100  func (c *switchCli) ImagePull(ctx context.Context, ref reference.Named) (reference.Canonical, error) {
   101  	return c.client(ctx).ImagePull(ctx, ref)
   102  }
   103  func (c *switchCli) ImagePush(ctx context.Context, ref reference.NamedTagged) (io.ReadCloser, error) {
   104  	return c.client(ctx).ImagePush(ctx, ref)
   105  }
   106  func (c *switchCli) ImageBuild(ctx context.Context, g *errgroup.Group, buildContext io.Reader, options BuildOptions) (types.ImageBuildResponse, error) {
   107  	return c.client(ctx).ImageBuild(ctx, g, buildContext, options)
   108  }
   109  func (c *switchCli) ImageTag(ctx context.Context, source, target string) error {
   110  	return c.client(ctx).ImageTag(ctx, source, target)
   111  }
   112  func (c *switchCli) ImageInspectWithRaw(ctx context.Context, imageID string) (types.ImageInspect, []byte, error) {
   113  	return c.client(ctx).ImageInspectWithRaw(ctx, imageID)
   114  }
   115  func (c *switchCli) ImageList(ctx context.Context, options typesimage.ListOptions) ([]typesimage.Summary, error) {
   116  	return c.client(ctx).ImageList(ctx, options)
   117  }
   118  func (c *switchCli) ImageRemove(ctx context.Context, imageID string, options typesimage.RemoveOptions) ([]typesimage.DeleteResponse, error) {
   119  	return c.client(ctx).ImageRemove(ctx, imageID, options)
   120  }
   121  func (c *switchCli) NewVersionError(ctx context.Context, apiRequired, feature string) error {
   122  	return c.client(context.Background()).NewVersionError(ctx, apiRequired, feature)
   123  }
   124  func (c *switchCli) BuildCachePrune(ctx context.Context, opts types.BuildCachePruneOptions) (*types.BuildCachePruneReport, error) {
   125  	return c.client(ctx).BuildCachePrune(ctx, opts)
   126  }
   127  func (c *switchCli) ContainersPrune(ctx context.Context, pruneFilters filters.Args) (typescontainer.PruneReport, error) {
   128  	return c.client(ctx).ContainersPrune(ctx, pruneFilters)
   129  }
   130  
   131  // CompositeClient
   132  func (c *switchCli) DefaultLocalClient() Client {
   133  	return c.localCli
   134  }
   135  func (c *switchCli) DefaultClusterClient() Client {
   136  	return c.clusterCli
   137  }
   138  func (c *switchCli) ClientFor(cluster v1alpha1.Cluster) Client {
   139  	conn := cluster.Spec.Connection
   140  	if conn.Kubernetes != nil {
   141  		// TODO: pick correct client in multiple cluster situation
   142  		return c.DefaultClusterClient()
   143  	}
   144  	return c.DefaultLocalClient()
   145  }
   146  func (c *switchCli) HasMultipleClients() bool {
   147  	return c.localCli.Env().DaemonHost() != c.clusterCli.Env().DaemonHost()
   148  }