pkg/compose: use state consts from moby API

Signed-off-by: Sebastiaan van Stijn <github@gone.nl>
This commit is contained in:
Sebastiaan van Stijn 2025-09-06 20:19:46 +02:00 committed by Nicolas De loof
parent 02ffe2ac6c
commit f217207876
4 changed files with 58 additions and 64 deletions

View File

@ -20,23 +20,17 @@ import (
"io"
moby "github.com/docker/docker/api/types"
"github.com/docker/docker/api/types/container"
)
const (
// ContainerCreated created status
ContainerCreated = "created"
// ContainerRestarting restarting status
ContainerRestarting = "restarting"
// ContainerRunning running status
ContainerRunning = "running"
// ContainerRemoving removing status
ContainerRemoving = "removing"
// ContainerPaused paused status
ContainerPaused = "paused"
// ContainerExited exited status
ContainerExited = "exited"
// ContainerDead dead status
ContainerDead = "dead"
ContainerCreated = container.StateCreated // StateCreated indicates the container is created, but not (yet) started.
ContainerRunning = container.StateRunning // StateRunning indicates that the container is running.
ContainerPaused = container.StatePaused // StatePaused indicates that the container's current state is paused.
ContainerRestarting = container.StateRestarting // StateRestarting indicates that the container is currently restarting.
ContainerRemoving = container.StateRemoving // StateRemoving indicates that the container is being removed.
ContainerExited = container.StateExited // StateExited indicates that the container exited.
ContainerDead = container.StateDead // StateDead indicates that the container failed to be deleted. Containers in this state are attempted to be cleaned up when the daemon restarts.
)
var _ io.ReadCloser = ContainerStdout{}

View File

