Merge pull request #747 from enj/enj/i/delete_race

certs_expirer: be specific about what secret to delete
This commit is contained in:
Mo Khan 2021-07-28 10:32:17 -04:00 committed by GitHub
commit ef33846d7d
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
2 changed files with 59 additions and 4 deletions

View File

@ -90,7 +90,12 @@ func (c *certsExpirerController) Sync(ctx controllerlib.Context) error {
err := c.k8sClient. err := c.k8sClient.
CoreV1(). CoreV1().
Secrets(c.namespace). Secrets(c.namespace).
Delete(ctx.Context, c.certsSecretResourceName, metav1.DeleteOptions{}) Delete(ctx.Context, c.certsSecretResourceName, metav1.DeleteOptions{
Preconditions: &metav1.Preconditions{
UID: &secret.UID,
ResourceVersion: &secret.ResourceVersion,
},
})
if err != nil { if err != nil {
// Do return an error here so that the controller library will reschedule // Do return an error here so that the controller library will reschedule
// us to try deleting this cert again. // us to try deleting this cert again.

View File

@ -18,8 +18,11 @@ import (
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/types"
kubeinformers "k8s.io/client-go/informers" kubeinformers "k8s.io/client-go/informers"
"k8s.io/client-go/kubernetes"
kubernetesfake "k8s.io/client-go/kubernetes/fake" kubernetesfake "k8s.io/client-go/kubernetes/fake"
corev1client "k8s.io/client-go/kubernetes/typed/core/v1"
kubetesting "k8s.io/client-go/testing" kubetesting "k8s.io/client-go/testing"
"go.pinniped.dev/internal/controllerlib" "go.pinniped.dev/internal/controllerlib"
@ -223,6 +226,9 @@ func TestExpirerControllerSync(t *testing.T) {
test.configKubeAPIClient(kubeAPIClient) test.configKubeAPIClient(kubeAPIClient)
} }
testRV := "rv_001"
testUID := types.UID("uid_002")
kubeInformerClient := kubernetesfake.NewSimpleClientset() kubeInformerClient := kubernetesfake.NewSimpleClientset()
name := certsSecretResourceName name := certsSecretResourceName
namespace := "some-namespace" namespace := "some-namespace"
@ -231,6 +237,8 @@ func TestExpirerControllerSync(t *testing.T) {
ObjectMeta: metav1.ObjectMeta{ ObjectMeta: metav1.ObjectMeta{
Name: name, Name: name,
Namespace: namespace, Namespace: namespace,
ResourceVersion: testRV,
UID: testUID,
}, },
Data: map[string][]byte{}, Data: map[string][]byte{},
} }
@ -245,10 +253,12 @@ func TestExpirerControllerSync(t *testing.T) {
0, 0,
) )
trackDeleteClient := &clientWrapper{Interface: kubeAPIClient, opts: &[]metav1.DeleteOptions{}}
c := NewCertsExpirerController( c := NewCertsExpirerController(
namespace, namespace,
certsSecretResourceName, certsSecretResourceName,
kubeAPIClient, trackDeleteClient,
kubeInformers.Core().V1().Secrets(), kubeInformers.Core().V1().Secrets(),
controllerlib.WithInformer, controllerlib.WithInformer,
test.renewBefore, test.renewBefore,
@ -285,6 +295,46 @@ func TestExpirerControllerSync(t *testing.T) {
} }
acActions := kubeAPIClient.Actions() acActions := kubeAPIClient.Actions()
require.Equal(t, exActions, acActions) require.Equal(t, exActions, acActions)
if test.wantDelete {
require.Len(t, *trackDeleteClient.opts, 1)
require.Equal(t, metav1.DeleteOptions{
Preconditions: &metav1.Preconditions{
UID: &testUID,
ResourceVersion: &testRV,
},
}, (*trackDeleteClient.opts)[0])
} else {
require.Len(t, *trackDeleteClient.opts, 0)
}
}) })
} }
} }
type clientWrapper struct {
kubernetes.Interface
opts *[]metav1.DeleteOptions
}
func (c *clientWrapper) CoreV1() corev1client.CoreV1Interface {
return &coreWrapper{CoreV1Interface: c.Interface.CoreV1(), opts: c.opts}
}
type coreWrapper struct {
corev1client.CoreV1Interface
opts *[]metav1.DeleteOptions
}
func (c *coreWrapper) Secrets(namespace string) corev1client.SecretInterface {
return &secretsWrapper{SecretInterface: c.CoreV1Interface.Secrets(namespace), opts: c.opts}
}
type secretsWrapper struct {
corev1client.SecretInterface
opts *[]metav1.DeleteOptions
}
func (s *secretsWrapper) Delete(ctx context.Context, name string, opts metav1.DeleteOptions) error {
*s.opts = append(*s.opts, opts)
return s.SecretInterface.Delete(ctx, name, opts)
}