Skip to content

Commit

Permalink
add VolumeGroupSnapshotClass for CephFS and RBD
Browse files Browse the repository at this point in the history
CSI-drivers requires VolumeGroupSnapshotClass for VolumeGroupSnapshot.

Signed-off-by: ShravaniVangur <[email protected]>
  • Loading branch information
ShravaniVangur committed Oct 18, 2024
1 parent 38cbf3a commit de40e7b
Show file tree
Hide file tree
Showing 18 changed files with 1,212 additions and 16 deletions.
11 changes: 11 additions & 0 deletions config/rbac/role.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -128,6 +128,17 @@ rules:
- namespaces
verbs:
- get
- apiGroups:
- groupsnapshot.storage.k8s.io
resources:
- volumegroupsnapshotclasses
verbs:
- create
- delete
- get
- list
- update
- watch
- apiGroups:
- k8s.cni.cncf.io
resources:
Expand Down
11 changes: 11 additions & 0 deletions controllers/storagecluster/generate.go
Original file line number Diff line number Diff line change
Expand Up @@ -100,10 +100,21 @@ func generateNameForSnapshotClass(initData *ocsv1.StorageCluster, snapshotType S
return fmt.Sprintf("%s-%splugin-snapclass", initData.Name, snapshotType)
}

func generateNameForGroupSnapshotClass(initData *ocsv1.StorageCluster, groupSnapshotType GroupSnapshotterType) string {
return fmt.Sprintf("%s-%splugin-groupsnapclass", initData.Name, groupSnapshotType)
}

func generateNameForSnapshotClassDriver(snapshotType SnapshotterType) string {
return fmt.Sprintf("%s.%s.csi.ceph.com", storageclassDriverNamePrefix, snapshotType)
}

