Skip to content

Commit a41a19c

Browse files
committed
Sorting functions for common use (createCloneByPV)
createCloneByPV is create RBD clone volume by PV's snapshot Signed-off-by: Yuji Ito <llamerada.jp@gmail.com>
1 parent d709325 commit a41a19c

2 files changed

Lines changed: 52 additions & 43 deletions

File tree

internal/controller/mantlerestore_controller.go

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

98
mantlev1 "github.com/cybozu-go/mantle/api/v1"
109
"github.com/cybozu-go/mantle/internal/ceph"
@@ -183,54 +182,13 @@ func (r *MantleRestoreReconciler) restoringPVName(restore *mantlev1.MantleRestor
183182
}
184183

185184
func (r *MantleRestoreReconciler) cloneImageFromBackup(ctx context.Context, restore *mantlev1.MantleRestore, backup *mantlev1.MantleBackup) error {
186-
logger := log.FromContext(ctx)
187185
pv := corev1.PersistentVolume{}
188186
err := json.Unmarshal([]byte(backup.Status.PVManifest), &pv)
189187
if err != nil {
190188
return fmt.Errorf("failed to unmarshal PV manifest: %w", err)
191189
}
192190

193-
bkImage := pv.Spec.CSI.VolumeAttributes["imageName"]
194-
if bkImage == "" {
195-
return fmt.Errorf("imageName not found in PV manifest")
196-
}
197-
pool := pv.Spec.CSI.VolumeAttributes["pool"]
198-
if pool == "" {
199-
return fmt.Errorf("pool not found in PV manifest")
200-
}
201-
202-
images, err := r.ceph.RBDLs(pool)
203-
if err != nil {
204-
return fmt.Errorf("failed to list RBD images: %w", err)
205-
}
206-
207-
// check if the image already exists
208-
if slices.Contains(images, r.restoringRBDImageName(restore)) {
209-
info, err := r.ceph.RBDInfo(pool, r.restoringRBDImageName(restore))
210-
if err != nil {
211-
return fmt.Errorf("failed to get RBD info: %w", err)
212-
}
213-
if info.Parent == nil {
214-
return fmt.Errorf("failed to get RBD info: parent field is empty")
215-
}
216-
217-
if info.Parent.Pool == pool && info.Parent.Image == bkImage && info.Parent.Snapshot == backup.Name {
218-
logger.Info("image already exists", "image", r.restoringRBDImageName(restore))
219-
return nil
220-
} else {
221-
return fmt.Errorf("image already exists but not a clone of the backup: %s", r.restoringRBDImageName(restore))
222-
}
223-
}
224-
225-
features := pv.Spec.CSI.VolumeAttributes["imageFeatures"]
226-
if features == "" {
227-
features = "deep-flatten"
228-
} else {
229-
features += ",deep-flatten"
230-
}
231-
232-
// create a clone image from the backup
233-
return r.ceph.RBDClone(pool, bkImage, backup.Name, r.restoringRBDImageName(restore), features)
191+
return createCloneByPV(ctx, r.ceph, &pv, backup.Name, r.restoringRBDImageName(restore))
234192
}
235193

236194
func (r *MantleRestoreReconciler) createOrUpdateRestoringPV(ctx context.Context, restore *mantlev1.MantleRestore, backup *mantlev1.MantleBackup) error {

internal/controller/util.go

Lines changed: 51 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -5,9 +5,11 @@ import (
55
"errors"
66
"fmt"
77
"os"
8+
"slices"
89
"strings"
910
"time"
1011

12+
"github.com/cybozu-go/mantle/internal/ceph"
1113
batchv1 "k8s.io/api/batch/v1"
1214
corev1 "k8s.io/api/core/v1"
1315
storagev1 "k8s.io/api/storage/v1"
@@ -19,6 +21,55 @@ import (
1921

2022
var errEmptyClusterID error = errors.New("cluster ID is empty")
2123

24+
// createCloneByPV creates a clone RBD image from the snapshot of the volume bound to PV.
25+
// If the clone image already exists and is a clone of the snapshot, it does nothing.
26+
func createCloneByPV(ctx context.Context, cephCmd ceph.CephCmd, pv *corev1.PersistentVolume, snapshotName, cloneName string) error {
27+
logger := log.FromContext(ctx)
28+
29+
bkImage := pv.Spec.CSI.VolumeAttributes["imageName"]
30+
if bkImage == "" {
31+
return fmt.Errorf("imageName not found in PV manifest")
32+
}
33+
pool := pv.Spec.CSI.VolumeAttributes["pool"]
34+
if pool == "" {
35+
return fmt.Errorf("pool not found in PV manifest")
36+
}
37+
38+
images, err := cephCmd.RBDLs(pool)
39+
if err != nil {
40+
return fmt.Errorf("failed to list RBD images: %w", err)
41+
}
42+
43+
// check if the image already exists
44+
if slices.Contains(images, cloneName) {
45+
info, err := cephCmd.RBDInfo(pool, cloneName)
46+
if err != nil {
47+
return fmt.Errorf("failed to get RBD info: %w", err)
48+
}
49+
if info.Parent == nil {
50+
return fmt.Errorf("failed to get RBD info: parent field is empty")
51+
}
52+
53+
if info.Parent.Pool == pool && info.Parent.Image == bkImage && info.Parent.Snapshot == snapshotName {
54+
logger.Info("image already exists", "image", cloneName)
55+
return nil
56+
} else {
57+
// If the clone image already exists but is not a clone of the snapshot, it returns an error.
58+
return fmt.Errorf("image already exists but not a clone of the backup: %s", cloneName)
59+
}
60+
}
61+
62+
features := pv.Spec.CSI.VolumeAttributes["imageFeatures"]
63+
if features == "" {
64+
features = "deep-flatten"
65+
} else {
66+
features += ",deep-flatten"
67+
}
68+
69+
// create a clone image from the backup
70+
return cephCmd.RBDClone(pool, bkImage, snapshotName, cloneName, features)
71+
}
72+
2273
func getCephClusterIDFromSCName(ctx context.Context, k8sClient client.Client, storageClassName string) (string, error) {
2374
var storageClass storagev1.StorageClass
2475
err := k8sClient.Get(ctx, types.NamespacedName{Name: storageClassName}, &storageClass)

0 commit comments

Comments
 (0)