From 9e0195e02439c0f13aa6cd94bbb9d76c16461d0e Mon Sep 17 00:00:00 2001 From: Andrew Keesler Date: Thu, 24 Sep 2020 16:54:20 -0400 Subject: [PATCH] kubecertagent: use initial event for when key can't be found This should fix integration tests running on clusters that don't have visible controller manager pods (e.g., GKE). Pinniped should boot, not find any controller manager pods, but still post a status in the CIC. I also updated a test helper so that we could tell the difference between when an event was not added and when an event was added with an empty key. Signed-off-by: Andrew Keesler --- .../controller/apicerts/certs_manager_test.go | 2 +- internal/controller/kubecertagent/creater.go | 5 ++++ .../controller/kubecertagent/creater_test.go | 25 +++++++++++++++++++ .../controllermanager/prepare_controllers.go | 1 + .../observable_with_initial_event_option.go | 7 +++--- 5 files changed, 36 insertions(+), 4 deletions(-) diff --git a/internal/controller/apicerts/certs_manager_test.go b/internal/controller/apicerts/certs_manager_test.go index f36268e54..f7e99bdd5 100644 --- a/internal/controller/apicerts/certs_manager_test.go +++ b/internal/controller/apicerts/certs_manager_test.go @@ -103,7 +103,7 @@ func TestManagerControllerOptions(t *testing.T) { when("starting up", func() { it("asks for an initial event because the Secret may not exist yet and it needs to run anyway", func() { - r.Equal(controllerlib.Key{ + r.Equal(&controllerlib.Key{ Namespace: installedInNamespace, Name: certsSecretResourceName, }, observableWithInitialEventOption.GetInitialEventKey()) diff --git a/internal/controller/kubecertagent/creater.go b/internal/controller/kubecertagent/creater.go index 8354d6fd4..229848ec7 100644 --- a/internal/controller/kubecertagent/creater.go +++ b/internal/controller/kubecertagent/creater.go @@ -44,6 +44,7 @@ func NewCreaterController( kubeSystemPodInformer corev1informers.PodInformer, agentPodInformer corev1informers.PodInformer, withInformer pinnipedcontroller.WithInformerOptionFunc, + withInitialEvent pinnipedcontroller.WithInitialEventOptionFunc, ) controllerlib.Controller { return controllerlib.New( controllerlib.Config{ @@ -69,6 +70,10 @@ func NewCreaterController( pinnipedcontroller.SimpleFilter(isAgentPod), controllerlib.InformerOption{}, ), + // Be sure to run once even to make sure the CIC is updated if there are no controller manager + // pods. We should be able to pass an empty key since we don't use the key in the sync (we sync + // the world). + withInitialEvent(controllerlib.Key{}), ) } diff --git a/internal/controller/kubecertagent/creater_test.go b/internal/controller/kubecertagent/creater_test.go index 430ac83a5..2953b1f4c 100644 --- a/internal/controller/kubecertagent/creater_test.go +++ b/internal/controller/kubecertagent/creater_test.go @@ -48,11 +48,35 @@ func TestCreaterControllerFilter(t *testing.T) { kubeSystemPodInformer, agentPodInformer, observableWithInformerOption.WithInformer, + controllerlib.WithInitialEvent, ) }, ) } +func TestCreaterControllerInitialEvent(t *testing.T) { + kubeSystemInformerClient := kubernetesfake.NewSimpleClientset() + kubeSystemInformers := kubeinformers.NewSharedInformerFactory(kubeSystemInformerClient, 0) + + agentInformerClient := kubernetesfake.NewSimpleClientset() + agentInformers := kubeinformers.NewSharedInformerFactory(agentInformerClient, 0) + + observableWithInitialEventOption := testutil.NewObservableWithInitialEventOption() + + _ = NewCreaterController( + nil, // agentPodConfig, shouldn't matter + nil, // credentialIssuerConfigLocationConfig, shouldn't matter + nil, // clock, shound't matter + nil, // k8sClient, shouldn't matter + nil, // pinnipedAPIClient, shouldn't matter + kubeSystemInformers.Core().V1().Pods(), + agentInformers.Core().V1().Pods(), + controllerlib.WithInformer, + observableWithInitialEventOption.WithInitialEvent, + ) + require.Equal(t, &controllerlib.Key{}, observableWithInitialEventOption.GetInitialEventKey()) +} + func TestCreaterControllerSync(t *testing.T) { spec.Run(t, "CreaterControllerSync", func(t *testing.T, when spec.G, it spec.S) { const kubeSystemNamespace = "kube-system" @@ -98,6 +122,7 @@ func TestCreaterControllerSync(t *testing.T) { kubeSystemInformers.Core().V1().Pods(), agentInformers.Core().V1().Pods(), controllerlib.WithInformer, + controllerlib.WithInitialEvent, ) // Set this at the last second to support calling subject.Name(). diff --git a/internal/controllermanager/prepare_controllers.go b/internal/controllermanager/prepare_controllers.go index 41f22ce70..88296f3d0 100644 --- a/internal/controllermanager/prepare_controllers.go +++ b/internal/controllermanager/prepare_controllers.go @@ -180,6 +180,7 @@ func PrepareControllers(c *Config) (func(ctx context.Context), error) { informers.kubeSystemNamespaceK8s.Core().V1().Pods(), informers.installationNamespaceK8s.Core().V1().Pods(), controllerlib.WithInformer, + controllerlib.WithInitialEvent, ), singletonWorker, ). diff --git a/internal/testutil/observable_with_initial_event_option.go b/internal/testutil/observable_with_initial_event_option.go index 8cfb1e4d0..091390c39 100644 --- a/internal/testutil/observable_with_initial_event_option.go +++ b/internal/testutil/observable_with_initial_event_option.go @@ -6,7 +6,7 @@ package testutil import "go.pinniped.dev/internal/controllerlib" type ObservableWithInitialEventOption struct { - key controllerlib.Key + key *controllerlib.Key } func NewObservableWithInitialEventOption() *ObservableWithInitialEventOption { @@ -14,10 +14,11 @@ func NewObservableWithInitialEventOption() *ObservableWithInitialEventOption { } func (i *ObservableWithInitialEventOption) WithInitialEvent(key controllerlib.Key) controllerlib.Option { - i.key = key + i.key = new(controllerlib.Key) + *i.key = key return controllerlib.WithInitialEvent(key) } -func (i *ObservableWithInitialEventOption) GetInitialEventKey() controllerlib.Key { +func (i *ObservableWithInitialEventOption) GetInitialEventKey() *controllerlib.Key { return i.key }