cloudfoundry/cf-k8s-controllers

View on GitHub
kpack-image-builder/controllers/kpack_build_controller.go

Summary

Maintainability
A
0 mins
Test Coverage
package controllers

import (
    "context"
    "strings"

    "code.cloudfoundry.org/korifi/tools/image"
    "code.cloudfoundry.org/korifi/tools/k8s"
    "github.com/go-logr/logr"
    kpackv1alpha2 "github.com/pivotal/kpack/pkg/apis/build/v1alpha2"
    metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
    ctrl "sigs.k8s.io/controller-runtime"
    "sigs.k8s.io/controller-runtime/pkg/client"
    "sigs.k8s.io/controller-runtime/pkg/controller/controllerutil"
    "sigs.k8s.io/controller-runtime/pkg/manager"
    "sigs.k8s.io/controller-runtime/pkg/predicate"
)

const KpackBuildFinalizer string = "korifi.cloudfoundry.org/kpackBuild"

//counterfeiter:generate -o fake -fake-name ImageDeleter . ImageDeleter

type ImageDeleter interface {
    Delete(context.Context, image.Creds, string, ...string) error
}

type KpackBuildController struct {
    log                    logr.Logger
    k8sClient              client.Client
    imageDeleter           ImageDeleter
    registryServiceAccount string
}

func NewKpackBuildController(
    k8sClient client.Client,
    log logr.Logger,
    imageDeleter ImageDeleter,
    registryServiceAccount string,
) *k8s.PatchingReconciler[kpackv1alpha2.Build, *kpackv1alpha2.Build] {
    return k8s.NewPatchingReconciler[kpackv1alpha2.Build, *kpackv1alpha2.Build](log, k8sClient, KpackBuildController{
        log:                    log,
        k8sClient:              k8sClient,
        imageDeleter:           imageDeleter,
        registryServiceAccount: registryServiceAccount,
    })
}

func (c KpackBuildController) SetupWithManager(mgr manager.Manager) *ctrl.Builder {
    // ignoring error as this construction is not dynamic
    labelSelector, _ := predicate.LabelSelectorPredicate(metav1.LabelSelector{
        MatchExpressions: []metav1.LabelSelectorRequirement{
            {
                Key:      BuildWorkloadLabelKey,
                Operator: metav1.LabelSelectorOpExists,
                Values:   []string{},
            },
        },
    })

    return ctrl.NewControllerManagedBy(mgr).
        For(&kpackv1alpha2.Build{}).
        WithEventFilter(labelSelector)
}

//+kubebuilder:rbac:groups=kpack.io,resources=builds,verbs=get;list;watch;patch
//+kubebuilder:rbac:groups=kpack.io,resources=builds/status,verbs=get;patch
//+kubebuilder:rbac:groups=kpack.io,resources=builds/finalizers,verbs=get;patch

func (c KpackBuildController) ReconcileResource(ctx context.Context, kpackBuild *kpackv1alpha2.Build) (ctrl.Result, error) {
    log := logr.FromContextOrDiscard(ctx)

    if !kpackBuild.GetDeletionTimestamp().IsZero() {
        if !controllerutil.ContainsFinalizer(kpackBuild, KpackBuildFinalizer) {
            return ctrl.Result{}, nil
        }

        if kpackBuild.Status.LatestImage != "" {
            tagsToDelete := []string{}
            for _, t := range kpackBuild.Spec.Tags {
                parts := strings.Split(t, ":")
                if len(parts) == 2 {
                    tagsToDelete = append(tagsToDelete, parts[1])
                }
            }

            err := c.imageDeleter.Delete(ctx, image.Creds{
                Namespace:          kpackBuild.Namespace,
                ServiceAccountName: c.registryServiceAccount,
            }, kpackBuild.Status.LatestImage, tagsToDelete...)
            if err != nil {
                log.Info("failed to delete droplet image", "reason", err)
            }
        }

        if controllerutil.RemoveFinalizer(kpackBuild, KpackBuildFinalizer) {
            log.V(1).Info("finalizer removed")
        }

        return ctrl.Result{}, nil
    }

    return ctrl.Result{}, nil
}