Skip to content

Commit

Permalink
feat: add pv and pvc controllers to publish events
Browse files Browse the repository at this point in the history
Signed-off-by: Suleyman Akbas <[email protected]>
  • Loading branch information
suleymanakbas91 committed May 31, 2023
1 parent cd91081 commit 35455db
Show file tree
Hide file tree
Showing 9 changed files with 268 additions and 7 deletions.
34 changes: 34 additions & 0 deletions bundle/manifests/lvms-operator.clusterserviceversion.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -123,6 +123,14 @@ spec:
- list
- update
- watch
- apiGroups:
- ""
resources:
- events
verbs:
- create
- patch
- update
- apiGroups:
- ""
resources:
Expand All @@ -131,6 +139,24 @@ spec:
- get
- list
- watch
- apiGroups:
- ""
resources:
- persistentvolumeclaims
verbs:
- get
- list
- update
- watch
- apiGroups:
- ""
resources:
- persistentvolumes
verbs:
- get
- list
- update
- watch
- apiGroups:
- ""
resources:
Expand Down Expand Up @@ -246,6 +272,14 @@ spec:
- get
- list
- watch
- apiGroups:
- storage.k8s.io
resources:
- csistoragecapacities
verbs:
- get
- list
- watch
- apiGroups:
- storage.k8s.io
resources:
Expand Down
34 changes: 34 additions & 0 deletions config/rbac/role.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -29,6 +29,14 @@ rules:
- list
- update
- watch
- apiGroups:
- ""
resources:
- events
verbs:
- create
- patch
- update
- apiGroups:
- ""
resources:
Expand All @@ -37,6 +45,24 @@ rules:
- get
- list
- watch
- apiGroups:
- ""
resources:
- persistentvolumeclaims
verbs:
- get
- list
- update
- watch
- apiGroups:
- ""
resources:
- persistentvolumes
verbs:
- get
- list
- update
- watch
- apiGroups:
- ""
resources:
Expand Down Expand Up @@ -152,6 +178,14 @@ rules:
- get
- list
- watch
- apiGroups:
- storage.k8s.io
resources:
- csistoragecapacities
verbs:
- get
- list
- watch
- apiGroups:
- storage.k8s.io
resources:
Expand Down
2 changes: 1 addition & 1 deletion controllers/constants.go
Original file line number Diff line number Diff line change
Expand Up @@ -115,7 +115,7 @@ const (
PartOfLabelVal = "lvms-provisioner"
CsiDriverNameVal = "topolvm-csi-driver"

storageClassPrefix = "lvms-"
StorageClassPrefix = "lvms-"
volumeSnapshotClassPrefix = "lvms-"
sccPrefix = "lvms-"
)
2 changes: 1 addition & 1 deletion controllers/lvmcluster_controller.go
Original file line number Diff line number Diff line change
Expand Up @@ -208,7 +208,7 @@ func (r *LVMClusterReconciler) reconcile(ctx context.Context, instance *lvmv1alp
}
}

r.Log.Info("successfully reconciled LvmCluster")
r.Log.Info("successfully reconciled LVMCluster")

return ctrl.Result{}, nil
}
Expand Down
103 changes: 103 additions & 0 deletions controllers/persistent-volume-claim/controller.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,103 @@
package persistent_volume_claim

import (
"context"
"github.com/openshift/lvm-operator/controllers"
corev1 "k8s.io/api/core/v1"
v1 "k8s.io/api/storage/v1"
apierrors "k8s.io/apimachinery/pkg/api/errors"
"k8s.io/client-go/tools/record"
ctrl "sigs.k8s.io/controller-runtime"
"sigs.k8s.io/controller-runtime/pkg/client"
"sigs.k8s.io/controller-runtime/pkg/event"
crlog "sigs.k8s.io/controller-runtime/pkg/log"
"sigs.k8s.io/controller-runtime/pkg/predicate"
"strings"
)

// PersistentVolumeClaimReconciler reconciles a PersistentVolumeClaim object
type PersistentVolumeClaimReconciler struct {
client client.Client
apiReader client.Reader
recorder record.EventRecorder
}

// NewPersistentVolumeClaimReconciler returns PersistentVolumeClaimReconciler.
func NewPersistentVolumeClaimReconciler(client client.Client, apiReader client.Reader, eventRecorder record.EventRecorder) *PersistentVolumeClaimReconciler {
return &PersistentVolumeClaimReconciler{
client: client,
apiReader: apiReader,
recorder: eventRecorder,
}
}

//+kubebuilder:rbac:groups=core,resources=persistentvolumeclaims,verbs=get;list;watch;update
//+kubebuilder:rbac:groups=storage.k8s.io,resources=csistoragecapacities,verbs=get;list;watch
//+kubebuilder:rbac:groups=core,resources=events,verbs=create;update;patch

