diff --git a/pkg/psmdb/tls/certmanager.go b/pkg/psmdb/tls/certmanager.go index aa14cd746c..2f69b3d513 100644 --- a/pkg/psmdb/tls/certmanager.go +++ b/pkg/psmdb/tls/certmanager.go @@ -313,6 +313,11 @@ func (c *certManagerController) WaitForCerts(ctx context.Context, cr *api.Percon if v, ok := secret.Annotations[cm.CertificateNameKey]; !ok || v != secret.Name { continue } + // cert-manager sets the Certificate as the controller owner. + // In that case, the operator should not set a new controller reference. + if metav1.GetControllerOf(secret) != nil { + continue + } if err = controllerutil.SetControllerReference(cr, secret, c.scheme); err != nil { return errors.Wrap(err, "set controller reference") } diff --git a/pkg/psmdb/tls/certmanager_test.go b/pkg/psmdb/tls/certmanager_test.go index 18fec27ad8..a493fbd22f 100644 --- a/pkg/psmdb/tls/certmanager_test.go +++ b/pkg/psmdb/tls/certmanager_test.go @@ -6,6 +6,8 @@ import ( cm "github.com/cert-manager/cert-manager/pkg/apis/certmanager/v1" cmmeta "github.com/cert-manager/cert-manager/pkg/apis/meta/v1" + "github.com/stretchr/testify/assert" + corev1 "k8s.io/api/core/v1" metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" "k8s.io/apimachinery/pkg/types" "k8s.io/client-go/kubernetes/scheme" @@ -13,6 +15,7 @@ import ( "sigs.k8s.io/controller-runtime/pkg/client/fake" // nolint api "github.com/percona/percona-server-mongodb-operator/pkg/apis/psmdb/v1" + "github.com/percona/percona-server-mongodb-operator/pkg/version" ) func TestCreateIssuer(t *testing.T) { @@ -130,6 +133,137 @@ func TestCreateCertificate(t *testing.T) { }) } +func TestWaitForCerts(t *testing.T) { + ctx := context.Background() + + cr := &api.PerconaServerMongoDB{ + ObjectMeta: metav1.ObjectMeta{ + Name: "test-cluster", + Namespace: "default", + UID: "test-uid-123", + }, + Spec: api.PerconaServerMongoDBSpec{ + CRVersion: version.Version(), + }, + } + + certName := CACertificateSecretName(cr) + + tests := map[string]struct { + certificate *cm.Certificate + secret *corev1.Secret + }{ + "with cert-manager managed secret": { + certificate: &cm.Certificate{ + ObjectMeta: metav1.ObjectMeta{ + Name: certName, + Namespace: cr.Namespace, + UID: "cert-uid-456", + }, + Spec: cm.CertificateSpec{ + SecretName: certName, + }, + }, + secret: &corev1.Secret{ + ObjectMeta: metav1.ObjectMeta{ + Name: certName, + Namespace: cr.Namespace, + Annotations: map[string]string{ + cm.CertificateNameKey: certName, + }, + OwnerReferences: []metav1.OwnerReference{ + { + APIVersion: cm.SchemeGroupVersion.String(), + Kind: cm.CertificateKind, + Name: certName, + UID: "cert-uid-456", + Controller: pointer(true), + }, + }, + }, + Data: map[string][]byte{ + "ca.crt": []byte("fake-ca-cert"), + "tls.crt": []byte("fake-tls-cert"), + "tls.key": []byte("fake-tls-key"), + }, + }, + }, + "with cert-manager managed secret but without OwnerReferences": { + certificate: &cm.Certificate{ + ObjectMeta: metav1.ObjectMeta{ + Name: certName, + Namespace: cr.Namespace, + UID: "cert-uid-456", + }, + Spec: cm.CertificateSpec{ + SecretName: certName, + }, + }, + secret: &corev1.Secret{ + ObjectMeta: metav1.ObjectMeta{ + Name: certName, + Namespace: cr.Namespace, + Annotations: map[string]string{ + cm.CertificateNameKey: certName, + }, + }, + Data: map[string][]byte{ + "ca.crt": []byte("fake-ca-cert"), + "tls.crt": []byte("fake-tls-cert"), + "tls.key": []byte("fake-tls-key"), + }, + }, + }, + "without cert-manager": { + certificate: nil, + secret: &corev1.Secret{ + ObjectMeta: metav1.ObjectMeta{ + Name: certName, + Namespace: cr.Namespace, + }, + Data: map[string][]byte{ + "ca.crt": []byte("fake-ca-cert"), + "tls.crt": []byte("fake-tls-cert"), + "tls.key": []byte("fake-tls-key"), + }, + }, + }, + } + + for name, tc := range tests { + t.Run(name, func(t *testing.T) { + s := scheme.Scheme + s.AddKnownTypes(api.SchemeGroupVersion, new(api.PerconaServerMongoDB)) + s.AddKnownTypes(cm.SchemeGroupVersion, new(cm.Certificate)) + s.AddKnownTypes(corev1.SchemeGroupVersion, new(corev1.Secret)) + + objects := []client.Object{cr, tc.secret} + if tc.certificate != nil { + objects = append(objects, tc.certificate) + } + + cl := fake.NewClientBuilder(). + WithScheme(s). + WithObjects(objects...). + WithStatusSubresource(cr). + Build() + + controller := &certManagerController{ + cl: cl, + scheme: s, + dryRun: false, + } + + err := controller.WaitForCerts(ctx, cr, certName) + assert.NoError(t, err) + }) + } +} + +func pointer(b bool) *bool { + return &b +} + // creates a fake client to mock API calls with the mock objects func buildFakeClient(objs ...client.Object) CertManagerController { s := scheme.Scheme