cloudfoundry/cf-k8s-controllers

View on GitHub
controllers/webhooks/workloads/apps/apprev.go

Summary

Maintainability
A
0 mins
Test Coverage
package apps

//+kubebuilder:webhook:path=/mutate-korifi-cloudfoundry-org-v1alpha1-cfapp-apprev,mutating=true,failurePolicy=fail,sideEffects=None,groups=korifi.cloudfoundry.org,resources=cfapps,verbs=update,versions=v1alpha1,name=mcfapprev.korifi.cloudfoundry.org,admissionReviewVersions={v1,v1beta1}

import (
    "context"
    "encoding/json"
    "net/http"
    "strconv"

    korifiv1alpha1 "code.cloudfoundry.org/korifi/controllers/api/v1alpha1"
    ctrl "sigs.k8s.io/controller-runtime"
    logf "sigs.k8s.io/controller-runtime/pkg/log"
    "sigs.k8s.io/controller-runtime/pkg/webhook/admission"
)

// AppRevWebhook does not implement the admission.Defaulter interface as we
// need to access both oldObject and (new)Object to determine the actual state
// change. So we use the lower-level admission.Handler interface
type AppRevWebhook struct {
    decoder admission.Decoder
}

var apprevlog = logf.Log.WithName("apprev-webhook")

func (r *AppRevWebhook) SetupWebhookWithManager(mgr ctrl.Manager) {
    mgr.GetWebhookServer().Register("/mutate-korifi-cloudfoundry-org-v1alpha1-cfapp-apprev", &admission.Webhook{
        Handler: r,
    })
    r.decoder = admission.NewDecoder(mgr.GetScheme())
}

func (r *AppRevWebhook) Handle(ctx context.Context, req admission.Request) admission.Response {
    var cfApp korifiv1alpha1.CFApp
    if err := r.decoder.Decode(req, &cfApp); err != nil {
        return admission.Errored(http.StatusBadRequest, err)
    }

    var oldCFApp korifiv1alpha1.CFApp
    if err := r.decoder.DecodeRaw(req.OldObject, &oldCFApp); err != nil {
        return admission.Errored(http.StatusBadRequest, err)
    }

    if cfApp.Spec.DesiredState == korifiv1alpha1.StoppedState && oldCFApp.Spec.DesiredState == korifiv1alpha1.StartedState {
        newAppRev := bumpAppRev(cfApp.Annotations[korifiv1alpha1.CFAppRevisionKey])
        cfApp.Annotations[korifiv1alpha1.CFAppRevisionKey] = newAppRev
        cfApp.Annotations[korifiv1alpha1.CFAppLastStopRevisionKey] = newAppRev
    }

    marshalled, err := json.Marshal(cfApp)
    if err != nil {
        return admission.Errored(http.StatusInternalServerError, err)
    }

    return admission.PatchResponseFromRaw(req.Object.Raw, marshalled)
}

func bumpAppRev(currentRevValue string) string {
    revValue, err := strconv.Atoi(currentRevValue)
    if err != nil || revValue < 0 {
        apprevlog.V(1).Info("setting-invalid-app-rev-to-zero", "app-rev", currentRevValue)
        return korifiv1alpha1.CFAppRevisionKeyDefault
    }

    return strconv.Itoa(revValue + 1)
}