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

kubevirt / hyperconverged-cluster-operator / 16479226273

23 Jul 2025 06:48PM UTC coverage: 75.253% (-0.02%) from 75.274%
16479226273

Pull #3568

github

web-flow
Merge 7cfcb87ac into 073baf324
Pull Request #3568: Support NetworkPolicies in the bundle image

86 of 117 new or added lines in 6 files covered. (73.5%)

1 existing line in 1 file now uncovered.

6997 of 9298 relevant lines covered (75.25%)

1.77 hits per line

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

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

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

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

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

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

40
const DisableOperandDeletionAnnotation = "console.openshift.io/disable-operand-delete"
41

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

51
        cliDownloadsName = "hyperconverged-cluster-cli-download"
52

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

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

62
type DeploymentOperatorParams struct {
63
        Namespace              string
64
        Image                  string
65
        WebhookImage           string
66
        CliDownloadsImage      string
67
        KVUIPluginImage        string
68
        KVUIProxyImage         string
69
        PasstImage             string
70
        PasstCNIImage          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
        Env                    []corev1.EnvVar
89
        AddNetworkPolicyLabels bool
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(params *DeploymentOperatorParams) 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(params),
×
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() corev1.Service {
×
135
        return corev1.Service{
×
136
                TypeMeta: metav1.TypeMeta{
×
137
                        APIVersion: "v1",
×
138
                        Kind:       "Service",
×
139
                },
×
140
                ObjectMeta: metav1.ObjectMeta{
×
141
                        Name: hcoNameWebhook + "-service",
×
142
                },
×
143
                Spec: corev1.ServiceSpec{
×
144
                        Selector: map[string]string{
×
145
                                "name": hcoNameWebhook,
×
146
                        },
×
147
                        Ports: []corev1.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: ptr.To[int32](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: getLabelsWithNetworkPolicies(hcoName, params),
×
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(util.ReadinessEndpointName, util.HealthProbePort),
×
187
                                                LivenessProbe:   getLivenessProbe(util.LivenessEndpointName, util.HealthProbePort),
×
188
                                                Env:             envs,
×
189
                                                Resources: corev1.ResourceRequirements{
×
190
                                                        Requests: map[corev1.ResourceName]resource.Quantity{
×
191
                                                                corev1.ResourceCPU:    resource.MustParse("10m"),
×
192
                                                                corev1.ResourceMemory: resource.MustParse("96Mi"),
×
193
                                                        },
×
194
                                                },
×
195
                                                SecurityContext:          GetStdContainerSecurityContext(),
×
196
                                                TerminationMessagePolicy: corev1.TerminationMessageFallbackToLogsOnError,
×
197
                                                Ports: []corev1.ContainerPort{
×
198
                                                        getMetricsPort(),
×
199
                                                },
×
200
                                        },
×
201
                                },
×
202
                                PriorityClassName: "system-cluster-critical",
×
203
                        },
×
204
                },
×
205
        }
×
206
}
×
207

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

×
309
        if params.KvVirtLancherOsVersion != "" {
×
310
                envs = append(envs, corev1.EnvVar{
×
311
                        Name:  util.KvVirtLauncherOSVersionEnvV,
×
312
                        Value: params.KvVirtLancherOsVersion,
×
313
                })
×
314
        }
×
315

316
        return envs
×
317
}
318

319
func GetDeploymentSpecCliDownloads(params *DeploymentOperatorParams) appsv1.DeploymentSpec {
×
320
        return appsv1.DeploymentSpec{
×
321
                Replicas: ptr.To[int32](1),
×
322
                Selector: &metav1.LabelSelector{
×
323
                        MatchLabels: map[string]string{
×
324
                                "name": cliDownloadsName,
×
325
                        },
×
326
                },
×
327
                Strategy: appsv1.DeploymentStrategy{
×
328
                        Type: appsv1.RollingUpdateDeploymentStrategyType,
×
329
                },
×
330
                Template: corev1.PodTemplateSpec{
×
331
                        ObjectMeta: metav1.ObjectMeta{
×
332
                                Labels: getLabels(cliDownloadsName, params.HcoKvIoVersion),
×
333
                        },
×
334
                        Spec: corev1.PodSpec{
×
335
                                ServiceAccountName:           cliDownloadsName,
×
336
                                AutomountServiceAccountToken: ptr.To(false),
×
337
                                SecurityContext:              GetStdPodSecurityContext(),
×
338
                                Containers: []corev1.Container{
×
339
                                        {
×
340
                                                Name:            "server",
×
341
                                                Image:           params.CliDownloadsImage,
×
342
                                                ImagePullPolicy: corev1.PullPolicy(params.ImagePullPolicy),
×
343
                                                Resources: corev1.ResourceRequirements{
×
344
                                                        Requests: map[corev1.ResourceName]resource.Quantity{
×
345
                                                                corev1.ResourceCPU:    resource.MustParse("10m"),
×
346
                                                                corev1.ResourceMemory: resource.MustParse("96Mi"),
×
347
                                                        },
×
348
                                                },
×
349
                                                Ports: []corev1.ContainerPort{
×
350
                                                        {
×
351
                                                                Protocol:      corev1.ProtocolTCP,
×
352
                                                                ContainerPort: util.CliDownloadsServerPort,
×
353
                                                        },
×
354
                                                },
×
355
                                                SecurityContext:          GetStdContainerSecurityContext(),
×
356
                                                ReadinessProbe:           getReadinessProbe("/health", util.CliDownloadsServerPort),
×
357
                                                LivenessProbe:            getLivenessProbe("/health", util.CliDownloadsServerPort),
×
358
                                                TerminationMessagePolicy: corev1.TerminationMessageFallbackToLogsOnError,
×
359
                                        },
×
360
                                },
×
361
                                PriorityClassName: "system-cluster-critical",
×
362
                        },
×
363
                },
×
364
        }
×
365
}
×
366

367
func getLabels(name, hcoKvIoVersion string) map[string]string {
×
368
        return map[string]string{
×
369
                "name":                 name,
×
370
                util.AppLabelVersion:   hcoKvIoVersion,
×
371
                util.AppLabelPartOf:    util.HyperConvergedCluster,
×
372
                util.AppLabelComponent: string(util.AppComponentDeployment),
×
373
        }
×
374
}
×
375

376
func getLabelsWithNetworkPolicies(deploymentName string, params *DeploymentOperatorParams) map[string]string {
×
377
        labels := getLabels(deploymentName, params.HcoKvIoVersion)
×
378
        if params.AddNetworkPolicyLabels {
×
NEW
379
                labels[util.AllowEgressToDNSAndAPIServerLabel] = "true"
×
NEW
380
                labels[util.AllowIngressToMetricsEndpointLabel] = "true"
×
UNCOV
381
        }
×
382

383
        return labels
×
384
}
385

386
func GetStdPodSecurityContext() *corev1.PodSecurityContext {
3✔
387
        return &corev1.PodSecurityContext{
3✔
388
                RunAsNonRoot: ptr.To(true),
3✔
389
                SeccompProfile: &corev1.SeccompProfile{
3✔
390
                        Type: corev1.SeccompProfileTypeRuntimeDefault,
3✔
391
                },
3✔
392
        }
3✔
393
}
3✔
394

395
func GetStdContainerSecurityContext() *corev1.SecurityContext {
3✔
396
        return &corev1.SecurityContext{
3✔
397
                AllowPrivilegeEscalation: ptr.To(false),
3✔
398
                Capabilities: &corev1.Capabilities{
3✔
399
                        Drop: []corev1.Capability{"ALL"},
3✔
400
                },
3✔
401
        }
3✔
402
}
3✔
403

