In unit test, wait for obj from informer instead of resource version

In impersonator_config_test.go, instead of waiting for the resource
version to appear in the informers, wait for the actual object to
appear.

This is an attempt to resolve flaky failures that only happen in CI,
but it also cleans up the test a bit by avoiding inventing fake resource
version numbers all over the test.

Signed-off-by: Monis Khan <mok@vmware.com>
This commit is contained in:
Ryan Richard 2021-03-04 15:36:51 -08:00
parent 9eb97e2683
commit b102aa8991

View File

@ -15,6 +15,7 @@ import (
"io/ioutil" "io/ioutil"
"net" "net"
"net/http" "net/http"
"reflect"
"regexp" "regexp"
"strings" "strings"
"testing" "testing"
@ -25,21 +26,19 @@ import (
"github.com/stretchr/testify/assert" "github.com/stretchr/testify/assert"
"github.com/stretchr/testify/require" "github.com/stretchr/testify/require"
corev1 "k8s.io/api/core/v1" corev1 "k8s.io/api/core/v1"
k8serrors "k8s.io/apimachinery/pkg/api/errors"
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
"k8s.io/apimachinery/pkg/runtime" "k8s.io/apimachinery/pkg/runtime"
"k8s.io/apimachinery/pkg/runtime/schema" "k8s.io/apimachinery/pkg/runtime/schema"
"k8s.io/apimachinery/pkg/util/clock" "k8s.io/apimachinery/pkg/util/clock"
kubeinformers "k8s.io/client-go/informers" kubeinformers "k8s.io/client-go/informers"
corev1informers "k8s.io/client-go/informers/core/v1"
kubernetesfake "k8s.io/client-go/kubernetes/fake" kubernetesfake "k8s.io/client-go/kubernetes/fake"
coretesting "k8s.io/client-go/testing" coretesting "k8s.io/client-go/testing"
"k8s.io/client-go/tools/cache"
"go.pinniped.dev/generated/latest/apis/concierge/config/v1alpha1" "go.pinniped.dev/generated/latest/apis/concierge/config/v1alpha1"
pinnipedfake "go.pinniped.dev/generated/latest/client/concierge/clientset/versioned/fake" pinnipedfake "go.pinniped.dev/generated/latest/client/concierge/clientset/versioned/fake"
"go.pinniped.dev/internal/certauthority" "go.pinniped.dev/internal/certauthority"
"go.pinniped.dev/internal/controllerlib" "go.pinniped.dev/internal/controllerlib"
"go.pinniped.dev/internal/kubeclient"
"go.pinniped.dev/internal/testutil" "go.pinniped.dev/internal/testutil"
) )
@ -374,7 +373,7 @@ func TestImpersonatorConfigControllerSync(t *testing.T) {
assert.Eventually(t, func() bool { assert.Eventually(t, func() bool {
resp, err = client.Do(req.Clone(context.Background())) //nolint:bodyclose resp, err = client.Do(req.Clone(context.Background())) //nolint:bodyclose
return err == nil return err == nil
}, 5*time.Second, 50*time.Millisecond) }, 5*time.Second, 5*time.Millisecond)
r.NoError(err) r.NoError(err)
r.Equal(http.StatusOK, resp.StatusCode) r.Equal(http.StatusOK, resp.StatusCode)
@ -399,7 +398,7 @@ func TestImpersonatorConfigControllerSync(t *testing.T) {
assert.Eventually(t, func() bool { assert.Eventually(t, func() bool {
_, err = client.Do(req.Clone(context.Background())) //nolint:bodyclose _, err = client.Do(req.Clone(context.Background())) //nolint:bodyclose
return err != nil && expectedErrorRegexCompiled.MatchString(err.Error()) return err != nil && expectedErrorRegexCompiled.MatchString(err.Error())
}, 5*time.Second, 50*time.Millisecond) }, 5*time.Second, 5*time.Millisecond)
r.Error(err) r.Error(err)
r.Regexp(expectedErrorRegex, err.Error()) r.Regexp(expectedErrorRegex, err.Error())
} }
@ -417,7 +416,7 @@ func TestImpersonatorConfigControllerSync(t *testing.T) {
&tls.Config{InsecureSkipVerify: true}, //nolint:gosec &tls.Config{InsecureSkipVerify: true}, //nolint:gosec
) )
return err != nil && expectedErrorRegexCompiled.MatchString(err.Error()) return err != nil && expectedErrorRegexCompiled.MatchString(err.Error())
}, 5*time.Second, 50*time.Millisecond) }, 5*time.Second, 5*time.Millisecond)
r.Error(err) r.Error(err)
r.Regexp(expectedErrorRegex, err.Error()) r.Regexp(expectedErrorRegex, err.Error())
} }
@ -426,26 +425,6 @@ func TestImpersonatorConfigControllerSync(t *testing.T) {
r.Equal(0, startTLSListenerFuncWasCalled) r.Equal(0, startTLSListenerFuncWasCalled)
} }
var waitForInformerCacheToSeeResourceVersion = func(informer cache.SharedIndexInformer, wantVersion string) {
r.Eventually(func() bool {
return informer.LastSyncResourceVersion() == wantVersion
}, 10*time.Second, time.Millisecond)
}
var waitForServiceToBeDeleted = func(informer corev1informers.ServiceInformer, name string) {
r.Eventually(func() bool {
_, err := informer.Lister().Services(installedInNamespace).Get(name)
return k8serrors.IsNotFound(err)
}, 10*time.Second, time.Millisecond)
}
var waitForSecretToBeDeleted = func(informer corev1informers.SecretInformer, name string) {
r.Eventually(func() bool {
_, err := informer.Lister().Secrets(installedInNamespace).Get(name)
return k8serrors.IsNotFound(err)
}, 10*time.Second, time.Millisecond)
}
// Defer starting the informers until the last possible moment so that the // Defer starting the informers until the last possible moment so that the
// nested Before's can keep adding things to the informer caches. // nested Before's can keep adding things to the informer caches.
var startInformersAndController = func() { var startInformersAndController = func() {
@ -503,25 +482,6 @@ func TestImpersonatorConfigControllerSync(t *testing.T) {
r.NoError(client.Tracker().Add(impersonatorConfigMap)) r.NoError(client.Tracker().Add(impersonatorConfigMap))
} }
var updateImpersonatorConfigMapInTracker = func(resourceName, configYAML string, client *kubernetesfake.Clientset, newResourceVersion string) {
configMapObj, err := client.Tracker().Get(
schema.GroupVersionResource{Version: "v1", Resource: "configmaps"},
installedInNamespace,
resourceName,
)
r.NoError(err)
configMap := configMapObj.(*corev1.ConfigMap)
configMap.ResourceVersion = newResourceVersion
configMap.Data = map[string]string{
"config.yaml": configYAML,
}
r.NoError(client.Tracker().Update(
schema.GroupVersionResource{Version: "v1", Resource: "configmaps"},
configMap,
installedInNamespace,
))
}
var newSecretWithData = func(resourceName string, data map[string][]byte) *corev1.Secret { var newSecretWithData = func(resourceName string, data map[string][]byte) *corev1.Secret {
return &corev1.Secret{ return &corev1.Secret{
ObjectMeta: metav1.ObjectMeta{ ObjectMeta: metav1.ObjectMeta{
@ -574,22 +534,6 @@ func TestImpersonatorConfigControllerSync(t *testing.T) {
return newSecretWithData(resourceName, newTLSCertSecretData(ca, []string{"foo", "bar"}, ip)) return newSecretWithData(resourceName, newTLSCertSecretData(ca, []string{"foo", "bar"}, ip))
} }
var addSecretFromCreateActionToTracker = func(action coretesting.Action, client *kubernetesfake.Clientset, resourceVersion string) {
createdSecret, ok := action.(coretesting.CreateAction).GetObject().(*corev1.Secret)
r.True(ok, "should have been able to cast this action's object to Secret: %v", action)
createdSecret = createdSecret.DeepCopy()
createdSecret.ResourceVersion = resourceVersion
r.NoError(client.Tracker().Add(createdSecret))
}
var addServiceFromCreateActionToTracker = func(action coretesting.Action, client *kubernetesfake.Clientset, resourceVersion string) {
createdService, ok := action.(coretesting.CreateAction).GetObject().(*corev1.Service)
r.True(ok, "should have been able to cast this action's object to Service: %v", action)
createdService = createdService.DeepCopy()
createdService.ResourceVersion = resourceVersion
r.NoError(client.Tracker().Add(createdService))
}
var newLoadBalancerService = func(resourceName string, status corev1.ServiceStatus) *corev1.Service { var newLoadBalancerService = func(resourceName string, status corev1.ServiceStatus) *corev1.Service {
return &corev1.Service{ return &corev1.Service{
ObjectMeta: metav1.ObjectMeta{ ObjectMeta: metav1.ObjectMeta{
@ -603,6 +547,74 @@ func TestImpersonatorConfigControllerSync(t *testing.T) {
} }
} }
// Anytime an object is added/updated/deleted in the informer's client *after* the informer is started, then we
// need to wait for the informer's cache to asynchronously pick up that change from its "watch".
// If an object is added to the informer's client *before* the informer is started, then waiting is
// not needed because the informer's initial "list" will pick up the object.
var waitForObjectToAppearInInformer = func(obj kubeclient.Object, informer controllerlib.InformerGetter) {
r.Eventually(func() bool {
gotObj, exists, err := informer.Informer().GetIndexer().GetByKey(installedInNamespace + "/" + obj.GetName())
return err == nil && exists && reflect.DeepEqual(gotObj.(kubeclient.Object), obj)
}, 10*time.Second, 5*time.Millisecond)
}
// See comment for waitForObjectToAppearInInformer above.
var waitForObjectToBeDeletedFromInformer = func(resourceName string, informer controllerlib.InformerGetter) {
r.Eventually(func() bool {
_, exists, err := informer.Informer().GetIndexer().GetByKey(installedInNamespace + "/" + resourceName)
return err == nil && !exists
}, 10*time.Second, 5*time.Millisecond)
}
var addObjectToInformerAndWait = func(obj kubeclient.Object, informer controllerlib.InformerGetter) {
r.NoError(kubeInformerClient.Tracker().Add(obj))
waitForObjectToAppearInInformer(obj, informer)
}
var addObjectFromCreateActionToInformerAndWait = func(action coretesting.Action, informer controllerlib.InformerGetter) {
createdObject, ok := action.(coretesting.CreateAction).GetObject().(kubeclient.Object)
r.True(ok, "should have been able to cast this action's object to kubeclient.Object: %v", action)
addObjectToInformerAndWait(createdObject, informer)
}
var updateImpersonatorConfigMapInInformerAndWait = func(resourceName, configYAML string, informer controllerlib.InformerGetter) {
configMapObj, err := kubeInformerClient.Tracker().Get(
schema.GroupVersionResource{Version: "v1", Resource: "configmaps"},
installedInNamespace,
resourceName,
)
r.NoError(err)
configMap := configMapObj.(*corev1.ConfigMap)
configMap = configMap.DeepCopy() // don't edit the original from the tracker
configMap.Data = map[string]string{
"config.yaml": configYAML,
}
r.NoError(kubeInformerClient.Tracker().Update(
schema.GroupVersionResource{Version: "v1", Resource: "configmaps"},
configMap,
installedInNamespace,
))
waitForObjectToAppearInInformer(configMap, informer)
}
var updateLoadBalancerServiceInInformerAndWait = func(resourceName string, ingresses []corev1.LoadBalancerIngress, informer controllerlib.InformerGetter) {
serviceObj, err := kubeInformerClient.Tracker().Get(
schema.GroupVersionResource{Version: "v1", Resource: "services"},
installedInNamespace,
resourceName,
)
r.NoError(err)
service := serviceObj.(*corev1.Service)
service = service.DeepCopy() // don't edit the original from the tracker
service.Status = corev1.ServiceStatus{LoadBalancer: corev1.LoadBalancerStatus{Ingress: ingresses}}
r.NoError(kubeInformerClient.Tracker().Update(
schema.GroupVersionResource{Version: "v1", Resource: "services"},
service,
installedInNamespace,
))
waitForObjectToAppearInInformer(service, informer)
}
var addLoadBalancerServiceToTracker = func(resourceName string, client *kubernetesfake.Clientset) { var addLoadBalancerServiceToTracker = func(resourceName string, client *kubernetesfake.Clientset) {
loadBalancerService := newLoadBalancerService(resourceName, corev1.ServiceStatus{}) loadBalancerService := newLoadBalancerService(resourceName, corev1.ServiceStatus{})
r.NoError(client.Tracker().Add(loadBalancerService)) r.NoError(client.Tracker().Add(loadBalancerService))
@ -622,24 +634,6 @@ func TestImpersonatorConfigControllerSync(t *testing.T) {
} }
} }
var updateLoadBalancerServiceInTracker = func(resourceName string, ingresses []corev1.LoadBalancerIngress, client *kubernetesfake.Clientset, newResourceVersion string) {
serviceObj, err := client.Tracker().Get(
schema.GroupVersionResource{Version: "v1", Resource: "services"},
installedInNamespace,
resourceName,
)
r.NoError(err)
service := serviceObj.(*corev1.Service)
service = service.DeepCopy()
service.ResourceVersion = newResourceVersion
service.Status = corev1.ServiceStatus{LoadBalancer: corev1.LoadBalancerStatus{Ingress: ingresses}}
r.NoError(client.Tracker().Update(
schema.GroupVersionResource{Version: "v1", Resource: "services"},
service,
installedInNamespace,
))
}
var deleteServiceFromTracker = func(resourceName string, client *kubernetesfake.Clientset) { var deleteServiceFromTracker = func(resourceName string, client *kubernetesfake.Clientset) {
r.NoError(client.Tracker().Delete( r.NoError(client.Tracker().Delete(
schema.GroupVersionResource{Version: "v1", Resource: "services"}, schema.GroupVersionResource{Version: "v1", Resource: "services"},
@ -985,10 +979,8 @@ func TestImpersonatorConfigControllerSync(t *testing.T) {
requireCredentialIssuer(newSuccessStrategy(fakeIP, ca)) requireCredentialIssuer(newSuccessStrategy(fakeIP, ca))
// Simulate the informer cache's background update from its watch. // Simulate the informer cache's background update from its watch.
addSecretFromCreateActionToTracker(kubeAPIClient.Actions()[1], kubeInformerClient, "1") addObjectFromCreateActionToInformerAndWait(kubeAPIClient.Actions()[1], kubeInformers.Core().V1().Secrets())
waitForInformerCacheToSeeResourceVersion(kubeInformers.Core().V1().Secrets().Informer(), "1") addObjectFromCreateActionToInformerAndWait(kubeAPIClient.Actions()[2], kubeInformers.Core().V1().Secrets())
addSecretFromCreateActionToTracker(kubeAPIClient.Actions()[2], kubeInformerClient, "2")
waitForInformerCacheToSeeResourceVersion(kubeInformers.Core().V1().Secrets().Informer(), "2")
// keeps the secret around after resync // keeps the secret around after resync
r.NoError(runControllerSync()) r.NoError(runControllerSync())
@ -1016,10 +1008,8 @@ func TestImpersonatorConfigControllerSync(t *testing.T) {
requireCredentialIssuer(newSuccessStrategy(firstHostname, ca)) requireCredentialIssuer(newSuccessStrategy(firstHostname, ca))
// Simulate the informer cache's background update from its watch. // Simulate the informer cache's background update from its watch.
addSecretFromCreateActionToTracker(kubeAPIClient.Actions()[1], kubeInformerClient, "1") addObjectFromCreateActionToInformerAndWait(kubeAPIClient.Actions()[1], kubeInformers.Core().V1().Secrets())
waitForInformerCacheToSeeResourceVersion(kubeInformers.Core().V1().Secrets().Informer(), "1") addObjectFromCreateActionToInformerAndWait(kubeAPIClient.Actions()[2], kubeInformers.Core().V1().Secrets())
addSecretFromCreateActionToTracker(kubeAPIClient.Actions()[2], kubeInformerClient, "2")
waitForInformerCacheToSeeResourceVersion(kubeInformers.Core().V1().Secrets().Informer(), "2")
// keeps the secret around after resync // keeps the secret around after resync
r.NoError(runControllerSync()) r.NoError(runControllerSync())
@ -1047,10 +1037,8 @@ func TestImpersonatorConfigControllerSync(t *testing.T) {
requireCredentialIssuer(newSuccessStrategy(firstHostname, ca)) requireCredentialIssuer(newSuccessStrategy(firstHostname, ca))
// Simulate the informer cache's background update from its watch. // Simulate the informer cache's background update from its watch.
addSecretFromCreateActionToTracker(kubeAPIClient.Actions()[1], kubeInformerClient, "1") addObjectFromCreateActionToInformerAndWait(kubeAPIClient.Actions()[1], kubeInformers.Core().V1().Secrets())
waitForInformerCacheToSeeResourceVersion(kubeInformers.Core().V1().Secrets().Informer(), "1") addObjectFromCreateActionToInformerAndWait(kubeAPIClient.Actions()[2], kubeInformers.Core().V1().Secrets())
addSecretFromCreateActionToTracker(kubeAPIClient.Actions()[2], kubeInformerClient, "2")
waitForInformerCacheToSeeResourceVersion(kubeInformers.Core().V1().Secrets().Informer(), "2")
// keeps the secret around after resync // keeps the secret around after resync
r.NoError(runControllerSync()) r.NoError(runControllerSync())
@ -1129,8 +1117,7 @@ func TestImpersonatorConfigControllerSync(t *testing.T) {
requireNodesListed(kubeAPIClient.Actions()[0]) requireNodesListed(kubeAPIClient.Actions()[0])
requireTLSServerIsRunning(caCrt, testServerAddr(), nil) requireTLSServerIsRunning(caCrt, testServerAddr(), nil)
updateLoadBalancerServiceInTracker(loadBalancerServiceName, []corev1.LoadBalancerIngress{{IP: "not-an-ip"}}, kubeInformerClient, "1") updateLoadBalancerServiceInInformerAndWait(loadBalancerServiceName, []corev1.LoadBalancerIngress{{IP: "not-an-ip"}}, kubeInformers.Core().V1().Services())
waitForInformerCacheToSeeResourceVersion(kubeInformers.Core().V1().Services().Informer(), "1")
errString := "could not find valid IP addresses or hostnames from load balancer some-namespace/some-service-resource-name" errString := "could not find valid IP addresses or hostnames from load balancer some-namespace/some-service-resource-name"
r.EqualError(runControllerSync(), errString) r.EqualError(runControllerSync(), errString)
@ -1359,14 +1346,11 @@ func TestImpersonatorConfigControllerSync(t *testing.T) {
requireCredentialIssuer(newSuccessStrategy(fakeIP, ca)) requireCredentialIssuer(newSuccessStrategy(fakeIP, ca))
// Simulate the informer cache's background update from its watch. // Simulate the informer cache's background update from its watch.
addSecretFromCreateActionToTracker(kubeAPIClient.Actions()[1], kubeInformerClient, "1") addObjectFromCreateActionToInformerAndWait(kubeAPIClient.Actions()[1], kubeInformers.Core().V1().Secrets())
waitForInformerCacheToSeeResourceVersion(kubeInformers.Core().V1().Secrets().Informer(), "1") addObjectFromCreateActionToInformerAndWait(kubeAPIClient.Actions()[2], kubeInformers.Core().V1().Secrets())
addSecretFromCreateActionToTracker(kubeAPIClient.Actions()[2], kubeInformerClient, "2")
waitForInformerCacheToSeeResourceVersion(kubeInformers.Core().V1().Secrets().Informer(), "2")
// Switch the endpoint config to a hostname. // Switch the endpoint config to a hostname.
updateImpersonatorConfigMapInTracker(configMapResourceName, hostnameYAML, kubeInformerClient, "1") updateImpersonatorConfigMapInInformerAndWait(configMapResourceName, hostnameYAML, kubeInformers.Core().V1().ConfigMaps())
waitForInformerCacheToSeeResourceVersion(kubeInformers.Core().V1().ConfigMaps().Informer(), "1")
r.NoError(runControllerSync()) r.NoError(runControllerSync())
r.Len(kubeAPIClient.Actions(), 5) r.Len(kubeAPIClient.Actions(), 5)
@ -1378,12 +1362,10 @@ func TestImpersonatorConfigControllerSync(t *testing.T) {
// Simulate the informer cache's background update from its watch. // Simulate the informer cache's background update from its watch.
deleteSecretFromTracker(tlsSecretName, kubeInformerClient) deleteSecretFromTracker(tlsSecretName, kubeInformerClient)
addSecretFromCreateActionToTracker(kubeAPIClient.Actions()[4], kubeInformerClient, "3") addObjectFromCreateActionToInformerAndWait(kubeAPIClient.Actions()[4], kubeInformers.Core().V1().Secrets())
waitForInformerCacheToSeeResourceVersion(kubeInformers.Core().V1().Secrets().Informer(), "3")
// Switch the endpoint config back to an IP. // Switch the endpoint config back to an IP.
updateImpersonatorConfigMapInTracker(configMapResourceName, ipAddressYAML, kubeInformerClient, "2") updateImpersonatorConfigMapInInformerAndWait(configMapResourceName, ipAddressYAML, kubeInformers.Core().V1().ConfigMaps())
waitForInformerCacheToSeeResourceVersion(kubeInformers.Core().V1().ConfigMaps().Informer(), "2")
r.NoError(runControllerSync()) r.NoError(runControllerSync())
r.Len(kubeAPIClient.Actions(), 7) r.Len(kubeAPIClient.Actions(), 7)
@ -1415,8 +1397,7 @@ func TestImpersonatorConfigControllerSync(t *testing.T) {
requireCredentialIssuer(newSuccessStrategy(fakeHostname, ca)) requireCredentialIssuer(newSuccessStrategy(fakeHostname, ca))
// Simulate the informer cache's background update from its watch for the CA Secret. // Simulate the informer cache's background update from its watch for the CA Secret.
addSecretFromCreateActionToTracker(kubeAPIClient.Actions()[1], kubeInformerClient, "1") addObjectFromCreateActionToInformerAndWait(kubeAPIClient.Actions()[1], kubeInformers.Core().V1().Secrets())
waitForInformerCacheToSeeResourceVersion(kubeInformers.Core().V1().Secrets().Informer(), "1")
// Delete the TLS Secret that was just created from the Kube API server. Note that we never // Delete the TLS Secret that was just created from the Kube API server. Note that we never
// simulated it getting added to the informer cache, so we don't need to remove it from there. // simulated it getting added to the informer cache, so we don't need to remove it from there.
@ -1452,8 +1433,7 @@ func TestImpersonatorConfigControllerSync(t *testing.T) {
requireCredentialIssuer(newSuccessStrategy(fakeHostname, ca)) requireCredentialIssuer(newSuccessStrategy(fakeHostname, ca))
// Simulate the informer cache's background update from its watch for the CA Secret. // Simulate the informer cache's background update from its watch for the CA Secret.
addSecretFromCreateActionToTracker(kubeAPIClient.Actions()[2], kubeInformerClient, "1") addObjectFromCreateActionToInformerAndWait(kubeAPIClient.Actions()[2], kubeInformers.Core().V1().Secrets())
waitForInformerCacheToSeeResourceVersion(kubeInformers.Core().V1().Secrets().Informer(), "1")
// Delete the CA Secret that was just created from the Kube API server. Note that we never // Delete the CA Secret that was just created from the Kube API server. Note that we never
// simulated it getting added to the informer cache, so we don't need to remove it from there. // simulated it getting added to the informer cache, so we don't need to remove it from there.
@ -1489,8 +1469,7 @@ func TestImpersonatorConfigControllerSync(t *testing.T) {
requireCredentialIssuer(newSuccessStrategy(fakeHostname, ca)) requireCredentialIssuer(newSuccessStrategy(fakeHostname, ca))
// Simulate the informer cache's background update from its watch for the CA Secret. // Simulate the informer cache's background update from its watch for the CA Secret.
addSecretFromCreateActionToTracker(kubeAPIClient.Actions()[2], kubeInformerClient, "1") addObjectFromCreateActionToInformerAndWait(kubeAPIClient.Actions()[2], kubeInformers.Core().V1().Secrets())
waitForInformerCacheToSeeResourceVersion(kubeInformers.Core().V1().Secrets().Informer(), "1")
// Simulate someone updating the CA Secret out of band, e.g. when a human edits it with kubectl. // Simulate someone updating the CA Secret out of band, e.g. when a human edits it with kubectl.
// Delete the CA Secret that was just created from the Kube API server. Note that we never // Delete the CA Secret that was just created from the Kube API server. Note that we never
@ -1500,9 +1479,8 @@ func TestImpersonatorConfigControllerSync(t *testing.T) {
anotherCA := newCA() anotherCA := newCA()
newCASecret := newActualCASecret(anotherCA, caSecretName) newCASecret := newActualCASecret(anotherCA, caSecretName)
caCrt = newCASecret.Data["ca.crt"] caCrt = newCASecret.Data["ca.crt"]
newCASecret.ResourceVersion = "2" addSecretToTrackers(newCASecret, kubeAPIClient)
addSecretToTrackers(newCASecret, kubeInformerClient, kubeAPIClient) addObjectToInformerAndWait(newCASecret, kubeInformers.Core().V1().Secrets())
waitForInformerCacheToSeeResourceVersion(kubeInformers.Core().V1().Secrets().Informer(), "2")
}) })
it("deletes the old TLS cert and makes a new TLS cert using the new CA", func() { it("deletes the old TLS cert and makes a new TLS cert using the new CA", func() {
@ -1554,13 +1532,11 @@ func TestImpersonatorConfigControllerSync(t *testing.T) {
requireCredentialIssuer(newPendingStrategy()) requireCredentialIssuer(newPendingStrategy())
// Simulate the informer cache's background update from its watch. // Simulate the informer cache's background update from its watch.
addServiceFromCreateActionToTracker(kubeAPIClient.Actions()[1], kubeInformerClient, "1") addObjectFromCreateActionToInformerAndWait(kubeAPIClient.Actions()[1], kubeInformers.Core().V1().Services())
waitForInformerCacheToSeeResourceVersion(kubeInformers.Core().V1().Services().Informer(), "1") addObjectFromCreateActionToInformerAndWait(kubeAPIClient.Actions()[2], kubeInformers.Core().V1().Secrets())
addSecretFromCreateActionToTracker(kubeAPIClient.Actions()[2], kubeInformerClient, "1")
waitForInformerCacheToSeeResourceVersion(kubeInformers.Core().V1().Secrets().Informer(), "1")
updateImpersonatorConfigMapInTracker(configMapResourceName, "mode: disabled", kubeInformerClient, "1") // Update the configmap.
waitForInformerCacheToSeeResourceVersion(kubeInformers.Core().V1().ConfigMaps().Informer(), "1") updateImpersonatorConfigMapInInformerAndWait(configMapResourceName, "mode: disabled", kubeInformers.Core().V1().ConfigMaps())
r.NoError(runControllerSync()) r.NoError(runControllerSync())
requireTLSServerIsNoLongerRunning() requireTLSServerIsNoLongerRunning()
@ -1569,10 +1545,10 @@ func TestImpersonatorConfigControllerSync(t *testing.T) {
requireCredentialIssuer(newManuallyDisabledStrategy()) requireCredentialIssuer(newManuallyDisabledStrategy())
deleteServiceFromTracker(loadBalancerServiceName, kubeInformerClient) deleteServiceFromTracker(loadBalancerServiceName, kubeInformerClient)
waitForServiceToBeDeleted(kubeInformers.Core().V1().Services(), loadBalancerServiceName) waitForObjectToBeDeletedFromInformer(loadBalancerServiceName, kubeInformers.Core().V1().Services())
updateImpersonatorConfigMapInTracker(configMapResourceName, "mode: enabled", kubeInformerClient, "2") // Update the configmap again.
waitForInformerCacheToSeeResourceVersion(kubeInformers.Core().V1().ConfigMaps().Informer(), "2") updateImpersonatorConfigMapInInformerAndWait(configMapResourceName, "mode: enabled", kubeInformers.Core().V1().ConfigMaps())
r.NoError(runControllerSync()) r.NoError(runControllerSync())
requireTLSServerIsRunningWithoutCerts() requireTLSServerIsRunningWithoutCerts()
@ -1591,8 +1567,8 @@ func TestImpersonatorConfigControllerSync(t *testing.T) {
r.NoError(runControllerSync()) r.NoError(runControllerSync())
requireTLSServerIsRunningWithoutCerts() requireTLSServerIsRunningWithoutCerts()
updateImpersonatorConfigMapInTracker(configMapResourceName, "mode: disabled", kubeInformerClient, "1") // Update the configmap.
waitForInformerCacheToSeeResourceVersion(kubeInformers.Core().V1().ConfigMaps().Informer(), "1") updateImpersonatorConfigMapInInformerAndWait(configMapResourceName, "mode: disabled", kubeInformers.Core().V1().ConfigMaps())
r.EqualError(runControllerSync(), "fake server close error") r.EqualError(runControllerSync(), "fake server close error")
requireTLSServerIsNoLongerRunning() requireTLSServerIsNoLongerRunning()
@ -1621,14 +1597,11 @@ func TestImpersonatorConfigControllerSync(t *testing.T) {
requireCredentialIssuer(newSuccessStrategy(localhostIP, ca)) requireCredentialIssuer(newSuccessStrategy(localhostIP, ca))
// Simulate the informer cache's background update from its watch. // Simulate the informer cache's background update from its watch.
addSecretFromCreateActionToTracker(kubeAPIClient.Actions()[1], kubeInformerClient, "1") addObjectFromCreateActionToInformerAndWait(kubeAPIClient.Actions()[1], kubeInformers.Core().V1().Secrets())
waitForInformerCacheToSeeResourceVersion(kubeInformers.Core().V1().Secrets().Informer(), "1") addObjectFromCreateActionToInformerAndWait(kubeAPIClient.Actions()[2], kubeInformers.Core().V1().Secrets())
addSecretFromCreateActionToTracker(kubeAPIClient.Actions()[2], kubeInformerClient, "2")
waitForInformerCacheToSeeResourceVersion(kubeInformers.Core().V1().Secrets().Informer(), "2")
// Switch to "enabled" mode without an "endpoint", so a load balancer is needed now. // Switch to "enabled" mode without an "endpoint", so a load balancer is needed now.
updateImpersonatorConfigMapInTracker(configMapResourceName, "mode: enabled", kubeInformerClient, "1") updateImpersonatorConfigMapInInformerAndWait(configMapResourceName, "mode: enabled", kubeInformers.Core().V1().ConfigMaps())
waitForInformerCacheToSeeResourceVersion(kubeInformers.Core().V1().ConfigMaps().Informer(), "1")
r.NoError(runControllerSync()) r.NoError(runControllerSync())
r.Len(kubeAPIClient.Actions(), 5) r.Len(kubeAPIClient.Actions(), 5)
@ -1638,10 +1611,9 @@ func TestImpersonatorConfigControllerSync(t *testing.T) {
requireCredentialIssuer(newPendingStrategy()) requireCredentialIssuer(newPendingStrategy())
// Simulate the informer cache's background update from its watch. // Simulate the informer cache's background update from its watch.
addServiceFromCreateActionToTracker(kubeAPIClient.Actions()[3], kubeInformerClient, "1") addObjectFromCreateActionToInformerAndWait(kubeAPIClient.Actions()[3], kubeInformers.Core().V1().Services())
waitForInformerCacheToSeeResourceVersion(kubeInformers.Core().V1().Services().Informer(), "1")
deleteSecretFromTracker(tlsSecretName, kubeInformerClient) deleteSecretFromTracker(tlsSecretName, kubeInformerClient)
waitForSecretToBeDeleted(kubeInformers.Core().V1().Secrets(), tlsSecretName) waitForObjectToBeDeletedFromInformer(tlsSecretName, kubeInformers.Core().V1().Secrets())
// The controller should be waiting for the load balancer's ingress to become available. // The controller should be waiting for the load balancer's ingress to become available.
r.NoError(runControllerSync()) r.NoError(runControllerSync())
@ -1651,8 +1623,7 @@ func TestImpersonatorConfigControllerSync(t *testing.T) {
// Update the ingress of the LB in the informer's client and run Sync again. // Update the ingress of the LB in the informer's client and run Sync again.
fakeIP := "127.0.0.123" fakeIP := "127.0.0.123"
updateLoadBalancerServiceInTracker(loadBalancerServiceName, []corev1.LoadBalancerIngress{{IP: fakeIP}}, kubeInformerClient, "2") updateLoadBalancerServiceInInformerAndWait(loadBalancerServiceName, []corev1.LoadBalancerIngress{{IP: fakeIP}}, kubeInformers.Core().V1().Services())
waitForInformerCacheToSeeResourceVersion(kubeInformers.Core().V1().Services().Informer(), "2")
r.NoError(runControllerSync()) r.NoError(runControllerSync())
r.Len(kubeAPIClient.Actions(), 6) r.Len(kubeAPIClient.Actions(), 6)
requireTLSSecretWasCreated(kubeAPIClient.Actions()[5], ca) // reuses the existing CA requireTLSSecretWasCreated(kubeAPIClient.Actions()[5], ca) // reuses the existing CA
@ -1661,13 +1632,11 @@ func TestImpersonatorConfigControllerSync(t *testing.T) {
requireCredentialIssuer(newSuccessStrategy(fakeIP, ca)) requireCredentialIssuer(newSuccessStrategy(fakeIP, ca))
// Simulate the informer cache's background update from its watch. // Simulate the informer cache's background update from its watch.
addSecretFromCreateActionToTracker(kubeAPIClient.Actions()[5], kubeInformerClient, "3") addObjectFromCreateActionToInformerAndWait(kubeAPIClient.Actions()[5], kubeInformers.Core().V1().Secrets())
waitForInformerCacheToSeeResourceVersion(kubeInformers.Core().V1().Secrets().Informer(), "3")
// Now switch back to having the "endpoint" specified, so the load balancer is not needed anymore. // Now switch back to having the "endpoint" specified, so the load balancer is not needed anymore.
configMapYAML := fmt.Sprintf("{mode: enabled, endpoint: %s}", localhostIP) configMapYAML := fmt.Sprintf("{mode: enabled, endpoint: %s}", localhostIP)
updateImpersonatorConfigMapInTracker(configMapResourceName, configMapYAML, kubeInformerClient, "2") updateImpersonatorConfigMapInInformerAndWait(configMapResourceName, configMapYAML, kubeInformers.Core().V1().ConfigMaps())
waitForInformerCacheToSeeResourceVersion(kubeInformers.Core().V1().ConfigMaps().Informer(), "2")
r.NoError(runControllerSync()) r.NoError(runControllerSync())
r.Len(kubeAPIClient.Actions(), 9) r.Len(kubeAPIClient.Actions(), 9)
@ -1696,10 +1665,8 @@ func TestImpersonatorConfigControllerSync(t *testing.T) {
requireCredentialIssuer(newPendingStrategy()) requireCredentialIssuer(newPendingStrategy())
// Simulate the informer cache's background update from its watch. // Simulate the informer cache's background update from its watch.
addServiceFromCreateActionToTracker(kubeAPIClient.Actions()[1], kubeInformerClient, "1") addObjectFromCreateActionToInformerAndWait(kubeAPIClient.Actions()[1], kubeInformers.Core().V1().Services())
waitForInformerCacheToSeeResourceVersion(kubeInformers.Core().V1().Services().Informer(), "1") addObjectFromCreateActionToInformerAndWait(kubeAPIClient.Actions()[2], kubeInformers.Core().V1().Secrets())
addSecretFromCreateActionToTracker(kubeAPIClient.Actions()[2], kubeInformerClient, "1")
waitForInformerCacheToSeeResourceVersion(kubeInformers.Core().V1().Secrets().Informer(), "1")
r.NoError(runControllerSync()) r.NoError(runControllerSync())
r.Equal(1, startTLSListenerFuncWasCalled) // wasn't started a second time r.Equal(1, startTLSListenerFuncWasCalled) // wasn't started a second time
@ -1719,13 +1686,10 @@ func TestImpersonatorConfigControllerSync(t *testing.T) {
requireCredentialIssuer(newPendingStrategy()) requireCredentialIssuer(newPendingStrategy())
// Simulate the informer cache's background update from its watch. // Simulate the informer cache's background update from its watch.
addServiceFromCreateActionToTracker(kubeAPIClient.Actions()[1], kubeInformerClient, "1") addObjectFromCreateActionToInformerAndWait(kubeAPIClient.Actions()[1], kubeInformers.Core().V1().Services())
waitForInformerCacheToSeeResourceVersion(kubeInformers.Core().V1().Services().Informer(), "1") addObjectFromCreateActionToInformerAndWait(kubeAPIClient.Actions()[2], kubeInformers.Core().V1().Secrets())
addSecretFromCreateActionToTracker(kubeAPIClient.Actions()[2], kubeInformerClient, "1")
waitForInformerCacheToSeeResourceVersion(kubeInformers.Core().V1().Secrets().Informer(), "1")
updateLoadBalancerServiceInTracker(loadBalancerServiceName, []corev1.LoadBalancerIngress{{IP: localhostIP}}, kubeInformerClient, "2") updateLoadBalancerServiceInInformerAndWait(loadBalancerServiceName, []corev1.LoadBalancerIngress{{IP: localhostIP}}, kubeInformers.Core().V1().Services())
waitForInformerCacheToSeeResourceVersion(kubeInformers.Core().V1().Services().Informer(), "2")
r.NoError(runControllerSync()) r.NoError(runControllerSync())
r.Equal(1, startTLSListenerFuncWasCalled) // wasn't started a second time r.Equal(1, startTLSListenerFuncWasCalled) // wasn't started a second time
@ -1735,8 +1699,7 @@ func TestImpersonatorConfigControllerSync(t *testing.T) {
requireCredentialIssuer(newSuccessStrategy(localhostIP, ca)) requireCredentialIssuer(newSuccessStrategy(localhostIP, ca))
// Simulate the informer cache's background update from its watch. // Simulate the informer cache's background update from its watch.
addSecretFromCreateActionToTracker(kubeAPIClient.Actions()[3], kubeInformerClient, "2") addObjectFromCreateActionToInformerAndWait(kubeAPIClient.Actions()[3], kubeInformers.Core().V1().Secrets())
waitForInformerCacheToSeeResourceVersion(kubeInformers.Core().V1().Secrets().Informer(), "2")
r.NoError(runControllerSync()) r.NoError(runControllerSync())
r.Equal(1, startTLSListenerFuncWasCalled) // wasn't started again r.Equal(1, startTLSListenerFuncWasCalled) // wasn't started again
@ -1757,13 +1720,10 @@ func TestImpersonatorConfigControllerSync(t *testing.T) {
requireCredentialIssuer(newPendingStrategy()) requireCredentialIssuer(newPendingStrategy())
// Simulate the informer cache's background update from its watch. // Simulate the informer cache's background update from its watch.
addServiceFromCreateActionToTracker(kubeAPIClient.Actions()[1], kubeInformerClient, "1") addObjectFromCreateActionToInformerAndWait(kubeAPIClient.Actions()[1], kubeInformers.Core().V1().Services())
waitForInformerCacheToSeeResourceVersion(kubeInformers.Core().V1().Services().Informer(), "1") addObjectFromCreateActionToInformerAndWait(kubeAPIClient.Actions()[2], kubeInformers.Core().V1().Secrets())
addSecretFromCreateActionToTracker(kubeAPIClient.Actions()[2], kubeInformerClient, "1")
waitForInformerCacheToSeeResourceVersion(kubeInformers.Core().V1().Secrets().Informer(), "1")
updateLoadBalancerServiceInTracker(loadBalancerServiceName, []corev1.LoadBalancerIngress{{IP: localhostIP, Hostname: hostname}}, kubeInformerClient, "2") updateLoadBalancerServiceInInformerAndWait(loadBalancerServiceName, []corev1.LoadBalancerIngress{{IP: localhostIP, Hostname: hostname}}, kubeInformers.Core().V1().Services())
waitForInformerCacheToSeeResourceVersion(kubeInformers.Core().V1().Services().Informer(), "2")
r.NoError(runControllerSync()) r.NoError(runControllerSync())
r.Equal(1, startTLSListenerFuncWasCalled) // wasn't started a second time r.Equal(1, startTLSListenerFuncWasCalled) // wasn't started a second time
@ -1773,8 +1733,7 @@ func TestImpersonatorConfigControllerSync(t *testing.T) {
requireCredentialIssuer(newSuccessStrategy(hostname, ca)) requireCredentialIssuer(newSuccessStrategy(hostname, ca))
// Simulate the informer cache's background update from its watch. // Simulate the informer cache's background update from its watch.
addSecretFromCreateActionToTracker(kubeAPIClient.Actions()[3], kubeInformerClient, "2") addObjectFromCreateActionToInformerAndWait(kubeAPIClient.Actions()[3], kubeInformers.Core().V1().Secrets())
waitForInformerCacheToSeeResourceVersion(kubeInformers.Core().V1().Secrets().Informer(), "2")
r.NoError(runControllerSync()) r.NoError(runControllerSync())
r.Equal(1, startTLSListenerFuncWasCalled) // wasn't started a third time r.Equal(1, startTLSListenerFuncWasCalled) // wasn't started a third time