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

kubevirt / containerized-data-importer / #5477

15 Jul 2025 02:02PM UTC coverage: 59.527% (+0.03%) from 59.502%
#5477

Pull #3841

travis-ci

akalenyu
stop opinionating webhook namespaceselector

CDI opinionates the namespace selector field
which makes it play badly in case something is mutating
this field.
Since we don't care we can just leave empty and allow
merging with our desired spec.

Signed-off-by: Alex Kalenyuk <akalenyu@redhat.com>
Pull Request #3841: stop opinionating webhook namespaceselector field

24 of 28 new or added lines in 2 files covered. (85.71%)

4 existing lines in 1 file now uncovered.

17104 of 28733 relevant lines covered (59.53%)

0.66 hits per line

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

52.62
/pkg/operator/controller/callbacks.go
1
/*
2
Copyright 2018 The CDI Authors.
3

4
Licensed under the Apache License, Version 2.0 (the "License");
5
you may not use this file except in compliance with the License.
6
You may obtain a copy of the License at
7

8
    http://www.apache.org/licenses/LICENSE-2.0
9

10
Unless required by applicable law or agreed to in writing, software
11
distributed under the License is distributed on an "AS IS" BASIS,
12
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13
See the License for the specific language governing permissions and
14
limitations under the License.
15
*/
16

17
package controller
18

19
import (
20
        "context"
21
        "fmt"
22
        "reflect"
23

24
        "github.com/go-logr/logr"
25

26
        admissionregistrationv1 "k8s.io/api/admissionregistration/v1"
27
        appsv1 "k8s.io/api/apps/v1"
28
        corev1 "k8s.io/api/core/v1"
29
        extv1 "k8s.io/apiextensions-apiserver/pkg/apis/apiextensions/v1"
30
        "k8s.io/apimachinery/pkg/api/errors"
31
        "k8s.io/apimachinery/pkg/api/meta"
32
        metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
33
        "k8s.io/apimachinery/pkg/apis/meta/v1/unstructured"
34
        "k8s.io/apimachinery/pkg/labels"
35
        "k8s.io/apimachinery/pkg/runtime"
36
        "k8s.io/apimachinery/pkg/runtime/schema"
37

38
        "sigs.k8s.io/controller-runtime/pkg/client"
39
        "sigs.k8s.io/controller-runtime/pkg/controller/controllerutil"
40

41
        cdiv1 "kubevirt.io/containerized-data-importer-api/pkg/apis/core/v1beta1"
42
        "kubevirt.io/containerized-data-importer/pkg/common"
43
        cdicontroller "kubevirt.io/containerized-data-importer/pkg/controller"
44
        cc "kubevirt.io/containerized-data-importer/pkg/controller/common"
45
        featuregates "kubevirt.io/containerized-data-importer/pkg/feature-gates"
46
        "kubevirt.io/containerized-data-importer/pkg/operator/resources/cluster"
47
        "kubevirt.io/containerized-data-importer/pkg/operator/resources/utils"
48
        sdk "kubevirt.io/controller-lifecycle-operator-sdk/pkg/sdk"
49
        "kubevirt.io/controller-lifecycle-operator-sdk/pkg/sdk/callbacks"
50
)
51

52
func addReconcileCallbacks(r *ReconcileCDI) {
1✔
53
        r.reconciler.AddCallback(&appsv1.Deployment{}, reconcileDeleteControllerDeployment)
1✔
54
        r.reconciler.AddCallback(&appsv1.Deployment{}, reconcileUpdateControllerDeploymentSelector)
1✔
55
        r.reconciler.AddCallback(&corev1.ServiceAccount{}, reconcileSCC)
1✔
56
        r.reconciler.AddCallback(&appsv1.Deployment{}, reconcileCreatePrometheusInfra)
1✔
57
        r.reconciler.AddCallback(&appsv1.Deployment{}, reconcileRemainingRelationshipLabels)
1✔
58
        r.reconciler.AddCallback(&appsv1.Deployment{}, reconcileDeleteDeprecatedResources)
1✔
59
        r.reconciler.AddCallback(&appsv1.Deployment{}, reconcileCDICRD)
1✔
60
        r.reconciler.AddCallback(&appsv1.Deployment{}, reconcilePvcMutatingWebhook)
1✔
61
        r.reconciler.AddCallback(&extv1.CustomResourceDefinition{}, reconcileSetConfigAuthority)
1✔
62
        r.reconciler.AddCallback(&extv1.CustomResourceDefinition{}, reconcileHandleOldVersion)
1✔
63
        if r.haveRoutes {
2✔
64
                r.reconciler.AddCallback(&appsv1.Deployment{}, reconcileRoute)
1✔
65
        }
1✔
66
}
67

