Skip to content

Commit 65f04d9

Browse files
use verify Job
1 parent 98cd287 commit 65f04d9

10 files changed

Lines changed: 223 additions & 57 deletions

api/v1/mantlebackup_types.go

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -101,6 +101,10 @@ func (m *MantleBackup) IsSynced() bool {
101101
return meta.IsStatusConditionTrue(m.Status.Conditions, BackupConditionSyncedToRemote)
102102
}
103103

104+
func (m *MantleBackup) IsVerified() bool {
105+
return meta.IsStatusConditionTrue(m.Status.Conditions, BackupConditionVerified)
106+
}
107+
104108
func init() {
105109
SchemeBuilder.Register(&MantleBackup{}, &MantleBackupList{})
106110
}

internal/controller/mantlebackup_controller.go

Lines changed: 114 additions & 20 deletions
Original file line numberDiff line numberDiff line change
@@ -410,8 +410,10 @@ func (r *MantleBackupReconciler) reconcilePre(ctx context.Context, backup *mantl
410410
return ctrl.Result{}, err
411411
}
412412

413-
if err := r.provisionRBDSnapshot(ctx, backup, target); err != nil {
414-
return ctrl.Result{}, err
413+
if !backup.IsReady() {
414+
if err := r.provisionRBDSnapshot(ctx, backup, target); err != nil {
415+
return ctrl.Result{}, err
416+
}
415417
}
416418

417419
return ctrl.Result{}, nil
@@ -423,6 +425,13 @@ func (r *MantleBackupReconciler) reconcileAsStandalone(ctx context.Context, back
423425
return result, err
424426
}
425427

428+
if !backup.IsVerified() {
429+
if err := r.verify(ctx, backup); err != nil {
430+
return ctrl.Result{}, err
431+
}
432+
return requeueReconciliation(), nil
433+
}
434+
426435
return r.primaryCleanup(ctx, backup)
427436
}
428437

@@ -432,8 +441,21 @@ func (r *MantleBackupReconciler) reconcileAsPrimary(ctx context.Context, backup
432441
return result, err
433442
}
434443

444+
if !backup.IsVerified() {
445+
if err := r.verify(ctx, backup); err != nil {
446+
return ctrl.Result{}, err
447+
}
448+
}
449+
435450
if !backup.IsSynced() {
436-
return r.replicate(ctx, backup)
451+
result, err := r.replicate(ctx, backup)
452+
if err != nil || !result.IsZero() {
453+
return result, err
454+
}
455+
}
456+
457+
if !backup.IsVerified() || !backup.IsSynced() {
458+
return requeueReconciliation(), nil
437459
}
438460

439461
return r.primaryCleanup(ctx, backup)
@@ -477,7 +499,17 @@ func (r *MantleBackupReconciler) reconcileAsSecondary(ctx context.Context, backu
477499
}
478500

479501
if !backup.IsReady() {
480-
return r.startImport(ctx, backup, target)
502+
result, err := r.startImport(ctx, backup, target)
503+
if err != nil || !result.IsZero() {
504+
return result, err
505+
}
506+
}
507+
508+
if backup.IsReady() && !backup.IsVerified() {
509+
if err := r.verify(ctx, backup); err != nil {
510+
return ctrl.Result{}, err
511+
}
512+
return requeueReconciliation(), nil
481513
}
482514

483515
return r.secondaryCleanup(ctx, backup, true)
@@ -658,7 +690,6 @@ func (r *MantleBackupReconciler) replicateManifests(
658690
return ctrl.Result{}, nil
659691
}
660692