404
// Currently we are abusing the pod readiness to signal to OLM that HCO is not ready
405
// for an upgrade. This has a lot of side effects, one of this is the validating webhook
406
// being not able to receive traffic when exposed by a pod that is not reporting ready=true.
407
// This can cause a lot of side effects if not deadlocks when the system reach a status where,
408
// for any possible reason, HCO pod cannot be ready and so HCO pod cannot validate any further update or
409
// delete request on HCO CR.
410
// A proper solution is properly use the readiness probe only to report the pod readiness and communicate
411
// status to OLM via conditions once OLM will be ready for:
412
// https://github.com/operator-framework/enhancements/blob/master/enhancements/operator-conditions.md
413
// in the meanwhile a quick (but dirty!) solution is to expose the same hco binary on two distinct pods:
414
// the first one will run only the controller and the second one (almost always ready) just the validating
415
// webhook one.
416
func GetDeploymentSpecWebhook(params *DeploymentOperatorParams) appsv1.DeploymentSpec {
×
417
        return appsv1.DeploymentSpec{
×
418
                Replicas: ptr.To[int32](1),
×
419
                Selector: &metav1.LabelSelector{
×
420
                        MatchLabels: map[string]string{
×
421
                                "name": hcoNameWebhook,
×
422
                        },
×
423
                },
×
424
                Strategy: appsv1.DeploymentStrategy{
×
425
                        Type: appsv1.RollingUpdateDeploymentStrategyType,
×
426
                },
×
427
                Template: corev1.PodTemplateSpec{
×
428
                        ObjectMeta: metav1.ObjectMeta{
×
429
                                Labels: getLabelsWithNetworkPolicies(hcoNameWebhook, params),
×
430
                        },
×
431
                        Spec: corev1.PodSpec{
×
432
                                ServiceAccountName: hcoName,
×
433
                                SecurityContext:    GetStdPodSecurityContext(),
×
434
                                Containers: []corev1.Container{
×
435
                                        {
×
436
                                                Name:            hcoNameWebhook,
×
437
                                                Image:           params.WebhookImage,
×
438
                                                ImagePullPolicy: corev1.PullPolicy(params.ImagePullPolicy),
×
439
                                                Command:         stringListToSlice(hcoNameWebhook),
×
440
                                                ReadinessProbe:  getReadinessProbe(util.ReadinessEndpointName, util.HealthProbePort),
×
441
                                                LivenessProbe:   getLivenessProbe(util.LivenessEndpointName, util.HealthProbePort),
×
442
                                                Env: append([]corev1.EnvVar{
×
443
                                                        {
×
444
                                                                // deprecated: left here for CI test.
×
445
                                                                Name:  util.OperatorWebhookModeEnv,
×
446
                                                                Value: "true",
×
447
                                                        },
×
448
                                                        {
×
449
                                                                Name:  util.ContainerAppName,
×
450
                                                                Value: util.ContainerWebhookApp,
×
451
                                                        },
×
452
                                                        {
×
453
                                                                Name:  "OPERATOR_IMAGE",
×
454
                                                                Value: params.WebhookImage,
×
455
                                                        },
×
456
                                                        {
×
457
                                                                Name:  "OPERATOR_NAME",
×
458
                                                                Value: hcoNameWebhook,
×
459
                                                        },
×
460
                                                        {
×
461
                                                                Name:  "OPERATOR_NAMESPACE",
×
462
                                                                Value: params.Namespace,
×
463
                                                        },
×
464
                                                        {
×
465
                                                                Name: "POD_NAME",
×
466
                                                                ValueFrom: &corev1.EnvVarSource{
×
467
                                                                        FieldRef: &corev1.ObjectFieldSelector{
×
468
                                                                                FieldPath: "metadata.name",
×
469
                                                                        },
×
470
                                                                },
×
471
                                                        },
×
472
                                                }, params.Env...),
×
473
                                                Resources: corev1.ResourceRequirements{
×
474
                                                        Requests: map[corev1.ResourceName]resource.Quantity{
×
475
                                                                corev1.ResourceCPU:    resource.MustParse("5m"),
×
476
                                                                corev1.ResourceMemory: resource.MustParse("48Mi"),
×
477
                                                        },
×
478
                                                },
×
479
                                                SecurityContext:          GetStdContainerSecurityContext(),
×
480
                                                TerminationMessagePolicy: corev1.TerminationMessageFallbackToLogsOnError,
×
481
                                                Ports: []corev1.ContainerPort{
×
482
                                                        getWebhookPort(),
×
483
                                                        getMetricsPort(),
×
484
                                                },
×
485
                                        },
×
486
                                },
×
487
                                PriorityClassName: "system-node-critical",
×
488
                        },
×
489
                },
×
490
        }
×
491
}
×
492

493
func GetClusterRole() rbacv1.ClusterRole {
×
494
        return rbacv1.ClusterRole{
×
495
                TypeMeta: metav1.TypeMeta{
×
496
                        APIVersion: rbacVersionV1,
×
497
                        Kind:       "ClusterRole",
×
498
                },
×
499
                ObjectMeta: metav1.ObjectMeta{
×
500
                        Name: hcoName,
×
501
                        Labels: map[string]string{
×
502
                                "name": hcoName,
×
503
                        },
×
504
                },
×
505
                Rules: GetClusterPermissions(),
×
506
        }
×
507
}
×
508

509
var (
510
        emptyAPIGroup = []string{""}
511
)
512

513
func GetClusterPermissions() []rbacv1.PolicyRule {
×
514
        const configOpenshiftIO = "config.openshift.io"
×
515
        const operatorOpenshiftIO = "operator.openshift.io"
×
516
        return []rbacv1.PolicyRule{
×
517
                {
×
518
                        APIGroups: stringListToSlice(util.APIVersionGroup),
×
519
                        Resources: stringListToSlice("hyperconvergeds"),
×
520
                        Verbs:     stringListToSlice("get", "list", "update", "watch"),
×
521
                },
×
522
                {
×
523
                        APIGroups: stringListToSlice(util.APIVersionGroup),
×
524
                        Resources: stringListToSlice("hyperconvergeds/finalizers", "hyperconvergeds/status"),
×
525
                        Verbs:     stringListToSlice("get", "list", "create", "update", "watch"),
×
526
                },
×
527
                roleWithAllPermissions(kvapi.GroupName, stringListToSlice("kubevirts", "kubevirts/finalizers")),
×
528
                roleWithAllPermissions(cdiapi.GroupName, stringListToSlice("cdis", "cdis/finalizers")),
×
529
                roleWithAllPermissions(sspapi.GroupVersion.Group, stringListToSlice("ssps", "ssps/finalizers")),
×
530
                roleWithAllPermissions(cnaoapi.GroupVersion.Group, stringListToSlice("networkaddonsconfigs", "networkaddonsconfigs/finalizers")),
×
531
                roleWithAllPermissions(aaqapi.GroupName, stringListToSlice("aaqs", "aaqs/finalizers")),
×
532
                roleWithAllPermissions("", stringListToSlice("configmaps")),
×
533
                {
×
534
                        APIGroups: emptyAPIGroup,
×
535
                        Resources: stringListToSlice("events"),
×
536
                        Verbs:     stringListToSlice("get", "list", "watch", "create", "patch"),
×
537
                },
×
538
                roleWithAllPermissions("", stringListToSlice("services")),
×
539
                {
×
540
                        APIGroups: emptyAPIGroup,
×
541
                        Resources: stringListToSlice("pods", "nodes"),
×
542
                        Verbs:     stringListToSlice("get", "list", "watch"),
×
543
                },
×
544
                {
×
545
                        APIGroups: emptyAPIGroup,
×
546
                        Resources: stringListToSlice("secrets"),
×
547
                        Verbs:     stringListToSlice("get", "list", "watch", "create", "update"),
×
548
                },
×
549
                {
×
550
                        APIGroups: emptyAPIGroup,
×
551
                        Resources: stringListToSlice("endpoints"),
×
552
                        Verbs:     stringListToSlice("get", "list", "delete", "watch"),
×
553
                },
×
554
                {
×
555
                        APIGroups: emptyAPIGroup,
×
556
                        Resources: stringListToSlice("namespaces"),
×
557
                        Verbs:     stringListToSlice("get", "list", "watch", "patch", "update"),
×
558
                },
×
559
                {
×
560
                        APIGroups: stringListToSlice("apps"),
×
561
                        Resources: stringListToSlice("deployments", "replicasets", "daemonsets"),
×
562
                        Verbs:     stringListToSlice("get", "list", "watch", "create", "update", "delete"),
×
563
                },
×
564
                roleWithAllPermissions("rbac.authorization.k8s.io", stringListToSlice("roles", "rolebindings")),
×
565
                {
×
566
                        APIGroups: stringListToSlice("apiextensions.k8s.io"),
×
567
                        Resources: stringListToSlice("customresourcedefinitions"),
×
568
                        Verbs:     stringListToSlice("get", "list", "watch", "delete"),
×
569
                },
×
570
                {
×
571
                        APIGroups: stringListToSlice("apiextensions.k8s.io"),
×
572
                        Resources: stringListToSlice("customresourcedefinitions/status"),
×
573
                        Verbs:     stringListToSlice("get", "list", "watch", "patch", "update"),
×
574
                },
×
575
                roleWithAllPermissions("monitoring.coreos.com", stringListToSlice("servicemonitors", "prometheusrules")),
×
576
                {
×
577
                        APIGroups: stringListToSlice("operators.coreos.com"),
×
578
                        Resources: stringListToSlice("clusterserviceversions"),
×
579
                        Verbs:     stringListToSlice("get", "list", "watch", "update", "patch"),
×
580
                },
×
581
                {
×
582
                        APIGroups: stringListToSlice("scheduling.k8s.io"),
×
583
                        Resources: stringListToSlice("priorityclasses"),
×
584
                        Verbs:     stringListToSlice("get", "list", "watch", "create", "delete", "patch"),
×
585
                },
×
586
                {
×
587
                        APIGroups: stringListToSlice("admissionregistration.k8s.io"),
×
588
                        Resources: stringListToSlice("validatingwebhookconfigurations"),
×
589
                        Verbs:     stringListToSlice("list", "watch", "update", "patch"),
×
590
                },
×
591
                roleWithAllPermissions("console.openshift.io", stringListToSlice("consoleclidownloads", "consolequickstarts")),
×
592
                {
×
593
                        APIGroups: stringListToSlice(configOpenshiftIO),
×
594
                        Resources: stringListToSlice("clusterversions", "infrastructures", "networks"),
×
595
                        Verbs:     stringListToSlice("get", "list"),
×
596
                },
×
597
                {
×
598
                        APIGroups: stringListToSlice(configOpenshiftIO),
×
599
                        Resources: stringListToSlice("ingresses"),
×
600
                        Verbs:     stringListToSlice("get", "list", "watch"),
×
601
                },
×
602
                {
×
603
                        APIGroups: stringListToSlice(configOpenshiftIO),
×
604
                        Resources: stringListToSlice("ingresses/status"),
×
605
                        Verbs:     stringListToSlice("update"),
×
606
                },
×
607
                {
×
608
                        APIGroups: stringListToSlice(configOpenshiftIO),
×
609
                        Resources: stringListToSlice("apiservers"),
×
610
                        Verbs:     stringListToSlice("get", "list", "watch"),
×
611
                },
×
612
                {
×
613
                        APIGroups: stringListToSlice(operatorOpenshiftIO),
×
614
                        Resources: stringListToSlice("kubedeschedulers"),
×
615
                        Verbs:     stringListToSlice("get", "list", "watch"),
×
616
                },
×
617
                {
×
618
                        APIGroups: stringListToSlice(configOpenshiftIO),
×
619
                        Resources: stringListToSlice("dnses"),
×
620
                        Verbs:     stringListToSlice("get"),
×
621
                },
×
622
                roleWithAllPermissions("coordination.k8s.io", stringListToSlice("leases")),
×
623
                roleWithAllPermissions("route.openshift.io", stringListToSlice("routes")),
×
624
                {
×
625
                        APIGroups: stringListToSlice("route.openshift.io"),
×
626
                        Resources: stringListToSlice("routes/custom-host"),
×
627
                        Verbs:     stringListToSlice("create", "update", "patch"),
×
628
                },
×
629
                {
×
630
                        APIGroups: stringListToSlice("operators.coreos.com"),
×
631
                        Resources: stringListToSlice("operatorconditions"),
×
632
                        Verbs:     stringListToSlice("get", "list", "watch", "update", "patch"),
×
633
                },
×
634
                roleWithAllPermissions("image.openshift.io", stringListToSlice("imagestreams")),
×
635
                roleWithAllPermissions("console.openshift.io", stringListToSlice("consoleplugins")),
×
636
                {
×
637
                        APIGroups: stringListToSlice("operator.openshift.io"),
×
638
                        Resources: stringListToSlice("consoles"),
×
639
                        Verbs:     stringListToSlice("get", "list", "watch", "update"),
×
640
                },
×
641
                {
×
642
                        APIGroups: stringListToSlice("monitoring.coreos.com"),
×
643
                        Resources: stringListToSlice("alertmanagers", "alertmanagers/api"),
×
644
                        Verbs:     stringListToSlice("get", "list", "create", "delete"),
×
645
                },
×
646
                {
×
647
                        APIGroups: stringListToSlice(""),
×
648
                        Resources: stringListToSlice("serviceaccounts"),
×
649
                        Verbs:     stringListToSlice("get", "list", "watch", "create", "update", "delete"),
×
650
                },
×
651
                {
×
652
                        APIGroups: stringListToSlice("k8s.cni.cncf.io"),
×
653
                        Resources: stringListToSlice("network-attachment-definitions"),
×
654
                        Verbs:     stringListToSlice("get", "list", "watch", "create", "update", "delete"),
×
655
                },
×
656
                {
×
657
                        APIGroups: stringListToSlice("security.openshift.io"),
×
658
                        Resources: stringListToSlice("securitycontextconstraints"),
×
659
                        Verbs:     stringListToSlice("get", "list", "watch", "create", "update", "delete"),
×
660
                },
×
NEW
661
                {
×
NEW
662
                        APIGroups: stringListToSlice(networkingv1.GroupName),
×
NEW
663
                        Resources: stringListToSlice("networkpolicies"),
×
NEW
664
                        Verbs:     stringListToSlice("get", "list", "watch", "create", "update", "delete"),
×
NEW
665
                },
×
666
        }
×
667
}
×
668

