• Home
  • Features
  • Pricing
  • Docs
  • Announcements
  • Sign In

kubevirt / hyperconverged-cluster-operator / 20021419104

08 Dec 2025 08:22AM UTC coverage: 76.505% (-0.2%) from 76.718%
20021419104

Pull #3912

github

web-flow
Merge 5909fb4a9 into cae67e758
Pull Request #3912: CNV-61721: Add ValidatingAdmissionPolicy to validate the HyperConverged namespace

115 of 189 new or added lines in 4 files covered. (60.85%)

5 existing lines in 1 file now uncovered.

8183 of 10696 relevant lines covered (76.51%)

1.81 hits per line

Source File
Press 'n' to go to next uncovered line, 'b' for previous

48.78
/controllers/admissionpolicy/admission_policy_controller.go
1
package admissionpolicy
2

3
import (
4
        "context"
5
        "errors"
6
        "fmt"
7
        "reflect"
8

9
        "github.com/go-logr/logr"
10
        "github.com/google/uuid"
11
        operatorhandler "github.com/operator-framework/operator-lib/handler"
12
        admissionv1 "k8s.io/api/admissionregistration/v1"
13
        k8serrors "k8s.io/apimachinery/pkg/api/errors"
14
        k8stypes "k8s.io/apimachinery/pkg/types"
15
        "sigs.k8s.io/controller-runtime/pkg/client"
16
        "sigs.k8s.io/controller-runtime/pkg/controller"
17
        "sigs.k8s.io/controller-runtime/pkg/event"
18
        "sigs.k8s.io/controller-runtime/pkg/handler"
19
        logf "sigs.k8s.io/controller-runtime/pkg/log"
20
        "sigs.k8s.io/controller-runtime/pkg/manager"
21
        "sigs.k8s.io/controller-runtime/pkg/reconcile"
22
        "sigs.k8s.io/controller-runtime/pkg/source"
23

24
        hcoutil "github.com/kubevirt/hyperconverged-cluster-operator/pkg/util"
25
)
26

27
const controllerName = "admission-policy-controller"
28

29
var (
30
        initLogger = logf.Log.WithName(controllerName)
31

32
        randomConstSuffix = uuid.New().String()
33

34
        startupReq = reconcile.Request{
35
                NamespacedName: k8stypes.NamespacedName{
36
                        Name: "startup-req-" + randomConstSuffix,
37
                },
38
        }
39
)
40

41
// RegisterReconciler creates a new Nodes Reconciler and registers it into manager.
NEW
42
func RegisterReconciler(mgr manager.Manager) error {
×
NEW
43
        startupEvent := make(chan event.GenericEvent, 1)
×
NEW
44
        defer close(startupEvent)
×
NEW
45

×
NEW
46
        r := newReconciler(mgr, startupEvent)
×
NEW
47

×
NEW
48
        startupEvent <- event.GenericEvent{}
×
NEW
49

×
NEW
50
        return add(mgr, r)
×
NEW
51
}
×
52

53
// newReconciler returns a new reconcile.Reconciler
NEW
54
func newReconciler(mgr manager.Manager, startupEvent <-chan event.GenericEvent) *ReconcileAdmissionPolicy {
×
NEW
55
        initLogger.Info("Initializing the admission policy controller")
×
NEW
56

×
NEW
57
        r := &ReconcileAdmissionPolicy{
×
NEW
58
                Client:       mgr.GetClient(),
×
NEW
59
                startupEvent: startupEvent,
×
NEW
60
        }
×
NEW
61

×
NEW
62
        return r
×
NEW
63
}
×
64

65
// add adds a new Controller to mgr with r as the reconcile.Reconciler
NEW
66
func add(mgr manager.Manager, r *ReconcileAdmissionPolicy) error {
×
NEW
67
        // Create a new controller
×
NEW
68
        c, err := controller.New(controllerName, mgr, controller.Options{Reconciler: r})
×
NEW
69
        if err != nil {
×
NEW
70
                return err
×
NEW
71
        }
×
72

73
        // Watch for changes to the ValidatingAdmissionPolicy
NEW
74
        if err = c.Watch(
×
NEW
75
                source.Kind[*admissionv1.ValidatingAdmissionPolicy](
×
NEW
76
                        mgr.GetCache(), &admissionv1.ValidatingAdmissionPolicy{},
×
NEW
77
                        &operatorhandler.InstrumentedEnqueueRequestForObject[*admissionv1.ValidatingAdmissionPolicy]{},
×
NEW
78
                        policyPredicate,
×
NEW
79
                ),
×
NEW
80
        ); err != nil {
×
NEW
81
                return err
×
NEW
82
        }
×
83

84
        // Watch for changes to the ValidatingAdmissionPolicyBinding
NEW
85
        if err = c.Watch(
×
NEW
86
                source.Kind[*admissionv1.ValidatingAdmissionPolicyBinding](
×
NEW
87
                        mgr.GetCache(), &admissionv1.ValidatingAdmissionPolicyBinding{},
×
NEW
88
                        &handler.TypedEnqueueRequestForObject[*admissionv1.ValidatingAdmissionPolicyBinding]{},
×
NEW
89
                        bindingPredicate,
×
NEW
90
                ),
×
NEW
91
        ); err != nil {
×
NEW
92
                return err
×
NEW
93
        }
×
94

NEW
95
        return c.Watch(
×
NEW
96
                source.Channel(
×
NEW
97
                        r.startupEvent,
×
NEW
98
                        handler.EnqueueRequestsFromMapFunc(func(ctx context.Context, a client.Object) []reconcile.Request {
×
NEW
99
                                logr.FromContextOrDiscard(ctx).Info("first reconciliation of ValidatingAdmissionPolicy")
×
NEW
100
                                return []reconcile.Request{startupReq}
×
NEW
101
                        }),
×
102
                ),
103
        )
104
}
105

