package deployment import ( "reflect" "github.com/ankitrgadiya/operatorlib/pkg/interfaces" "github.com/ankitrgadiya/operatorlib/pkg/meta" "github.com/ankitrgadiya/operatorlib/pkg/operation" "github.com/imdario/mergo" "sigs.k8s.io/controller-runtime/pkg/reconcile" podlib "github.com/ankitrgadiya/operatorlib/pkg/pod" "github.com/pkg/errors" appsv1 "k8s.io/api/apps/v1" 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 GenerateDeployment(c Conf) (obj *appsv1.Deployment, err error) { var om *metav1.ObjectMeta // var container corev1.Container // var initContainer corev1.Container var podTemplate corev1.PodTemplateSpec 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") } podConf := podlib.Conf{ Instance: c.Instance, // Namespace: c.Namespace, // Name: c.Name, GenLabelsFunc: c.GenLabelsFunc, } err = mergo.Merge(&podConf, c.Pod) if err != nil { return nil, err } p, err := podlib.GeneratePod(podConf) if err != nil { return nil, errors.Wrap(err, "failed to generate pod template spec") } podTemplate = *p obj = &appsv1.Deployment{ TypeMeta: metav1.TypeMeta{ Kind: "Deployment", APIVersion: "apps/v1", }, ObjectMeta: *om, Spec: appsv1.DeploymentSpec{ // Replicas: c.Size, Strategy: c.Strategy, Selector: metav1.SetAsLabelSelector(om.Labels), Template: podTemplate, }, } 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.(*appsv1.Deployment) if !ok { return false, errors.New("failed to assert the original object") } n, ok := new.(*appsv1.Deployment) if !ok { return false, errors.New("failed to assert the new object") } result := reflect.DeepEqual(o.Spec.Template, n.Spec.Template) if result { return false, nil } o.Spec = n.Spec return true, 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 *appsv1.Deployment var err error if c.GenDeploymentFunc != nil { s, err = c.GenDeploymentFunc(c) } else { s, err = GenerateDeployment(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 *appsv1.Deployment var err error if c.GenDeploymentFunc != nil { s, err = c.GenDeploymentFunc(c) } else { s, err = GenerateDeployment(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: &appsv1.Deployment{}, 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 *appsv1.Deployment var err error if c.GenDeploymentFunc != nil { s, err = c.GenDeploymentFunc(c) } else { s, err = GenerateDeployment(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: &appsv1.Deployment{}, 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: &appsv1.Deployment{ObjectMeta: *om}, AfterDeleteFunc: c.AfterDeleteFunc, }) if err != nil { return result, errors.Wrap(err, "failed to delete secret") } return result, nil }