68
func isControllerDeployment(d *appsv1.Deployment) bool {
1✔
69
        return d.Name == "cdi-deployment"
1✔
70
}
1✔
71

72
func reconcileUpdateControllerDeploymentSelector(args *callbacks.ReconcileCallbackArgs) error {
1✔
73
        if args.State != callbacks.ReconcileStatePostRead {
2✔
74
                return nil
1✔
75
        }
1✔
76

77
        if args.CurrentObject == nil || args.DesiredObject == nil {
1✔
78
                return nil
×
79
        }
×
80

81
        deployment := args.DesiredObject.(*appsv1.Deployment)
1✔
82

1✔
83
        if !isControllerDeployment(deployment) {
2✔
84
                return nil
1✔
85
        }
1✔
86

87
        if !reflect.DeepEqual(args.CurrentObject.(*appsv1.Deployment).Spec.Selector.MatchLabels, deployment.Spec.Selector.MatchLabels) {
2✔
88
                args.Logger.Info("Mismatching selector detected for CDI deployment, cleaning up")
1✔
89
                if err := deleteControllerDeployment(deployment, args); err != nil {
1✔
90
                        return err
×
91
                }
×
92
        }
93

94
        return nil
1✔
95
}
96

97
func reconcileDeleteControllerDeployment(args *callbacks.ReconcileCallbackArgs) error {
1✔
98
        switch args.State {
1✔
99
        case callbacks.ReconcileStatePostDelete, callbacks.ReconcileStateOperatorDelete:
1✔
100
        default:
1✔
101
                return nil
1✔
102
        }
103

104
        var deployment *appsv1.Deployment
1✔
105
        if args.DesiredObject != nil {
2✔
106
                deployment = args.DesiredObject.(*appsv1.Deployment)
1✔
107
        } else if args.CurrentObject != nil {
3✔
108
                deployment = args.CurrentObject.(*appsv1.Deployment)
1✔
109
        } else {
1✔
110
                args.Logger.Info("Received callback with no desired/current object")
×
111
                return nil
×
112
        }
×
113

114
        if !isControllerDeployment(deployment) {
2✔
115
                return nil
1✔
116
        }
1✔
117

118
        if err := deleteControllerDeployment(deployment, args); err != nil {
1✔
119
                return err
×
120
        }
×
121

122
        cr := args.Resource.(runtime.Object)
1✔
123
        if err := deleteWorkerResources(args.Logger, args.Client); err != nil {
1✔
124
                args.Logger.Error(err, "Error deleting worker resources")
×
125
                args.Recorder.Event(cr, corev1.EventTypeWarning, deleteResourceFailed, fmt.Sprintf("Failed to deleted worker resources %v", err))
×
126
                return err
×
127
        }
×
128
        args.Recorder.Event(cr, corev1.EventTypeNormal, deleteResourceSuccess, "Deleted worker resources successfully")
1✔
129

1✔
130
        return nil
1✔
131
}
132

133
func deleteControllerDeployment(deployment *appsv1.Deployment, args *callbacks.ReconcileCallbackArgs) error {
1✔
134
        args.Logger.Info("Deleting CDI deployment and all import/upload/clone pods/services")
1✔
135
        err := args.Client.Delete(context.TODO(), deployment, &client.DeleteOptions{
1✔
136
                PropagationPolicy: &[]metav1.DeletionPropagation{metav1.DeletePropagationForeground}[0],
1✔
137
        })
1✔
138
        cr := args.Resource.(runtime.Object)
1✔
139
        if err != nil && !errors.IsNotFound(err) {
1✔
140
                args.Logger.Error(err, "Error deleting cdi controller deployment")
×
141
                args.Recorder.Event(cr, corev1.EventTypeWarning, deleteResourceFailed, fmt.Sprintf("Failed to delete deployment %s, %v", deployment.Name, err))
×
142
                return err
×
143
        }
×
144
        args.Recorder.Event(cr, corev1.EventTypeNormal, deleteResourceSuccess, fmt.Sprintf("Deleted deployment %s successfully", deployment.Name))
1✔
145

1✔
146
        return nil
1✔
147
}
148