// Reconcile PVC
func (r *PersistentVolumeClaimReconciler) Reconcile(ctx context.Context, req ctrl.Request) (ctrl.Result, error) {
log := crlog.FromContext(ctx)

log.Info("Reconciling PVC", "PVC", req.NamespacedName)
pvc := &corev1.PersistentVolumeClaim{}
err := r.client.Get(ctx, req.NamespacedName, pvc)
switch {
case err == nil:
case apierrors.IsNotFound(err):
return ctrl.Result{}, nil
default:
return ctrl.Result{}, err
}

// Skip if the PVC is deleted or does not use the lvms storage class.
if pvc.DeletionTimestamp != nil || !strings.HasPrefix(*pvc.Spec.StorageClassName, controllers.StorageClassPrefix) {
return ctrl.Result{}, nil
}

// Skip if the PVC is not in Pending state.
if pvc.Status.Phase != "Pending" {
return ctrl.Result{}, nil
}

// List csi storage capacities
storageCapacityList := &v1.CSIStorageCapacityList{}
err = r.client.List(ctx, storageCapacityList, &client.ListOptions{Namespace: controllers.OperatorNamespace})
switch {
case err == nil:
case apierrors.IsNotFound(err):
return ctrl.Result{}, nil
default:
return ctrl.Result{}, err
}

// Check if there is any node that has enough storage capacity for the PVC
found := false
for _, sc := range storageCapacityList.Items {
if strings.HasPrefix(sc.StorageClassName, controllers.StorageClassPrefix) && pvc.Spec.Resources.Requests.Storage().Cmp(*sc.Capacity) < 0 {
found = true
}
}

// Publish an event if the requested storage is greater than the available capacity
if !found {
r.recorder.Event(pvc, "Warning", "NotEnoughCapacity", "Requested storage is greater than available capacity on all the nodes. Check available capacity by `oc get csistoragecapacity`.")
log.Info("Event published for the PVC", "PVC", req.NamespacedName)
}

return ctrl.Result{}, nil
}

// SetupWithManager sets up the controller with the Manager.
func (r *PersistentVolumeClaimReconciler) SetupWithManager(mgr ctrl.Manager) error {
pred := predicate.Funcs{
CreateFunc: func(event.CreateEvent) bool { return true },
DeleteFunc: func(event.DeleteEvent) bool { return false },
UpdateFunc: func(event.UpdateEvent) bool { return true },
GenericFunc: func(event.GenericEvent) bool { return false },
}
return ctrl.NewControllerManagedBy(mgr).
WithEventFilter(pred).
For(&corev1.PersistentVolumeClaim{}).
Complete(r)
}
77 changes: 77 additions & 0 deletions controllers/persistent-volume/controller.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,77 @@
package persistent_volume

import (
"context"
"github.com/openshift/lvm-operator/controllers"
corev1 "k8s.io/api/core/v1"
apierrors "k8s.io/apimachinery/pkg/api/errors"
"k8s.io/client-go/tools/record"
ctrl "sigs.k8s.io/controller-runtime"
"sigs.k8s.io/controller-runtime/pkg/client"
"sigs.k8s.io/controller-runtime/pkg/event"
crlog "sigs.k8s.io/controller-runtime/pkg/log"
"sigs.k8s.io/controller-runtime/pkg/predicate"
"strings"
)

// PersistentVolumeReconciler reconciles a PersistentVolume object
type PersistentVolumeReconciler struct {
client client.Client
apiReader client.Reader
recorder record.EventRecorder
}

// NewPersistentVolumeReconciler returns PersistentVolumeReconciler.
func NewPersistentVolumeReconciler(client client.Client, apiReader client.Reader, eventRecorder record.EventRecorder) *PersistentVolumeReconciler {
return &PersistentVolumeReconciler{
client: client,
apiReader: apiReader,
recorder: eventRecorder,
}
}

//+kubebuilder:rbac:groups=core,resources=persistentvolumes,verbs=get;list;watch;update
//+kubebuilder:rbac:groups=core,resources=events,verbs=create;update;patch

// Reconcile PV
func (r *PersistentVolumeReconciler) Reconcile(ctx context.Context, req ctrl.Request) (ctrl.Result, error) {
log := crlog.FromContext(ctx)

log.Info("Reconciling PV", "PV", req.NamespacedName)
pv := &corev1.PersistentVolume{}
err := r.client.Get(ctx, req.NamespacedName, pv)
switch {
case err == nil:
case apierrors.IsNotFound(err):
return ctrl.Result{}, nil
default:
return ctrl.Result{}, err
}

// Skip if the PV is deleted or PV does not use the lvms storage class.
if pv.DeletionTimestamp != nil || !strings.HasPrefix(pv.Spec.StorageClassName, controllers.StorageClassPrefix) {
return ctrl.Result{}, nil
}

// Publish an event if PV has no claimRef
if pv.Spec.ClaimRef == nil {
r.recorder.Event(pv, "Warning", "RemovedClaimReference", "Claim reference is removed. This PV is dynamically managed. Please do not modify it.")
log.Info("Event published for the PV", "PV", req.NamespacedName)
}

return ctrl.Result{}, nil
}