@ -135,7 +135,7 @@ func isOrphaned(project *types.Project) containerPredicate {
// One-off container
v, ok := c.Labels[api.OneoffLabel]
if ok && v == "True" {
return c.State == ContainerExited || c.State == ContainerDead
return c.State == container.StateExited || c.State == container.StateDead
}
// Service that is not defined in the compose model
service := c.Labels[api.ServiceLabel]

View File

@ -30,7 +30,7 @@ import (
"github.com/compose-spec/compose-go/v2/types"
"github.com/containerd/platforms"
containerType "github.com/docker/docker/api/types/container"
"github.com/docker/docker/api/types/container"
mmount "github.com/docker/docker/api/types/mount"
"github.com/docker/docker/api/types/versions"
specs "github.com/opencontainers/image-spec/specs-go/v1"
@ -152,19 +152,19 @@ func (c *convergence) ensureService(ctx context.Context, project *types.Project,
})
slices.Reverse(containers)
for i, container := range containers {
for i, ctr := range containers {
if i >= expected {
// Scale Down
// As we sorted containers, obsolete ones and/or highest number will be removed
container := container
traceOpts := append(tracing.ServiceOptions(service), tracing.ContainerOptions(container)...)
ctr := ctr
traceOpts := append(tracing.ServiceOptions(service), tracing.ContainerOptions(ctr)...)
eg.Go(tracing.SpanWrapFuncForErrGroup(ctx, "service/scale/down", traceOpts, func(ctx context.Context) error {
return c.service.stopAndRemoveContainer(ctx, container, &service, timeout, false)
return c.service.stopAndRemoveContainer(ctx, ctr, &service, timeout, false)
}))
continue
}
mustRecreate, err := c.mustRecreate(service, container, recreate)
mustRecreate, err := c.mustRecreate(service, ctr, recreate)
if err != nil {
return err
}
@ -174,9 +174,9 @@ func (c *convergence) ensureService(ctx context.Context, project *types.Project,
return err
}
i, container := i, container
eg.Go(tracing.SpanWrapFuncForErrGroup(ctx, "container/recreate", tracing.ContainerOptions(container), func(ctx context.Context) error {
recreated, err := c.service.recreateContainer(ctx, project, service, container, inherit, timeout)
i, ctr := i, ctr
eg.Go(tracing.SpanWrapFuncForErrGroup(ctx, "container/recreate", tracing.ContainerOptions(ctr), func(ctx context.Context) error {
recreated, err := c.service.recreateContainer(ctx, project, service, ctr, inherit, timeout)
updated[i] = recreated
return err
}))
@ -185,20 +185,20 @@ func (c *convergence) ensureService(ctx context.Context, project *types.Project,
// Enforce non-diverged containers are running
w := progress.ContextWriter(ctx)
name := getContainerProgressName(container)
switch container.State {
case ContainerRunning:
name := getContainerProgressName(ctr)
switch ctr.State {
case container.StateRunning:
w.Event(progress.RunningEvent(name))
case ContainerCreated:
case ContainerRestarting:
case ContainerExited:
case container.StateCreated:
case container.StateRestarting:
case container.StateExited:
default:
container := container
eg.Go(tracing.EventWrapFuncForErrGroup(ctx, "service/start", tracing.ContainerOptions(container), func(ctx context.Context) error {
return c.service.startContainer(ctx, container)
ctr := ctr
eg.Go(tracing.EventWrapFuncForErrGroup(ctx, "service/start", tracing.ContainerOptions(ctr), func(ctx context.Context) error {
return c.service.startContainer(ctx, ctr)
}))
}
updated[i] = container
updated[i] = ctr
}
next := nextContainerNumber(containers)
@ -214,8 +214,8 @@ func (c *convergence) ensureService(ctx context.Context, project *types.Project,
UseNetworkAliases: true,
Labels: mergeLabels(service.Labels, service.CustomLabels),
}
container, err := c.service.createContainer(ctx, project, service, name, number, opts)
updated[actual+i] = container
ctr, err := c.service.createContainer(ctx, project, service, name, number, opts)
updated[actual+i] = ctr
return err
}))
continue
@ -245,7 +245,7 @@ func (c *convergence) stopDependentContainers(ctx context.Context, project *type
for _, name := range dependents {
dependentStates := c.getObservedState(name)
for i, dependent := range dependentStates {
dependent.State = ContainerExited
dependent.State = container.StateExited
dependentStates[i] = dependent
}
c.setObservedState(name, dependentStates)
@ -328,7 +328,7 @@ func (c *convergence) resolveSharedNamespaces(service *types.ServiceConfig) erro
return nil
}
func (c *convergence) mustRecreate(expected types.ServiceConfig, actual containerType.Summary, policy string) (bool, error) {
func (c *convergence) mustRecreate(expected types.ServiceConfig, actual container.Summary, policy string) (bool, error) {
if policy == api.RecreateNever {
return false, nil
}
@ -360,7 +360,7 @@ func (c *convergence) mustRecreate(expected types.ServiceConfig, actual containe
return false, nil
}
func checkExpectedNetworks(expected types.ServiceConfig, actual containerType.Summary, networks map[string]string) bool {
func checkExpectedNetworks(expected types.ServiceConfig, actual container.Summary, networks map[string]string) bool {
// check the networks container is connected to are the expected ones
for net := range expected.Networks {
id := networks[net]
@ -383,7 +383,7 @@ func checkExpectedNetworks(expected types.ServiceConfig, actual containerType.Su
return false
}
func checkExpectedVolumes(expected types.ServiceConfig, actual containerType.Summary, volumes map[string]string) bool {
func checkExpectedVolumes(expected types.ServiceConfig, actual container.Summary, volumes map[string]string) bool {
// check container's volume mounts and search for the expected ones
for _, vol := range expected.Volumes {
if vol.Type != string(mmount.TypeVolume) {
@ -423,7 +423,7 @@ func getDefaultContainerName(projectName, serviceName, index string) string {
return strings.Join([]string{projectName, serviceName, index}, api.Separator)
}
func getContainerProgressName(ctr containerType.Summary) string {
func getContainerProgressName(ctr container.Summary) string {
return "Container " + getCanonicalContainerName(ctr)
}
@ -571,7 +571,7 @@ func shouldWaitForDependency(serviceName string, dependencyConfig types.ServiceD
return true, nil
}
func nextContainerNumber(containers []containerType.Summary) int {
func nextContainerNumber(containers []container.Summary) int {
maxNumber := 0
for _, c := range containers {
s, ok := c.Labels[api.ContainerNumberLabel]
@ -592,7 +592,7 @@ func nextContainerNumber(containers []containerType.Summary) int {
func (s *composeService) createContainer(ctx context.Context, project *types.Project, service types.ServiceConfig,
name string, number int, opts createOptions,
) (ctr containerType.Summary, err error) {
) (ctr container.Summary, err error) {
w := progress.ContextWriter(ctx)
eventName := "Container " + name
w.Event(progress.CreatingEvent(eventName))
@ -612,8 +612,8 @@ func (s *composeService) createContainer(ctx context.Context, project *types.Pro
}
func (s *composeService) recreateContainer(ctx context.Context, project *types.Project, service types.ServiceConfig,
replaced containerType.Summary, inherit bool, timeout *time.Duration,
) (created containerType.Summary, err error) {
replaced container.Summary, inherit bool, timeout *time.Duration,
) (created container.Summary, err error) {
w := progress.ContextWriter(ctx)
eventName := getContainerProgressName(replaced)
w.Event(progress.NewEvent(eventName, progress.Working, "Recreate"))
@ -632,7 +632,7 @@ func (s *composeService) recreateContainer(ctx context.Context, project *types.P
return created, err
}
var inherited *containerType.Summary
var inherited *container.Summary
if inherit {
inherited = &replaced
}
@ -655,12 +655,12 @@ func (s *composeService) recreateContainer(ctx context.Context, project *types.P
}
timeoutInSecond := utils.DurationSecondToInt(timeout)
err = s.apiClient().ContainerStop(ctx, replaced.ID, containerType.StopOptions{Timeout: timeoutInSecond})
err = s.apiClient().ContainerStop(ctx, replaced.ID, container.StopOptions{Timeout: timeoutInSecond})
if err != nil {
return created, err
}
err = s.apiClient().ContainerRemove(ctx, replaced.ID, containerType.RemoveOptions{})
err = s.apiClient().ContainerRemove(ctx, replaced.ID, container.RemoveOptions{})
if err != nil {
return created, err
}
@ -677,12 +677,12 @@ func (s *composeService) recreateContainer(ctx context.Context, project *types.P
// force sequential calls to ContainerStart to prevent race condition in engine assigning ports from ranges
var startMx sync.Mutex
func (s *composeService) startContainer(ctx context.Context, ctr containerType.Summary) error {
func (s *composeService) startContainer(ctx context.Context, ctr container.Summary) error {
w := progress.ContextWriter(ctx)
w.Event(progress.NewEvent(getContainerProgressName(ctr), progress.Working, "Restart"))
startMx.Lock()
defer startMx.Unlock()
err := s.apiClient().ContainerStart(ctx, ctr.ID, containerType.StartOptions{})
err := s.apiClient().ContainerStart(ctx, ctr.ID, container.StartOptions{})
if err != nil {
return err
}
@ -695,11 +695,11 @@ func (s *composeService) createMobyContainer(ctx context.Context,
service types.ServiceConfig,
name string,
number int,
inherit *containerType.Summary,
inherit *container.Summary,
opts createOptions,
w progress.Writer,
) (containerType.Summary, error) {
var created containerType.Summary
) (container.Summary, error) {
var created container.Summary
cfgs, err := s.getCreateConfigs(ctx, project, service, number, inherit, opts)
if err != nil {
return created, err
@ -733,11 +733,11 @@ func (s *composeService) createMobyContainer(ctx context.Context,
if err != nil {
return created, err
}
created = containerType.Summary{
created = container.Summary{
ID: inspectedContainer.ID,
Labels: inspectedContainer.Config.Labels,
Names: []string{inspectedContainer.Name},
NetworkSettings: &containerType.NetworkSettingsSummary{
NetworkSettings: &container.NetworkSettingsSummary{
Networks: inspectedContainer.NetworkSettings.Networks,
},
}
@ -834,24 +834,24 @@ func (s *composeService) isServiceHealthy(ctx context.Context, containers Contai
}
name := ctr.Name[1:]
if ctr.State.Status == containerType.StateExited {
if ctr.State.Status == container.StateExited {
return false, fmt.Errorf("container %s exited (%d)", name, ctr.State.ExitCode)
}
if ctr.Config.Healthcheck == nil && fallbackRunning {
// Container does not define a health check, but we can fall back to "running" state
return ctr.State != nil && ctr.State.Status == containerType.StateRunning, nil
return ctr.State != nil && ctr.State.Status == container.StateRunning, nil
}
if ctr.State == nil || ctr.State.Health == nil {
return false, fmt.Errorf("container %s has no healthcheck configured", name)
}
switch ctr.State.Health.Status {
case containerType.Healthy:
case container.Healthy:
// Continue by checking the next container.
case containerType.Unhealthy:
case container.Unhealthy:
return false, fmt.Errorf("container %s is unhealthy", name)
case containerType.Starting:
case container.Starting:
return false, nil
default:
return false, fmt.Errorf("container %s had unexpected health status %q", name, ctr.State.Health.Status)
@ -866,7 +866,7 @@ func (s *composeService) isServiceCompleted(ctx context.Context, containers Cont
if err != nil {
return false, 0, err
}
if ctr.State != nil && ctr.State.Status == containerType.StateExited {
if ctr.State != nil && ctr.State.Status == container.StateExited {
return true, ctr.State.ExitCode, nil
}
}
@ -896,7 +896,7 @@ func (s *composeService) startService(ctx context.Context,
w := progress.ContextWriter(ctx)
for _, ctr := range containers.filter(isService(service.Name)) {
if ctr.State == ContainerRunning {
if ctr.State == container.StateRunning {
continue
}
@ -912,7 +912,7 @@ func (s *composeService) startService(ctx context.Context,
eventName := getContainerProgressName(ctr)
w.Event(progress.StartingEvent(eventName))
err = s.apiClient().ContainerStart(ctx, ctr.ID, containerType.StartOptions{})
err = s.apiClient().ContainerStart(ctx, ctr.ID, container.StartOptions{})
if err != nil {
return err
}

View File

@ -111,7 +111,7 @@ func testContainer(service string, id string, oneOff bool) container.Summary {
ID: id,
Names: []string{name},
Labels: containerLabels(service, oneOff),
State: ContainerExited,
State: container.StateExited,
}
}