149
func reconcileRoute(args *callbacks.ReconcileCallbackArgs) error {
1✔
150
        if args.State != callbacks.ReconcileStatePostRead {
2✔
151
                return nil
1✔
152
        }
1✔
153

154
        deployment := args.CurrentObject.(*appsv1.Deployment)
1✔
155
        if !isControllerDeployment(deployment) || !sdk.CheckDeploymentReady(deployment) {
2✔
156
                return nil
1✔
157
        }
1✔
158

159
        cr := args.Resource.(runtime.Object)
1✔
160
        updated, err := ensureUploadProxyRouteExists(context.TODO(), args.Logger, args.Client, args.Scheme, deployment)
1✔
161
        if err != nil {
1✔
162
                args.Recorder.Event(cr, corev1.EventTypeWarning, createResourceFailed, fmt.Sprintf("Failed to ensure upload proxy route exists, %v", err))
×
163
                return err
×
164
        }
×
165

166
        if updated {
2✔
167
                args.Recorder.Event(cr, corev1.EventTypeNormal, createResourceSuccess, "Successfully ensured upload proxy route exists")
1✔
168
        }
1✔
169

170
        if err := updateUserRoutes(context.TODO(), args.Logger, args.Client, args.Recorder); err != nil {
1✔
171
                return err
×
172
        }
×
173

174
        return nil
1✔
175
}
176

177
func reconcileSCC(args *callbacks.ReconcileCallbackArgs) error {
1✔
178
        switch args.State {
1✔
179
        case callbacks.ReconcileStatePreCreate, callbacks.ReconcileStatePostRead:
1✔
180
        default:
1✔
181
                return nil
1✔
182
        }
183

184
        sa := args.DesiredObject.(*corev1.ServiceAccount)
1✔
185
        if sa.Name != common.ControllerServiceAccountName {
2✔
186
                return nil
1✔
187
        }
1✔
188

189
        cr := args.Resource.(runtime.Object)
1✔
190
        updated, err := ensureSCCExists(context.TODO(), args.Logger, args.Client, args.Namespace, common.ControllerServiceAccountName, common.CronJobServiceAccountName)
1✔
191
        if err != nil {
1✔
192
                args.Recorder.Event(cr, corev1.EventTypeWarning, createResourceFailed, fmt.Sprintf("Failed to ensure SecurityContextConstraint exists, %v", err))
×
193
                return err
×
194
        }
×
195

196
        if updated {
2✔
197
                args.Recorder.Event(cr, corev1.EventTypeNormal, createResourceSuccess, "Successfully ensured SecurityContextConstraint exists")
1✔
198
        }
1✔
199

200
        return nil
1✔
201
}
202

203
func reconcileCreatePrometheusInfra(args *callbacks.ReconcileCallbackArgs) error {
1✔
204
        if args.State != callbacks.ReconcileStatePostRead {
2✔
205
                return nil
1✔
206
        }
1✔
207

208
        deployment := args.CurrentObject.(*appsv1.Deployment)
1✔
209
        // we don't check sdk.CheckDeploymentReady(deployment) since we want Prometheus to cover NotReady state as well
1✔
210
        if !isControllerDeployment(deployment) {
2✔
211
                return nil
1✔
212
        }
1✔
213

214
        cr := args.Resource.(runtime.Object)
1✔
215
        namespace := deployment.GetNamespace()
1✔
216
        if namespace == "" {
1✔
217
                return fmt.Errorf("cluster scoped owner not supported")
×
218
        }
×
219

220
        if deployed, err := isPrometheusDeployed(args.Logger, args.Client, namespace); err != nil {
1✔
221
                return err
×
222
        } else if !deployed {
1✔
223
                return nil
×
224
        }
×
225
        if err := ensurePrometheusResourcesExist(context.TODO(), args.Client, args.Scheme, deployment); err != nil {
1✔
226
                args.Recorder.Event(cr, corev1.EventTypeWarning, createResourceFailed, fmt.Sprintf("Failed to ensure prometheus resources exists, %v", err))
×
227
                return err
×
228
        }
×
229

230
        return nil
1✔
231
}
232

