Skip to content

Commit f7fa143

Browse files
authored
Add detection for cert-manager CRDs v1beta1 and v1 (#1710)
* Add support to detect cert manager APIs in version v1beta1 and v1 Signed-off-by: Andreas Neumann <[email protected]>
1 parent 821686d commit f7fa143

19 files changed

+46049
-35
lines changed

pkg/kudoctl/cmd/init_test.go

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -325,7 +325,9 @@ func MockCRD(client *kube.Client, crdName string, apiVersion string) {
325325
Spec: extv1beta1.CustomResourceDefinitionSpec{
326326
Versions: []extv1beta1.CustomResourceDefinitionVersion{
327327
{
328-
Name: apiVersion,
328+
Name: apiVersion,
329+
Served: true,
330+
Storage: true,
329331
},
330332
},
331333
},

pkg/kudoctl/kudoinit/prereq/webhook.go

Lines changed: 41 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -3,6 +3,7 @@ package prereq
33
import (
44
"context"
55
"fmt"
6+
"sort"
67
"strings"
78

89
"github.com/thoas/go-funk"
@@ -14,6 +15,7 @@ import (
1415
"k8s.io/apimachinery/pkg/apis/meta/v1/unstructured"
1516
"k8s.io/apimachinery/pkg/runtime"
1617
"k8s.io/apimachinery/pkg/runtime/schema"
18+
"k8s.io/apimachinery/pkg/version"
1719
"k8s.io/client-go/dynamic"
1820
"k8s.io/client-go/kubernetes"
1921
clientv1beta1 "k8s.io/client-go/kubernetes/typed/admissionregistration/v1beta1"
@@ -52,11 +54,19 @@ const (
5254
var (
5355
// Cert-Manager APIs that we can detect
5456
certManagerAPIs = []certManagerVersion{
55-
{group: "cert-manager.io", versions: []string{"v1alpha2", "v1alpha3"}}, // 0.11.0+
56-
{group: "certmanager.k8s.io", versions: []string{"v1alpha1"}}, // 0.10.1
57+
{group: "cert-manager.io", versions: []string{"v1", "v1beta1", "v1alpha3", "v1alpha2"}}, // 0.11.0+
58+
{group: "certmanager.k8s.io", versions: []string{"v1alpha1"}}, // 0.10.1
5759
}
5860
)
5961

62+
type kubeLikeVersions []string
63+
64+
func (a kubeLikeVersions) Len() int { return len(a) }
65+
func (a kubeLikeVersions) Swap(i, j int) { a[i], a[j] = a[j], a[i] }
66+
func (a kubeLikeVersions) Less(i, j int) bool {
67+
return version.CompareKubeAwareVersionStrings(a[i], a[j]) < 0
68+
}
69+
6070
func NewWebHookInitializer(options kudoinit.Options) *KudoWebHook {
6171
return &KudoWebHook{
6272
opts: options,
@@ -253,9 +263,22 @@ func detectCertManagerCRD(extClient clientset.Interface, api certManagerVersion)
253263
clog.V(4).Printf("Try to retrieve cert-manager CRD %s", testCRD)
254264
crd, err := extClient.ApiextensionsV1beta1().CustomResourceDefinitions().Get(context.TODO(), testCRD, metav1.GetOptions{})
255265
if err == nil {
256-
// crd.Spec.Versions[0] must be the one that is stored and served, we should use that one
257-
clog.V(4).Printf("Got CRD. Group: %s, Version: %s", api.group, crd.Spec.Versions[0].Name)
258-
return api.group, crd.Spec.Versions[0].Name, nil
266+
servedVersions := kubeLikeVersions{}
267+
// Look through the versions and find the one that is the stored one
268+
for _, v := range crd.Spec.Versions {
269+
v := v
270+
if v.Served {
271+
servedVersions = append(servedVersions, v.Name)
272+
}
273+
}
274+
if len(servedVersions) == 0 {
275+
return "", "", fmt.Errorf("failed to detect cert manager CRD %s: no served version found", testCRD)
276+
}
277+
sort.Sort(servedVersions)
278+
bestVersion := servedVersions[len(servedVersions)-1]
279+
280+
clog.V(4).Printf("Got CRD. Group: %s, Version: %s", api.group, bestVersion)
281+
return api.group, bestVersion, nil
259282
}
260283
if !kerrors.IsNotFound(err) {
261284
return "", "", fmt.Errorf("failed to detect cert manager CRD %s: %v", testCRD, err)
@@ -334,12 +357,20 @@ func validateCrdVersion(extClient clientset.Interface, crdName string, expectedV
334357
}
335358
return err
336359
}
337-
crdVersion := certCRD.Spec.Versions[0].Name
338-
339-
if crdVersion != expectedVersion {
340-
result.AddErrors(fmt.Sprintf("invalid CRD version found for '%s': %s instead of %s", crdName, crdVersion, expectedVersion))
360+
allVersions := []string{}
361+
for _, v := range certCRD.Spec.Versions {
362+
if v.Name == expectedVersion {
363+
if v.Served {
364+
clog.V(2).Printf("CRD %s is served with version %s", crdName, v.Name)
365+
return nil
366+
}
367+
result.AddErrors(fmt.Sprintf("outdated CRD version found for '%s': %s is known but not served", crdName, v.Name))
368+
return nil
369+
}
370+
allVersions = append(allVersions, v.Name)
341371
}
342-
clog.V(2).Printf("CRD %s is installed with version %s", crdName, crdVersion)
372+
373+
result.AddErrors(fmt.Sprintf("CRD versions for '%s' are %v, did not find expected version %s or it is not served", crdName, allVersions, expectedVersion))
343374
return nil
344375
}
345376

pkg/kudoctl/kudoinit/prereq/webhook_test.go

Lines changed: 73 additions & 24 deletions
Original file line numberDiff line numberDiff line change
@@ -51,7 +51,7 @@ func TestPrereq_Fail_PreValidate_Webhook_WrongCertificateVersion(t *testing.T) {
5151
_ = init.PreInstallVerify(client, &result)
5252

5353
assert.EqualValues(t, verifier.NewWarning(
54-
"Detected cert-manager CRDs with version v0, only versions [v1alpha2 v1alpha3] are fully supported. Certificates for webhooks may not work.",
54+
"Detected cert-manager CRDs with version v0, only versions [v1 v1beta1 v1alpha3 v1alpha2] are fully supported. Certificates for webhooks may not work.",
5555
), result)
5656
}
5757

@@ -67,7 +67,7 @@ func TestPrereq_Fail_PreValidate_Webhook_WrongCertManagerInstallation(t *testing
6767
_ = init.PreInstallVerify(client, &result)
6868

6969
assert.EqualValues(t, verifier.NewError(
70-
"invalid CRD version found for 'issuers.cert-manager.io': v0 instead of v1alpha2",
70+
"CRD versions for 'issuers.cert-manager.io' are [v0], did not find expected version v1alpha2 or it is not served",
7171
), result)
7272
}
7373

@@ -95,7 +95,7 @@ func TestPrereq_Fail_PreValidate_Webhook_WrongIssuerVersion(t *testing.T) {
9595
result := verifier.NewResult()
9696
_ = init.PreInstallVerify(client, &result)
9797

98-
assert.EqualValues(t, verifier.NewError("invalid CRD version found for 'issuers.cert-manager.io': v0 instead of v1alpha2"), result)
98+
assert.EqualValues(t, verifier.NewError("CRD versions for 'issuers.cert-manager.io' are [v0], did not find expected version v1alpha2 or it is not served"), result)
9999
}
100100

101101
func TestPrereq_Ok_PreValidate_Webhook_CertManager_v1alpha2(t *testing.T) {
@@ -126,32 +126,81 @@ func TestPrereq_Ok_PreValidate_Webhook_CertManager_v1alpha1(t *testing.T) {
126126
assert.Equal(t, 0, len(result.Errors))
127127
}
128128

129-
func mockCRD(client *kube.Client, crdName string, apiVersion string) {
130-
client.ExtClient.(*apiextensionsfake.Clientset).Fake.PrependReactor("get", "customresourcedefinitions", func(action testing2.Action) (handled bool, ret runtime.Object, err error) {
129+
func TestPrereq_Ok_PreValidate_Webhook_CertManager_MultipleVersions(t *testing.T) {
130+
client := getFakeClient()
131+
132+
cert := createCrd("certificates.certmanager.k8s.io", "v1alpha1")
133+
cert.Spec.Versions = append(cert.Spec.Versions, apiextensions.CustomResourceDefinitionVersion{
134+
Name: "v1beta1",
135+
Served: true,
136+
Storage: false,
137+
})
138+
cert.Spec.Versions = append(cert.Spec.Versions, apiextensions.CustomResourceDefinitionVersion{
139+
Name: "v1beta2",
140+
Served: true,
141+
Storage: false,
142+
})
143+
144+
issuer := createCrd("issuers.certmanager.k8s.io", "v1alpha1")
145+
issuer.Spec.Versions = append(cert.Spec.Versions, apiextensions.CustomResourceDefinitionVersion{
146+
Name: "v1beta1",
147+
Served: true,
148+
Storage: false,
149+
})
150+
issuer.Spec.Versions = append(cert.Spec.Versions, apiextensions.CustomResourceDefinitionVersion{
151+
Name: "v1beta2",
152+
Served: true,
153+
Storage: false,
154+
})
131155

156+
mockFullCRD(client, cert)
157+
mockFullCRD(client, issuer)
158+
159+
init := NewWebHookInitializer(kudoinit.NewOptions("", "", "", false, false))
160+
161+
result := verifier.NewResult()
162+
_ = init.PreInstallVerify(client, &result)
163+
164+
assert.Equal(t, init.certManagerAPIVersion, "v1beta2")
165+
166+
assert.Equal(t, 0, len(result.Errors))
167+
}
168+
169+
func mockFullCRD(client *kube.Client, definition *apiextensions.CustomResourceDefinition) {
170+
client.ExtClient.(*apiextensionsfake.Clientset).Fake.PrependReactor("get", "customresourcedefinitions", func(action testing2.Action) (handled bool, ret runtime.Object, err error) {
132171
getAction, _ := action.(testing2.GetAction)
133172
if getAction != nil {
134-
if getAction.GetName() == crdName {
135-
crd := &apiextensions.CustomResourceDefinition{
136-
TypeMeta: metav1.TypeMeta{
137-
APIVersion: apiVersion,
138-
},
139-
ObjectMeta: metav1.ObjectMeta{
140-
Name: crdName,
141-
},
142-
Spec: apiextensions.CustomResourceDefinitionSpec{
143-
Versions: []apiextensions.CustomResourceDefinitionVersion{
144-
{
145-
Name: apiVersion,
146-
},
147-
},
148-
},
149-
Status: apiextensions.CustomResourceDefinitionStatus{},
150-
}
151-
return true, crd, nil
173+
if getAction.GetName() == definition.Name {
174+
return true, definition, nil
152175
}
153176
}
154-
155177
return false, nil, nil
156178
})
157179
}
180+
181+
func createCrd(crdName string, apiVersion string) *apiextensions.CustomResourceDefinition {
182+
return &apiextensions.CustomResourceDefinition{
183+
TypeMeta: metav1.TypeMeta{
184+
APIVersion: apiVersion,
185+
},
186+
ObjectMeta: metav1.ObjectMeta{
187+
Name: crdName,
188+
},
189+
Spec: apiextensions.CustomResourceDefinitionSpec{
190+
Versions: []apiextensions.CustomResourceDefinitionVersion{
191+
{
192+
Name: apiVersion,
193+
Served: true,
194+
Storage: true,
195+
},
196+
},
197+
},
198+
Status: apiextensions.CustomResourceDefinitionStatus{},
199+
}
200+
}
201+
202+
func mockCRD(client *kube.Client, crdName string, apiVersion string) {
203+
def := createCrd(crdName, apiVersion)
204+
mockFullCRD(client, def)
205+
206+
}
Lines changed: 23 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,23 @@
1+
apiVersion: apiextensions.k8s.io/v1
2+
kind: CustomResourceDefinition
3+
metadata:
4+
name: issuers.cert-manager.io
5+
spec:
6+
versions:
7+
- name: v1alpha2
8+
- name: v1alpha3
9+
- name: v1beta1
10+
---
11+
apiVersion: apps/v1
12+
kind: Deployment
13+
metadata:
14+
name: cert-manager-webhook
15+
namespace: cert-manager
16+
status:
17+
readyReplicas: 1
18+
---
19+
apiVersion: v1
20+
kind: Secret
21+
metadata:
22+
name: cert-manager-webhook-ca
23+
namespace: cert-manager
Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,4 @@
1+
apiVersion: kudo.dev/v1beta1
2+
kind: TestStep
3+
commands:
4+
- command: kubectl apply --validate=false -f cert-manager/cert-manager-0.16.0.yaml
Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,11 @@
1+
apiVersion: cert-manager.io/v1beta1
2+
kind: Issuer
3+
metadata:
4+
name: selfsigned-issuer
5+
namespace: kudo-system
6+
---
7+
apiVersion: cert-manager.io/v1beta1
8+
kind: Certificate
9+
metadata:
10+
name: kudo-webhook-server-certificate
11+
namespace: kudo-system
Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,5 @@
1+
apiVersion: kudo.dev/v1beta1
2+
kind: TestStep
3+
commands:
4+
- command: sleep 10
5+
- command: kubectl kudo init -v 4 --kudo-image kudobuilder/controller:test --kudo-image-pull-policy IfNotPresent --wait
Lines changed: 26 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,26 @@
1+
apiVersion: apiextensions.k8s.io/v1beta1
2+
kind: CustomResourceDefinition
3+
metadata:
4+
name: instances.kudo.dev
5+
spec:
6+
group: kudo.dev
7+
names:
8+
kind: Instance
9+
---
10+
apiVersion: apiextensions.k8s.io/v1beta1
11+
kind: CustomResourceDefinition
12+
metadata:
13+
name: operators.kudo.dev
14+
spec:
15+
group: kudo.dev
16+
names:
17+
kind: Operator
18+
---
19+
apiVersion: apiextensions.k8s.io/v1beta1
20+
kind: CustomResourceDefinition
21+
metadata:
22+
name: operatorversions.kudo.dev
23+
spec:
24+
group: kudo.dev
25+
names:
26+
kind: OperatorVersion
Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,4 @@
1+
apiVersion: kudo.dev/v1beta1
2+
kind: TestStep
3+
commands:
4+
- script: kubectl kudo init --upgrade --kudo-image kudobuilder/controller:test --kudo-image-pull-policy IfNotPresent --dry-run --output yaml | tee output.log | kubectl delete -f -
Lines changed: 23 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,23 @@
1+
apiVersion: apiextensions.k8s.io/v1
2+
kind: CustomResourceDefinition
3+
metadata:
4+
name: issuers.cert-manager.io
5+
spec:
6+
versions:
7+
- name: v1alpha2
8+
- name: v1alpha3
9+
- name: v1beta1
10+
---
11+
apiVersion: apps/v1
12+
kind: Deployment
13+
metadata:
14+
name: cert-manager-webhook
15+
namespace: cert-manager
16+
status:
17+
readyReplicas: 1
18+
---
19+
apiVersion: v1
20+
kind: Secret
21+
metadata:
22+
name: cert-manager-webhook-ca
23+
namespace: cert-manager

0 commit comments

Comments
 (0)