Skip to content

Commit 134eca9

Browse files
authored
Merge pull request #276 from cybozu-go/fix-expire
Fix expire not running when target PVC is deleted before backup expires
2 parents e6f561b + 6482709 commit 134eca9

11 files changed

Lines changed: 900 additions & 82 deletions

File tree

internal/ceph/ceph.go

Lines changed: 8 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -45,6 +45,11 @@ type RBDSnapshot struct {
4545
Timestamp RBDTimeStamp `json:"timestamp,omitzero"`
4646
}
4747

48+
type RBDTrashInfo struct {
49+
ID string `json:"id"`
50+
Name string `json:"name"`
51+
}
52+
4853
type CephCmd interface {
4954
RBDClone(pool, srcImage, srcSnap, dstImage, features string) error
5055
RBDInfo(pool, image string) (*RBDImageInfo, error)
@@ -54,10 +59,12 @@ type CephCmd interface {
5459
RBDLockRm(pool, image string, lock *RBDLock) error
5560
RBDRm(pool, image string) error
5661
RBDTrashMv(pool, image string) error
62+
RBDTrashLs(pool string) ([]*RBDTrashInfo, error)
5763
CephRBDTaskAddTrashRemove(pool, image string) error
5864
RBDSnapCreate(pool, image, snap string) error
5965
RBDSnapLs(pool, image string) ([]RBDSnapshot, error)
60-
RBDSnapRm(pool, image, snap string) error
66+
RBDSnapLsByID(pool, imageID string) ([]RBDSnapshot, error)
67+
RBDSnapRm(pool, imageID, snap string) error
6168
}
6269

6370
type cephCmdImpl struct {

internal/ceph/ceph_mock.go

Lines changed: 34 additions & 4 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

internal/ceph/rbd.go

Lines changed: 34 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -109,6 +109,22 @@ func (c *cephCmdImpl) RBDTrashMv(pool, image string) error {
109109
return nil
110110
}
111111

112+
// RBDTrashLs lists RBD images in trash.
113+
func (c *cephCmdImpl) RBDTrashLs(pool string) ([]*RBDTrashInfo, error) {
114+
stdout, stderr, err := c.command.execute("rbd", "trash", "ls", "-p", pool, "--format", "json")
115+
if err != nil {
116+
return nil, fmt.Errorf("failed to list RBD images in trash: %w, stderr: %s", err, string(stderr))
117+
}
118+
119+
var trashInfos []*RBDTrashInfo
120+
err = json.Unmarshal(stdout, &trashInfos)
121+
if err != nil {
122+
return nil, fmt.Errorf("failed to unmarshal RBD trash info: %w, stdout: %s", err, stdout)
123+
}
124+
125+
return trashInfos, nil
126+
}
127+
112128
// CephRBDTaskTrashRemove adds a task to remove the image from trash.
113129
func (c *cephCmdImpl) CephRBDTaskAddTrashRemove(pool, imageID string) error {
114130
_, stderr, err := c.command.execute("ceph", "rbd", "task", "add", "trash", "remove", fmt.Sprintf("%s/%s", pool, imageID))
@@ -145,9 +161,25 @@ func (c *cephCmdImpl) RBDSnapLs(pool, image string) ([]RBDSnapshot, error) {
145161
return snapshots, nil
146162
}
147163

164+
// RBDSnapLsByID lists RBD snapshots of an image by image ID.
165+
func (c *cephCmdImpl) RBDSnapLsByID(pool, imageID string) ([]RBDSnapshot, error) {
166+
stdout, stderr, err := c.command.execute("rbd", "snap", "ls", "-p", pool, "--image-id", imageID, "--format", "json")
167+
if err != nil {
168+
return nil, fmt.Errorf("failed to list RBD snapshots: %w, stderr: %s", err, string(stderr))
169+
}
170+
171+
var snapshots []RBDSnapshot
172+
err = json.Unmarshal(stdout, &snapshots)
173+
if err != nil {
174+
return nil, fmt.Errorf("failed to unmarshal RBD snapshots: %w, stdout: %s", err, stdout)
175+
}
176+
177+
return snapshots, nil
178+
}
179+
148180
// RBDSnapRm removes an RBD snapshot.
149-
func (c *cephCmdImpl) RBDSnapRm(pool, image, snap string) error {
150-
_, stderr, err := c.command.execute("rbd", "snap", "rm", fmt.Sprintf("%s/%s@%s", pool, image, snap))
181+
func (c *cephCmdImpl) RBDSnapRm(pool, imageID, snap string) error {
182+
_, stderr, err := c.command.execute("rbd", "snap", "rm", "-p", pool, "--image-id", imageID, "--snap", snap)
151183
if err != nil {
152184
return fmt.Errorf("failed to remove RBD snapshot: %w, stderr: %s", err, string(stderr))
153185
}

internal/ceph/rbd_test.go

Lines changed: 95 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -309,6 +309,59 @@ var _ = Describe("CephCmd.RBDRm", func() {
309309
})
310310
})
311311

312+
var _ = Describe("CephCmd.RBDTrashLs", func() {
313+
var t reporter
314+
315+
It("should return the correct list of trashed images", func() {
316+
ctrl := gomock.NewController(t)
317+
defer ctrl.Finish()
318+
319+
m := NewMockcommand(ctrl)
320+
m.EXPECT().
321+
execute("rbd", "trash", "ls", "-p", "pool", "--format", "json").
322+
Return([]byte(`[
323+
{"id": "abc123", "name": "csi-vol-d2556cc0-5ba6-4e70-b966-56522225bdc5"},
324+
{"id": "def456", "name": "csi-vol-f2a83492-3cf2-48e7-8500-804754c42ce6"}
325+
]`), []byte{}, nil)
326+
327+
cmd := mockedCephCmd(m)
328+
infos, err := cmd.RBDTrashLs("pool")
329+
Expect(err).ToNot(HaveOccurred())
330+
Expect(infos).To(HaveLen(2))
331+
Expect(infos[0].ID).To(Equal("abc123"))
332+
Expect(infos[0].Name).To(Equal("csi-vol-d2556cc0-5ba6-4e70-b966-56522225bdc5"))
333+
Expect(infos[1].ID).To(Equal("def456"))
334+
Expect(infos[1].Name).To(Equal("csi-vol-f2a83492-3cf2-48e7-8500-804754c42ce6"))
335+
})
336+
337+
It("should return empty list, if trash is empty", func() {
338+
ctrl := gomock.NewController(t)
339+
defer ctrl.Finish()
340+
341+
m := NewMockcommand(ctrl)
342+
m.EXPECT().
343+
execute("rbd", "trash", "ls", "-p", "pool", "--format", "json").
344+
Return([]byte(`[]`), []byte{}, nil)
345+
346+
cmd := mockedCephCmd(m)
347+
infos, err := cmd.RBDTrashLs("pool")
348+
Expect(err).ToNot(HaveOccurred())
349+
Expect(infos).To(BeEmpty())
350+
})
351+
352+
It("should return an error, if the command failed", func() {
353+
ctrl := gomock.NewController(t)
354+
defer ctrl.Finish()
355+
356+
m := NewMockcommand(ctrl)
357+
m.EXPECT().execute(gomock.Any()).Return([]byte{}, []byte("error!"), errors.New("error"))
358+
359+
cmd := mockedCephCmd(m)
360+
_, err := cmd.RBDTrashLs("pool")
361+
Expect(err).To(HaveOccurred())
362+
})
363+
})
364+
312365
var _ = Describe("CephCmd.RBDSnapCreate", func() {
313366
var t reporter
314367

@@ -378,6 +431,45 @@ var _ = Describe("CephCmd.RBDSnapLs", func() {
378431
})
379432
})
380433

434+
var _ = Describe("CephCmd.RBDSnapLsByID", func() {
435+
var t reporter
436+
437+
It("should return the correct RBDSnapshot", func() {
438+
ctrl := gomock.NewController(t)
439+
defer ctrl.Finish()
440+
441+
m := NewMockcommand(ctrl)
442+
m.EXPECT().
443+
execute("rbd", "snap", "ls", "-p", "pool", "--image-id", "image-id", "--format", "json").
444+
Return([]byte(`
445+
[{"id":4,"name":"test","size":10737418240,"protected":"false","timestamp":"Tue Oct 1 10:11:31 2024"}]
446+
`), []byte{}, nil)
447+
448+
cmd := mockedCephCmd(m)
449+
snaps, err := cmd.RBDSnapLsByID("pool", "image-id")
450+
Expect(err).ToNot(HaveOccurred())
451+
Expect(snaps).To(HaveLen(1))
452+
snap := snaps[0]
453+
Expect(snap.Id).To(Equal(int(4)))
454+
Expect(snap.Name).To(Equal("test"))
455+
Expect(snap.Size).To(Equal(int64(10737418240)))
456+
Expect(snap.Protected).To(BeFalse())
457+
Expect(snap.Timestamp).To(Equal(NewRBDTimeStamp(time.Date(2024, 10, 1, 10, 11, 31, 0, time.UTC))))
458+
})
459+
460+
It("should return an error, if the command failed", func() {
461+
ctrl := gomock.NewController(t)
462+
defer ctrl.Finish()
463+
464+
m := NewMockcommand(ctrl)
465+
m.EXPECT().execute(gomock.Any()).Return([]byte{}, []byte("error!"), errors.New("error"))
466+
467+
cmd := mockedCephCmd(m)
468+
_, err := cmd.RBDSnapLsByID("pool", "image-id")
469+
Expect(err).To(HaveOccurred())
470+
})
471+
})
472+
381473
var _ = Describe("CephCmd.RBDSnapRm", func() {
382474
var t reporter
383475

@@ -387,11 +479,11 @@ var _ = Describe("CephCmd.RBDSnapRm", func() {
387479

388480
m := NewMockcommand(ctrl)
389481
m.EXPECT().
390-
execute("rbd", "snap", "rm", "pool/image@snap").
482+
execute("rbd", "snap", "rm", "-p", "pool", "--image-id", "image-id", "--snap", "snap").
391483
Return([]byte{}, []byte{}, nil)
392484

393485
cmd := mockedCephCmd(m)
394-
err := cmd.RBDSnapRm("pool", "image", "snap")
486+
err := cmd.RBDSnapRm("pool", "image-id", "snap")
395487
Expect(err).ToNot(HaveOccurred())
396488
})
397489

@@ -403,7 +495,7 @@ var _ = Describe("CephCmd.RBDSnapRm", func() {
403495
m.EXPECT().execute(gomock.Any()).Return([]byte{}, []byte("error!"), errors.New("error"))
404496

405497
cmd := mockedCephCmd(m)
406-
err := cmd.RBDSnapRm("pool", "image", "snap")
498+
err := cmd.RBDSnapRm("pool", "image-id", "snap")
407499
Expect(err).To(HaveOccurred())
408500
})
409501
})

0 commit comments

Comments
 (0)