From feba34e40664006a20a434b461f04fc4173e26b5 Mon Sep 17 00:00:00 2001 From: Nicolas De Loof Date: Mon, 3 Jan 2022 09:08:41 +0100 Subject: [PATCH] only remove volumes set by compose file Signed-off-by: Nicolas De Loof --- pkg/compose/down.go | 47 +++++++++++++++++++++++++--------------- pkg/compose/down_test.go | 9 +++++++- pkg/e2e/volumes_test.go | 6 ++--- 3 files changed, 40 insertions(+), 22 deletions(-) diff --git a/pkg/compose/down.go b/pkg/compose/down.go index 7aeb434fc..fda34fbd9 100644 --- a/pkg/compose/down.go +++ b/pkg/compose/down.go @@ -51,7 +51,10 @@ func (s *composeService) down(ctx context.Context, projectName string, options a } if options.Project == nil { - options.Project = s.projectFromContainerLabels(containers.filter(isNotOneOff), projectName) + options.Project, err = s.projectFromLabels(ctx, containers.filter(isNotOneOff), projectName) + if err != nil { + return err + } } if len(containers) > 0 { @@ -85,11 +88,7 @@ func (s *composeService) down(ctx context.Context, projectName string, options a } if options.Volumes { - rm, err := s.ensureVolumesDown(ctx, projectName, w) - if err != nil { - return err - } - ops = append(ops, rm...) + ops = append(ops, s.ensureVolumesDown(ctx, options.Project, w)...) } if !resourceToRemove && len(ops) == 0 { @@ -103,19 +102,15 @@ func (s *composeService) down(ctx context.Context, projectName string, options a return eg.Wait() } -func (s *composeService) ensureVolumesDown(ctx context.Context, projectName string, w progress.Writer) ([]downOp, error) { +func (s *composeService) ensureVolumesDown(ctx context.Context, project *types.Project, w progress.Writer) []downOp { var ops []downOp - volumes, err := s.apiClient.VolumeList(ctx, filters.NewArgs(projectFilter(projectName))) - if err != nil { - return ops, err - } - for _, vol := range volumes.Volumes { - id := vol.Name + for _, vol := range project.Volumes { + volumeName := vol.Name ops = append(ops, func() error { - return s.removeVolume(ctx, id, w) + return s.removeVolume(ctx, volumeName, w) }) } - return ops, nil + return ops } func (s *composeService) ensureImagesDown(ctx context.Context, projectName string, options api.DownOptions, w progress.Writer) []downOp { @@ -237,12 +232,13 @@ func (s *composeService) removeContainers(ctx context.Context, w progress.Writer return eg.Wait() } -func (s *composeService) projectFromContainerLabels(containers Containers, projectName string) *types.Project { +// projectFromLabels builds a types.Project based on actual resources with compose labels set +func (s *composeService) projectFromLabels(ctx context.Context, containers Containers, projectName string) (*types.Project, error) { project := &types.Project{ Name: projectName, } if len(containers) == 0 { - return project + return project, nil } set := map[string]moby.Container{} for _, c := range containers { @@ -263,5 +259,20 @@ func (s *composeService) projectFromContainerLabels(containers Containers, proje } project.Services = append(project.Services, service) } - return project + + volumes, err := s.apiClient.VolumeList(ctx, filters.NewArgs(projectFilter(projectName))) + if err != nil { + return nil, err + } + + 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, + } + } + + return project, nil } diff --git a/pkg/compose/down_test.go b/pkg/compose/down_test.go index bf6c9200a..b862ce154 100644 --- a/pkg/compose/down_test.go +++ b/pkg/compose/down_test.go @@ -44,6 +44,8 @@ func TestDown(t *testing.T) { testContainer("service2", "789", false), testContainer("service_orphan", "321", true), }, nil) + api.EXPECT().VolumeList(gomock.Any(), filters.NewArgs(projectFilter(strings.ToLower(testProject)))). + Return(volume.VolumeListOKBody{}, nil) api.EXPECT().ContainerStop(gomock.Any(), "123", nil).Return(nil) api.EXPECT().ContainerStop(gomock.Any(), "456", nil).Return(nil) @@ -74,6 +76,8 @@ func TestDownRemoveOrphans(t *testing.T) { testContainer("service2", "789", false), testContainer("service_orphan", "321", true), }, nil) + api.EXPECT().VolumeList(gomock.Any(), filters.NewArgs(projectFilter(strings.ToLower(testProject)))). + Return(volume.VolumeListOKBody{}, nil) api.EXPECT().ContainerStop(gomock.Any(), "123", nil).Return(nil) api.EXPECT().ContainerStop(gomock.Any(), "789", nil).Return(nil) @@ -100,13 +104,16 @@ func TestDownRemoveVolumes(t *testing.T) { api.EXPECT().ContainerList(gomock.Any(), projectFilterListOpt()).Return( []moby.Container{testContainer("service1", "123", false)}, nil) + api.EXPECT().VolumeList(gomock.Any(), filters.NewArgs(projectFilter(strings.ToLower(testProject)))). + Return(volume.VolumeListOKBody{ + Volumes: []*moby.Volume{{Name: "myProject_volume"}}, + }, 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().VolumeList(gomock.Any(), filters.NewArgs(projectFilter(strings.ToLower(testProject)))).Return(volume.VolumeListOKBody{Volumes: []*moby.Volume{{Name: "myProject_volume"}}}, nil) api.EXPECT().VolumeRemove(gomock.Any(), "myProject_volume", true).Return(nil) err := tested.Down(context.Background(), strings.ToLower(testProject), compose.DownOptions{Volumes: true}) diff --git a/pkg/e2e/volumes_test.go b/pkg/e2e/volumes_test.go index 32528a9df..571744902 100644 --- a/pkg/e2e/volumes_test.go +++ b/pkg/e2e/volumes_test.go @@ -83,8 +83,8 @@ func TestLocalComposeVolume(t *testing.T) { t.Run("cleanup volume project", func(t *testing.T) { c.RunDockerComposeCmd("--project-name", projectName, "down", "--volumes") - res := c.RunDockerCmd("volume", "ls") - assert.Assert(t, !strings.Contains(res.Stdout(), projectName+"_staticVol")) - assert.Assert(t, !strings.Contains(res.Stdout(), "myvolume")) + ls := c.RunDockerCmd("volume", "ls").Stdout() + assert.Assert(t, !strings.Contains(ls, projectName+"_staticVol")) + assert.Assert(t, !strings.Contains(ls, "myvolume")) }) }