mirror of
https://github.com/docker/compose.git
synced 2025-07-21 20:54:32 +02:00
use containers we expect to start for wait condition
Signed-off-by: Nicolas De Loof <nicolas.deloof@gmail.com>
This commit is contained in:
parent
e908f41ec8
commit
b5f0a4eefa
@ -28,7 +28,6 @@ import (
|
|||||||
"github.com/containerd/containerd/platforms"
|
"github.com/containerd/containerd/platforms"
|
||||||
moby "github.com/docker/docker/api/types"
|
moby "github.com/docker/docker/api/types"
|
||||||
containerType "github.com/docker/docker/api/types/container"
|
containerType "github.com/docker/docker/api/types/container"
|
||||||
"github.com/docker/docker/api/types/filters"
|
|
||||||
"github.com/docker/docker/api/types/network"
|
"github.com/docker/docker/api/types/network"
|
||||||
specs "github.com/opencontainers/image-spec/specs-go/v1"
|
specs "github.com/opencontainers/image-spec/specs-go/v1"
|
||||||
"github.com/pkg/errors"
|
"github.com/pkg/errors"
|
||||||
@ -281,7 +280,7 @@ func containerEvents(containers Containers, eventFunc func(string) progress.Even
|
|||||||
// ServiceConditionRunningOrHealthy is a service condition on status running or healthy
|
// ServiceConditionRunningOrHealthy is a service condition on status running or healthy
|
||||||
const ServiceConditionRunningOrHealthy = "running_or_healthy"
|
const ServiceConditionRunningOrHealthy = "running_or_healthy"
|
||||||
|
|
||||||
func (s *composeService) waitDependencies(ctx context.Context, project *types.Project, dependencies types.DependsOnConfig) error {
|
func (s *composeService) waitDependencies(ctx context.Context, project *types.Project, dependencies types.DependsOnConfig, containers Containers) error {
|
||||||
eg, _ := errgroup.WithContext(ctx)
|
eg, _ := errgroup.WithContext(ctx)
|
||||||
w := progress.ContextWriter(ctx)
|
w := progress.ContextWriter(ctx)
|
||||||
for dep, config := range dependencies {
|
for dep, config := range dependencies {
|
||||||
@ -291,10 +290,7 @@ func (s *composeService) waitDependencies(ctx context.Context, project *types.Pr
|
|||||||
continue
|
continue
|
||||||
}
|
}
|
||||||
|
|
||||||
containers, err := s.getContainers(ctx, project.Name, oneOffExclude, false, dep)
|
containers = containers.filter(isService(dep))
|
||||||
if err != nil {
|
|
||||||
return err
|
|
||||||
}
|
|
||||||
w.Events(containerEvents(containers, progress.Waiting))
|
w.Events(containerEvents(containers, progress.Waiting))
|
||||||
|
|
||||||
dep, config := dep, config
|
dep, config := dep, config
|
||||||
@ -305,7 +301,7 @@ func (s *composeService) waitDependencies(ctx context.Context, project *types.Pr
|
|||||||
<-ticker.C
|
<-ticker.C
|
||||||
switch config.Condition {
|
switch config.Condition {
|
||||||
case ServiceConditionRunningOrHealthy:
|
case ServiceConditionRunningOrHealthy:
|
||||||
healthy, err := s.isServiceHealthy(ctx, project, dep, true)
|
healthy, err := s.isServiceHealthy(ctx, containers, dep, true)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
@ -314,7 +310,7 @@ func (s *composeService) waitDependencies(ctx context.Context, project *types.Pr
|
|||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
case types.ServiceConditionHealthy:
|
case types.ServiceConditionHealthy:
|
||||||
healthy, err := s.isServiceHealthy(ctx, project, dep, false)
|
healthy, err := s.isServiceHealthy(ctx, containers, dep, false)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
w.Events(containerEvents(containers, progress.ErrorEvent))
|
w.Events(containerEvents(containers, progress.ErrorEvent))
|
||||||
return errors.Wrap(err, "dependency failed to start")
|
return errors.Wrap(err, "dependency failed to start")
|
||||||
@ -324,7 +320,7 @@ func (s *composeService) waitDependencies(ctx context.Context, project *types.Pr
|
|||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
case types.ServiceConditionCompletedSuccessfully:
|
case types.ServiceConditionCompletedSuccessfully:
|
||||||
exited, code, err := s.isServiceCompleted(ctx, project, dep)
|
exited, code, err := s.isServiceCompleted(ctx, containers, dep)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
@ -650,12 +646,7 @@ func (s *composeService) connectContainerToNetwork(ctx context.Context, id strin
|
|||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func (s *composeService) isServiceHealthy(ctx context.Context, project *types.Project, service string, fallbackRunning bool) (bool, error) {
|
func (s *composeService) isServiceHealthy(ctx context.Context, containers Containers, service string, fallbackRunning bool) (bool, error) {
|
||||||
containers, err := s.getContainers(ctx, project.Name, oneOffExclude, true, service)
|
|
||||||
if err != nil {
|
|
||||||
return false, err
|
|
||||||
}
|
|
||||||
|
|
||||||
if len(containers) == 0 {
|
if len(containers) == 0 {
|
||||||
return false, nil
|
return false, nil
|
||||||
}
|
}
|
||||||
@ -690,11 +681,7 @@ func (s *composeService) isServiceHealthy(ctx context.Context, project *types.Pr
|
|||||||
return true, nil
|
return true, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func (s *composeService) isServiceCompleted(ctx context.Context, project *types.Project, dep string) (bool, int, error) {
|
func (s *composeService) isServiceCompleted(ctx context.Context, containers Containers, dep string) (bool, int, error) {
|
||||||
containers, err := s.getContainers(ctx, project.Name, oneOffExclude, true, dep)
|
|
||||||
if err != nil {
|
|
||||||
return false, 0, err
|
|
||||||
}
|
|
||||||
for _, c := range containers {
|
for _, c := range containers {
|
||||||
container, err := s.apiClient().ContainerInspect(ctx, c.ID)
|
container, err := s.apiClient().ContainerInspect(ctx, c.ID)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
@ -707,23 +694,12 @@ func (s *composeService) isServiceCompleted(ctx context.Context, project *types.
|
|||||||
return false, 0, nil
|
return false, 0, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func (s *composeService) startService(ctx context.Context, project *types.Project, service types.ServiceConfig) error {
|
func (s *composeService) startService(ctx context.Context, project *types.Project, service types.ServiceConfig, containers Containers) error {
|
||||||
if service.Deploy != nil && service.Deploy.Replicas != nil && *service.Deploy.Replicas == 0 {
|
if service.Deploy != nil && service.Deploy.Replicas != nil && *service.Deploy.Replicas == 0 {
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
err := s.waitDependencies(ctx, project, service.DependsOn)
|
err := s.waitDependencies(ctx, project, service.DependsOn, containers)
|
||||||
if err != nil {
|
|
||||||
return err
|
|
||||||
}
|
|
||||||
containers, err := s.apiClient().ContainerList(ctx, moby.ContainerListOptions{
|
|
||||||
Filters: filters.NewArgs(
|
|
||||||
projectFilter(project.Name),
|
|
||||||
serviceFilter(service.Name),
|
|
||||||
oneOffFilter(false),
|
|
||||||
),
|
|
||||||
All: true,
|
|
||||||
})
|
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
@ -229,7 +229,7 @@ func TestWaitDependencies(t *testing.T) {
|
|||||||
"db": {Condition: ServiceConditionRunningOrHealthy},
|
"db": {Condition: ServiceConditionRunningOrHealthy},
|
||||||
"redis": {Condition: ServiceConditionRunningOrHealthy},
|
"redis": {Condition: ServiceConditionRunningOrHealthy},
|
||||||
}
|
}
|
||||||
assert.NilError(t, tested.waitDependencies(context.Background(), &project, dependencies))
|
assert.NilError(t, tested.waitDependencies(context.Background(), &project, dependencies, nil))
|
||||||
})
|
})
|
||||||
t.Run("should skip dependencies with condition service_started", func(t *testing.T) {
|
t.Run("should skip dependencies with condition service_started", func(t *testing.T) {
|
||||||
dbService := types.ServiceConfig{Name: "db", Scale: 1}
|
dbService := types.ServiceConfig{Name: "db", Scale: 1}
|
||||||
@ -239,6 +239,6 @@ func TestWaitDependencies(t *testing.T) {
|
|||||||
"db": {Condition: types.ServiceConditionStarted},
|
"db": {Condition: types.ServiceConditionStarted},
|
||||||
"redis": {Condition: types.ServiceConditionStarted},
|
"redis": {Condition: types.ServiceConditionStarted},
|
||||||
}
|
}
|
||||||
assert.NilError(t, tested.waitDependencies(context.Background(), &project, dependencies))
|
assert.NilError(t, tested.waitDependencies(context.Background(), &project, dependencies, nil))
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
@ -76,11 +76,6 @@ func (s *composeService) prepareRun(ctx context.Context, project *types.Project,
|
|||||||
if err := s.ensureImagesExists(ctx, project, opts.QuietPull); err != nil { // all dependencies already checked, but might miss service img
|
if err := s.ensureImagesExists(ctx, project, opts.QuietPull); err != nil { // all dependencies already checked, but might miss service img
|
||||||
return "", err
|
return "", err
|
||||||
}
|
}
|
||||||
if !opts.NoDeps {
|
|
||||||
if err := s.waitDependencies(ctx, project, service.DependsOn); err != nil {
|
|
||||||
return "", err
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
observedState, err := s.getContainers(ctx, project.Name, oneOffInclude, true)
|
observedState, err := s.getContainers(ctx, project.Name, oneOffInclude, true)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
@ -88,6 +83,11 @@ func (s *composeService) prepareRun(ctx context.Context, project *types.Project,
|
|||||||
}
|
}
|
||||||
updateServices(&service, observedState)
|
updateServices(&service, observedState)
|
||||||
|
|
||||||
|
if !opts.NoDeps {
|
||||||
|
if err := s.waitDependencies(ctx, project, service.DependsOn, observedState); err != nil {
|
||||||
|
return "", err
|
||||||
|
}
|
||||||
|
}
|
||||||
created, err := s.createContainer(ctx, project, service, service.ContainerName, 1,
|
created, err := s.createContainer(ctx, project, service, service.ContainerName, 1,
|
||||||
opts.AutoRemove, opts.UseNetworkAliases, opts.Interactive)
|
opts.AutoRemove, opts.UseNetworkAliases, opts.Interactive)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
|
@ -18,6 +18,7 @@ package compose
|
|||||||
|
|
||||||
import (
|
import (
|
||||||
"context"
|
"context"
|
||||||
|
"github.com/docker/docker/api/types/filters"
|
||||||
"strings"
|
"strings"
|
||||||
"time"
|
"time"
|
||||||
|
|
||||||
@ -75,13 +76,25 @@ func (s *composeService) start(ctx context.Context, projectName string, options
|
|||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
err := InDependencyOrder(ctx, project, func(c context.Context, name string) error {
|
var containers Containers
|
||||||
|
containers, err := s.apiClient().ContainerList(ctx, moby.ContainerListOptions{
|
||||||
|
Filters: filters.NewArgs(
|
||||||
|
projectFilter(project.Name),
|
||||||
|
oneOffFilter(false),
|
||||||
|
),
|
||||||
|
All: true,
|
||||||
|
})
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
err = InDependencyOrder(ctx, project, func(c context.Context, name string) error {
|
||||||
service, err := project.GetService(name)
|
service, err := project.GetService(name)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
|
||||||
return s.startService(ctx, project, service)
|
return s.startService(ctx, project, service, containers.filter(isService(service.Name)))
|
||||||
})
|
})
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
@ -94,7 +107,7 @@ func (s *composeService) start(ctx context.Context, projectName string, options
|
|||||||
Condition: getDependencyCondition(s, project),
|
Condition: getDependencyCondition(s, project),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
err = s.waitDependencies(ctx, project, depends)
|
err = s.waitDependencies(ctx, project, depends, containers)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
Loading…
x
Reference in New Issue
Block a user