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