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 }