106
// ReconcileAdmissionPolicy reconciles the ValidatingAdmissionPolicy and ValidatingAdmissionPolicyBinding
107
type ReconcileAdmissionPolicy struct {
108
        client.Client
109
        startupEvent <-chan event.GenericEvent
110
}
111

112
// Reconcile updates the ValidatingAdmissionPolicy and ValidatingAdmissionPolicyBinding
113
func (r *ReconcileAdmissionPolicy) Reconcile(ctx context.Context, req reconcile.Request) (reconcile.Result, error) {
1✔
114
        logger, err := logr.FromContext(ctx)
1✔
115
        if err != nil {
2✔
116
                logger = initLogger.WithValues("Request.Name", req.Name)
1✔
117
        }
1✔
118

119
        logger.Info(fmt.Sprintf("Reconciling admission policy %s", req.Name))
1✔
120

1✔
121
        startup := startupReq == req
1✔
122
        var policyErr, bindingErr error
1✔
123

1✔
124
        if req.Name == policyName || startup {
2✔
125
                policyErr = r.reconcilePolicy(ctx, logger)
1✔
126
        }
1✔
127

128
        if req.Name == policyBindingName || startup {
2✔
129
                bindingErr = r.reconcileBinding(ctx, logger)
1✔
130
        }
1✔
131

132
        err = errors.Join(policyErr, bindingErr)
1✔
133
        if err != nil {
1✔
NEW
134
                logger.Error(err, "Reconciliation failed")
×
NEW
135
        }
×
136

137
        return reconcile.Result{}, err
1✔
138
}
139

140
func (r *ReconcileAdmissionPolicy) reconcilePolicy(ctx context.Context, logger logr.Logger) error {
1✔
141
        policy := getRequiredPolicy()
1✔
142
        key := client.ObjectKeyFromObject(policy)
1✔
143
        foundPolicy := &admissionv1.ValidatingAdmissionPolicy{}
1✔
144

1✔
145
        if err := r.Get(ctx, key, foundPolicy); err != nil {
2✔
146
                if k8serrors.IsNotFound(err) {
2✔
147
                        logger.Info("ValidatingAdmissionPolicy does not exist; creating it", "name", policy.Name)
1✔
148
                        return r.Create(ctx, policy.DeepCopy())
1✔
149
                }
1✔
150

NEW
151
                return err
×
152
        }
153

154
        changed := false
1✔
155
        if !reflect.DeepEqual(foundPolicy.Spec, policy.Spec) {
2✔
156
                policy.Spec.DeepCopyInto(&foundPolicy.Spec)
1✔
157
                changed = true
1✔
158
        }
1✔
159

160
        if !hcoutil.CompareLabels(policy, foundPolicy) {
1✔
NEW
161
                hcoutil.MergeLabels(&policy.ObjectMeta, &foundPolicy.ObjectMeta)
×
NEW
162
                changed = true
×
NEW
163
        }
×
164

165
        if changed {
2✔
166
                logger.Info("ValidatingAdmissionPolicy was modified; updating it", "name", policy.Name)
1✔
167
                return r.Update(ctx, foundPolicy)
1✔
168
        }
1✔
169

NEW
170
        return nil
×
171
}
172

173
func (r *ReconcileAdmissionPolicy) reconcileBinding(ctx context.Context, logger logr.Logger) error {
1✔
174
        binding := getRequiredBinding()
1✔
175

1✔
176
        key := client.ObjectKeyFromObject(binding)
1✔
177
        foundBinding := &admissionv1.ValidatingAdmissionPolicyBinding{}
1✔
178

1✔
179
        if err := r.Get(ctx, key, foundBinding); err != nil {
2✔
180
                if k8serrors.IsNotFound(err) {
2✔
181
                        logger.Info("ValidatingAdmissionPolicyBinding does not exist; creating it", "name", binding.Name)
1✔
182
                        return r.Create(ctx, binding.DeepCopy())
1✔
183
                }
1✔
184

NEW
185
                return err
×
186
        }
187

188
        changed := false
1✔
189
        if !reflect.DeepEqual(foundBinding.Spec, binding.Spec) {
2✔
190
                binding.Spec.DeepCopyInto(&foundBinding.Spec)
1✔
191
                changed = true
1✔
192
        }
1✔
193

194
        if !hcoutil.CompareLabels(binding, foundBinding) {
1✔
NEW
195
                hcoutil.MergeLabels(&binding.ObjectMeta, &foundBinding.ObjectMeta)
×
NEW
196
                changed = true
×
NEW
197
        }
×
198

199
        if changed {
2✔
200
                logger.Info("ValidatingAdmissionPolicyBinding was modified; updating it", "name", binding.Name)
1✔
201
                return r.Update(ctx, foundBinding)
1✔
202
        }
1✔
203

NEW
204
        return nil
×
205
}
STATUS · Troubleshooting · Open an Issue · Sales · Support · CAREERS · ENTERPRISE · START FREE · SCHEDULE DEMO
ANNOUNCEMENTS · TWITTER · TOS & SLA · Supported CI Services · What's a CI service? · Automated Testing

© 2025 Coveralls, Inc