Skip to content

Commit

Permalink
refactor: move writeKMProviderStatus to controller
Browse files Browse the repository at this point in the history
  • Loading branch information
duffney committed Sep 4, 2024
1 parent 7519519 commit bf50d5c
Show file tree
Hide file tree
Showing 14 changed files with 1,478 additions and 1,160 deletions.
121 changes: 114 additions & 7 deletions pkg/controllers/clusterresource/keymanagementprovider_controller.go
Original file line number Diff line number Diff line change
Expand Up @@ -18,11 +18,18 @@ package clusterresource

import (
"context"
"encoding/json"
"fmt"

"github.com/ratify-project/ratify/internal/constants"
cutils "github.com/ratify-project/ratify/pkg/controllers/utils"
kmp "github.com/ratify-project/ratify/pkg/keymanagementprovider"
_ "github.com/ratify-project/ratify/pkg/keymanagementprovider/azurekeyvault" // register azure key vault key management provider
_ "github.com/ratify-project/ratify/pkg/keymanagementprovider/inline" // register inline key management provider
"github.com/ratify-project/ratify/pkg/keymanagementprovider/refresh"
"github.com/sirupsen/logrus"
apierrors "k8s.io/apimachinery/pkg/api/errors"
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
"k8s.io/apimachinery/pkg/runtime"
ctrl "sigs.k8s.io/controller-runtime"
"sigs.k8s.io/controller-runtime/pkg/client"
Expand All @@ -37,33 +44,91 @@ type KeyManagementProviderReconciler struct {
Scheme *runtime.Scheme
}

func (r *KeyManagementProviderReconciler) ReconcileWithConfig(ctx context.Context, config map[string]interface{}) (ctrl.Result, error) {
func (r *KeyManagementProviderReconciler) ReconcileWithType(ctx context.Context, req ctrl.Request, refresherType string) (ctrl.Result, error) {
logger := logrus.WithContext(ctx)

var keyManagementProvider configv1beta1.KeyManagementProvider

resource := req.Name

logger.Infof("reconciling cluster key management provider '%v'", resource)

if err := r.Get(ctx, req.NamespacedName, &keyManagementProvider); err != nil {
if apierrors.IsNotFound(err) {
logger.Infof("deletion detected, removing key management provider %v", resource)
kmp.DeleteResourceFromMap(resource)
} else {
logger.Error(err, "unable to fetch key management provider")
}

return ctrl.Result{}, client.IgnoreNotFound(err)
}

lastFetchedTime := metav1.Now()

// get certificate store list to check if certificate store is configured
// TODO: remove check in v2.0.0+
var certificateStoreList configv1beta1.CertificateStoreList
if err := r.List(ctx, &certificateStoreList); err != nil {
logger.Error(err, "unable to list certificate stores")
return ctrl.Result{}, err
}

if len(certificateStoreList.Items) > 0 {
// Note: for backwards compatibility in upgrade scenarios, Ratify will only log a warning statement.
logger.Warn("Certificate Store already exists. Key management provider and certificate store should not be configured together. Please migrate to key management provider and delete certificate store.")
}

provider, err := cutils.SpecToKeyManagementProvider(keyManagementProvider.Spec.Parameters.Raw, keyManagementProvider.Spec.Type)
if err != nil {
kmp.SetCertificateError(resource, err)
kmp.SetKeyError(resource, err)
writeKMProviderStatus(ctx, r, &keyManagementProvider, logger, false, err.Error(), lastFetchedTime, nil)
return ctrl.Result{}, err
}

config := map[string]interface{}{
"refresherType": refresherType,
"provider": provider,
"providerType": keyManagementProvider.Spec.Type,
"providerRefreshInterval": keyManagementProvider.Spec.RefreshInterval,
"resource": resource,
}

refresher, err := refresh.CreateRefresherFromConfig(config)
if err != nil {
writeKMProviderStatus(ctx, r, &keyManagementProvider, logger, false, err.Error(), lastFetchedTime, nil)
return ctrl.Result{}, err
}

err = refresher.Refresh(ctx)
if err != nil {
writeKMProviderStatus(ctx, r, &keyManagementProvider, logger, false, err.Error(), lastFetchedTime, nil)
return ctrl.Result{}, err
}

result, ok := refresher.GetResult().(ctrl.Result)
if !ok {
writeKMProviderStatus(ctx, r, &keyManagementProvider, logger, false, "reconcile failed, unexpected result type returned by key management provider", lastFetchedTime, nil)
return ctrl.Result{}, fmt.Errorf("unexpected type returned from GetResult: %T", refresher.GetResult())
}

status, ok := refresher.GetStatus().(kmp.KeyManagementProviderStatus)
if !ok {
writeKMProviderStatus(ctx, r, &keyManagementProvider, logger, false, "reconcile failed, unexpected status type returned by key management provider", lastFetchedTime, nil)
return ctrl.Result{}, fmt.Errorf("unexpected type returned from GetStatus: %T", refresher.GetStatus())
}

writeKMProviderStatus(ctx, r, &keyManagementProvider, logger, true, "", lastFetchedTime, status)

return result, nil
}

// +kubebuilder:rbac:groups=config.ratify.deislabs.io,resources=keymanagementproviders,verbs=get;list;watch;create;update;patch;delete
// +kubebuilder:rbac:groups=config.ratify.deislabs.io,resources=keymanagementproviders/status,verbs=get;update;patch
// +kubebuilder:rbac:groups=config.ratify.deislabs.io,resources=keymanagementproviders/finalizers,verbs=update
func (r *KeyManagementProviderReconciler) Reconcile(ctx context.Context, req ctrl.Request) (ctrl.Result, error) {
refresherConfig := map[string]interface{}{
"type": refresh.KubeRefresherType,
"client": r.Client,
"request": req,
}
return r.ReconcileWithConfig(ctx, refresherConfig)
return r.ReconcileWithType(ctx, req, refresh.KubeRefresherType)
}

// SetupWithManager sets up the controller with the Manager.
Expand All @@ -77,3 +142,45 @@ func (r *KeyManagementProviderReconciler) SetupWithManager(mgr ctrl.Manager) err
For(&configv1beta1.KeyManagementProvider{}).WithEventFilter(pred).
Complete(r)
}

func writeKMProviderStatus(ctx context.Context, r client.StatusClient, keyManagementProvider *configv1beta1.KeyManagementProvider, logger *logrus.Entry, isSuccess bool, errorString string, operationTime metav1.Time, kmProviderStatus kmp.KeyManagementProviderStatus) {
if isSuccess {
updateKMProviderSuccessStatus(keyManagementProvider, &operationTime, kmProviderStatus)
} else {
updateKMProviderErrorStatus(keyManagementProvider, errorString, &operationTime)
}
if statusErr := r.Status().Update(ctx, keyManagementProvider); statusErr != nil {
logger.Error(statusErr, ",unable to update key management provider error status")
}
}

// updateKMProviderErrorStatus updates the key management provider status with error, brief error and last fetched time
func updateKMProviderErrorStatus(keyManagementProvider *configv1beta1.KeyManagementProvider, errorString string, operationTime *metav1.Time) {
// truncate brief error string to maxBriefErrLength
briefErr := errorString
if len(errorString) > constants.MaxBriefErrLength {
briefErr = fmt.Sprintf("%s...", errorString[:constants.MaxBriefErrLength])
}
keyManagementProvider.Status.IsSuccess = false
keyManagementProvider.Status.Error = errorString
keyManagementProvider.Status.BriefError = briefErr
keyManagementProvider.Status.LastFetchedTime = operationTime
}

// updateKMProviderSuccessStatus updates the key management provider status if status argument is non nil
// Success status includes last fetched time and other provider-specific properties
func updateKMProviderSuccessStatus(keyManagementProvider *configv1beta1.KeyManagementProvider, lastOperationTime *metav1.Time, kmProviderStatus kmp.KeyManagementProviderStatus) {
keyManagementProvider.Status.IsSuccess = true
keyManagementProvider.Status.Error = ""
keyManagementProvider.Status.BriefError = ""
keyManagementProvider.Status.LastFetchedTime = lastOperationTime

if kmProviderStatus != nil {
jsonString, _ := json.Marshal(kmProviderStatus)

raw := runtime.RawExtension{
Raw: jsonString,
}
keyManagementProvider.Status.Properties = raw
}
}
Loading

0 comments on commit bf50d5c

Please sign in to comment.