661-
//nolint:unused // TODO: Delete this line after starting use.
662693
func (r *MantleBackupReconciler) verify(
663694
ctx context.Context,
664695
backup *mantlev1.MantleBackup,
@@ -674,15 +705,15 @@ func (r *MantleBackupReconciler) verify(
674705
}
675706

676707
// create a clone by the snapshot bound to the MB
677-
if err := createCloneByPV(ctx, r.ceph, &storedPV, backup.Name, makeVerifyImageName(backup)); err != nil {
708+
if err := createCloneByPV(ctx, r.ceph, &storedPV, backup.Name, MakeVerifyImageName(backup)); err != nil {
678709
return fmt.Errorf("failed to create a clone by the snapshot: %w", err)
679710
}
680711

681712
// create a static PV with the clone
682713
if err := r.createOrUpdateStaticPV(
683714
ctx,
684715
&storedPV,
685-
makeVerifyImageName(backup),
716+
MakeVerifyImageName(backup),
686717
corev1.ResourceList{
687718
corev1.ResourceStorage: *resource.NewQuantity(*backup.Status.SnapSize, resource.BinarySI),
688719
},
@@ -744,8 +775,6 @@ func (r *MantleBackupReconciler) verify(
744775

745776
// checkJobStatus checks the status of the Job with the given name.
746777
// It returns (is job finished, is job succeeded, error).
747-
//
748-
//nolint:unused // TODO: Delete this line after starting use `verify`.
749778
func (r *MantleBackupReconciler) checkJobStatus(ctx context.Context, jobName string) (bool, bool, error) {
750779
var job batchv1.Job
751780
if err := r.Get(
@@ -799,11 +828,6 @@ func (r *MantleBackupReconciler) provisionRBDSnapshot(
799828
return err
800829
}
801830

802-
// If the given MantleBackup is not ready to use, create a new RBD snapshot and update its status.
803-
if backup.IsReady() {
804-
return nil
805-
}
806-
807831
snapshot, err := r.createRBDSnapshot(ctx, target.poolName, target.imageName, backup)
808832
if err != nil {
809833
return err
@@ -1513,22 +1537,18 @@ func MakeMiddleSnapshotName(backup *mantlev1.MantleBackup, offset int) string {
15131537
return fmt.Sprintf("%s-offset-%d", backup.GetAnnotations()[annotRemoteUID], offset)
15141538
}
15151539

1516-
//nolint:unused // TODO: Delete this line after starting use.
1517-
func makeVerifyImageName(target *mantlev1.MantleBackup) string {
1540+
func MakeVerifyImageName(target *mantlev1.MantleBackup) string {
15181541
return mantleVerifyImagePrefix + string(target.GetUID())
15191542
}
15201543

1521-
//nolint:unused // TODO: Delete this line after starting use.
15221544
func makeVerifyJobName(target *mantlev1.MantleBackup) string {
15231545
return mantleVerifyJobPrefix + string(target.GetUID())
15241546
}
15251547

1526-
//nolint:unused // TODO: Delete this line after starting use.
15271548
func makeVerifyPVCName(target *mantlev1.MantleBackup) string {
15281549
return mantleVerifyPVCPrefix + string(target.GetUID())
15291550
}
15301551

1531-
//nolint:unused // TODO: Delete this line after starting use.
15321552
func makeVerifyPVName(target *mantlev1.MantleBackup) string {
15331553
return mantleVerifyPVPrefix + string(target.GetUID())
15341554
}
@@ -2363,7 +2383,6 @@ blkdiscard -z /dev/zeroout-rbd
23632383
return err
23642384
}
23652385

2366-
//nolint:unused // TODO: Delete this line after starting use `verify`.
23672386
func (r *MantleBackupReconciler) createOrUpdateVerifyJob(ctx context.Context, jobName, pvcName string) error {
23682387
var job batchv1.Job
23692388
job.SetName(jobName)
@@ -2751,6 +2770,19 @@ func (r *MantleBackupReconciler) primaryCleanup(
27512770
return ctrl.Result{}, fmt.Errorf("failed to delete export data PVCs: %w", err)
27522771
}
27532772

2773+
if err := r.deleteVerifyJob(ctx, target); err != nil {
2774+
return ctrl.Result{}, fmt.Errorf("failed to delete verify Job: %w", err)
2775+
}
2776+
if err := r.deleteVerifyPVC(ctx, target); err != nil {
2777+
return ctrl.Result{}, fmt.Errorf("failed to delete verify PVC: %w", err)
2778+
}
2779+
if err := r.deleteVerifyPV(ctx, target); err != nil {
2780+
return ctrl.Result{}, fmt.Errorf("failed to delete verify PV: %w", err)
2781+
}
2782+
if err := r.deleteVerifyRBDImage(target); err != nil {
2783+
return ctrl.Result{}, fmt.Errorf("failed to delete verify RBD image: %w", err)
2784+
}
2785+
27542786
delete(target.GetAnnotations(), annotDiffFrom)
27552787
delete(target.GetAnnotations(), annotSyncMode)
27562788
if err := r.Update(ctx, target); err != nil {
@@ -2819,6 +2851,55 @@ func (r *MantleBackupReconciler) deleteAllExportDataPVCs(ctx context.Context, ba
28192851
return nil
28202852
}
28212853

2854+
func (r *MantleBackupReconciler) deleteVerifyJob(ctx context.Context, backup *mantlev1.MantleBackup) error {
2855+
var job batchv1.Job
2856+
job.SetName(makeVerifyJobName(backup))
2857+
job.SetNamespace(r.managedCephClusterID)
2858+
if err := r.Delete(ctx, &job, &client.DeleteOptions{
2859+
PropagationPolicy: ptr.To(metav1.DeletePropagationBackground),
2860+
}); err != nil && !aerrors.IsNotFound(err) {
2861+
return fmt.Errorf("failed to delete verify Job: %s/%s: %w", job.GetNamespace(), job.GetName(), err)
2862+
}
2863+
return nil
2864+
}
2865+
2866+
func (r *MantleBackupReconciler) deleteVerifyPV(ctx context.Context, backup *mantlev1.MantleBackup) error {
2867+
var pv corev1.PersistentVolume
2868+
pv.SetName(makeVerifyPVName(backup))
2869+
if err := r.Delete(ctx, &pv); err != nil && !aerrors.IsNotFound(err) {
2870+
return fmt.Errorf("failed to delete verify PV: %w", err)
2871+
}
2872+
return nil
2873+
}
2874+
2875+
func (r *MantleBackupReconciler) deleteVerifyPVC(ctx context.Context, backup *mantlev1.MantleBackup) error {
2876+
var pvc corev1.PersistentVolumeClaim
2877+
pvc.SetName(makeVerifyPVCName(backup))
2878+
pvc.SetNamespace(r.managedCephClusterID)
2879+
if err := r.Delete(ctx, &pvc); err != nil && !aerrors.IsNotFound(err) {
2880+
return fmt.Errorf("failed to delete verify PVC: %w", err)
2881+
}
2882+
return nil
2883+
}
2884+
2885+
func (r *MantleBackupReconciler) deleteVerifyRBDImage(backup *mantlev1.MantleBackup) error {
2886+
if backup.Status.PVManifest == "" {
2887+
// The RBD image for verification is created after the PV manifest is stored in the status.
2888+
// Thus, when the PV manifest is missing, the RBD image hasn't been created, so we can safely return nil.
2889+
return nil
2890+
}
2891+
var pv corev1.PersistentVolume
2892+
if err := json.Unmarshal([]byte(backup.Status.PVManifest), &pv); err != nil {
2893+
return fmt.Errorf("failed to unmarshal PV manifest: %w", err)
2894+
}
2895+
pool := pv.Spec.CSI.VolumeAttributes["pool"]
2896+
if pool == "" {
2897+
return errors.New("pool name is missing in the PV manifest")
2898+
}
2899+
image := MakeVerifyImageName(backup)
2900+
return deleteRBDImageAsynchronously(r.ceph, pool, image)
2901+
}
2902+
28222903
func (r *MantleBackupReconciler) secondaryCleanup(
28232904
ctx context.Context,
28242905
target *mantlev1.MantleBackup,
@@ -2866,6 +2947,19 @@ func (r *MantleBackupReconciler) secondaryCleanup(
28662947
return ctrl.Result{}, fmt.Errorf("failed to delete zeroout PV: %w", err)
28672948
}
28682949

2950+
if err := r.deleteVerifyJob(ctx, target); err != nil {
2951+
return ctrl.Result{}, fmt.Errorf("failed to delete verify Job: %w", err)
2952+
}
2953+
if err := r.deleteVerifyPVC(ctx, target); err != nil {
2954+
return ctrl.Result{}, fmt.Errorf("failed to delete verify PVC: %w", err)
2955+
}
2956+
if err := r.deleteVerifyPV(ctx, target); err != nil {
2957+
return ctrl.Result{}, fmt.Errorf("failed to delete verify PV: %w", err)
2958+
}
2959+
if err := r.deleteVerifyRBDImage(target); err != nil {
2960+
return ctrl.Result{}, fmt.Errorf("failed to delete verify RBD image: %w", err)
2961+
}
2962+
28692963
if deleteExportData {
28702964
if err := r.deleteAllExportedData(ctx, target); err != nil {
28712965
return ctrl.Result{}, fmt.Errorf("failed to delete exported data in the object storage: %w", err)

internal/controller/mantlebackup_controller_test.go

Lines changed: 5 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -1591,9 +1591,9 @@ var _ = Describe("export and upload", func() {
15911591
origSize := *resource.NewQuantity(testutil.FakeRBDSnapshotSize-1, resource.BinarySI)
15921592
mbr.backupTransferPartSize = origSize
15931593

1594-
// We use reconcileAsStandalone to focus on the part size update logic.
1594+
// We use reconcilePre to focus on the part size update logic.
15951595
Eventually(func(g Gomega) {
1596-
result, err := mbr.reconcileAsStandalone(ctx, backup)
1596+
result, err := mbr.reconcilePre(ctx, backup)
15971597
g.Expect(result.IsZero()).To(BeTrue())
15981598
g.Expect(err).NotTo(HaveOccurred())
15991599

@@ -1607,7 +1607,7 @@ var _ = Describe("export and upload", func() {
16071607
mbr.backupTransferPartSize = newSize
16081608

16091609
Eventually(func(g Gomega) {
1610-
result, err := mbr.reconcileAsStandalone(ctx, backup)
1610+
result, err := mbr.reconcilePre(ctx, backup)
16111611
g.Expect(result.IsZero()).To(BeTrue())
16121612
g.Expect(err).NotTo(HaveOccurred())
16131613
}, "10s").Should(Succeed())
@@ -2583,7 +2583,7 @@ var _ = Describe("MantleBackupReconciler", func() {
25832583
"pool": pvSrc.Spec.CSI.VolumeAttributes["pool"],
25842584
"staticVolume": "true",
25852585
},
2586-
VolumeHandle: makeVerifyImageName(backup),
2586+
VolumeHandle: MakeVerifyImageName(backup),
25872587
},
25882588
},
25892589
PersistentVolumeReclaimPolicy: corev1.PersistentVolumeReclaimRetain,
@@ -2739,7 +2739,7 @@ var _ = Describe("MantleBackupReconciler", func() {
27392739

27402740
It("generates correct names", func(ctx SpecContext) {
27412741
for _, backup := range []*mantlev1.MantleBackup{backupSuccess, backupFail} {
2742-
Expect(makeVerifyImageName(backup)).To(Equal(mantleVerifyImagePrefix + string(backup.GetUID())))
2742+
Expect(MakeVerifyImageName(backup)).To(Equal(mantleVerifyImagePrefix + string(backup.GetUID())))
27432743
Expect(makeVerifyJobName(backup)).To(Equal(mantleVerifyJobPrefix + string(backup.GetUID())))
27442744
Expect(makeVerifyPVName(backup)).To(Equal(mantleVerifyPVPrefix + string(backup.GetUID())))
27452745
Expect(makeVerifyPVCName(backup)).To(Equal(mantleVerifyPVCPrefix + string(backup.GetUID())))

internal/controller/mantlerestore_controller.go

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -29,6 +29,8 @@ type MantleRestoreReconciler struct {
2929
}
3030

3131
const (
32+
mbAnnotationSkipVerifyKey = "mantle.cybozu.io/skip-verify"
33+
mbAnnotationSkipVerifyValue = "true"
3234
MantleRestoreFinalizerName = "mantlerestore.mantle.cybozu.io/finalizer"
3335
RestoringPVFinalizerName = "mantle.cybozu.io/restoring-pv-finalizer"
3436
PVAnnotationRestoredBy = "mantle.cybozu.io/restored-by"
@@ -140,6 +142,12 @@ func (r *MantleRestoreReconciler) restore(ctx context.Context, restore *mantlev1
140142
return requeueReconciliation(), nil
141143
}
142144

145+
// check if the backup is verified or verification is skipped
146+
if skip, ok := backup.GetAnnotations()[mbAnnotationSkipVerifyKey]; !backup.IsVerified() && (!ok || skip != mbAnnotationSkipVerifyValue) {
147+
logger.Info("verification is not completed", "backup", backup.Name, "namespace", backup.Namespace)
148+
return requeueReconciliation(), nil
149+
}
150+
143151
// create a clone image from the backup
144152
if err := r.cloneImageFromBackup(ctx, restore, &backup); err != nil {
145153
logger.Error(err, "failed to clone image from backup", "backup", backup.Name, "namespace", backup.Namespace)

internal/controller/persistentvolume_controller.go

Lines changed: 1 addition & 24 deletions
Original file line numberDiff line numberDiff line change
@@ -4,7 +4,6 @@ import (
44
"context"
55
"errors"
66
"fmt"
7-
"slices"
87

98
"github.com/cybozu-go/mantle/internal/ceph"
109
corev1 "k8s.io/api/core/v1"
@@ -130,27 +129,5 @@ func (r *PersistentVolumeReconciler) removeRBDImage(ctx context.Context, pv *cor
130129
pool := pv.Spec.CSI.VolumeAttributes["pool"]
131130
logger.Info("removing image", "pool", pool, "image", image)
132131

133-
images, err := r.ceph.RBDLs(pool)
134-
if err != nil {
135-
return fmt.Errorf("failed to list RBD images: %w", err)
136-
}
137-
138-
if !slices.Contains(images, image) {
139-
return nil
140-
}
141-
142-
imageInfo, err := r.ceph.RBDInfo(pool, image)
143-
if err != nil {
144-
return fmt.Errorf("failed to get info about the RBD image: %s/%s: %w", pool, image, err)
145-
}
146-
147-
if err := r.ceph.RBDTrashMv(pool, image); err != nil {
148-
return fmt.Errorf("failed to move the RBD image to trash: %s/%s: %w", pool, image, err)
149-
}
150-
151-
if err := r.ceph.CephRBDTaskAddTrashRemove(pool, imageInfo.ID); err != nil {
152-
return fmt.Errorf("failed to add task to remove the RBD image from trash: %s/%s: %w", pool, image, err)
153-
}
154-
155-
return nil
132+
return deleteRBDImageAsynchronously(r.ceph, pool, image)
156133
}

internal/controller/util.go

Lines changed: 26 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -160,3 +160,29 @@ func requeueReconciliation() ctrl.Result {
160160
}
161161
return ctrl.Result{RequeueAfter: duration}
162162
}
163+
164+
func deleteRBDImageAsynchronously(ceph ceph.CephCmd, pool, image string) error {
165+
images, err := ceph.RBDLs(pool)
166+
if err != nil {
167+
return fmt.Errorf("failed to list RBD images: %w", err)
168+
}
169+
170+
if !slices.Contains(images, image) {
171+
return nil
172+
}
173+
174+
imageInfo, err := ceph.RBDInfo(pool, image)
175+
if err != nil {
176+
return fmt.Errorf("failed to get info about the RBD image: %s/%s: %w", pool, image, err)
177+
}
178+
179+
if err := ceph.RBDTrashMv(pool, image); err != nil {
180+
return fmt.Errorf("failed to move the RBD image to trash: %s/%s: %w", pool, image, err)
181+
}
182+
183+
if err := ceph.CephRBDTaskAddTrashRemove(pool, imageInfo.ID); err != nil {
184+
return fmt.Errorf("failed to add task to remove the RBD image from trash: %s/%s: %w", pool, image, err)
185+
}
186+
187+
return nil
188+
}

0 commit comments

Comments
 (0)