Skip to content

Commit

Permalink
controllers: Generates VGSClass
Browse files Browse the repository at this point in the history
Signed-off-by: raaizik <[email protected]>
  • Loading branch information
raaizik committed Nov 25, 2024
1 parent 672e703 commit 6356b95
Show file tree
Hide file tree
Showing 9 changed files with 1,089 additions and 7 deletions.
18 changes: 18 additions & 0 deletions bundle/manifests/ocs-client-operator.clusterserviceversion.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -208,6 +208,24 @@ spec:
- list
- update
- watch
- apiGroups:
- groupsnapshot.storage.k8s.io
resources:
- volumegroupsnapshotclasses
verbs:
- create
- delete
- get
- list
- watch
- apiGroups:
- groupsnapshot.storage.k8s.io
resources:
- volumegroupsnapshotcontents
verbs:
- get
- list
- watch
- apiGroups:
- monitoring.coreos.com
resources:
Expand Down
18 changes: 18 additions & 0 deletions config/rbac/role.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -165,6 +165,24 @@ rules:
- list
- update
- watch
- apiGroups:
- groupsnapshot.storage.k8s.io
resources:
- volumegroupsnapshotclasses
verbs:
- create
- delete
- get
- list
- watch
- apiGroups:
- groupsnapshot.storage.k8s.io
resources:
- volumegroupsnapshotcontents
verbs:
- get
- list
- watch
- apiGroups:
- monitoring.coreos.com
resources:
Expand Down
4 changes: 4 additions & 0 deletions internal/controller/operatorconfigmap_controller.go
Original file line number Diff line number Diff line change
Expand Up @@ -351,6 +351,10 @@ func (c *OperatorConfigMapReconciler) reconcileDelegatedCSI() error {
templates.CSIOperatorConfigSpec.DeepCopyInto(&csiOperatorConfig.Spec)
csiOperatorConfig.Spec.DriverSpecDefaults.ImageSet = &corev1.LocalObjectReference{Name: cmName}
csiOperatorConfig.Spec.DriverSpecDefaults.ClusterName = ptr.To(string(clusterVersion.Spec.ClusterID))
if c.AvailableCrds[volumeGroupSnapshotClassCrd] {
csiOperatorConfig.Spec.DriverSpecDefaults.SnapshotPolicy = csiopv1a1.VolumeGroupSnapshotPolicy
}

return nil
}); err != nil {
return fmt.Errorf("failed to reconcile csi operator config: %v", err)
Expand Down
107 changes: 100 additions & 7 deletions internal/controller/storageclaim_controller.go
Original file line number Diff line number Diff line change
Expand Up @@ -20,20 +20,23 @@ import (
"context"
"encoding/json"
"fmt"
"slices"
"strings"

v1alpha1 "github.com/red-hat-storage/ocs-client-operator/api/v1alpha1"
"github.com/red-hat-storage/ocs-client-operator/pkg/templates"
"github.com/red-hat-storage/ocs-client-operator/pkg/utils"
"slices"
"strings"

csiopv1a1 "github.com/ceph/ceph-csi-operator/api/v1alpha1"
"github.com/go-logr/logr"

replicationv1alpha1 "github.com/csi-addons/kubernetes-csi-addons/api/replication.storage/v1alpha1"
groupsnapapi "github.com/kubernetes-csi/external-snapshotter/client/v8/apis/volumegroupsnapshot/v1alpha1"
snapapi "github.com/kubernetes-csi/external-snapshotter/client/v8/apis/volumesnapshot/v1"
providerclient "github.com/red-hat-storage/ocs-operator/services/provider/api/v4/client"
corev1 "k8s.io/api/core/v1"
storagev1 "k8s.io/api/storage/v1"
extv1 "k8s.io/apiextensions-apiserver/pkg/apis/apiextensions/v1"
"k8s.io/apimachinery/pkg/api/errors"
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
"k8s.io/apimachinery/pkg/runtime"
Expand All @@ -42,6 +45,7 @@ import (
"sigs.k8s.io/controller-runtime/pkg/cache"
"sigs.k8s.io/controller-runtime/pkg/client"
"sigs.k8s.io/controller-runtime/pkg/controller/controllerutil"
"sigs.k8s.io/controller-runtime/pkg/handler"
ctrllog "sigs.k8s.io/controller-runtime/pkg/log"
"sigs.k8s.io/controller-runtime/pkg/predicate"
"sigs.k8s.io/controller-runtime/pkg/reconcile"
Expand All @@ -52,8 +56,10 @@ const (
storageClaimAnnotation = "ocs.openshift.io/storageclaim"
keyRotationAnnotation = "keyrotation.csiaddons.openshift.io/schedule"

pvClusterIDIndexName = "index:persistentVolumeClusterID"
vscClusterIDIndexName = "index:volumeSnapshotContentCSIDriver"
pvClusterIDIndexName = "index:persistentVolumeClusterID"
vscClusterIDIndexName = "index:volumeSnapshotContentCSIDriver"
volumeGroupSnapshotClassCrd = "groupsnapshot.storage.k8s.io/volumegroupsnapshotclass"
drClusterConfigCRDName = "drclusterconfigs.ramendr.openshift.io"
)

// StorageClaimReconciler reconciles a StorageClaim object
Expand All @@ -62,6 +68,7 @@ type StorageClaimReconciler struct {
cache.Cache
Scheme *runtime.Scheme
OperatorNamespace string
AvailableCrds map[string]bool

log logr.Logger
ctx context.Context
Expand Down Expand Up @@ -109,8 +116,24 @@ func (r *StorageClaimReconciler) SetupWithManager(mgr ctrl.Manager) error {
For(&v1alpha1.StorageClaim{}, builder.WithPredicates(generationChangePredicate)).
Owns(&storagev1.StorageClass{}).
Owns(&snapapi.VolumeSnapshotClass{}).
Owns(&replicationv1alpha1.VolumeReplicationClass{}, builder.WithPredicates(generationChangePredicate)).
Owns(&csiopv1a1.ClientProfile{}, builder.WithPredicates(generationChangePredicate))
Owns(&csiopv1a1.ClientProfile{}, builder.WithPredicates(generationChangePredicate)).
Watches(
&extv1.CustomResourceDefinition{},
&handler.EnqueueRequestForObject{},
builder.WithPredicates(
utils.NamePredicate(volumeGroupSnapshotClassCrd),
utils.EventTypePredicate(
!r.AvailableCrds[volumeGroupSnapshotClassCrd],
false,
r.AvailableCrds[volumeGroupSnapshotClassCrd],
false,
),
),
builder.OnlyMetadata,
)
if r.AvailableCrds[volumeGroupSnapshotClassCrd] {
bldr = bldr.Owns(&groupsnapapi.VolumeGroupSnapshotClass{})
}

return bldr.Complete(r)
}
Expand All @@ -121,8 +144,10 @@ func (r *StorageClaimReconciler) SetupWithManager(mgr ctrl.Manager) error {
//+kubebuilder:rbac:groups="",resources=secrets,verbs=get;list;watch;create;update;delete
//+kubebuilder:rbac:groups=storage.k8s.io,resources=storageclasses,verbs=get;list;watch;create;update;patch;delete
//+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=create;delete;get;list;watch
//+kubebuilder:rbac:groups=core,resources=persistentvolumes,verbs=get;list;watch
//+kubebuilder:rbac:groups=snapshot.storage.k8s.io,resources=volumesnapshotcontents,verbs=get;list;watch
//+kubebuilder:rbac:groups=groupsnapshot.storage.k8s.io,resources=volumegroupsnapshotcontents,verbs=get;list;watch
//+kubebuilder:rbac:groups=csi.ceph.io,resources=clientprofiles,verbs=get;list;update;create;watch;delete
//+kubebuilder:rbac:groups=replication.storage.openshift.io,resources=volumereplicationclass,verbs=get;list;watch;create;delete

Expand All @@ -141,6 +166,17 @@ func (r *StorageClaimReconciler) Reconcile(ctx context.Context, req ctrl.Request
r.ctx = ctrllog.IntoContext(ctx, r.log)
r.log.Info("Reconciling StorageClaim.")

crd := &metav1.PartialObjectMetadata{}
for _, crdName := range []string{volumeGroupSnapshotClassCrd, drClusterConfigCRDName} {
crd.SetGroupVersionKind(extv1.SchemeGroupVersion.WithKind("CustomResourceDefinition"))
crd.Name = crdName
if err := r.Client.Get(ctx, client.ObjectKeyFromObject(crd), crd); client.IgnoreNotFound(err) != nil {
r.log.Error(err, "Failed to get CRD", "CRD", crdName)
return reconcile.Result{}, err
}
}
utils.AssertEqual(r.AvailableCrds[crd.Name], crd.UID != "", utils.ExitCodeThatShouldRestartTheProcess)

// Fetch the StorageClaim instance
r.storageClaim = &v1alpha1.StorageClaim{}
r.storageClaim.Name = req.Name
Expand Down Expand Up @@ -401,7 +437,31 @@ func (r *StorageClaimReconciler) reconcilePhases() (reconcile.Result, error) {
return nil
})
if err != nil {
return reconcile.Result{}, fmt.Errorf("failed to create or update VolumeSnapshotClass: %s", err)
return reconcile.Result{}, fmt.Errorf("failed to create or update StorageClass: %s", err)
}
case "VolumeGroupSnapshotClass":
// check for CRD availability
if r.AvailableCrds[("VolumeGroupSnapshotClass")] {
var volumeGroupSnapshotClass *groupsnapapi.VolumeGroupSnapshotClass
data := map[string]string{}
err = json.Unmarshal(resource.Data, &data)
if err != nil {
return reconcile.Result{}, fmt.Errorf("failed to unmarshal StorageClaim configuration response: %v", err)
}
data["csi.storage.k8s.io/group-snapshotter-secret-namespace"] = r.OperatorNamespace
// generate a new clusterID for cephfs subvolumegroup, as
// storageclaim is clusterscoped resources using its
// hash as the clusterID
data["clusterID"] = r.storageClaimHash
volumeGroupSnapshotClass = r.getCephDriverVolumeGroupSnapshotClass(resource.Labels, resource.Annotations)
utils.AddAnnotation(volumeGroupSnapshotClass, storageClaimAnnotation, r.storageClaim.Name)
err = utils.CreateOrReplace(r.ctx, r.Client, volumeGroupSnapshotClass, func() error {
volumeGroupSnapshotClass.Parameters = data
return nil
})
if err != nil {
return reconcile.Result{}, fmt.Errorf("failed to create or update StorageClass: %s", err)
}
}
case "VolumeReplicationClass":
vrc := &replicationv1alpha1.VolumeReplicationClass{}
Expand Down Expand Up @@ -466,6 +526,11 @@ func (r *StorageClaimReconciler) reconcilePhases() (reconcile.Result, error) {
} else if exist {
return reconcile.Result{}, fmt.Errorf("one or more volumesnapshotcontents exist that are dependent on storageclaim %s", r.storageClaim.Name)
}
if exist, err := r.hasVolumeGroupSnapshotContents(); err != nil {
return reconcile.Result{}, fmt.Errorf("failed to verify volumegroupsnapshotcontents dependent on storageclaim %q: %v", r.storageClaim.Name, err)
} else if exist {
return reconcile.Result{}, fmt.Errorf("one or more volumegroupsnapshotcontents exist that are dependent on storageclaim %s", r.storageClaim.Name)
}

// Call `RevokeStorageClaim` service on the provider server with StorageClaim as a request message.
// Check if StorageClaim is still exists (it might have been manually removed during the StorageClass
Expand Down Expand Up @@ -550,6 +615,20 @@ func (r *StorageClaimReconciler) getCephRBDVolumeSnapshotClass() *snapapi.Volume
return volumesnapshotclass
}

func (r *StorageClaimReconciler) getCephDriverVolumeGroupSnapshotClass(
labels map[string]string, annotations map[string]string) *groupsnapapi.VolumeGroupSnapshotClass {
volumegroupsnapshotclass := &groupsnapapi.VolumeGroupSnapshotClass{
ObjectMeta: metav1.ObjectMeta{
Name: r.storageClaim.Name,
Labels: labels,
Annotations: annotations,
},
Driver: templates.RBDDriverName,
DeletionPolicy: snapapi.VolumeSnapshotContentDelete,
}
return volumegroupsnapshotclass
}

func (r *StorageClaimReconciler) get(obj client.Object) error {
key := client.ObjectKeyFromObject(obj)
return r.Client.Get(r.ctx, key, obj)
Expand Down Expand Up @@ -594,3 +673,17 @@ func (r *StorageClaimReconciler) hasVolumeSnapshotContents() (bool, error) {

return false, nil
}

func (r *StorageClaimReconciler) hasVolumeGroupSnapshotContents() (bool, error) {
vscList := &groupsnapapi.VolumeGroupSnapshotContentList{}
if err := r.list(vscList, client.MatchingFields{vscClusterIDIndexName: r.storageClaimHash}); err != nil {
return false, fmt.Errorf("failed to list volume group snapshot content resources: %v", err)
}

if len(vscList.Items) != 0 {
r.log.Info(fmt.Sprintf("VolumeGroupSnapshotContent referring storageclaim %q exists", r.storageClaim.Name))
return true, nil
}

return false, nil
}

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

Loading

0 comments on commit 6356b95

Please sign in to comment.