mirror of
https://github.com/docker/compose.git
synced 2025-04-08 17:05:13 +02:00
Merge pull request #1618 from ndeloof/remove_volume
This commit is contained in:
commit
64329c2223
@ -938,7 +938,7 @@ func (s *composeService) ensureNetwork(ctx context.Context, n types.NetworkConfi
|
||||
return nil
|
||||
}
|
||||
|
||||
func (s *composeService) ensureNetworkDown(ctx context.Context, networkID string, networkName string) error {
|
||||
func (s *composeService) removeNetwork(ctx context.Context, networkID string, networkName string) error {
|
||||
w := progress.ContextWriter(ctx)
|
||||
eventName := fmt.Sprintf("Network %s", networkName)
|
||||
w.Event(progress.RemovingEvent(eventName))
|
||||
|
@ -33,6 +33,8 @@ import (
|
||||
"github.com/docker/compose-cli/api/progress"
|
||||
)
|
||||
|
||||
type downOp func() error
|
||||
|
||||
func (s *composeService) Down(ctx context.Context, projectName string, options compose.DownOptions) error {
|
||||
w := progress.ContextWriter(ctx)
|
||||
resourceToRemove := false
|
||||
@ -73,37 +75,76 @@ func (s *composeService) Down(ctx context.Context, projectName string, options c
|
||||
}
|
||||
}
|
||||
|
||||
networks, err := s.apiClient.NetworkList(ctx, moby.NetworkListOptions{Filters: filters.NewArgs(projectFilter(projectName))})
|
||||
ops, err := s.ensureNetwoksDown(ctx, projectName)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
eg, _ := errgroup.WithContext(ctx)
|
||||
for _, n := range networks {
|
||||
resourceToRemove = true
|
||||
networkID := n.ID
|
||||
networkName := n.Name
|
||||
eg.Go(func() error {
|
||||
return s.ensureNetworkDown(ctx, networkID, networkName)
|
||||
})
|
||||
}
|
||||
|
||||
if options.Images != "" {
|
||||
for image := range s.getServiceImages(options, projectName) {
|
||||
image := image
|
||||
eg.Go(func() error {
|
||||
resourceToRemove = true
|
||||
return s.removeImage(ctx, image, w)
|
||||
})
|
||||
}
|
||||
ops = append(ops, s.ensureImagesDown(ctx, projectName, options, w)...)
|
||||
}
|
||||
|
||||
if !resourceToRemove {
|
||||
if options.Volumes {
|
||||
rm, err := s.ensureVolumesDown(ctx, projectName, w)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
ops = append(ops, rm...)
|
||||
}
|
||||
|
||||
if !resourceToRemove && len(ops) == 0 {
|
||||
w.Event(progress.NewEvent(projectName, progress.Done, "Warning: No resource found to remove"))
|
||||
}
|
||||
|
||||
eg, _ := errgroup.WithContext(ctx)
|
||||
for _, op := range ops {
|
||||
eg.Go(op)
|
||||
}
|
||||
return eg.Wait()
|
||||
}
|
||||
|
||||
func (s *composeService) ensureVolumesDown(ctx context.Context, projectName string, w progress.Writer) ([]downOp, error) {
|
||||
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
|
||||
ops = append(ops, func() error {
|
||||
return s.removeVolume(ctx, id, w)
|
||||
})
|
||||
}
|
||||
return ops, nil
|
||||
}
|
||||
|
||||
func (s *composeService) ensureImagesDown(ctx context.Context, projectName string, options compose.DownOptions, w progress.Writer) []downOp {
|
||||
var ops []downOp
|
||||
for image := range s.getServiceImages(options, projectName) {
|
||||
image := image
|
||||
ops = append(ops, func() error {
|
||||
return s.removeImage(ctx, image, w)
|
||||
})
|
||||
}
|
||||
return ops
|
||||
}
|
||||
|
||||
func (s *composeService) ensureNetwoksDown(ctx context.Context, projectName string) ([]downOp, error) {
|
||||
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
|
||||
networkName := n.Name
|
||||
ops = append(ops, func() error {
|
||||
return s.removeNetwork(ctx, networkID, networkName)
|
||||
})
|
||||
}
|
||||
return ops, nil
|
||||
}
|
||||
|
||||
func (s *composeService) getServiceImages(options compose.DownOptions, projectName string) map[string]struct{} {
|
||||
images := map[string]struct{}{}
|
||||
for _, service := range options.Project.Services {
|
||||
@ -134,6 +175,21 @@ func (s *composeService) removeImage(ctx context.Context, image string, w progre
|
||||
return err
|
||||
}
|
||||
|
||||
func (s *composeService) removeVolume(ctx context.Context, id string, w progress.Writer) error {
|
||||
resource := fmt.Sprintf("Volume %s", id)
|
||||
w.Event(progress.NewEvent(resource, progress.Working, "Removing"))
|
||||
err := s.apiClient.VolumeRemove(ctx, id, true)
|
||||
if err == nil {
|
||||
w.Event(progress.NewEvent(resource, progress.Done, "Removed"))
|
||||
return nil
|
||||
}
|
||||
if errdefs.IsNotFound(err) {
|
||||
w.Event(progress.NewEvent(resource, progress.Done, "Warning: No resource found to remove"))
|
||||
return nil
|
||||
}
|
||||
return err
|
||||
}
|
||||
|
||||
func (s *composeService) stopContainers(ctx context.Context, w progress.Writer, containers []moby.Container, timeout *time.Duration) error {
|
||||
for _, container := range containers {
|
||||
toStop := container
|
||||
|
@ -20,12 +20,12 @@ import (
|
||||
"context"
|
||||
"testing"
|
||||
|
||||
"github.com/docker/docker/api/types/filters"
|
||||
|
||||
"github.com/docker/compose-cli/api/compose"
|
||||
"github.com/docker/compose-cli/local/mocks"
|
||||
|
||||
apitypes "github.com/docker/docker/api/types"
|
||||
"github.com/docker/docker/api/types/filters"
|
||||
"github.com/docker/docker/api/types/volume"
|
||||
"github.com/golang/mock/gomock"
|
||||
"gotest.tools/v3/assert"
|
||||
)
|
||||
@ -79,3 +79,24 @@ func TestDownRemoveOrphans(t *testing.T) {
|
||||
err := tested.Down(context.Background(), testProject, compose.DownOptions{RemoveOrphans: true})
|
||||
assert.NilError(t, err)
|
||||
}
|
||||
|
||||
func TestDownRemoveVolumes(t *testing.T) {
|
||||
mockCtrl := gomock.NewController(t)
|
||||
defer mockCtrl.Finish()
|
||||
api := mocks.NewMockAPIClient(mockCtrl)
|
||||
tested.apiClient = api
|
||||
|
||||
api.EXPECT().ContainerList(gomock.Any(), projectFilterListOpt()).Return(
|
||||
[]apitypes.Container{testContainer("service1", "123")}, nil)
|
||||
|
||||
api.EXPECT().ContainerStop(gomock.Any(), "123", nil).Return(nil)
|
||||
api.EXPECT().ContainerRemove(gomock.Any(), "123", apitypes.ContainerRemoveOptions{Force: true}).Return(nil)
|
||||
|
||||
api.EXPECT().NetworkList(gomock.Any(), apitypes.NetworkListOptions{Filters: filters.NewArgs(projectFilter(testProject))}).Return(nil, nil)
|
||||
|
||||
api.EXPECT().VolumeList(gomock.Any(), filters.NewArgs(projectFilter(testProject))).Return(volume.VolumeListOKBody{Volumes: []*apitypes.Volume{{Name: "myProject_volume"}}}, nil)
|
||||
api.EXPECT().VolumeRemove(gomock.Any(), "myProject_volume", true).Return(nil)
|
||||
|
||||
err := tested.Down(context.Background(), testProject, compose.DownOptions{Volumes: true})
|
||||
assert.NilError(t, err)
|
||||
}
|
||||
|
@ -72,7 +72,9 @@ func TestLocalComposeVolume(t *testing.T) {
|
||||
})
|
||||
|
||||
t.Run("cleanup volume project", func(t *testing.T) {
|
||||
c.RunDockerCmd("compose", "--project-name", projectName, "down")
|
||||
c.RunDockerCmd("volume", "rm", projectName+"_staticVol")
|
||||
c.RunDockerCmd("compose", "--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"))
|
||||
})
|
||||
}
|
||||
|
Loading…
x
Reference in New Issue
Block a user