Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion VERSION
Original file line number Diff line number Diff line change
@@ -1 +1 @@
v0.1.14-dev
v0.1.15
4 changes: 2 additions & 2 deletions charts/control-plane-operator/Chart.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -2,8 +2,8 @@ apiVersion: v2
name: control-plane-operator
description: A Helm chart for the Cloud Orchestration Control Plane Operator
type: application
version: v0.1.14
appVersion: v0.1.14
version: v0.1.15
appVersion: v0.1.15
home: https://github.com/openmcp-project/control-plane-operator
sources:
- https://github.com/openmcp-project/control-plane-operator
3 changes: 3 additions & 0 deletions charts/control-plane-operator/templates/deployment.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -125,6 +125,9 @@ spec:
{{ if .Values.syncPeriod }}
- "--sync-period={{ .Values.syncPeriod }}"
{{ end }}
{{ if .Values.fluxTokenLifetime }}
- "--flux-token-lifetime={{ .Values.fluxTokenLifetime }}"
{{ end }}
ports:
{{- if .Values.webhooks.listen }}
- name: webhooks-https
Expand Down
3 changes: 2 additions & 1 deletion charts/control-plane-operator/values.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -8,12 +8,13 @@ image:
repository: ghcr.io/openmcp-project/images/control-plane-operator
pullPolicy: IfNotPresent
# Overrides the image tag whose default is the chart appVersion.
tag: v0.1.14
tag: v0.1.15

imagePullSecrets: []
nameOverride: ""
fullnameOverride: ""
syncPeriod: 1m
fluxTokenLifetime: 1h

serviceAccount:
# Specifies whether a service account should be created
Expand Down
1 change: 1 addition & 0 deletions charts/control-plane-operator/values.yaml.tpl
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,7 @@ imagePullSecrets: []
nameOverride: ""
fullnameOverride: ""
syncPeriod: 1m
fluxTokenLifetime: 1h