func setParameterBasedOnSnapshotterType(instance *ocsv1.StorageCluster, groupSnapshotterType GroupSnapshotterType) (string, string) {
if groupSnapshotterType == rbdGroupSnapshotter {
return "pool", generateNameForCephBlockPool(instance)
}
return "fsName", generateNameForCephFilesystem(instance)

}
func generateNameForSnapshotClassSecret(instance *ocsv1.StorageCluster, snapshotType SnapshotterType) string {
// nfs uses the same cephfs secrets
if snapshotType == "nfs" {
Expand Down
3 changes: 3 additions & 0 deletions controllers/storagecluster/reconcile.go
Original file line number Diff line number Diff line change
Expand Up @@ -120,6 +120,7 @@ var validTopologyLabelKeys = []string{
// +kubebuilder:rbac:groups=monitoring.coreos.com,resources=servicemonitors;prometheusrules,verbs=get;list;watch;create;update;delete
// +kubebuilder:rbac:groups=template.openshift.io,resources=templates,verbs=get;list;watch;create;update;delete
// +kubebuilder:rbac:groups=snapshot.storage.k8s.io,resources=volumesnapshotclasses,verbs=get;watch;create;update;delete
// +kubebuilder:rbac:groups=groupsnapshot.storage.k8s.io,resources=volumegroupsnapshotclasses,verbs=get;watch;create;update;delete;list
// +kubebuilder:rbac:groups=config.openshift.io,resources=infrastructures;networks,verbs=get;list;watch
// +kubebuilder:rbac:groups=config.openshift.io,resources=clusterversions;networks,verbs=get;list;watch
// +kubebuilder:rbac:groups=apiextensions.k8s.io,resources=customresourcedefinitions,verbs=get;list;watch;create;update
Expand Down Expand Up @@ -427,6 +428,7 @@ func (r *StorageClusterReconciler) reconcilePhases(
&ocsStorageClass{},
&ocsNoobaaSystem{},
&ocsSnapshotClass{},
&ocsGroupSnapshotClass{},
&ocsJobTemplates{},
&ocsCephRbdMirrors{},
&odfInfoConfig{},
Expand All @@ -446,6 +448,7 @@ func (r *StorageClusterReconciler) reconcilePhases(
&ocsStorageQuota{},
&ocsCephCluster{},
&ocsSnapshotClass{},
&ocsGroupSnapshotClass{},
&ocsNoobaaSystem{},
&odfInfoConfig{},
}
Expand Down
2 changes: 2 additions & 0 deletions controllers/storagecluster/storagecluster_controller.go
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,7 @@ import (

"github.com/go-logr/logr"
"github.com/google/go-cmp/cmp"
volumegroupsnapshotv1a1 "github.com/kubernetes-csi/external-snapshotter/client/v8/apis/volumegroupsnapshot/v1alpha1"
volumesnapshotv1 "github.com/kubernetes-csi/external-snapshotter/client/v8/apis/volumesnapshot/v1"
nbv1 "github.com/noobaa/noobaa-operator/v5/pkg/apis/noobaa/v1alpha1"
routev1 "github.com/openshift/api/route/v1"
Expand Down Expand Up @@ -240,6 +241,7 @@ func (r *StorageClusterReconciler) SetupWithManager(mgr ctrl.Manager) error {
).
Watches(&storagev1.StorageClass{}, enqueueStorageClusterRequest).
Watches(&volumesnapshotv1.VolumeSnapshotClass{}, enqueueStorageClusterRequest).
Watches(&volumegroupsnapshotv1a1.VolumeGroupSnapshotClass{}, enqueueStorageClusterRequest).
Watches(&ocsclientv1a1.StorageClient{}, enqueueStorageClusterRequest).
Watches(&ocsv1.StorageProfile{}, enqueueStorageClusterRequest).
Watches(&ocsv1alpha1.StorageConsumer{}, enqueueStorageClusterRequest, builder.WithPredicates(storageConsumerStatusPredicate))
Expand Down
5 changes: 5 additions & 0 deletions controllers/storagecluster/storagecluster_controller_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,7 @@ import (
ocsversion "github.com/red-hat-storage/ocs-operator/v4/version"

"github.com/blang/semver/v4"
groupsnapapi "github.com/kubernetes-csi/external-snapshotter/client/v8/apis/volumegroupsnapshot/v1alpha1"
snapapi "github.com/kubernetes-csi/external-snapshotter/client/v8/apis/volumesnapshot/v1"
nbv1 "github.com/noobaa/noobaa-operator/v5/pkg/apis/noobaa/v1alpha1"
configv1 "github.com/openshift/api/config/v1"
Expand Down Expand Up @@ -1253,6 +1254,10 @@ func createFakeScheme(t *testing.T) *runtime.Scheme {
if err != nil {
assert.Fail(t, "failed to add volume-snapshot scheme")
}
err = groupsnapapi.AddToScheme(scheme)
if err != nil {
assert.Fail(t, "failed to add volume-group-snapshot scheme")
}
err = monitoringv1.AddToScheme(scheme)
if err != nil {
assert.Fail(t, "failed to add monitoringv1 scheme")
Expand Down
1 change: 1 addition & 0 deletions controllers/storagecluster/uninstall_reconciler.go
Original file line number Diff line number Diff line change
Expand Up @@ -331,6 +331,7 @@ func (r *StorageClusterReconciler) deleteResources(sc *ocsv1.StorageCluster) (re
&ocsCephFilesystems{},
&ocsCephBlockPools{},
&ocsSnapshotClass{},
&ocsGroupSnapshotClass{},
&ocsStorageQuota{},
&ocsStorageClass{},
&ocsCephCluster{},
Expand Down
169 changes: 169 additions & 0 deletions controllers/storagecluster/volumegroupsnapshotterclasses.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,169 @@
package storagecluster

import (
"context"
"fmt"
"reflect"

groupsnapapi "github.com/kubernetes-csi/external-snapshotter/client/v8/apis/volumegroupsnapshot/v1alpha1"
snapapi "github.com/kubernetes-csi/external-snapshotter/client/v8/apis/volumesnapshot/v1"
ocsv1 "github.com/red-hat-storage/ocs-operator/api/v4/v1"
"k8s.io/apimachinery/pkg/api/errors"
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
"k8s.io/apimachinery/pkg/types"
"k8s.io/klog/v2"
"sigs.k8s.io/controller-runtime/pkg/reconcile"
)

type GroupSnapshotterType string

type ocsGroupSnapshotClass struct{}

const (
rbdGroupSnapshotter GroupSnapshotterType = "rbd"
cephfsGroupSnapshotter GroupSnapshotterType = "cephfs"
)

const (
groupSnapshotterSecretName = "csi.storage.k8s.io/group-snapshotter-secret-name"
groupSnapshotterSecretNamespace = "csi.storage.k8s.io/group-snapshotter-secret-namespace"
)

type GroupSnapshotClassConfiguration struct {
groupSnapshotClass *groupsnapapi.VolumeGroupSnapshotClass
reconcileStrategy ReconcileStrategy
disable bool
}

var driverName, driverValue string

func newVolumeGroupSnapshotClass(instance *ocsv1.StorageCluster, groupSnaphotterType GroupSnapshotterType) *groupsnapapi.VolumeGroupSnapshotClass {
driverName, driverValue = setParameterBasedOnSnapshotterType(instance, groupSnaphotterType)
groupSnapClass := &groupsnapapi.VolumeGroupSnapshotClass{
ObjectMeta: metav1.ObjectMeta{
Name: generateNameForGroupSnapshotClass(instance, groupSnaphotterType),
},
Driver: generateNameForSnapshotClassDriver(SnapshotterType(groupSnaphotterType)),
Parameters: map[string]string{
"clusterID": instance.Namespace,
driverName: driverValue,
groupSnapshotterSecretName: generateNameForSnapshotClassSecret(instance, SnapshotterType(groupSnaphotterType)),
groupSnapshotterSecretNamespace: instance.Namespace,
},
DeletionPolicy: snapapi.VolumeSnapshotContentDelete,
}
return groupSnapClass
}

func newCephFilesystemGroupSnapshotClassConfiguration(instance *ocsv1.StorageCluster) GroupSnapshotClassConfiguration {
return GroupSnapshotClassConfiguration{
groupSnapshotClass: newVolumeGroupSnapshotClass(instance, cephfsGroupSnapshotter),
reconcileStrategy: ReconcileStrategy(instance.Spec.ManagedResources.CephFilesystems.ReconcileStrategy),
}
}

func newCephBlockPoolGroupSnapshotClassConfiguration(instance *ocsv1.StorageCluster) GroupSnapshotClassConfiguration {
return GroupSnapshotClassConfiguration{
groupSnapshotClass: newVolumeGroupSnapshotClass(instance, rbdGroupSnapshotter),
reconcileStrategy: ReconcileStrategy(instance.Spec.ManagedResources.CephBlockPools.ReconcileStrategy),
}
}

func newGroupSnapshotClassConfigurations(instance *ocsv1.StorageCluster) []GroupSnapshotClassConfiguration {
vsccs := []GroupSnapshotClassConfiguration{
newCephFilesystemGroupSnapshotClassConfiguration(instance),
newCephBlockPoolGroupSnapshotClassConfiguration(instance),
}
return vsccs
}

func (r *StorageClusterReconciler) createGroupSnapshotClasses(vsccs []GroupSnapshotClassConfiguration) error {

for _, vscc := range vsccs {
if vscc.reconcileStrategy == ReconcileStrategyIgnore || vscc.disable {
continue
}

vsc := vscc.groupSnapshotClass
existing := &groupsnapapi.VolumeGroupSnapshotClass{}
err := r.Client.Get(context.TODO(), types.NamespacedName{Name: vsc.Name, Namespace: vsc.Namespace}, existing)
if err != nil {
if errors.IsNotFound(err) {
// Since the SnapshotClass is not found, we will create a new one
r.Log.Info("Creating GroupSnapshotClass.", "GroupSnapshotClass", klog.KRef(vsc.Namespace, vsc.Name))
err = r.Client.Create(context.TODO(), vsc)
if err != nil {
r.Log.Error(err, "Failed to create GroupSnapshotClass.", "GroupSnapshotClass", klog.KRef(vsc.Namespace, vsc.Name))
return err
}
// no error, continue with the next iteration
continue
}

r.Log.Error(err, "Failed to 'Get' GroupSnapshotClass.", "GroupSnapshotClass", klog.KRef(vsc.Namespace, vsc.Name))
return err
}
if vscc.reconcileStrategy == ReconcileStrategyInit {
return nil
}
if existing.DeletionTimestamp != nil {
return fmt.Errorf("failed to restore GroupSnapshotClass %q because it is marked for deletion", existing.Name)
}
// if there is a mismatch in the parameters of existing vs created resources,
if !reflect.DeepEqual(vsc.Parameters, existing.Parameters) {
// we have to update the existing SnapshotClass
r.Log.Info("GroupSnapshotClass needs to be updated", "GroupSnapshotClass", klog.KRef(existing.Namespace, existing.Name))
existing.ObjectMeta.OwnerReferences = vsc.ObjectMeta.OwnerReferences
vsc.ObjectMeta = existing.ObjectMeta
if err := r.Client.Update(context.TODO(), vsc); err != nil {
r.Log.Error(err, "GroupSnapshotClass updation failed.", "GroupSnapshotClass", klog.KRef(existing.Namespace, existing.Name))
return err
}
}
}
return nil
}

func (obj *ocsGroupSnapshotClass) ensureCreated(r *StorageClusterReconciler, instance *ocsv1.StorageCluster) (reconcile.Result, error) {

vgsc := newGroupSnapshotClassConfigurations(instance)

err := r.createGroupSnapshotClasses(vgsc)
if err != nil {
return reconcile.Result{}, nil
}

return reconcile.Result{}, nil
}

func (obj *ocsGroupSnapshotClass) ensureDeleted(r *StorageClusterReconciler, instance *ocsv1.StorageCluster) (reconcile.Result, error) {

vgscs := newGroupSnapshotClassConfigurations(instance)
for _, vgsc := range vgscs {
sc := vgsc.groupSnapshotClass
existing := groupsnapapi.VolumeGroupSnapshotClass{}
err := r.Client.Get(context.TODO(), types.NamespacedName{Name: sc.Name, Namespace: sc.Namespace}, &existing)

switch {
case err == nil:
if existing.DeletionTimestamp != nil {
r.Log.Info("Uninstall: GroupSnapshotClass is already marked for deletion.", "GroupSnapshotClass", klog.KRef(existing.Namespace, existing.Name))
break
}

r.Log.Info("Uninstall: Deleting GroupSnapshotClass.", "GroupSnapshotClass", klog.KRef(existing.Namespace, existing.Name))
existing.ObjectMeta.OwnerReferences = sc.ObjectMeta.OwnerReferences
sc.ObjectMeta = existing.ObjectMeta

err = r.Client.Delete(context.TODO(), sc)
if err != nil {
r.Log.Error(err, "Uninstall: Ignoring error deleting the GroupSnapshotClass.", "GroupSnapshotClass", klog.KRef(existing.Namespace, existing.Name))
}
case errors.IsNotFound(err):
r.Log.Info("Uninstall: GroupSnapshotClass not found, nothing to do.", "GroupSnapshotClass", klog.KRef(sc.Namespace, sc.Name))
default:
r.Log.Error(err, "Uninstall: Error while getting GroupSnapshotClass.", "GroupSnapshotClass", klog.KRef(sc.Namespace, sc.Name))
}
}
return reconcile.Result{}, nil
}
33 changes: 33 additions & 0 deletions controllers/storagecluster/volumegroupsnapshotterclasses_test.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,33 @@
package storagecluster

import (
"context"
"testing"

groupsnapapi "github.com/kubernetes-csi/external-snapshotter/client/v8/apis/volumegroupsnapshot/v1alpha1"
"github.com/stretchr/testify/assert"
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
"sigs.k8s.io/controller-runtime/pkg/reconcile"
)

func TestVolumeGroupSnapshotterClasses(t *testing.T) {
t, reconciler, _, request := initStorageClusterResourceCreateUpdateTest(t, nil, nil)
assertVolumeGroupSnapshotterClasses(t, reconciler, request)
}

func assertVolumeGroupSnapshotterClasses(t *testing.T, reconciler StorageClusterReconciler,
request reconcile.Request) {
rbdVSCName := "ocsinit-rbdplugin-groupsnapclass"
cephfsVSCName := "ocsinit-cephfsplugin-groupsnapclass"
vscNames := []string{cephfsVSCName, rbdVSCName}
for _, eachVSCName := range vscNames {
actualVSC := &groupsnapapi.VolumeGroupSnapshotClass{
ObjectMeta: metav1.ObjectMeta{
Name: eachVSCName,
},
}
request.Name = eachVSCName
err := reconciler.Client.Get(context.TODO(), request.NamespacedName, actualVSC)
assert.NoError(t, err)
}
}
3 changes: 3 additions & 0 deletions controllers/storagerequest/storagerequest_controller.go
Original file line number Diff line number Diff line change
Expand Up @@ -21,6 +21,7 @@ import (
"strings"

"github.com/go-logr/logr"
groupsnapapi "github.com/kubernetes-csi/external-snapshotter/client/v8/apis/volumegroupsnapshot/v1alpha1"
snapapi "github.com/kubernetes-csi/external-snapshotter/client/v8/apis/volumesnapshot/v1"
v1 "github.com/red-hat-storage/ocs-operator/api/v4/v1"
"github.com/red-hat-storage/ocs-operator/api/v4/v1alpha1"
Expand Down Expand Up @@ -78,6 +79,7 @@ type StorageRequestReconciler struct {
// +kubebuilder:rbac:groups=ocs.openshift.io,resources=storageclusters,verbs=get;watch;list
// +kubebuilder:rbac:groups=storage.k8s.io,resources=storageclasses,verbs=watch;create;delete;get;list
// +kubebuilder:rbac:groups=snapshot.storage.k8s.io,resources=volumesnapshotclasses,verbs=get;list;watch;create;delete
// +kubebuilder:rbac:groups=groupsnapshot.storage.k8s.io,resources=volumegroupsnapshotclasses,verbs=get;watch;create;update;delete
// +kubebuilder:rbac:groups=core,resources=persistentvolumes,verbs=get;list;watch

func (r *StorageRequestReconciler) Reconcile(ctx context.Context, request reconcile.Request) (reconcile.Result, error) {
Expand Down Expand Up @@ -186,6 +188,7 @@ func (r *StorageRequestReconciler) SetupWithManager(mgr ctrl.Manager) error {
Watches(&rookCephv1.CephClient{}, enqueueForOwner).
Watches(&storagev1.StorageClass{}, enqueueStorageConsumerRequest).
Watches(&snapapi.VolumeSnapshotClass{}, enqueueStorageConsumerRequest).
Watches(&groupsnapapi.VolumeGroupSnapshotClass{}, enqueueStorageConsumerRequest).
Complete(r)
}

Expand Down
11 changes: 11 additions & 0 deletions deploy/csv-templates/ocs-operator.csv.yaml.in
Original file line number Diff line number Diff line change
Expand Up @@ -299,6 +299,17 @@ spec:
- namespaces
verbs:
- get
- apiGroups:
- groupsnapshot.storage.k8s.io
resources:
- volumegroupsnapshotclasses
verbs:
- create
- delete
- get
- list
- update
- watch
- apiGroups:
- k8s.cni.cncf.io
resources:
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -308,6 +308,17 @@ spec:
- namespaces
verbs:
- get
- apiGroups:
- groupsnapshot.storage.k8s.io
resources:
- volumegroupsnapshotclasses
verbs:
- create
- delete
- get
- list
- update
- watch
- apiGroups:
- k8s.cni.cncf.io
resources:
Expand Down
2 changes: 2 additions & 0 deletions main.go
Original file line number Diff line number Diff line change
Expand Up @@ -24,6 +24,7 @@ import (
"runtime"

nadscheme "github.com/k8snetworkplumbingwg/network-attachment-definition-client/pkg/client/clientset/versioned/scheme"
groupsnapapi "github.com/kubernetes-csi/external-snapshotter/client/v8/apis/volumegroupsnapshot/v1alpha1"
snapapi "github.com/kubernetes-csi/external-snapshotter/client/v8/apis/volumesnapshot/v1"
nbapis "github.com/noobaa/noobaa-operator/v5/pkg/apis"
openshiftConfigv1 "github.com/openshift/api/config/v1"
Expand Down Expand Up @@ -86,6 +87,7 @@ func init() {
utilruntime.Must(corev1.AddToScheme(scheme))
utilruntime.Must(openshiftv1.AddToScheme(scheme))
utilruntime.Must(snapapi.AddToScheme(scheme))
utilruntime.Must(groupsnapapi.AddToScheme(scheme))
utilruntime.Must(openshiftConfigv1.AddToScheme(scheme))
utilruntime.Must(extv1.AddToScheme(scheme))
utilruntime.Must(routev1.AddToScheme(scheme))
Expand Down
Loading

0 comments on commit de40e7b

Please sign in to comment.