Merge pull request #9281 from ndeloof/down_volume_external

don't remove external volumes/networks
This commit is contained in:
Guillaume Lours 2022-03-14 17:21:04 +01:00 committed by GitHub
commit d999c230a5
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
4 changed files with 74 additions and 45 deletions

View File

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

View File

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

View File

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

View File

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