diff --git a/addons/agent_mirrorpeer_controller.go b/addons/agent_mirrorpeer_controller.go index 8aa3e15a..ad574123 100644 --- a/addons/agent_mirrorpeer_controller.go +++ b/addons/agent_mirrorpeer_controller.go @@ -24,6 +24,7 @@ import ( "strconv" "time" + snapshotv1 "github.com/kubernetes-csi/external-snapshotter/client/v8/apis/volumesnapshot/v1" ocsv1 "github.com/red-hat-storage/ocs-operator/api/v4/v1" multiclusterv1alpha1 "github.com/red-hat-storage/odf-multicluster-orchestrator/api/v1alpha1" "github.com/red-hat-storage/odf-multicluster-orchestrator/controllers/utils" @@ -147,17 +148,29 @@ func (r *MirrorPeerReconciler) Reconcile(ctx context.Context, req ctrl.Request) return ctrl.Result{}, err } - if mirrorPeer.Spec.Type == multiclusterv1alpha1.Async && !hasStorageClientRef { - clusterFSIDs := make(map[string]string) - logger.Info("Fetching clusterFSIDs") - err = r.fetchClusterFSIDs(ctx, &mirrorPeer, clusterFSIDs) - if err != nil { - if errors.IsNotFound(err) { - return ctrl.Result{RequeueAfter: 60 * time.Second}, nil - } - return ctrl.Result{}, fmt.Errorf("an unknown error occurred while fetching the cluster fsids, retrying again: %v", err) + clusterFSIDs := make(map[string]string) + logger.Info("Fetching clusterFSIDs") + err = r.fetchClusterFSIDs(ctx, &mirrorPeer, clusterFSIDs) + if err != nil { + if errors.IsNotFound(err) { + return ctrl.Result{RequeueAfter: 60 * time.Second}, nil + } + return ctrl.Result{}, fmt.Errorf("an unknown error occurred while fetching the cluster fsids, retrying again: %v", err) + } + + if !hasStorageClientRef { + logger.Info("Labeling RBD storageclasses") + errs := r.labelStorageClasses(ctx, scr.Namespace, clusterFSIDs) + if len(errs) > 0 { + return ctrl.Result{}, fmt.Errorf("few failures occurred while labeling StorageClasses: %v", errs) } + errs = labelVolumeSnapshotClasses(ctx, logger, r.SpokeClient, r.SpokeClusterName, scr.Namespace, clusterFSIDs) + if len(errs) > 0 { + return ctrl.Result{}, fmt.Errorf("few failures occurred while labeling VolumeSnapshotClasses: %v", errs) + } + } + if mirrorPeer.Spec.Type == multiclusterv1alpha1.Async && !hasStorageClientRef { logger.Info("Enabling async mode dependencies") err = r.labelCephClusters(ctx, scr, clusterFSIDs) if err != nil { @@ -174,11 +187,6 @@ func (r *MirrorPeerReconciler) Reconcile(ctx context.Context, req ctrl.Request) return ctrl.Result{}, fmt.Errorf("failed to enable mirroring the storagecluster %q in namespace %q in managed cluster: %v", scr.Name, scr.Namespace, err) } - logger.Info("Labeling RBD storageclasses") - errs := r.labelRBDStorageClasses(ctx, scr.Namespace, clusterFSIDs) - if len(errs) > 0 { - return ctrl.Result{}, fmt.Errorf("few failures occurred while labeling RBD StorageClasses: %v", errs) - } } if mirrorPeer.Spec.Type == multiclusterv1alpha1.Async && hasStorageClientRef { @@ -290,8 +298,7 @@ func (r *MirrorPeerReconciler) getSecretNameByType(clusterType utils.ClusterType return secretName } -func (r *MirrorPeerReconciler) labelRBDStorageClasses(ctx context.Context, storageClusterNamespace string, clusterFSIDs map[string]string) []error { - r.Logger.Info("Fetching cluster FSIDs", "clusterFSIDs", clusterFSIDs) +func (r *MirrorPeerReconciler) labelStorageClasses(ctx context.Context, storageClusterNamespace string, clusterFSIDs map[string]string) []error { // Get all StorageClasses in storageClusterNamespace scs := &storagev1.StorageClassList{} err := r.SpokeClient.List(ctx, scs) @@ -328,6 +335,44 @@ func (r *MirrorPeerReconciler) labelRBDStorageClasses(ctx context.Context, stora return errs } +func labelVolumeSnapshotClasses(ctx context.Context, logger *slog.Logger, spokeClient client.Client, spokeClusterName, storageClusterNamespace string, clusterFSIDs map[string]string) []error { + vscList := &snapshotv1.VolumeSnapshotClassList{} + err := spokeClient.List(ctx, vscList) + var errs []error + if err != nil { + errs = append(errs, err) + logger.Error("Failed to list VolumeSnapshotClasses", "error", err) + return errs + } + logger.Info("Found VolumeSnapshotClasses", "count", len(vscList.Items)) + + key := spokeClusterName + fsid, ok := clusterFSIDs[key] + if !ok { + errMsg := fmt.Errorf("no FSID found for key: %s, unable to update VolumeSnapshotClasses", key) + errs = append(errs, errMsg) + logger.Error("Missing FSID for VolumeSnapshotClass update", "key", key) + return errs + } + + for _, vsc := range vscList.Items { + if vsc.Driver == fmt.Sprintf(RBDProvisionerTemplate, storageClusterNamespace) || + vsc.Driver == fmt.Sprintf(CephFSProvisionerTemplate, storageClusterNamespace) { + logger.Info("Updating VolumeSnapshotClass with FSID", "VolumeSnapshotClass", vsc.Name, "FSID", fsid) + if vsc.Labels == nil { + vsc.Labels = make(map[string]string) + } + vsc.Labels[fmt.Sprintf(RamenLabelTemplate, StorageIDKey)] = fsid + if err = spokeClient.Update(ctx, &vsc); err != nil { + errs = append(errs, err) + logger.Error("Failed to update VolumeSnapshotClass with FSID", "VolumeSnapshotClass", vsc.Name, "FSID", fsid, "error", err) + } + } + } + + return errs +} + func (r *MirrorPeerReconciler) createS3(ctx context.Context, mirrorPeer multiclusterv1alpha1.MirrorPeer, scNamespace string, hasStorageClientRef bool) error { bucketNamespace := utils.GetEnv("ODR_NAMESPACE", scNamespace) bucketName := utils.GenerateBucketName(mirrorPeer, hasStorageClientRef) diff --git a/addons/manager.go b/addons/manager.go index d17c8390..79de99d4 100644 --- a/addons/manager.go +++ b/addons/manager.go @@ -10,6 +10,7 @@ import ( replicationv1alpha1 "github.com/csi-addons/kubernetes-csi-addons/apis/replication.storage/v1alpha1" "github.com/go-logr/zapr" obv1alpha1 "github.com/kube-object-storage/lib-bucket-provisioner/pkg/apis/objectbucket.io/v1alpha1" + snapshotv1 "github.com/kubernetes-csi/external-snapshotter/client/v8/apis/volumesnapshot/v1" routev1 "github.com/openshift/api/route/v1" ramenv1alpha1 "github.com/ramendr/ramen/api/v1alpha1" ocsv1 "github.com/red-hat-storage/ocs-operator/api/v4/v1" @@ -61,6 +62,7 @@ func init() { utilruntime.Must(routev1.AddToScheme(mgrScheme)) utilruntime.Must(rookv1.AddToScheme(mgrScheme)) utilruntime.Must(extv1.AddToScheme(mgrScheme)) + utilruntime.Must(snapshotv1.AddToScheme(mgrScheme)) //+kubebuilder:scaffold:scheme } diff --git a/addons/setup/tokenexchange-manifests/spoke_clusterrole.yaml b/addons/setup/tokenexchange-manifests/spoke_clusterrole.yaml index f33e6aff..5c7eb657 100644 --- a/addons/setup/tokenexchange-manifests/spoke_clusterrole.yaml +++ b/addons/setup/tokenexchange-manifests/spoke_clusterrole.yaml @@ -39,3 +39,12 @@ rules: - apiGroups: ["apiextensions.k8s.io"] resources: ["customresourcedefinitions"] verbs: ["get","list","watch"] +- apiGroups: + - snapshot.storage.k8s.io + resources: + - volumesnapshotclasses + verbs: + - get + - list + - watch + - update \ No newline at end of file diff --git a/controllers/drpolicy_controller.go b/controllers/drpolicy_controller.go index ffaca719..2fb0c0ed 100644 --- a/controllers/drpolicy_controller.go +++ b/controllers/drpolicy_controller.go @@ -40,6 +40,7 @@ const ( RBDFlattenVolumeReplicationClassLabelKey = "replication.storage.openshift.io/flatten-mode" RBDFlattenVolumeReplicationClassLabelValue = "force" RBDVolumeReplicationClassDefaultAnnotation = "replication.storage.openshift.io/is-default-class" + StorageIDKey = "storageid" ) type DRPolicyReconciler struct { @@ -188,6 +189,7 @@ func (r *DRPolicyReconciler) createOrUpdateManifestWorkForVRC(ctx context.Contex labels := make(map[string]string) labels[fmt.Sprintf(RamenLabelTemplate, ReplicationIDKey)] = replicationId labels[fmt.Sprintf(RamenLabelTemplate, "maintenancemodes")] = "Failover" + labels[fmt.Sprintf(RamenLabelTemplate, StorageIDKey)] = clusterFSIDs[pr.ClusterName] vrc := replicationv1alpha1.VolumeReplicationClass{ TypeMeta: metav1.TypeMeta{ Kind: "VolumeReplicationClass", diff --git a/go.mod b/go.mod index 191cc3f9..a1e626f7 100644 --- a/go.mod +++ b/go.mod @@ -7,6 +7,7 @@ require ( github.com/go-logr/zapr v1.3.0 github.com/google/uuid v1.6.0 github.com/kube-object-storage/lib-bucket-provisioner v0.0.0-20221122204822-d1a8c34382f1 + github.com/kubernetes-csi/external-snapshotter/client/v8 v8.0.0 github.com/onsi/ginkgo v1.16.5 github.com/onsi/gomega v1.34.1 github.com/openshift/api v0.0.0-20240828125535-01b3675ba7b3 diff --git a/go.sum b/go.sum index df6b93c7..e9ddfddc 100644 --- a/go.sum +++ b/go.sum @@ -547,6 +547,8 @@ github.com/kr/text v0.2.0/go.mod h1:eLer722TekiGuMkidMxC/pM04lWEeraHUUmBw8l2grE= github.com/kube-object-storage/lib-bucket-provisioner v0.0.0-20221122204822-d1a8c34382f1 h1:dQEHhTfi+bSIOSViQrKY9PqJvZenD6tFz+3lPzux58o= github.com/kube-object-storage/lib-bucket-provisioner v0.0.0-20221122204822-d1a8c34382f1/go.mod h1:my+EVjOJLeQ9lUR9uVkxRvNNkhO2saSGIgzV8GZT9HY= github.com/kubernetes-csi/external-snapshotter/client/v4 v4.0.0/go.mod h1:YBCo4DoEeDndqvAn6eeu0vWM7QdXmHEeI9cFWplmBys= +github.com/kubernetes-csi/external-snapshotter/client/v8 v8.0.0 h1:mjQG0Vakr2h246kEDR85U8y8ZhPgT3bguTCajRa/jaw= +github.com/kubernetes-csi/external-snapshotter/client/v8 v8.0.0/go.mod h1:E3vdYxHj2C2q6qo8/Da4g7P+IcwqRZyy3gJBzYybV9Y= github.com/libopenstorage/autopilot-api v0.6.1-0.20210128210103-5fbb67948648/go.mod h1:6JLrPbR3ZJQFbUY/+QJMl/aF00YdIrLf8/GWAplgvJs= github.com/libopenstorage/openstorage v8.0.0+incompatible/go.mod h1:Sp1sIObHjat1BeXhfMqLZ14wnOzEhNx2YQedreMcUyc= github.com/libopenstorage/operator v0.0.0-20200725001727-48d03e197117/go.mod h1:Qh+VXOB6hj60VmlgsmY+R1w+dFuHK246UueM4SAqZG0=