diff --git a/internal/ceph/ceph.go b/internal/ceph/ceph.go index 795bca6..26f47ba 100644 --- a/internal/ceph/ceph.go +++ b/internal/ceph/ceph.go @@ -43,6 +43,8 @@ type CephCmd interface { RBDInfo(pool, image string) (*RBDImageInfo, error) RBDLs(pool string) ([]string, error) RBDRm(pool, image string) error + RBDTrashMv(pool, image string) error + CephRBDTaskAddTrashRemove(pool, image string) error RBDSnapCreate(pool, image, snap string) error RBDSnapLs(pool, image string) ([]RBDSnapshot, error) RBDSnapRm(pool, image, snap string) error diff --git a/internal/ceph/rbd.go b/internal/ceph/rbd.go index c46e6b3..b2fea97 100644 --- a/internal/ceph/rbd.go +++ b/internal/ceph/rbd.go @@ -62,6 +62,24 @@ func (c *cephCmdImpl) RBDRm(pool, image string) error { return nil } +// RBDTrashMv removes an RBD image asynchronously. +func (c *cephCmdImpl) RBDTrashMv(pool, image string) error { + _, err := c.command.execute("rbd", "trash", "mv", fmt.Sprintf("%s/%s", pool, image)) + if err != nil { + return fmt.Errorf("failed to move RBD image to trash: %w", err) + } + return nil +} + +// CephRBDTaskTrashRemove adds a task to remove the image from trash. +func (c *cephCmdImpl) CephRBDTaskAddTrashRemove(pool, imageID string) error { + _, err := c.command.execute("ceph", "rbd", "task", "add", "trash", "remove", fmt.Sprintf("%s/%s", pool, imageID)) + if err != nil { + return fmt.Errorf("failed to add task to remove the image from trash: %w", err) + } + return nil +} + // RBDSnapCreate creates an RBD snapshot. func (c *cephCmdImpl) RBDSnapCreate(pool, image, snap string) error { _, err := c.command.execute("rbd", "snap", "create", fmt.Sprintf("%s/%s@%s", pool, image, snap)) diff --git a/internal/controller/internal/testutil/fake_rbd.go b/internal/controller/internal/testutil/fake_rbd.go index fb3c39e..1823740 100644 --- a/internal/controller/internal/testutil/fake_rbd.go +++ b/internal/controller/internal/testutil/fake_rbd.go @@ -38,6 +38,14 @@ func (f *fakeRBD) RBDRm(pool, image string) error { return nil } +func (f *fakeRBD) RBDTrashMv(pool, image string) error { + return nil +} + +func (f *fakeRBD) CephRBDTaskAddTrashRemove(pool, image string) error { + return nil +} + func (f *fakeRBD) RBDSnapCreate(pool, image, snap string) error { key := pool + "/" + image diff --git a/internal/controller/persistentvolume_controller.go b/internal/controller/persistentvolume_controller.go index ec0043d..b12a836 100644 --- a/internal/controller/persistentvolume_controller.go +++ b/internal/controller/persistentvolume_controller.go @@ -132,12 +132,25 @@ func (r *PersistentVolumeReconciler) removeRBDImage(ctx context.Context, pv *cor images, err := r.ceph.RBDLs(pool) if err != nil { - return fmt.Errorf("failed to list RBD images: %v", err) + return fmt.Errorf("failed to list RBD images: %w", err) } if !slices.Contains(images, image) { return nil } - return r.ceph.RBDRm(pool, image) + imageInfo, err := r.ceph.RBDInfo(pool, image) + if err != nil { + return fmt.Errorf("failed to get info about the RBD image: %s/%s: %w", pool, image, err) + } + + if err := r.ceph.RBDTrashMv(pool, image); err != nil { + return fmt.Errorf("failed to move the RBD image to trash: %s/%s: %w", pool, image, err) + } + + if err := r.ceph.CephRBDTaskAddTrashRemove(pool, imageInfo.ID); err != nil { + return fmt.Errorf("failed to add task to remove the RBD image from trash: %s/%s: %w", pool, image, err) + } + + return nil }