feat: conditionally pull images

This commit is contained in:
Rob Watson 2025-03-04 21:44:36 +01:00
parent 8b65a3573c
commit f5bfa62330

View File

@ -62,9 +62,11 @@ type Client struct {
id shortid.ID
ctx context.Context
cancel context.CancelFunc
mu sync.Mutex
wg sync.WaitGroup
apiClient DockerClient
networkID string
pulledImages map[string]struct{}
logger *slog.Logger
}
@ -84,6 +86,7 @@ func NewClient(ctx context.Context, apiClient DockerClient, logger *slog.Logger)
cancel: cancel,
apiClient: apiClient,
networkID: network.ID,
pulledImages: make(map[string]struct{}),
logger: logger,
}
@ -154,15 +157,10 @@ func (a *Client) RunContainer(ctx context.Context, params RunContainerParams) (<
defer a.wg.Done()
defer close(errC)
containerStateC <- domain.Container{State: "pulling"}
pullReader, err := a.apiClient.ImagePull(ctx, params.ContainerConfig.Image, image.PullOptions{})
if err != nil {
if err := a.pullImageIfNeeded(ctx, params.ContainerConfig.Image, containerStateC); err != nil {
sendError(fmt.Errorf("image pull: %w", err))
return
}
_, _ = io.Copy(io.Discard, pullReader)
_ = pullReader.Close()
containerConfig := *params.ContainerConfig
containerConfig.Labels = make(map[string]string)
@ -208,6 +206,32 @@ func (a *Client) RunContainer(ctx context.Context, params RunContainerParams) (<
return containerStateC, errC
}
// pullImageIfNeeded pulls the image if it has not already been pulled.
func (a *Client) pullImageIfNeeded(ctx context.Context, imageName string, containerStateC chan<- domain.Container) error {
a.mu.Lock()
_, ok := a.pulledImages[imageName]
a.mu.Unlock()
if ok {
return nil
}
containerStateC <- domain.Container{State: "pulling"}
pullReader, err := a.apiClient.ImagePull(ctx, imageName, image.PullOptions{})
if err != nil {
return err
}
_, _ = io.Copy(io.Discard, pullReader)
_ = pullReader.Close()
a.mu.Lock()
a.pulledImages[imageName] = struct{}{}
a.mu.Unlock()
return nil
}
// runContainerLoop is the control loop for a single container. It returns only
// when the container exits.
func (a *Client) runContainerLoop(