diff --git a/internal/k8s/secret_controller.go b/internal/k8s/secret_controller.go index 13a8bb3..1b57a14 100644 --- a/internal/k8s/secret_controller.go +++ b/internal/k8s/secret_controller.go @@ -50,6 +50,7 @@ type SecretController struct { config *configv1.Config secrets map[string][]*oidcv1.OIDCConfig restConf *rest.Config + manager manager.Manager k8sClient client.Client namespace string } @@ -63,10 +64,16 @@ func NewSecretController(cfg *configv1.Config) *SecretController { } } +// Name implements run.PreRunner +func (s *SecretController) Name() string { return "Secret controller" } + // PreRun saves the original configuration in PreRun phase because the // configuration is loaded from the file in the Config Validate phase. func (s *SecretController) PreRun() error { - var needWatchSecrets = false + var ( + needWatchSecrets = false + err error + ) // Check if there are any k8s secrets to watch for _, c := range s.config.Chains { @@ -118,30 +125,33 @@ func (s *SecretController) PreRun() error { } } + // Load the k8s configuration from in-cluster environment if s.restConf == nil { - conf, err := config.GetConfig() + s.restConf, err = config.GetConfig() if err != nil { return fmt.Errorf("%w: %w", ErrLoadingConfig, err) } - s.restConf = conf } - return nil -} + // The controller manager is encapsulated in the secret controller because we + // only need it to watch secrets and update the configuration. + //TODO: Add manager options, like metrics, healthz, leader election, etc. + s.manager, err = ctrl.NewManager(s.restConf, manager.Options{}) + s.k8sClient = s.manager.GetClient() + if err != nil { + return fmt.Errorf("error creating controller manager: %w", err) + } -func secretNamespacedName(secretRef *oidcv1.OIDCConfig_SecretReference, currentNamespace string) types.NamespacedName { - return types.NamespacedName{ - Namespace: currentNamespace, - Name: secretRef.GetName(), + if err = ctrl.NewControllerManagedBy(s.manager). + For(&corev1.Secret{}). + Complete(s); err != nil { + return fmt.Errorf("error creating secret controller:%w", err) } -} -// Name implements run.PreRunner -func (s *SecretController) Name() string { return "Secret controller" } + return nil +} // ServeContext starts the controller manager and watches secrets for updates. -// The controller manager is encapsulated in the secret controller because we -// only need it to watch secrets and update the configuration. func (s *SecretController) ServeContext(ctx context.Context) error { // If there are no secrets to watch, we can skip starting the controller manager if len(s.secrets) == 0 { @@ -149,26 +159,20 @@ func (s *SecretController) ServeContext(ctx context.Context) error { return nil } - //TODO: Add manager options, like metrics, healthz, leader election, etc. - mgr, err := ctrl.NewManager(s.restConf, manager.Options{}) - s.k8sClient = mgr.GetClient() - if err != nil { - return fmt.Errorf("error creating controller manager: %w", err) - } - - if err = ctrl.NewControllerManagedBy(mgr). - For(&corev1.Secret{}). - Complete(s); err != nil { - return fmt.Errorf("error creating secret controller:%w", err) - } - - if err = mgr.Start(ctx); err != nil { + if err := s.manager.Start(ctx); err != nil { return fmt.Errorf("error starting controller manager:%w", err) } return nil } +func secretNamespacedName(secretRef *oidcv1.OIDCConfig_SecretReference, currentNamespace string) types.NamespacedName { + return types.NamespacedName{ + Namespace: currentNamespace, + Name: secretRef.GetName(), + } +} + func (s *SecretController) Reconcile(ctx context.Context, req ctrl.Request) (ctrl.Result, error) { changedSecret := req.NamespacedName.String() diff --git a/internal/k8s/secret_controller_lifecycle_test.go b/internal/k8s/secret_controller_lifecycle_test.go index 2ec54bf..bbf0978 100644 --- a/internal/k8s/secret_controller_lifecycle_test.go +++ b/internal/k8s/secret_controller_lifecycle_test.go @@ -61,11 +61,13 @@ func TestController(t *testing.T) { require.NoError(t, err) }() - t.Run("controller ", func(t *testing.T) { + t.Run("controller is setup at preRun", func(t *testing.T) { require.Eventually(t, func() bool { return controller.k8sClient != nil - }, defaultWait, defaultTick, "Controller manager is not ready") + }, defaultWait, defaultTick, "Controller manager is not setup") + }) + t.Run("controller is ready", func(t *testing.T) { require.Eventually(t, func() bool { err := controller.k8sClient.Create(context.Background(), &corev1.Secret{ ObjectMeta: metav1.ObjectMeta{ diff --git a/internal/k8s/secret_controller_reconcile_test.go b/internal/k8s/secret_controller_reconcile_test.go index 34a5c5d..d285f74 100644 --- a/internal/k8s/secret_controller_reconcile_test.go +++ b/internal/k8s/secret_controller_reconcile_test.go @@ -57,7 +57,6 @@ func TestOIDCProcessWithKubernetesSecret(t *testing.T) { secrets := secretsForTest() kubeClient := fake.NewClientBuilder().WithLists(secrets).Build() controller := NewSecretController(originalConf) - controller.k8sClient = kubeClient controller.namespace = "default" // pre-run the controller @@ -65,6 +64,8 @@ func TestOIDCProcessWithKubernetesSecret(t *testing.T) { if tt.err != "" { require.EqualError(t, err, tt.err) } + // replace the k8s client with the fake client for testing + controller.k8sClient = kubeClient // reconcile the secrets for _, secret := range secrets.Items {