up should not silently ignore missing depends_on service

Signed-off-by: Nicolas De Loof <nicolas.deloof@gmail.com>
This commit is contained in:
Nicolas De Loof 2023-05-23 14:06:45 +02:00 committed by Nicolas De loof
parent 6f6e1635fd
commit 06ec06472f
5 changed files with 29 additions and 86 deletions

2
go.mod
View File

@ -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

4
go.sum
View File

@ -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=

View File

@ -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 ""

View File

@ -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

View File

@ -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 {