669
func roleWithAllPermissions(apiGroup string, resources []string) rbacv1.PolicyRule {
×
670
        return rbacv1.PolicyRule{
×
671
                APIGroups: stringListToSlice(apiGroup),
×
672
                Resources: resources,
×
673
                Verbs:     stringListToSlice("get", "list", "watch", "create", "update", "delete", "patch"),
×
674
        }
×
675
}
×
676

677
func GetServiceAccount(namespace string) corev1.ServiceAccount {
×
678
        return createServiceAccount(namespace, hcoName)
×
679
}
×
680

681
func GetCLIDownloadServiceAccount(namespace string) corev1.ServiceAccount {
×
682
        return createServiceAccount(namespace, cliDownloadsName)
×
683
}
×
684

685
func createServiceAccount(namespace, name string) corev1.ServiceAccount {
×
686
        return corev1.ServiceAccount{
×
687
                TypeMeta: metav1.TypeMeta{
×
688
                        APIVersion: "v1",
×
689
                        Kind:       "ServiceAccount",
×
690
                },
×
691
                ObjectMeta: metav1.ObjectMeta{
×
692
                        Name:      name,
×
693
                        Namespace: namespace,
×
694
                        Labels: map[string]string{
×
695
                                "name": name,
×
696
                        },
×
697
                },
×
698
        }
×
699
}
×
700

701
func GetClusterRoleBinding(namespace string) rbacv1.ClusterRoleBinding {
×
702
        return rbacv1.ClusterRoleBinding{
×
703
                TypeMeta: metav1.TypeMeta{
×
704
                        APIVersion: rbacVersionV1,
×
705
                        Kind:       "ClusterRoleBinding",
×
706
                },
×
707
                ObjectMeta: metav1.ObjectMeta{
×
708
                        Name: hcoName,
×
709
                        Labels: map[string]string{
×
710
                                "name": hcoName,
×
711
                        },
×
712
                },
×
713
                RoleRef: rbacv1.RoleRef{
×
714
                        APIGroup: "rbac.authorization.k8s.io",
×
715
                        Kind:     "ClusterRole",
×
716
                        Name:     hcoName,
×
717
                },
×
718
                Subjects: []rbacv1.Subject{
×
719
                        {
×
720
                                Kind:      "ServiceAccount",
×
721
                                Name:      hcoName,
×
722
                                Namespace: namespace,
×
723
                        },
×
724
                },
×
725
        }
×
726
}
×
727

728
func packageErrors(pkg *loader.Package, filterKinds ...packages.ErrorKind) error {
×
729
        toSkip := make(map[packages.ErrorKind]struct{})
×
730
        for _, errKind := range filterKinds {
×
731
                toSkip[errKind] = struct{}{}
×
732
        }
×
733
        var outErr error
×
734
        packages.Visit([]*packages.Package{pkg.Package}, nil, func(pkgRaw *packages.Package) {
×
735
                for _, err := range pkgRaw.Errors {
×
736
                        if _, skip := toSkip[err.Kind]; skip {
×
737
                                continue
×
738
                        }
739
                        outErr = err
×
740
                }
741
        })
742
        return outErr
×
743
}
744

745
const objectType = "object"
746

747
func GetOperatorCRD(relPath string) *extv1.CustomResourceDefinition {
×
748
        pkgs, err := loader.LoadRoots(relPath)
×
749
        if err != nil {
×
750
                panic(err)
×
751
        }
752
        reg := &markers.Registry{}
×
753
        panicOnError(crdmarkers.Register(reg))
×
754

×
755
        parser := &crdgen.Parser{
×
756
                Collector:                  &markers.Collector{Registry: reg},
×
757
                Checker:                    &loader.TypeChecker{},
×
758
                GenerateEmbeddedObjectMeta: true,
×
759
        }
×
760

×
761
        crdgen.AddKnownTypes(parser)
×
762
        if len(pkgs) == 0 {
×
763
                panic("Failed identifying packages")
×
764
        }
765
        for _, p := range pkgs {
×
766
                parser.NeedPackage(p)
×
767
        }
×
768
        groupKind := schema.GroupKind{Kind: util.HyperConvergedKind, Group: util.APIVersionGroup}
×
769
        parser.NeedCRDFor(groupKind, nil)
×
770
        for _, p := range pkgs {
×
771
                err = packageErrors(p, packages.TypeError)
×
772
                if err != nil {
×
773
                        panic(err)
×
774
                }
775
        }
776
        c := parser.CustomResourceDefinitions[groupKind]
×
777
        // enforce validation of CR name to prevent multiple CRs
×
778
        for _, v := range c.Spec.Versions {
×
779
                v.Schema.OpenAPIV3Schema.Properties["metadata"] = extv1.JSONSchemaProps{
×
780
                        Type: objectType,
×
781
                        Properties: map[string]extv1.JSONSchemaProps{
×
782
                                "name": {
×
783
                                        Type:    "string",
×
784
                                        Pattern: hcov1beta1.HyperConvergedName,
×
785
                                },
×
786
                        },
×
787
                }
×
788
        }
×
789
        return &c
×
790
}
791

