ContainerImage.Pinniped/internal/controller/issuerconfig/update_strategy.go
Matt Moyer 657488fe90
Create CredentialIssuer at install, not runtime.
Previously, our controllers would automatically create a CredentialIssuer with a singleton name. The helpers we had for this also used "raw" client access and did not take advantage of the informer cache pattern.

With this change, the CredentialIssuer is always created at install time in the ytt YAML. The controllers now only update the existing CredentialIssuer status, and they do so using the informer cache as much as possible.

This change is targeted at only the kubecertagent controller to start. The impersonatorconfig controller will be updated in a following PR along with other changes.

Signed-off-by: Matt Moyer <moyerm@vmware.com>
2021-05-19 17:15:25 -05:00

94 lines
3.3 KiB
Go

// Copyright 2021 the Pinniped contributors. All Rights Reserved.
// SPDX-License-Identifier: Apache-2.0
package issuerconfig
import (
"context"
"fmt"
"sort"
apiequality "k8s.io/apimachinery/pkg/api/equality"
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
"go.pinniped.dev/generated/latest/apis/concierge/config/v1alpha1"
"go.pinniped.dev/generated/latest/client/concierge/clientset/versioned"
)
// UpdateStrategy creates or updates the desired strategy in the CredentialIssuer status.strategies field.
// The CredentialIssuer will be created if it does not already exist.
func UpdateStrategy(ctx context.Context,
name string,
credentialIssuerLabels map[string]string,
pinnipedAPIClient versioned.Interface,
strategy v1alpha1.CredentialIssuerStrategy,
) error {
return CreateOrUpdateCredentialIssuerStatus(
ctx,
name,
credentialIssuerLabels,
pinnipedAPIClient,
func(configToUpdate *v1alpha1.CredentialIssuerStatus) { mergeStrategy(configToUpdate, strategy) },
)
}
// Update a strategy on an existing CredentialIssuer, merging into any existing strategy entries.
func Update(ctx context.Context, client versioned.Interface, issuer *v1alpha1.CredentialIssuer, strategy v1alpha1.CredentialIssuerStrategy) error {
// Update the existing object to merge in the new strategy.
updated := issuer.DeepCopy()
mergeStrategy(&updated.Status, strategy)
// If the status has not changed, we're done.
if apiequality.Semantic.DeepEqual(issuer.Status, updated.Status) {
return nil
}
if _, err := client.ConfigV1alpha1().CredentialIssuers().UpdateStatus(ctx, updated, metav1.UpdateOptions{}); err != nil {
return fmt.Errorf("failed to update CredentialIssuer status: %w", err)
}
return nil
}
func mergeStrategy(configToUpdate *v1alpha1.CredentialIssuerStatus, strategy v1alpha1.CredentialIssuerStrategy) {
var existing *v1alpha1.CredentialIssuerStrategy
for i := range configToUpdate.Strategies {
if configToUpdate.Strategies[i].Type == strategy.Type {
existing = &configToUpdate.Strategies[i]
break
}
}
if existing != nil {
strategy.DeepCopyInto(existing)
} else {
configToUpdate.Strategies = append(configToUpdate.Strategies, strategy)
}
sort.Stable(sortableStrategies(configToUpdate.Strategies))
// Special case: the "TokenCredentialRequestAPI" data is mirrored into the deprecated status.kubeConfigInfo field.
if strategy.Frontend != nil && strategy.Frontend.Type == v1alpha1.TokenCredentialRequestAPIFrontendType {
configToUpdate.KubeConfigInfo = &v1alpha1.CredentialIssuerKubeConfigInfo{
Server: strategy.Frontend.TokenCredentialRequestAPIInfo.Server,
CertificateAuthorityData: strategy.Frontend.TokenCredentialRequestAPIInfo.CertificateAuthorityData,
}
}
}
// weights are a set of priorities for each strategy type.
//nolint: gochecknoglobals
var weights = map[v1alpha1.StrategyType]int{
v1alpha1.KubeClusterSigningCertificateStrategyType: 2, // most preferred strategy
v1alpha1.ImpersonationProxyStrategyType: 1,
// unknown strategy types will have weight 0 by default
}
type sortableStrategies []v1alpha1.CredentialIssuerStrategy
func (s sortableStrategies) Len() int { return len(s) }
func (s sortableStrategies) Less(i, j int) bool {
if wi, wj := weights[s[i].Type], weights[s[j].Type]; wi != wj {
return wi > wj
}
return s[i].Type < s[j].Type
}
func (s sortableStrategies) Swap(i, j int) { s[i], s[j] = s[j], s[i] }