diff --git a/.github/workflows/codegen.yml b/.github/workflows/codegen.yml index 688f955665c1..74fb05769987 100644 --- a/.github/workflows/codegen.yml +++ b/.github/workflows/codegen.yml @@ -38,8 +38,18 @@ jobs: with: go-version: "1.22" + - name: post-process checkout - copy to github.com + run: | + # copy to the github.com path so codegen will work as expected + mkdir -p $(go env GOPATH)/src/github.com/rook/rook/ + cp -R . $(go env GOPATH)/src/github.com/rook/rook/ + - name: run codegen - run: GOPATH=$(go env GOPATH) make codegen + run: | + cd $(go env GOPATH)/src/github.com/rook/rook + GOPATH=$(go env GOPATH) make codegen - name: validate codegen - run: tests/scripts/validate_modified_files.sh codegen + run: | + cd $(go env GOPATH)/src/github.com/rook/rook + tests/scripts/validate_modified_files.sh codegen diff --git a/Documentation/Storage-Configuration/Ceph-CSI/ceph-csi-volume-group-snapshot.md b/Documentation/Storage-Configuration/Ceph-CSI/ceph-csi-volume-group-snapshot.md index f569ac15186d..33d58b807fa2 100644 --- a/Documentation/Storage-Configuration/Ceph-CSI/ceph-csi-volume-group-snapshot.md +++ b/Documentation/Storage-Configuration/Ceph-CSI/ceph-csi-volume-group-snapshot.md @@ -23,97 +23,12 @@ In short, as the documentation describes it: Created by cluster administrators to describe how volume group snapshots should be created. including the driver information, the deletion policy, etc. -## RBD Volume Group Snapshots - -### RBD VolumeGroupSnapshotClass - -In [VolumeGroupSnapshotClass](https://github.com/rook/rook/tree/master/deploy/examples/csi/rbd/groupsnapshotclass.yaml), -the `csi.storage.k8s.io/group-snapshotter-secret-name` parameter references the -name of the secret created for the rbd-plugin and `pool` to reflect the Ceph pool name. - -In the `VolumeGroupSnapshotClass`, update the value of the `clusterID` field to match the namespace -that Rook is running in. When Ceph CSI is deployed by Rook, the operator will automatically -maintain a configmap whose contents will match this key. By default this is -"rook-ceph". - -```console -kubectl create -f deploy/examples/csi/rbd/groupsnapshotclass.yaml -``` - -### RBD VolumeGroupSnapshot - -In [VolumeGroupSnapshot](https://github.com/rook/rook/tree/master/deploy/examples/csi/rbd/groupsnapshot.yaml), -`volumeGroupSnapshotClassName` is the name of the `VolumeGroupSnapshotClass` -previously created. The labels inside `matchLabels` must be present on the -PVCs that are already created by the RBD CSI driver. - -```console -kubectl create -f deploy/examples/csi/rbd/groupsnapshot.yaml -``` - -### Verify RBD GroupSnapshot Creation - -```console -$ kubectl get volumegroupsnapshotclass -NAME DRIVER DELETIONPOLICY AGE -csi-rbdplugin-groupsnapclass rook-ceph.rbd.csi.ceph.com Delete 21m -``` - -```console -$ kubectl get volumegroupsnapshot -NAME READYTOUSE VOLUMEGROUPSNAPSHOTCLASS VOLUMEGROUPSNAPSHOTCONTENT CREATIONTIME AGE -rbd-groupsnapshot true csi-rbdplugin-groupsnapclass groupsnapcontent-d13f4d95-8822-4729-9586-4f222a3f788e 5m37s 5m39s -``` - -The snapshot will be ready to restore to a new PVC when `READYTOUSE` field of the -`volumegroupsnapshot` is set to true. - -### Restore the RBD volume group snapshot to a new PVC - -Find the name of the snapshots created by the `VolumeGroupSnapshot` first by running: - -```console -$ kubectl get volumegroupsnapshot/rbd-groupsnapshot -o=jsonpath='{range .status.pvcVolumeSnapshotRefList[*]}PVC: {.persistentVolumeClaimRef.name}, Snapshot: {.volumeSnapshotRef.name}{"\n"}{end}' -PVC: rbd-pvc, Snapshot: snapshot-9d21b143904c10f49ddc92664a7e8fe93c23387d0a88549c14337484ebaf1011-2024-09-12-3.49.13 -``` - -It will list the PVC's name followed by its snapshot name. - -In -[pvc-restore](https://github.com/rook/rook/tree/master/deploy/examples/csi/rbd/pvc-restore.yaml), -`dataSource` is one of the `Snapshot` that we just -found. The `dataSource` kind must be the `VolumeSnapshot`. - -Create a new PVC from the snapshot - -```console -kubectl create -f deploy/examples/csi/rbd/pvc-restore.yaml -``` - -### Verify RBD Restore PVC Creation - -```console -$ kubectl get pvc -rbd-pvc Bound pvc-9ae60bf9-4931-4f9a-9de1-7f45f31fe4da 1Gi RWO rook-cephfs 171m -rbd-pvc-restore Bound pvc-b4b73cbb-5061-48c7-9ac8-e1202508cf97 1Gi RWO rook-cephfs 46s -``` - -### RBD volume group snapshot resource Cleanup - -To clean the resources created by this example, run the following: - -```console -kubectl delete -f deploy/examples/csi/rbd/pvc-restore.yaml -kubectl delete -f deploy/examples/csi/rbd/groupsnapshot.yaml -kubectl delete -f deploy/examples/csi/rbd/groupsnapshotclass.yaml -``` - -## CephFS Volume Group Snapshots +## Volume Group Snapshots ### CephFS VolumeGroupSnapshotClass In [VolumeGroupSnapshotClass](https://github.com/rook/rook/tree/master/deploy/examples/csi/cephfs/groupsnapshotclass.yaml), -the `csi.storage.k8s.io/group-snapshotter-secret-name` parameter references the +the `csi.storage.k8s.io/group-snapshotter-secret-name` parameter should reference the name of the secret created for the cephfs-plugin. In the `VolumeGroupSnapshotClass`, update the value of the `clusterID` field to match the namespace @@ -128,8 +43,8 @@ kubectl create -f deploy/examples/csi/cephfs/groupsnapshotclass.yaml ### CephFS VolumeGroupSnapshot In [VolumeGroupSnapshot](https://github.com/rook/rook/tree/master/deploy/examples/csi/cephfs/groupsnapshot.yaml), -`volumeGroupSnapshotClassName` is the name of the `VolumeGroupSnapshotClass` -previously created. The labels inside `matchLabels` must be present on the +`volumeGroupSnapshotClassName` should be the name of the `VolumeGroupSnapshotClass` +previously created. The labels inside `matchLabels` should be present on the PVCs that are already created by the CephFS CSI driver. ```console @@ -166,8 +81,8 @@ It will list the PVC's name followed by its snapshot name. In [pvc-restore](https://github.com/rook/rook/tree/master/deploy/examples/csi/cephfs/pvc-restore.yaml), -`dataSource` is one of the `Snapshot` that we just -found. The `dataSource` kind must be the `VolumeSnapshot`. +`dataSource` should be one of the `Snapshot` that we just +found. The `dataSource` kind should be the `VolumeSnapshot`. Create a new PVC from the snapshot @@ -183,7 +98,7 @@ cephfs-pvc Bound pvc-9ae60bf9-4931-4f9a-9de1-7f45f31fe4da 1Gi cephfs-pvc-restore Bound pvc-b4b73cbb-5061-48c7-9ac8-e1202508cf97 1Gi RWO rook-cephfs 46s ``` -### CephFS volume group snapshot resource Cleanup +## CephFS volume group snapshot resource Cleanup To clean the resources created by this example, run the following: diff --git a/deploy/examples/csi/cephfs/pvc.yaml b/deploy/examples/csi/cephfs/pvc.yaml index 656d46859331..cf3057de3115 100644 --- a/deploy/examples/csi/cephfs/pvc.yaml +++ b/deploy/examples/csi/cephfs/pvc.yaml @@ -3,8 +3,6 @@ apiVersion: v1 kind: PersistentVolumeClaim metadata: name: cephfs-pvc - # Use this with the example `groupsnapshotclass.yaml`. - # Not needed if the volume group snapshots are not required. labels: group: snapshot-test spec: diff --git a/deploy/examples/csi/rbd/groupsnapshot.yaml b/deploy/examples/csi/rbd/groupsnapshot.yaml deleted file mode 100644 index b0f329125099..000000000000 --- a/deploy/examples/csi/rbd/groupsnapshot.yaml +++ /dev/null @@ -1,13 +0,0 @@ ---- -apiVersion: groupsnapshot.storage.k8s.io/v1alpha1 -kind: VolumeGroupSnapshot -metadata: - name: rbd-groupsnapshot -spec: - source: - selector: - matchLabels: - # The PVCs require this label for them to be - # included in the VolumeGroupSnapshot - group: snapshot-test - volumeGroupSnapshotClassName: csi-rbdplugin-groupsnapclass diff --git a/deploy/examples/csi/rbd/groupsnapshotclass.yaml b/deploy/examples/csi/rbd/groupsnapshotclass.yaml deleted file mode 100644 index 05a64852fe18..000000000000 --- a/deploy/examples/csi/rbd/groupsnapshotclass.yaml +++ /dev/null @@ -1,15 +0,0 @@ ---- -apiVersion: groupsnapshot.storage.k8s.io/v1alpha1 -kind: VolumeGroupSnapshotClass -metadata: - name: csi-rbdplugin-groupsnapclass -driver: rook-ceph.rbd.csi.ceph.com # csi-provisioner-name -parameters: - # Specify a string that identifies your cluster. Ceph CSI supports any - # unique string. When Ceph CSI is deployed by Rook use the Rook namespace, - # for example "rook-ceph". - clusterID: rook-ceph # namespace: cluster - pool: replicapool - csi.storage.k8s.io/group-snapshotter-secret-name: rook-csi-rbd-provisioner - csi.storage.k8s.io/group-snapshotter-secret-namespace: rook-ceph -deletionPolicy: Delete diff --git a/deploy/examples/csi/rbd/pvc.yaml b/deploy/examples/csi/rbd/pvc.yaml index edb8b1ba86ed..516a5aa87b56 100644 --- a/deploy/examples/csi/rbd/pvc.yaml +++ b/deploy/examples/csi/rbd/pvc.yaml @@ -3,10 +3,6 @@ apiVersion: v1 kind: PersistentVolumeClaim metadata: name: rbd-pvc - # Use this with the example `groupsnapshotclass.yaml`. - # Not needed if the volume group snapshots are not required. - labels: - group: snapshot-test spec: accessModes: - ReadWriteOnce diff --git a/pkg/operator/ceph/object/json_helpers.go b/pkg/operator/ceph/object/json_helpers.go index 719339e7db2a..5558272cd635 100644 --- a/pkg/operator/ceph/object/json_helpers.go +++ b/pkg/operator/ceph/object/json_helpers.go @@ -43,14 +43,9 @@ func getObjProperty[T string | map[string]interface{} | []interface{}](obj map[s return res, fmt.Errorf("json property %q not found", strings.Join(path, ".")) } -// setObjProperty - helper function to manipulate JSON Objects. -// sets value to json object nested field and returns previous value if presented. -// Example: -// -// obj = {"a":{"b":"foo"}} -// // will replace "foo" with "bar" and return "foo" -// setObjProperty(obj,"bar","a","b") -func setObjProperty[T string | []string | map[string]interface{} | []interface{}](obj map[string]interface{}, val T, path ...string) (T, error) { +// updateObjProperty - helper function to manipulate JSON Objects. +// sets new value to json object nested field only if it is already exists in json and returns previous value. +func updateObjProperty[T string | []string | map[string]interface{} | []interface{}](obj map[string]interface{}, val T, path ...string) (T, error) { var prev T if len(path) == 0 { return prev, fmt.Errorf("json property path is empty") @@ -60,6 +55,10 @@ func setObjProperty[T string | []string | map[string]interface{} | []interface{} if last { // last path segment: set result and return prev value prevVal, ok := obj[p] + if !ok { + // not exists: + return prev, fmt.Errorf("json property %q not exists", strings.Join(path, ".")) + } if ok { prevRes, ok := prevVal.(T) if ok { diff --git a/pkg/operator/ceph/object/json_helpers_test.go b/pkg/operator/ceph/object/json_helpers_test.go index 9448c107067c..6ba5dac40597 100644 --- a/pkg/operator/ceph/object/json_helpers_test.go +++ b/pkg/operator/ceph/object/json_helpers_test.go @@ -219,7 +219,24 @@ func Test_getObjPropertyObjArr(t *testing.T) { } } -func Test_setObjProperty(t *testing.T) { +func Test_deepCopyJson(t *testing.T) { + in := map[string]interface{}{ + "key": []interface{}{"1", "2", "3"}, + } + inCopy, err := deepCopyJson(in) + assert.NoError(t, err) + assert.EqualValues(t, in, inCopy) + + assert.EqualValues(t, []interface{}{"1", "2", "3"}, in["key"]) + assert.EqualValues(t, []interface{}{"1", "2", "3"}, inCopy["key"]) + + inCopy["key"].([]interface{})[1] = "7" + + assert.EqualValues(t, []interface{}{"1", "2", "3"}, in["key"]) + assert.EqualValues(t, []interface{}{"1", "7", "3"}, inCopy["key"]) +} + +func Test_updateObjProperty(t *testing.T) { type args struct { json string val string @@ -233,7 +250,7 @@ func Test_setObjProperty(t *testing.T) { wantErr bool }{ { - name: "replace val", + name: "exists", args: args{ json: `{"a":{"b":"val"}}`, val: "new val", @@ -259,7 +276,7 @@ func Test_setObjProperty(t *testing.T) { wantErr: false, }, { - name: "add val", + name: "not exists", args: args{ json: `{"a":{"b":"val"}}`, val: "val2", @@ -268,21 +285,8 @@ func Test_setObjProperty(t *testing.T) { }, }, wantPrev: "", - wantJSON: `{"a":{"b":"val","c":"val2"}}`, - wantErr: false, - }, - { - name: "add root val", - args: args{ - json: `{"a":{"b":"val"}}`, - val: "val2", - path: []string{ - "c", - }, - }, - wantPrev: "", - wantJSON: `{"a":{"b":"val"},"c":"val2"}`, - wantErr: false, + wantJSON: `{"a":{"b":"val"}}`, + wantErr: true, }, } for _, tt := range tests { @@ -290,7 +294,7 @@ func Test_setObjProperty(t *testing.T) { obj := map[string]interface{}{} err := json.Unmarshal([]byte(tt.args.json), &obj) assert.NoError(t, err) - prev, err := setObjProperty(obj, tt.args.val, tt.args.path...) + prev, err := updateObjProperty(obj, tt.args.val, tt.args.path...) if tt.wantErr { assert.Error(t, err) return @@ -304,7 +308,8 @@ func Test_setObjProperty(t *testing.T) { }) } } -func Test_setObjPropertyObj(t *testing.T) { + +func Test_updateObjPropertyObj(t *testing.T) { type args struct { json string val map[string]interface{} @@ -318,30 +323,30 @@ func Test_setObjPropertyObj(t *testing.T) { wantErr bool }{ { - name: "add obj", + name: "exists", args: args{ - json: `{"a":{"b":{}}}`, - val: map[string]interface{}{"c": "val1"}, + json: `{"a":{"b":{"c": "val1"}}}`, + val: map[string]interface{}{"d": "val2"}, path: []string{ "a", "b", }, }, - wantPrev: map[string]interface{}{}, - wantJSON: `{"a":{"b":{"c":"val1"}}}`, + wantPrev: map[string]interface{}{"c": "val1"}, + wantJSON: `{"a":{"b":{"d":"val2"}}}`, wantErr: false, }, { - name: "set obj", + name: "not exists", args: args{ - json: `{"a":{"b":{"c": "val1"}}}`, - val: map[string]interface{}{"d": "val2"}, + json: `{"a":{"b":{}}}`, + val: map[string]interface{}{"c": "val1"}, path: []string{ - "a", "b", + "a", "c", }, }, - wantPrev: map[string]interface{}{"c": "val1"}, - wantJSON: `{"a":{"b":{"d":"val2"}}}`, - wantErr: false, + wantPrev: nil, + wantJSON: `{"a":{"b":{}}}`, + wantErr: true, }, } for _, tt := range tests { @@ -349,7 +354,7 @@ func Test_setObjPropertyObj(t *testing.T) { obj := map[string]interface{}{} err := json.Unmarshal([]byte(tt.args.json), &obj) assert.NoError(t, err) - prev, err := setObjProperty(obj, tt.args.val, tt.args.path...) + prev, err := updateObjProperty(obj, tt.args.val, tt.args.path...) if tt.wantErr { assert.Error(t, err) return @@ -364,7 +369,7 @@ func Test_setObjPropertyObj(t *testing.T) { } } -func Test_setObjPropertyArr(t *testing.T) { +func Test_updateObjPropertyArr(t *testing.T) { type args struct { json string val []interface{} @@ -378,23 +383,7 @@ func Test_setObjPropertyArr(t *testing.T) { wantErr bool }{ { - name: "set obj arr", - args: args{ - json: `{"a":{"b":{}}}`, - val: []interface{}{ - map[string]interface{}{"c": "val1"}, - map[string]interface{}{"d": "val2"}, - }, - path: []string{ - "a", "b", - }, - }, - wantPrev: nil, - wantJSON: `{"a":{"b":[{"c":"val1"},{"d":"val2"}]}}`, - wantErr: false, - }, - { - name: "add obj arr", + name: "exists", args: args{ json: `{"a":{"b":[{"c": "val"}]}}`, val: []interface{}{ @@ -411,64 +400,21 @@ func Test_setObjPropertyArr(t *testing.T) { wantJSON: `{"a":{"b":[{"d":"val1"},{"e":"val2"}]}}`, wantErr: false, }, - } - for _, tt := range tests { - t.Run(tt.name, func(t *testing.T) { - obj := map[string]interface{}{} - err := json.Unmarshal([]byte(tt.args.json), &obj) - assert.NoError(t, err) - prev, err := setObjProperty(obj, tt.args.val, tt.args.path...) - if tt.wantErr { - assert.Error(t, err) - return - } else { - assert.NoError(t, err) - } - assert.EqualValues(t, tt.wantPrev, prev) - bytes, err := json.Marshal(obj) - assert.NoError(t, err) - assert.JSONEq(t, tt.wantJSON, string(bytes)) - }) - } -} -func Test_setObjPropertyStrArr(t *testing.T) { - type args struct { - json string - val []string - path []string - } - tests := []struct { - name string - args args - wantPrev []string - wantJSON string - wantErr bool - }{ { - name: "add str arr", + name: "not exists", args: args{ json: `{"a":{"b":{}}}`, - val: []string{"c", "d"}, - path: []string{ - "a", "b", + val: []interface{}{ + map[string]interface{}{"c": "val1"}, + map[string]interface{}{"d": "val2"}, }, - }, - wantPrev: nil, - wantJSON: `{"a":{"b":["c","d"]}}`, - wantErr: false, - }, - { - name: "set str arr", - args: args{ - json: `{"a":{"b":["val"]}}`, - val: []string{"c", "d"}, path: []string{ - "a", "b", + "a", "c", }, }, - wantPrev: []string{"val"}, - wantJSON: `{"a":{"b":["c","d"]}}`, - wantErr: false, + wantPrev: nil, + wantJSON: `{"a":{"b":{}}}`, + wantErr: true, }, } for _, tt := range tests { @@ -476,7 +422,7 @@ func Test_setObjPropertyStrArr(t *testing.T) { obj := map[string]interface{}{} err := json.Unmarshal([]byte(tt.args.json), &obj) assert.NoError(t, err) - prev, err := setObjProperty(obj, tt.args.val, tt.args.path...) + prev, err := updateObjProperty(obj, tt.args.val, tt.args.path...) if tt.wantErr { assert.Error(t, err) return @@ -490,20 +436,3 @@ func Test_setObjPropertyStrArr(t *testing.T) { }) } } - -func Test_deepCopyJson(t *testing.T) { - in := map[string]interface{}{ - "key": []interface{}{"1", "2", "3"}, - } - inCopy, err := deepCopyJson(in) - assert.NoError(t, err) - assert.EqualValues(t, in, inCopy) - - assert.EqualValues(t, []interface{}{"1", "2", "3"}, in["key"]) - assert.EqualValues(t, []interface{}{"1", "2", "3"}, inCopy["key"]) - - inCopy["key"].([]interface{})[1] = "7" - - assert.EqualValues(t, []interface{}{"1", "2", "3"}, in["key"]) - assert.EqualValues(t, []interface{}{"1", "7", "3"}, inCopy["key"]) -} diff --git a/pkg/operator/ceph/object/objectstore.go b/pkg/operator/ceph/object/objectstore.go index b808068456b1..63f28dbedded 100644 --- a/pkg/operator/ceph/object/objectstore.go +++ b/pkg/operator/ceph/object/objectstore.go @@ -903,18 +903,37 @@ func adjustZoneDefaultPools(zone map[string]interface{}, spec cephv1.ObjectShare "user_uid_pool": ".meta.users.uid", "otp_pool": ".otp", "notif_pool": ".log.notif", + "topics_pool": ".meta.topics", // introduced in Ceph v19 + "account_pool": ".meta.account", // introduced in Ceph v19 + "group_pool": ".meta.group", // introduced in Ceph v19 } for pool, nsSuffix := range zonePoolNSSuffix { // replace rgw internal index pools with namespaced metadata pool namespacedPool := defaultMetaPool + nsSuffix - prev, err := setObjProperty(zone, namespacedPool, pool) + prev, err := updateObjProperty(zone, namespacedPool, pool) if err != nil { - return nil, fmt.Errorf("unable to set pool %s for zone %s: %w", pool, name, err) + logger.Infof("unable to apply rados namespace to shared pool: %v", err) } if namespacedPool != prev { logger.Debugf("update shared pool %s for zone %s: %s -> %s", pool, name, prev, namespacedPool) } } + + // check for unknown pool properties in zone json + for field, val := range zone { + if _, ok := val.(string); !ok { + // not a string property + continue + } + if !strings.HasSuffix(field, "_pool") { + // not a pool property + continue + } + if _, ok := zonePoolNSSuffix[field]; !ok { + logger.Warningf("zone config %q contains unknown pool %q", name, field) + } + } + return zone, nil } diff --git a/pkg/operator/ceph/object/shared_pools.go b/pkg/operator/ceph/object/shared_pools.go index 0ab62b8d71d1..7627a08a8a38 100644 --- a/pkg/operator/ceph/object/shared_pools.go +++ b/pkg/operator/ceph/object/shared_pools.go @@ -98,11 +98,11 @@ func adjustZonePlacementPools(zone map[string]interface{}, spec cephv1.ObjectSha } // update placement with values from spec: if pSpec, inSpec := fromSpec[placementID]; inSpec { - _, err = setObjProperty(pObj, pSpec.Val.IndexPool, "val", "index_pool") + _, err = updateObjProperty(pObj, pSpec.Val.IndexPool, "val", "index_pool") if err != nil { return nil, fmt.Errorf("unable to set index pool to pool placement %q for zone %q: %w", placementID, name, err) } - _, err = setObjProperty(pObj, pSpec.Val.DataExtraPool, "val", "data_extra_pool") + _, err = updateObjProperty(pObj, pSpec.Val.DataExtraPool, "val", "data_extra_pool") if err != nil { return nil, fmt.Errorf("unable to set data extra pool to pool placement %q for zone %q: %w", placementID, name, err) } @@ -111,7 +111,7 @@ func adjustZonePlacementPools(zone map[string]interface{}, spec cephv1.ObjectSha return nil, fmt.Errorf("unable convert to pool placement %q storage class for zone %q: %w", placementID, name, err) } - _, err = setObjProperty(pObj, scObj, "val", "storage_classes") + _, err = updateObjProperty(pObj, scObj, "val", "storage_classes") if err != nil { return nil, fmt.Errorf("unable to set storage classes to pool placement %q for zone %q: %w", placementID, name, err) } @@ -144,7 +144,7 @@ func adjustZonePlacementPools(zone map[string]interface{}, spec cephv1.ObjectSha placements = append(placements, pObj) } - _, err = setObjProperty(zone, placements, "placement_pools") + _, err = updateObjProperty(zone, placements, "placement_pools") if err != nil { return nil, fmt.Errorf("unable to set pool placements for zone %q: %w", name, err) } @@ -247,7 +247,7 @@ func adjustZoneGroupPlacementTargets(group, zone map[string]interface{}) (map[st return nil, fmt.Errorf("unable to deep copy config for zonegroup %s: %w", name, err) } - _, err = setObjProperty(group, defaultPlacementCephConfigName, "default_placement") + _, err = updateObjProperty(group, defaultPlacementCephConfigName, "default_placement") if err != nil { return nil, fmt.Errorf("unable to set default_placement for zonegroup %s: %w", name, err) } @@ -277,9 +277,9 @@ func adjustZoneGroupPlacementTargets(group, zone map[string]interface{}) (map[st sc := []interface{}{} ok = castJson(desired.StorageClasses, &sc) if ok { - _, err = setObjProperty(tObj, sc, "storage_classes") + _, err = updateObjProperty(tObj, sc, "storage_classes") } else { - _, err = setObjProperty(tObj, desired.StorageClasses, "storage_classes") + _, err = updateObjProperty(tObj, desired.StorageClasses, "storage_classes") } if err != nil { return nil, fmt.Errorf("unable to set storage classes to pool placement target %q for zonegroup %q: %w", tName, name, err) @@ -317,7 +317,7 @@ func adjustZoneGroupPlacementTargets(group, zone map[string]interface{}) (map[st currentTargets = append(currentTargets, tObj) } - _, err = setObjProperty(group, currentTargets, "placement_targets") + _, err = updateObjProperty(group, currentTargets, "placement_targets") if err != nil { return nil, fmt.Errorf("unable to set placement targets for zonegroup %q: %w", name, err) } diff --git a/pkg/operator/ceph/object/shared_pools_test.go b/pkg/operator/ceph/object/shared_pools_test.go index 33f3e6ed2484..4ef29275f258 100644 --- a/pkg/operator/ceph/object/shared_pools_test.go +++ b/pkg/operator/ceph/object/shared_pools_test.go @@ -993,6 +993,74 @@ func Test_adjustZoneDefaultPools(t *testing.T) { }, "placement_pools": [], "realm_id": "29e28253-be54-4581-90dd-206020d2fcdd" +}`, + wantChanged: true, + wantErr: false, + }, + { + name: "v19 shared pool set", + args: args{ + beforeJSON: `{ + "id": "f539c2c0-e1ed-4c42-9294-41742352eeae", + "name": "test", + "topics_pool": "TopicsPool", + "account_pool": "AccountPool", + "group_pool": "GroupPool", + "domain_root": "DomainRoot", + "control_pool": "ControlPool", + "gc_pool": "GcPool", + "lc_pool": "LcPool", + "log_pool": "LogPool", + "intent_log_pool": "IntentLogPool", + "usage_log_pool": "UsageLogPool", + "roles_pool": "RolesPool", + "reshard_pool": "ReshardPool", + "user_keys_pool": "UserKeysPool", + "user_email_pool": "UserEmailPool", + "user_swift_pool": "UserSwiftPool", + "user_uid_pool": "UserUIDPool", + "otp_pool": "OtpPool", + "notif_pool": "NotifPool", + "system_key": { + "access_key": "AccessKey", + "secret_key": "SecretKey" + }, + "placement_pools": [], + "realm_id": "29e28253-be54-4581-90dd-206020d2fcdd" +}`, + spec: cephv1.ObjectSharedPoolsSpec{ + MetadataPoolName: "meta-pool", + DataPoolName: "data-pool", + PreserveRadosNamespaceDataOnDelete: false, + }, + }, + wantJSON: `{ + "id": "f539c2c0-e1ed-4c42-9294-41742352eeae", + "name": "test", + "topics_pool": "meta-pool:test.meta.topics", + "account_pool": "meta-pool:test.meta.account", + "group_pool": "meta-pool:test.meta.group", + "domain_root": "meta-pool:test.meta.root", + "control_pool": "meta-pool:test.control", + "gc_pool": "meta-pool:test.log.gc", + "lc_pool": "meta-pool:test.log.lc", + "log_pool": "meta-pool:test.log", + "intent_log_pool": "meta-pool:test.log.intent", + "usage_log_pool": "meta-pool:test.log.usage", + "roles_pool": "meta-pool:test.meta.roles", + "reshard_pool": "meta-pool:test.log.reshard", + "user_keys_pool": "meta-pool:test.meta.users.keys", + "user_email_pool": "meta-pool:test.meta.users.email", + "user_swift_pool": "meta-pool:test.meta.users.swift", + "user_uid_pool": "meta-pool:test.meta.users.uid", + "otp_pool": "meta-pool:test.otp", + "notif_pool": "meta-pool:test.log.notif", + "system_key": { + "access_key": "AccessKey", + "secret_key": "SecretKey" + }, + "placement_pools": [], + "realm_id": "29e28253-be54-4581-90dd-206020d2fcdd" }`, wantChanged: true, wantErr: false,