792
func GetOperatorCR() *hcov1beta1.HyperConverged {
11✔
793
        defaultScheme := runtime.NewScheme()
11✔
794
        _ = hcov1beta1.AddToScheme(defaultScheme)
11✔
795
        _ = hcov1beta1.RegisterDefaults(defaultScheme)
11✔
796
        defaultHco := &hcov1beta1.HyperConverged{
11✔
797
                TypeMeta: metav1.TypeMeta{
11✔
798
                        APIVersion: util.APIVersion,
11✔
799
                        Kind:       util.HyperConvergedKind,
11✔
800
                },
11✔
801
                ObjectMeta: metav1.ObjectMeta{
11✔
802
                        Name: crName,
11✔
803
                }}
11✔
804
        defaultScheme.Default(defaultHco)
11✔
805
        return defaultHco
11✔
806
}
11✔
807

808
// GetInstallStrategyBase returns the basics of an HCO InstallStrategy
809
func GetInstallStrategyBase(params *DeploymentOperatorParams) *csvv1alpha1.StrategyDetailsDeployment {
×
810
        return &csvv1alpha1.StrategyDetailsDeployment{
×
811

×
812
                DeploymentSpecs: []csvv1alpha1.StrategyDeploymentSpec{
×
813
                        {
×
814
                                Name:  hcoDeploymentName,
×
815
                                Spec:  GetDeploymentSpecOperator(params),
×
816
                                Label: getLabels(hcoName, params.HcoKvIoVersion),
×
817
                        },
×
818
                        {
×
819
                                Name:  hcoWhDeploymentName,
×
820
                                Spec:  GetDeploymentSpecWebhook(params),
×
821
                                Label: getLabels(hcoNameWebhook, params.HcoKvIoVersion),
×
822
                        },
×
823
                        {
×
824
                                Name:  cliDownloadsName,
×
825
                                Spec:  GetDeploymentSpecCliDownloads(params),
×
826
                                Label: getLabels(cliDownloadsName, params.HcoKvIoVersion),
×
827
                        },
×
828
                },
×
829
                Permissions: []csvv1alpha1.StrategyDeploymentPermissions{},
×
830
                ClusterPermissions: []csvv1alpha1.StrategyDeploymentPermissions{
×
831
                        {
×
832
                                ServiceAccountName: hcoName,
×
833
                                Rules:              GetClusterPermissions(),
×
834
                        },
×
835
                        {
×
836
                                ServiceAccountName: cliDownloadsName,
×
837
                                Rules:              []rbacv1.PolicyRule{},
×
838
                        },
×
839
                },
×
840
        }
×
841
}
×
842

843
type CSVBaseParams struct {
844
        Name            string
845
        Namespace       string
846
        DisplayName     string
847
        MetaDescription string
848
        Description     string
849
        Image           string
850
        Replaces        string
851
        Version         semver.Version
852
        CrdDisplay      string
853
}
854