233
func deleteWorkerResources(l logr.Logger, c client.Client) error {
1✔
234
        listTypes := []client.ObjectList{&corev1.PodList{}, &corev1.ServiceList{}}
1✔
235

1✔
236
        ls, err := labels.Parse(fmt.Sprintf("cdi.kubevirt.io in (%s, %s, %s)",
1✔
237
                common.ImporterPodName, common.UploadServerCDILabel, common.ClonerSourcePodName))
1✔
238
        if err != nil {
1✔
239
                return err
×
240
        }
×
241

242
        for _, lt := range listTypes {
2✔
243
                lo := &client.ListOptions{
1✔
244
                        LabelSelector: ls,
1✔
245
                }
1✔
246

1✔
247
                l.V(1).Info("Deleting worker resources", "type", reflect.TypeOf(lt).Elem().Name())
1✔
248

1✔
249
                if err := cc.BulkDeleteResources(context.TODO(), c, lt, lo); err != nil {
1✔
250
                        return err
×
251
                }
×
252
        }
253

254
        return nil
1✔
255
}
256

257
func reconcileSetConfigAuthority(args *callbacks.ReconcileCallbackArgs) error {
1✔
258
        if args.State != callbacks.ReconcileStatePostRead {
2✔
259
                return nil
1✔
260
        }
1✔
261

262
        crd := args.CurrentObject.(*extv1.CustomResourceDefinition)
1✔
263
        if crd.Name != "cdiconfigs.cdi.kubevirt.io" {
2✔
264
                return nil
1✔
265
        }
1✔
266

267
        cdi, ok := args.Resource.(*cdiv1.CDI)
1✔
268
        if !ok {
1✔
269
                return nil
×
270
        }
×
271

272
        if _, ok = cdi.Annotations[cdicontroller.AnnConfigAuthority]; ok {
2✔
273
                return nil
1✔
274
        }
1✔
275

276
        if cdi.Spec.Config == nil {
2✔
277
                cl := &cdiv1.CDIConfigList{}
1✔
278
                err := args.Client.List(context.TODO(), cl)
1✔
279
                if err != nil {
1✔
280
                        if meta.IsNoMatchError(err) {
×
281
                                return nil
×
282
                        }
×
283

284
                        return err
×
285
                }
286

287
                if len(cl.Items) != 1 {
2✔
288
                        return nil
1✔
289
                }
1✔
290

291
                cs := cl.Items[0].Spec.DeepCopy()
1✔
292
                if !reflect.DeepEqual(cs, &cdiv1.CDIConfigSpec{}) {
2✔
293
                        cdi.Spec.Config = cs
1✔
294
                }
1✔
295
        }
296

297
        if cdi.Annotations == nil {
2✔
298
                cdi.Annotations = map[string]string{}
1✔
299
        }
1✔
300
        cdi.Annotations[cdicontroller.AnnConfigAuthority] = ""
1✔
301

1✔
302
        return args.Client.Update(context.TODO(), cdi)
1✔
303
}
304

305
func getSpecVersion(version string, crd *extv1.CustomResourceDefinition) *extv1.CustomResourceDefinitionVersion {
1✔
306
        for _, v := range crd.Spec.Versions {
2✔
307
                if v.Name == version {
2✔
308
                        return &v
1✔
309
                }
1✔
310
        }
311
        return nil
1✔
312
}
313

314
func rewriteOldObjects(args *callbacks.ReconcileCallbackArgs, version string, crd *extv1.CustomResourceDefinition) error {
×
315
        args.Logger.Info("Rewriting old objects")
×
316
        kind := crd.Spec.Names.Kind
×
317
        gvk := schema.GroupVersionKind{
×
318
                Group:   crd.Spec.Group,
×
319
                Version: version,
×
320
                Kind:    kind,
×
321
        }
×
322
        ul := &unstructured.UnstructuredList{}
×
323
        ul.SetGroupVersionKind(gvk)
×
324
        err := args.Client.List(context.TODO(), ul, &client.ListOptions{})
×
325
        if err != nil {
×
326
                return err
×
327
        }
×
328
        for _, item := range ul.Items {
×
329
                nn := client.ObjectKey{Namespace: item.GetNamespace(), Name: item.GetName()}
×
330
                u := &unstructured.Unstructured{}
×
331
                u.SetGroupVersionKind(item.GetObjectKind().GroupVersionKind())
×
332
                err = args.Client.Get(context.TODO(), nn, u)
×
333
                if err != nil {
×
334
                        return err
×
335
                }
×
336
                err = args.Client.Update(context.TODO(), u)
×
337
                if err != nil {
×
338
                        return err
×
339
                }
×
340
        }
341
        return nil
×
342
}
343