// SetupWithManager sets up the controller with the Manager.
func (r *PersistentVolumeReconciler) SetupWithManager(mgr ctrl.Manager) error {
pred := predicate.Funcs{
CreateFunc: func(event.CreateEvent) bool { return true },
DeleteFunc: func(event.DeleteEvent) bool { return false },
UpdateFunc: func(event.UpdateEvent) bool { return true },
GenericFunc: func(event.GenericEvent) bool { return false },
}
return ctrl.NewControllerManagedBy(mgr).
WithEventFilter(pred).
For(&corev1.PersistentVolume{}).
Complete(r)
}
2 changes: 1 addition & 1 deletion controllers/utils.go
Original file line number Diff line number Diff line change
Expand Up @@ -58,7 +58,7 @@ func setDaemonsetNodeSelector(nodeSelector *corev1.NodeSelector, ds *appsv1.Daem
}

func getStorageClassName(deviceName string) string {
return storageClassPrefix + deviceName
return StorageClassPrefix + deviceName
}

func getVolumeSnapshotClassName(deviceName string) string {
Expand Down
4 changes: 2 additions & 2 deletions docs/design/lvm-operator-manager.md
Original file line number Diff line number Diff line change
Expand Up @@ -41,11 +41,11 @@ The `topolvmNode` reconcile unit is responsible for deploying and managing the T

### TopoLVM Scheduler

The TopoLVM Scheduler is **not** used in LVMS for scheduling Pods. Instead, the CSI StorageCapacity tracking feature is utilized by the Kubernetes scheduler to determine the Node on which to provision storage. This feature provides the necessary information to the scheduler regarding the available storage on each Node, allowing it to make an informed decision about where to place the Pod.
The TopoLVM Scheduler is **not** used in LVMS for scheduling Pods. Instead, the CSI StorageCapacity tracking feature is utilized by the Kubernetes scheduler to determine the Node on which to provision storage. This feature provides the necessary information to the scheduler regarding the available storage on each node, allowing it to make an informed decision about where to place the Pod.

## Storage Classes

The `topolvmStorageClass` reconcile unit is responsible for creating and managing all storage classes associated with the device classes specified in the LVMCluster CR. Each storage class is named with a prefix of 'lvms-' followed by the name of the corresponding device class in the LVMCluster CR.
The `topolvmStorageClass` reconcile unit is responsible for creating and managing all storage classes associated with the device classes specified in the LVMCluster CR. Each storage class is named with a prefix of `lvms-` followed by the name of the corresponding device class in the LVMCluster CR.

## Volume Group Manager

Expand Down
17 changes: 15 additions & 2 deletions main.go
Original file line number Diff line number Diff line change
Expand Up @@ -37,6 +37,8 @@ import (

lvmv1alpha1 "github.com/openshift/lvm-operator/api/v1alpha1"
"github.com/openshift/lvm-operator/controllers"
persistent_volume "github.com/openshift/lvm-operator/controllers/persistent-volume"
persistent_volume_claim "github.com/openshift/lvm-operator/controllers/persistent-volume-claim"
topolvmv1 "github.com/topolvm/topolvm/api/v1"
//+kubebuilder:scaffold:imports
)
Expand Down Expand Up @@ -84,7 +86,6 @@ func main() {
Scheme: scheme,
MetricsBindAddress: metricsAddr,
Port: 9443,
Namespace: operatorNamespace,
HealthProbeBindAddress: probeAddr,
LeaderElection: enableLeaderElection,
LeaderElectionID: "1136b8a6.topolvm.io",
Expand All @@ -94,6 +95,7 @@ func main() {
os.Exit(1)
}

// register controllers
if err = (&controllers.LVMClusterReconciler{
Client: mgr.GetClient(),
Scheme: mgr.GetScheme(),
Expand All @@ -107,7 +109,18 @@ func main() {
setupLog.Error(err, "unable to create webhook", "webhook", "LVMCluster")
os.Exit(1)
}
//+kubebuilder:scaffold:builder

pvController := persistent_volume.NewPersistentVolumeReconciler(mgr.GetClient(), mgr.GetAPIReader(), mgr.GetEventRecorderFor("lvms-persistentvolume-controller"))
if err := pvController.SetupWithManager(mgr); err != nil {
setupLog.Error(err, "unable to create controller", "controller", "PersistentVolume")
os.Exit(1)
}

pvcController := persistent_volume_claim.NewPersistentVolumeClaimReconciler(mgr.GetClient(), mgr.GetAPIReader(), mgr.GetEventRecorderFor("lvms-persistentvolumeclaim-controller"))
if err := pvcController.SetupWithManager(mgr); err != nil {
setupLog.Error(err, "unable to create controller", "controller", "PersistentVolumeClaim")
os.Exit(1)
}

if err := mgr.AddHealthzCheck("healthz", healthz.Ping); err != nil {
setupLog.Error(err, "unable to set up health check")
Expand Down

0 comments on commit 35455db

Please sign in to comment.