855
// GetCSVBase returns a base HCO CSV without an InstallStrategy
856
func GetCSVBase(params *CSVBaseParams) *csvv1alpha1.ClusterServiceVersion {
×
857
        almExamples, _ := json.Marshal(
×
858
                map[string]interface{}{
×
859
                        "apiVersion": util.APIVersion,
×
860
                        "kind":       util.HyperConvergedKind,
×
861
                        "metadata": map[string]interface{}{
×
862
                                "name":      packageName,
×
863
                                "namespace": params.Namespace,
×
864
                                "annotations": map[string]string{
×
865
                                        "deployOVS": "false",
×
866
                                },
×
867
                        },
×
868
                        "spec": map[string]interface{}{},
×
869
                })
×
870

×
871
        // Explicitly fail on unvalidated (for any reason) requests:
×
872
        // this can make removing HCO CR harder if HCO webhook is not able
×
873
        // to really validate the requests.
×
874
        // In that case the user can only directly remove the
×
875
        // ValidatingWebhookConfiguration object first (eventually bypassing the OLM if needed).
×
876
        // so failurePolicy = admissionregistrationv1.Fail
×
877

×
878
        validatingWebhook := csvv1alpha1.WebhookDescription{
×
879
                GenerateName:            util.HcoValidatingWebhook,
×
880
                Type:                    csvv1alpha1.ValidatingAdmissionWebhook,
×
881
                DeploymentName:          hcoWhDeploymentName,
×
882
                ContainerPort:           util.WebhookPort,
×
883
                AdmissionReviewVersions: stringListToSlice("v1beta1", "v1"),
×
884
                SideEffects:             ptr.To(admissionregistrationv1.SideEffectClassNone),
×
885
                FailurePolicy:           ptr.To(admissionregistrationv1.Fail),
×
886
                TimeoutSeconds:          ptr.To[int32](10),
×
887
                Rules: []admissionregistrationv1.RuleWithOperations{
×
888
                        {
×
889
                                Operations: []admissionregistrationv1.OperationType{
×
890
                                        admissionregistrationv1.Create,
×
891
                                        admissionregistrationv1.Delete,
×
892
                                        admissionregistrationv1.Update,
×
893
                                },
×
894
                                Rule: admissionregistrationv1.Rule{
×
895
                                        APIGroups:   stringListToSlice(util.APIVersionGroup),
×
896
                                        APIVersions: stringListToSlice(util.APIVersionAlpha, util.APIVersionBeta),
×
897
                                        Resources:   stringListToSlice("hyperconvergeds"),
×
898
                                },
×
899
                        },
×
900
                },
×
901
                WebhookPath: ptr.To(util.HCOWebhookPath),
×
902
        }
×
903

×
904
        mutatingNamespaceWebhook := csvv1alpha1.WebhookDescription{
×
905
                GenerateName:            util.HcoMutatingWebhookNS,
×
906
                Type:                    csvv1alpha1.MutatingAdmissionWebhook,
×
907
                DeploymentName:          hcoWhDeploymentName,
×
908
                ContainerPort:           util.WebhookPort,
×
909
                AdmissionReviewVersions: stringListToSlice("v1beta1", "v1"),
×
910
                SideEffects:             ptr.To(admissionregistrationv1.SideEffectClassNoneOnDryRun),
×
911
                FailurePolicy:           ptr.To(admissionregistrationv1.Fail),
×
912
                TimeoutSeconds:          ptr.To[int32](10),
×
913
                ObjectSelector: &metav1.LabelSelector{
×
914
                        MatchLabels: map[string]string{util.KubernetesMetadataName: params.Namespace},
×
915
                },
×
916
                Rules: []admissionregistrationv1.RuleWithOperations{
×
917
                        {
×
918
                                Operations: []admissionregistrationv1.OperationType{
×
919
                                        admissionregistrationv1.Delete,
×
920
                                },
×
921
                                Rule: admissionregistrationv1.Rule{
×
922
                                        APIGroups:   []string{""},
×
923
                                        APIVersions: stringListToSlice("v1"),
×
924
                                        Resources:   stringListToSlice("namespaces"),
×
925
                                },
×
926
                        },
×
927
                },
×
928
                WebhookPath: ptr.To(util.HCONSWebhookPath),
×
929
        }
×
930

×
931
        mutatingHyperConvergedWebhook := csvv1alpha1.WebhookDescription{
×
932
                GenerateName:            util.HcoMutatingWebhookHyperConverged,
×
933
                Type:                    csvv1alpha1.MutatingAdmissionWebhook,
×
934
                DeploymentName:          hcoWhDeploymentName,
×
935
                ContainerPort:           util.WebhookPort,
×
936
                AdmissionReviewVersions: stringListToSlice("v1beta1", "v1"),
×
937
                SideEffects:             ptr.To(admissionregistrationv1.SideEffectClassNoneOnDryRun),
×
938
                FailurePolicy:           ptr.To(admissionregistrationv1.Fail),
×
939
                TimeoutSeconds:          ptr.To[int32](10),
×
940
                Rules: []admissionregistrationv1.RuleWithOperations{
×
941
                        {
×
942
                                Operations: []admissionregistrationv1.OperationType{
×
943
                                        admissionregistrationv1.Create,
×
944
                                        admissionregistrationv1.Update,
×
945
                                },
×
946
                                Rule: admissionregistrationv1.Rule{
×
947
                                        APIGroups:   stringListToSlice(util.APIVersionGroup),
×
948
                                        APIVersions: stringListToSlice(util.APIVersionAlpha, util.APIVersionBeta),
×
949
                                        Resources:   stringListToSlice("hyperconvergeds"),
×
950
                                },
×
951
                        },
×
952
                },
×
953
                WebhookPath: ptr.To(util.HCOMutatingWebhookPath),
×
954
        }
×
955

×
956
        return &csvv1alpha1.ClusterServiceVersion{
×
957
                TypeMeta: metav1.TypeMeta{
×
958
                        APIVersion: "operators.coreos.com/v1alpha1",
×
959
                        Kind:       "ClusterServiceVersion",
×
960
                },
×
961
                ObjectMeta: metav1.ObjectMeta{
×
962
                        Name:      fmt.Sprintf("%v.v%v", params.Name, params.Version.String()),
×
963
                        Namespace: params.Namespace,
×
964
                        Annotations: map[string]string{
×
965
                                "alm-examples":                   string(almExamples),
×
966
                                "capabilities":                   "Deep Insights",
×
967
                                "certified":                      "false",
×
968
                                "categories":                     "OpenShift Optional",
×
969
                                "containerImage":                 params.Image,
×
970
                                DisableOperandDeletionAnnotation: "true",
×
971
                                "createdAt":                      time.Now().Format("2006-01-02 15:04:05"),
×
972
                                "description":                    params.MetaDescription,
×
973
                                "repository":                     "https://github.com/kubevirt/hyperconverged-cluster-operator",
×
974
                                "support":                        "false",
×
975
                                "operatorframework.io/suggested-namespace":         params.Namespace,
×
976
                                "operatorframework.io/initialization-resource":     string(almExamples),
×
977
                                "operators.openshift.io/infrastructure-features":   `["disconnected","proxy-aware"]`, // TODO: deprecated, remove once all the tools support "features.operators.openshift.io/*"
×
978
                                "features.operators.openshift.io/disconnected":     "true",
×
979
                                "features.operators.openshift.io/fips-compliant":   "false",
×
980
                                "features.operators.openshift.io/proxy-aware":      "true",
×
981
                                "features.operators.openshift.io/cnf":              "false",
×
982
                                "features.operators.openshift.io/cni":              "true",
×
983
                                "features.operators.openshift.io/csi":              "true",
×
984
                                "features.operators.openshift.io/tls-profiles":     "true",
×
985
                                "features.operators.openshift.io/token-auth-aws":   "false",
×
986
                                "features.operators.openshift.io/token-auth-azure": "false",
×
987
                                "features.operators.openshift.io/token-auth-gcp":   "false",
×
988
                                "openshift.io/required-scc":                        "restricted-v2",
×
989
                        },
×
990
                },
×
991
                Spec: csvv1alpha1.ClusterServiceVersionSpec{
×
992
                        DisplayName: params.DisplayName,
×
993
                        Description: params.Description,
×
994
                        Keywords:    stringListToSlice("KubeVirt", "Virtualization"),
×
995
                        Version:     csvVersion.OperatorVersion{Version: params.Version},
×
996
                        Replaces:    params.Replaces,
×
997
                        Maintainers: []csvv1alpha1.Maintainer{
×
998
                                {
×
999
                                        Name:  kubevirtProjectName,
×
1000
                                        Email: "kubevirt-dev@googlegroups.com",
×
1001
                                },
×
1002
                        },
×
1003
                        Maturity: "alpha",
×
1004
                        Provider: csvv1alpha1.AppLink{
×
1005
                                Name: kubevirtProjectName,
×
1006
                                // https://github.com/operator-framework/operator-courier/issues/173
×
1007
                                // URL:  "https://kubevirt.io",
×
1008
                        },
×
1009
                        Links: []csvv1alpha1.AppLink{
×
1010
                                {
×
1011
                                        Name: kubevirtProjectName,
×
1012
                                        URL:  "https://kubevirt.io",
×
1013
                                },
×
1014
                                {
×
1015
                                        Name: "Source Code",
×
1016
                                        URL:  "https://github.com/kubevirt/hyperconverged-cluster-operator",
×
1017
                                },
×
1018
                        },
×
1019
                        Icon: []csvv1alpha1.Icon{
×
1020
                                {
×
1021
                                        MediaType: "image/svg+xml",
×
1022
                                        Data:      "PHN2ZyB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciIHZpZXdCb3g9IjAgMCA3MDQgNzA3Ij48ZGVmcy8+PGcgZmlsbD0ibm9uZSIgZmlsbC1ydWxlPSJldmVub2RkIj48cGF0aCBkPSJNODguMzMgMTQwLjg5bC4zOC0uNC0uMzguNHpNNzQuMTggMTY3LjcyYy45Ni0zLjMgMi44Ny02LjU4IDUuNzQtOS44Ny0yLjg3IDMuMy00Ljc4IDYuNTgtNS43NCA5Ljg3ek0yMjcuNTIgNjkwLjcxYy0yLjk0IDAtNi42MiAwLTkuNTYtLjk5IDMuNjcgMCA2LjYyLjk5IDkuNTYuOTl6Ii8+PHBhdGggZmlsbD0iIzAwQUFCMiIgZmlsbC1ydWxlPSJub256ZXJvIiBkPSJNNjA2Ljg0IDEzNi45NEwzNzEuMjkgMjAuNTRsLTIuMy0xLjE4YTE4LjUgMTguNSAwIDAwLTQuOTYtMS41OGMtMS41My0uNC0zLjA2LS43OS00LjYtLjc5LTIuMjktLjM5LTQuOTYtLjM5LTcuMjYtLjM5LTQuOTcgMC05LjU2IDAtMTQuNTMuNzktMS41My40LTMuMDYuNC00Ljk3Ljc5TDk3LjEyIDEzNS4zNmEzNC45MSAzNC45MSAwIDAwLTguMDMgNS4xM2wtLjM4LjQgMTIxLjk4IDI1My4zLTkxLjc3LTE5My4zM0gyNzMuOGw2MS45NCAxMTcuOTctMjEuNDEgNDEuMDQtLjc3LjQtNjIuNy0xMTkuOTVIMTgyLjRsMTA3LjgzIDIzNS45NSAxNS4zLTMwYzQuOTYtOS40NiAxNi40NC0xMy40IDI2LTguMjhhMjAuMzMgMjAuMzMgMCAwMTguMDIgMjYuODNsLTI3LjkgNTQuMDYtMjEuNDIgNDEuMDMgNjIuNyAxMjkuODFMNDEyLjIyIDU2OWMtNi4xMiA4LjY4LTE4LjM2IDEwLjY1LTI2Ljc3IDQuMzQtNy42NS01LjUzLTkuOTQtMTYuMTgtNS43NC0yNC40N2wxMy43Ny0yOC40YzUuMzUtOS40NyAxNi44My0xMi42MyAyNi03LjEgOC4wMyA0LjczIDExLjQ3IDE0Ljk5IDguNDEgMjQuMDZsMjcuOTItNTYuODFjLTYuMTIgOC42OC0xOC4zNiAxMC42NS0yNi43NyAzLjk0YTE5LjkzIDE5LjkzIDAgMDEtNS43My0yNC40NmwyNy41My01Ni40MmM0LjU5LTkuODcgMTYuMDYtMTMuODEgMjUuNjItOC42OGExOS42NSAxOS42NSAwIDAxOC40MSAyNi40M2wtNi44OCAxMy44MSAzNS4xOC03MS44MWMtNi4xMiA5LjA4LTE3Ljk4IDExLjQ0LTI2LjM5IDUuMTNhMTkuNzggMTkuNzggMCAwMS02LjUtMjQuODZsMjcuMTUtNTYuNDJjNC41OS05Ljg2IDE2LjA2LTEzLjgxIDI1LjYyLTguNjggOS41NiA0LjczIDEzLjM4IDE2LjU3IDguNDEgMjYuNDRsLTE1LjMgMzEuOTUgNDMuNi04OC43N2MtNS4zNiA5LjQ3LTE2LjgzIDEzLjAyLTI2IDcuNWEyMC4wMyAyMC4wMyAwIDAxLTkuMTgtMTMuMDNoLTIyLjk0Yy0xMC43MSAwLTE5LjEyLTguNjgtMTkuMTItMTkuNzIgMC0xMS4wNSA4LjQxLTE5LjczIDE5LjEyLTE5LjczaDc5LjkxbC0xOS4xMiAzOS4wNiA0Ny4wNC05NS44OGE0MC44MiA0MC44MiAwIDAwLTQuNi0zLjk0IDQxLjg1IDQxLjg1IDAgMDAtOC4wMi01LjUzek00MDUuNyAzNDQuMWwtMjguNjggNTUuNjNjLTQuOTcgOS40Ny0xNi40NCAxMy40Mi0yNiA4LjI5LTkuNTYtNS4xMy0xMy0xNi45Ny04LjAzLTI2LjgzbDI4LjY3LTU1LjY0YzQuOTgtOS40NyAxNi40NS0xMy40MSAyNi04LjI4IDkuNTcgNS4xMyAxMyAxNy4zNiA4LjA0IDI2Ljgzem01OC44OC0xMTUuMjJsLTI4LjY4IDU2LjAzYy00Ljk3IDkuNDctMTYuNDQgMTMuNDItMjYgOC4yOWEyMC4zMyAyMC4zMyAwIDAxLTguMDMtMjYuODNsMzMuNjUtNjYuMjloMTIuMjRjMy4wNiAwIDYuMTIuOCA4LjggMi4zN2ExOS42MiAxOS42MiAwIDAxOC4wMiAyNi40M3oiLz48cGF0aCBmaWxsPSIjRkZGIiBmaWxsLXJ1bGU9Im5vbnplcm8iIGQ9Ik04OS4xIDE0MC41YTkxLjA1IDkxLjA1IDAgMDE4LjAyLTUuMTRMMzMyLjY3IDE4LjE4YzEuNTMtLjQgMy4wNi0uOCA0LjU5LS44IDQuOTctLjc4IDkuOTQtLjc4IDE0LjkxLS43OCAyLjMgMCA0Ljk3IDAgNy4yNy40IDEuNTMuMzkgMy40NC4zOSA0Ljk3Ljc4IDEuNTMuNCAzLjQ0LjggNC45NyAxLjU4bDIuMyAxLjE5IDIzNS41NCAxMTYuNGE0MS44NSA0MS44NSAwIDAxOC4wMyA1LjUyIDQwLjgyIDQwLjgyIDAgMDE0LjU5IDMuOTRsNy4yNy0xNC42Yy0zLjgzLTMuMTUtOC4wMy02LjMxLTEyLjYyLTguNjhoLS43N0wzNzguMTggNi4zNGE1NC4zIDU0LjMgMCAwMC0yNi01LjUyYy03LjY1LS40LTE1LjMuNC0yMi45NSAxLjk3bC0xLjUzLjQtMS41My43OEw5MC42MiAxMjEuMTZhNjYuOTkgNjYuOTkgMCAwMC04Ljc5IDUuNTJsNi44OCAxNC4yLjM4LS4zOXpNNzA1LjUgNDI1LjM3bC0uMzktMS41OC01OC44OS0yNjAuNDF2LTEuMTljLTMuNDQtMTEuNDQtMTAuMzItMjIuMS0xOS41LTI5LjU5bC03LjI2IDE0LjZjNC4yIDQuMzQgOC4wMyA5LjQ3IDEwLjMyIDE1YTIyLjc0IDIyLjc0IDAgMDExLjUzIDQuNzNsNTguNSAyNjAuNDFhOTIgOTIgMCAwMS4zOSAxMC4yNmMwIDMuMTUtLjc3IDUuOTItMS4xNSA5LjA3IDAgLjgtLjM4IDEuNTgtLjM4IDIuMzdhNTYuMjMgNTYuMjMgMCAwMS03LjY1IDE2Ljk3bC03MC4zNiA4OS45Ni05Mi41MyAxMTcuOTdjLTYuMTIgOC42OC0xNS42OCAxNC4yLTI2IDE1Ljc4LTMuMDYuNC02LjUuOC05LjU2LjhIMzUyLjk0bDU4Ljg4IDE1Ljc4aDcwLjc1YzIwLjI2IDAgMzcuMDktOC4yOSA0Ny44LTIyLjg5bDE2Mi44OS0yMDcuOTMuMzgtLjQuMzgtLjRjOS41Ni0xNC42IDEzLjc3LTMxLjk1IDExLjQ3LTQ5LjMxek0yMjIuOTMgNjkwLjEyYy0xLjUzIDAtMy40NC0uNC00Ljk3LS40LTIuMy0uNC00LjItLjc5LTYuNS0xLjU3bC0zLjQ0LTEuMTljLTIuMy0uNzktNC42LTEuOTctNi41LTIuNzZhNjAuMDEgNjAuMDEgMCAwMS05LjE4LTUuOTJjLTEuOTEtMS41OC0zLjgzLTMuMTYtNS4zNi00LjczbC01NC4zLTY5LjQ1LTEwOC4yLTEzOC44OGE1My40MiA1My40MiAwIDAxLTguOC0yMy4yOGMtLjM4LTEuNTgtLjM4LTMuMTYtLjM4LTQuNzQgMC0zLjU1IDAtNi43Ljc2LTEwLjI1bDU4LjEyLTI2MmEyNS42NCAyNS42NCAwIDAxMi4zLTcuMWMyLjY3LTYuNyA2Ljg4LTEyLjIzIDEyLjIzLTE2Ljk2bC02Ljg4LTE0LjJhNTcuNTMgNTcuNTMgMCAwMC0yMi41NiAzNC43MWwtNTguMTIgMjYydi43OWMtMy4wNiAxNy43NSAxLjE0IDM1LjUgMTEuMDkgNTAuMWwuMzguNC4zOC40TDE3NS41MSA2ODMuNGwuMzkuNzkuNzYuNGE2OS44MiA2OS44MiAwIDAwNDUuNSAyMS4zaDEzMC43OHYtMTUuNzhIMjIyLjkzeiIvPjxwYXRoIGZpbGw9IiNGRkYiIGZpbGwtcnVsZT0ibm9uemVybyIgZD0iTTM1Mi45NCA2OTAuMTJ2MTUuNzhoNTguODh6Ii8+PHBhdGggZmlsbD0iIzAwNzk3RiIgZmlsbC1ydWxlPSJub256ZXJvIiBkPSJNMjg5Ljg1IDU2MS4xbC03OS4xNi0xNjYuNUw4OC4zMyAxNDAuODhhNDEuNjggNDEuNjggMCAwMC0xMi4yNCAxNi45NmwtMi4yOSA3LjEtNTcuNzQgMjYyYy0uNzYgMy41NS0uNzYgNi43LS43NiAxMC4yNSAwIDEuNTggMCAzLjE2LjM4IDUuMTNhNTcuNDMgNTcuNDMgMCAwMDguOCAyMy4yOEwxMzMuMDYgNjA0LjVsNTQuMyA2OC42NWMxLjUzIDEuNTggMy40NCAzLjE2IDUuMzUgNC43NGEzNy4wOCAzNy4wOCAwIDAwOS4xOCA1LjkyYzIuMyAxLjE4IDQuMiAxLjk3IDYuNSAyLjc2bDMuNDQgMS4xOGMxLjkxLjc5IDQuMiAxLjE4IDYuNSAxLjU4IDEuNTMuNCAzLjQ0LjQgNC45Ny40aDEzMC4wMUwyOTAuOTkgNTU5LjlsLTEuMTQgMS4xOXoiLz48cGF0aCBkPSJNMTUuMyA0MzcuMmMwLTMuNTUgMC02LjcgMS45LTEwLjI1Ii8+PHBhdGggZmlsbD0iIzAwNzk3RiIgZmlsbC1ydWxlPSJub256ZXJvIiBkPSJNMTk2LjkzIDY4My40MWMtMy40Mi0zLjI5LTYuODMtNi41OC05LjU2LTkuODYgMi43MyAzLjI4IDYuMTQgNi41NyA5LjU2IDkuODZ6Ii8+PHBhdGggZD0iTTIwMi4yOCA2ODcuNzVhNjguNyA2OC43IDAgMDEtOS41Ni05Ljg2TTE4Ny4zNyA2NzMuMTVsLTU0LjMtNjkuMDVNMjE3IDY4OS45MmwtOC42LTIuOTYiLz48cGF0aCBmaWxsPSIjMDA3OTdGIiBmaWxsLXJ1bGU9Im5vbnplcm8iIGQ9Ik0yMTEuNDYgNjkxLjFjLTMuMzgtMS45Ny02Ljc1LTQuOTMtOS41Ni02LjkgMi44IDEuOTcgNi4xOCA0LjkzIDkuNTYgNi45eiIvPjxwYXRoIGZpbGw9IiMzQUNDQzUiIGZpbGwtcnVsZT0ibm9uemVybyIgZD0iTTU3MC4xMyAyNDcuNDJsLTQzLjYgODguNzgtMTEuODQgMjQuNDZhOC42OCA4LjY4IDAgMDEtMS4xNSAxLjk3bC0zNS4xOCA3MS40Mi0yMC42NSA0Mi42MWMtLjM4Ljc5LTEuMTUgMS45Ny0xLjUzIDIuNzZsLTI3LjkxIDU3LjIxYzAgLjQgMCAuNC0uMzkuOGwtMTMuNzYgMjguNGMtLjM4Ljc5LTEuMTUgMS45Ny0xLjUzIDIuNzZsLTU5LjI3IDEyMC43NGgxMjkuNjNjMy4wNiAwIDYuNS0uNCA5LjU2LS43OWEzOS44IDM5LjggMCAwMDI2LTE1Ljc4bDkyLjU0LTExNy45OCA3MC4zNS04OS45NmE1Mi4yIDUyLjIgMCAwMDcuNjUtMTYuOTZjLjM4LS44LjM4LTEuNTguMzgtMi4zN2EzNi45IDM2LjkgMCAwMDEuMTUtOS4wOGMwLTMuNTUgMC02LjctLjM4LTEwLjI1bC01OC41LTI1OS42M2MtLjM5LTEuNTctMS4xNS0zLjE1LTEuNTQtNC43My0yLjI5LTUuNTItNi4xMS0xMC42NS0xMC4zMi0xNWwtNDcuMDMgOTUuNDktMi42OCA1LjEzeiIvPjxwYXRoIGQ9Ik02OTIuMyA0MzcuMmMwIDMuNDMtMS45MSA2LjQ0LTIuODcgOS44N002OTIuNjggNDQ4LjY1Yy0xLjkgMy40NS0zLjgyIDYuOS02LjY5IDkuODZNNDkyLjEyIDY4OS4zM2EzOS44IDM5LjggMCAwMDI2LTE1Ljc4bDkyLjU0LTExNy45OE02OTAuNTggNDI2Ljk1Yy45NiAzLjU1Ljk2IDYuNy45NiAxMC4yNSIvPjxwYXRoIGZpbGw9IiNGRkYiIGZpbGwtcnVsZT0ibm9uemVybyIgZD0iTTM5Ny42OCAzMTcuMjZjLTkuMTgtNS4xMy0yMS4wMy0xLjU4LTI2IDguMjhMMzQzIDM4MS4xOGMtNC45NyA5LjQ3LTEuNTMgMjEuNyA4LjAzIDI2LjgzIDkuMTcgNS4xMyAyMS4wMyAxLjU3IDI2LTguMjlsMjguNjgtNTUuNjNjNC45Ny05LjQ3IDEuMTQtMjEuNy04LjAzLTI2Ljgzek00MTkuMDkgNTExLjM4YTE5LjAzIDE5LjAzIDAgMDAtMjUuNjIgOC42OGwtMTMuNzcgMjguNDFjLTQuNTggOS44Ni0uNzYgMjEuNyA4LjggMjYuNDQgOC40MSA0LjM0IDE4LjM1IDEuNTcgMjMuNy01LjkybDE1LjY4LTMxLjk2YzQuMjEtOS40Ny4zOS0yMC45MS04Ljc5LTI1LjY1ek00MjcuODggNTM3LjgyYzAtLjQgMC0uNC4zOS0uOEw0MTIuNTkgNTY5YTYuNDEgNi40MSAwIDAwMS41My0yLjc2bDEzLjc2LTI4LjQxeiIvPjxwYXRoIGZpbGw9IiNGRkYiIGZpbGwtcnVsZT0ibm9uemVybyIgZD0iTTMxMS42NCA1MTkuMjdsMjcuOTEtNTQuMDVjNC45OC05LjQ3IDEuNTMtMjEuNy04LjAzLTI2LjgzLTkuMTctNS4xMy0yMS4wMy0xLjU4LTI2IDguMjhsLTE1LjMgMjkuOTlMMTgyLjQgMjQwLjMyaDY4LjQ0bDYyLjcxIDExOS45NC43Ny0uNCAyMS4wMy00MC42My02MS45NS0xMTguMzdIMTE4LjU0TDIxMC4zIDM5NC4ybDc5LjkyIDE2NS43MSAyMS40MS00MC42NHoiLz48cGF0aCBmaWxsPSIjRkZGIiBmaWxsLXJ1bGU9Im5vbnplcm8iIGQ9Ik0yOTAuMjMgNTYwLjMxbC03OS41NC0xNjUuNzIgNzkuMTYgMTY2LjUxek01OTEuNTQgMjAzLjIzaC03OS45MWMtMTAuNzEgMC0xOS4xMiA4LjY4LTE5LjEyIDE5LjczIDAgMTEuMDQgOC40MSAxOS43MiAxOS4xMiAxOS43MmgyMi45NGMyLjMgMTAuNjYgMTIuNjIgMTcuMzcgMjIuOTQgMTVhMTkuNSAxOS41IDAgMDAxMi42Mi05LjQ3bDIuNjgtNS41MyAxOC43My0zOS40NXpNNTc2LjgyIDI0Mi4yOWwtNi42OSA5Ljg2Ljk2LS43ek01NDEuODMgMzA0LjYzYzQuOTgtOS44NiAxLjE1LTIxLjctOC40LTI2LjQ0LTkuNTctNC43My0yMS4wNC0xLjE4LTI1LjYzIDguNjl2LjM5bC0yNy4xNSA1Ni40MmMtNC41OSA5Ljg3LS43NiAyMS43IDguOCAyNi40NCA4LjQxIDQuMzQgMTguNzMgMS41OCAyNC4wOS02LjcxbDEzLTI2LjgzIDE1LjMtMzEuOTZ6Ii8+PHBhdGggZmlsbD0iI0ZGRiIgZmlsbC1ydWxlPSJub256ZXJvIiBkPSJNNTI2LjU0IDMzNi41OWwtMTMgMjYuODNjLjM4LS43OS43Ni0xLjU4IDEuMTUtMS45N2wxMS44NS0yNC44NnpNNDg0Ljg2IDQyMS4wM2M0LjU5LTkuODcuNzYtMjEuNy04LjQxLTI2LjQ0LTkuMTgtNC43My0yMS4wMy0uNzktMjUuNjIgOC42OGwtMjcuMTUgNTYuNDJjLTQuNTkgOS44Ny0uNzcgMjEuNyA4LjggMjYuNDQgOC40IDQuMzQgMTguMzUgMS41OCAyMy43LTUuOTJsMjIuMTgtNDUuMzcgNi41LTEzLjgxeiIvPjxwYXRoIGZpbGw9IiNGRkYiIGZpbGwtcnVsZT0ibm9uemVybyIgZD0iTTQ3OC4zNiA0MzQuODRsLTIyLjE4IDQ1LjM3Yy43Ny0uNzkgMS4xNS0xLjk3IDEuNTMtMi43NmwyMC42NS00Mi42MXpNNDU2LjU2IDIwMi40NGExNy4zNCAxNy4zNCAwIDAwLTguOC0yLjM3aC0xMS44NWwtMzMuNjQgNjYuMjlhMjAuMTUgMjAuMTUgMCAwMDQuOTcgMjcuNjJjOC44IDYuMzEgMjAuNjQgMy45NCAyNi43Ni01LjEzLjc3LTEuMTkgMS41My0yLjM3IDEuOTEtMy45NWwyOC42OC01NS42M2M0Ljk3LTkuODYgMS41My0yMS43LTguMDMtMjYuODMuMzkgMCAwIDAgMCAweiIvPjwvZz48L3N2Zz4=",
×
1023
                                },
×
1024
                        },
×
1025
                        Labels: map[string]string{
×
1026
                                "alm-owner-kubevirt": packageName,
×
1027
                                "operated-by":        packageName,
×
1028
                        },
×
1029
                        Selector: &metav1.LabelSelector{
×
1030
                                MatchLabels: map[string]string{
×
1031
                                        "alm-owner-kubevirt": packageName,
×
1032
                                        "operated-by":        packageName,
×
1033
                                },
×
1034
                        },
×
1035
                        InstallModes: []csvv1alpha1.InstallMode{
×
1036
                                {
×
1037
                                        Type:      csvv1alpha1.InstallModeTypeOwnNamespace,
×
1038
                                        Supported: false,
×
1039
                                },
×
1040
                                {
×
1041
                                        Type:      csvv1alpha1.InstallModeTypeSingleNamespace,
×
1042
                                        Supported: false,
×
1043
                                },
×
1044
                                {
×
1045
                                        Type:      csvv1alpha1.InstallModeTypeMultiNamespace,
×
1046
                                        Supported: false,
×
1047
                                },
×
1048
                                {
×
1049
                                        Type:      csvv1alpha1.InstallModeTypeAllNamespaces,
×
1050
                                        Supported: true,
×
1051
                                },
×
1052
                        },
×
1053
                        // Skip this in favor of having a separate function to get
×
1054
                        // the actual StrategyDetailsDeployment when merging CSVs
×
1055
                        InstallStrategy: csvv1alpha1.NamedInstallStrategy{},
×
1056
                        WebhookDefinitions: []csvv1alpha1.WebhookDescription{
×
1057
                                validatingWebhook,
×
1058
                                mutatingNamespaceWebhook,
×
1059
                                mutatingHyperConvergedWebhook,
×
1060
                        },
×
1061
                        CustomResourceDefinitions: csvv1alpha1.CustomResourceDefinitions{
×
1062
                                Owned: []csvv1alpha1.CRDDescription{
×
1063
                                        {
×
1064
                                                Name:        "hyperconvergeds.hco.kubevirt.io",
×
1065
                                                Version:     util.CurrentAPIVersion,
×
1066
                                                Kind:        util.HyperConvergedKind,
×
1067
                                                DisplayName: params.CrdDisplay + " Deployment",
×
1068
                                                Description: "Represents the deployment of " + params.CrdDisplay,
×
1069
                                                // TODO: move this to annotations on hyperconverged_types.go once kubebuilder
×
1070
                                                // properly supports SpecDescriptors as the operator-sdk already does
×
1071
                                                SpecDescriptors: []csvv1alpha1.SpecDescriptor{
×
1072
                                                        {
×
1073
                                                                DisplayName: "Infra components node affinity",
×
1074
                                                                Description: "nodeAffinity describes node affinity scheduling rules for the infra pods.",
×
1075
                                                                Path:        "infra.nodePlacement.affinity.nodeAffinity",
×
1076
                                                                XDescriptors: stringListToSlice(
×
1077
                                                                        "urn:alm:descriptor:com.tectonic.ui:nodeAffinity",
×
1078
                                                                ),
×
1079
                                                        },
×
1080
                                                        {
×
1081
                                                                DisplayName: "Infra components pod affinity",
×
1082
                                                                Description: "podAffinity describes pod affinity scheduling rules for the infra pods.",
×
1083
                                                                Path:        "infra.nodePlacement.affinity.podAffinity",
×
1084
                                                                XDescriptors: stringListToSlice(
×
1085
                                                                        "urn:alm:descriptor:com.tectonic.ui:podAffinity",
×
1086
                                                                ),
×
1087
                                                        },
×
1088
                                                        {
×
1089
                                                                DisplayName: "Infra components pod anti-affinity",
×
1090
                                                                Description: "podAntiAffinity describes pod anti affinity scheduling rules for the infra pods.",
×
1091
                                                                Path:        "infra.nodePlacement.affinity.podAntiAffinity",
×
1092
                                                                XDescriptors: stringListToSlice(
×
1093
                                                                        "urn:alm:descriptor:com.tectonic.ui:podAntiAffinity",
×
1094
                                                                ),
×
1095
                                                        },
×
1096
                                                        {
×
1097
                                                                DisplayName: "Workloads components node affinity",
×
1098
                                                                Description: "nodeAffinity describes node affinity scheduling rules for the workloads pods.",
×
1099
                                                                Path:        "workloads.nodePlacement.affinity.nodeAffinity",
×
1100
                                                                XDescriptors: stringListToSlice(
×
1101
                                                                        "urn:alm:descriptor:com.tectonic.ui:nodeAffinity",
×
1102
                                                                ),
×
1103
                                                        },
×
1104
                                                        {
×
1105
                                                                DisplayName: "Workloads components pod affinity",
×
1106
                                                                Description: "podAffinity describes pod affinity scheduling rules for the workloads pods.",
×
1107
                                                                Path:        "workloads.nodePlacement.affinity.podAffinity",
×
1108
                                                                XDescriptors: stringListToSlice(
×
1109
                                                                        "urn:alm:descriptor:com.tectonic.ui:podAffinity",
×
1110
                                                                ),
×
1111
                                                        },
×
1112
                                                        {
×
1113
                                                                DisplayName: "Workloads components pod anti-affinity",
×
1114
                                                                Description: "podAntiAffinity describes pod anti affinity scheduling rules for the workloads pods.",
×
1115
                                                                Path:        "workloads.nodePlacement.affinity.podAntiAffinity",
×
1116
                                                                XDescriptors: stringListToSlice(
×
1117
                                                                        "urn:alm:descriptor:com.tectonic.ui:podAntiAffinity",
×
1118
                                                                ),
×
1119
                                                        },
×
1120
                                                        {
×
1121
                                                                DisplayName: "HIDDEN FIELDS - operator version",
×
1122
                                                                Description: "HIDDEN FIELDS - operator version.",
×
1123
                                                                Path:        "version",
×
1124
                                                                XDescriptors: stringListToSlice(
×
1125
                                                                        "urn:alm:descriptor:com.tectonic.ui:hidden",
×
1126
                                                                ),
×
1127
                                                        },
×
1128
                                                },
×
1129
                                                StatusDescriptors: []csvv1alpha1.StatusDescriptor{},
×
1130
                                        },
×
1131
                                },
×
1132
                                Required: []csvv1alpha1.CRDDescription{},
×
1133
                        },
×
1134
                },
×
1135
        }
×
1136
}
×
1137

