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

kubevirt / hyperconverged-cluster-operator / 20689747098

04 Jan 2026 07:49AM UTC coverage: 72.256% (-0.2%) from 72.483%
20689747098

push

github

web-flow
[release 1.14] Add ValidatingAdmissionPolicy to validate the HyperConverged namespace (#3940)

* Add the new admission policy controller

The current implementation of preventing the creation of the
HyperConverged CR in non-allowed namespace, is not working in Openshift,
where becasue of a race condition, the webhook's namespace selector is
removed by OLM.

This commit adds a new controller, to create and reconcile a
ValidatingAdmissionPolicy and the related
ValidatingAdmissionPolicyBinding, to perform the same validation.

The reason we're doing it in a new controller, is because we need the
ValidatingAdmissionPolicy to be set, even if the HyperConverged CR is
not deployed, while our main controller only reconciles resources if
the HyperConverged CR is deployed.



* Register the admission policy controller on boot



* Remove the current validation

Remove the existing validation of the HyperConverged CR namespace from
the validation webhook, as it is now done by the policy, created by the
admission policy controller.



* Don't remove the namespace selector from the validation wh

OLM adds a namespace selection on the validation webhook CR, causing the
namespace validation to be not relevant.

The webhook setup logic removes this selector, but actually this is
reconciled by OLM, and eventually, user can still create the
HyperConverged CR in any namespace.

The issue is now handled by a ValidationgAdmissionPolicy, and so we
don't need this logic anymore, and so this commit removes it.



---------

Signed-off-by: Nahshon Unna Tsameret <nahsh.ut@gmail.com>

138 of 215 new or added lines in 3 files covered. (64.19%)

6 existing lines in 2 files now uncovered.

6675 of 9238 relevant lines covered (72.26%)

0.8 hits per line

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

3.12
/pkg/components/components.go
1
package components
2

3
import (
4
        "encoding/json"
5
        "fmt"
6
        "strconv"
7
        "time"
8

9
        "k8s.io/utils/ptr"
10

11
        "github.com/blang/semver/v4"
12
        csvVersion "github.com/operator-framework/api/pkg/lib/version"
13
        csvv1alpha1 "github.com/operator-framework/api/pkg/operators/v1alpha1"
14
        "golang.org/x/tools/go/packages"
15
        admissionregistrationv1 "k8s.io/api/admissionregistration/v1"
16
        appsv1 "k8s.io/api/apps/v1"
17
        corev1 "k8s.io/api/core/v1"
18
        v1 "k8s.io/api/core/v1"
19
        rbacv1 "k8s.io/api/rbac/v1"
20
        extv1 "k8s.io/apiextensions-apiserver/pkg/apis/apiextensions/v1"
21
        "k8s.io/apimachinery/pkg/api/resource"
22
        metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
23
        "k8s.io/apimachinery/pkg/runtime"
24
        "k8s.io/apimachinery/pkg/runtime/schema"
25
        "k8s.io/apimachinery/pkg/util/intstr"
26
        crdgen "sigs.k8s.io/controller-tools/pkg/crd"
27
        crdmarkers "sigs.k8s.io/controller-tools/pkg/crd/markers"
28
        "sigs.k8s.io/controller-tools/pkg/loader"
29
        "sigs.k8s.io/controller-tools/pkg/markers"
30

31
        cnaoapi "github.com/kubevirt/cluster-network-addons-operator/pkg/apis/networkaddonsoperator/v1"
32
        kvapi "kubevirt.io/api/core"
33
        aaqapi "kubevirt.io/application-aware-quota/staging/src/kubevirt.io/application-aware-quota-api/pkg/apis/core"
34
        cdiapi "kubevirt.io/containerized-data-importer-api/pkg/apis/core"
35
        sspapi "kubevirt.io/ssp-operator/api/v1beta2"
36

37
        hcov1beta1 "github.com/kubevirt/hyperconverged-cluster-operator/api/v1beta1"
38
        "github.com/kubevirt/hyperconverged-cluster-operator/pkg/util"
39
        hcoutil "github.com/kubevirt/hyperconverged-cluster-operator/pkg/util"
40
)
41

42
const DisableOperandDeletionAnnotation = "console.openshift.io/disable-operand-delete"
43

44
const (
45
        crName              = util.HyperConvergedName
46
        packageName         = util.HyperConvergedName
47
        hcoName             = "hyperconverged-cluster-operator"
48
        hcoNameWebhook      = "hyperconverged-cluster-webhook"
49
        hcoDeploymentName   = "hco-operator"
50
        hcoWhDeploymentName = "hco-webhook"
51
        certVolume          = "apiservice-cert"
52

53
        cliDownloadsName = "hyperconverged-cluster-cli-download"
54

55
        kubevirtProjectName = "KubeVirt project"
56
        rbacVersionV1       = "rbac.authorization.k8s.io/v1"
57
)
58

59
var deploymentType = metav1.TypeMeta{
60
        APIVersion: "apps/v1",
61
        Kind:       "Deployment",
62
}
63

64
type DeploymentOperatorParams struct {
65
        Namespace              string
66
        Image                  string
67
        WebhookImage           string
68
        CliDownloadsImage      string
69
        KVUIPluginImage        string
70
        KVUIProxyImage         string
71
        ImagePullPolicy        string
72
        ConversionContainer    string
73
        VmwareContainer        string
74
        VirtIOWinContainer     string
75
        Smbios                 string
76
        Machinetype            string
77
        Amd64MachineType       string
78
        Arm64MachineType       string
79
        HcoKvIoVersion         string
80
        KubevirtVersion        string
81
        KvVirtLancherOsVersion string
82
        CdiVersion             string
83
        CnaoVersion            string
84
        SspVersion             string
85
        HppoVersion            string
86
        MtqVersion             string
87
        AaqVersion             string
88
        PrimaryUDNImage        string
89
        Env                    []corev1.EnvVar
90
}
91

92
func GetDeploymentOperator(params *DeploymentOperatorParams) appsv1.Deployment {
×
93
        return appsv1.Deployment{
×
94
                TypeMeta: deploymentType,
×
95
                ObjectMeta: metav1.ObjectMeta{
×
96
                        Name: hcoName,
×
97
                        Labels: map[string]string{
×
98
                                "name": hcoName,
×
99
                        },
×
100
                },
×
101
                Spec: GetDeploymentSpecOperator(params),
×
102
        }
×
103
}
×
104

105
func GetDeploymentWebhook(namespace, image, imagePullPolicy, hcoKvIoVersion string, env []corev1.EnvVar) appsv1.Deployment {
×
106
        deploy := appsv1.Deployment{
×
107
                TypeMeta: deploymentType,
×
108
                ObjectMeta: metav1.ObjectMeta{
×
109
                        Name: hcoNameWebhook,
×
110
                        Labels: map[string]string{
×
111
                                "name": hcoNameWebhook,
×
112
                        },
×
113
                },
×
114
                Spec: GetDeploymentSpecWebhook(namespace, image, imagePullPolicy, hcoKvIoVersion, env),
×
115
        }
×
116

×
117
        InjectVolumesForWebHookCerts(&deploy)
×
118
        return deploy
×
119
}
×
120

121
func GetDeploymentCliDownloads(params *DeploymentOperatorParams) appsv1.Deployment {
×
122
        return appsv1.Deployment{
×
123
                TypeMeta: deploymentType,
×
124
                ObjectMeta: metav1.ObjectMeta{
×
125
                        Name: cliDownloadsName,
×
126
                        Labels: map[string]string{
×
127
                                "name": cliDownloadsName,
×
128
                        },
×
129
                },
×
130
                Spec: GetDeploymentSpecCliDownloads(params),
×
131
        }
×
132
}
×
133

134
func GetServiceWebhook() v1.Service {
×
135
        return v1.Service{
×
136
                TypeMeta: metav1.TypeMeta{
×
137
                        APIVersion: "v1",
×
138
                        Kind:       "Service",
×
139
                },
×
140
                ObjectMeta: metav1.ObjectMeta{
×
141
                        Name: hcoNameWebhook + "-service",
×
142
                },
×
143
                Spec: v1.ServiceSpec{
×
144
                        Selector: map[string]string{
×
145
                                "name": hcoNameWebhook,
×
146
                        },
×
147
                        Ports: []v1.ServicePort{
×
148
                                {
×
149
                                        Name:       strconv.Itoa(util.WebhookPort),
×
150
                                        Port:       util.WebhookPort,
×
151
                                        Protocol:   corev1.ProtocolTCP,
×
152
                                        TargetPort: intstr.FromInt32(util.WebhookPort),
×
153
                                },
×
154
                        },
×
155
                        Type: corev1.ServiceTypeClusterIP,
×
156
                },
×
157
        }
×
158
}
×
159

160
func GetDeploymentSpecOperator(params *DeploymentOperatorParams) appsv1.DeploymentSpec {
×
161
        envs := buildEnvVars(params)
×
162

×
163
        return appsv1.DeploymentSpec{
×
164
                Replicas: int32Ptr(1),
×
165
                Selector: &metav1.LabelSelector{
×
166
                        MatchLabels: map[string]string{
×
167
                                "name": hcoName,
×
168
                        },
×
169
                },
×
170
                Strategy: appsv1.DeploymentStrategy{
×
171
                        Type: appsv1.RollingUpdateDeploymentStrategyType,
×
172
                },
×
173
                Template: corev1.PodTemplateSpec{
×
174
                        ObjectMeta: metav1.ObjectMeta{
×
175
                                Labels: getLabels(hcoName, params.HcoKvIoVersion),
×
176
                        },
×
177
                        Spec: corev1.PodSpec{
×
178
                                ServiceAccountName: hcoName,
×
179
                                SecurityContext:    GetStdPodSecurityContext(),
×
180
                                Containers: []corev1.Container{
×
181
                                        {
×
182
                                                Name:            hcoName,
×
183
                                                Image:           params.Image,
×
184
                                                ImagePullPolicy: corev1.PullPolicy(params.ImagePullPolicy),
×
185
                                                Command:         stringListToSlice(hcoName),
×
186
                                                ReadinessProbe:  getReadinessProbe(),
×
187
                                                LivenessProbe:   getLivenessProbe(),
×
188
                                                Env:             envs,
×
189
                                                Resources: v1.ResourceRequirements{
×
190
                                                        Requests: map[v1.ResourceName]resource.Quantity{
×
191
                                                                v1.ResourceCPU:    resource.MustParse("10m"),
×
192
                                                                v1.ResourceMemory: resource.MustParse("96Mi"),
×
193
                                                        },
×
194
                                                },
×
195
                                                SecurityContext: GetStdContainerSecurityContext(),
×
196
                                        },
×
197
                                },
×
198
                                PriorityClassName: "system-cluster-critical",
×
199
                        },
×
200
                },
×
201
        }
×
202
}
×
203

204
func buildEnvVars(params *DeploymentOperatorParams) []corev1.EnvVar {
×
205
        envs := append([]corev1.EnvVar{
×
206
                {
×
207
                        // deprecated: left here for CI test.
×
208
                        Name:  util.OperatorWebhookModeEnv,
×
209
                        Value: "false",
×
210
                },
×
211
                {
×
212
                        Name:  util.ContainerAppName,
×
213
                        Value: util.ContainerOperatorApp,
×
214
                },
×
215
                {
×
216
                        Name:  "KVM_EMULATION",
×
217
                        Value: "",
×
218
                },
×
219
                {
×
220
                        Name:  "OPERATOR_IMAGE",
×
221
                        Value: params.Image,
×
222
                },
×
223
                {
×
224
                        Name:  "OPERATOR_NAME",
×
225
                        Value: hcoName,
×
226
                },
×
227
                {
×
228
                        Name:  "OPERATOR_NAMESPACE",
×
229
                        Value: params.Namespace,
×
230
                },
×
231
                {
×
232
                        Name: "POD_NAME",
×
233
                        ValueFrom: &corev1.EnvVarSource{
×
234
                                FieldRef: &corev1.ObjectFieldSelector{
×
235
                                        FieldPath: "metadata.name",
×
236
                                },
×
237
                        },
×
238
                },
×
239
                {
×
240
                        Name:  "VIRTIOWIN_CONTAINER",
×
241
                        Value: params.VirtIOWinContainer,
×
242
                },
×
243
                {
×
244
                        Name:  "SMBIOS",
×
245
                        Value: params.Smbios,
×
246
                },
×
247
                {
×
248
                        Name:  "MACHINETYPE",
×
249
                        Value: params.Machinetype,
×
250
                },
×
251
                {
×
252
                        Name:  "AMD64_MACHINETYPE",
×
253
                        Value: params.Amd64MachineType,
×
254
                },
×
255
                {
×
256
                        Name:  "ARM64_MACHINETYPE",
×
257
                        Value: params.Arm64MachineType,
×
258
                },
×
259
                {
×
260
                        Name:  util.HcoKvIoVersionName,
×
261
                        Value: params.HcoKvIoVersion,
×
262
                },
×
263
                {
×
264
                        Name:  util.KubevirtVersionEnvV,
×
265
                        Value: params.KubevirtVersion,
×
266
                },
×
267
                {
×
268
                        Name:  util.CdiVersionEnvV,
×
269
                        Value: params.CdiVersion,
×
270
                },
×
271
                {
×
272
                        Name:  util.CnaoVersionEnvV,
×
273
                        Value: params.CnaoVersion,
×
274
                },
×
275
                {
×
276
                        Name:  util.SspVersionEnvV,
×
277
                        Value: params.SspVersion,
×
278
                },
×
279
                {
×
280
                        Name:  util.HppoVersionEnvV,
×
281
                        Value: params.HppoVersion,
×
282
                },
×
283
                {
×
284
                        Name:  util.AaqVersionEnvV,
×
285
                        Value: params.AaqVersion,
×
286
                },
×
287
                {
×
288
                        Name:  util.KVUIPluginImageEnvV,
×
289
                        Value: params.KVUIPluginImage,
×
290
                },
×
291
                {
×
292
                        Name:  util.KVUIProxyImageEnvV,
×
293
                        Value: params.KVUIProxyImage,
×
294
                },
×
295
                {
×
296
                        Name:  util.PrimaryUDNImageEnvV,
×
297
                        Value: params.PrimaryUDNImage,
×
298
                },
×
299
        }, params.Env...)
×
300

×
301
        if params.KvVirtLancherOsVersion != "" {
×
302
                envs = append(envs, corev1.EnvVar{
×
303
                        Name:  util.KvVirtLauncherOSVersionEnvV,
×
304
                        Value: params.KvVirtLancherOsVersion,
×
305
                })
×
306
        }
×
307

308
        return envs
×
309
}
310

311
func GetDeploymentSpecCliDownloads(params *DeploymentOperatorParams) appsv1.DeploymentSpec {
×
312
        return appsv1.DeploymentSpec{
×
313
                Replicas: int32Ptr(1),
×
314
                Selector: &metav1.LabelSelector{
×
315
                        MatchLabels: map[string]string{
×
316
                                "name": cliDownloadsName,
×
317
                        },
×
318
                },
×
319
                Strategy: appsv1.DeploymentStrategy{
×
320
                        Type: appsv1.RollingUpdateDeploymentStrategyType,
×
321
                },
×
322
                Template: corev1.PodTemplateSpec{
×
323
                        ObjectMeta: metav1.ObjectMeta{
×
324
                                Labels: getLabels(cliDownloadsName, params.HcoKvIoVersion),
×
325
                        },
×
326
                        Spec: corev1.PodSpec{
×
327
                                SecurityContext: GetStdPodSecurityContext(),
×
328
                                Containers: []corev1.Container{
×
329
                                        {
×
330
                                                Name:            "server",
×
331
                                                Image:           params.CliDownloadsImage,
×
332
                                                ImagePullPolicy: corev1.PullPolicy(params.ImagePullPolicy),
×
333
                                                Resources: v1.ResourceRequirements{
×
334
                                                        Requests: map[v1.ResourceName]resource.Quantity{
×
335
                                                                v1.ResourceCPU:    resource.MustParse("10m"),
×
336
                                                                v1.ResourceMemory: resource.MustParse("96Mi"),
×
337
                                                        },
×
338
                                                },
×
339
                                                Ports: []v1.ContainerPort{
×
340
                                                        {
×
341
                                                                Protocol:      v1.ProtocolTCP,
×
342
                                                                ContainerPort: int32(8080),
×
343
                                                        },
×
344
                                                },
×
345
                                                SecurityContext: GetStdContainerSecurityContext(),
×
346
                                        },
×
347
                                },
×
348
                                PriorityClassName: "system-cluster-critical",
×
349
                        },
×
350
                },
×
351
        }
×
352
}
×
353

354
func getLabels(name, hcoKvIoVersion string) map[string]string {
×
355
        return map[string]string{
×
356
                "name":                    name,
×
357
                hcoutil.AppLabelVersion:   hcoKvIoVersion,
×
358
                hcoutil.AppLabelPartOf:    hcoutil.HyperConvergedCluster,
×
359
                hcoutil.AppLabelComponent: string(hcoutil.AppComponentDeployment),
×
360
        }
×
361
}
×
362

363
func GetStdPodSecurityContext() *v1.PodSecurityContext {
1✔
364
        return &v1.PodSecurityContext{
1✔
365
                RunAsNonRoot: ptr.To(true),
1✔
366
                SeccompProfile: &v1.SeccompProfile{
1✔
367
                        Type: corev1.SeccompProfileTypeRuntimeDefault,
1✔
368
                },
1✔
369
        }
1✔
370
}
1✔
371

372
func GetStdContainerSecurityContext() *v1.SecurityContext {
1✔
373
        return &v1.SecurityContext{
1✔
374
                AllowPrivilegeEscalation: ptr.To(false),
1✔
375
                Capabilities: &v1.Capabilities{
1✔
376
                        Drop: []v1.Capability{"ALL"},
1✔
377
                },
1✔
378
        }
1✔
379
}
1✔
380

381
// Currently we are abusing the pod readiness to signal to OLM that HCO is not ready
382
// for an upgrade. This has a lot of side effects, one of this is the validating webhook
383
// being not able to receive traffic when exposed by a pod that is not reporting ready=true.
384
// This can cause a lot of side effects if not deadlocks when the system reach a status where,
385
// for any possible reason, HCO pod cannot be ready and so HCO pod cannot validate any further update or
386
// delete request on HCO CR.
387
// A proper solution is properly use the readiness probe only to report the pod readiness and communicate
388
// status to OLM via conditions once OLM will be ready for:
389
// https://github.com/operator-framework/enhancements/blob/master/enhancements/operator-conditions.md
390
// in the meanwhile a quick (but dirty!) solution is to expose the same hco binary on two distinct pods:
391
// the first one will run only the controller and the second one (almost always ready) just the validating
392
// webhook one.
393
func GetDeploymentSpecWebhook(namespace, image, imagePullPolicy, hcoKvIoVersion string, env []corev1.EnvVar) appsv1.DeploymentSpec {
×
394
        return appsv1.DeploymentSpec{
×
395
                Replicas: int32Ptr(1),
×
396
                Selector: &metav1.LabelSelector{
×
397
                        MatchLabels: map[string]string{
×
398
                                "name": hcoNameWebhook,
×
399
                        },
×
400
                },
×
401
                Strategy: appsv1.DeploymentStrategy{
×
402
                        Type: appsv1.RollingUpdateDeploymentStrategyType,
×
403
                },
×
404
                Template: corev1.PodTemplateSpec{
×
405
                        ObjectMeta: metav1.ObjectMeta{
×
406
                                Labels: getLabels(hcoNameWebhook, hcoKvIoVersion),
×
407
                        },
×
408
                        Spec: corev1.PodSpec{
×
409
                                ServiceAccountName: hcoName,
×
410
                                SecurityContext:    GetStdPodSecurityContext(),
×
411
                                Containers: []corev1.Container{
×
412
                                        {
×
413
                                                Name:            hcoNameWebhook,
×
414
                                                Image:           image,
×
415
                                                ImagePullPolicy: corev1.PullPolicy(imagePullPolicy),
×
416
                                                Command:         stringListToSlice(hcoNameWebhook),
×
417
                                                ReadinessProbe:  getReadinessProbe(),
×
418
                                                LivenessProbe:   getLivenessProbe(),
×
419
                                                Env: append([]corev1.EnvVar{
×
420
                                                        {
×
421
                                                                // deprecated: left here for CI test.
×
422
                                                                Name:  util.OperatorWebhookModeEnv,
×
423
                                                                Value: "true",
×
424
                                                        },
×
425
                                                        {
×
426
                                                                Name:  util.ContainerAppName,
×
427
                                                                Value: util.ContainerWebhookApp,
×
428
                                                        },
×
429
                                                        {
×
430
                                                                Name:  "OPERATOR_IMAGE",
×
431
                                                                Value: image,
×
432
                                                        },
×
433
                                                        {
×
434
                                                                Name:  "OPERATOR_NAME",
×
435
                                                                Value: hcoNameWebhook,
×
436
                                                        },
×
437
                                                        {
×
438
                                                                Name:  "OPERATOR_NAMESPACE",
×
439
                                                                Value: namespace,
×
440
                                                        },
×
441
                                                        {
×
442
                                                                Name: "POD_NAME",
×
443
                                                                ValueFrom: &corev1.EnvVarSource{
×
444
                                                                        FieldRef: &corev1.ObjectFieldSelector{
×
445
                                                                                FieldPath: "metadata.name",
×
446
                                                                        },
×
447
                                                                },
×
448
                                                        },
×
449
                                                }, env...),
×
450
                                                Resources: v1.ResourceRequirements{
×
451
                                                        Requests: map[v1.ResourceName]resource.Quantity{
×
452
                                                                v1.ResourceCPU:    resource.MustParse("5m"),
×
453
                                                                v1.ResourceMemory: resource.MustParse("48Mi"),
×
454
                                                        },
×
455
                                                },
×
456
                                                SecurityContext: GetStdContainerSecurityContext(),
×
457
                                        },
×
458
                                },
×
459
                                PriorityClassName: "system-node-critical",
×
460
                        },
×
461
                },
×
462
        }
×
463
}
×
464

465
func GetClusterRole() rbacv1.ClusterRole {
×
466
        return rbacv1.ClusterRole{
×
467
                TypeMeta: metav1.TypeMeta{
×
468
                        APIVersion: rbacVersionV1,
×
469
                        Kind:       "ClusterRole",
×
470
                },
×
471
                ObjectMeta: metav1.ObjectMeta{
×
472
                        Name: hcoName,
×
473
                        Labels: map[string]string{
×
474
                                "name": hcoName,
×
475
                        },
×
476
                },
×
477
                Rules: GetClusterPermissions(),
×
478
        }
×
479
}
×
480

481
var (
482
        emptyAPIGroup = []string{""}
483
)
484

485
func GetClusterPermissions() []rbacv1.PolicyRule {
×
486
        const configOpenshiftIO = "config.openshift.io"
×
487
        const operatorOpenshiftIO = "operator.openshift.io"
×
488
        return []rbacv1.PolicyRule{
×
489
                {
×
490
                        APIGroups: stringListToSlice(util.APIVersionGroup),
×
491
                        Resources: stringListToSlice("hyperconvergeds"),
×
492
                        Verbs:     stringListToSlice("get", "list", "update", "watch"),
×
493
                },
×
494
                {
×
495
                        APIGroups: stringListToSlice(util.APIVersionGroup),
×
496
                        Resources: stringListToSlice("hyperconvergeds/finalizers", "hyperconvergeds/status"),
×
497
                        Verbs:     stringListToSlice("get", "list", "create", "update", "watch"),
×
498
                },
×
499
                roleWithAllPermissions(kvapi.GroupName, stringListToSlice("kubevirts", "kubevirts/finalizers")),
×
500
                roleWithAllPermissions(cdiapi.GroupName, stringListToSlice("cdis", "cdis/finalizers")),
×
501
                roleWithAllPermissions(sspapi.GroupVersion.Group, stringListToSlice("ssps", "ssps/finalizers")),
×
502
                roleWithAllPermissions(cnaoapi.GroupVersion.Group, stringListToSlice("networkaddonsconfigs", "networkaddonsconfigs/finalizers")),
×
503
                roleWithAllPermissions(aaqapi.GroupName, stringListToSlice("aaqs", "aaqs/finalizers")),
×
504
                roleWithAllPermissions("", stringListToSlice("configmaps")),
×
505
                {
×
506
                        APIGroups: emptyAPIGroup,
×
507
                        Resources: stringListToSlice("events"),
×
508
                        Verbs:     stringListToSlice("get", "list", "watch", "create", "patch"),
×
509
                },
×
510
                roleWithAllPermissions("", stringListToSlice("services")),
×
511
                {
×
512
                        APIGroups: emptyAPIGroup,
×
513
                        Resources: stringListToSlice("pods"),
×
514
                        Verbs:     stringListToSlice("get", "list", "watch"),
×
515
                },
×
516
                {
×
517
                        APIGroups: emptyAPIGroup,
×
518
                        Resources: stringListToSlice("nodes"),
×
519
                        Verbs:     stringListToSlice("get", "list", "watch"),
×
520
                },
×
521
                {
×
522
                        APIGroups: emptyAPIGroup,
×
523
                        Resources: stringListToSlice("secrets"),
×
524
                        Verbs:     stringListToSlice("get", "list", "watch", "create", "update", "delete"),
×
525
                },
×
526
                {
×
527
                        APIGroups: emptyAPIGroup,
×
528
                        Resources: stringListToSlice("endpoints"),
×
529
                        Verbs:     stringListToSlice("get", "list", "delete", "watch"),
×
530
                },
×
531
                {
×
532
                        APIGroups: emptyAPIGroup,
×
533
                        Resources: stringListToSlice("namespaces"),
×
534
                        Verbs:     stringListToSlice("get", "list", "watch", "patch", "update"),
×
535
                },
×
536
                {
×
537
                        APIGroups: stringListToSlice("apps"),
×
538
                        Resources: stringListToSlice("deployments", "replicasets"),
×
539
                        Verbs:     stringListToSlice("get", "list", "watch", "create", "update", "delete"),
×
540
                },
×
541
                roleWithAllPermissions("rbac.authorization.k8s.io", stringListToSlice("roles", "rolebindings")),
×
542
                {
×
543
                        APIGroups: stringListToSlice("apiextensions.k8s.io"),
×
544
                        Resources: stringListToSlice("customresourcedefinitions"),
×
545
                        Verbs:     stringListToSlice("get", "list", "watch", "delete"),
×
546
                },
×
547
                {
×
548
                        APIGroups: stringListToSlice("apiextensions.k8s.io"),
×
NEW
549
                        Resources: stringListToSlice("customresourcedefinitions/status", "customresourcedefinitions/finalizers"),
×
550
                        Verbs:     stringListToSlice("get", "list", "watch", "patch", "update"),
×
551
                },
×
552
                roleWithAllPermissions("monitoring.coreos.com", stringListToSlice("servicemonitors", "prometheusrules")),
×
553
                {
×
554
                        APIGroups: stringListToSlice("operators.coreos.com"),
×
555
                        Resources: stringListToSlice("clusterserviceversions"),
×
556
                        Verbs:     stringListToSlice("get", "list", "watch", "update", "patch"),
×
557
                },
×
558
                {
×
559
                        APIGroups: stringListToSlice("scheduling.k8s.io"),
×
560
                        Resources: stringListToSlice("priorityclasses"),
×
561
                        Verbs:     stringListToSlice("get", "list", "watch", "create", "delete", "patch"),
×
562
                },
×
563
                {
×
564
                        APIGroups: stringListToSlice("admissionregistration.k8s.io"),
×
565
                        Resources: stringListToSlice("validatingwebhookconfigurations"),
×
566
                        Verbs:     stringListToSlice("list", "watch", "update", "patch"),
×
567
                },
×
568
                roleWithAllPermissions("console.openshift.io", stringListToSlice("consoleclidownloads", "consolequickstarts")),
×
569
                {
×
570
                        APIGroups: stringListToSlice(configOpenshiftIO),
×
571
                        Resources: stringListToSlice("clusterversions", "infrastructures", "ingresses", "networks"),
×
572
                        Verbs:     stringListToSlice("get", "list"),
×
573
                },
×
574
                {
×
575
                        APIGroups: stringListToSlice(configOpenshiftIO),
×
576
                        Resources: stringListToSlice("apiservers"),
×
577
                        Verbs:     stringListToSlice("get", "list", "watch"),
×
578
                },
×
579
                {
×
580
                        APIGroups: stringListToSlice(operatorOpenshiftIO),
×
581
                        Resources: stringListToSlice("kubedeschedulers"),
×
582
                        Verbs:     stringListToSlice("get", "list", "watch"),
×
583
                },
×
584
                {
×
585
                        APIGroups: stringListToSlice(configOpenshiftIO),
×
586
                        Resources: stringListToSlice("dnses"),
×
587
                        Verbs:     stringListToSlice("get"),
×
588
                },
×
589
                roleWithAllPermissions("coordination.k8s.io", stringListToSlice("leases")),
×
590
                roleWithAllPermissions("route.openshift.io", stringListToSlice("routes")),
×
591
                {
×
592
                        APIGroups: stringListToSlice("operators.coreos.com"),
×
593
                        Resources: stringListToSlice("operatorconditions"),
×
594
                        Verbs:     stringListToSlice("get", "list", "watch", "update", "patch"),
×
595
                },
×
596
                roleWithAllPermissions("image.openshift.io", stringListToSlice("imagestreams")),
×
597
                roleWithAllPermissions("console.openshift.io", stringListToSlice("consoleplugins")),
×
598
                {
×
599
                        APIGroups: stringListToSlice("operator.openshift.io"),
×
600
                        Resources: stringListToSlice("consoles"),
×
601
                        Verbs:     stringListToSlice("get", "list", "watch", "update"),
×
602
                },
×
603
                {
×
604
                        APIGroups: stringListToSlice("monitoring.coreos.com"),
×
605
                        Resources: stringListToSlice("alertmanagers", "alertmanagers/api"),
×
606
                        Verbs:     stringListToSlice("get", "list", "create", "delete"),
×
607
                },
×
NEW
608
                {
×
NEW
609
                        APIGroups: stringListToSlice(admissionregistrationv1.GroupName),
×
NEW
610
                        Resources: stringListToSlice("validatingadmissionpolicies", "validatingadmissionpolicybindings"),
×
NEW
611
                        Verbs:     stringListToSlice("get", "list", "watch", "create", "update", "delete"),
×
NEW
612
                },
×
613
        }
×
614
}
×
615

616
func roleWithAllPermissions(apiGroup string, resources []string) rbacv1.PolicyRule {
×
617
        return rbacv1.PolicyRule{
×
618
                APIGroups: stringListToSlice(apiGroup),
×
619
                Resources: resources,
×
620
                Verbs:     stringListToSlice("get", "list", "watch", "create", "update", "delete", "patch"),
×
621
        }
×
622
}
×
623

624
func GetServiceAccount(namespace string) v1.ServiceAccount {
×
625
        return v1.ServiceAccount{
×
626
                TypeMeta: metav1.TypeMeta{
×
627
                        APIVersion: "v1",
×
628
                        Kind:       "ServiceAccount",
×
629
                },
×
630
                ObjectMeta: metav1.ObjectMeta{
×
631
                        Name:      hcoName,
×
632
                        Namespace: namespace,
×
633
                        Labels: map[string]string{
×
634
                                "name": hcoName,
×
635
                        },
×
636
                },
×
637
        }
×
638
}
×
639

640
func GetClusterRoleBinding(namespace string) rbacv1.ClusterRoleBinding {
×
641
        return rbacv1.ClusterRoleBinding{
×
642
                TypeMeta: metav1.TypeMeta{
×
643
                        APIVersion: rbacVersionV1,
×
644
                        Kind:       "ClusterRoleBinding",
×
645
                },
×
646
                ObjectMeta: metav1.ObjectMeta{
×
647
                        Name: hcoName,
×
648
                        Labels: map[string]string{
×
649
                                "name": hcoName,
×
650
                        },
×
651
                },
×
652
                RoleRef: rbacv1.RoleRef{
×
653
                        APIGroup: "rbac.authorization.k8s.io",
×
654
                        Kind:     "ClusterRole",
×
655
                        Name:     hcoName,
×
656
                },
×
657
                Subjects: []rbacv1.Subject{
×
658
                        {
×
659
                                Kind:      "ServiceAccount",
×
660
                                Name:      hcoName,
×
661
                                Namespace: namespace,
×
662
                        },
×
663
                },
×
664
        }
×
665
}
×
666

667
func packageErrors(pkg *loader.Package, filterKinds ...packages.ErrorKind) error {
×
668
        toSkip := make(map[packages.ErrorKind]struct{})
×
669
        for _, errKind := range filterKinds {
×
670
                toSkip[errKind] = struct{}{}
×
671
        }
×
672
        var outErr error
×
673
        packages.Visit([]*packages.Package{pkg.Package}, nil, func(pkgRaw *packages.Package) {
×
674
                for _, err := range pkgRaw.Errors {
×
675
                        if _, skip := toSkip[err.Kind]; skip {
×
676
                                continue
×
677
                        }
678
                        outErr = err
×
679
                }
680
        })
681
        return outErr
×
682
}
683

684
const objectType = "object"
685

686
func GetOperatorCRD(relPath string) *extv1.CustomResourceDefinition {
×
687
        pkgs, err := loader.LoadRoots(relPath)
×
688
        if err != nil {
×
689
                panic(err)
×
690
        }
691
        reg := &markers.Registry{}
×
692
        panicOnError(crdmarkers.Register(reg))
×
693

×
694
        parser := &crdgen.Parser{
×
695
                Collector:                  &markers.Collector{Registry: reg},
×
696
                Checker:                    &loader.TypeChecker{},
×
697
                GenerateEmbeddedObjectMeta: true,
×
698
        }
×
699

×
700
        crdgen.AddKnownTypes(parser)
×
701
        if len(pkgs) == 0 {
×
702
                panic("Failed identifying packages")
×
703
        }
704
        for _, p := range pkgs {
×
705
                parser.NeedPackage(p)
×
706
        }
×
707
        groupKind := schema.GroupKind{Kind: util.HyperConvergedKind, Group: util.APIVersionGroup}
×
708
        parser.NeedCRDFor(groupKind, nil)
×
709
        for _, p := range pkgs {
×
710
                err = packageErrors(p, packages.TypeError)
×
711
                if err != nil {
×
712
                        panic(err)
×
713
                }
714
        }
715
        c := parser.CustomResourceDefinitions[groupKind]
×
716
        // enforce validation of CR name to prevent multiple CRs
×
717
        for _, v := range c.Spec.Versions {
×
718
                v.Schema.OpenAPIV3Schema.Properties["metadata"] = extv1.JSONSchemaProps{
×
719
                        Type: objectType,
×
720
                        Properties: map[string]extv1.JSONSchemaProps{
×
721
                                "name": {
×
722
                                        Type:    "string",
×
723
                                        Pattern: hcov1beta1.HyperConvergedName,
×
724
                                },
×
725
                        },
×
726
                }
×
727
        }
×
728
        return &c
×
729
}
730

731
func GetOperatorCR() *hcov1beta1.HyperConverged {
1✔
732
        defaultScheme := runtime.NewScheme()
1✔
733
        _ = hcov1beta1.AddToScheme(defaultScheme)
1✔
734
        _ = hcov1beta1.RegisterDefaults(defaultScheme)
1✔
735
        defaultHco := &hcov1beta1.HyperConverged{
1✔
736
                TypeMeta: metav1.TypeMeta{
1✔
737
                        APIVersion: util.APIVersion,
1✔
738
                        Kind:       util.HyperConvergedKind,
1✔
739
                },
1✔
740
                ObjectMeta: metav1.ObjectMeta{
1✔
741
                        Name: crName,
1✔
742
                }}
1✔
743
        defaultScheme.Default(defaultHco)
1✔
744
        return defaultHco
1✔
745
}
1✔
746

747
// GetInstallStrategyBase returns the basics of an HCO InstallStrategy
748
func GetInstallStrategyBase(params *DeploymentOperatorParams) *csvv1alpha1.StrategyDetailsDeployment {
×
749
        return &csvv1alpha1.StrategyDetailsDeployment{
×
750

×
751
                DeploymentSpecs: []csvv1alpha1.StrategyDeploymentSpec{
×
752
                        {
×
753
                                Name:  hcoDeploymentName,
×
754
                                Spec:  GetDeploymentSpecOperator(params),
×
755
                                Label: getLabels(hcoName, params.HcoKvIoVersion),
×
756
                        },
×
757
                        {
×
758
                                Name:  hcoWhDeploymentName,
×
759
                                Spec:  GetDeploymentSpecWebhook(params.Namespace, params.WebhookImage, params.ImagePullPolicy, params.HcoKvIoVersion, params.Env),
×
760
                                Label: getLabels(hcoNameWebhook, params.HcoKvIoVersion),
×
761
                        },
×
762
                        {
×
763
                                Name:  cliDownloadsName,
×
764
                                Spec:  GetDeploymentSpecCliDownloads(params),
×
765
                                Label: getLabels(cliDownloadsName, params.HcoKvIoVersion),
×
766
                        },
×
767
                },
×
768
                Permissions: []csvv1alpha1.StrategyDeploymentPermissions{},
×
769
                ClusterPermissions: []csvv1alpha1.StrategyDeploymentPermissions{
×
770
                        {
×
771
                                ServiceAccountName: hcoName,
×
772
                                Rules:              GetClusterPermissions(),
×
773
                        },
×
774
                },
×
775
        }
×
776
}
×
777

778
type CSVBaseParams struct {
779
        Name            string
780
        Namespace       string
781
        DisplayName     string
782
        MetaDescription string
783
        Description     string
784
        Image           string
785
        Version         semver.Version
786
        CrdDisplay      string
787
}
788

789
// GetCSVBase returns a base HCO CSV without an InstallStrategy
790
func GetCSVBase(params *CSVBaseParams) *csvv1alpha1.ClusterServiceVersion {
×
791
        almExamples, _ := json.Marshal(
×
792
                map[string]interface{}{
×
793
                        "apiVersion": util.APIVersion,
×
794
                        "kind":       util.HyperConvergedKind,
×
795
                        "metadata": map[string]interface{}{
×
796
                                "name":      packageName,
×
797
                                "namespace": params.Namespace,
×
798
                                "annotations": map[string]string{
×
799
                                        "deployOVS": "false",
×
800
                                },
×
801
                        },
×
802
                        "spec": map[string]interface{}{},
×
803
                })
×
804

×
805
        // Explicitly fail on unvalidated (for any reason) requests:
×
806
        // this can make removing HCO CR harder if HCO webhook is not able
×
807
        // to really validate the requests.
×
808
        // In that case the user can only directly remove the
×
809
        // ValidatingWebhookConfiguration object first (eventually bypassing the OLM if needed).
×
810
        // so failurePolicy = admissionregistrationv1.Fail
×
811

×
812
        validatingWebhook := csvv1alpha1.WebhookDescription{
×
813
                GenerateName:            util.HcoValidatingWebhook,
×
814
                Type:                    csvv1alpha1.ValidatingAdmissionWebhook,
×
815
                DeploymentName:          hcoWhDeploymentName,
×
816
                ContainerPort:           util.WebhookPort,
×
817
                AdmissionReviewVersions: stringListToSlice("v1beta1", "v1"),
×
818
                SideEffects:             ptr.To(admissionregistrationv1.SideEffectClassNone),
×
819
                FailurePolicy:           ptr.To(admissionregistrationv1.Fail),
×
820
                TimeoutSeconds:          ptr.To[int32](10),
×
821
                Rules: []admissionregistrationv1.RuleWithOperations{
×
822
                        {
×
823
                                Operations: []admissionregistrationv1.OperationType{
×
824
                                        admissionregistrationv1.Create,
×
825
                                        admissionregistrationv1.Delete,
×
826
                                        admissionregistrationv1.Update,
×
827
                                },
×
828
                                Rule: admissionregistrationv1.Rule{
×
829
                                        APIGroups:   stringListToSlice(util.APIVersionGroup),
×
830
                                        APIVersions: stringListToSlice(util.APIVersionAlpha, util.APIVersionBeta),
×
831
                                        Resources:   stringListToSlice("hyperconvergeds"),
×
832
                                },
×
833
                        },
×
834
                },
×
835
                WebhookPath: ptr.To(util.HCOWebhookPath),
×
836
        }
×
837

×
838
        mutatingNamespaceWebhook := csvv1alpha1.WebhookDescription{
×
839
                GenerateName:            util.HcoMutatingWebhookNS,
×
840
                Type:                    csvv1alpha1.MutatingAdmissionWebhook,
×
841
                DeploymentName:          hcoWhDeploymentName,
×
842
                ContainerPort:           util.WebhookPort,
×
843
                AdmissionReviewVersions: stringListToSlice("v1beta1", "v1"),
×
844
                SideEffects:             ptr.To(admissionregistrationv1.SideEffectClassNoneOnDryRun),
×
845
                FailurePolicy:           ptr.To(admissionregistrationv1.Fail),
×
846
                TimeoutSeconds:          ptr.To[int32](10),
×
847
                ObjectSelector: &metav1.LabelSelector{
×
848
                        MatchLabels: map[string]string{util.KubernetesMetadataName: params.Namespace},
×
849
                },
×
850
                Rules: []admissionregistrationv1.RuleWithOperations{
×
851
                        {
×
852
                                Operations: []admissionregistrationv1.OperationType{
×
853
                                        admissionregistrationv1.Delete,
×
854
                                },
×
855
                                Rule: admissionregistrationv1.Rule{
×
856
                                        APIGroups:   []string{""},
×
857
                                        APIVersions: stringListToSlice("v1"),
×
858
                                        Resources:   stringListToSlice("namespaces"),
×
859
                                },
×
860
                        },
×
861
                },
×
862
                WebhookPath: ptr.To(util.HCONSWebhookPath),
×
863
        }
×
864

×
865
        mutatingHyperConvergedWebhook := csvv1alpha1.WebhookDescription{
×
866
                GenerateName:            util.HcoMutatingWebhookHyperConverged,
×
867
                Type:                    csvv1alpha1.MutatingAdmissionWebhook,
×
868
                DeploymentName:          hcoWhDeploymentName,
×
869
                ContainerPort:           util.WebhookPort,
×
870
                AdmissionReviewVersions: stringListToSlice("v1beta1", "v1"),
×
871
                SideEffects:             ptr.To(admissionregistrationv1.SideEffectClassNoneOnDryRun),
×
872
                FailurePolicy:           ptr.To(admissionregistrationv1.Fail),
×
873
                TimeoutSeconds:          ptr.To[int32](10),
×
874
                Rules: []admissionregistrationv1.RuleWithOperations{
×
875
                        {
×
876
                                Operations: []admissionregistrationv1.OperationType{
×
877
                                        admissionregistrationv1.Create,
×
878
                                        admissionregistrationv1.Update,
×
879
                                },
×
880
                                Rule: admissionregistrationv1.Rule{
×
881
                                        APIGroups:   stringListToSlice(util.APIVersionGroup),
×
882
                                        APIVersions: stringListToSlice(util.APIVersionAlpha, util.APIVersionBeta),
×
883
                                        Resources:   stringListToSlice("hyperconvergeds"),
×
884
                                },
×
885
                        },
×
886
                },
×
887
                WebhookPath: ptr.To(util.HCOMutatingWebhookPath),
×
888
        }
×
889

×
890
        return &csvv1alpha1.ClusterServiceVersion{
×
891
                TypeMeta: metav1.TypeMeta{
×
892
                        APIVersion: "operators.coreos.com/v1alpha1",
×
893
                        Kind:       "ClusterServiceVersion",
×
894
                },
×
895
                ObjectMeta: metav1.ObjectMeta{
×
896
                        Name:      fmt.Sprintf("%v.v%v", params.Name, params.Version.String()),
×
897
                        Namespace: params.Namespace,
×
898
                        Annotations: map[string]string{
×
899
                                "alm-examples":                   string(almExamples),
×
900
                                "capabilities":                   "Deep Insights",
×
901
                                "certified":                      "false",
×
902
                                "categories":                     "OpenShift Optional",
×
903
                                "containerImage":                 params.Image,
×
904
                                DisableOperandDeletionAnnotation: "true",
×
905
                                "createdAt":                      time.Now().Format("2006-01-02 15:04:05"),
×
906
                                "description":                    params.MetaDescription,
×
907
                                "repository":                     "https://github.com/kubevirt/hyperconverged-cluster-operator",
×
908
                                "support":                        "false",
×
909
                                "operatorframework.io/suggested-namespace":         params.Namespace,
×
910
                                "operatorframework.io/initialization-resource":     string(almExamples),
×
911
                                "operators.openshift.io/infrastructure-features":   `["disconnected","proxy-aware"]`, // TODO: deprecated, remove once all the tools support "features.operators.openshift.io/*"
×
912
                                "features.operators.openshift.io/disconnected":     "true",
×
913
                                "features.operators.openshift.io/fips-compliant":   "false",
×
914
                                "features.operators.openshift.io/proxy-aware":      "true",
×
915
                                "features.operators.openshift.io/cnf":              "false",
×
916
                                "features.operators.openshift.io/cni":              "true",
×
917
                                "features.operators.openshift.io/csi":              "true",
×
918
                                "features.operators.openshift.io/tls-profiles":     "true",
×
919
                                "features.operators.openshift.io/token-auth-aws":   "false",
×
920
                                "features.operators.openshift.io/token-auth-azure": "false",
×
921
                                "features.operators.openshift.io/token-auth-gcp":   "false",
×
922
                                "openshift.io/required-scc":                        "restricted-v2",
×
923
                        },
×
924
                },
×
925
                Spec: csvv1alpha1.ClusterServiceVersionSpec{
×
926
                        DisplayName: params.DisplayName,
×
927
                        Description: params.Description,
×
928
                        Keywords:    stringListToSlice("KubeVirt", "Virtualization"),
×
929
                        Version:     csvVersion.OperatorVersion{Version: params.Version},
×
930
                        Maintainers: []csvv1alpha1.Maintainer{
×
931
                                {
×
932
                                        Name:  kubevirtProjectName,
×
933
                                        Email: "kubevirt-dev@googlegroups.com",
×
934
                                },
×
935
                        },
×
936
                        Maturity: "alpha",
×
937
                        Provider: csvv1alpha1.AppLink{
×
938
                                Name: kubevirtProjectName,
×
939
                                // https://github.com/operator-framework/operator-courier/issues/173
×
940
                                // URL:  "https://kubevirt.io",
×
941
                        },
×
942
                        Links: []csvv1alpha1.AppLink{
×
943
                                {
×
944
                                        Name: kubevirtProjectName,
×
945
                                        URL:  "https://kubevirt.io",
×
946
                                },
×
947
                                {
×
948
                                        Name: "Source Code",
×
949
                                        URL:  "https://github.com/kubevirt/hyperconverged-cluster-operator",
×
950
                                },
×
951
                        },
×
952
                        Icon: []csvv1alpha1.Icon{
×
953
                                {
×
954
                                        MediaType: "image/svg+xml",
×
955
                                        Data:      "PHN2ZyB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciIHZpZXdCb3g9IjAgMCA3MDQgNzA3Ij48ZGVmcy8+PGcgZmlsbD0ibm9uZSIgZmlsbC1ydWxlPSJldmVub2RkIj48cGF0aCBkPSJNODguMzMgMTQwLjg5bC4zOC0uNC0uMzguNHpNNzQuMTggMTY3LjcyYy45Ni0zLjMgMi44Ny02LjU4IDUuNzQtOS44Ny0yLjg3IDMuMy00Ljc4IDYuNTgtNS43NCA5Ljg3ek0yMjcuNTIgNjkwLjcxYy0yLjk0IDAtNi42MiAwLTkuNTYtLjk5IDMuNjcgMCA2LjYyLjk5IDkuNTYuOTl6Ii8+PHBhdGggZmlsbD0iIzAwQUFCMiIgZmlsbC1ydWxlPSJub256ZXJvIiBkPSJNNjA2Ljg0IDEzNi45NEwzNzEuMjkgMjAuNTRsLTIuMy0xLjE4YTE4LjUgMTguNSAwIDAwLTQuOTYtMS41OGMtMS41My0uNC0zLjA2LS43OS00LjYtLjc5LTIuMjktLjM5LTQuOTYtLjM5LTcuMjYtLjM5LTQuOTcgMC05LjU2IDAtMTQuNTMuNzktMS41My40LTMuMDYuNC00Ljk3Ljc5TDk3LjEyIDEzNS4zNmEzNC45MSAzNC45MSAwIDAwLTguMDMgNS4xM2wtLjM4LjQgMTIxLjk4IDI1My4zLTkxLjc3LTE5My4zM0gyNzMuOGw2MS45NCAxMTcuOTctMjEuNDEgNDEuMDQtLjc3LjQtNjIuNy0xMTkuOTVIMTgyLjRsMTA3LjgzIDIzNS45NSAxNS4zLTMwYzQuOTYtOS40NiAxNi40NC0xMy40IDI2LTguMjhhMjAuMzMgMjAuMzMgMCAwMTguMDIgMjYuODNsLTI3LjkgNTQuMDYtMjEuNDIgNDEuMDMgNjIuNyAxMjkuODFMNDEyLjIyIDU2OWMtNi4xMiA4LjY4LTE4LjM2IDEwLjY1LTI2Ljc3IDQuMzQtNy42NS01LjUzLTkuOTQtMTYuMTgtNS43NC0yNC40N2wxMy43Ny0yOC40YzUuMzUtOS40NyAxNi44My0xMi42MyAyNi03LjEgOC4wMyA0LjczIDExLjQ3IDE0Ljk5IDguNDEgMjQuMDZsMjcuOTItNTYuODFjLTYuMTIgOC42OC0xOC4zNiAxMC42NS0yNi43NyAzLjk0YTE5LjkzIDE5LjkzIDAgMDEtNS43My0yNC40NmwyNy41My01Ni40MmM0LjU5LTkuODcgMTYuMDYtMTMuODEgMjUuNjItOC42OGExOS42NSAxOS42NSAwIDAxOC40MSAyNi40M2wtNi44OCAxMy44MSAzNS4xOC03MS44MWMtNi4xMiA5LjA4LTE3Ljk4IDExLjQ0LTI2LjM5IDUuMTNhMTkuNzggMTkuNzggMCAwMS02LjUtMjQuODZsMjcuMTUtNTYuNDJjNC41OS05Ljg2IDE2LjA2LTEzLjgxIDI1LjYyLTguNjggOS41NiA0LjczIDEzLjM4IDE2LjU3IDguNDEgMjYuNDRsLTE1LjMgMzEuOTUgNDMuNi04OC43N2MtNS4zNiA5LjQ3LTE2LjgzIDEzLjAyLTI2IDcuNWEyMC4wMyAyMC4wMyAwIDAxLTkuMTgtMTMuMDNoLTIyLjk0Yy0xMC43MSAwLTE5LjEyLTguNjgtMTkuMTItMTkuNzIgMC0xMS4wNSA4LjQxLTE5LjczIDE5LjEyLTE5LjczaDc5LjkxbC0xOS4xMiAzOS4wNiA0Ny4wNC05NS44OGE0MC44MiA0MC44MiAwIDAwLTQuNi0zLjk0IDQxLjg1IDQxLjg1IDAgMDAtOC4wMi01LjUzek00MDUuNyAzNDQuMWwtMjguNjggNTUuNjNjLTQuOTcgOS40Ny0xNi40NCAxMy40Mi0yNiA4LjI5LTkuNTYtNS4xMy0xMy0xNi45Ny04LjAzLTI2LjgzbDI4LjY3LTU1LjY0YzQuOTgtOS40NyAxNi40NS0xMy40MSAyNi04LjI4IDkuNTcgNS4xMyAxMyAxNy4zNiA4LjA0IDI2Ljgzem01OC44OC0xMTUuMjJsLTI4LjY4IDU2LjAzYy00Ljk3IDkuNDctMTYuNDQgMTMuNDItMjYgOC4yOWEyMC4zMyAyMC4zMyAwIDAxLTguMDMtMjYuODNsMzMuNjUtNjYuMjloMTIuMjRjMy4wNiAwIDYuMTIuOCA4LjggMi4zN2ExOS42MiAxOS42MiAwIDAxOC4wMiAyNi40M3oiLz48cGF0aCBmaWxsPSIjRkZGIiBmaWxsLXJ1bGU9Im5vbnplcm8iIGQ9Ik04OS4xIDE0MC41YTkxLjA1IDkxLjA1IDAgMDE4LjAyLTUuMTRMMzMyLjY3IDE4LjE4YzEuNTMtLjQgMy4wNi0uOCA0LjU5LS44IDQuOTctLjc4IDkuOTQtLjc4IDE0LjkxLS43OCAyLjMgMCA0Ljk3IDAgNy4yNy40IDEuNTMuMzkgMy40NC4zOSA0Ljk3Ljc4IDEuNTMuNCAzLjQ0LjggNC45NyAxLjU4bDIuMyAxLjE5IDIzNS41NCAxMTYuNGE0MS44NSA0MS44NSAwIDAxOC4wMyA1LjUyIDQwLjgyIDQwLjgyIDAgMDE0LjU5IDMuOTRsNy4yNy0xNC42Yy0zLjgzLTMuMTUtOC4wMy02LjMxLTEyLjYyLTguNjhoLS43N0wzNzguMTggNi4zNGE1NC4zIDU0LjMgMCAwMC0yNi01LjUyYy03LjY1LS40LTE1LjMuNC0yMi45NSAxLjk3bC0xLjUzLjQtMS41My43OEw5MC42MiAxMjEuMTZhNjYuOTkgNjYuOTkgMCAwMC04Ljc5IDUuNTJsNi44OCAxNC4yLjM4LS4zOXpNNzA1LjUgNDI1LjM3bC0uMzktMS41OC01OC44OS0yNjAuNDF2LTEuMTljLTMuNDQtMTEuNDQtMTAuMzItMjIuMS0xOS41LTI5LjU5bC03LjI2IDE0LjZjNC4yIDQuMzQgOC4wMyA5LjQ3IDEwLjMyIDE1YTIyLjc0IDIyLjc0IDAgMDExLjUzIDQuNzNsNTguNSAyNjAuNDFhOTIgOTIgMCAwMS4zOSAxMC4yNmMwIDMuMTUtLjc3IDUuOTItMS4xNSA5LjA3IDAgLjgtLjM4IDEuNTgtLjM4IDIuMzdhNTYuMjMgNTYuMjMgMCAwMS03LjY1IDE2Ljk3bC03MC4zNiA4OS45Ni05Mi41MyAxMTcuOTdjLTYuMTIgOC42OC0xNS42OCAxNC4yLTI2IDE1Ljc4LTMuMDYuNC02LjUuOC05LjU2LjhIMzUyLjk0bDU4Ljg4IDE1Ljc4aDcwLjc1YzIwLjI2IDAgMzcuMDktOC4yOSA0Ny44LTIyLjg5bDE2Mi44OS0yMDcuOTMuMzgtLjQuMzgtLjRjOS41Ni0xNC42IDEzLjc3LTMxLjk1IDExLjQ3LTQ5LjMxek0yMjIuOTMgNjkwLjEyYy0xLjUzIDAtMy40NC0uNC00Ljk3LS40LTIuMy0uNC00LjItLjc5LTYuNS0xLjU3bC0zLjQ0LTEuMTljLTIuMy0uNzktNC42LTEuOTctNi41LTIuNzZhNjAuMDEgNjAuMDEgMCAwMS05LjE4LTUuOTJjLTEuOTEtMS41OC0zLjgzLTMuMTYtNS4zNi00LjczbC01NC4zLTY5LjQ1LTEwOC4yLTEzOC44OGE1My40MiA1My40MiAwIDAxLTguOC0yMy4yOGMtLjM4LTEuNTgtLjM4LTMuMTYtLjM4LTQuNzQgMC0zLjU1IDAtNi43Ljc2LTEwLjI1bDU4LjEyLTI2MmEyNS42NCAyNS42NCAwIDAxMi4zLTcuMWMyLjY3LTYuNyA2Ljg4LTEyLjIzIDEyLjIzLTE2Ljk2bC02Ljg4LTE0LjJhNTcuNTMgNTcuNTMgMCAwMC0yMi41NiAzNC43MWwtNTguMTIgMjYydi43OWMtMy4wNiAxNy43NSAxLjE0IDM1LjUgMTEuMDkgNTAuMWwuMzguNC4zOC40TDE3NS41MSA2ODMuNGwuMzkuNzkuNzYuNGE2OS44MiA2OS44MiAwIDAwNDUuNSAyMS4zaDEzMC43OHYtMTUuNzhIMjIyLjkzeiIvPjxwYXRoIGZpbGw9IiNGRkYiIGZpbGwtcnVsZT0ibm9uemVybyIgZD0iTTM1Mi45NCA2OTAuMTJ2MTUuNzhoNTguODh6Ii8+PHBhdGggZmlsbD0iIzAwNzk3RiIgZmlsbC1ydWxlPSJub256ZXJvIiBkPSJNMjg5Ljg1IDU2MS4xbC03OS4xNi0xNjYuNUw4OC4zMyAxNDAuODhhNDEuNjggNDEuNjggMCAwMC0xMi4yNCAxNi45NmwtMi4yOSA3LjEtNTcuNzQgMjYyYy0uNzYgMy41NS0uNzYgNi43LS43NiAxMC4yNSAwIDEuNTggMCAzLjE2LjM4IDUuMTNhNTcuNDMgNTcuNDMgMCAwMDguOCAyMy4yOEwxMzMuMDYgNjA0LjVsNTQuMyA2OC42NWMxLjUzIDEuNTggMy40NCAzLjE2IDUuMzUgNC43NGEzNy4wOCAzNy4wOCAwIDAwOS4xOCA1LjkyYzIuMyAxLjE4IDQuMiAxLjk3IDYuNSAyLjc2bDMuNDQgMS4xOGMxLjkxLjc5IDQuMiAxLjE4IDYuNSAxLjU4IDEuNTMuNCAzLjQ0LjQgNC45Ny40aDEzMC4wMUwyOTAuOTkgNTU5LjlsLTEuMTQgMS4xOXoiLz48cGF0aCBkPSJNMTUuMyA0MzcuMmMwLTMuNTUgMC02LjcgMS45LTEwLjI1Ii8+PHBhdGggZmlsbD0iIzAwNzk3RiIgZmlsbC1ydWxlPSJub256ZXJvIiBkPSJNMTk2LjkzIDY4My40MWMtMy40Mi0zLjI5LTYuODMtNi41OC05LjU2LTkuODYgMi43MyAzLjI4IDYuMTQgNi41NyA5LjU2IDkuODZ6Ii8+PHBhdGggZD0iTTIwMi4yOCA2ODcuNzVhNjguNyA2OC43IDAgMDEtOS41Ni05Ljg2TTE4Ny4zNyA2NzMuMTVsLTU0LjMtNjkuMDVNMjE3IDY4OS45MmwtOC42LTIuOTYiLz48cGF0aCBmaWxsPSIjMDA3OTdGIiBmaWxsLXJ1bGU9Im5vbnplcm8iIGQ9Ik0yMTEuNDYgNjkxLjFjLTMuMzgtMS45Ny02Ljc1LTQuOTMtOS41Ni02LjkgMi44IDEuOTcgNi4xOCA0LjkzIDkuNTYgNi45eiIvPjxwYXRoIGZpbGw9IiMzQUNDQzUiIGZpbGwtcnVsZT0ibm9uemVybyIgZD0iTTU3MC4xMyAyNDcuNDJsLTQzLjYgODguNzgtMTEuODQgMjQuNDZhOC42OCA4LjY4IDAgMDEtMS4xNSAxLjk3bC0zNS4xOCA3MS40Mi0yMC42NSA0Mi42MWMtLjM4Ljc5LTEuMTUgMS45Ny0xLjUzIDIuNzZsLTI3LjkxIDU3LjIxYzAgLjQgMCAuNC0uMzkuOGwtMTMuNzYgMjguNGMtLjM4Ljc5LTEuMTUgMS45Ny0xLjUzIDIuNzZsLTU5LjI3IDEyMC43NGgxMjkuNjNjMy4wNiAwIDYuNS0uNCA5LjU2LS43OWEzOS44IDM5LjggMCAwMDI2LTE1Ljc4bDkyLjU0LTExNy45OCA3MC4zNS04OS45NmE1Mi4yIDUyLjIgMCAwMDcuNjUtMTYuOTZjLjM4LS44LjM4LTEuNTguMzgtMi4zN2EzNi45IDM2LjkgMCAwMDEuMTUtOS4wOGMwLTMuNTUgMC02LjctLjM4LTEwLjI1bC01OC41LTI1OS42M2MtLjM5LTEuNTctMS4xNS0zLjE1LTEuNTQtNC43My0yLjI5LTUuNTItNi4xMS0xMC42NS0xMC4zMi0xNWwtNDcuMDMgOTUuNDktMi42OCA1LjEzeiIvPjxwYXRoIGQ9Ik02OTIuMyA0MzcuMmMwIDMuNDMtMS45MSA2LjQ0LTIuODcgOS44N002OTIuNjggNDQ4LjY1Yy0xLjkgMy40NS0zLjgyIDYuOS02LjY5IDkuODZNNDkyLjEyIDY4OS4zM2EzOS44IDM5LjggMCAwMDI2LTE1Ljc4bDkyLjU0LTExNy45OE02OTAuNTggNDI2Ljk1Yy45NiAzLjU1Ljk2IDYuNy45NiAxMC4yNSIvPjxwYXRoIGZpbGw9IiNGRkYiIGZpbGwtcnVsZT0ibm9uemVybyIgZD0iTTM5Ny42OCAzMTcuMjZjLTkuMTgtNS4xMy0yMS4wMy0xLjU4LTI2IDguMjhMMzQzIDM4MS4xOGMtNC45NyA5LjQ3LTEuNTMgMjEuNyA4LjAzIDI2LjgzIDkuMTcgNS4xMyAyMS4wMyAxLjU3IDI2LTguMjlsMjguNjgtNTUuNjNjNC45Ny05LjQ3IDEuMTQtMjEuNy04LjAzLTI2Ljgzek00MTkuMDkgNTExLjM4YTE5LjAzIDE5LjAzIDAgMDAtMjUuNjIgOC42OGwtMTMuNzcgMjguNDFjLTQuNTggOS44Ni0uNzYgMjEuNyA4LjggMjYuNDQgOC40MSA0LjM0IDE4LjM1IDEuNTcgMjMuNy01LjkybDE1LjY4LTMxLjk2YzQuMjEtOS40Ny4zOS0yMC45MS04Ljc5LTI1LjY1ek00MjcuODggNTM3LjgyYzAtLjQgMC0uNC4zOS0uOEw0MTIuNTkgNTY5YTYuNDEgNi40MSAwIDAwMS41My0yLjc2bDEzLjc2LTI4LjQxeiIvPjxwYXRoIGZpbGw9IiNGRkYiIGZpbGwtcnVsZT0ibm9uemVybyIgZD0iTTMxMS42NCA1MTkuMjdsMjcuOTEtNTQuMDVjNC45OC05LjQ3IDEuNTMtMjEuNy04LjAzLTI2LjgzLTkuMTctNS4xMy0yMS4wMy0xLjU4LTI2IDguMjhsLTE1LjMgMjkuOTlMMTgyLjQgMjQwLjMyaDY4LjQ0bDYyLjcxIDExOS45NC43Ny0uNCAyMS4wMy00MC42My02MS45NS0xMTguMzdIMTE4LjU0TDIxMC4zIDM5NC4ybDc5LjkyIDE2NS43MSAyMS40MS00MC42NHoiLz48cGF0aCBmaWxsPSIjRkZGIiBmaWxsLXJ1bGU9Im5vbnplcm8iIGQ9Ik0yOTAuMjMgNTYwLjMxbC03OS41NC0xNjUuNzIgNzkuMTYgMTY2LjUxek01OTEuNTQgMjAzLjIzaC03OS45MWMtMTAuNzEgMC0xOS4xMiA4LjY4LTE5LjEyIDE5LjczIDAgMTEuMDQgOC40MSAxOS43MiAxOS4xMiAxOS43MmgyMi45NGMyLjMgMTAuNjYgMTIuNjIgMTcuMzcgMjIuOTQgMTVhMTkuNSAxOS41IDAgMDAxMi42Mi05LjQ3bDIuNjgtNS41MyAxOC43My0zOS40NXpNNTc2LjgyIDI0Mi4yOWwtNi42OSA5Ljg2Ljk2LS43ek01NDEuODMgMzA0LjYzYzQuOTgtOS44NiAxLjE1LTIxLjctOC40LTI2LjQ0LTkuNTctNC43My0yMS4wNC0xLjE4LTI1LjYzIDguNjl2LjM5bC0yNy4xNSA1Ni40MmMtNC41OSA5Ljg3LS43NiAyMS43IDguOCAyNi40NCA4LjQxIDQuMzQgMTguNzMgMS41OCAyNC4wOS02LjcxbDEzLTI2LjgzIDE1LjMtMzEuOTZ6Ii8+PHBhdGggZmlsbD0iI0ZGRiIgZmlsbC1ydWxlPSJub256ZXJvIiBkPSJNNTI2LjU0IDMzNi41OWwtMTMgMjYuODNjLjM4LS43OS43Ni0xLjU4IDEuMTUtMS45N2wxMS44NS0yNC44NnpNNDg0Ljg2IDQyMS4wM2M0LjU5LTkuODcuNzYtMjEuNy04LjQxLTI2LjQ0LTkuMTgtNC43My0yMS4wMy0uNzktMjUuNjIgOC42OGwtMjcuMTUgNTYuNDJjLTQuNTkgOS44Ny0uNzcgMjEuNyA4LjggMjYuNDQgOC40IDQuMzQgMTguMzUgMS41OCAyMy43LTUuOTJsMjIuMTgtNDUuMzcgNi41LTEzLjgxeiIvPjxwYXRoIGZpbGw9IiNGRkYiIGZpbGwtcnVsZT0ibm9uemVybyIgZD0iTTQ3OC4zNiA0MzQuODRsLTIyLjE4IDQ1LjM3Yy43Ny0uNzkgMS4xNS0xLjk3IDEuNTMtMi43NmwyMC42NS00Mi42MXpNNDU2LjU2IDIwMi40NGExNy4zNCAxNy4zNCAwIDAwLTguOC0yLjM3aC0xMS44NWwtMzMuNjQgNjYuMjlhMjAuMTUgMjAuMTUgMCAwMDQuOTcgMjcuNjJjOC44IDYuMzEgMjAuNjQgMy45NCAyNi43Ni01LjEzLjc3LTEuMTkgMS41My0yLjM3IDEuOTEtMy45NWwyOC42OC01NS42M2M0Ljk3LTkuODYgMS41My0yMS43LTguMDMtMjYuODMuMzkgMCAwIDAgMCAweiIvPjwvZz48L3N2Zz4=",
×
956
                                },
×
957
                        },
×
958
                        Labels: map[string]string{
×
959
                                "alm-owner-kubevirt": packageName,
×
960
                                "operated-by":        packageName,
×
961
                        },
×
962
                        Selector: &metav1.LabelSelector{
×
963
                                MatchLabels: map[string]string{
×
964
                                        "alm-owner-kubevirt": packageName,
×
965
                                        "operated-by":        packageName,
×
966
                                },
×
967
                        },
×
968
                        InstallModes: []csvv1alpha1.InstallMode{
×
969
                                {
×
970
                                        Type:      csvv1alpha1.InstallModeTypeOwnNamespace,
×
971
                                        Supported: false,
×
972
                                },
×
973
                                {
×
974
                                        Type:      csvv1alpha1.InstallModeTypeSingleNamespace,
×
975
                                        Supported: false,
×
976
                                },
×
977
                                {
×
978
                                        Type:      csvv1alpha1.InstallModeTypeMultiNamespace,
×
979
                                        Supported: false,
×
980
                                },
×
981
                                {
×
982
                                        Type:      csvv1alpha1.InstallModeTypeAllNamespaces,
×
983
                                        Supported: true,
×
984
                                },
×
985
                        },
×
986
                        // Skip this in favor of having a separate function to get
×
987
                        // the actual StrategyDetailsDeployment when merging CSVs
×
988
                        InstallStrategy: csvv1alpha1.NamedInstallStrategy{},
×
989
                        WebhookDefinitions: []csvv1alpha1.WebhookDescription{
×
990
                                validatingWebhook,
×
991
                                mutatingNamespaceWebhook,
×
992
                                mutatingHyperConvergedWebhook,
×
993
                        },
×
994
                        CustomResourceDefinitions: csvv1alpha1.CustomResourceDefinitions{
×
995
                                Owned: []csvv1alpha1.CRDDescription{
×
996
                                        {
×
997
                                                Name:        "hyperconvergeds.hco.kubevirt.io",
×
998
                                                Version:     util.CurrentAPIVersion,
×
999
                                                Kind:        util.HyperConvergedKind,
×
1000
                                                DisplayName: params.CrdDisplay + " Deployment",
×
1001
                                                Description: "Represents the deployment of " + params.CrdDisplay,
×
1002
                                                // TODO: move this to annotations on hyperconverged_types.go once kubebuilder
×
1003
                                                // properly supports SpecDescriptors as the operator-sdk already does
×
1004
                                                SpecDescriptors: []csvv1alpha1.SpecDescriptor{
×
1005
                                                        {
×
1006
                                                                DisplayName: "Infra components node affinity",
×
1007
                                                                Description: "nodeAffinity describes node affinity scheduling rules for the infra pods.",
×
1008
                                                                Path:        "infra.nodePlacement.affinity.nodeAffinity",
×
1009
                                                                XDescriptors: stringListToSlice(
×
1010
                                                                        "urn:alm:descriptor:com.tectonic.ui:nodeAffinity",
×
1011
                                                                ),
×
1012
                                                        },
×
1013
                                                        {
×
1014
                                                                DisplayName: "Infra components pod affinity",
×
1015
                                                                Description: "podAffinity describes pod affinity scheduling rules for the infra pods.",
×
1016
                                                                Path:        "infra.nodePlacement.affinity.podAffinity",
×
1017
                                                                XDescriptors: stringListToSlice(
×
1018
                                                                        "urn:alm:descriptor:com.tectonic.ui:podAffinity",
×
1019
                                                                ),
×
1020
                                                        },
×
1021
                                                        {
×
1022
                                                                DisplayName: "Infra components pod anti-affinity",
×
1023
                                                                Description: "podAntiAffinity describes pod anti affinity scheduling rules for the infra pods.",
×
1024
                                                                Path:        "infra.nodePlacement.affinity.podAntiAffinity",
×
1025
                                                                XDescriptors: stringListToSlice(
×
1026
                                                                        "urn:alm:descriptor:com.tectonic.ui:podAntiAffinity",
×
1027
                                                                ),
×
1028
                                                        },
×
1029
                                                        {
×
1030
                                                                DisplayName: "Workloads components node affinity",
×
1031
                                                                Description: "nodeAffinity describes node affinity scheduling rules for the workloads pods.",
×
1032
                                                                Path:        "workloads.nodePlacement.affinity.nodeAffinity",
×
1033
                                                                XDescriptors: stringListToSlice(
×
1034
                                                                        "urn:alm:descriptor:com.tectonic.ui:nodeAffinity",
×
1035
                                                                ),
×
1036
                                                        },
×
1037
                                                        {
×
1038
                                                                DisplayName: "Workloads components pod affinity",
×
1039
                                                                Description: "podAffinity describes pod affinity scheduling rules for the workloads pods.",
×
1040
                                                                Path:        "workloads.nodePlacement.affinity.podAffinity",
×
1041
                                                                XDescriptors: stringListToSlice(
×
1042
                                                                        "urn:alm:descriptor:com.tectonic.ui:podAffinity",
×
1043
                                                                ),
×
1044
                                                        },
×
1045
                                                        {
×
1046
                                                                DisplayName: "Workloads components pod anti-affinity",
×
1047
                                                                Description: "podAntiAffinity describes pod anti affinity scheduling rules for the workloads pods.",
×
1048
                                                                Path:        "workloads.nodePlacement.affinity.podAntiAffinity",
×
1049
                                                                XDescriptors: stringListToSlice(
×
1050
                                                                        "urn:alm:descriptor:com.tectonic.ui:podAntiAffinity",
×
1051
                                                                ),
×
1052
                                                        },
×
1053
                                                        {
×
1054
                                                                DisplayName: "HIDDEN FIELDS - operator version",
×
1055
                                                                Description: "HIDDEN FIELDS - operator version.",
×
1056
                                                                Path:        "version",
×
1057
                                                                XDescriptors: stringListToSlice(
×
1058
                                                                        "urn:alm:descriptor:com.tectonic.ui:hidden",
×
1059
                                                                ),
×
1060
                                                        },
×
1061
                                                },
×
1062
                                                StatusDescriptors: []csvv1alpha1.StatusDescriptor{},
×
1063
                                        },
×
1064
                                },
×
1065
                                Required: []csvv1alpha1.CRDDescription{},
×
1066
                        },
×
1067
                },
×
1068
        }
×
1069
}
×
1070

1071
func InjectVolumesForWebHookCerts(deploy *appsv1.Deployment) {
×
1072
        // check if there is already a volume for api certificates
×
1073
        for _, vol := range deploy.Spec.Template.Spec.Volumes {
×
1074
                if vol.Name == certVolume {
×
1075
                        return
×
1076
                }
×
1077
        }
1078

1079
        volume := v1.Volume{
×
1080
                Name: certVolume,
×
1081
                VolumeSource: corev1.VolumeSource{
×
1082
                        Secret: &corev1.SecretVolumeSource{
×
1083
                                SecretName:  deploy.Name + "-service-cert",
×
1084
                                DefaultMode: ptr.To[int32](420),
×
1085
                                Items: []corev1.KeyToPath{
×
1086
                                        {
×
1087
                                                Key:  "tls.crt",
×
1088
                                                Path: hcoutil.WebhookCertName,
×
1089
                                        },
×
1090
                                        {
×
1091
                                                Key:  "tls.key",
×
1092
                                                Path: hcoutil.WebhookKeyName,
×
1093
                                        },
×
1094
                                },
×
1095
                        },
×
1096
                },
×
1097
        }
×
1098
        deploy.Spec.Template.Spec.Volumes = append(deploy.Spec.Template.Spec.Volumes, volume)
×
1099

×
1100
        for index, container := range deploy.Spec.Template.Spec.Containers {
×
1101
                deploy.Spec.Template.Spec.Containers[index].VolumeMounts = append(container.VolumeMounts,
×
1102
                        corev1.VolumeMount{
×
1103
                                Name:      certVolume,
×
1104
                                MountPath: hcoutil.DefaultWebhookCertDir,
×
1105
                        })
×
1106
        }
×
1107
}
1108

1109
func getReadinessProbe() *corev1.Probe {
×
1110
        return &corev1.Probe{
×
1111
                ProbeHandler: corev1.ProbeHandler{
×
1112
                        HTTPGet: &corev1.HTTPGetAction{
×
1113
                                Path: hcoutil.ReadinessEndpointName,
×
1114
                                Port: intstr.IntOrString{
×
1115
                                        Type:   intstr.Int,
×
1116
                                        IntVal: hcoutil.HealthProbePort,
×
1117
                                },
×
1118
                                Scheme: corev1.URISchemeHTTP,
×
1119
                        },
×
1120
                },
×
1121
                InitialDelaySeconds: 5,
×
1122
                PeriodSeconds:       5,
×
1123
                FailureThreshold:    1,
×
1124
        }
×
1125
}
×
1126

1127
func getLivenessProbe() *corev1.Probe {
×
1128
        return &corev1.Probe{
×
1129
                ProbeHandler: corev1.ProbeHandler{
×
1130
                        HTTPGet: &corev1.HTTPGetAction{
×
1131
                                Path: hcoutil.LivenessEndpointName,
×
1132
                                Port: intstr.IntOrString{
×
1133
                                        Type:   intstr.Int,
×
1134
                                        IntVal: hcoutil.HealthProbePort,
×
1135
                                },
×
1136
                                Scheme: corev1.URISchemeHTTP,
×
1137
                        },
×
1138
                },
×
1139
                InitialDelaySeconds: 30,
×
1140
                PeriodSeconds:       5,
×
1141
                FailureThreshold:    1,
×
1142
        }
×
1143
}
×
1144

1145
func stringListToSlice(words ...string) []string {
×
1146
        return words
×
1147
}
×
1148

1149
func int32Ptr(i int32) *int32 {
×
1150
        return &i
×
1151
}
×
1152

1153
func panicOnError(err error) {
×
1154
        if err != nil {
×
1155
                panic(err)
×
1156
        }
1157
}
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