344
func removeStoredVersion(args *callbacks.ReconcileCallbackArgs, desiredVersion string, crd *extv1.CustomResourceDefinition) error {
×
345
        args.Logger.Info("Removing stored version")
×
346
        crd.Status.StoredVersions = []string{desiredVersion}
×
347
        return args.Client.Status().Update(context.TODO(), crd)
×
348
}
×
349

350
// Handle upgrade from clusters that had v1alpha1 as a storage version
351
// and remove it from all CRDs managed by us
352
func reconcileHandleOldVersion(args *callbacks.ReconcileCallbackArgs) error {
1✔
353
        if args.State != callbacks.ReconcileStatePostRead {
2✔
354
                return nil
1✔
355
        }
1✔
356
        currentCrd := args.CurrentObject.(*extv1.CustomResourceDefinition)
1✔
357
        desiredCrd := args.DesiredObject.(*extv1.CustomResourceDefinition)
1✔
358
        desiredVersion := newestVersion(desiredCrd)
1✔
359

1✔
360
        if olderVersionsExist(desiredVersion, currentCrd) {
1✔
361
                restoreOlderVersions(currentCrd, desiredCrd)
×
362
                if !desiredIsStorage(desiredVersion, currentCrd) {
×
363
                        // Let kubernetes add it
×
364
                        return nil
×
365
                }
×
366
                if err := rewriteOldObjects(args, desiredVersion, currentCrd); err != nil {
×
367
                        return err
×
368
                }
×
369
                if err := removeStoredVersion(args, desiredVersion, currentCrd); err != nil {
×
370
                        return err
×
371
                }
×
372
        }
373
        return nil
1✔
374
}
375

376
func olderVersionsExist(desiredVersion string, crd *extv1.CustomResourceDefinition) bool {
1✔
377
        for _, version := range crd.Status.StoredVersions {
1✔
378
                if version != desiredVersion {
×
379
                        return true
×
380
                }
×
381
        }
382
        return false
1✔
383
}
384

385
func desiredIsStorage(desiredVersion string, crd *extv1.CustomResourceDefinition) bool {
×
386
        specVersion := getSpecVersion(desiredVersion, crd)
×
387
        return specVersion != nil && specVersion.Storage
×
388
}
×
389

390
func newestVersion(crd *extv1.CustomResourceDefinition) string {
1✔
391
        orderedVersions := []string{"v1", "v1beta1", "v1alpha1"}
1✔
392
        for _, version := range orderedVersions {
2✔
393
                specVersion := getSpecVersion(version, crd)
1✔
394
                if specVersion != nil {
2✔
395
                        return version
1✔
396
                }
1✔
397
        }
398
        return ""
×
399
}
400

401
// Merge both old and new versions into new CRD, so we have both in the desiredCrd object
402
func restoreOlderVersions(currentCrd, desiredCrd *extv1.CustomResourceDefinition) *extv1.CustomResourceDefinition {
×
403
        for _, version := range currentCrd.Status.StoredVersions {
×
404
                specVersion := getSpecVersion(version, desiredCrd)
×
405
                if specVersion == nil {
×
406
                        // Not available in desired CRD, restore from current CRD
×
407
                        specVersion := getSpecVersion(version, currentCrd)
×
408
                        // We are only allowed one storage version
×
409
                        // The desired CRD already has one
×
410
                        specVersion.Storage = false
×
411

×
412
                        desiredCrd.Spec.Versions = append(desiredCrd.Spec.Versions, *specVersion)
×
413
                }
×
414
        }
415
        return desiredCrd
×
416
}
417

