diff --git a/pkg/controller/certificates/BUILD.bazel b/pkg/controller/certificates/BUILD.bazel index 0f1e1dae5..658201714 100644 --- a/pkg/controller/certificates/BUILD.bazel +++ b/pkg/controller/certificates/BUILD.bazel @@ -66,7 +66,9 @@ go_test( "//pkg/issuer:go_default_library", "//pkg/issuer/fake:go_default_library", "//pkg/issuer/selfsigned:go_default_library", + "//pkg/util/pki:go_default_library", "//test/unit/gen:go_default_library", + "//vendor/k8s.io/api/core/v1:go_default_library", "//vendor/k8s.io/apimachinery/pkg/apis/meta/v1:go_default_library", "//vendor/k8s.io/apimachinery/pkg/runtime:go_default_library", "//vendor/k8s.io/client-go/testing:go_default_library", diff --git a/pkg/controller/certificates/sync_test.go b/pkg/controller/certificates/sync_test.go index 607366f1c..bffe5ee2b 100644 --- a/pkg/controller/certificates/sync_test.go +++ b/pkg/controller/certificates/sync_test.go @@ -17,28 +17,123 @@ limitations under the License. package certificates import ( + "bytes" "context" + "crypto" + "crypto/rand" + "crypto/rsa" + "crypto/x509" + "crypto/x509/pkix" + "encoding/pem" + "math/big" "testing" "time" + corev1 "k8s.io/api/core/v1" metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" "k8s.io/apimachinery/pkg/runtime" coretesting "k8s.io/client-go/testing" clock "k8s.io/utils/clock/testing" + "github.com/jetstack/cert-manager/pkg/apis/certmanager/v1alpha1" cmapi "github.com/jetstack/cert-manager/pkg/apis/certmanager/v1alpha1" testpkg "github.com/jetstack/cert-manager/pkg/controller/test" "github.com/jetstack/cert-manager/pkg/issuer" "github.com/jetstack/cert-manager/pkg/issuer/fake" _ "github.com/jetstack/cert-manager/pkg/issuer/selfsigned" + "github.com/jetstack/cert-manager/pkg/util/pki" "github.com/jetstack/cert-manager/test/unit/gen" ) + +func generatePrivateKey(t *testing.T) *rsa.PrivateKey { + pk, err := pki.GenerateRSAPrivateKey(2048) + if err != nil { + t.Errorf("failed to generate private key: %v", err) + t.FailNow() + } + return pk +} + +var serialNumberLimit = new(big.Int).Lsh(big.NewInt(1), 128) + +func generateSelfSignedCert(t *testing.T, crt *v1alpha1.Certificate, key crypto.Signer, notBefore, notAfter time.Time) []byte { + commonName := pki.CommonNameForCertificate(crt) + dnsNames := pki.DNSNamesForCertificate(crt) + + serialNumber, err := rand.Int(rand.Reader, serialNumberLimit) + if err != nil { + t.Errorf("failed to generate serial number: %v", err) + t.FailNow() + } + + template := &x509.Certificate{ + Version: 3, + BasicConstraintsValid: true, + SerialNumber: serialNumber, + Subject: pkix.Name{ + CommonName: commonName, + }, + NotBefore: notBefore, + NotAfter: notAfter, + // see http://golang.org/pkg/crypto/x509/#KeyUsage + KeyUsage: x509.KeyUsageDigitalSignature | x509.KeyUsageKeyEncipherment, + DNSNames: dnsNames, + } + + derBytes, err := x509.CreateCertificate(rand.Reader, template, template, key.Public(), key) + if err != nil { + t.Errorf("error signing cert: %v", err) + t.FailNow() + } + + pemByteBuffer := bytes.NewBuffer([]byte{}) + err = pem.Encode(pemByteBuffer, &pem.Block{Type: "CERTIFICATE", Bytes: derBytes}) + if err != nil { + t.Errorf("failed to encode cert: %v", err) + t.FailNow() + } + + return pemByteBuffer.Bytes() +} + func TestSync(t *testing.T) { nowTime := time.Now() nowMetaTime := metav1.NewTime(nowTime) fixedClock := clock.NewFakeClock(nowTime) + exampleCert := gen.Certificate("test", + gen.SetCertificateDNSNames("example.com"), + gen.SetCertificateIssuer(cmapi.ObjectReference{Name: "test"}), + gen.SetCertificateSecretName("output"), + ) + exampleCertNotFoundCondition := gen.CertificateFrom(exampleCert, + gen.SetCertificateStatusCondition(cmapi.CertificateCondition{ + Type: cmapi.CertificateConditionReady, + Status: cmapi.ConditionFalse, + Reason: "NotFound", + Message: "Certificate does not exist", + LastTransitionTime: nowMetaTime, + }), + ) + pk1 := generatePrivateKey(t) + pk1PEM := pki.EncodePKCS1PrivateKey(pk1) + cert1PEM := generateSelfSignedCert(t, exampleCert, pk1, nowTime, nowTime.Add(time.Hour*12)) + cert1, err := pki.DecodeX509CertificateBytes(cert1PEM) + if err != nil { + t.Errorf("Error decoding test cert1 bytes: %v", err) + t.FailNow() + } + + pk2 := generatePrivateKey(t) + // pk2PEM := pki.EncodePKCS1PrivateKey(pk2) + cert2PEM := generateSelfSignedCert(t, exampleCert, pk2, nowTime, nowTime.Add(time.Hour*24)) + cert2, err := pki.DecodeX509CertificateBytes(cert2PEM) + if err != nil { + t.Errorf("Error decoding test cert2 bytes: %v", err) + t.FailNow() + } + tests := map[string]controllerFixture{ "should update certificate with NotExists if issuer does not return a keypair": { Issuer: gen.Issuer("test", @@ -48,13 +143,12 @@ func TestSync(t *testing.T) { }), gen.SetIssuerSelfSigned(cmapi.SelfSignedIssuer{}), ), - Certificate: *gen.Certificate("test", - gen.SetCertificateDNSNames("example.com"), - gen.SetCertificateIssuer(cmapi.ObjectReference{Name: "test"}), - gen.SetCertificateSecretName("output"), - ), + Certificate: *exampleCert, IssuerImpl: &fake.Issuer{ FakeIssue: func(context.Context, *cmapi.Certificate) (*issuer.IssueResponse, error) { + // By not returning a response, we trigger a 'no-op' action + // which causes the certificate controller to only update + // the status of the Certificate and not create a Secret. return nil, nil }, }, @@ -64,18 +158,7 @@ func TestSync(t *testing.T) { testpkg.NewAction(coretesting.NewUpdateAction( cmapi.SchemeGroupVersion.WithResource("certificates"), gen.DefaultTestNamespace, - gen.Certificate("test", - gen.SetCertificateDNSNames("example.com"), - gen.SetCertificateIssuer(cmapi.ObjectReference{Name: "test"}), - gen.SetCertificateSecretName("output"), - gen.SetCertificateStatusCondition(cmapi.CertificateCondition{ - Type: cmapi.CertificateConditionReady, - Status: cmapi.ConditionFalse, - Reason: "NotFound", - Message: "Certificate does not exist", - LastTransitionTime: nowMetaTime, - }), - ), + exampleCertNotFoundCondition, )), }, }, @@ -83,6 +166,491 @@ func TestSync(t *testing.T) { }, Err: false, }, + "should create a secret containing the private key only when one doesn't exist": { + Issuer: gen.Issuer("test", + gen.AddIssuerCondition(cmapi.IssuerCondition{ + Type: cmapi.IssuerConditionReady, + Status: cmapi.ConditionTrue, + }), + gen.SetIssuerSelfSigned(cmapi.SelfSignedIssuer{}), + ), + Certificate: *exampleCert, + IssuerImpl: &fake.Issuer{ + FakeIssue: func(context.Context, *cmapi.Certificate) (*issuer.IssueResponse, error) { + return &issuer.IssueResponse{ + PrivateKey: pk1PEM, + }, nil + }, + }, + Builder: &testpkg.Builder{ + CertManagerObjects: []runtime.Object{gen.Certificate("test")}, + ExpectedActions: []testpkg.Action{ + testpkg.NewAction(coretesting.NewUpdateAction( + cmapi.SchemeGroupVersion.WithResource("certificates"), + gen.DefaultTestNamespace, + exampleCertNotFoundCondition, + )), + testpkg.NewAction(coretesting.NewGetAction( + corev1.SchemeGroupVersion.WithResource("secrets"), + gen.DefaultTestNamespace, + "output", + )), + testpkg.NewAction(coretesting.NewCreateAction( + corev1.SchemeGroupVersion.WithResource("secrets"), + gen.DefaultTestNamespace, + &corev1.Secret{ + ObjectMeta: metav1.ObjectMeta{ + Namespace: gen.DefaultTestNamespace, + Name: "output", + Labels: map[string]string{ + cmapi.CertificateNameKey: "test", + }, + Annotations: map[string]string{}, + }, + Type: corev1.SecretTypeTLS, + Data: map[string][]byte{ + corev1.TLSCertKey: nil, + corev1.TLSPrivateKeyKey: pk1PEM, + TLSCAKey: nil, + }, + }, + )), + }, + }, + }, + "should update an existing empty secret with the private key": { + Issuer: gen.Issuer("test", + gen.AddIssuerCondition(cmapi.IssuerCondition{ + Type: cmapi.IssuerConditionReady, + Status: cmapi.ConditionTrue, + }), + gen.SetIssuerSelfSigned(cmapi.SelfSignedIssuer{}), + ), + Certificate: *exampleCert, + IssuerImpl: &fake.Issuer{ + FakeIssue: func(context.Context, *cmapi.Certificate) (*issuer.IssueResponse, error) { + return &issuer.IssueResponse{ + PrivateKey: pk1PEM, + }, nil + }, + }, + Builder: &testpkg.Builder{ + KubeObjects: []runtime.Object{ + &corev1.Secret{ + ObjectMeta: metav1.ObjectMeta{ + Namespace: gen.DefaultTestNamespace, + Name: "output", + SelfLink: "abc", + Labels: map[string]string{ + cmapi.CertificateNameKey: "nottest", + }, + Annotations: map[string]string{ + "testannotation": "true", + }, + }, + }, + }, + CertManagerObjects: []runtime.Object{gen.Certificate("test")}, + ExpectedActions: []testpkg.Action{ + testpkg.NewAction(coretesting.NewUpdateAction( + cmapi.SchemeGroupVersion.WithResource("certificates"), + gen.DefaultTestNamespace, + exampleCertNotFoundCondition, + )), + testpkg.NewAction(coretesting.NewGetAction( + corev1.SchemeGroupVersion.WithResource("secrets"), + gen.DefaultTestNamespace, + "output", + )), + testpkg.NewAction(coretesting.NewUpdateAction( + corev1.SchemeGroupVersion.WithResource("secrets"), + gen.DefaultTestNamespace, + &corev1.Secret{ + ObjectMeta: metav1.ObjectMeta{ + Namespace: gen.DefaultTestNamespace, + Name: "output", + SelfLink: "abc", + Labels: map[string]string{ + cmapi.CertificateNameKey: "test", + }, + Annotations: map[string]string{ + "testannotation": "true", + }, + }, + Data: map[string][]byte{ + corev1.TLSCertKey: nil, + corev1.TLSPrivateKeyKey: pk1PEM, + TLSCAKey: nil, + }, + }, + )), + }, + }, + }, + "should create a new secret containing private key and cert": { + Issuer: gen.Issuer("test", + gen.AddIssuerCondition(cmapi.IssuerCondition{ + Type: cmapi.IssuerConditionReady, + Status: cmapi.ConditionTrue, + }), + gen.SetIssuerSelfSigned(cmapi.SelfSignedIssuer{}), + ), + Certificate: *exampleCert, + IssuerImpl: &fake.Issuer{ + FakeIssue: func(context.Context, *cmapi.Certificate) (*issuer.IssueResponse, error) { + return &issuer.IssueResponse{ + PrivateKey: pk1PEM, + Certificate: cert1PEM, + }, nil + }, + }, + Builder: &testpkg.Builder{ + CertManagerObjects: []runtime.Object{gen.Certificate("test")}, + ExpectedActions: []testpkg.Action{ + testpkg.NewAction(coretesting.NewUpdateAction( + cmapi.SchemeGroupVersion.WithResource("certificates"), + gen.DefaultTestNamespace, + exampleCertNotFoundCondition, + )), + testpkg.NewAction(coretesting.NewGetAction( + corev1.SchemeGroupVersion.WithResource("secrets"), + gen.DefaultTestNamespace, + "output", + )), + testpkg.NewAction(coretesting.NewCreateAction( + corev1.SchemeGroupVersion.WithResource("secrets"), + gen.DefaultTestNamespace, + &corev1.Secret{ + ObjectMeta: metav1.ObjectMeta{ + Namespace: gen.DefaultTestNamespace, + Name: "output", + Labels: map[string]string{ + cmapi.CertificateNameKey: "test", + }, + Annotations: map[string]string{ + "certmanager.k8s.io/alt-names": "example.com", + "certmanager.k8s.io/common-name": "example.com", + "certmanager.k8s.io/issuer-kind": "Issuer", + "certmanager.k8s.io/issuer-name": "test", + }, + }, + Data: map[string][]byte{ + corev1.TLSCertKey: cert1PEM, + corev1.TLSPrivateKeyKey: pk1PEM, + TLSCAKey: nil, + }, + Type: corev1.SecretTypeTLS, + }, + )), + }, + }, + }, + "should update an existing secret with private key and cert": { + Issuer: gen.Issuer("test", + gen.AddIssuerCondition(cmapi.IssuerCondition{ + Type: cmapi.IssuerConditionReady, + Status: cmapi.ConditionTrue, + }), + gen.SetIssuerSelfSigned(cmapi.SelfSignedIssuer{}), + ), + Certificate: *exampleCert, + IssuerImpl: &fake.Issuer{ + FakeIssue: func(context.Context, *cmapi.Certificate) (*issuer.IssueResponse, error) { + return &issuer.IssueResponse{ + PrivateKey: pk1PEM, + Certificate: cert1PEM, + }, nil + }, + }, + Builder: &testpkg.Builder{ + KubeObjects: []runtime.Object{ + &corev1.Secret{ + ObjectMeta: metav1.ObjectMeta{ + Namespace: gen.DefaultTestNamespace, + Name: "output", + SelfLink: "abc", + Labels: map[string]string{ + cmapi.CertificateNameKey: "nottest", + }, + Annotations: map[string]string{ + "testannotation": "true", + }, + }, + }, + }, + CertManagerObjects: []runtime.Object{gen.Certificate("test")}, + ExpectedActions: []testpkg.Action{ + testpkg.NewAction(coretesting.NewUpdateAction( + cmapi.SchemeGroupVersion.WithResource("certificates"), + gen.DefaultTestNamespace, + exampleCertNotFoundCondition, + )), + testpkg.NewAction(coretesting.NewGetAction( + corev1.SchemeGroupVersion.WithResource("secrets"), + gen.DefaultTestNamespace, + "output", + )), + testpkg.NewAction(coretesting.NewUpdateAction( + corev1.SchemeGroupVersion.WithResource("secrets"), + gen.DefaultTestNamespace, + &corev1.Secret{ + ObjectMeta: metav1.ObjectMeta{ + Namespace: gen.DefaultTestNamespace, + Name: "output", + SelfLink: "abc", + Labels: map[string]string{ + cmapi.CertificateNameKey: "test", + }, + Annotations: map[string]string{ + "testannotation": "true", + "certmanager.k8s.io/alt-names": "example.com", + "certmanager.k8s.io/common-name": "example.com", + "certmanager.k8s.io/issuer-kind": "Issuer", + "certmanager.k8s.io/issuer-name": "test", + }, + }, + Data: map[string][]byte{ + corev1.TLSCertKey: cert1PEM, + corev1.TLSPrivateKeyKey: pk1PEM, + TLSCAKey: nil, + }, + }, + )), + }, + }, + }, + "should mark certificate with invalid private key as DoesNotMatch": { + Issuer: gen.Issuer("test", + gen.AddIssuerCondition(cmapi.IssuerCondition{ + Type: cmapi.IssuerConditionReady, + Status: cmapi.ConditionTrue, + }), + gen.SetIssuerSelfSigned(cmapi.SelfSignedIssuer{}), + ), + Certificate: *exampleCert, + IssuerImpl: &fake.Issuer{ + FakeIssue: func(context.Context, *cmapi.Certificate) (*issuer.IssueResponse, error) { + return &issuer.IssueResponse{ + PrivateKey: pk1PEM, + Certificate: cert1PEM, + }, nil + }, + }, + Builder: &testpkg.Builder{ + KubeObjects: []runtime.Object{ + &corev1.Secret{ + ObjectMeta: metav1.ObjectMeta{ + Namespace: gen.DefaultTestNamespace, + Name: "output", + SelfLink: "abc", + Labels: map[string]string{ + cmapi.CertificateNameKey: "nottest", + }, + Annotations: map[string]string{ + "testannotation": "true", + }, + }, + Data: map[string][]byte{ + corev1.TLSCertKey: cert2PEM, + corev1.TLSPrivateKeyKey: pk1PEM, + TLSCAKey: nil, + }, + }, + }, + CertManagerObjects: []runtime.Object{gen.Certificate("test")}, + ExpectedActions: []testpkg.Action{ + testpkg.NewAction(coretesting.NewUpdateAction( + cmapi.SchemeGroupVersion.WithResource("certificates"), + gen.DefaultTestNamespace, + gen.CertificateFrom(exampleCert, + gen.SetCertificateStatusCondition(cmapi.CertificateCondition{ + Type: cmapi.CertificateConditionReady, + Status: cmapi.ConditionFalse, + Reason: "DoesNotMatch", + Message: "Certificate private key does not match certificate", + LastTransitionTime: nowMetaTime, + }), + gen.SetCertificateNotAfter(metav1.NewTime(cert2.NotAfter)), + ), + )), + testpkg.NewAction(coretesting.NewGetAction( + corev1.SchemeGroupVersion.WithResource("secrets"), + gen.DefaultTestNamespace, + "output", + )), + testpkg.NewAction(coretesting.NewUpdateAction( + corev1.SchemeGroupVersion.WithResource("secrets"), + gen.DefaultTestNamespace, + &corev1.Secret{ + ObjectMeta: metav1.ObjectMeta{ + Namespace: gen.DefaultTestNamespace, + Name: "output", + SelfLink: "abc", + Labels: map[string]string{ + cmapi.CertificateNameKey: "test", + }, + Annotations: map[string]string{ + "testannotation": "true", + "certmanager.k8s.io/alt-names": "example.com", + "certmanager.k8s.io/common-name": "example.com", + "certmanager.k8s.io/issuer-kind": "Issuer", + "certmanager.k8s.io/issuer-name": "test", + }, + }, + Data: map[string][]byte{ + corev1.TLSCertKey: cert1PEM, + corev1.TLSPrivateKeyKey: pk1PEM, + TLSCAKey: nil, + }, + }, + )), + }, + }, + }, + "should update status of up to date certificate": { + Issuer: gen.Issuer("test", + gen.AddIssuerCondition(cmapi.IssuerCondition{ + Type: cmapi.IssuerConditionReady, + Status: cmapi.ConditionTrue, + }), + gen.SetIssuerSelfSigned(cmapi.SelfSignedIssuer{}), + ), + Certificate: *exampleCert, + IssuerImpl: &fake.Issuer{ + FakeIssue: func(context.Context, *cmapi.Certificate) (*issuer.IssueResponse, error) { + return &issuer.IssueResponse{ + PrivateKey: pk1PEM, + Certificate: cert1PEM, + }, nil + }, + }, + Builder: &testpkg.Builder{ + KubeObjects: []runtime.Object{ + &corev1.Secret{ + ObjectMeta: metav1.ObjectMeta{ + Namespace: gen.DefaultTestNamespace, + Name: "output", + SelfLink: "abc", + Labels: map[string]string{ + cmapi.CertificateNameKey: "test", + }, + Annotations: map[string]string{ + "testannotation": "true", + "certmanager.k8s.io/alt-names": "example.com", + "certmanager.k8s.io/common-name": "example.com", + "certmanager.k8s.io/issuer-kind": "Issuer", + "certmanager.k8s.io/issuer-name": "test", + }, + }, + Data: map[string][]byte{ + corev1.TLSCertKey: cert1PEM, + corev1.TLSPrivateKeyKey: pk1PEM, + TLSCAKey: nil, + }, + }, + }, + CertManagerObjects: []runtime.Object{gen.Certificate("test")}, + ExpectedActions: []testpkg.Action{ + testpkg.NewAction(coretesting.NewUpdateAction( + cmapi.SchemeGroupVersion.WithResource("certificates"), + gen.DefaultTestNamespace, + gen.CertificateFrom(exampleCert, + gen.SetCertificateStatusCondition(cmapi.CertificateCondition{ + Type: cmapi.CertificateConditionReady, + Status: cmapi.ConditionTrue, + Reason: "Ready", + Message: "Certificate is up to date and has not expired", + LastTransitionTime: nowMetaTime, + }), + gen.SetCertificateNotAfter(metav1.NewTime(cert1.NotAfter)), + ), + )), + }, + }, + }, + //"should add annotations to already existing secret resource": { + // Issuer: gen.Issuer("test", + // gen.AddIssuerCondition(cmapi.IssuerCondition{ + // Type: cmapi.IssuerConditionReady, + // Status: cmapi.ConditionTrue, + // }), + // gen.SetIssuerSelfSigned(cmapi.SelfSignedIssuer{}), + // ), + // Certificate: *gen.CertificateFrom(exampleCert, + // gen.SetCertificateStatusCondition(cmapi.CertificateCondition{ + // Type: cmapi.CertificateConditionReady, + // Status: cmapi.ConditionTrue, + // Reason: "Ready", + // Message: "Certificate is up to date and has not expired", + // LastTransitionTime: nowMetaTime, + // }), + // gen.SetCertificateNotAfter(metav1.NewTime(cert1.NotAfter)), + // ), + // IssuerImpl: &fake.Issuer{ + // FakeIssue: func(context.Context, *cmapi.Certificate) (*issuer.IssueResponse, error) { + // return &issuer.IssueResponse{ + // PrivateKey: pk1PEM, + // Certificate: cert1PEM, + // }, nil + // }, + // }, + // Builder: &testpkg.Builder{ + // KubeObjects: []runtime.Object{ + // &corev1.Secret{ + // ObjectMeta: metav1.ObjectMeta{ + // Namespace: gen.DefaultTestNamespace, + // Name: "output", + // SelfLink: "abc", + // Labels: map[string]string{ + // cmapi.CertificateNameKey: "nottest", + // }, + // Annotations: map[string]string{ + // "testannotation": "true", + // }, + // }, + // Data: map[string][]byte{ + // corev1.TLSCertKey: cert1PEM, + // corev1.TLSPrivateKeyKey: pk1PEM, + // TLSCAKey: nil, + // }, + // }, + // }, + // CertManagerObjects: []runtime.Object{gen.Certificate("test")}, + // ExpectedActions: []testpkg.Action{ + // testpkg.NewAction(coretesting.NewGetAction( + // corev1.SchemeGroupVersion.WithResource("secrets"), + // gen.DefaultTestNamespace, + // "output", + // )), + // testpkg.NewAction(coretesting.NewUpdateAction( + // corev1.SchemeGroupVersion.WithResource("secrets"), + // gen.DefaultTestNamespace, + // &corev1.Secret{ + // ObjectMeta: metav1.ObjectMeta{ + // Namespace: gen.DefaultTestNamespace, + // Name: "output", + // SelfLink: "abc", + // Labels: map[string]string{ + // cmapi.CertificateNameKey: "test", + // }, + // Annotations: map[string]string{ + // "testannotation": "true", + // "certmanager.k8s.io/alt-names": "example.com", + // "certmanager.k8s.io/common-name": "example.com", + // "certmanager.k8s.io/issuer-kind": "Issuer", + // "certmanager.k8s.io/issuer-name": "test", + // }, + // }, + // Data: map[string][]byte{ + // corev1.TLSCertKey: cert1PEM, + // corev1.TLSPrivateKeyKey: pk1PEM, + // TLSCAKey: nil, + // }, + // }, + // )), + // }, + // }, + //}, } for n, test := range tests { t.Run(n, func(t *testing.T) { diff --git a/pkg/issuer/fake/fake.go b/pkg/issuer/fake/fake.go index d3bb8347e..b17134ffc 100644 --- a/pkg/issuer/fake/fake.go +++ b/pkg/issuer/fake/fake.go @@ -1,3 +1,19 @@ +/* +Copyright 2019 The Jetstack cert-manager contributors. + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. +*/ + package fake import ( diff --git a/pkg/issuer/helper.go b/pkg/issuer/helper.go index 8b8e9b33e..bc3e6bcc8 100644 --- a/pkg/issuer/helper.go +++ b/pkg/issuer/helper.go @@ -1,3 +1,19 @@ +/* +Copyright 2019 The Jetstack cert-manager contributors. + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. +*/ + package issuer import ( diff --git a/test/unit/gen/certificate.go b/test/unit/gen/certificate.go index a7fbb8b23..25db1abce 100644 --- a/test/unit/gen/certificate.go +++ b/test/unit/gen/certificate.go @@ -35,6 +35,7 @@ func Certificate(name string, mods ...CertificateModifier) *v1alpha1.Certificate } func CertificateFrom(crt *v1alpha1.Certificate, mods ...CertificateModifier) *v1alpha1.Certificate { + crt = crt.DeepCopy() for _, mod := range mods { mod(crt) } @@ -105,3 +106,9 @@ func SetCertificateLastFailureTime(p metav1.Time) CertificateModifier { crt.Status.LastFailureTime = &p } } + +func SetCertificateNotAfter(p metav1.Time) CertificateModifier { + return func(crt *v1alpha1.Certificate) { + crt.Status.NotAfter = &p + } +}