mirror of https://github.com/docker/compose.git
Merge pull request #9281 from ndeloof/down_volume_external
don't remove external volumes/networks
This commit is contained in:
commit
d999c230a5
|
@ -24,15 +24,15 @@ import (
|
|||
"io"
|
||||
"strings"
|
||||
|
||||
"github.com/docker/compose/v2/pkg/api"
|
||||
"github.com/pkg/errors"
|
||||
|
||||
"github.com/compose-spec/compose-go/types"
|
||||
"github.com/docker/cli/cli/command"
|
||||
"github.com/docker/cli/cli/config/configfile"
|
||||
"github.com/docker/cli/cli/streams"
|
||||
"github.com/docker/compose/v2/pkg/api"
|
||||
moby "github.com/docker/docker/api/types"
|
||||
"github.com/docker/docker/api/types/filters"
|
||||
"github.com/docker/docker/client"
|
||||
"github.com/pkg/errors"
|
||||
"github.com/sanathkr/go-yaml"
|
||||
)
|
||||
|
||||
|
@ -194,3 +194,39 @@ func (s *composeService) actualState(ctx context.Context, projectName string, se
|
|||
}
|
||||
return containers, project, nil
|
||||
}
|
||||
|
||||
func (s *composeService) actualVolumes(ctx context.Context, projectName string) (types.Volumes, error) {
|
||||
volumes, err := s.apiClient().VolumeList(ctx, filters.NewArgs(projectFilter(projectName)))
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
actual := types.Volumes{}
|
||||
for _, vol := range volumes.Volumes {
|
||||
actual[vol.Labels[api.VolumeLabel]] = types.VolumeConfig{
|
||||
Name: vol.Name,
|
||||
Driver: vol.Driver,
|
||||
Labels: vol.Labels,
|
||||
}
|
||||
}
|
||||
return actual, nil
|
||||
}
|
||||
|
||||
func (s *composeService) actualNetworks(ctx context.Context, projectName string) (types.Networks, error) {
|
||||
networks, err := s.apiClient().NetworkList(ctx, moby.NetworkListOptions{
|
||||
Filters: filters.NewArgs(projectFilter(projectName)),
|
||||
})
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
actual := types.Networks{}
|
||||
for _, net := range networks {
|
||||
actual[net.Labels[api.NetworkLabel]] = types.NetworkConfig{
|
||||
Name: net.Name,
|
||||
Driver: net.Driver,
|
||||
Labels: net.Labels,
|
||||
}
|
||||
}
|
||||
return actual, nil
|
||||
}
|
||||
|
|
|
@ -1078,14 +1078,13 @@ func (s *composeService) ensureNetwork(ctx context.Context, n types.NetworkConfi
|
|||
return nil
|
||||
}
|
||||
|
||||
func (s *composeService) removeNetwork(ctx context.Context, networkID string, networkName string) error {
|
||||
w := progress.ContextWriter(ctx)
|
||||
eventName := fmt.Sprintf("Network %s", networkName)
|
||||
func (s *composeService) removeNetwork(ctx context.Context, network string, w progress.Writer) error {
|
||||
eventName := fmt.Sprintf("Network %s", network)
|
||||
w.Event(progress.RemovingEvent(eventName))
|
||||
|
||||
if err := s.apiClient().NetworkRemove(ctx, networkID); err != nil {
|
||||
if err := s.apiClient().NetworkRemove(ctx, network); err != nil {
|
||||
w.Event(progress.ErrorEvent(eventName))
|
||||
return errors.Wrapf(err, fmt.Sprintf("failed to remove network %s", networkID))
|
||||
return errors.Wrapf(err, fmt.Sprintf("failed to remove network %s", network))
|
||||
}
|
||||
|
||||
w.Event(progress.RemovedEvent(eventName))
|
||||
|
|
|
@ -24,7 +24,6 @@ import (
|
|||
|
||||
"github.com/compose-spec/compose-go/types"
|
||||
moby "github.com/docker/docker/api/types"
|
||||
"github.com/docker/docker/api/types/filters"
|
||||
"github.com/docker/docker/errdefs"
|
||||
"golang.org/x/sync/errgroup"
|
||||
|
||||
|
@ -41,7 +40,6 @@ func (s *composeService) Down(ctx context.Context, projectName string, options a
|
|||
}
|
||||
|
||||
func (s *composeService) down(ctx context.Context, projectName string, options api.DownOptions) error {
|
||||
builtFromResources := options.Project == nil
|
||||
w := progress.ContextWriter(ctx)
|
||||
resourceToRemove := false
|
||||
|
||||
|
@ -51,8 +49,9 @@ func (s *composeService) down(ctx context.Context, projectName string, options a
|
|||
return err
|
||||
}
|
||||
|
||||
if builtFromResources {
|
||||
options.Project, err = s.getProjectWithVolumes(ctx, containers, projectName)
|
||||
project := options.Project
|
||||
if project == nil {
|
||||
project, err = s.getProjectWithResources(ctx, containers, projectName)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
@ -62,7 +61,7 @@ func (s *composeService) down(ctx context.Context, projectName string, options a
|
|||
resourceToRemove = true
|
||||
}
|
||||
|
||||
err = InReverseDependencyOrder(ctx, options.Project, func(c context.Context, service string) error {
|
||||
err = InReverseDependencyOrder(ctx, project, func(c context.Context, service string) error {
|
||||
serviceContainers := containers.filter(isService(service))
|
||||
err := s.removeContainers(ctx, w, serviceContainers, options.Timeout, options.Volumes)
|
||||
return err
|
||||
|
@ -71,7 +70,7 @@ func (s *composeService) down(ctx context.Context, projectName string, options a
|
|||
return err
|
||||
}
|
||||
|
||||
orphans := containers.filter(isNotService(options.Project.ServiceNames()...))
|
||||
orphans := containers.filter(isNotService(project.ServiceNames()...))
|
||||
if options.RemoveOrphans && len(orphans) > 0 {
|
||||
err := s.removeContainers(ctx, w, orphans, options.Timeout, false)
|
||||
if err != nil {
|
||||
|
@ -79,17 +78,14 @@ func (s *composeService) down(ctx context.Context, projectName string, options a
|
|||
}
|
||||
}
|
||||
|
||||
ops, err := s.ensureNetworksDown(ctx, projectName)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
ops := s.ensureNetworksDown(ctx, project, w)
|
||||
|
||||
if options.Images != "" {
|
||||
ops = append(ops, s.ensureImagesDown(ctx, projectName, options, w)...)
|
||||
}
|
||||
|
||||
if options.Volumes {
|
||||
ops = append(ops, s.ensureVolumesDown(ctx, options.Project, w)...)
|
||||
ops = append(ops, s.ensureVolumesDown(ctx, project, w)...)
|
||||
}
|
||||
|
||||
if !resourceToRemove && len(ops) == 0 {
|
||||
|
@ -106,6 +102,9 @@ func (s *composeService) down(ctx context.Context, projectName string, options a
|
|||
func (s *composeService) ensureVolumesDown(ctx context.Context, project *types.Project, w progress.Writer) []downOp {
|
||||
var ops []downOp
|
||||
for _, vol := range project.Volumes {
|
||||
if vol.External.External {
|
||||
continue
|
||||
}
|
||||
volumeName := vol.Name
|
||||
ops = append(ops, func() error {
|
||||
return s.removeVolume(ctx, volumeName, w)
|
||||
|
@ -125,20 +124,18 @@ func (s *composeService) ensureImagesDown(ctx context.Context, projectName strin
|
|||
return ops
|
||||
}
|
||||
|
||||
func (s *composeService) ensureNetworksDown(ctx context.Context, projectName string) ([]downOp, error) {
|
||||
func (s *composeService) ensureNetworksDown(ctx context.Context, project *types.Project, w progress.Writer) []downOp {
|
||||
var ops []downOp
|
||||
networks, err := s.apiClient().NetworkList(ctx, moby.NetworkListOptions{Filters: filters.NewArgs(projectFilter(projectName))})
|
||||
if err != nil {
|
||||
return ops, err
|
||||
}
|
||||
for _, n := range networks {
|
||||
networkID := n.ID
|
||||
for _, n := range project.Networks {
|
||||
if n.External.External {
|
||||
continue
|
||||
}
|
||||
networkName := n.Name
|
||||
ops = append(ops, func() error {
|
||||
return s.removeNetwork(ctx, networkID, networkName)
|
||||
return s.removeNetwork(ctx, networkName, w)
|
||||
})
|
||||
}
|
||||
return ops, nil
|
||||
return ops
|
||||
}
|
||||
|
||||
func (s *composeService) getServiceImages(options api.DownOptions, projectName string) map[string]struct{} {
|
||||
|
@ -233,21 +230,20 @@ func (s *composeService) removeContainers(ctx context.Context, w progress.Writer
|
|||
return eg.Wait()
|
||||
}
|
||||
|
||||
func (s *composeService) getProjectWithVolumes(ctx context.Context, containers Containers, projectName string) (*types.Project, error) {
|
||||
func (s *composeService) getProjectWithResources(ctx context.Context, containers Containers, projectName string) (*types.Project, error) {
|
||||
containers = containers.filter(isNotOneOff)
|
||||
project, _ := s.projectFromName(containers, projectName)
|
||||
volumes, err := s.apiClient().VolumeList(ctx, filters.NewArgs(projectFilter(projectName)))
|
||||
|
||||
volumes, err := s.actualVolumes(ctx, projectName)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
project.Volumes = volumes
|
||||
|
||||
project.Volumes = types.Volumes{}
|
||||
for _, vol := range volumes.Volumes {
|
||||
project.Volumes[vol.Labels[api.VolumeLabel]] = types.VolumeConfig{
|
||||
Name: vol.Name,
|
||||
Driver: vol.Driver,
|
||||
Labels: vol.Labels,
|
||||
}
|
||||
networks, err := s.actualNetworks(ctx, projectName)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
project.Networks = networks
|
||||
return project, nil
|
||||
}
|
||||
|
|
|
@ -49,6 +49,8 @@ func TestDown(t *testing.T) {
|
|||
}, nil)
|
||||
api.EXPECT().VolumeList(gomock.Any(), filters.NewArgs(projectFilter(strings.ToLower(testProject)))).
|
||||
Return(volume.VolumeListOKBody{}, nil)
|
||||
api.EXPECT().NetworkList(gomock.Any(), moby.NetworkListOptions{Filters: filters.NewArgs(projectFilter(strings.ToLower(testProject)))}).
|
||||
Return([]moby.NetworkResource{{Name: "myProject_default"}}, nil)
|
||||
|
||||
api.EXPECT().ContainerStop(gomock.Any(), "123", nil).Return(nil)
|
||||
api.EXPECT().ContainerStop(gomock.Any(), "456", nil).Return(nil)
|
||||
|
@ -58,9 +60,6 @@ func TestDown(t *testing.T) {
|
|||
api.EXPECT().ContainerRemove(gomock.Any(), "456", moby.ContainerRemoveOptions{Force: true}).Return(nil)
|
||||
api.EXPECT().ContainerRemove(gomock.Any(), "789", moby.ContainerRemoveOptions{Force: true}).Return(nil)
|
||||
|
||||
api.EXPECT().NetworkList(gomock.Any(), moby.NetworkListOptions{Filters: filters.NewArgs(projectFilter(strings.ToLower(testProject)))}).Return([]moby.NetworkResource{{ID: "myProject_default"}},
|
||||
nil)
|
||||
|
||||
api.EXPECT().NetworkRemove(gomock.Any(), "myProject_default").Return(nil)
|
||||
|
||||
err := tested.Down(context.Background(), strings.ToLower(testProject), compose.DownOptions{})
|
||||
|
@ -84,6 +83,8 @@ func TestDownRemoveOrphans(t *testing.T) {
|
|||
}, nil)
|
||||
api.EXPECT().VolumeList(gomock.Any(), filters.NewArgs(projectFilter(strings.ToLower(testProject)))).
|
||||
Return(volume.VolumeListOKBody{}, nil)
|
||||
api.EXPECT().NetworkList(gomock.Any(), moby.NetworkListOptions{Filters: filters.NewArgs(projectFilter(strings.ToLower(testProject)))}).
|
||||
Return([]moby.NetworkResource{{Name: "myProject_default"}}, nil)
|
||||
|
||||
api.EXPECT().ContainerStop(gomock.Any(), "123", nil).Return(nil)
|
||||
api.EXPECT().ContainerStop(gomock.Any(), "789", nil).Return(nil)
|
||||
|
@ -93,9 +94,6 @@ func TestDownRemoveOrphans(t *testing.T) {
|
|||
api.EXPECT().ContainerRemove(gomock.Any(), "789", moby.ContainerRemoveOptions{Force: true}).Return(nil)
|
||||
api.EXPECT().ContainerRemove(gomock.Any(), "321", moby.ContainerRemoveOptions{Force: true}).Return(nil)
|
||||
|
||||
api.EXPECT().NetworkList(gomock.Any(), moby.NetworkListOptions{Filters: filters.NewArgs(projectFilter(strings.ToLower(testProject)))}).Return([]moby.NetworkResource{{ID: "myProject_default"}},
|
||||
nil)
|
||||
|
||||
api.EXPECT().NetworkRemove(gomock.Any(), "myProject_default").Return(nil)
|
||||
|
||||
err := tested.Down(context.Background(), strings.ToLower(testProject), compose.DownOptions{RemoveOrphans: true})
|
||||
|
@ -117,12 +115,12 @@ func TestDownRemoveVolumes(t *testing.T) {
|
|||
Return(volume.VolumeListOKBody{
|
||||
Volumes: []*moby.Volume{{Name: "myProject_volume"}},
|
||||
}, nil)
|
||||
api.EXPECT().NetworkList(gomock.Any(), moby.NetworkListOptions{Filters: filters.NewArgs(projectFilter(strings.ToLower(testProject)))}).
|
||||
Return(nil, nil)
|
||||
|
||||
api.EXPECT().ContainerStop(gomock.Any(), "123", nil).Return(nil)
|
||||
api.EXPECT().ContainerRemove(gomock.Any(), "123", moby.ContainerRemoveOptions{Force: true, RemoveVolumes: true}).Return(nil)
|
||||
|
||||
api.EXPECT().NetworkList(gomock.Any(), moby.NetworkListOptions{Filters: filters.NewArgs(projectFilter(strings.ToLower(testProject)))}).Return(nil, nil)
|
||||
|
||||
api.EXPECT().VolumeRemove(gomock.Any(), "myProject_volume", true).Return(nil)
|
||||
|
||||
err := tested.Down(context.Background(), strings.ToLower(testProject), compose.DownOptions{Volumes: true})
|
||||
|
|
Loading…
Reference in New Issue