1087 lines
32 KiB
Go
1087 lines
32 KiB
Go
/*
|
|
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 controller
|
|
|
|
import (
|
|
"context"
|
|
"errors"
|
|
"fmt"
|
|
"testing"
|
|
|
|
extv1beta1 "k8s.io/api/extensions/v1beta1"
|
|
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
|
|
"k8s.io/apimachinery/pkg/runtime"
|
|
types "k8s.io/apimachinery/pkg/types"
|
|
coretesting "k8s.io/client-go/testing"
|
|
|
|
cmacme "github.com/jetstack/cert-manager/pkg/apis/acme/v1alpha2"
|
|
cmapi "github.com/jetstack/cert-manager/pkg/apis/certmanager/v1alpha2"
|
|
cmmeta "github.com/jetstack/cert-manager/pkg/apis/meta/v1"
|
|
testpkg "github.com/jetstack/cert-manager/pkg/controller/test"
|
|
"github.com/jetstack/cert-manager/test/unit/gen"
|
|
)
|
|
|
|
const testAcmeTLSAnnotation = "kubernetes.io/tls-acme"
|
|
|
|
func TestShouldSync(t *testing.T) {
|
|
type testT struct {
|
|
Annotations map[string]string
|
|
ShouldSync bool
|
|
}
|
|
tests := []testT{
|
|
{
|
|
Annotations: map[string]string{cmapi.IngressIssuerNameAnnotationKey: ""},
|
|
ShouldSync: true,
|
|
},
|
|
{
|
|
Annotations: map[string]string{cmapi.IngressClusterIssuerNameAnnotationKey: ""},
|
|
ShouldSync: true,
|
|
},
|
|
{
|
|
Annotations: map[string]string{testAcmeTLSAnnotation: "true"},
|
|
ShouldSync: true,
|
|
},
|
|
{
|
|
Annotations: map[string]string{testAcmeTLSAnnotation: "false"},
|
|
ShouldSync: false,
|
|
},
|
|
{
|
|
Annotations: map[string]string{testAcmeTLSAnnotation: ""},
|
|
ShouldSync: false,
|
|
},
|
|
{
|
|
ShouldSync: false,
|
|
},
|
|
}
|
|
for _, test := range tests {
|
|
shouldSync := shouldSync(buildIngress("", "", test.Annotations), []string{"kubernetes.io/tls-acme"})
|
|
if shouldSync != test.ShouldSync {
|
|
t.Errorf("Expected shouldSync=%v for annotations %#v", test.ShouldSync, test.Annotations)
|
|
}
|
|
}
|
|
}
|
|
|
|
func TestSync(t *testing.T) {
|
|
clusterIssuer := gen.ClusterIssuer("issuer-name")
|
|
acmeIssuerNewFormat := gen.Issuer("issuer-name",
|
|
gen.SetIssuerACME(cmacme.ACMEIssuer{}))
|
|
acmeIssuer := gen.Issuer("issuer-name",
|
|
gen.SetIssuerACME(cmacme.ACMEIssuer{}))
|
|
acmeClusterIssuer := gen.ClusterIssuer("issuer-name",
|
|
gen.SetIssuerACME(cmacme.ACMEIssuer{}))
|
|
type testT struct {
|
|
Name string
|
|
Ingress *extv1beta1.Ingress
|
|
Issuer cmapi.GenericIssuer
|
|
IssuerLister []runtime.Object
|
|
ClusterIssuerLister []runtime.Object
|
|
CertificateLister []runtime.Object
|
|
DefaultIssuerName string
|
|
DefaultIssuerKind string
|
|
DefaultIssuerGroup string
|
|
Err bool
|
|
ExpectedCreate []*cmapi.Certificate
|
|
ExpectedUpdate []*cmapi.Certificate
|
|
ExpectedDelete []*cmapi.Certificate
|
|
}
|
|
tests := []testT{
|
|
{
|
|
Name: "return a single HTTP01 Certificate for an ingress with a single valid TLS entry and HTTP01 annotations using edit-in-place",
|
|
Issuer: acmeClusterIssuer,
|
|
Ingress: &extv1beta1.Ingress{
|
|
ObjectMeta: metav1.ObjectMeta{
|
|
Name: "ingress-name",
|
|
Namespace: gen.DefaultTestNamespace,
|
|
Labels: map[string]string{
|
|
"my-test-label": "should be copied",
|
|
},
|
|
Annotations: map[string]string{
|
|
cmapi.IngressClusterIssuerNameAnnotationKey: "issuer-name",
|
|
cmacme.IngressEditInPlaceAnnotationKey: "true",
|
|
},
|
|
UID: types.UID("ingress-name"),
|
|
},
|
|
Spec: extv1beta1.IngressSpec{
|
|
TLS: []extv1beta1.IngressTLS{
|
|
{
|
|
Hosts: []string{"example.com", "www.example.com"},
|
|
SecretName: "example-com-tls",
|
|
},
|
|
},
|
|
},
|
|
},
|
|
ClusterIssuerLister: []runtime.Object{acmeClusterIssuer},
|
|
ExpectedCreate: []*cmapi.Certificate{
|
|
{
|
|
ObjectMeta: metav1.ObjectMeta{
|
|
Name: "example-com-tls",
|
|
Namespace: gen.DefaultTestNamespace,
|
|
Labels: map[string]string{
|
|
"my-test-label": "should be copied",
|
|
},
|
|
Annotations: map[string]string{
|
|
cmacme.ACMECertificateHTTP01IngressNameOverride: "ingress-name",
|
|
cmapi.IssueTemporaryCertificateAnnotation: "true",
|
|
},
|
|
OwnerReferences: buildOwnerReferences("ingress-name", gen.DefaultTestNamespace),
|
|
},
|
|
Spec: cmapi.CertificateSpec{
|
|
DNSNames: []string{"example.com", "www.example.com"},
|
|
SecretName: "example-com-tls",
|
|
IssuerRef: cmmeta.ObjectReference{
|
|
Name: "issuer-name",
|
|
Kind: "ClusterIssuer",
|
|
},
|
|
},
|
|
},
|
|
},
|
|
},
|
|
{
|
|
Name: "create a Certificate with the HTTP01 name override if the given ingress uses http01 annotations",
|
|
Issuer: gen.Issuer(acmeIssuer.Name),
|
|
Ingress: &extv1beta1.Ingress{
|
|
ObjectMeta: metav1.ObjectMeta{
|
|
Name: "ingress-name",
|
|
Namespace: gen.DefaultTestNamespace,
|
|
Labels: map[string]string{
|
|
"my-test-label": "should be copied",
|
|
},
|
|
Annotations: map[string]string{
|
|
cmapi.IngressClusterIssuerNameAnnotationKey: "issuer-name",
|
|
cmacme.IngressEditInPlaceAnnotationKey: "true",
|
|
},
|
|
UID: types.UID("ingress-name"),
|
|
},
|
|
Spec: extv1beta1.IngressSpec{
|
|
TLS: []extv1beta1.IngressTLS{
|
|
{
|
|
Hosts: []string{"example.com", "www.example.com"},
|
|
SecretName: "example-com-tls",
|
|
},
|
|
},
|
|
},
|
|
},
|
|
ClusterIssuerLister: []runtime.Object{acmeClusterIssuer},
|
|
ExpectedCreate: []*cmapi.Certificate{
|
|
{
|
|
ObjectMeta: metav1.ObjectMeta{
|
|
Name: "example-com-tls",
|
|
Namespace: gen.DefaultTestNamespace,
|
|
Labels: map[string]string{
|
|
"my-test-label": "should be copied",
|
|
},
|
|
Annotations: map[string]string{
|
|
cmacme.ACMECertificateHTTP01IngressNameOverride: "ingress-name",
|
|
cmapi.IssueTemporaryCertificateAnnotation: "true",
|
|
},
|
|
OwnerReferences: buildOwnerReferences("ingress-name", gen.DefaultTestNamespace),
|
|
},
|
|
Spec: cmapi.CertificateSpec{
|
|
DNSNames: []string{"example.com", "www.example.com"},
|
|
SecretName: "example-com-tls",
|
|
IssuerRef: cmmeta.ObjectReference{
|
|
Name: "issuer-name",
|
|
Kind: "ClusterIssuer",
|
|
},
|
|
},
|
|
},
|
|
},
|
|
},
|
|
{
|
|
Name: "return a single HTTP01 Certificate for an ingress with a single valid TLS entry and HTTP01 annotations with no ingress class set",
|
|
Issuer: acmeClusterIssuer,
|
|
Ingress: &extv1beta1.Ingress{
|
|
ObjectMeta: metav1.ObjectMeta{
|
|
Name: "ingress-name",
|
|
Namespace: gen.DefaultTestNamespace,
|
|
Annotations: map[string]string{
|
|
cmapi.IngressClusterIssuerNameAnnotationKey: "issuer-name",
|
|
},
|
|
UID: types.UID("ingress-name"),
|
|
},
|
|
Spec: extv1beta1.IngressSpec{
|
|
TLS: []extv1beta1.IngressTLS{
|
|
{
|
|
Hosts: []string{"example.com", "www.example.com"},
|
|
SecretName: "example-com-tls",
|
|
},
|
|
},
|
|
},
|
|
},
|
|
ClusterIssuerLister: []runtime.Object{acmeClusterIssuer},
|
|
ExpectedCreate: []*cmapi.Certificate{
|
|
{
|
|
ObjectMeta: metav1.ObjectMeta{
|
|
Name: "example-com-tls",
|
|
Namespace: gen.DefaultTestNamespace,
|
|
OwnerReferences: buildOwnerReferences("ingress-name", gen.DefaultTestNamespace),
|
|
},
|
|
Spec: cmapi.CertificateSpec{
|
|
DNSNames: []string{"example.com", "www.example.com"},
|
|
SecretName: "example-com-tls",
|
|
IssuerRef: cmmeta.ObjectReference{
|
|
Name: "issuer-name",
|
|
Kind: "ClusterIssuer",
|
|
},
|
|
},
|
|
},
|
|
},
|
|
},
|
|
{
|
|
Name: "return a single HTTP01 Certificate for an ingress with a single valid TLS entry and HTTP01 annotations with a custom ingress class",
|
|
Issuer: acmeClusterIssuer,
|
|
Ingress: &extv1beta1.Ingress{
|
|
ObjectMeta: metav1.ObjectMeta{
|
|
Name: "ingress-name",
|
|
Namespace: gen.DefaultTestNamespace,
|
|
Annotations: map[string]string{
|
|
cmapi.IngressClusterIssuerNameAnnotationKey: "issuer-name",
|
|
cmapi.IngressClassAnnotationKey: "nginx-ing",
|
|
},
|
|
UID: types.UID("ingress-name"),
|
|
},
|
|
Spec: extv1beta1.IngressSpec{
|
|
TLS: []extv1beta1.IngressTLS{
|
|
{
|
|
Hosts: []string{"example.com", "www.example.com"},
|
|
SecretName: "example-com-tls",
|
|
},
|
|
},
|
|
},
|
|
},
|
|
ClusterIssuerLister: []runtime.Object{acmeClusterIssuer},
|
|
ExpectedCreate: []*cmapi.Certificate{
|
|
{
|
|
ObjectMeta: metav1.ObjectMeta{
|
|
Name: "example-com-tls",
|
|
Namespace: gen.DefaultTestNamespace,
|
|
OwnerReferences: buildOwnerReferences("ingress-name", gen.DefaultTestNamespace),
|
|
},
|
|
Spec: cmapi.CertificateSpec{
|
|
DNSNames: []string{"example.com", "www.example.com"},
|
|
SecretName: "example-com-tls",
|
|
IssuerRef: cmmeta.ObjectReference{
|
|
Name: "issuer-name",
|
|
Kind: "ClusterIssuer",
|
|
},
|
|
},
|
|
},
|
|
},
|
|
},
|
|
{
|
|
Name: "return a single HTTP01 Certificate for an ingress with a single valid TLS entry and HTTP01 annotations with a certificate ingress class",
|
|
Issuer: acmeClusterIssuer,
|
|
Ingress: &extv1beta1.Ingress{
|
|
ObjectMeta: metav1.ObjectMeta{
|
|
Name: "ingress-name",
|
|
Namespace: gen.DefaultTestNamespace,
|
|
Annotations: map[string]string{
|
|
cmapi.IngressClusterIssuerNameAnnotationKey: "issuer-name",
|
|
cmapi.IngressACMEIssuerHTTP01IngressClassAnnotationKey: "cert-ing",
|
|
cmapi.IngressClassAnnotationKey: "nginx-ing",
|
|
},
|
|
UID: types.UID("ingress-name"),
|
|
},
|
|
Spec: extv1beta1.IngressSpec{
|
|
TLS: []extv1beta1.IngressTLS{
|
|
{
|
|
Hosts: []string{"example.com", "www.example.com"},
|
|
SecretName: "example-com-tls",
|
|
},
|
|
},
|
|
},
|
|
},
|
|
ClusterIssuerLister: []runtime.Object{acmeClusterIssuer},
|
|
ExpectedCreate: []*cmapi.Certificate{
|
|
{
|
|
ObjectMeta: metav1.ObjectMeta{
|
|
Name: "example-com-tls",
|
|
Namespace: gen.DefaultTestNamespace,
|
|
OwnerReferences: buildOwnerReferences("ingress-name", gen.DefaultTestNamespace),
|
|
Annotations: map[string]string{
|
|
cmacme.ACMECertificateHTTP01IngressClassOverride: "cert-ing",
|
|
},
|
|
},
|
|
Spec: cmapi.CertificateSpec{
|
|
DNSNames: []string{"example.com", "www.example.com"},
|
|
SecretName: "example-com-tls",
|
|
IssuerRef: cmmeta.ObjectReference{
|
|
Name: "issuer-name",
|
|
Kind: "ClusterIssuer",
|
|
},
|
|
},
|
|
},
|
|
},
|
|
},
|
|
{
|
|
Name: "edit-in-place set to false should not trigger editing the ingress in-place",
|
|
Issuer: acmeClusterIssuer,
|
|
Ingress: &extv1beta1.Ingress{
|
|
ObjectMeta: metav1.ObjectMeta{
|
|
Name: "ingress-name",
|
|
Namespace: gen.DefaultTestNamespace,
|
|
Annotations: map[string]string{
|
|
cmapi.IngressClusterIssuerNameAnnotationKey: "issuer-name",
|
|
cmapi.IngressClassAnnotationKey: "nginx-ing",
|
|
cmacme.IngressEditInPlaceAnnotationKey: "false",
|
|
},
|
|
UID: types.UID("ingress-name"),
|
|
},
|
|
Spec: extv1beta1.IngressSpec{
|
|
TLS: []extv1beta1.IngressTLS{
|
|
{
|
|
Hosts: []string{"example.com", "www.example.com"},
|
|
SecretName: "example-com-tls",
|
|
},
|
|
},
|
|
},
|
|
},
|
|
ClusterIssuerLister: []runtime.Object{acmeClusterIssuer},
|
|
ExpectedCreate: []*cmapi.Certificate{
|
|
{
|
|
ObjectMeta: metav1.ObjectMeta{
|
|
Name: "example-com-tls",
|
|
Namespace: gen.DefaultTestNamespace,
|
|
OwnerReferences: buildOwnerReferences("ingress-name", gen.DefaultTestNamespace),
|
|
},
|
|
Spec: cmapi.CertificateSpec{
|
|
DNSNames: []string{"example.com", "www.example.com"},
|
|
SecretName: "example-com-tls",
|
|
IssuerRef: cmmeta.ObjectReference{
|
|
Name: "issuer-name",
|
|
Kind: "ClusterIssuer",
|
|
},
|
|
},
|
|
},
|
|
},
|
|
},
|
|
{
|
|
Name: "return a single DNS01 Certificate for an ingress with a single valid TLS entry",
|
|
Issuer: acmeClusterIssuer,
|
|
Err: true,
|
|
Ingress: &extv1beta1.Ingress{
|
|
ObjectMeta: metav1.ObjectMeta{
|
|
Name: "ingress-name",
|
|
Namespace: gen.DefaultTestNamespace,
|
|
Annotations: map[string]string{
|
|
cmapi.IngressClusterIssuerNameAnnotationKey: "issuer-name",
|
|
},
|
|
UID: types.UID("ingress-name"),
|
|
},
|
|
Spec: extv1beta1.IngressSpec{
|
|
TLS: []extv1beta1.IngressTLS{
|
|
{
|
|
Hosts: []string{"example.com", "www.example.com"},
|
|
SecretName: "example-com-tls",
|
|
},
|
|
},
|
|
},
|
|
},
|
|
ClusterIssuerLister: []runtime.Object{acmeClusterIssuer},
|
|
ExpectedCreate: []*cmapi.Certificate{
|
|
{
|
|
ObjectMeta: metav1.ObjectMeta{
|
|
Name: "example-com-tls",
|
|
Namespace: gen.DefaultTestNamespace,
|
|
OwnerReferences: buildOwnerReferences("ingress-name", gen.DefaultTestNamespace),
|
|
},
|
|
Spec: cmapi.CertificateSpec{
|
|
DNSNames: []string{"example.com", "www.example.com"},
|
|
SecretName: "example-com-tls",
|
|
IssuerRef: cmmeta.ObjectReference{
|
|
Name: "issuer-name",
|
|
Kind: "ClusterIssuer",
|
|
},
|
|
},
|
|
},
|
|
},
|
|
},
|
|
{
|
|
Name: "should return a basic certificate when no provider specific config is provided",
|
|
Issuer: clusterIssuer,
|
|
DefaultIssuerName: "issuer-name",
|
|
DefaultIssuerKind: "ClusterIssuer",
|
|
DefaultIssuerGroup: "cert-manager.io",
|
|
ClusterIssuerLister: []runtime.Object{clusterIssuer},
|
|
Ingress: &extv1beta1.Ingress{
|
|
ObjectMeta: metav1.ObjectMeta{
|
|
Name: "ingress-name",
|
|
Namespace: gen.DefaultTestNamespace,
|
|
Annotations: map[string]string{
|
|
testAcmeTLSAnnotation: "true",
|
|
},
|
|
UID: types.UID("ingress-name"),
|
|
},
|
|
Spec: extv1beta1.IngressSpec{
|
|
TLS: []extv1beta1.IngressTLS{
|
|
{
|
|
Hosts: []string{"example.com", "www.example.com"},
|
|
SecretName: "example-com-tls",
|
|
},
|
|
},
|
|
},
|
|
},
|
|
ExpectedCreate: []*cmapi.Certificate{
|
|
{
|
|
ObjectMeta: metav1.ObjectMeta{
|
|
Name: "example-com-tls",
|
|
Namespace: gen.DefaultTestNamespace,
|
|
OwnerReferences: buildOwnerReferences("ingress-name", gen.DefaultTestNamespace),
|
|
},
|
|
Spec: cmapi.CertificateSpec{
|
|
DNSNames: []string{"example.com", "www.example.com"},
|
|
SecretName: "example-com-tls",
|
|
IssuerRef: cmmeta.ObjectReference{
|
|
Name: "issuer-name",
|
|
Kind: "ClusterIssuer",
|
|
Group: "cert-manager.io",
|
|
},
|
|
},
|
|
},
|
|
},
|
|
},
|
|
{
|
|
Name: "should return an error when no TLS hosts are specified",
|
|
Issuer: acmeIssuer,
|
|
IssuerLister: []runtime.Object{acmeIssuer},
|
|
Err: true,
|
|
Ingress: &extv1beta1.Ingress{
|
|
ObjectMeta: metav1.ObjectMeta{
|
|
Name: "ingress-name",
|
|
Namespace: gen.DefaultTestNamespace,
|
|
Annotations: map[string]string{
|
|
cmapi.IngressIssuerNameAnnotationKey: "issuer-name",
|
|
},
|
|
UID: types.UID("ingress-name"),
|
|
},
|
|
Spec: extv1beta1.IngressSpec{
|
|
TLS: []extv1beta1.IngressTLS{
|
|
{
|
|
SecretName: "example-com-tls",
|
|
},
|
|
},
|
|
},
|
|
},
|
|
},
|
|
{
|
|
Name: "should return an error when no TLS secret name is specified",
|
|
Issuer: acmeIssuer,
|
|
Err: true,
|
|
Ingress: &extv1beta1.Ingress{
|
|
ObjectMeta: metav1.ObjectMeta{
|
|
Name: "ingress-name",
|
|
Namespace: gen.DefaultTestNamespace,
|
|
Annotations: map[string]string{
|
|
cmapi.IngressIssuerNameAnnotationKey: "issuer-name",
|
|
},
|
|
UID: types.UID("ingress-name"),
|
|
},
|
|
Spec: extv1beta1.IngressSpec{
|
|
TLS: []extv1beta1.IngressTLS{
|
|
{
|
|
Hosts: []string{"example.com"},
|
|
},
|
|
},
|
|
},
|
|
},
|
|
IssuerLister: []runtime.Object{acmeIssuer},
|
|
},
|
|
{
|
|
Name: "should error if the specified issuer is not found",
|
|
Err: true,
|
|
Ingress: &extv1beta1.Ingress{
|
|
ObjectMeta: metav1.ObjectMeta{
|
|
Name: "ingress-name",
|
|
Namespace: gen.DefaultTestNamespace,
|
|
Annotations: map[string]string{
|
|
cmapi.IngressIssuerNameAnnotationKey: "invalid-issuer-name",
|
|
},
|
|
UID: types.UID("ingress-name"),
|
|
},
|
|
},
|
|
},
|
|
{
|
|
Name: "should not return any certificates if a correct Certificate already exists",
|
|
Issuer: acmeIssuer,
|
|
IssuerLister: []runtime.Object{acmeIssuer},
|
|
Ingress: &extv1beta1.Ingress{
|
|
ObjectMeta: metav1.ObjectMeta{
|
|
Name: "ingress-name",
|
|
Namespace: gen.DefaultTestNamespace,
|
|
Annotations: map[string]string{
|
|
cmapi.IngressIssuerNameAnnotationKey: "issuer-name",
|
|
},
|
|
UID: types.UID("ingress-name"),
|
|
},
|
|
Spec: extv1beta1.IngressSpec{
|
|
TLS: []extv1beta1.IngressTLS{
|
|
{
|
|
Hosts: []string{"example.com"},
|
|
SecretName: "existing-crt",
|
|
},
|
|
},
|
|
},
|
|
},
|
|
DefaultIssuerKind: "Issuer",
|
|
DefaultIssuerGroup: "cert-manager.io",
|
|
CertificateLister: []runtime.Object{
|
|
&cmapi.Certificate{
|
|
ObjectMeta: metav1.ObjectMeta{
|
|
Name: "existing-crt",
|
|
Namespace: gen.DefaultTestNamespace,
|
|
OwnerReferences: buildOwnerReferences("ingress-name", gen.DefaultTestNamespace),
|
|
},
|
|
Spec: cmapi.CertificateSpec{
|
|
DNSNames: []string{"example.com"},
|
|
SecretName: "existing-crt",
|
|
IssuerRef: cmmeta.ObjectReference{
|
|
Name: "issuer-name",
|
|
Kind: "Issuer",
|
|
Group: "cert-manager.io",
|
|
},
|
|
},
|
|
},
|
|
},
|
|
},
|
|
{
|
|
Name: "should update a certificate if an incorrect Certificate exists",
|
|
Issuer: acmeIssuer,
|
|
IssuerLister: []runtime.Object{acmeIssuer},
|
|
Ingress: &extv1beta1.Ingress{
|
|
ObjectMeta: metav1.ObjectMeta{
|
|
Name: "ingress-name",
|
|
Namespace: gen.DefaultTestNamespace,
|
|
Annotations: map[string]string{
|
|
cmapi.IngressIssuerNameAnnotationKey: "issuer-name",
|
|
},
|
|
UID: types.UID("ingress-name"),
|
|
},
|
|
Spec: extv1beta1.IngressSpec{
|
|
TLS: []extv1beta1.IngressTLS{
|
|
{
|
|
Hosts: []string{"example.com"},
|
|
SecretName: "existing-crt",
|
|
},
|
|
},
|
|
},
|
|
},
|
|
CertificateLister: []runtime.Object{
|
|
buildCertificate("existing-crt",
|
|
gen.DefaultTestNamespace,
|
|
buildOwnerReferences("ingress-name", gen.DefaultTestNamespace),
|
|
),
|
|
},
|
|
DefaultIssuerKind: "Issuer",
|
|
ExpectedUpdate: []*cmapi.Certificate{
|
|
{
|
|
ObjectMeta: metav1.ObjectMeta{
|
|
Name: "existing-crt",
|
|
Namespace: gen.DefaultTestNamespace,
|
|
OwnerReferences: buildOwnerReferences("ingress-name", gen.DefaultTestNamespace),
|
|
},
|
|
Spec: cmapi.CertificateSpec{
|
|
DNSNames: []string{"example.com"},
|
|
SecretName: "existing-crt",
|
|
IssuerRef: cmmeta.ObjectReference{
|
|
Name: "issuer-name",
|
|
Kind: "Issuer",
|
|
},
|
|
},
|
|
},
|
|
},
|
|
},
|
|
{
|
|
Name: "should update an existing Certificate resource with new labels if they do not match those specified on the Ingress",
|
|
Issuer: acmeIssuer,
|
|
IssuerLister: []runtime.Object{acmeIssuerNewFormat},
|
|
Ingress: &extv1beta1.Ingress{
|
|
ObjectMeta: metav1.ObjectMeta{
|
|
Name: "ingress-name",
|
|
Namespace: gen.DefaultTestNamespace,
|
|
Labels: map[string]string{
|
|
"my-test-label": "should be copied",
|
|
},
|
|
Annotations: map[string]string{
|
|
cmapi.IngressIssuerNameAnnotationKey: "issuer-name",
|
|
},
|
|
UID: types.UID("ingress-name"),
|
|
},
|
|
Spec: extv1beta1.IngressSpec{
|
|
TLS: []extv1beta1.IngressTLS{
|
|
{
|
|
Hosts: []string{"example.com"},
|
|
SecretName: "cert-secret-name",
|
|
},
|
|
},
|
|
},
|
|
},
|
|
DefaultIssuerKind: "Issuer",
|
|
CertificateLister: []runtime.Object{
|
|
&cmapi.Certificate{
|
|
ObjectMeta: metav1.ObjectMeta{
|
|
Name: "cert-secret-name",
|
|
Namespace: gen.DefaultTestNamespace,
|
|
Labels: map[string]string{
|
|
"a-different-value": "should be removed",
|
|
},
|
|
OwnerReferences: buildOwnerReferences("ingress-name", gen.DefaultTestNamespace),
|
|
},
|
|
Spec: cmapi.CertificateSpec{
|
|
DNSNames: []string{"example.com"},
|
|
SecretName: "cert-secret-name",
|
|
IssuerRef: cmmeta.ObjectReference{
|
|
Name: "issuer-name",
|
|
Kind: "Issuer",
|
|
},
|
|
},
|
|
},
|
|
},
|
|
ExpectedUpdate: []*cmapi.Certificate{
|
|
{
|
|
ObjectMeta: metav1.ObjectMeta{
|
|
Name: "cert-secret-name",
|
|
Namespace: gen.DefaultTestNamespace,
|
|
Labels: map[string]string{
|
|
"my-test-label": "should be copied",
|
|
},
|
|
OwnerReferences: buildOwnerReferences("ingress-name", gen.DefaultTestNamespace),
|
|
},
|
|
Spec: cmapi.CertificateSpec{
|
|
DNSNames: []string{"example.com"},
|
|
SecretName: "cert-secret-name",
|
|
IssuerRef: cmmeta.ObjectReference{
|
|
Name: "issuer-name",
|
|
Kind: "Issuer",
|
|
},
|
|
},
|
|
},
|
|
},
|
|
},
|
|
{
|
|
Name: "should not update certificate if it does not belong to any ingress",
|
|
Issuer: acmeIssuer,
|
|
IssuerLister: []runtime.Object{acmeIssuer},
|
|
Ingress: &extv1beta1.Ingress{
|
|
ObjectMeta: metav1.ObjectMeta{
|
|
Name: "ingress-name",
|
|
Namespace: gen.DefaultTestNamespace,
|
|
Annotations: map[string]string{
|
|
cmapi.IngressIssuerNameAnnotationKey: "issuer-name",
|
|
cmapi.IngressClassAnnotationKey: "toot-ing",
|
|
},
|
|
UID: types.UID("ingress-name"),
|
|
},
|
|
Spec: extv1beta1.IngressSpec{
|
|
TLS: []extv1beta1.IngressTLS{
|
|
{
|
|
Hosts: []string{"example.com"},
|
|
SecretName: "existing-crt",
|
|
},
|
|
},
|
|
},
|
|
},
|
|
CertificateLister: []runtime.Object{
|
|
&cmapi.Certificate{
|
|
ObjectMeta: metav1.ObjectMeta{
|
|
Name: "existing-crt",
|
|
Namespace: gen.DefaultTestNamespace,
|
|
OwnerReferences: []metav1.OwnerReference{},
|
|
},
|
|
Spec: cmapi.CertificateSpec{
|
|
DNSNames: []string{"example.com"},
|
|
SecretName: "existing-crt",
|
|
IssuerRef: cmmeta.ObjectReference{
|
|
Name: "issuer-name",
|
|
Kind: "Issuer",
|
|
},
|
|
},
|
|
},
|
|
},
|
|
},
|
|
{
|
|
Name: "should not update certificate if it does not belong to the ingress",
|
|
Issuer: acmeIssuer,
|
|
IssuerLister: []runtime.Object{acmeIssuer},
|
|
Ingress: &extv1beta1.Ingress{
|
|
ObjectMeta: metav1.ObjectMeta{
|
|
Name: "ingress-name",
|
|
Namespace: gen.DefaultTestNamespace,
|
|
Annotations: map[string]string{
|
|
cmapi.IngressIssuerNameAnnotationKey: "issuer-name",
|
|
cmapi.IngressClassAnnotationKey: "toot-ing",
|
|
},
|
|
UID: types.UID("ingress-name"),
|
|
},
|
|
Spec: extv1beta1.IngressSpec{
|
|
TLS: []extv1beta1.IngressTLS{
|
|
{
|
|
Hosts: []string{"example.com"},
|
|
SecretName: "existing-crt",
|
|
},
|
|
},
|
|
},
|
|
},
|
|
CertificateLister: []runtime.Object{
|
|
&cmapi.Certificate{
|
|
ObjectMeta: metav1.ObjectMeta{
|
|
Name: "existing-crt",
|
|
Namespace: gen.DefaultTestNamespace,
|
|
OwnerReferences: buildOwnerReferences("not-ingress-name", gen.DefaultTestNamespace),
|
|
},
|
|
Spec: cmapi.CertificateSpec{
|
|
DNSNames: []string{"example.com"},
|
|
SecretName: "existing-crt",
|
|
IssuerRef: cmmeta.ObjectReference{
|
|
Name: "issuer-name",
|
|
Kind: "Issuer",
|
|
},
|
|
},
|
|
},
|
|
},
|
|
},
|
|
{
|
|
Name: "should delete a Certificate if its SecretName is not present in the ingress",
|
|
Issuer: acmeIssuer,
|
|
IssuerLister: []runtime.Object{acmeIssuer},
|
|
Ingress: &extv1beta1.Ingress{
|
|
ObjectMeta: metav1.ObjectMeta{
|
|
Name: "ingress-name",
|
|
Namespace: gen.DefaultTestNamespace,
|
|
Annotations: map[string]string{
|
|
cmapi.IngressIssuerNameAnnotationKey: "issuer-name",
|
|
},
|
|
UID: types.UID("ingress-name"),
|
|
},
|
|
},
|
|
CertificateLister: []runtime.Object{
|
|
&cmapi.Certificate{
|
|
ObjectMeta: metav1.ObjectMeta{
|
|
Name: "existing-crt",
|
|
Namespace: gen.DefaultTestNamespace,
|
|
OwnerReferences: buildOwnerReferences("ingress-name", gen.DefaultTestNamespace),
|
|
},
|
|
Spec: cmapi.CertificateSpec{
|
|
DNSNames: []string{"example.com"},
|
|
SecretName: "existing-crt",
|
|
IssuerRef: cmmeta.ObjectReference{
|
|
Name: "issuer-name",
|
|
Kind: "Issuer",
|
|
},
|
|
},
|
|
},
|
|
},
|
|
ExpectedDelete: []*cmapi.Certificate{
|
|
{
|
|
ObjectMeta: metav1.ObjectMeta{
|
|
Name: "existing-crt",
|
|
Namespace: gen.DefaultTestNamespace,
|
|
OwnerReferences: buildOwnerReferences("ingress-name", gen.DefaultTestNamespace),
|
|
},
|
|
Spec: cmapi.CertificateSpec{
|
|
DNSNames: []string{"example.com"},
|
|
SecretName: "existing-crt",
|
|
IssuerRef: cmmeta.ObjectReference{
|
|
Name: "issuer-name",
|
|
Kind: "Issuer",
|
|
},
|
|
},
|
|
},
|
|
},
|
|
},
|
|
{
|
|
Name: "should update a Certificate if is contains a Common Name that is not defined on the ingress annotations",
|
|
Issuer: acmeIssuer,
|
|
IssuerLister: []runtime.Object{acmeIssuer},
|
|
Ingress: &extv1beta1.Ingress{
|
|
ObjectMeta: metav1.ObjectMeta{
|
|
Name: "ingress-name",
|
|
Namespace: gen.DefaultTestNamespace,
|
|
Annotations: map[string]string{
|
|
cmapi.IngressIssuerNameAnnotationKey: "issuer-name",
|
|
cmapi.IssuerKindAnnotationKey: "Issuer",
|
|
cmapi.IssuerGroupAnnotationKey: "cert-manager.io",
|
|
},
|
|
UID: types.UID("ingress-name"),
|
|
},
|
|
Spec: extv1beta1.IngressSpec{
|
|
TLS: []extv1beta1.IngressTLS{
|
|
{
|
|
Hosts: []string{"example.com"},
|
|
SecretName: "example-com-tls",
|
|
},
|
|
},
|
|
},
|
|
},
|
|
CertificateLister: []runtime.Object{
|
|
&cmapi.Certificate{
|
|
ObjectMeta: metav1.ObjectMeta{
|
|
Name: "example-com-tls",
|
|
Namespace: gen.DefaultTestNamespace,
|
|
OwnerReferences: buildOwnerReferences("ingress-name", gen.DefaultTestNamespace),
|
|
},
|
|
Spec: cmapi.CertificateSpec{
|
|
DNSNames: []string{"example.com"},
|
|
SecretName: "example-com-tls",
|
|
CommonName: "example-common-name",
|
|
IssuerRef: cmmeta.ObjectReference{
|
|
Name: "issuer-name",
|
|
Kind: "Issuer",
|
|
Group: "cert-manager.io",
|
|
},
|
|
},
|
|
},
|
|
},
|
|
ExpectedUpdate: []*cmapi.Certificate{
|
|
{
|
|
ObjectMeta: metav1.ObjectMeta{
|
|
Name: "example-com-tls",
|
|
Namespace: gen.DefaultTestNamespace,
|
|
OwnerReferences: buildOwnerReferences("ingress-name", gen.DefaultTestNamespace),
|
|
},
|
|
Spec: cmapi.CertificateSpec{
|
|
DNSNames: []string{"example.com"},
|
|
SecretName: "example-com-tls",
|
|
IssuerRef: cmmeta.ObjectReference{
|
|
Name: "issuer-name",
|
|
Kind: "Issuer",
|
|
Group: "cert-manager.io",
|
|
},
|
|
},
|
|
},
|
|
},
|
|
},
|
|
}
|
|
testFn := func(test testT) func(t *testing.T) {
|
|
return func(t *testing.T) {
|
|
var allCMObjects []runtime.Object
|
|
allCMObjects = append(allCMObjects, test.IssuerLister...)
|
|
allCMObjects = append(allCMObjects, test.ClusterIssuerLister...)
|
|
allCMObjects = append(allCMObjects, test.CertificateLister...)
|
|
var expectedActions []testpkg.Action
|
|
for _, cr := range test.ExpectedCreate {
|
|
expectedActions = append(expectedActions,
|
|
testpkg.NewAction(coretesting.NewCreateAction(
|
|
cmapi.SchemeGroupVersion.WithResource("certificates"),
|
|
cr.Namespace,
|
|
cr,
|
|
)),
|
|
)
|
|
}
|
|
for _, cr := range test.ExpectedUpdate {
|
|
expectedActions = append(expectedActions,
|
|
testpkg.NewAction(coretesting.NewUpdateAction(
|
|
cmapi.SchemeGroupVersion.WithResource("certificates"),
|
|
cr.Namespace,
|
|
cr,
|
|
)),
|
|
)
|
|
}
|
|
for _, cr := range test.ExpectedDelete {
|
|
expectedActions = append(expectedActions,
|
|
testpkg.NewAction(coretesting.NewDeleteAction(
|
|
cmapi.SchemeGroupVersion.WithResource("certificates"),
|
|
cr.Namespace,
|
|
cr.Name,
|
|
)))
|
|
}
|
|
b := &testpkg.Builder{
|
|
T: t,
|
|
CertManagerObjects: allCMObjects,
|
|
ExpectedActions: expectedActions,
|
|
}
|
|
b.Init()
|
|
defer b.Stop()
|
|
c := &controller{
|
|
kClient: b.Client,
|
|
cmClient: b.CMClient,
|
|
recorder: b.Recorder,
|
|
issuerLister: b.SharedInformerFactory.Certmanager().V1alpha2().Issuers().Lister(),
|
|
clusterIssuerLister: b.SharedInformerFactory.Certmanager().V1alpha2().ClusterIssuers().Lister(),
|
|
certificateLister: b.SharedInformerFactory.Certmanager().V1alpha2().Certificates().Lister(),
|
|
defaults: defaults{
|
|
issuerName: test.DefaultIssuerName,
|
|
issuerKind: test.DefaultIssuerKind,
|
|
issuerGroup: test.DefaultIssuerGroup,
|
|
autoCertificateAnnotations: []string{testAcmeTLSAnnotation},
|
|
},
|
|
helper: &fakeHelper{issuer: test.Issuer},
|
|
}
|
|
b.Start()
|
|
|
|
err := c.Sync(context.Background(), test.Ingress)
|
|
if err != nil && !test.Err {
|
|
t.Errorf("Expected no error, but got: %s", err)
|
|
}
|
|
|
|
if err := b.AllReactorsCalled(); err != nil {
|
|
t.Errorf("Not all expected reactors were called: %v", err)
|
|
}
|
|
if err := b.AllActionsExecuted(); err != nil {
|
|
t.Errorf(err.Error())
|
|
}
|
|
}
|
|
}
|
|
for _, test := range tests {
|
|
t.Run(test.Name, testFn(test))
|
|
}
|
|
}
|
|
|
|
type fakeHelper struct {
|
|
issuer cmapi.GenericIssuer
|
|
}
|
|
|
|
func (f *fakeHelper) GetGenericIssuer(ref cmmeta.ObjectReference, ns string) (cmapi.GenericIssuer, error) {
|
|
if f.issuer == nil {
|
|
return nil, fmt.Errorf("no issuer specified on fake helper")
|
|
}
|
|
return f.issuer, nil
|
|
}
|
|
|
|
func TestIssuerForIngress(t *testing.T) {
|
|
type testT struct {
|
|
Ingress *extv1beta1.Ingress
|
|
DefaultName string
|
|
DefaultKind string
|
|
DefaultGroup string
|
|
ExpectedName string
|
|
ExpectedKind string
|
|
ExpectedGroup string
|
|
ExpectedError error
|
|
}
|
|
tests := []testT{
|
|
{
|
|
Ingress: buildIngress("name", "namespace", map[string]string{
|
|
cmapi.IngressIssuerNameAnnotationKey: "issuer",
|
|
cmapi.IssuerGroupAnnotationKey: "foo.bar",
|
|
}),
|
|
DefaultKind: "Issuer",
|
|
ExpectedName: "issuer",
|
|
ExpectedKind: "Issuer",
|
|
ExpectedGroup: "foo.bar",
|
|
},
|
|
{
|
|
Ingress: buildIngress("name", "namespace", map[string]string{
|
|
cmapi.IngressClusterIssuerNameAnnotationKey: "clusterissuer",
|
|
}),
|
|
ExpectedName: "clusterissuer",
|
|
ExpectedKind: "ClusterIssuer",
|
|
},
|
|
{
|
|
Ingress: buildIngress("name", "namespace", map[string]string{
|
|
testAcmeTLSAnnotation: "true",
|
|
}),
|
|
DefaultName: "default-name",
|
|
DefaultKind: "ClusterIssuer",
|
|
DefaultGroup: "cert-manager.io",
|
|
ExpectedName: "default-name",
|
|
ExpectedKind: "ClusterIssuer",
|
|
ExpectedGroup: "cert-manager.io",
|
|
},
|
|
{
|
|
Ingress: buildIngress("name", "namespace", nil),
|
|
ExpectedError: errors.New("failed to determine issuer name to be used for ingress resource"),
|
|
},
|
|
{
|
|
Ingress: buildIngress("name", "namespace", map[string]string{
|
|
testAcmeTLSAnnotation: "true",
|
|
}),
|
|
ExpectedError: errors.New("failed to determine issuer name to be used for ingress resource"),
|
|
},
|
|
{
|
|
Ingress: buildIngress("name", "namespace", map[string]string{
|
|
cmapi.IngressClusterIssuerNameAnnotationKey: "clusterissuer",
|
|
cmapi.IngressIssuerNameAnnotationKey: "issuer",
|
|
cmapi.IssuerGroupAnnotationKey: "group.io",
|
|
}),
|
|
ExpectedError: errors.New(`both "cert-manager.io/issuer" and "cert-manager.io/cluster-issuer" may not be set, both "cert-manager.io/cluster-issuer" and "cert-manager.io/issuer-group" may not be set`),
|
|
},
|
|
}
|
|
for _, test := range tests {
|
|
c := &controller{
|
|
defaults: defaults{
|
|
issuerKind: test.DefaultKind,
|
|
issuerName: test.DefaultName,
|
|
issuerGroup: test.DefaultGroup,
|
|
},
|
|
}
|
|
name, kind, group, err := c.issuerForIngress(test.Ingress)
|
|
if err != nil {
|
|
if test.ExpectedError == nil || err.Error() != test.ExpectedError.Error() {
|
|
t.Errorf("unexpected error, exp=%v got=%s", test.ExpectedError, err)
|
|
}
|
|
} else if test.ExpectedError != nil {
|
|
t.Errorf("expected error but got nil: %s", test.ExpectedError)
|
|
}
|
|
|
|
if name != test.ExpectedName {
|
|
t.Errorf("expected name to be %q but got %q", test.ExpectedName, name)
|
|
}
|
|
|
|
if kind != test.ExpectedKind {
|
|
t.Errorf("expected kind to be %q but got %q", test.ExpectedKind, kind)
|
|
}
|
|
|
|
if group != test.ExpectedGroup {
|
|
t.Errorf("expected group to be %q but got %q", test.ExpectedGroup, group)
|
|
}
|
|
}
|
|
}
|
|
|
|
func buildCertificate(name, namespace string, ownerReferences []metav1.OwnerReference) *cmapi.Certificate {
|
|
return &cmapi.Certificate{
|
|
ObjectMeta: metav1.ObjectMeta{
|
|
Name: name,
|
|
Namespace: namespace,
|
|
OwnerReferences: ownerReferences,
|
|
},
|
|
Spec: cmapi.CertificateSpec{
|
|
SecretName: name,
|
|
},
|
|
}
|
|
}
|
|
|
|
func buildACMEIssuer(name, namespace string) *cmapi.Issuer {
|
|
return &cmapi.Issuer{
|
|
ObjectMeta: metav1.ObjectMeta{
|
|
Name: name,
|
|
Namespace: namespace,
|
|
},
|
|
Spec: cmapi.IssuerSpec{
|
|
IssuerConfig: cmapi.IssuerConfig{
|
|
ACME: &cmacme.ACMEIssuer{},
|
|
},
|
|
},
|
|
}
|
|
}
|
|
|
|
func buildIngress(name, namespace string, annotations map[string]string) *extv1beta1.Ingress {
|
|
return &extv1beta1.Ingress{
|
|
ObjectMeta: metav1.ObjectMeta{
|
|
Name: name,
|
|
Namespace: namespace,
|
|
Annotations: annotations,
|
|
UID: types.UID(name),
|
|
},
|
|
}
|
|
}
|
|
|
|
func buildOwnerReferences(name, namespace string) []metav1.OwnerReference {
|
|
return []metav1.OwnerReference{
|
|
*metav1.NewControllerRef(buildIngress(name, namespace, nil), ingressGVK),
|
|
}
|
|
}
|