1138
func InjectVolumesForWebHookCerts(deploy *appsv1.Deployment) {
×
1139
        // check if there is already a volume for api certificates
×
1140
        for _, vol := range deploy.Spec.Template.Spec.Volumes {
×
1141
                if vol.Name == certVolume {
×
1142
                        return
×
1143
                }
×
1144
        }
1145

1146
        volume := corev1.Volume{
×
1147
                Name: certVolume,
×
1148
                VolumeSource: corev1.VolumeSource{
×
1149
                        Secret: &corev1.SecretVolumeSource{
×
1150
                                SecretName:  deploy.Name + "-service-cert",
×
1151
                                DefaultMode: ptr.To[int32](420),
×
1152
                                Items: []corev1.KeyToPath{
×
1153
                                        {
×
1154
                                                Key:  "tls.crt",
×
1155
                                                Path: util.WebhookCertName,
×
1156
                                        },
×
1157
                                        {
×
1158
                                                Key:  "tls.key",
×
1159
                                                Path: util.WebhookKeyName,
×
1160
                                        },
×
1161
                                },
×
1162
                        },
×
1163
                },
×
1164
        }
×
1165
        deploy.Spec.Template.Spec.Volumes = append(deploy.Spec.Template.Spec.Volumes, volume)
×
1166

×
1167
        for index, container := range deploy.Spec.Template.Spec.Containers {
×
1168
                deploy.Spec.Template.Spec.Containers[index].VolumeMounts = append(container.VolumeMounts,
×
1169
                        corev1.VolumeMount{
×
1170
                                Name:      certVolume,
×
1171
                                MountPath: util.DefaultWebhookCertDir,
×
1172
                        })
×
1173
        }
×
1174
}
1175

