diff --git a/internal/controllers/certificates/cert_manager.go b/internal/controllers/certificates/cert_manager.go index 6f24e361..69602dfa 100644 --- a/internal/controllers/certificates/cert_manager.go +++ b/internal/controllers/certificates/cert_manager.go @@ -12,6 +12,7 @@ import ( cmv1 "github.com/cert-manager/cert-manager/pkg/apis/certmanager/v1" cmmeta "github.com/cert-manager/cert-manager/pkg/apis/meta/v1" + corev1 "k8s.io/api/core/v1" k8serrors "k8s.io/apimachinery/pkg/api/errors" metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" "k8s.io/apimachinery/pkg/apis/meta/v1/unstructured" @@ -45,6 +46,10 @@ func reconcileCertManager(ctx context.Context, client client.Client, instance, i var cert cmv1.Certificate err = client.Get(ctx, types.NamespacedName{Name: newCert.Name, Namespace: newCert.Namespace}, &cert) if err != nil && k8serrors.IsNotFound(err) { + if err = takeOverPreviousSecret(ctx, client, instance, instanceMergedWithFlavors, newCert); err != nil { + return err + } + if err = client.Create(ctx, newCert); err != nil { return err } @@ -112,6 +117,46 @@ func removeOldCertificates(ctx context.Context, c client.Client, instance, insta return nil } +func takeOverPreviousSecret(ctx context.Context, c client.Client, instance, instanceMergedWithFlavors *v1alpha1.RpaasInstance, cert *cmv1.Certificate) error { + var secret corev1.Secret + + err := c.Get(ctx, types.NamespacedName{Name: cert.Spec.SecretName, Namespace: cert.Namespace}, &secret) + + if err == nil { + return nil + } + + if !k8serrors.IsNotFound(err) { + return err + } + + // find previous secret + certificateName := cert.Labels[CertificateNameLabel] + previousSecret, err := getTLSSecretByCertificateName(ctx, c, instanceMergedWithFlavors, certificateName) + + if err == ErrTLSSecretNotFound { + return nil + } + + if err != nil { + return err + } + + secret = corev1.Secret{ + ObjectMeta: metav1.ObjectMeta{ + Name: cert.Spec.SecretName, + Namespace: cert.Namespace, + Labels: cert.Labels, + Annotations: cert.Annotations, + }, + Data: previousSecret.Data, + StringData: previousSecret.StringData, + Type: previousSecret.Type, + } + + return c.Create(ctx, &secret) +} + func getCertificates(ctx context.Context, c client.Client, i *v1alpha1.RpaasInstance) ([]cmv1.Certificate, error) { var certList cmv1.CertificateList err := c.List(ctx, &certList, &client.ListOptions{ diff --git a/internal/controllers/certificates/cert_manager_test.go b/internal/controllers/certificates/cert_manager_test.go index 67b0eeb3..b86a1105 100644 --- a/internal/controllers/certificates/cert_manager_test.go +++ b/internal/controllers/certificates/cert_manager_test.go @@ -78,6 +78,21 @@ func Test_ReconcileCertManager(t *testing.T) { }, }, + &corev1.Secret{ + ObjectMeta: metav1.ObjectMeta{ + Name: "my-instance-take-over-old", + Namespace: "rpaasv2", + Labels: map[string]string{ + "rpaas.extensions.tsuru.io/certificate-name": "my-instance-take-over", + "rpaas.extensions.tsuru.io/instance-name": "my-instance-take-over-test", + }, + }, + Data: map[string][]byte{ + "tls.crt": []byte(`--- some old cert here ---`), + "tls.key": []byte(`--- some old key here ---`), + }, + }, + &cmv1.Certificate{ ObjectMeta: metav1.ObjectMeta{ Name: "my-instance-2", @@ -323,6 +338,87 @@ wg4cGbIbBPs= }, }, + "when take over existing certificate using cert manager": { + instance: &v1alpha1.RpaasInstance{ + ObjectMeta: metav1.ObjectMeta{ + Name: "my-instance-take-over-test", + Namespace: "rpaasv2", + }, + Spec: v1alpha1.RpaasInstanceSpec{ + DynamicCertificates: &v1alpha1.DynamicCertificates{ + CertManagerRequests: []v1alpha1.CertManager{ + { + Name: "my-instance-take-over", + Issuer: "issuer-1", + DNSNames: []string{"my-instance.example.com"}, + }, + }, + }, + TLS: []nginxv1alpha1.NginxTLS{ + { + SecretName: "my-instance-take-over-old", + Hosts: []string{"my-instance.example.com"}, + }, + }, + }, + }, + assert: func(t *testing.T, cli client.Client, instance *v1alpha1.RpaasInstance) { + var certList cmv1.CertificateList + + err := cli.List(context.TODO(), &certList) + require.NoError(t, err) + + certs := []cmv1.Certificate{} + for _, cert := range certList.Items { + if cert.Labels["rpaas.extensions.tsuru.io/instance-name"] == "my-instance-take-over-test" { + certs = append(certs, cert) + } + } + + require.Len(t, certs, 1) + + for _, cert := range certs { + assert.Equal(t, []metav1.OwnerReference{ + { + APIVersion: "extensions.tsuru.io/v1alpha1", + Kind: "RpaasInstance", + Name: "my-instance-take-over-test", + Controller: func(b bool) *bool { return &b }(true), + BlockOwnerDeletion: func(b bool) *bool { return &b }(true), + }, + }, cert.ObjectMeta.OwnerReferences) + } + + assert.Equal(t, map[string]string{ + "rpaas.extensions.tsuru.io/certificate-name": "my-instance-take-over", + "rpaas.extensions.tsuru.io/instance-name": "my-instance-take-over-test", + }, certs[0].Labels) + + assert.Equal(t, cmv1.CertificateSpec{ + IssuerRef: cmmeta.ObjectReference{ + Name: "issuer-1", + Group: "cert-manager.io", + Kind: "Issuer", + }, + SecretName: "my-instance-take-over-test-my-instance-take-over", + DNSNames: []string{"my-instance.example.com"}, + }, certs[0].Spec) + + secret := corev1.Secret{} + err = cli.Get(context.TODO(), types.NamespacedName{ + Name: certs[0].Spec.SecretName, + Namespace: instance.Namespace, + }, &secret) + require.NoError(t, err) + + assert.Equal(t, certs[0].Labels, secret.Labels) + assert.Equal(t, certs[0].Annotations, secret.Annotations) + + assert.Equal(t, "--- some old cert here ---", string(secret.Data["tls.crt"])) + assert.Equal(t, "--- some old key here ---", string(secret.Data["tls.key"])) + }, + }, + "when cert manager set to use DNS zone, should create certificate": { instance: &v1alpha1.RpaasInstance{ ObjectMeta: metav1.ObjectMeta{