diff --git a/go.mod b/go.mod index ba47c3a7e..bfda6d541 100644 --- a/go.mod +++ b/go.mod @@ -5,7 +5,7 @@ go 1.20 require ( github.com/AlecAivazis/survey/v2 v2.3.6 github.com/buger/goterm v1.0.4 - github.com/compose-spec/compose-go v1.13.5 + github.com/compose-spec/compose-go v1.14.0 github.com/containerd/console v1.0.3 github.com/containerd/containerd v1.6.21 github.com/cucumber/godog v0.0.0-00010101000000-000000000000 // replaced; see replace for the actual version used diff --git a/go.sum b/go.sum index 57443d187..3ad20350f 100644 --- a/go.sum +++ b/go.sum @@ -157,8 +157,8 @@ github.com/cncf/xds/go v0.0.0-20210805033703-aa0b78936158/go.mod h1:eXthEFrGJvWH github.com/cncf/xds/go v0.0.0-20210922020428-25de7278fc84/go.mod h1:eXthEFrGJvWHgFFCl3hGmgk+/aYT6PnTQLykKQRLhEs= github.com/cncf/xds/go v0.0.0-20211001041855-01bcc9b48dfe/go.mod h1:eXthEFrGJvWHgFFCl3hGmgk+/aYT6PnTQLykKQRLhEs= github.com/cncf/xds/go v0.0.0-20211011173535-cb28da3451f1/go.mod h1:eXthEFrGJvWHgFFCl3hGmgk+/aYT6PnTQLykKQRLhEs= -github.com/compose-spec/compose-go v1.13.5 h1:ogqJOGEbe3uRxMg0ZEufOoCQTpX61l8tUeyW4UQgEBk= -github.com/compose-spec/compose-go v1.13.5/go.mod h1:m0o4G6MQDHjjz9rY7No9FpnNi+9sKic262rzrwuCqic= +github.com/compose-spec/compose-go v1.14.0 h1:/+tQxBEPIrfsi87Qh7/VjMzcJN3BRNER/RO71ku+u6E= +github.com/compose-spec/compose-go v1.14.0/go.mod h1:m0o4G6MQDHjjz9rY7No9FpnNi+9sKic262rzrwuCqic= github.com/containerd/cgroups v1.0.4 h1:jN/mbWBEaz+T1pi5OFtnkQ+8qnmEbAr1Oo1FRm5B0dA= github.com/containerd/console v1.0.3 h1:lIr7SlA5PxZyMV30bDW0MGbiOPXwc63yRuCP0ARubLw= github.com/containerd/console v1.0.3/go.mod h1:7LqA/THxQ86k76b8c/EMSiaJ3h1eZkMkXar0TQ1gf3U= diff --git a/pkg/compose/create.go b/pkg/compose/create.go index bdaff2618..14a3ee8bc 100644 --- a/pkg/compose/create.go +++ b/pkg/compose/create.go @@ -106,11 +106,6 @@ func (s *composeService) create(ctx context.Context, project *types.Project, opt } } - err = prepareServicesDependsOn(project) - if err != nil { - return err - } - return newConvergence(options.Services, observedState, s).apply(ctx, project, options) } @@ -147,72 +142,6 @@ func prepareNetworks(project *types.Project) { } } -func prepareServicesDependsOn(p *types.Project) error { - allServices := types.Project{} - allServices.Services = p.AllServices() - - for i, service := range p.Services { - var dependencies []string - networkDependency := getDependentServiceFromMode(service.NetworkMode) - if networkDependency != "" { - dependencies = append(dependencies, networkDependency) - } - - ipcDependency := getDependentServiceFromMode(service.Ipc) - if ipcDependency != "" { - dependencies = append(dependencies, ipcDependency) - } - - pidDependency := getDependentServiceFromMode(service.Pid) - if pidDependency != "" { - dependencies = append(dependencies, pidDependency) - } - - for _, vol := range service.VolumesFrom { - spec := strings.Split(vol, ":") - if len(spec) == 0 { - continue - } - if spec[0] == "container" { - continue - } - dependencies = append(dependencies, spec[0]) - } - - for _, link := range service.Links { - dependencies = append(dependencies, strings.Split(link, ":")[0]) - } - - for d := range service.DependsOn { - dependencies = append(dependencies, d) - } - - if len(dependencies) == 0 { - continue - } - - // Verify dependencies exist in the project, whether disabled or not - deps, err := allServices.GetServices(dependencies...) - if err != nil { - return err - } - - if service.DependsOn == nil { - service.DependsOn = make(types.DependsOnConfig) - } - - for _, d := range deps { - if _, ok := service.DependsOn[d.Name]; !ok { - service.DependsOn[d.Name] = types.ServiceDependency{ - Condition: types.ServiceConditionStarted, - } - } - } - p.Services[i] = service - } - return nil -} - func (s *composeService) ensureNetworks(ctx context.Context, networks types.Networks) error { for _, network := range networks { err := s.ensureNetwork(ctx, network) @@ -640,8 +569,8 @@ func setLimits(limits *types.Resource, resources *container.Resources) { resources.NanoCPUs = int64(f * 1e9) } } - if limits.PIds > 0 { - resources.PidsLimit = &limits.PIds + if limits.Pids > 0 { + resources.PidsLimit = &limits.Pids } } @@ -743,7 +672,10 @@ func getVolumesFrom(project *types.Project, volumesFrom []string) ([]string, []s } func getDependentServiceFromMode(mode string) string { - if strings.HasPrefix(mode, types.NetworkModeServicePrefix) { + if strings.HasPrefix( + mode, + types.NetworkModeServicePrefix, + ) { return mode[len(types.NetworkModeServicePrefix):] } return "" diff --git a/pkg/compose/dependencies.go b/pkg/compose/dependencies.go index f735f5782..de66f84cd 100644 --- a/pkg/compose/dependencies.go +++ b/pkg/compose/dependencies.go @@ -23,6 +23,8 @@ import ( "sync" "github.com/compose-spec/compose-go/types" + "github.com/docker/compose/v2/pkg/api" + "github.com/pkg/errors" "golang.org/x/sync/errgroup" "github.com/docker/compose/v2/pkg/utils" @@ -76,7 +78,7 @@ func downDirectionTraversal(visitorFn func(context.Context, string) error) *grap // InDependencyOrder applies the function to the services of the project taking in account the dependency order func InDependencyOrder(ctx context.Context, project *types.Project, fn func(context.Context, string) error, options ...func(*graphTraversal)) error { - graph, err := NewGraph(project.Services, ServiceStopped) + graph, err := NewGraph(project, ServiceStopped) if err != nil { return err } @@ -89,7 +91,7 @@ func InDependencyOrder(ctx context.Context, project *types.Project, fn func(cont // InReverseDependencyOrder applies the function to the services of the project in reverse order of dependencies func InReverseDependencyOrder(ctx context.Context, project *types.Project, fn func(context.Context, string) error, options ...func(*graphTraversal)) error { - graph, err := NewGraph(project.Services, ServiceStarted) + graph, err := NewGraph(project, ServiceStarted) if err != nil { return err } @@ -252,19 +254,28 @@ func (v *Vertex) GetChildren() []*Vertex { } // NewGraph returns the dependency graph of the services -func NewGraph(services types.Services, initialStatus ServiceStatus) (*Graph, error) { +func NewGraph(project *types.Project, initialStatus ServiceStatus) (*Graph, error) { graph := &Graph{ lock: sync.RWMutex{}, Vertices: map[string]*Vertex{}, } - for _, s := range services { + for _, s := range project.Services { graph.AddVertex(s.Name, s.Name, initialStatus) } - for _, s := range services { + for _, s := range project.Services { for _, name := range s.GetDependencies() { - _ = graph.AddEdge(s.Name, name) + err := graph.AddEdge(s.Name, name) + if err != nil { + if api.IsNotFoundError(err) { + ds, err := project.GetDisabledService(name) + if err == nil { + return nil, fmt.Errorf("service %s is required by %s but is disabled. Can be enabled by profiles %s", name, s.Name, ds.Profiles) + } + } + return nil, err + } } } @@ -304,10 +315,10 @@ func (g *Graph) AddEdge(source string, destination string) error { destinationVertex := g.Vertices[destination] if sourceVertex == nil { - return fmt.Errorf("could not find %s", source) + return errors.Wrapf(api.ErrNotFound, "could not find %s", source) } if destinationVertex == nil { - return fmt.Errorf("could not find %s", destination) + return errors.Wrapf(api.ErrNotFound, "could not find %s", destination) } // If they are already connected diff --git a/pkg/compose/dependencies_test.go b/pkg/compose/dependencies_test.go index ce30cdf9d..b668f4ada 100644 --- a/pkg/compose/dependencies_test.go +++ b/pkg/compose/dependencies_test.go @@ -270,7 +270,7 @@ func TestBuildGraph(t *testing.T) { Services: tC.services, } - graph, err := NewGraph(project.Services, ServiceStopped) + graph, err := NewGraph(&project, ServiceStopped) assert.NilError(t, err, fmt.Sprintf("failed to build graph for: %s", tC.desc)) for k, vertex := range graph.Vertices {