1176
func getReadinessProbe(endpoint string, port int32) *corev1.Probe {
×
1177
        return &corev1.Probe{
×
1178
                ProbeHandler: corev1.ProbeHandler{
×
1179
                        HTTPGet: &corev1.HTTPGetAction{
×
1180
                                Path: endpoint,
×
1181
                                Port: intstr.IntOrString{
×
1182
                                        Type:   intstr.Int,
×
1183
                                        IntVal: port,
×
1184
                                },
×
1185
                                Scheme: corev1.URISchemeHTTP,
×
1186
                        },
×
1187
                },
×
1188
                InitialDelaySeconds: 5,
×
1189
                PeriodSeconds:       5,
×
1190
                FailureThreshold:    1,
×
1191
        }
×
1192
}
×
1193

1194
func getLivenessProbe(endpoint string, port int32) *corev1.Probe {
×
1195
        return &corev1.Probe{
×
1196
                ProbeHandler: corev1.ProbeHandler{
×
1197
                        HTTPGet: &corev1.HTTPGetAction{
×
1198
                                Path: endpoint,
×
1199
                                Port: intstr.IntOrString{
×
1200
                                        Type:   intstr.Int,
×
1201
                                        IntVal: port,
×
1202
                                },
×
1203
                                Scheme: corev1.URISchemeHTTP,
×
1204
                        },
×
1205
                },
×
1206
                InitialDelaySeconds: 30,
×
1207
                PeriodSeconds:       5,
×
1208
                FailureThreshold:    1,
×
1209
        }
×
1210
}
×
1211

1212
func getMetricsPort() corev1.ContainerPort {
×
1213
        return corev1.ContainerPort{
×
1214
                Name:          util.MetricsPortName,
×
1215
                ContainerPort: util.MetricsPort,
×
1216
                Protocol:      corev1.ProtocolTCP,
×
1217
        }
×
1218
}
×
1219

1220
func getWebhookPort() corev1.ContainerPort {
×
1221
        return corev1.ContainerPort{
×
1222
                Name:          util.WebhookPortName,
×
1223
                ContainerPort: util.WebhookPort,
×
1224
                Protocol:      corev1.ProtocolTCP,
×
1225
        }
×
1226
}
×
1227

1228
func stringListToSlice(words ...string) []string {
×
1229
        return words
×
1230
}
×
1231

1232
func panicOnError(err error) {
×
1233
        if err != nil {
×
1234
                panic(err)
×
1235
        }
1236
}
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