mirror of
https://github.com/docker/compose.git
synced 2025-09-16 06:17:41 +02:00
pkg/compose: use state consts from moby API
Signed-off-by: Sebastiaan van Stijn <github@gone.nl>
This commit is contained in:
parent
02ffe2ac6c
commit
f217207876
@ -20,23 +20,17 @@ import (
|
|||||||
"io"
|
"io"
|
||||||
|
|
||||||
moby "github.com/docker/docker/api/types"
|
moby "github.com/docker/docker/api/types"
|
||||||
|
"github.com/docker/docker/api/types/container"
|
||||||
)
|
)
|
||||||
|
|
||||||
const (
|
const (
|
||||||
// ContainerCreated created status
|
ContainerCreated = container.StateCreated // StateCreated indicates the container is created, but not (yet) started.
|
||||||
ContainerCreated = "created"
|
ContainerRunning = container.StateRunning // StateRunning indicates that the container is running.
|
||||||
// ContainerRestarting restarting status
|
ContainerPaused = container.StatePaused // StatePaused indicates that the container's current state is paused.
|
||||||
ContainerRestarting = "restarting"
|
ContainerRestarting = container.StateRestarting // StateRestarting indicates that the container is currently restarting.
|
||||||
// ContainerRunning running status
|
ContainerRemoving = container.StateRemoving // StateRemoving indicates that the container is being removed.
|
||||||
ContainerRunning = "running"
|
ContainerExited = container.StateExited // StateExited indicates that the container exited.
|
||||||
// ContainerRemoving removing status
|
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.
|
||||||
ContainerRemoving = "removing"
|
|
||||||
// ContainerPaused paused status
|
|
||||||
ContainerPaused = "paused"
|
|
||||||
// ContainerExited exited status
|
|
||||||
ContainerExited = "exited"
|
|
||||||
// ContainerDead dead status
|
|
||||||
ContainerDead = "dead"
|
|
||||||
)
|
)
|
||||||
|
|
||||||
var _ io.ReadCloser = ContainerStdout{}
|
var _ io.ReadCloser = ContainerStdout{}
|
||||||
|
@ -135,7 +135,7 @@ func isOrphaned(project *types.Project) containerPredicate {
|
|||||||
// One-off container
|
// One-off container
|
||||||
v, ok := c.Labels[api.OneoffLabel]
|
v, ok := c.Labels[api.OneoffLabel]
|
||||||
if ok && v == "True" {
|
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 that is not defined in the compose model
|
||||||
service := c.Labels[api.ServiceLabel]
|
service := c.Labels[api.ServiceLabel]
|
||||||
|
@ -30,7 +30,7 @@ import (
|
|||||||
|
|
||||||
"github.com/compose-spec/compose-go/v2/types"
|
"github.com/compose-spec/compose-go/v2/types"
|
||||||
"github.com/containerd/platforms"
|
"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"
|
mmount "github.com/docker/docker/api/types/mount"
|
||||||
"github.com/docker/docker/api/types/versions"
|
"github.com/docker/docker/api/types/versions"
|
||||||
specs "github.com/opencontainers/image-spec/specs-go/v1"
|
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)
|
slices.Reverse(containers)
|
||||||
for i, container := range containers {
|
for i, ctr := range containers {
|
||||||
if i >= expected {
|
if i >= expected {
|
||||||
// Scale Down
|
// Scale Down
|
||||||
// As we sorted containers, obsolete ones and/or highest number will be removed
|
// As we sorted containers, obsolete ones and/or highest number will be removed
|
||||||
container := container
|
ctr := ctr
|
||||||
traceOpts := append(tracing.ServiceOptions(service), tracing.ContainerOptions(container)...)
|
traceOpts := append(tracing.ServiceOptions(service), tracing.ContainerOptions(ctr)...)
|
||||||
eg.Go(tracing.SpanWrapFuncForErrGroup(ctx, "service/scale/down", traceOpts, func(ctx context.Context) error {
|
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
|
continue
|
||||||
}
|
}
|
||||||
|
|
||||||
mustRecreate, err := c.mustRecreate(service, container, recreate)
|
mustRecreate, err := c.mustRecreate(service, ctr, recreate)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
@ -174,9 +174,9 @@ func (c *convergence) ensureService(ctx context.Context, project *types.Project,
|
|||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
|
||||||
i, container := i, container
|
i, ctr := i, ctr
|
||||||
eg.Go(tracing.SpanWrapFuncForErrGroup(ctx, "container/recreate", tracing.ContainerOptions(container), func(ctx context.Context) error {
|
eg.Go(tracing.SpanWrapFuncForErrGroup(ctx, "container/recreate", tracing.ContainerOptions(ctr), func(ctx context.Context) error {
|
||||||
recreated, err := c.service.recreateContainer(ctx, project, service, container, inherit, timeout)
|
recreated, err := c.service.recreateContainer(ctx, project, service, ctr, inherit, timeout)
|
||||||
updated[i] = recreated
|
updated[i] = recreated
|
||||||
return err
|
return err
|
||||||
}))
|
}))
|
||||||
@ -185,20 +185,20 @@ func (c *convergence) ensureService(ctx context.Context, project *types.Project,
|
|||||||
|
|
||||||
// Enforce non-diverged containers are running
|
// Enforce non-diverged containers are running
|
||||||
w := progress.ContextWriter(ctx)
|
w := progress.ContextWriter(ctx)
|
||||||
name := getContainerProgressName(container)
|
name := getContainerProgressName(ctr)
|
||||||
switch container.State {
|
switch ctr.State {
|
||||||
case ContainerRunning:
|
case container.StateRunning:
|
||||||
w.Event(progress.RunningEvent(name))
|
w.Event(progress.RunningEvent(name))
|
||||||
case ContainerCreated:
|
case container.StateCreated:
|
||||||
case ContainerRestarting:
|
case container.StateRestarting:
|
||||||
case ContainerExited:
|
case container.StateExited:
|
||||||
default:
|
default:
|
||||||
container := container
|
ctr := ctr
|
||||||
eg.Go(tracing.EventWrapFuncForErrGroup(ctx, "service/start", tracing.ContainerOptions(container), func(ctx context.Context) error {
|
eg.Go(tracing.EventWrapFuncForErrGroup(ctx, "service/start", tracing.ContainerOptions(ctr), func(ctx context.Context) error {
|
||||||
return c.service.startContainer(ctx, container)
|
return c.service.startContainer(ctx, ctr)
|
||||||
}))
|
}))
|
||||||
}
|
}
|
||||||
updated[i] = container
|
updated[i] = ctr
|
||||||
}
|
}
|
||||||
|
|
||||||
next := nextContainerNumber(containers)
|
next := nextContainerNumber(containers)
|
||||||
@ -214,8 +214,8 @@ func (c *convergence) ensureService(ctx context.Context, project *types.Project,
|
|||||||
UseNetworkAliases: true,
|
UseNetworkAliases: true,
|
||||||
Labels: mergeLabels(service.Labels, service.CustomLabels),
|
Labels: mergeLabels(service.Labels, service.CustomLabels),
|
||||||
}
|
}
|
||||||
container, err := c.service.createContainer(ctx, project, service, name, number, opts)
|
ctr, err := c.service.createContainer(ctx, project, service, name, number, opts)
|
||||||
updated[actual+i] = container
|
updated[actual+i] = ctr
|
||||||
return err
|
return err
|
||||||
}))
|
}))
|
||||||
continue
|
continue
|
||||||
@ -245,7 +245,7 @@ func (c *convergence) stopDependentContainers(ctx context.Context, project *type
|
|||||||
for _, name := range dependents {
|
for _, name := range dependents {
|
||||||
dependentStates := c.getObservedState(name)
|
dependentStates := c.getObservedState(name)
|
||||||
for i, dependent := range dependentStates {
|
for i, dependent := range dependentStates {
|
||||||
dependent.State = ContainerExited
|
dependent.State = container.StateExited
|
||||||
dependentStates[i] = dependent
|
dependentStates[i] = dependent
|
||||||
}
|
}
|
||||||
c.setObservedState(name, dependentStates)
|
c.setObservedState(name, dependentStates)
|
||||||
@ -328,7 +328,7 @@ func (c *convergence) resolveSharedNamespaces(service *types.ServiceConfig) erro
|
|||||||
return nil
|
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 {
|
if policy == api.RecreateNever {
|
||||||
return false, nil
|
return false, nil
|
||||||
}
|
}
|
||||||
@ -360,7 +360,7 @@ func (c *convergence) mustRecreate(expected types.ServiceConfig, actual containe
|
|||||||
return false, nil
|
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
|
// check the networks container is connected to are the expected ones
|
||||||
for net := range expected.Networks {
|
for net := range expected.Networks {
|
||||||
id := networks[net]
|
id := networks[net]
|
||||||
@ -383,7 +383,7 @@ func checkExpectedNetworks(expected types.ServiceConfig, actual containerType.Su
|
|||||||
return false
|
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
|
// check container's volume mounts and search for the expected ones
|
||||||
for _, vol := range expected.Volumes {
|
for _, vol := range expected.Volumes {
|
||||||
if vol.Type != string(mmount.TypeVolume) {
|
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)
|
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)
|
return "Container " + getCanonicalContainerName(ctr)
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -571,7 +571,7 @@ func shouldWaitForDependency(serviceName string, dependencyConfig types.ServiceD
|
|||||||
return true, nil
|
return true, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func nextContainerNumber(containers []containerType.Summary) int {
|
func nextContainerNumber(containers []container.Summary) int {
|
||||||
maxNumber := 0
|
maxNumber := 0
|
||||||
for _, c := range containers {
|
for _, c := range containers {
|
||||||
s, ok := c.Labels[api.ContainerNumberLabel]
|
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,
|
func (s *composeService) createContainer(ctx context.Context, project *types.Project, service types.ServiceConfig,
|
||||||
name string, number int, opts createOptions,
|
name string, number int, opts createOptions,
|
||||||
) (ctr containerType.Summary, err error) {
|
) (ctr container.Summary, err error) {
|
||||||
w := progress.ContextWriter(ctx)
|
w := progress.ContextWriter(ctx)
|
||||||
eventName := "Container " + name
|
eventName := "Container " + name
|
||||||
w.Event(progress.CreatingEvent(eventName))
|
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,
|
func (s *composeService) recreateContainer(ctx context.Context, project *types.Project, service types.ServiceConfig,
|
||||||
replaced containerType.Summary, inherit bool, timeout *time.Duration,
|
replaced container.Summary, inherit bool, timeout *time.Duration,
|
||||||
) (created containerType.Summary, err error) {
|
) (created container.Summary, err error) {
|
||||||
w := progress.ContextWriter(ctx)
|
w := progress.ContextWriter(ctx)
|
||||||
eventName := getContainerProgressName(replaced)
|
eventName := getContainerProgressName(replaced)
|
||||||
w.Event(progress.NewEvent(eventName, progress.Working, "Recreate"))
|
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
|
return created, err
|
||||||
}
|
}
|
||||||
|
|
||||||
var inherited *containerType.Summary
|
var inherited *container.Summary
|
||||||
if inherit {
|
if inherit {
|
||||||
inherited = &replaced
|
inherited = &replaced
|
||||||
}
|
}
|
||||||
@ -655,12 +655,12 @@ func (s *composeService) recreateContainer(ctx context.Context, project *types.P
|
|||||||
}
|
}
|
||||||
|
|
||||||
timeoutInSecond := utils.DurationSecondToInt(timeout)
|
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 {
|
if err != nil {
|
||||||
return created, err
|
return created, err
|
||||||
}
|
}
|
||||||
|
|
||||||
err = s.apiClient().ContainerRemove(ctx, replaced.ID, containerType.RemoveOptions{})
|
err = s.apiClient().ContainerRemove(ctx, replaced.ID, container.RemoveOptions{})
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return created, err
|
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
|
// force sequential calls to ContainerStart to prevent race condition in engine assigning ports from ranges
|
||||||
var startMx sync.Mutex
|
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 := progress.ContextWriter(ctx)
|
||||||
w.Event(progress.NewEvent(getContainerProgressName(ctr), progress.Working, "Restart"))
|
w.Event(progress.NewEvent(getContainerProgressName(ctr), progress.Working, "Restart"))
|
||||||
startMx.Lock()
|
startMx.Lock()
|
||||||
defer startMx.Unlock()
|
defer startMx.Unlock()
|
||||||
err := s.apiClient().ContainerStart(ctx, ctr.ID, containerType.StartOptions{})
|
err := s.apiClient().ContainerStart(ctx, ctr.ID, container.StartOptions{})
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
@ -695,11 +695,11 @@ func (s *composeService) createMobyContainer(ctx context.Context,
|
|||||||
service types.ServiceConfig,
|
service types.ServiceConfig,
|
||||||
name string,
|
name string,
|
||||||
number int,
|
number int,
|
||||||
inherit *containerType.Summary,
|
inherit *container.Summary,
|
||||||
opts createOptions,
|
opts createOptions,
|
||||||
w progress.Writer,
|
w progress.Writer,
|
||||||
) (containerType.Summary, error) {
|
) (container.Summary, error) {
|
||||||
var created containerType.Summary
|
var created container.Summary
|
||||||
cfgs, err := s.getCreateConfigs(ctx, project, service, number, inherit, opts)
|
cfgs, err := s.getCreateConfigs(ctx, project, service, number, inherit, opts)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return created, err
|
return created, err
|
||||||
@ -733,11 +733,11 @@ func (s *composeService) createMobyContainer(ctx context.Context,
|
|||||||
if err != nil {
|
if err != nil {
|
||||||
return created, err
|
return created, err
|
||||||
}
|
}
|
||||||
created = containerType.Summary{
|
created = container.Summary{
|
||||||
ID: inspectedContainer.ID,
|
ID: inspectedContainer.ID,
|
||||||
Labels: inspectedContainer.Config.Labels,
|
Labels: inspectedContainer.Config.Labels,
|
||||||
Names: []string{inspectedContainer.Name},
|
Names: []string{inspectedContainer.Name},
|
||||||
NetworkSettings: &containerType.NetworkSettingsSummary{
|
NetworkSettings: &container.NetworkSettingsSummary{
|
||||||
Networks: inspectedContainer.NetworkSettings.Networks,
|
Networks: inspectedContainer.NetworkSettings.Networks,
|
||||||
},
|
},
|
||||||
}
|
}
|
||||||
@ -834,24 +834,24 @@ func (s *composeService) isServiceHealthy(ctx context.Context, containers Contai
|
|||||||
}
|
}
|
||||||
name := ctr.Name[1:]
|
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)
|
return false, fmt.Errorf("container %s exited (%d)", name, ctr.State.ExitCode)
|
||||||
}
|
}
|
||||||
|
|
||||||
if ctr.Config.Healthcheck == nil && fallbackRunning {
|
if ctr.Config.Healthcheck == nil && fallbackRunning {
|
||||||
// Container does not define a health check, but we can fall back to "running" state
|
// 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 {
|
if ctr.State == nil || ctr.State.Health == nil {
|
||||||
return false, fmt.Errorf("container %s has no healthcheck configured", name)
|
return false, fmt.Errorf("container %s has no healthcheck configured", name)
|
||||||
}
|
}
|
||||||
switch ctr.State.Health.Status {
|
switch ctr.State.Health.Status {
|
||||||
case containerType.Healthy:
|
case container.Healthy:
|
||||||
// Continue by checking the next container.
|
// Continue by checking the next container.
|
||||||
case containerType.Unhealthy:
|
case container.Unhealthy:
|
||||||
return false, fmt.Errorf("container %s is unhealthy", name)
|
return false, fmt.Errorf("container %s is unhealthy", name)
|
||||||
case containerType.Starting:
|
case container.Starting:
|
||||||
return false, nil
|
return false, nil
|
||||||
default:
|
default:
|
||||||
return false, fmt.Errorf("container %s had unexpected health status %q", name, ctr.State.Health.Status)
|
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 {
|
if err != nil {
|
||||||
return false, 0, err
|
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
|
return true, ctr.State.ExitCode, nil
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -896,7 +896,7 @@ func (s *composeService) startService(ctx context.Context,
|
|||||||
|
|
||||||
w := progress.ContextWriter(ctx)
|
w := progress.ContextWriter(ctx)
|
||||||
for _, ctr := range containers.filter(isService(service.Name)) {
|
for _, ctr := range containers.filter(isService(service.Name)) {
|
||||||
if ctr.State == ContainerRunning {
|
if ctr.State == container.StateRunning {
|
||||||
continue
|
continue
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -912,7 +912,7 @@ func (s *composeService) startService(ctx context.Context,
|
|||||||
|
|
||||||
eventName := getContainerProgressName(ctr)
|
eventName := getContainerProgressName(ctr)
|
||||||
w.Event(progress.StartingEvent(eventName))
|
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 {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
@ -111,7 +111,7 @@ func testContainer(service string, id string, oneOff bool) container.Summary {
|
|||||||
ID: id,
|
ID: id,
|
||||||
Names: []string{name},
|
Names: []string{name},
|
||||||
Labels: containerLabels(service, oneOff),
|
Labels: containerLabels(service, oneOff),
|
||||||
State: ContainerExited,
|
State: container.StateExited,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
Loading…
x
Reference in New Issue
Block a user