From 5c826edb8fe87d48404733b81a3b62726b40ffe1 Mon Sep 17 00:00:00 2001 From: Timothee Gosselin Date: Thu, 7 Nov 2019 16:34:53 +0100 Subject: [PATCH] add pvc --- pkg/pvc/pvc.go | 217 +++++++++++++++++++++++++++++++++++++++++++++++ pkg/pvc/types.go | 57 +++++++++++++ 2 files changed, 274 insertions(+) create mode 100644 pkg/pvc/pvc.go create mode 100644 pkg/pvc/types.go diff --git a/pkg/pvc/pvc.go b/pkg/pvc/pvc.go new file mode 100644 index 0000000..7c45f40 --- /dev/null +++ b/pkg/pvc/pvc.go @@ -0,0 +1,217 @@ +package pvc + +import ( + "reflect" + + "github.com/ankitrgadiya/operatorlib/pkg/interfaces" + "github.com/ankitrgadiya/operatorlib/pkg/meta" + "github.com/ankitrgadiya/operatorlib/pkg/operation" + "sigs.k8s.io/controller-runtime/pkg/reconcile" + + "github.com/pkg/errors" + corev1 "k8s.io/api/core/v1" + metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" +) + +// GenerateConfigMap generates ConfigMap object as per the `Conf` struct passed +func GeneratePVC(c Conf) (obj *corev1.PersistentVolumeClaim, err error) { + var om *metav1.ObjectMeta + var accessModes []corev1.PersistentVolumeAccessMode + var resources corev1.ResourceRequirements + + om, err = meta.GenerateObjectMeta(meta.Conf{ + Instance: c.Instance, + Name: c.Name, + Namespace: c.Namespace, + GenLabelsFunc: c.GenLabelsFunc, + GenAnnotationsFunc: c.GenAnnotationsFunc, + AppendLabels: c.AppendLabels, + }) + + if err != nil { + return nil, errors.Wrap(err, "failed to generate objectmeta") + } + if c.GenAccessModesFunc != nil { + accessModes, err = c.GenAccessModesFunc(c.Instance) + if err != nil { + return nil, errors.Wrap(err, "failed to generate pvc accessmodes") + } + } + if c.GenResourcesFunc != nil { + resources, err = c.GenResourcesFunc(c.Instance) + if err != nil { + return nil, errors.Wrap(err, "failed to generate pvc accessmodes") + } + } + obj = &corev1.PersistentVolumeClaim{ + TypeMeta: metav1.TypeMeta{ + Kind: "PersistentVolumeClaim", + APIVersion: "core/v1", + }, + ObjectMeta: *om, + Spec: corev1.PersistentVolumeClaimSpec{ + AccessModes: accessModes, + Resources: resources, + StorageClassName: c.StorageClassName, + }, + } + return obj, err +} + +// MaybeUpdate implements MaybeUpdateFunc for Secret object. It +// compares the two Secrets being passed and update the first one if +// required. +func MaybeUpdate(original interfaces.Object, new interfaces.Object) (bool, error) { + o, ok := original.(*corev1.PersistentVolumeClaim) + if !ok { + return false, errors.New("failed to assert the original object") + } + + n, ok := new.(*corev1.PersistentVolumeClaim) + if !ok { + return false, errors.New("failed to assert the new object") + } + + result := reflect.DeepEqual(o.Spec, n.Spec) + if result { + return false, nil + } + + o.Spec = n.Spec + // TOFIX + return false, nil +} + +// Create generates Secret as per the `Conf` struct passed and creates +// it in the cluster +func Create(c Conf) (reconcile.Result, error) { + var s *corev1.PersistentVolumeClaim + var err error + if c.GenPVCFunc != nil { + s, err = c.GenPVCFunc(c) + } else { + s, err = GeneratePVC(c) + } + if err != nil { + return reconcile.Result{}, errors.Wrap(err, "failed to generate secret") + } + + result, err := operation.Create(operation.Conf{ + Instance: c.Instance, + Reconcile: c.Reconcile, + Object: s, + OwnerReference: c.OwnerReference, + AfterCreateFunc: c.AfterCreateFunc, + }) + if err != nil { + return result, errors.Wrap(err, "failed to create secret") + } + return result, nil +} + +// Update generates the Secret as per the `Conf` struct passed and +// compares it with the in-cluster version. If required, it updates +// the in-cluster Secret with the changes. For comparing the Secrets, +// it uses `MaybeUpdate` function by default but can also use +// `MaybeUpdateFunc` from `Conf` if passed. +func Update(c Conf) (reconcile.Result, error) { + var s *corev1.PersistentVolumeClaim + var err error + if c.GenPVCFunc != nil { + s, err = c.GenPVCFunc(c) + } else { + s, err = GeneratePVC(c) + } + if err != nil { + return reconcile.Result{}, errors.Wrap(err, "failed to generate secret") + } + + var maybeUpdateFunc operation.MaybeUpdateFunc + if c.MaybeUpdateFunc != nil { + maybeUpdateFunc = c.MaybeUpdateFunc + } else { + maybeUpdateFunc = MaybeUpdate + } + + result, err := operation.Update(operation.Conf{ + Instance: c.Instance, + Reconcile: c.Reconcile, + Object: s, + ExistingObject: &corev1.PersistentVolumeClaim{}, + MaybeUpdateFunc: maybeUpdateFunc, + AfterUpdateFunc: c.AfterUpdateFunc, + }) + if err != nil { + return result, errors.Wrap(err, "failed to update secret") + } + + return result, nil +} + +// CreateOrUpdate is a combination of `Create` and `Update` +// functions. It creates the Secret object if it is not already in the +// cluster and updates the Secret if one exists. +func CreateOrUpdate(c Conf) (reconcile.Result, error) { + var s *corev1.PersistentVolumeClaim + var err error + if c.GenPVCFunc != nil { + s, err = c.GenPVCFunc(c) + } else { + s, err = GeneratePVC(c) + } + if err != nil { + return reconcile.Result{}, errors.Wrap(err, "failed to generate secret") + } + + var maybeUpdateFunc operation.MaybeUpdateFunc + if c.MaybeUpdateFunc != nil { + maybeUpdateFunc = c.MaybeUpdateFunc + } else { + maybeUpdateFunc = MaybeUpdate + } + + result, err := operation.CreateOrUpdate(operation.Conf{ + Instance: c.Instance, + Reconcile: c.Reconcile, + Object: s, + ExistingObject: &corev1.PersistentVolumeClaim{}, + OwnerReference: c.OwnerReference, + MaybeUpdateFunc: maybeUpdateFunc, + AfterUpdateFunc: c.AfterUpdateFunc, + AfterCreateFunc: c.AfterCreateFunc, + }) + if err != nil { + return result, errors.Wrap(err, "failed to create or update secret") + } + + return result, nil +} + +// Delete generates the ObjectMeta for Secret as per the `Conf` struct +// passed and deletes it from the cluster +func Delete(c Conf) (reconcile.Result, error) { + om, err := meta.GenerateObjectMeta(meta.Conf{ + Instance: c.Instance, + Name: c.Name, + Namespace: c.Namespace, + GenLabelsFunc: c.GenLabelsFunc, + GenAnnotationsFunc: c.GenAnnotationsFunc, + GenFinalizersFunc: c.GenFinalizersFunc, + AppendLabels: c.AppendLabels, + }) + if err != nil { + return reconcile.Result{}, errors.Wrap(err, "failed to generate objectmeta for secret") + } + + result, err := operation.Delete(operation.Conf{ + Instance: c.Instance, + Reconcile: c.Reconcile, + Object: &corev1.PersistentVolumeClaim{ObjectMeta: *om}, + AfterDeleteFunc: c.AfterDeleteFunc, + }) + if err != nil { + return result, errors.Wrap(err, "failed to delete secret") + } + + return result, nil +} diff --git a/pkg/pvc/types.go b/pkg/pvc/types.go new file mode 100644 index 0000000..cd777d6 --- /dev/null +++ b/pkg/pvc/types.go @@ -0,0 +1,57 @@ +package pvc + +import ( + "github.com/ankitrgadiya/operatorlib/pkg/interfaces" + "github.com/ankitrgadiya/operatorlib/pkg/meta" + "github.com/ankitrgadiya/operatorlib/pkg/operation" + + corev1 "k8s.io/api/core/v1" +) + +// GenConfigMapFunc defines a function which generates ConfigMap. +type GenPVCFunc func(Conf) (*corev1.PersistentVolumeClaim, error) +type GenResourcesFunc func(interfaces.Object) (corev1.ResourceRequirements, error) +type GenAccessModesFunc func(interfaces.Object) ([]corev1.PersistentVolumeAccessMode, error) + +// Conf is used to pass parameters to functions in this package to +// perform operations on Configmap objects. +type Conf struct { + // Instance is the Owner object which manages the Configmap + Instance interfaces.Object + // Reconcile is the pointer to reconcile struct of owner object + interfaces.Reconcile + // Name of the Configmap + Name string + // Namespace of the Configmap + Namespace string + // GenLalebsFunc is used to generate labels for ObjectMeta + meta.GenLabelsFunc + // GenAnnotationsFunc is used to generate annotations for ObjectMeta + meta.GenAnnotationsFunc + // GenFinalizers is used to generate finalizers for ObjectMeta + meta.GenFinalizersFunc + // AppendLabels is used to determine if labels from Owner object + // are to be inherited + AppendLabels bool + // OwnerReference is used to determine if owner reference needs to + // be set on Configmap before creating it in cluster + OwnerReference bool + // MaybeUpdateFunc defines an update function with custom logic + // for Configmap update + operation.MaybeUpdateFunc + // AfterCreateFunc hook is called after creating the Configmap + operation.AfterCreateFunc + // AfterUpdateFunc hook is called after updating the Configmap + operation.AfterUpdateFunc + // AfterDeleteFunc hook is called after deleting the Configmap + operation.AfterDeleteFunc + // GenConfigMapFunc defines a function to generate the Configmap + // object. The package comes with default configmap generator + // function which is used by operation functions. By specifying + // this field, user can override the default function with a + // custom one. + GenPVCFunc + StorageClassName *string + GenResourcesFunc + GenAccessModesFunc +} -- GitLab