func (r *ReconcileCertificateRequest) finalizeCertificateRequest(reqLogger logr.Logger, cr *certmanv1alpha1.CertificateRequest) (reconcile.Result, error) {
	if utils.ContainsString(cr.ObjectMeta.Finalizers, certmanv1alpha1.CertmanOperatorFinalizerLabel) {
		reqLogger.Info("revoking certificate and deleting secret")
		if err := r.revokeCertificateAndDeleteSecret(reqLogger, cr); err != nil {
			reqLogger.Error(err, err.Error())
			return reconcile.Result{}, err
		}
		reqLogger.Info("removing finalizers")
		baseToPatch := client.MergeFrom(cr.DeepCopy())
		cr.ObjectMeta.Finalizers = utils.RemoveString(cr.ObjectMeta.Finalizers, certmanv1alpha1.CertmanOperatorFinalizerLabel)
		if err := r.client.Patch(context.TODO(), cr, baseToPatch); err != nil {
			reqLogger.Error(err, err.Error())
			return reconcile.Result{}, err
		}
	}
	localmetrics.DecrementCertRequestsCounter()
	reqLogger.Info("certificaterequest has been deleted")
	return reconcile.Result{}, nil
}
Helper function for Reconcile handles CertificateRequests with a deletion timestamp by
revoking the certificate and removing the finalizer if it exists.
package certificaterequest
import (
	"context"
	gerrors "errors"
	"fmt"
	"strings"
	"github.com/go-logr/logr"
	hivev1 "github.com/openshift/hive/pkg/apis/hive/v1"
	"github.com/prometheus/client_golang/prometheus"
	corev1 "k8s.io/api/core/v1"
	"k8s.io/apimachinery/pkg/api/errors"
	metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
	"k8s.io/apimachinery/pkg/runtime"
	"k8s.io/apimachinery/pkg/types"
	"sigs.k8s.io/controller-runtime/pkg/client"
	"sigs.k8s.io/controller-runtime/pkg/controller"
	"sigs.k8s.io/controller-runtime/pkg/controller/controllerutil"
	"sigs.k8s.io/controller-runtime/pkg/handler"
	logf "sigs.k8s.io/controller-runtime/pkg/log"
	"sigs.k8s.io/controller-runtime/pkg/manager"
	"sigs.k8s.io/controller-runtime/pkg/reconcile"
	"sigs.k8s.io/controller-runtime/pkg/source"
	certmanv1alpha1 "github.com/openshift/certman-operator/pkg/apis/certman/v1alpha1"
	cClient "github.com/openshift/certman-operator/pkg/clients"
	"github.com/openshift/certman-operator/pkg/controller/utils"
	"github.com/openshift/certman-operator/pkg/localmetrics"
)
const (
	controllerName                        = "controller_certificaterequest"
	maxConcurrentReconciles               = 10
	hiveRelocationAnnotation              = "hive.openshift.io/relocate"
	hiveRelocationOutgoingValue           = "outgoing"
	hiveRelocationCertificateRequstStatus = "Not reconciling: ClusterDeployment is relocating"
	certRequestSuffix                     = "-primary-cert-bundle"
)
var log = logf.Log.WithName(controllerName)
func Add(mgr manager.Manager) error {
	return add(mgr, newReconciler(mgr))
}
func newReconciler(mgr manager.Manager) reconcile.Reconciler {
	return &ReconcileCertificateRequest{
		client:        mgr.GetClient(),
		scheme:        mgr.GetScheme(),
		clientBuilder: cClient.NewClient,
	}
}
func add(mgr manager.Manager, r reconcile.Reconciler) error {
	o := controller.Options{
		Reconciler:              r,
		MaxConcurrentReconciles: maxConcurrentReconciles,
	}
	c, err := controller.New("certificaterequest-controller", mgr, o)
	if err != nil {
		return err
	}
	err = c.Watch(&source.Kind{Type: &certmanv1alpha1.CertificateRequest{}}, &handler.EnqueueRequestForObject{})
	if err != nil {
		return err
	}
	err = c.Watch(&source.Kind{Type: &corev1.Secret{}}, &handler.EnqueueRequestForOwner{
		IsController: true,
		OwnerType:    &certmanv1alpha1.CertificateRequest{},
	})
	if err != nil {
		return err
	}
	return nil
}
var _ reconcile.Reconciler = &ReconcileCertificateRequest{}
type ReconcileCertificateRequest struct {
	client        client.Client
	scheme        *runtime.Scheme
	clientBuilder func(reqLogger logr.Logger, kubeClient client.Client, platfromSecret certmanv1alpha1.Platform, namespace string, clusterDeploymentName string) (cClient.Client, error)
}
func (r *ReconcileCertificateRequest) Reconcile(request reconcile.Request) (reconcile.Result, error) {
	reqLogger := log.WithValues("Request.Namespace", request.Namespace, "Request.Name", request.Name)
	reqLogger.Info("reconciling CertificateRequest")
	timer := prometheus.NewTimer(localmetrics.MetricCertificateRequestReconcileDuration)
	defer func() {
		reconcileDuration := timer.ObserveDuration()
		reqLogger.WithValues("Duration", reconcileDuration).Info("Reconcile complete.")
	}()
	localmetrics.CheckInitCounter(r.client)
	cr := &certmanv1alpha1.CertificateRequest{}
	err := r.client.Get(context.TODO(), request.NamespacedName, cr)
	if err != nil {
		if errors.IsNotFound(err) {
			return reconcile.Result{}, nil
		}
		reqLogger.Error(err, err.Error())
		return reconcile.Result{}, err
	}
	clusterDeploymentName := strings.Split(request.NamespacedName.Name, certRequestSuffix)[0]
	if clusterDeploymentName == "" {
		err = gerrors.New("ClusterDeployment not found")
		reqLogger.Error(err, "ClusterDeployment not found")
		return reconcile.Result{}, err
	}
	cd := &hivev1.ClusterDeployment{}
	err = r.client.Get(context.TODO(), types.NamespacedName{Namespace: request.Namespace, Name: clusterDeploymentName}, cd)
	if err != nil {
		reqLogger.Error(err, err.Error())
		return reconcile.Result{}, err
	}
	if len(cr.OwnerReferences) == 0 {
		baseToPatch := client.MergeFrom(cr.DeepCopy())
		missingOwnerReference := metav1.OwnerReference{
			APIVersion:         fmt.Sprintf("%s/%s", hivev1.HiveAPIGroup, hivev1.HiveAPIVersion),
			Kind:               "ClusterDeployment",
			Name:               cd.Name,
			UID:                cd.UID,
			Controller:         boolPointer(true),
			BlockOwnerDeletion: boolPointer(true),
		}
		cr.OwnerReferences = []metav1.OwnerReference{missingOwnerReference}
		reqLogger.WithValues("CertificateRequest.Name", cr.Name, "OwnerReference.Name", missingOwnerReference.Name).Info("adding OwnerReference to CertificateRequest")
		if err := r.client.Patch(context.TODO(), cr, baseToPatch); err != nil {
			reqLogger.Error(err, err.Error())
			return reconcile.Result{}, err
		}
	}
	relocating, err := relocationBailOut(r.client, types.NamespacedName{Namespace: request.Namespace, Name: cd.Name})
	if err != nil {
		if !errors.IsNotFound(err) {
			reqLogger.Error(err, err.Error())
			return reconcile.Result{}, err
		}
	}
	if relocating {
		reqLogger.Info("Not reconciling, clusterdeployment is relocating")
		cr.Status.Status = hiveRelocationCertificateRequstStatus
		err = r.client.Update(context.TODO(), cr)
		if err != nil {
			return reconcile.Result{}, err
		}
		return reconcile.Result{}, nil
	}
	if !cr.DeletionTimestamp.IsZero() {
		return r.finalizeCertificateRequest(reqLogger, cr)
	}
	if !utils.ContainsString(cr.ObjectMeta.Finalizers, certmanv1alpha1.CertmanOperatorFinalizerLabel) {
		reqLogger.Info("adding finalizer to the certificate request")
		localmetrics.IncrementCertRequestsCounter()
		baseToPatch := client.MergeFrom(cr.DeepCopy())
		cr.ObjectMeta.Finalizers = append(cr.ObjectMeta.Finalizers, certmanv1alpha1.CertmanOperatorFinalizerLabel)
		if err := r.client.Patch(context.TODO(), cr, baseToPatch); err != nil {
			reqLogger.Error(err, err.Error())
			return reconcile.Result{}, err
		}
	}
	found := &corev1.Secret{}
	err = r.client.Get(context.TODO(), types.NamespacedName{Name: cr.Spec.CertificateSecret.Name, Namespace: cr.Namespace}, found)
	if err != nil {
		if errors.IsNotFound(err) {
			reqLogger.Info("requesting new certificates as secret was not found")
			return r.createCertificateSecret(reqLogger, cr)
		}
		reqLogger.Error(err, err.Error())
		return reconcile.Result{}, err
	}
	reqLogger.Info("checking if certificates need to be reissued")
	shouldReissue, err := r.ShouldReissue(reqLogger, cr)
	if err != nil {
		reqLogger.Error(err, err.Error())
		return reconcile.Result{}, err
	}
	relocating, err = relocationBailOut(r.client, types.NamespacedName{Namespace: request.Namespace, Name: clusterDeploymentName})
	if err != nil {
		return reconcile.Result{}, err
	}
	if relocating {
		reqLogger.Info("Not reconciling, clusterdeployment is relocating")
		cr.Status.Status = hiveRelocationCertificateRequstStatus
		err = r.client.Update(context.TODO(), cr)
		if err != nil {
			return reconcile.Result{}, err
		}
		return reconcile.Result{}, nil
	}
	if shouldReissue {
		err := r.IssueCertificate(reqLogger, cr, found)
		if err != nil {
			return reconcile.Result{}, err
		}
		localmetrics.AddCertificateIssuance("renewal")
		err = r.client.Update(context.TODO(), found)
		if err != nil {
			return reconcile.Result{}, err
		}
		err = r.updateStatus(reqLogger, cr)
		if err != nil {
			reqLogger.Error(err, err.Error())
		}
		reqLogger.Info("certificate has been reissued.")
		return reconcile.Result{}, nil
	}
	err = r.updateStatus(reqLogger, cr)
	if err != nil {
		reqLogger.Error(err, err.Error())
	}
	return reconcile.Result{}, nil
}
func newSecret(cr *certmanv1alpha1.CertificateRequest) *corev1.Secret {
	return &corev1.Secret{
		Type: corev1.SecretTypeTLS,
		ObjectMeta: metav1.ObjectMeta{
			Name:      cr.Spec.CertificateSecret.Name,
			Namespace: cr.Namespace,
		},
	}
}
func (r *ReconcileCertificateRequest) getClient(reqLogger logr.Logger, cr *certmanv1alpha1.CertificateRequest) (cClient.Client, error) {
	clusterDeploymentName := ""
	for _, ownerRef := range cr.OwnerReferences {
		if ownerRef.Kind == "ClusterDeployment" {
			clusterDeploymentName = ownerRef.Name
		}
	}
	client, err := r.clientBuilder(reqLogger, r.client, cr.Spec.Platform, cr.Namespace, clusterDeploymentName)
	return client, err
}