diff --git a/VERSION b/VERSION index a49dff9..bb86fac 100644 --- a/VERSION +++ b/VERSION @@ -1 +1 @@ -v0.1.14-dev \ No newline at end of file +v0.1.15 \ No newline at end of file diff --git a/charts/control-plane-operator/Chart.yaml b/charts/control-plane-operator/Chart.yaml index 194c185..e346fb6 100644 --- a/charts/control-plane-operator/Chart.yaml +++ b/charts/control-plane-operator/Chart.yaml @@ -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 diff --git a/charts/control-plane-operator/templates/deployment.yaml b/charts/control-plane-operator/templates/deployment.yaml index aeb883d..9619360 100644 --- a/charts/control-plane-operator/templates/deployment.yaml +++ b/charts/control-plane-operator/templates/deployment.yaml @@ -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 diff --git a/charts/control-plane-operator/values.yaml b/charts/control-plane-operator/values.yaml index ae56f34..efc4402 100644 --- a/charts/control-plane-operator/values.yaml +++ b/charts/control-plane-operator/values.yaml @@ -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 diff --git a/charts/control-plane-operator/values.yaml.tpl b/charts/control-plane-operator/values.yaml.tpl index 2cc0c89..5f60adc 100644 --- a/charts/control-plane-operator/values.yaml.tpl +++ b/charts/control-plane-operator/values.yaml.tpl @@ -14,6 +14,7 @@ imagePullSecrets: [] nameOverride: "" fullnameOverride: "" syncPeriod: 1m +fluxTokenLifetime: 1h serviceAccount: # Specifies whether a service account should be created diff --git a/cmd/control-plane-operator/main.go b/cmd/control-plane-operator/main.go index 74cef1f..e6a9a43 100644 --- a/cmd/control-plane-operator/main.go +++ b/cmd/control-plane-operator/main.go @@ -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 @@ -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, @@ -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) diff --git a/internal/controller/controlplane_controller.go b/internal/controller/controlplane_controller.go index 13dc840..b76f852 100644 --- a/internal/controller/controlplane_controller.go +++ b/internal/controller/controlplane_controller.go @@ -59,8 +59,7 @@ import ( ) const ( - requeueAfter = 1 * time.Minute - requeueAfterError = 5 * time.Second + requeueAfterError = 10 * time.Second cpNamespacePrefix = "cp-" cpNamespaceMaxLen = 63 @@ -92,6 +91,7 @@ type ControlPlaneReconciler struct { FluxSecretResolver secretresolver.SecretResolver WebhookMiddleware types.NamespacedName ReconcilePeriod time.Duration + FluxTokenLifetime time.Duration RemoteConfigBuilder RemoteConfigBuilder EmbeddedCRDs embed.FS } diff --git a/internal/controller/controlplane_controller_test.go b/internal/controller/controlplane_controller_test.go index fdc4d80..da0423e 100644 --- a/internal/controller/controlplane_controller_test.go +++ b/internal/controller/controlplane_controller_test.go @@ -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, }, { @@ -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), diff --git a/internal/controller/kubeconfigs.go b/internal/controller/kubeconfigs.go index ffe7838..a5d970e 100644 --- a/internal/controller/kubeconfigs.go +++ b/internal/controller/kubeconfigs.go @@ -2,7 +2,6 @@ package controller import ( "context" - "errors" "time" corev1 "k8s.io/api/core/v1" @@ -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, @@ -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 } diff --git a/internal/controller/secret_controller.go b/internal/controller/secret_controller.go index 4cd2caa..587a774 100644 --- a/internal/controller/secret_controller.go +++ b/internal/controller/secret_controller.go @@ -4,6 +4,7 @@ import ( "context" "errors" "strings" + "time" "github.com/openmcp-project/control-plane-operator/pkg/constants" @@ -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 @@ -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 { diff --git a/internal/controller/secret_controller_test.go b/internal/controller/secret_controller_test.go index 6babcd0..8c3e664 100644 --- a/internal/controller/secret_controller_test.go +++ b/internal/controller/secret_controller_test.go @@ -4,6 +4,7 @@ import ( "context" "errors" "testing" + "time" "github.com/stretchr/testify/assert" corev1 "k8s.io/api/core/v1" @@ -152,7 +153,7 @@ func Test_SecretReconciler_Reconcile(t *testing.T) { return nil }, expectedResult: ctrl.Result{ - RequeueAfter: requeueAfter, + RequeueAfter: time.Minute, }, }, { @@ -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)