Skip to content

Commit 2d7c381

Browse files
committed
[node_certificate_controller] add unit test and minor refactor
1 parent ec32006 commit 2d7c381

2 files changed

Lines changed: 119 additions & 10 deletions

File tree

internal/controller/node_certificate_controller.go

Lines changed: 16 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -27,13 +27,13 @@ import (
2727
cmmeta "github.com/cert-manager/cert-manager/pkg/apis/meta/v1"
2828
corev1 "k8s.io/api/core/v1"
2929
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
30-
"k8s.io/apimachinery/pkg/labels"
3130
"k8s.io/apimachinery/pkg/runtime"
3231
"k8s.io/client-go/util/retry"
3332
ctrl "sigs.k8s.io/controller-runtime"
3433
k8sclient "sigs.k8s.io/controller-runtime/pkg/client"
3534
"sigs.k8s.io/controller-runtime/pkg/controller/controllerutil"
3635
logger "sigs.k8s.io/controller-runtime/pkg/log"
36+
"sigs.k8s.io/controller-runtime/pkg/predicate"
3737
)
3838

3939
type NodeCertificateController struct {
@@ -53,13 +53,12 @@ func getSecretAndCertName(name string) (string, string) {
5353
func (r *NodeCertificateController) ensureCertificate(ctx context.Context, node *corev1.Node, computeHost string) error {
5454
log := logger.FromContext(ctx)
5555

56-
apiVersion := "cert-manager.io/v1"
5756
secretName, certName := getSecretAndCertName(node.Name)
5857

5958
certificate := &cmapi.Certificate{
6059
TypeMeta: metav1.TypeMeta{
6160
Kind: cmapi.CertificateKind,
62-
APIVersion: apiVersion,
61+
APIVersion: cmapi.SchemeGroupVersion.String(),
6362
},
6463
ObjectMeta: metav1.ObjectMeta{
6564
Name: certName,
@@ -131,7 +130,7 @@ func (r *NodeCertificateController) ensureCertificate(ctx context.Context, node
131130
IssuerRef: cmmeta.ObjectReference{
132131
Name: r.issuerName,
133132
Kind: cmapi.IssuerKind,
134-
Group: "cert-manager.io",
133+
Group: cmapi.SchemeGroupVersion.Group,
135134
},
136135
}
137136
return nil
@@ -163,12 +162,6 @@ func (r *NodeCertificateController) Reconcile(ctx context.Context, req ctrl.Requ
163162
return ctrl.Result{}, k8sclient.IgnoreNotFound(err)
164163
}
165164

166-
found := (labels.Set)(node.Labels).Has(labelHypervisor)
167-
168-
if !found {
169-
return ctrl.Result{}, nil
170-
}
171-
172165
err := retry.RetryOnConflict(retry.DefaultRetry, func() error {
173166
return r.ensureCertificate(ctx, node, node.Name)
174167
})
@@ -185,8 +178,21 @@ func (r *NodeCertificateController) SetupWithManager(mgr ctrl.Manager, namespace
185178
r.namespace = namespace
186179
r.issuerName = issuerName
187180

181+
novaVirtLabeledPredicate, err := predicate.LabelSelectorPredicate(metav1.LabelSelector{
182+
MatchExpressions: []metav1.LabelSelectorRequirement{
183+
{
184+
Key: labelHypervisor,
185+
Operator: metav1.LabelSelectorOpExists,
186+
},
187+
},
188+
})
189+
if err != nil {
190+
return fmt.Errorf("failed to create label selector predicate: %w", err)
191+
}
192+
188193
return ctrl.NewControllerManagedBy(mgr).
189194
Named("certificate").
190195
For(&corev1.Node{}).
196+
WithEventFilter(novaVirtLabeledPredicate).
191197
Complete(r)
192198
}
Lines changed: 103 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,103 @@
1+
/*
2+
SPDX-FileCopyrightText: Copyright 2024 SAP SE or an SAP affiliate company and cobaltcore-dev contributors
3+
SPDX-License-Identifier: Apache-2.0
4+
5+
Licensed under the Apache License, Version 2.0 (the "License");
6+
you may not use this file except in compliance with the License.
7+
You may obtain a copy of the License at
8+
9+
http://www.apache.org/licenses/LICENSE-2.0
10+
11+
Unless required by applicable law or agreed to in writing, software
12+
distributed under the License is distributed on an "AS IS" BASIS,
13+
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
14+
See the License for the specific language governing permissions and
15+
limitations under the License.
16+
*/
17+
18+
package controller
19+
20+
import (
21+
cmapi "github.com/cert-manager/cert-manager/pkg/apis/certmanager/v1"
22+
. "github.com/onsi/ginkgo/v2"
23+
. "github.com/onsi/gomega"
24+
corev1 "k8s.io/api/core/v1"
25+
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
26+
"k8s.io/apimachinery/pkg/runtime"
27+
"k8s.io/apimachinery/pkg/types"
28+
ctrl "sigs.k8s.io/controller-runtime"
29+
"sigs.k8s.io/controller-runtime/pkg/client"
30+
"sigs.k8s.io/controller-runtime/pkg/client/fake"
31+
)
32+
33+
var _ = Describe("Node Certificate Controller", func() {
34+
var nodeCertificateController *NodeCertificateController
35+
var k8sClient client.Client
36+
const (
37+
nodeName = "random-node"
38+
issuerName = "test-issuer"
39+
namespace = "test-namespace"
40+
)
41+
42+
// Setup
43+
44+
BeforeEach(func() {
45+
By("Setting up the test environment")
46+
scheme := runtime.NewScheme()
47+
Expect(corev1.AddToScheme(scheme)).To(Succeed())
48+
Expect(cmapi.AddToScheme(scheme)).To(Succeed())
49+
50+
// We need to use the fake client because the envtest environment does include
51+
// cert-manager CRDs out of the box.
52+
By("Creating the fake client")
53+
k8sClient = fake.NewClientBuilder().WithScheme(scheme).Build()
54+
nodeCertificateController = &NodeCertificateController{
55+
Client: k8sClient,
56+
Scheme: k8sClient.Scheme(),
57+
issuerName: issuerName,
58+
namespace: namespace,
59+
}
60+
61+
By("creating the namespace for the reconciler")
62+
ns := &corev1.Namespace{ObjectMeta: metav1.ObjectMeta{Name: namespace}}
63+
Expect(client.IgnoreAlreadyExists(k8sClient.Create(ctx, ns))).To(Succeed())
64+
65+
By("creating the core resource for the Kind Node")
66+
resource := &corev1.Node{
67+
ObjectMeta: metav1.ObjectMeta{
68+
Name: nodeName,
69+
Labels: map[string]string{labelHypervisor: "test"}, //nolint:goconst
70+
},
71+
}
72+
Expect(k8sClient.Create(ctx, resource)).To(Succeed())
73+
})
74+
75+
AfterEach(func() {
76+
node := &corev1.Node{ObjectMeta: metav1.ObjectMeta{Name: nodeName}}
77+
By("Cleanup the specific node")
78+
Expect(client.IgnoreAlreadyExists(k8sClient.Delete(ctx, node))).To(Succeed())
79+
80+
By("Cleaning up the test environment")
81+
})
82+
83+
// Tests
84+
85+
Context("When reconciling a node with nova virt label", func() {
86+
It("should successfully create a new certificate", func() {
87+
By("Reconciling the node")
88+
req := ctrl.Request{
89+
NamespacedName: types.NamespacedName{Name: nodeName},
90+
}
91+
_, err := nodeCertificateController.Reconcile(ctx, req)
92+
Expect(err).NotTo(HaveOccurred())
93+
94+
By("Checking if the certificate was created")
95+
_, certName := getSecretAndCertName(nodeName)
96+
certificate := &cmapi.Certificate{}
97+
err = k8sClient.Get(ctx, types.NamespacedName{Name: certName, Namespace: namespace}, certificate)
98+
Expect(err).NotTo(HaveOccurred())
99+
Expect(certificate.Spec.IssuerRef.Name).To(Equal(issuerName))
100+
Expect(certificate.Spec.DNSNames).To(ContainElement(nodeName))
101+
})
102+
})
103+
})

0 commit comments

Comments
 (0)