Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

feat: implementation of csidriver resource unit #18

Merged
merged 3 commits into from
Dec 15, 2021
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
10 changes: 10 additions & 0 deletions config/rbac/role.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -32,3 +32,13 @@ rules:
- get
- patch
- update
- apiGroups:
- storage.k8s.io
resources:
- csidrivers
verbs:
- create
- delete
- get
- list
- watch
2 changes: 2 additions & 0 deletions controllers/defaults.go
Original file line number Diff line number Diff line change
Expand Up @@ -38,6 +38,8 @@ var (
CsiProvisionerImage = GetEnvOrDefault("CSI_PROVISIONER_IMAGE")
CsiLivenessProbeImage = GetEnvOrDefault("CSI_LIVENESSPROBE_IMAGE")
CsiResizerImage = GetEnvOrDefault("CSI_RESIZER_IMAGE")

TopolvmCSIDriverName = "topolvm.cybozu.com"
)

func GetEnvOrDefault(env string) string {
Expand Down
4 changes: 3 additions & 1 deletion controllers/lvmcluster_controller.go
Original file line number Diff line number Diff line change
Expand Up @@ -96,7 +96,9 @@ func (r *LVMClusterReconciler) Reconcile(ctx context.Context, req ctrl.Request)

// errors returned by this will be updated in the reconcileSucceeded condition of the LVMCluster
func (r *LVMClusterReconciler) reconcile(ctx context.Context, instance *lvmv1alpha1.LVMCluster) (ctrl.Result, error) {
resourceList := []resourceManager{}
resourceList := []resourceManager{
&csiDriver{},
}

//The resource was deleted
if !instance.DeletionTimestamp.IsZero() {
Expand Down
29 changes: 27 additions & 2 deletions controllers/lvmcluster_controller_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -19,6 +19,8 @@ import (
. "github.com/onsi/ginkgo"
. "github.com/onsi/gomega"
lvmv1alpha1 "github.com/red-hat-storage/lvm-operator/api/v1alpha1"
storagev1 "k8s.io/api/storage/v1"
"k8s.io/apimachinery/pkg/api/errors"
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
"k8s.io/apimachinery/pkg/types"
)
Expand All @@ -45,6 +47,10 @@ var _ = Describe("LVMCluster controller", func() {
},
}

// CSI Driver Resource
csiDriverName := types.NamespacedName{Name: TopolvmCSIDriverName}
csiDriverOut := &storagev1.CSIDriver{}

Context("Reconciliation on creating an LVMCluster CR", func() {
It("should reconcile LVMCluster CR creation, ", func() {
By("verifying CR status.Ready is set to true on reconciliation")
Expand All @@ -58,18 +64,37 @@ var _ = Describe("LVMCluster controller", func() {
}
return lvmClusterOut.Status.Ready
}, timeout, interval).Should(Equal(true))

By("confirming presence of CSIDriver resource")
Eventually(func() bool {
err := k8sClient.Get(ctx, csiDriverName, csiDriverOut)
return err == nil
}, timeout, interval).Should(BeTrue())
})
})

Context("Reconciliation on deleting the LVMCluster CR", func() {
It("should reconcile LVMCluster CR deletion ", func() {
By("confirming absence of lvm cluster CR and deletion of operator created resources")
// deletion of LVMCluster CR
Eventually(func() bool {
err := k8sClient.Delete(ctx, lvmClusterOut)
leelavg marked this conversation as resolved.
Show resolved Hide resolved

// deletion of LVM Cluster CR
return err != nil
}, timeout, interval).Should(BeTrue())

// deletion of CSI Driver resource
By("confirming absence of CSI Driver Resource")
Eventually(func() bool {
err := k8sClient.Get(ctx, csiDriverName, csiDriverOut)
return errors.IsNotFound(err)
}, timeout, interval).Should(BeTrue())

By("confirming absence of LVMCluster CR")
Eventually(func() bool {
err := k8sClient.Get(ctx, lvmClusterName, lvmClusterOut)
return errors.IsNotFound(err)
}, timeout, interval).Should(BeTrue())

})
})

Expand Down
100 changes: 100 additions & 0 deletions controllers/topolvm_csi_driver.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,100 @@
package controllers

import (
"context"
"fmt"

lvmv1alpha1 "github.com/red-hat-storage/lvm-operator/api/v1alpha1"
storagev1 "k8s.io/api/storage/v1"
"k8s.io/apimachinery/pkg/api/errors"
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
"k8s.io/apimachinery/pkg/types"
cutil "sigs.k8s.io/controller-runtime/pkg/controller/controllerutil"
)

const (
driverName = "topolvm-csi-driver"
)

type csiDriver struct{}

// csiDriver unit satisfies resourceManager interface
var _ resourceManager = csiDriver{}

func (c csiDriver) getName() string {
return driverName
}

//+kubebuilder:rbac:groups=storage.k8s.io,resources=csidrivers,verbs=get;create;delete;watch;list

func (c csiDriver) ensureCreated(r *LVMClusterReconciler, ctx context.Context, lvmCluster *lvmv1alpha1.LVMCluster) error {
csiDriverResource := getCSIDriverResource()
result, err := cutil.CreateOrUpdate(ctx, r.Client, csiDriverResource, func() error {
return nil
leelavg marked this conversation as resolved.
Show resolved Hide resolved
})
// CSIDriver resource is an immutable resource and can have result either Created or Unchanged and it's clusterscoped
switch result {
case cutil.OperationResultCreated:
r.Log.Info("csi driver", "operation", result, "name", csiDriverResource.Name)
case cutil.OperationResultNone:
r.Log.Info("csi driver", "operation", result, "name", csiDriverResource.Name)
default:
r.Log.Error(err, "csi driver reconcile failure", "name", csiDriverResource.Name)
return err
}
return nil
}

func (c csiDriver) ensureDeleted(r *LVMClusterReconciler, ctx context.Context, lvmCluster *lvmv1alpha1.LVMCluster) error {
csiDriverResource := &storagev1.CSIDriver{}
err := r.Client.Get(ctx, types.NamespacedName{Name: TopolvmCSIDriverName}, csiDriverResource)

if err != nil {
// already deleted in previous reconcile
if errors.IsNotFound(err) {
r.Log.Info("csi driver deleted", "TopolvmCSIDriverName", csiDriverResource.Name)
return nil
}
r.Log.Error(err, "failed to retrieve topolvm csi driver resource", "TopolvmCSIDriverName", csiDriverResource.Name)
return err
}

// if not deleted, initiate deletion
if csiDriverResource.GetDeletionTimestamp().IsZero() {
if err = r.Client.Delete(ctx, csiDriverResource); err != nil {
r.Log.Error(err, "failed to delete topolvm csi driver", "TopolvmCSIDriverName", csiDriverResource.Name)
return err
}
} else {
// set deletion in-progress for next reconcile to confirm deletion
return fmt.Errorf("topolvm csi driver %s is already marked for deletion", csiDriverResource.Name)
}

return nil
}

func (c csiDriver) updateStatus(r *LVMClusterReconciler, ctx context.Context, lvmCluster *lvmv1alpha1.LVMCluster) error {
// intentionally empty as there'll be no status field on CSIDriver resource
return nil
}

func getCSIDriverResource() *storagev1.CSIDriver {
// topolvm doesn't use/need attacher and reduce a round trip of the rpc by setting this to false
attachRequired := false
podInfoOnMount := true

// use storageCapacity tracking to take scheduling decisions
storageCapacity := true
csiDriver := &storagev1.CSIDriver{
ObjectMeta: metav1.ObjectMeta{
Name: TopolvmCSIDriverName,
},
Spec: storagev1.CSIDriverSpec{
AttachRequired: &attachRequired,
PodInfoOnMount: &podInfoOnMount,
StorageCapacity: &storageCapacity,
VolumeLifecycleModes: []storagev1.VolumeLifecycleMode{storagev1.VolumeLifecyclePersistent},
},
}
return csiDriver
}