serviceAccount:
# Specifies whether a service account should be created
Expand Down
14 changes: 12 additions & 2 deletions cmd/control-plane-operator/main.go
Original file line number Diff line number Diff line change
Expand Up @@ -109,6 +109,8 @@ func main() {

var syncPeriod string
flag.StringVar(&syncPeriod, "sync-period", "1m", "The period at which the controller will sync the resources.")
var fluxTokenLifetimeStr string
flag.StringVar(&fluxTokenLifetimeStr, "flux-token-lifetime", "1h", "The desired lifetime of the flux service account token used to access the MCP.")

// component flags
var webhookMiddlewareName string
Expand Down Expand Up @@ -178,11 +180,18 @@ func main() {
}
setupLog.Info("sync period set to", "syncPeriod", reconcilePeriod)

fluxTokenLifetime, errFluxTokenLifetime := time.ParseDuration(fluxTokenLifetimeStr)
if errFluxTokenLifetime != nil {
fluxTokenLifetime = 1 * time.Hour
}
setupLog.Info("flux token lifetime set to", "fluxTokenLifetime", fluxTokenLifetime)

if err = (&controller.ControlPlaneReconciler{
Client: mgr.GetClient(),
Scheme: mgr.GetScheme(),
Kubeconfiggen: &kubeconfiggen.Default{},
FluxSecretResolver: fluxSecretResolver,
FluxTokenLifetime: fluxTokenLifetime,
WebhookMiddleware: types.NamespacedName{
Namespace: webhookMiddlewareNamespace,
Name: webhookMiddlewareName,
Expand All @@ -196,8 +205,9 @@ func main() {
os.Exit(1)
}
if err = (&controller.SecretReconciler{
Client: mgr.GetClient(),
Scheme: mgr.GetScheme(),
Client: mgr.GetClient(),
Scheme: mgr.GetScheme(),
ReconcilePeriod: reconcilePeriod,
}).SetupWithManager(mgr); err != nil {
setupLog.Error(err, "unable to create controller", "controller", "Secret")
os.Exit(1)
Expand Down
4 changes: 2 additions & 2 deletions internal/controller/controlplane_controller.go
Original file line number Diff line number Diff line change
Expand Up @@ -59,8 +59,7 @@ import (
)

const (
requeueAfter = 1 * time.Minute
requeueAfterError = 5 * time.Second
requeueAfterError = 10 * time.Second

cpNamespacePrefix = "cp-"
cpNamespaceMaxLen = 63
Expand Down Expand Up @@ -92,6 +91,7 @@ type ControlPlaneReconciler struct {
FluxSecretResolver secretresolver.SecretResolver
WebhookMiddleware types.NamespacedName
ReconcilePeriod time.Duration
FluxTokenLifetime time.Duration
RemoteConfigBuilder RemoteConfigBuilder
EmbeddedCRDs embed.FS
}
Expand Down
3 changes: 2 additions & 1 deletion internal/controller/controlplane_controller_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -288,7 +288,7 @@ func TestControlPlaneReconciler_Reconcile(t *testing.T) {
assert.Equal(t, "Uninstalled", cond.Reason)
return nil
},
expectedResult: ctrl.Result{RequeueAfter: 5 * time.Second},
expectedResult: ctrl.Result{RequeueAfter: requeueAfterError},
expectedErr: nil,
},
{
Expand Down Expand Up @@ -352,6 +352,7 @@ func TestControlPlaneReconciler_Reconcile(t *testing.T) {
Scheme: c.Scheme(),
Kubeconfiggen: &kubeconfiggen.Default{},
FluxSecretResolver: testSecretResolver,
FluxTokenLifetime: 1 * time.Hour,
WebhookMiddleware: types.NamespacedName{},
ReconcilePeriod: time.Second * 30,
Recorder: record.NewFakeRecorder(100),
Expand Down
17 changes: 3 additions & 14 deletions internal/controller/kubeconfigs.go
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,6 @@ package controller

import (
"context"
"errors"
"time"

corev1 "k8s.io/api/core/v1"
Expand All @@ -19,20 +18,9 @@ import (
const (
keyKubeconfig = "kubeconfig"
keyExpiration = "expiresAt"

kubeconfigExpiration = 10 * time.Minute
kubeconfigBuffer = 3 * requeueAfter
)

var (
errInvalidExpirationOrBuffer = errors.New("desired expiration and buffer are incompatible. make sure that desired expiration is greater than the buffer")
)

func (r *ControlPlaneReconciler) ensureKubeconfig(ctx context.Context, remoteCfg *rest.Config, namespace string, secretName string, svcaccountRef corev1beta1.ServiceAccountReference) (*corev1.SecretReference, error) {
if kubeconfigBuffer >= kubeconfigExpiration {
return nil, errInvalidExpirationOrBuffer
}

secret := &corev1.Secret{
ObjectMeta: metav1.ObjectMeta{
Name: secretName,
Expand All @@ -53,13 +41,14 @@ func (r *ControlPlaneReconciler) ensureKubeconfig(ctx context.Context, remoteCfg
return nil, err
}

if time.Now().Before(expiration.Add(-kubeconfigBuffer)) {
// check if token would expire before next planned reconciliation
if time.Now().Before(expiration.Add(-r.ReconcilePeriod)) {
// kubeconfig is still valid
return &corev1.SecretReference{Name: secret.Name, Namespace: secret.Namespace}, nil
}
}

kubeconfig, expiration, err := r.Kubeconfiggen.ForServiceAccount(ctx, remoteCfg, svcaccountRef, kubeconfigExpiration)
kubeconfig, expiration, err := r.Kubeconfiggen.ForServiceAccount(ctx, remoteCfg, svcaccountRef, r.FluxTokenLifetime)
if err != nil {
return nil, err
}
Expand Down
6 changes: 4 additions & 2 deletions internal/controller/secret_controller.go
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@ import (
"context"
"errors"
"strings"
"time"

"github.com/openmcp-project/control-plane-operator/pkg/constants"

Expand Down Expand Up @@ -33,7 +34,8 @@ var (
// SecretReconciler reconciles a Secret object
type SecretReconciler struct {
client.Client
Scheme *runtime.Scheme
Scheme *runtime.Scheme
ReconcilePeriod time.Duration
}

// Reconcile is part of the main kubernetes reconciliation loop which aims to
Expand Down Expand Up @@ -136,7 +138,7 @@ func (r *SecretReconciler) handleSync(ctx context.Context, secret *corev1.Secret
}
}

return ctrl.Result{RequeueAfter: requeueAfter}, nil
return ctrl.Result{RequeueAfter: r.ReconcilePeriod}, nil
}

func (r *SecretReconciler) shouldReconcile(o client.Object) bool {
Expand Down
8 changes: 5 additions & 3 deletions internal/controller/secret_controller_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@ import (
"context"
"errors"
"testing"
"time"

"github.com/stretchr/testify/assert"
corev1 "k8s.io/api/core/v1"
Expand Down Expand Up @@ -152,7 +153,7 @@ func Test_SecretReconciler_Reconcile(t *testing.T) {
return nil
},
expectedResult: ctrl.Result{
RequeueAfter: requeueAfter,
RequeueAfter: time.Minute,
},
},
{
Expand Down Expand Up @@ -212,8 +213,9 @@ func Test_SecretReconciler_Reconcile(t *testing.T) {
req := newRequest(tC.initObjs[0])

sr := &SecretReconciler{
Client: c,
Scheme: c.Scheme(),
Client: c,
Scheme: c.Scheme(),
ReconcilePeriod: time.Minute,
}
result, err := sr.Reconcile(ctx, req)

Expand Down
Loading