mirror of
https://github.com/docker/compose.git
synced 2025-05-31 11:50:13 +02:00
build full compose model from resources, then filter by services
Signed-off-by: Nicolas De Loof <nicolas.deloof@gmail.com>
This commit is contained in:
parent
ce944520ff
commit
158b5ff6a3
@ -59,13 +59,13 @@ Any data which is not in a volume will be lost.`,
|
|||||||
}
|
}
|
||||||
|
|
||||||
func runRemove(ctx context.Context, backend api.Service, opts removeOptions, services []string) error {
|
func runRemove(ctx context.Context, backend api.Service, opts removeOptions, services []string) error {
|
||||||
project, err := opts.toProject(services)
|
project, err := opts.toProjectName()
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
|
||||||
if opts.stop {
|
if opts.stop {
|
||||||
err := backend.Stop(ctx, project.Name, api.StopOptions{
|
err := backend.Stop(ctx, project, api.StopOptions{
|
||||||
Services: services,
|
Services: services,
|
||||||
})
|
})
|
||||||
if err != nil {
|
if err != nil {
|
||||||
|
@ -59,7 +59,7 @@ type Service interface {
|
|||||||
// RunOneOffContainer creates a service oneoff container and starts its dependencies
|
// RunOneOffContainer creates a service oneoff container and starts its dependencies
|
||||||
RunOneOffContainer(ctx context.Context, project *types.Project, opts RunOptions) (int, error)
|
RunOneOffContainer(ctx context.Context, project *types.Project, opts RunOptions) (int, error)
|
||||||
// Remove executes the equivalent to a `compose rm`
|
// Remove executes the equivalent to a `compose rm`
|
||||||
Remove(ctx context.Context, project *types.Project, options RemoveOptions) error
|
Remove(ctx context.Context, project string, options RemoveOptions) error
|
||||||
// Exec executes a command in a running service container
|
// Exec executes a command in a running service container
|
||||||
Exec(ctx context.Context, project string, opts RunOptions) (int, error)
|
Exec(ctx context.Context, project string, opts RunOptions) (int, error)
|
||||||
// Copy copies a file/folder between a service container and the local filesystem
|
// Copy copies a file/folder between a service container and the local filesystem
|
||||||
|
@ -39,7 +39,7 @@ type ServiceProxy struct {
|
|||||||
ConvertFn func(ctx context.Context, project *types.Project, options ConvertOptions) ([]byte, error)
|
ConvertFn func(ctx context.Context, project *types.Project, options ConvertOptions) ([]byte, error)
|
||||||
KillFn func(ctx context.Context, project *types.Project, options KillOptions) error
|
KillFn func(ctx context.Context, project *types.Project, options KillOptions) error
|
||||||
RunOneOffContainerFn func(ctx context.Context, project *types.Project, opts RunOptions) (int, error)
|
RunOneOffContainerFn func(ctx context.Context, project *types.Project, opts RunOptions) (int, error)
|
||||||
RemoveFn func(ctx context.Context, project *types.Project, options RemoveOptions) error
|
RemoveFn func(ctx context.Context, project string, options RemoveOptions) error
|
||||||
ExecFn func(ctx context.Context, project string, opts RunOptions) (int, error)
|
ExecFn func(ctx context.Context, project string, opts RunOptions) (int, error)
|
||||||
CopyFn func(ctx context.Context, project string, options CopyOptions) error
|
CopyFn func(ctx context.Context, project string, options CopyOptions) error
|
||||||
PauseFn func(ctx context.Context, project string, options PauseOptions) error
|
PauseFn func(ctx context.Context, project string, options PauseOptions) error
|
||||||
@ -241,13 +241,10 @@ func (s *ServiceProxy) RunOneOffContainer(ctx context.Context, project *types.Pr
|
|||||||
}
|
}
|
||||||
|
|
||||||
// Remove implements Service interface
|
// Remove implements Service interface
|
||||||
func (s *ServiceProxy) Remove(ctx context.Context, project *types.Project, options RemoveOptions) error {
|
func (s *ServiceProxy) Remove(ctx context.Context, project string, options RemoveOptions) error {
|
||||||
if s.RemoveFn == nil {
|
if s.RemoveFn == nil {
|
||||||
return ErrNotImplemented
|
return ErrNotImplemented
|
||||||
}
|
}
|
||||||
for _, i := range s.interceptors {
|
|
||||||
i(ctx, project)
|
|
||||||
}
|
|
||||||
return s.RemoveFn(ctx, project, options)
|
return s.RemoveFn(ctx, project, options)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -149,3 +149,23 @@ SERVICES:
|
|||||||
|
|
||||||
return project, nil
|
return project, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// actualState list resources labelled by projectName to rebuild compose project model
|
||||||
|
func (s *composeService) actualState(ctx context.Context, projectName string, services []string) (Containers, *types.Project, error) {
|
||||||
|
var containers Containers
|
||||||
|
// don't filter containers by options.Services so projectFromName can rebuild project with all existing resources
|
||||||
|
containers, err := s.getContainers(ctx, projectName, oneOffInclude, true)
|
||||||
|
if err != nil {
|
||||||
|
return nil, nil, err
|
||||||
|
}
|
||||||
|
|
||||||
|
project, err := s.projectFromName(containers, projectName, services...)
|
||||||
|
if err != nil && !api.IsNotFoundError(err) {
|
||||||
|
return nil, nil, err
|
||||||
|
}
|
||||||
|
|
||||||
|
if len(services) > 0 {
|
||||||
|
containers = containers.filter(isService(services...))
|
||||||
|
}
|
||||||
|
return containers, project, nil
|
||||||
|
}
|
||||||
|
@ -21,7 +21,6 @@ import (
|
|||||||
"fmt"
|
"fmt"
|
||||||
"strings"
|
"strings"
|
||||||
|
|
||||||
"github.com/compose-spec/compose-go/types"
|
|
||||||
"github.com/docker/compose/v2/pkg/api"
|
"github.com/docker/compose/v2/pkg/api"
|
||||||
moby "github.com/docker/docker/api/types"
|
moby "github.com/docker/docker/api/types"
|
||||||
"golang.org/x/sync/errgroup"
|
"golang.org/x/sync/errgroup"
|
||||||
@ -30,13 +29,8 @@ import (
|
|||||||
"github.com/docker/compose/v2/pkg/prompt"
|
"github.com/docker/compose/v2/pkg/prompt"
|
||||||
)
|
)
|
||||||
|
|
||||||
func (s *composeService) Remove(ctx context.Context, project *types.Project, options api.RemoveOptions) error {
|
func (s *composeService) Remove(ctx context.Context, projectName string, options api.RemoveOptions) error {
|
||||||
services := options.Services
|
containers, _, err := s.actualState(ctx, projectName, options.Services)
|
||||||
if len(services) == 0 {
|
|
||||||
services = project.ServiceNames()
|
|
||||||
}
|
|
||||||
|
|
||||||
containers, err := s.getContainers(ctx, project.Name, oneOffInclude, true, services...)
|
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
@ -32,26 +32,11 @@ func (s *composeService) Stop(ctx context.Context, projectName string, options a
|
|||||||
func (s *composeService) stop(ctx context.Context, projectName string, options api.StopOptions) error {
|
func (s *composeService) stop(ctx context.Context, projectName string, options api.StopOptions) error {
|
||||||
w := progress.ContextWriter(ctx)
|
w := progress.ContextWriter(ctx)
|
||||||
|
|
||||||
services := options.Services
|
containers, project, err := s.actualState(ctx, projectName, options.Services)
|
||||||
if len(services) == 0 {
|
|
||||||
services = []string{}
|
|
||||||
}
|
|
||||||
|
|
||||||
var containers Containers
|
|
||||||
containers, err := s.getContainers(ctx, projectName, oneOffInclude, true, services...)
|
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
|
||||||
project, err := s.projectFromName(containers, projectName, services...)
|
|
||||||
if err != nil && !api.IsNotFoundError(err) {
|
|
||||||
return err
|
|
||||||
}
|
|
||||||
|
|
||||||
if len(services) > 0 {
|
|
||||||
containers = containers.filter(isService(services...))
|
|
||||||
}
|
|
||||||
|
|
||||||
return InReverseDependencyOrder(ctx, project, func(c context.Context, service string) error {
|
return InReverseDependencyOrder(ctx, project, func(c context.Context, service string) error {
|
||||||
return s.stopContainers(ctx, w, containers.filter(isService(service)), options.Timeout)
|
return s.stopContainers(ctx, w, containers.filter(isService(service)), options.Timeout)
|
||||||
})
|
})
|
||||||
|
8
pkg/e2e/fixtures/dependencies/compose.yaml
Normal file
8
pkg/e2e/fixtures/dependencies/compose.yaml
Normal file
@ -0,0 +1,8 @@
|
|||||||
|
services:
|
||||||
|
foo:
|
||||||
|
image: nginx:alpine
|
||||||
|
depends_on:
|
||||||
|
- bar
|
||||||
|
|
||||||
|
bar:
|
||||||
|
image: nginx:alpine
|
@ -95,3 +95,27 @@ func TestStartStop(t *testing.T) {
|
|||||||
_ = c.RunDockerComposeCmd("--project-name", projectName, "down")
|
_ = c.RunDockerComposeCmd("--project-name", projectName, "down")
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func TestStopWithDependencies(t *testing.T) {
|
||||||
|
c := NewParallelE2eCLI(t, binDir)
|
||||||
|
const projectName = "e2e-stop-with-dependencies"
|
||||||
|
|
||||||
|
defer c.RunDockerComposeCmd("--project-name", projectName, "rm", "-fsv")
|
||||||
|
|
||||||
|
t.Run("Up", func(t *testing.T) {
|
||||||
|
res := c.RunDockerComposeCmd("-f", "./fixtures/dependencies/compose.yaml", "--project-name", projectName, "up", "-d")
|
||||||
|
assert.Assert(t, strings.Contains(res.Combined(), "Container e2e-stop-with-dependencies-foo-1 Started"), res.Combined())
|
||||||
|
assert.Assert(t, strings.Contains(res.Combined(), "Container e2e-stop-with-dependencies-bar-1 Started"), res.Combined())
|
||||||
|
})
|
||||||
|
|
||||||
|
t.Run("stop foo", func(t *testing.T) {
|
||||||
|
res := c.RunDockerComposeCmd("--project-name", projectName, "stop", "foo")
|
||||||
|
|
||||||
|
assert.Assert(t, strings.Contains(res.Combined(), "Container e2e-stop-with-dependencies-foo-1 Stopped"), res.Combined())
|
||||||
|
|
||||||
|
res = c.RunDockerComposeCmd("--project-name", projectName, "ps", "--status", "running")
|
||||||
|
assert.Assert(t, strings.Contains(res.Combined(), "e2e-stop-with-dependencies-bar-1"), res.Combined())
|
||||||
|
assert.Assert(t, !strings.Contains(res.Combined(), "e2e-stop-with-dependencies-foo-1"), res.Combined())
|
||||||
|
})
|
||||||
|
|
||||||
|
}
|
||||||
|
Loading…
x
Reference in New Issue
Block a user