Skip to content
pvc.go 5.98 KiB
Newer Older
Timothee Gosselin's avatar
Timothee Gosselin committed
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
}