Sfoglia il codice sorgente

Merge pull request #9281 from ndeloof/down_volume_external

don't remove external volumes/networks
Guillaume Lours 3 anni fa
parent
commit
d999c230a5
4 ha cambiato i file con 74 aggiunte e 45 eliminazioni
  1. 39 3
      pkg/compose/compose.go
  2. 4 5
      pkg/compose/create.go
  3. 25 29
      pkg/compose/down.go
  4. 6 8
      pkg/compose/down_test.go

+ 39 - 3
pkg/compose/compose.go

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

+ 4 - 5
pkg/compose/create.go

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

+ 25 - 29
pkg/compose/down.go

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

+ 6 - 8
pkg/compose/down_test.go

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