418
func reconcilePvcMutatingWebhook(args *callbacks.ReconcileCallbackArgs) error {
1✔
419
        if args.State != callbacks.ReconcileStatePostRead {
2✔
420
                return nil
1✔
421
        }
1✔
422

423
        deployment, ok := args.DesiredObject.(*appsv1.Deployment)
1✔
424
        if !ok || deployment.Name != common.CDIApiServerResourceName {
2✔
425
                return nil
1✔
426
        }
1✔
427

428
        enabled, err := featuregates.IsWebhookPvcRenderingEnabled(args.Client)
1✔
429
        if err != nil {
2✔
430
                return cc.IgnoreNotFound(err)
1✔
431
        }
1✔
432

433
        whc := &admissionregistrationv1.MutatingWebhookConfiguration{}
1✔
434
        key := client.ObjectKey{Name: "cdi-api-pvc-mutate"}
1✔
435
        err = args.Client.Get(context.TODO(), key, whc)
1✔
436
        if err != nil && !errors.IsNotFound(err) {
1✔
437
                return err
×
438
        }
×
439

440
        exists := err == nil
1✔
441
        if !enabled {
2✔
442
                if !exists {
2✔
443
                        return nil
1✔
444
                }
1✔
445
                err = args.Client.Delete(context.TODO(), whc)
×
446
                return client.IgnoreNotFound(err)
×
447
        }
448

449
        if !exists {
×
450
                if err := initPvcMutatingWebhook(whc, args); err != nil {
×
451
                        return err
×
452
                }
×
453
                return args.Client.Create(context.TODO(), whc)
×
454
        }
455

456
        whcCopy := whc.DeepCopy()
×
457
        if err := initPvcMutatingWebhook(whc, args); err != nil {
×
458
                return err
×
459
        }
×
460
        if !reflect.DeepEqual(whc, whcCopy) {
×
461
                return args.Client.Update(context.TODO(), whc)
×
462
        }
×
463

464
        return nil
×
465
}
466

467
func initPvcMutatingWebhook(whc *admissionregistrationv1.MutatingWebhookConfiguration, args *callbacks.ReconcileCallbackArgs) error {
×
468
        path := "/pvc-mutate"
×
469
        defaultServicePort := int32(443)
×
470
        allScopes := admissionregistrationv1.AllScopes
×
471
        exactPolicy := admissionregistrationv1.Exact
×
472
        failurePolicy := admissionregistrationv1.Fail
×
473
        defaultTimeoutSeconds := int32(10)
×
474
        reinvocationNever := admissionregistrationv1.NeverReinvocationPolicy
×
475
        sideEffect := admissionregistrationv1.SideEffectClassNone
×
476
        bundle := cluster.GetAPIServerCABundle(args.Namespace, args.Client, args.Logger)
×
477

×
478
        whc.Name = "cdi-api-pvc-mutate"
×
479
        whc.Labels = map[string]string{utils.CDILabel: cluster.APIServerServiceName}
×
480
        whc.Webhooks = []admissionregistrationv1.MutatingWebhook{
×
481
                {
×
482
                        Name: "pvc-mutate.cdi.kubevirt.io",
×
483
                        Rules: []admissionregistrationv1.RuleWithOperations{{
×
484
                                Operations: []admissionregistrationv1.OperationType{
×
485
                                        admissionregistrationv1.Create,
×
486
                                },
×
487
                                Rule: admissionregistrationv1.Rule{
×
488
                                        APIGroups:   []string{corev1.SchemeGroupVersion.Group},
×
489
                                        APIVersions: []string{corev1.SchemeGroupVersion.Version},
×
490
                                        Resources:   []string{"persistentvolumeclaims"},
×
491
                                        Scope:       &allScopes,
×
492
                                },
×
493
                        }},
×
494
                        ClientConfig: admissionregistrationv1.WebhookClientConfig{
×
495
                                Service: &admissionregistrationv1.ServiceReference{
×
496
                                        Namespace: args.Namespace,
×
497
                                        Name:      cluster.APIServerServiceName,
×
498
                                        Path:      &path,
×
499
                                        Port:      &defaultServicePort,
×
500
                                },
×
501
                                CABundle: bundle,
×
502
                        },
×
NEW
503
                        FailurePolicy:  &failurePolicy,
×
NEW
504
                        SideEffects:    &sideEffect,
×
NEW
505
                        MatchPolicy:    &exactPolicy,
×
NEW
506
                        TimeoutSeconds: &defaultTimeoutSeconds,
×
507
                        AdmissionReviewVersions: []string{
×
508
                                "v1",
×
509
                        },
×
510
                        ObjectSelector: &metav1.LabelSelector{
×
511
                                MatchLabels: map[string]string{
×
512
                                        common.PvcApplyStorageProfileLabel: "true",
×
513
                                },
×
514
                        },
×
515
                        ReinvocationPolicy: &reinvocationNever,
×
516
                },
×
517
        }
×
518

×
519
        cdi, err := cc.GetActiveCDI(context.TODO(), args.Client)
×
520
        if err != nil {
×
521
                return err
×
522
        }
×
523

524
        return controllerutil.SetControllerReference(cdi, whc, args.Scheme)
×
525
}
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

© 2026 Coveralls, Inc