From 03015fe6dee6dd083c42dd1a2f4df006c2d6eae1 Mon Sep 17 00:00:00 2001 From: Drew Erny Date: Wed, 3 Aug 2022 11:04:14 -0500 Subject: [PATCH] fix force remove for cluster volumes Signed-off-by: Drew Erny (cherry picked from commit 3246db3755698455740c812c6477f43e74924fa7) Signed-off-by: Bjorn Neergaard --- api/server/router/volume/volume_routes.go | 15 ++++++++++----- api/server/router/volume/volume_routes_test.go | 12 ++++++++++-- 2 files changed, 20 insertions(+), 7 deletions(-) diff --git a/api/server/router/volume/volume_routes.go b/api/server/router/volume/volume_routes.go index 7f1adfaa78..7a0fa42c26 100644 --- a/api/server/router/volume/volume_routes.go +++ b/api/server/router/volume/volume_routes.go @@ -162,11 +162,16 @@ func (v *volumeRouter) deleteVolumes(ctx context.Context, w http.ResponseWriter, version := httputils.VersionFromContext(ctx) err := v.backend.Remove(ctx, vars["name"], opts.WithPurgeOnError(force)) - if err != nil { - if errdefs.IsNotFound(err) && versions.GreaterThanOrEqualTo(version, clusterVolumesVersion) && v.cluster.IsManager() { - err := v.cluster.RemoveVolume(vars["name"], force) - if err != nil { - return err + // when a removal is forced, if the volume does not exist, no error will be + // returned. this means that to ensure forcing works on swarm volumes as + // well, we should always also force remove against the cluster. + if err != nil || force { + if versions.GreaterThanOrEqualTo(version, clusterVolumesVersion) && v.cluster.IsManager() { + if errdefs.IsNotFound(err) || force { + err := v.cluster.RemoveVolume(vars["name"], force) + if err != nil { + return err + } } } else { return err diff --git a/api/server/router/volume/volume_routes_test.go b/api/server/router/volume/volume_routes_test.go index c80ff189a4..9bc50f3392 100644 --- a/api/server/router/volume/volume_routes_test.go +++ b/api/server/router/volume/volume_routes_test.go @@ -574,6 +574,7 @@ func TestVolumeRemoveSwarmForce(t *testing.T) { assert.NilError(t, err) assert.Equal(t, len(b.volumes), 0) + assert.Equal(t, len(c.volumes), 0) } type fakeVolumeBackend struct { @@ -616,9 +617,16 @@ func (b *fakeVolumeBackend) Create(_ context.Context, name, driverName string, _ return v, nil } -func (b *fakeVolumeBackend) Remove(_ context.Context, name string, _ ...opts.RemoveOption) error { +func (b *fakeVolumeBackend) Remove(_ context.Context, name string, o ...opts.RemoveOption) error { + removeOpts := &opts.RemoveConfig{} + for _, opt := range o { + opt(removeOpts) + } + if v, ok := b.volumes[name]; !ok { - return errdefs.NotFound(fmt.Errorf("volume %s not found", name)) + if !removeOpts.PurgeOnError { + return errdefs.NotFound(fmt.Errorf("volume %s not found", name)) + } } else if v.Name == "inuse" { return errdefs.Conflict(fmt.Errorf("volume in use")) }