diff --git a/Makefile b/Makefile index 218eb194de..a497c02829 100644 --- a/Makefile +++ b/Makefile @@ -244,7 +244,10 @@ gogenerate-crd-creator: generate go generate ./tools/csv-merger go generate ./tools/manifest-templator -generate: +generate-featuregate-comment: + go run ./tools/feature-gate-doc/ + +generate: generate-featuregate-comment ./hack/generate.sh generate-doc: build-docgen @@ -367,6 +370,7 @@ push-builder-image: retag-builder-image deploy_fake_kubedescheduler \ build-docgen \ gogenerate \ + generate-featuregate-comment \ generate \ generate-doc \ validate-no-offensive-lang \ diff --git a/api/addtoscheme_hco_v1beta1.go b/api/addtoscheme_hco.go similarity index 60% rename from api/addtoscheme_hco_v1beta1.go rename to api/addtoscheme_hco.go index b3cbf99cff..88529fa5a0 100644 --- a/api/addtoscheme_hco_v1beta1.go +++ b/api/addtoscheme_hco.go @@ -1,10 +1,11 @@ package api import ( + hcov1 "github.com/kubevirt/hyperconverged-cluster-operator/api/v1" hcov1beta1 "github.com/kubevirt/hyperconverged-cluster-operator/api/v1beta1" ) func init() { // Register the types with the Scheme so the components can map objects to GroupVersionKinds and back - AddToSchemes = append(AddToSchemes, hcov1beta1.SchemeBuilder.AddToScheme) + AddToSchemes = append(AddToSchemes, hcov1.AddToScheme, hcov1beta1.AddToScheme) } diff --git a/api/v1/conversion.go b/api/v1/conversion.go new file mode 100644 index 0000000000..0735480e52 --- /dev/null +++ b/api/v1/conversion.go @@ -0,0 +1,7 @@ +package v1 + +import "sigs.k8s.io/controller-runtime/pkg/conversion" + +var _ conversion.Hub = &HyperConverged{} + +func (*HyperConverged) Hub() { /* no implementation. Just to satisfy the Hub interface */ } diff --git a/api/v1/doc.go b/api/v1/doc.go new file mode 100644 index 0000000000..f4e1650843 --- /dev/null +++ b/api/v1/doc.go @@ -0,0 +1,5 @@ +// Package v1 contains API Schema definitions for the hco v1 API group +// +k8s:deepcopy-gen=package,register +// +k8s:defaulter-gen=TypeMeta +// +groupName=hco.kubevirt.io +package v1 diff --git a/api/v1/featuregates/doc.go b/api/v1/featuregates/doc.go new file mode 100644 index 0000000000..9c0501adb1 --- /dev/null +++ b/api/v1/featuregates/doc.go @@ -0,0 +1,4 @@ +// Package featuregates contains API Schema definitions for the feature gates in the hco v1 API group +// +k8s:deepcopy-gen=package,register +// + group Name=hco.kubevirt.io +package featuregates diff --git a/api/v1/featuregates/feature_gates.go b/api/v1/featuregates/feature_gates.go new file mode 100644 index 0000000000..b192757dbd --- /dev/null +++ b/api/v1/featuregates/feature_gates.go @@ -0,0 +1,125 @@ +package featuregates + +import ( + "encoding/json" + "slices" + "strings" + + "k8s.io/utils/ptr" +) + +type FeatureGateState string + +const ( + Enabled FeatureGateState = "Enabled" + Disabled FeatureGateState = "Disabled" +) + +// FeatureGate is an optional feature gate to enable or disable a new feature that is not generally available yet. +// +k8s:conversion-gen=false +// +k8s:openapi-gen=true +type FeatureGate struct { + // Name is the feature gate name + Name string `json:"name"` + + // State determines if the feature gate is enabled ("Enabled"), or disabled ("False"). The default value is "Disabled". + // +kubebuilder:validation:Enum="Enabled";"Disabled" + State *FeatureGateState `json:"state,omitempty"` +} + +func (fg FeatureGate) MarshalJSON() ([]byte, error) { + builder := &strings.Builder{} + builder.WriteString(`{"name":"`) + builder.WriteString(fg.Name) + builder.WriteByte('"') + + if fg.State != nil && *fg.State == Disabled { + builder.WriteString(`,"state":"`) + builder.WriteString(string(Disabled)) + builder.WriteByte('"') + } + builder.WriteByte('}') + + return []byte(builder.String()), nil +} + +func (fg *FeatureGate) UnmarshalJSON(bytes []byte) error { + type plain FeatureGate + err := json.Unmarshal(bytes, (*plain)(fg)) + if err != nil { + return err + } + + if fg.State == nil { + fg.State = ptr.To(Enabled) + } + + return nil +} + +// HyperConvergedFeatureGates is a set of optional feature gates to enable or disable new features that are not +// generally available yet. +// Add a new FeatureGate Object to this set, to enable a feature that is disabled by default, or to disable a feature +// that is enabled by default. +// +// +k8s:openapi-gen=true +// +k8s:conversion-gen=false +// +k8s:deepcopy-gen=false +type HyperConvergedFeatureGates []FeatureGate + +func (fgs *HyperConvergedFeatureGates) Add(fg FeatureGate) { + idx := slices.IndexFunc(*fgs, func(item FeatureGate) bool { + return item.Name == fg.Name + }) + + if idx == -1 { + *fgs = append(*fgs, fg) + return + } + + (*fgs)[idx].State = fg.State +} + +func (fgs *HyperConvergedFeatureGates) Enable(name string) { + fgs.set(name, Enabled) +} + +func (fgs *HyperConvergedFeatureGates) Disable(name string) { + fgs.set(name, Disabled) +} + +func (fgs *HyperConvergedFeatureGates) set(name string, enabled FeatureGateState) { + idx := slices.IndexFunc(*fgs, func(item FeatureGate) bool { + return item.Name == name + }) + + if idx == -1 { + *fgs = append(*fgs, FeatureGate{Name: name, State: &enabled}) + return + } + + (*fgs)[idx].State = &enabled +} + +func (fgs *HyperConvergedFeatureGates) IsEnabled(name string) bool { + isEnabled, isFinal := featureGatesDetails.isEnabled(name) + + if isFinal { + return isEnabled + } + + enabled := Disabled + if isEnabled { + enabled = Enabled + } + + idx := slices.IndexFunc(*fgs, func(fg FeatureGate) bool { + return fg.Name == name + }) + + if idx > -1 { + enabled = ptr.Deref((*fgs)[idx].State, Enabled) + } + + return enabled == Enabled +} diff --git a/api/v1/featuregates/feature_gates_details.go b/api/v1/featuregates/feature_gates_details.go new file mode 100644 index 0000000000..43ed9b7a80 --- /dev/null +++ b/api/v1/featuregates/feature_gates_details.go @@ -0,0 +1,131 @@ +package featuregates + +type Phase int + +const ( + UnknownFeatureGate Phase = iota + PhaseAlpha + PhaseBeta + PhaseGA + PhaseDeprecated +) + +type featureGateDetails struct { + phase Phase + description string +} + +type featureGatesDetailsType map[string]featureGateDetails + +var featureGatesDetails = featureGatesDetailsType{ + "downwardMetrics": { + phase: PhaseAlpha, + description: "Allow to expose a limited set of host metrics to guests.", + }, + "withHostPassthroughCPU": { + phase: PhaseDeprecated, + }, + "enableCommonBootImageImport": { + phase: PhaseDeprecated, + description: "This feature gate is ignored. Use spec.enableCommonBootImageImport field instead", + }, + "deployTektonTaskResources": { + phase: PhaseDeprecated, + }, + "deployVmConsoleProxy": { + phase: PhaseDeprecated, + }, + "deployKubeSecondaryDNS": { + phase: PhaseAlpha, + description: "Deploy KubeSecondaryDNS by CNAO", + }, + "deployKubevirtIpamController": { + phase: PhaseDeprecated, + }, + "nonRoot": { + phase: PhaseDeprecated, + }, + "disableMDevConfiguration": { + phase: PhaseAlpha, + description: "Disable mediated devices handling on KubeVirt", + }, + "persistentReservation": { + phase: PhaseAlpha, + description: "Enable persistent reservation of a LUN through the SCSI Persistent Reserve commands on Kubevirt." + + "In order to issue privileged SCSI ioctls, the VM requires activation of the persistent reservation flag. " + + "Once this feature gate is enabled, then the additional container with the qemu-pr-helper is deployed inside the virt-handler pod. " + + "Enabling (or removing) the feature gate causes the redeployment of the virt-handler pod.", + }, + "enableManagedTenantQuota": { + phase: PhaseDeprecated, + }, + "autoResourceLimits": { + phase: PhaseDeprecated, + }, + "alignCPUs": { + phase: PhaseAlpha, + description: "Enable KubeVirt to request up to two additional dedicated CPUs in order to complete the total CPU count to an even parity when using emulator thread isolation. " + + "Note: this feature is in Developer Preview.", + }, + "enableApplicationAwareQuota": { + phase: PhaseDeprecated, + description: "This feature gate is ignored. Use spec.enableApplicationAwareQuota field instead", + }, + "primaryUserDefinedNetworkBinding": { + phase: PhaseDeprecated, + }, + "enableMultiArchBootImageImport": { + phase: PhaseAlpha, + description: "allows the HCO to run on heterogeneous clusters with different CPU architectures. " + + "Enabling this feature gate will allow the HCO to create Golden Images for different CPU architectures.", + }, + "decentralizedLiveMigration": { + phase: PhaseAlpha, + description: "enables the decentralized live migration (cross-cluster migration) feature." + + "This feature allows live migration of VirtualMachineInstances between different clusters. " + + "Note: This feature is in Developer Preview.", + }, + "declarativeHotplugVolumes": { + phase: PhaseAlpha, + description: "enables the use of the declarative volume hotplug feature in KubeVirt. " + + `When enabled, the "DeclarativeHotplugVolumes" feature gate is enabled in the KubeVirt CR, instead of the "HotplugVolumes" feature gate. ` + + `When disabled, the "HotplugVolumes" feature gate is enabled (default behavior).`, + }, + "videoConfig": { + phase: PhaseBeta, + description: "allows users to configure video device types for their virtual machines. " + + "This can be useful for workloads that require specific video capabilities or architectures.", + }, + "objectGraph": { + phase: PhaseAlpha, + description: "enables the ObjectGraph VM and VMI subresource in KubeVirt. " + + "This subresource returns a structured list of k8s objects that are related to the specified VM or VMI, enabling better dependency tracking.", + }, +} + +func (fgs featureGatesDetailsType) isEnabled(name string) (isEnabled bool, isFinal bool) { + details, ok := fgs[name] + if !ok { // unsupported feature gate, even if it is in the featureGate list + return false, true + } + + switch details.phase { + case PhaseGA: + isFinal = true + isEnabled = true + case PhaseDeprecated: + isFinal = true + isEnabled = false + case PhaseAlpha: + isFinal = false + isEnabled = false + case PhaseBeta: + isFinal = false + isEnabled = true + default: + isFinal = true + isEnabled = false + } + + return isEnabled, isFinal +} \ No newline at end of file diff --git a/api/v1/featuregates/feature_gates_test.go b/api/v1/featuregates/feature_gates_test.go new file mode 100644 index 0000000000..7453b7fe7d --- /dev/null +++ b/api/v1/featuregates/feature_gates_test.go @@ -0,0 +1,403 @@ +package featuregates_test + +import ( + "encoding/json" + "testing" + + . "github.com/onsi/ginkgo/v2" + . "github.com/onsi/gomega" + gtypes "github.com/onsi/gomega/types" + "k8s.io/utils/ptr" + "sigs.k8s.io/yaml" + + "github.com/kubevirt/hyperconverged-cluster-operator/api/v1/featuregates" +) + +func TestFeatureGatesSuite(t *testing.T) { + RegisterFailHandler(Fail) + RunSpecs(t, "FeatureGates Suite") +} + +var _ = Describe("FeatureGate", func() { + Context("Marshal", func() { + It("should marshal an enabled feature gate", func() { + fg := featuregates.FeatureGate{ + Name: "fgName", + State: ptr.To(featuregates.Enabled), + } + + jsonBytes, err := json.Marshal(fg) + Expect(err).ToNot(HaveOccurred()) + Expect(jsonBytes).To(MatchJSON(`{"name":"fgName"}`)) + }) + + It("should marshal a disabled feature gate", func() { + fg := featuregates.FeatureGate{ + Name: "fgName", + State: ptr.To(featuregates.Disabled), + } + + jsonBytes, err := json.Marshal(fg) + Expect(err).ToNot(HaveOccurred()) + Expect(jsonBytes).To(MatchJSON(`{"name":"fgName","state":"Disabled"}`)) + }) + + It("should marshal an enabled feature gate pointer", func() { + fg := &featuregates.FeatureGate{ + Name: "fgName", + State: ptr.To(featuregates.Enabled), + } + + jsonBytes, err := json.Marshal(fg) + Expect(err).ToNot(HaveOccurred()) + Expect(jsonBytes).To(MatchJSON(`{"name":"fgName"}`)) + }) + + It("should marshal a disabled feature gate pointer", func() { + fg := &featuregates.FeatureGate{ + Name: "fgName", + State: ptr.To(featuregates.Disabled), + } + + jsonBytes, err := json.Marshal(fg) + Expect(err).ToNot(HaveOccurred()) + Expect(jsonBytes).To(MatchJSON(`{"name":"fgName","state":"Disabled"}`)) + }) + + It("should marshal a feature gate without enabled field, as enabled", func() { + fg := featuregates.FeatureGate{ + Name: "fgName", + } + + jsonBytes, err := json.Marshal(fg) + Expect(err).ToNot(HaveOccurred()) + Expect(jsonBytes).To(MatchJSON(`{"name":"fgName"}`)) + }) + + It("should marshal a FG array", func() { + fgs := featuregates.HyperConvergedFeatureGates{ + { + Name: "noEnabledField", + }, + { + Name: "enabledFG", + State: ptr.To(featuregates.Enabled), + }, + { + Name: "disabledFG", + State: ptr.To(featuregates.Disabled), + }, + } + + jsonBytes, err := json.Marshal(fgs) + Expect(err).ToNot(HaveOccurred()) + Expect(jsonBytes).To(MatchJSON(`[{"name":"noEnabledField"}, {"name": "enabledFG"}, {"name": "disabledFG", "state": "Disabled"}]`)) + }) + + It("should yaml marshal a FG array", func() { + fgs := featuregates.HyperConvergedFeatureGates{ + { + Name: "noEnabledField", + }, + { + Name: "enabledFG", + State: ptr.To(featuregates.Enabled), + }, + { + Name: "disabledFG", + State: ptr.To(featuregates.Disabled), + }, + } + + yamlBytes, err := yaml.Marshal(fgs) + Expect(err).ToNot(HaveOccurred()) + Expect(yamlBytes).To(MatchYAML(`- name: noEnabledField +- name: enabledFG +- name: disabledFG + state: "Disabled"`, + )) + }) + }) + + Context("Unmarshal", func() { + It("should unmarshal an enabled feature gate", func() { + fgBytes := []byte(`{"name":"fgName", "state":"Enabled"}`) + fg := featuregates.FeatureGate{} + Expect(json.Unmarshal(fgBytes, &fg)).To(Succeed()) + Expect(fg.Name).To(Equal("fgName")) + Expect(fg.State).To(HaveValue(Equal(featuregates.Enabled))) + }) + + It("should unmarshal a disabled feature gate", func() { + fgBytes := []byte(`{"name":"fgName", "state":"Disabled"}`) + fg := featuregates.FeatureGate{} + Expect(json.Unmarshal(fgBytes, &fg)).To(Succeed()) + Expect(fg.Name).To(Equal("fgName")) + Expect(fg.State).To(HaveValue(Equal(featuregates.Disabled))) + }) + + It("should unmarshal a feature gate w/o enabled field, as enabled FG", func() { + fgBytes := []byte(`{"name":"fgName"}`) + fg := featuregates.FeatureGate{} + Expect(json.Unmarshal(fgBytes, &fg)).To(Succeed()) + Expect(fg.Name).To(Equal("fgName")) + Expect(fg.State).To(HaveValue(Equal(featuregates.Enabled))) + }) + + It("should unmarshal an array of FGs", func() { + fgBytes := []byte(`[{"name":"noEnabledField"}, {"name": "enabledFG", "state": "Enabled"}, {"name": "disabledFG", "state": "Disabled"}]`) + fgs := featuregates.HyperConvergedFeatureGates{} + + Expect(json.Unmarshal(fgBytes, &fgs)).To(Succeed()) + Expect(fgs).To(HaveLen(3)) + Expect(fgs).To(ContainElements( + featuregates.FeatureGate{Name: "noEnabledField", State: ptr.To(featuregates.Enabled)}, + featuregates.FeatureGate{Name: "enabledFG", State: ptr.To(featuregates.Enabled)}, + featuregates.FeatureGate{Name: "disabledFG", State: ptr.To(featuregates.Disabled)}, + )) + }) + + It("should unmarshal a yaml array of FGs", func() { + fgBytes := []byte(`- name: noEnabledField +- name: enabledFG + enabled: "Enabled" +- name: disabledFG + state: "Disabled"`, + ) + fgs := featuregates.HyperConvergedFeatureGates{} + + Expect(yaml.Unmarshal(fgBytes, &fgs)).To(Succeed()) + Expect(fgs).To(HaveLen(3)) + Expect(fgs).To(ContainElements( + featuregates.FeatureGate{Name: "noEnabledField", State: ptr.To(featuregates.Enabled)}, + featuregates.FeatureGate{Name: "enabledFG", State: ptr.To(featuregates.Enabled)}, + featuregates.FeatureGate{Name: "disabledFG", State: ptr.To(featuregates.Disabled)}, + )) + }) + }) +}) + +var _ = Describe("Feature Gates", func() { + DescribeTable("check IsEnabled", func(fgs featuregates.HyperConvergedFeatureGates, fgName string, expected gtypes.GomegaMatcher) { + Expect(fgs.IsEnabled(fgName)).To(expected) + }, + Entry("unknown FG; in list", featuregates.HyperConvergedFeatureGates{{Name: "unknown", State: ptr.To(featuregates.Enabled)}}, "unknown", BeFalse()), + Entry("unknown FG; not in list", featuregates.HyperConvergedFeatureGates{{Name: "deployKubeSecondaryDNS", State: ptr.To(featuregates.Enabled)}}, "unknown", BeFalse()), + + Entry("known alpha FG; in list; enabled", featuregates.HyperConvergedFeatureGates{{Name: "downwardMetrics", State: ptr.To(featuregates.Enabled)}}, "downwardMetrics", BeTrue()), + Entry("known alpha FG; in list; disabled", featuregates.HyperConvergedFeatureGates{{Name: "downwardMetrics", State: ptr.To(featuregates.Disabled)}}, "downwardMetrics", BeFalse()), + Entry("known alpha FG; not in list; disabled", featuregates.HyperConvergedFeatureGates{{Name: "deployKubeSecondaryDNS", State: ptr.To(featuregates.Enabled)}}, "downwardMetrics", BeFalse()), + + Entry("known beta FG; in list; enabled", featuregates.HyperConvergedFeatureGates{{Name: "videoConfig", State: ptr.To(featuregates.Enabled)}}, "videoConfig", BeTrue()), + Entry("known beta FG; in list; disabled", featuregates.HyperConvergedFeatureGates{{Name: "videoConfig", State: ptr.To(featuregates.Disabled)}}, "videoConfig", BeFalse()), + Entry("known beta FG; not in list; disabled", featuregates.HyperConvergedFeatureGates{{Name: "deployKubeSecondaryDNS", State: ptr.To(featuregates.Enabled)}}, "videoConfig", BeTrue()), + + Entry("known deprecated FG; in list; enabled", featuregates.HyperConvergedFeatureGates{{Name: "withHostPassthroughCPU", State: ptr.To(featuregates.Enabled)}}, "withHostPassthroughCPU", BeFalse()), + Entry("known deprecated FG; in list; disabled", featuregates.HyperConvergedFeatureGates{{Name: "withHostPassthroughCPU", State: ptr.To(featuregates.Disabled)}}, "withHostPassthroughCPU", BeFalse()), + Entry("known deprecated FG; not in list; disabled", featuregates.HyperConvergedFeatureGates{{Name: "deployKubeSecondaryDNS", State: ptr.To(featuregates.Enabled)}}, "withHostPassthroughCPU", BeFalse()), + ) + + Context("check Add", func() { + It("should add to nil", func() { + var fgs featuregates.HyperConvergedFeatureGates + + fgs.Add(featuregates.FeatureGate{Name: "aaa", State: ptr.To(featuregates.Enabled)}) + + Expect(fgs).To(HaveLen(1)) + Expect(fgs).To(ContainElement(Equal(featuregates.FeatureGate{Name: "aaa", State: ptr.To(featuregates.Enabled)}))) + }) + + It("should add to non-empty", func() { + fgs := featuregates.HyperConvergedFeatureGates{ + {Name: "aaa", State: ptr.To(featuregates.Enabled)}, + } + + fgs.Add(featuregates.FeatureGate{Name: "bbb", State: ptr.To(featuregates.Disabled)}) + + Expect(fgs).To(HaveLen(2)) + Expect(fgs).To(ContainElement(Equal(featuregates.FeatureGate{Name: "aaa", State: ptr.To(featuregates.Enabled)}))) + Expect(fgs).To(ContainElement(Equal(featuregates.FeatureGate{Name: "bbb", State: ptr.To(featuregates.Disabled)}))) + }) + + It("should update if already exist - first item", func() { + fgs := featuregates.HyperConvergedFeatureGates{ + {Name: "aaa", State: ptr.To(featuregates.Enabled)}, + {Name: "bbb", State: ptr.To(featuregates.Enabled)}, + {Name: "ccc", State: ptr.To(featuregates.Enabled)}, + } + + fgs.Add(featuregates.FeatureGate{Name: "aaa", State: ptr.To(featuregates.Disabled)}) + + Expect(fgs).To(HaveLen(3)) + Expect(fgs).To(ContainElement(Equal(featuregates.FeatureGate{Name: "aaa", State: ptr.To(featuregates.Disabled)}))) + Expect(fgs).To(ContainElement(Equal(featuregates.FeatureGate{Name: "bbb", State: ptr.To(featuregates.Enabled)}))) + Expect(fgs).To(ContainElement(Equal(featuregates.FeatureGate{Name: "ccc", State: ptr.To(featuregates.Enabled)}))) + }) + + It("should update if already exist - middle item", func() { + fgs := featuregates.HyperConvergedFeatureGates{ + {Name: "aaa", State: ptr.To(featuregates.Enabled)}, + {Name: "bbb", State: ptr.To(featuregates.Enabled)}, + {Name: "ccc", State: ptr.To(featuregates.Enabled)}, + } + + fgs.Add(featuregates.FeatureGate{Name: "bbb", State: ptr.To(featuregates.Disabled)}) + + Expect(fgs).To(HaveLen(3)) + Expect(fgs).To(ContainElement(Equal(featuregates.FeatureGate{Name: "aaa", State: ptr.To(featuregates.Enabled)}))) + Expect(fgs).To(ContainElement(Equal(featuregates.FeatureGate{Name: "bbb", State: ptr.To(featuregates.Disabled)}))) + Expect(fgs).To(ContainElement(Equal(featuregates.FeatureGate{Name: "ccc", State: ptr.To(featuregates.Enabled)}))) + }) + + It("should update if already exist - last item", func() { + fgs := featuregates.HyperConvergedFeatureGates{ + {Name: "aaa", State: ptr.To(featuregates.Enabled)}, + {Name: "bbb", State: ptr.To(featuregates.Enabled)}, + {Name: "ccc", State: ptr.To(featuregates.Enabled)}, + } + + fgs.Add(featuregates.FeatureGate{Name: "ccc", State: ptr.To(featuregates.Disabled)}) + + Expect(fgs).To(HaveLen(3)) + Expect(fgs).To(ContainElement(Equal(featuregates.FeatureGate{Name: "aaa", State: ptr.To(featuregates.Enabled)}))) + Expect(fgs).To(ContainElement(Equal(featuregates.FeatureGate{Name: "bbb", State: ptr.To(featuregates.Enabled)}))) + Expect(fgs).To(ContainElement(Equal(featuregates.FeatureGate{Name: "ccc", State: ptr.To(featuregates.Disabled)}))) + }) + }) + + Context("check Enable", func() { + It("should add to nil", func() { + var fgs featuregates.HyperConvergedFeatureGates + + fgs.Enable("aaa") + + Expect(fgs).To(HaveLen(1)) + Expect(fgs).To(ContainElement(Equal(featuregates.FeatureGate{Name: "aaa", State: ptr.To(featuregates.Enabled)}))) + }) + + It("should add to non-empty", func() { + fgs := featuregates.HyperConvergedFeatureGates{ + {Name: "aaa", State: ptr.To(featuregates.Enabled)}, + } + + fgs.Enable("bbb") + + Expect(fgs).To(HaveLen(2)) + Expect(fgs).To(ContainElement(Equal(featuregates.FeatureGate{Name: "aaa", State: ptr.To(featuregates.Enabled)}))) + Expect(fgs).To(ContainElement(Equal(featuregates.FeatureGate{Name: "bbb", State: ptr.To(featuregates.Enabled)}))) + }) + + It("should update if already exist - first item", func() { + fgs := featuregates.HyperConvergedFeatureGates{ + {Name: "aaa", State: ptr.To(featuregates.Disabled)}, + {Name: "bbb", State: ptr.To(featuregates.Disabled)}, + {Name: "ccc", State: ptr.To(featuregates.Disabled)}, + } + + fgs.Enable("aaa") + + Expect(fgs).To(HaveLen(3)) + Expect(fgs).To(ContainElement(Equal(featuregates.FeatureGate{Name: "aaa", State: ptr.To(featuregates.Enabled)}))) + Expect(fgs).To(ContainElement(Equal(featuregates.FeatureGate{Name: "bbb", State: ptr.To(featuregates.Disabled)}))) + Expect(fgs).To(ContainElement(Equal(featuregates.FeatureGate{Name: "ccc", State: ptr.To(featuregates.Disabled)}))) + }) + + It("should update if already exist - middle item", func() { + fgs := featuregates.HyperConvergedFeatureGates{ + {Name: "aaa", State: ptr.To(featuregates.Disabled)}, + {Name: "bbb", State: ptr.To(featuregates.Disabled)}, + {Name: "ccc", State: ptr.To(featuregates.Disabled)}, + } + + fgs.Enable("bbb") + + Expect(fgs).To(HaveLen(3)) + Expect(fgs).To(ContainElement(Equal(featuregates.FeatureGate{Name: "aaa", State: ptr.To(featuregates.Disabled)}))) + Expect(fgs).To(ContainElement(Equal(featuregates.FeatureGate{Name: "bbb", State: ptr.To(featuregates.Enabled)}))) + Expect(fgs).To(ContainElement(Equal(featuregates.FeatureGate{Name: "ccc", State: ptr.To(featuregates.Disabled)}))) + }) + + It("should update if already exist - last item", func() { + fgs := featuregates.HyperConvergedFeatureGates{ + {Name: "aaa", State: ptr.To(featuregates.Disabled)}, + {Name: "bbb", State: ptr.To(featuregates.Disabled)}, + {Name: "ccc", State: ptr.To(featuregates.Disabled)}, + } + + fgs.Enable("ccc") + + Expect(fgs).To(HaveLen(3)) + Expect(fgs).To(ContainElement(Equal(featuregates.FeatureGate{Name: "aaa", State: ptr.To(featuregates.Disabled)}))) + Expect(fgs).To(ContainElement(Equal(featuregates.FeatureGate{Name: "bbb", State: ptr.To(featuregates.Disabled)}))) + Expect(fgs).To(ContainElement(Equal(featuregates.FeatureGate{Name: "ccc", State: ptr.To(featuregates.Enabled)}))) + }) + }) + + Context("check Disable", func() { + It("should add to nil", func() { + var fgs featuregates.HyperConvergedFeatureGates + + fgs.Disable("aaa") + + Expect(fgs).To(HaveLen(1)) + Expect(fgs).To(ContainElement(Equal(featuregates.FeatureGate{Name: "aaa", State: ptr.To(featuregates.Disabled)}))) + }) + + It("should add to non-empty", func() { + fgs := featuregates.HyperConvergedFeatureGates{ + {Name: "aaa", State: ptr.To(featuregates.Enabled)}, + } + + fgs.Disable("bbb") + + Expect(fgs).To(HaveLen(2)) + Expect(fgs).To(ContainElement(Equal(featuregates.FeatureGate{Name: "aaa", State: ptr.To(featuregates.Enabled)}))) + Expect(fgs).To(ContainElement(Equal(featuregates.FeatureGate{Name: "bbb", State: ptr.To(featuregates.Disabled)}))) + }) + + It("should update if already exist - first item", func() { + fgs := featuregates.HyperConvergedFeatureGates{ + {Name: "aaa", State: ptr.To(featuregates.Enabled)}, + {Name: "bbb", State: ptr.To(featuregates.Enabled)}, + {Name: "ccc", State: ptr.To(featuregates.Enabled)}, + } + + fgs.Disable("aaa") + + Expect(fgs).To(HaveLen(3)) + Expect(fgs).To(ContainElement(Equal(featuregates.FeatureGate{Name: "aaa", State: ptr.To(featuregates.Disabled)}))) + Expect(fgs).To(ContainElement(Equal(featuregates.FeatureGate{Name: "bbb", State: ptr.To(featuregates.Enabled)}))) + Expect(fgs).To(ContainElement(Equal(featuregates.FeatureGate{Name: "ccc", State: ptr.To(featuregates.Enabled)}))) + }) + + It("should update if already exist - middle item", func() { + fgs := featuregates.HyperConvergedFeatureGates{ + {Name: "aaa", State: ptr.To(featuregates.Enabled)}, + {Name: "bbb", State: ptr.To(featuregates.Enabled)}, + {Name: "ccc", State: ptr.To(featuregates.Enabled)}, + } + + fgs.Disable("bbb") + + Expect(fgs).To(HaveLen(3)) + Expect(fgs).To(ContainElement(Equal(featuregates.FeatureGate{Name: "aaa", State: ptr.To(featuregates.Enabled)}))) + Expect(fgs).To(ContainElement(Equal(featuregates.FeatureGate{Name: "bbb", State: ptr.To(featuregates.Disabled)}))) + Expect(fgs).To(ContainElement(Equal(featuregates.FeatureGate{Name: "ccc", State: ptr.To(featuregates.Enabled)}))) + }) + + It("should update if already exist - last item", func() { + fgs := featuregates.HyperConvergedFeatureGates{ + {Name: "aaa", State: ptr.To(featuregates.Enabled)}, + {Name: "bbb", State: ptr.To(featuregates.Enabled)}, + {Name: "ccc", State: ptr.To(featuregates.Enabled)}, + } + + fgs.Disable("ccc") + + Expect(fgs).To(HaveLen(3)) + Expect(fgs).To(ContainElement(Equal(featuregates.FeatureGate{Name: "aaa", State: ptr.To(featuregates.Enabled)}))) + Expect(fgs).To(ContainElement(Equal(featuregates.FeatureGate{Name: "bbb", State: ptr.To(featuregates.Enabled)}))) + Expect(fgs).To(ContainElement(Equal(featuregates.FeatureGate{Name: "ccc", State: ptr.To(featuregates.Disabled)}))) + }) + }) +}) diff --git a/api/v1/featuregates/zz_generated.deepcopy.go b/api/v1/featuregates/zz_generated.deepcopy.go new file mode 100644 index 0000000000..d86724d1c3 --- /dev/null +++ b/api/v1/featuregates/zz_generated.deepcopy.go @@ -0,0 +1,46 @@ +//go:build !ignore_autogenerated +// +build !ignore_autogenerated + +/* + * This file is part of the KubeVirt project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + * Copyright 2026 Red Hat, Inc. + * + */ + +// Code generated by deepcopy-gen. DO NOT EDIT. + +package featuregates + +// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. +func (in *FeatureGate) DeepCopyInto(out *FeatureGate) { + *out = *in + if in.State != nil { + in, out := &in.State, &out.State + *out = new(FeatureGateState) + **out = **in + } + return +} + +// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new FeatureGate. +func (in *FeatureGate) DeepCopy() *FeatureGate { + if in == nil { + return nil + } + out := new(FeatureGate) + in.DeepCopyInto(out) + return out +} diff --git a/api/v1/featuregates/zz_generated.openapi.go b/api/v1/featuregates/zz_generated.openapi.go new file mode 100644 index 0000000000..9935685815 --- /dev/null +++ b/api/v1/featuregates/zz_generated.openapi.go @@ -0,0 +1,65 @@ +//go:build !ignore_autogenerated +// +build !ignore_autogenerated + +/* + * This file is part of the KubeVirt project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + * Copyright 2026 Red Hat, Inc. + * + */ + +// Code generated by openapi-gen. DO NOT EDIT. + +package featuregates + +import ( + common "k8s.io/kube-openapi/pkg/common" + spec "k8s.io/kube-openapi/pkg/validation/spec" +) + +func GetOpenAPIDefinitions(ref common.ReferenceCallback) map[string]common.OpenAPIDefinition { + return map[string]common.OpenAPIDefinition{ + "github.com/kubevirt/hyperconverged-cluster-operator/api/v1/featuregates.FeatureGate": schema_hyperconverged_cluster_operator_api_v1_featuregates_FeatureGate(ref), + } +} + +func schema_hyperconverged_cluster_operator_api_v1_featuregates_FeatureGate(ref common.ReferenceCallback) common.OpenAPIDefinition { + return common.OpenAPIDefinition{ + Schema: spec.Schema{ + SchemaProps: spec.SchemaProps{ + Description: "FeatureGate is an optional feature gate to enable or disable a new feature that is not generally available yet.", + Type: []string{"object"}, + Properties: map[string]spec.Schema{ + "name": { + SchemaProps: spec.SchemaProps{ + Description: "Name is the feature gate name", + Default: "", + Type: []string{"string"}, + Format: "", + }, + }, + "state": { + SchemaProps: spec.SchemaProps{ + Description: "State determines if the feature gate is enabled (\"Enabled\"), or disabled (\"False\"). The default value is \"Disabled\".", + Type: []string{"string"}, + Format: "", + }, + }, + }, + Required: []string{"name"}, + }, + }, + } +} diff --git a/api/v1/hyperconverged_types.go b/api/v1/hyperconverged_types.go new file mode 100644 index 0000000000..283a0f4d58 --- /dev/null +++ b/api/v1/hyperconverged_types.go @@ -0,0 +1,924 @@ +package v1 + +import ( + openshiftconfigv1 "github.com/openshift/api/config/v1" + corev1 "k8s.io/api/core/v1" + metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" + + v1 "kubevirt.io/api/core/v1" + aaqv1alpha1 "kubevirt.io/application-aware-quota/staging/src/kubevirt.io/application-aware-quota-api/pkg/apis/core/v1alpha1" + cdiv1beta1 "kubevirt.io/containerized-data-importer-api/pkg/apis/core/v1beta1" + sdkapi "kubevirt.io/controller-lifecycle-operator-sdk/api" + + "github.com/kubevirt/hyperconverged-cluster-operator/api/v1/featuregates" +) + +// EDIT THIS FILE! THIS IS SCAFFOLDING FOR YOU TO OWN! +// NOTE: json tags are required. Any new fields you add must have json tags for the fields to be serialized. +// Important: Run "operator-sdk generate k8s" to regenerate code after modifying this file + +// HyperConvergedName is the name of the HyperConverged resource that will be reconciled +const HyperConvergedName = "kubevirt-hyperconverged" + +type HyperConvergedUninstallStrategy string + +const ( + HyperConvergedUninstallStrategyRemoveWorkloads HyperConvergedUninstallStrategy = "RemoveWorkloads" + HyperConvergedUninstallStrategyBlockUninstallIfWorkloadsExist HyperConvergedUninstallStrategy = "BlockUninstallIfWorkloadsExist" +) + +type HyperConvergedTuningPolicy string + +// HyperConvergedAnnotationTuningPolicy defines a static configuration of the kubevirt query per seconds (qps) and burst values +// through annotation values. +const ( + HyperConvergedAnnotationTuningPolicy HyperConvergedTuningPolicy = "annotation" + // Deprecated: The highBurst profile is deprecated as of v1.16.0 ahead of removal in a future release + HyperConvergedHighBurstProfile HyperConvergedTuningPolicy = "highBurst" +) + +// HyperConvergedSpec defines the desired state of HyperConverged +// +k8s:openapi-gen=true +type HyperConvergedSpec struct { + // INSERT ADDITIONAL SPEC FIELDS - desired state of cluster + // Important: Run "operator-sdk generate k8s" to regenerate code after modifying this file + // Add custom validation using kubebuilder tags: https://book.kubebuilder.io/beyond_basics/generating_crd.html + + // TuningPolicy allows to configure the mode in which the RateLimits of kubevirt are set. + // If TuningPolicy is not present the default kubevirt values are used. + // It can be set to `annotation` for fine-tuning the kubevirt queryPerSeconds (qps) and burst values. + // Qps and burst values are taken from the annotation hco.kubevirt.io/tuningPolicy + // +kubebuilder:validation:Enum=annotation;highBurst + // +optional + TuningPolicy HyperConvergedTuningPolicy `json:"tuningPolicy,omitempty"` + + // infra HyperConvergedConfig influences the pod configuration (currently only placement) + // for all the infra components needed on the virtualization enabled cluster + // but not necessarily directly on each node running VMs/VMIs. + // +optional + Infra HyperConvergedConfig `json:"infra,omitempty"` + + // workloads HyperConvergedConfig influences the pod configuration (currently only placement) of components + // which need to be running on a node where virtualization workloads should be able to run. + // Changes to Workloads HyperConvergedConfig can be applied only without existing workload. + // +optional + Workloads HyperConvergedConfig `json:"workloads,omitempty"` + + // The commet for the FeatureGates field below is auto generated by the + // tools/feature-gates-doc tool + // + // DO NOT EDIT THIS COMMENT! + // + // To edit the general text of the comment, edit the template in the + // tools/feature-gate-doc/featuregates_list.gotmplt file + // + // To edit a specific feature gate information, edit the feature gate in the + // featureGatesDetails map, in api/v1/featuregates/feature_gates_details.go + // + // Then, run "make generate" + + // FeatureGates is a set of optional feature gates to enable or disable new + // features that are not generally available yet. + // Add a new FeatureGate Object to this set, to enable a feature that is + // disabled by default, or to disable a feature that is enabled by default. + // + // A feature gate may be in the following phases: + // * Alpha: the feature is in dev-preview. It is disabled by default, but can + // be enabled. + // * Beta: the feature gate is in tech-preview. It is enabled by default, but + // can be disabled. + // * GA: the feature is graduated and is always enabled. There is no way to + // disable it. + // * Deprecated: the feature is no longer supported. There is no way to enable + // it + // + // Feature-Gate list: + // * alignCPUs: + // Enable KubeVirt to request up to two additional dedicated CPUs in order to + // complete the total CPU count to an even parity when using emulator thread + // isolation. + // Note: this feature is in Developer Preview. + // Phase: Alpha + // + // * decentralizedLiveMigration: + // enables the decentralized live migration (cross-cluster migration) feature. + // This feature allows live migration of VirtualMachineInstances between + // different clusters. + // Note: This feature is in Developer Preview. + // Phase: Alpha + // + // * declarativeHotplugVolumes: + // enables the use of the declarative volume hotplug feature in KubeVirt. + // When enabled, the "DeclarativeHotplugVolumes" feature gate is enabled in + // the KubeVirt CR, instead of the "HotplugVolumes" feature gate. + // When disabled, the "HotplugVolumes" feature gate is enabled (default + // behavior). + // Phase: Alpha + // + // * deployKubeSecondaryDNS: + // Deploy KubeSecondaryDNS by CNAO + // Phase: Alpha + // + // * disableMDevConfiguration: + // Disable mediated devices handling on KubeVirt + // Phase: Alpha + // + // * downwardMetrics: + // Allow to expose a limited set of host metrics to guests. + // Phase: Alpha + // + // * enableMultiArchBootImageImport: + // allows the HCO to run on heterogeneous clusters with different CPU + // architectures. + // Enabling this feature gate will allow the HCO to create Golden Images for + // different CPU architectures. + // Phase: Alpha + // + // * objectGraph: + // enables the ObjectGraph VM and VMI subresource in KubeVirt. + // This subresource returns a structured list of k8s objects that are related + // to the specified VM or VMI, enabling better dependency tracking. + // Phase: Alpha + // + // * persistentReservation: + // Enable persistent reservation of a LUN through the SCSI Persistent Reserve + // commands on Kubevirt. + // In order to issue privileged SCSI ioctls, the VM requires activation of the + // persistent reservation flag. + // Once this feature gate is enabled, then the additional container with the + // qemu-pr-helper is deployed inside the virt-handler pod. + // Enabling (or removing) the feature gate causes the redeployment of the + // virt-handler pod. + // Phase: Alpha + // + // * videoConfig: + // allows users to configure video device types for their virtual machines. + // This can be useful for workloads that require specific video capabilities + // or architectures. + // Phase: Beta + // + // * autoResourceLimits: + // Phase: Deprecated + // + // * deployKubevirtIpamController: + // Phase: Deprecated + // + // * deployTektonTaskResources: + // Phase: Deprecated + // + // * deployVmConsoleProxy: + // Phase: Deprecated + // + // * enableApplicationAwareQuota: + // This feature gate is ignored. Use spec.enableApplicationAwareQuota field instead + // Phase: Deprecated + // + // * enableCommonBootImageImport: + // This feature gate is ignored. Use spec.enableCommonBootImageImport field instead + // Phase: Deprecated + // + // * enableManagedTenantQuota: + // Phase: Deprecated + // + // * nonRoot: + // Phase: Deprecated + // + // * primaryUserDefinedNetworkBinding: + // Phase: Deprecated + // + // * withHostPassthroughCPU: + // Phase: Deprecated + // + // +optional + // +k8s:conversion-gen=false + FeatureGates featuregates.HyperConvergedFeatureGates `json:"featureGates,omitempty"` + + // Live migration limits and timeouts are applied so that migration processes do not + // overwhelm the cluster. + // +kubebuilder:default={"completionTimeoutPerGiB": 150, "parallelMigrationsPerCluster": 5, "parallelOutboundMigrationsPerNode": 2, "progressTimeout": 150, "allowAutoConverge": false, "allowPostCopy": false} + // +optional + LiveMigrationConfig LiveMigrationConfigurations `json:"liveMigrationConfig,omitempty"` + + // PermittedHostDevices holds information about devices allowed for passthrough + // +optional + PermittedHostDevices *PermittedHostDevices `json:"permittedHostDevices,omitempty"` + + // MediatedDevicesConfiguration holds information about MDEV types to be defined on nodes, if available + // +optional + MediatedDevicesConfiguration *MediatedDevicesConfiguration `json:"mediatedDevicesConfiguration,omitempty"` + + // certConfig holds the rotation policy for internal, self-signed certificates + // +kubebuilder:default={"ca": {"duration": "48h0m0s", "renewBefore": "24h0m0s"}, "server": {"duration": "24h0m0s", "renewBefore": "12h0m0s"}} + // +optional + CertConfig HyperConvergedCertConfig `json:"certConfig,omitempty"` + + // ResourceRequirements describes the resource requirements for the operand workloads. + // +kubebuilder:default={"vmiCPUAllocationRatio": 10} + // +kubebuilder:validation:XValidation:rule="!has(self.vmiCPUAllocationRatio) || self.vmiCPUAllocationRatio > 0",message="vmiCPUAllocationRatio must be greater than 0" + // +optional + ResourceRequirements *OperandResourceRequirements `json:"resourceRequirements,omitempty"` + + // Override the storage class used for scratch space during transfer operations. The scratch space storage class + // is determined in the following order: + // value of scratchSpaceStorageClass, if that doesn't exist, use the default storage class, if there is no default + // storage class, use the storage class of the DataVolume, if no storage class specified, use no storage class for + // scratch space + // +optional + ScratchSpaceStorageClass *string `json:"scratchSpaceStorageClass,omitempty"` + + // DefaultCPUModel defines a cluster default for CPU model: default CPU model is set when VMI doesn't have any CPU model. + // When VMI has CPU model set, then VMI's CPU model is preferred. + // When default CPU model is not set and VMI's CPU model is not set too, host-model will be set. + // Default CPU model can be changed when kubevirt is running. + // +optional + DefaultCPUModel *string `json:"defaultCPUModel,omitempty"` + + // DefaultRuntimeClass defines a cluster default for the RuntimeClass to be used for VMIs pods if not set there. + // Default RuntimeClass can be changed when kubevirt is running, existing VMIs are not impacted till + // the next restart/live-migration when they are eventually going to consume the new default RuntimeClass. + // +optional + DefaultRuntimeClass *string `json:"defaultRuntimeClass,omitempty"` + + // ObsoleteCPUs allows avoiding scheduling of VMs for obsolete CPU models + // +optional + ObsoleteCPUs *HyperConvergedObsoleteCPUs `json:"obsoleteCPUs,omitempty"` + + // CommonTemplatesNamespace defines namespace in which common templates will + // be deployed. It overrides the default openshift namespace. + // +optional + CommonTemplatesNamespace *string `json:"commonTemplatesNamespace,omitempty"` + + // StorageImport contains configuration for importing containerized data + // +optional + StorageImport *StorageImportConfig `json:"storageImport,omitempty"` + + // WorkloadUpdateStrategy defines at the cluster level how to handle automated workload updates + // +kubebuilder:default={"workloadUpdateMethods": {"LiveMigrate"}, "batchEvictionSize": 10, "batchEvictionInterval": "1m0s"} + WorkloadUpdateStrategy HyperConvergedWorkloadUpdateStrategy `json:"workloadUpdateStrategy,omitempty"` + + // DataImportCronTemplates holds list of data import cron templates (golden images) + // +optional + // +listType=atomic + DataImportCronTemplates []DataImportCronTemplate `json:"dataImportCronTemplates,omitempty"` + + // FilesystemOverhead describes the space reserved for overhead when using Filesystem volumes. + // A value is between 0 and 1, if not defined it is 0.055 (5.5 percent overhead) + // +optional + FilesystemOverhead *cdiv1beta1.FilesystemOverhead `json:"filesystemOverhead,omitempty"` + + // UninstallStrategy defines how to proceed on uninstall when workloads (VirtualMachines, DataVolumes) still exist. + // BlockUninstallIfWorkloadsExist will prevent the CR from being removed when workloads still exist. + // BlockUninstallIfWorkloadsExist is the safest choice to protect your workloads from accidental data loss, so it's strongly advised. + // RemoveWorkloads will cause all the workloads to be cascading deleted on uninstallation. + // WARNING: please notice that RemoveWorkloads will cause your workloads to be deleted as soon as this CR will be, even accidentally, deleted. + // Please correctly consider the implications of this option before setting it. + // BlockUninstallIfWorkloadsExist is the default behaviour. + // +kubebuilder:default=BlockUninstallIfWorkloadsExist + // +default="BlockUninstallIfWorkloadsExist" + // +kubebuilder:validation:Enum=RemoveWorkloads;BlockUninstallIfWorkloadsExist + // +optional + UninstallStrategy HyperConvergedUninstallStrategy `json:"uninstallStrategy,omitempty"` + + // LogVerbosityConfig configures the verbosity level of Kubevirt's different components. The higher + // the value - the higher the log verbosity. + // +optional + LogVerbosityConfig *LogVerbosityConfiguration `json:"logVerbosityConfig,omitempty"` + + // TLSSecurityProfile specifies the settings for TLS connections to be propagated to all kubevirt-hyperconverged components. + // If unset, the hyperconverged cluster operator will consume the value set on the APIServer CR on OCP/OKD or Intermediate if on vanilla k8s. + // Note that only Old, Intermediate and Custom profiles are currently supported, and the maximum available + // MinTLSVersions is VersionTLS12. + // +optional + TLSSecurityProfile *openshiftconfigv1.TLSSecurityProfile `json:"tlsSecurityProfile,omitempty"` + + // KubeSecondaryDNSNameServerIP defines name server IP used by KubeSecondaryDNS + // +optional + KubeSecondaryDNSNameServerIP *string `json:"kubeSecondaryDNSNameServerIP,omitempty"` + + // KubeMacPoolConfiguration holds kubemacpool MAC address range configuration. + // +optional + KubeMacPoolConfiguration *KubeMacPoolConfig `json:"kubeMacPoolConfiguration,omitempty"` + + // EvictionStrategy defines at the cluster level if the VirtualMachineInstance should be + // migrated instead of shut-off in case of a node drain. If the VirtualMachineInstance specific + // field is set it overrides the cluster level one. + // Allowed values: + // - `None` no eviction strategy at cluster level. + // - `LiveMigrate` migrate the VM on eviction; a not live migratable VM with no specific strategy will block the drain of the node util manually evicted. + // - `LiveMigrateIfPossible` migrate the VM on eviction if live migration is possible, otherwise directly evict. + // - `External` block the drain, track eviction and notify an external controller. + // Defaults to LiveMigrate with multiple worker nodes, None on single worker clusters. + // +kubebuilder:validation:Enum=None;LiveMigrate;LiveMigrateIfPossible;External + // +optional + EvictionStrategy *v1.EvictionStrategy `json:"evictionStrategy,omitempty"` + + // VMStateStorageClass is the name of the storage class to use for the PVCs created to preserve VM state, like TPM. + // +optional + VMStateStorageClass *string `json:"vmStateStorageClass,omitempty"` + + // VirtualMachineOptions holds the cluster level information regarding the virtual machine. + // +kubebuilder:default={"disableFreePageReporting": false, "disableSerialConsoleLog": false} + // +default={"disableFreePageReporting": false, "disableSerialConsoleLog": false} + // +optional + VirtualMachineOptions *VirtualMachineOptions `json:"virtualMachineOptions,omitempty"` + + // CommonBootImageNamespace override the default namespace of the common boot images, in order to hide them. + // + // If not set, HCO won't set any namespace, letting SSP to use the default. If set, use the namespace to create the + // DataImportCronTemplates and the common image streams, with this namespace. This field is not set by default. + // + // +optional + CommonBootImageNamespace *string `json:"commonBootImageNamespace,omitempty"` + + // KSMConfiguration holds the information regarding + // the enabling the KSM in the nodes (if available). + // +optional + KSMConfiguration *v1.KSMConfiguration `json:"ksmConfiguration,omitempty"` + + // NetworkBinding defines the network binding plugins. + // Those bindings can be used when defining virtual machine interfaces. + // +optional + NetworkBinding map[string]v1.InterfaceBindingPlugin `json:"networkBinding,omitempty"` + + // ApplicationAwareConfig set the AAQ configurations + // +optional + ApplicationAwareConfig *ApplicationAwareConfigurations `json:"applicationAwareConfig,omitempty"` + + // HigherWorkloadDensity holds configuration aimed to increase virtual machine density + // +kubebuilder:default={"memoryOvercommitPercentage": 100} + // +default={"memoryOvercommitPercentage": 100} + // +optional + HigherWorkloadDensity *HigherWorkloadDensityConfiguration `json:"higherWorkloadDensity,omitempty"` + + // Opt-in to automatic delivery/updates of the common data import cron templates. + // There are two sources for the data import cron templates: hard coded list of common templates, and custom (user + // defined) templates that can be added to the dataImportCronTemplates field. This field only controls the common + // templates. It is possible to use custom templates by adding them to the dataImportCronTemplates field. + // +optional + // +kubebuilder:default=true + // +default=true + EnableCommonBootImageImport *bool `json:"enableCommonBootImageImport,omitempty"` + + // InstancetypeConfig holds the configuration of instance type related functionality within KubeVirt. + // +optional + InstancetypeConfig *v1.InstancetypeConfiguration `json:"instancetypeConfig,omitempty"` + + // CommonInstancetypesDeployment holds the configuration of common-instancetypes deployment within KubeVirt. + // +optional + CommonInstancetypesDeployment *v1.CommonInstancetypesDeployment `json:"CommonInstancetypesDeployment,omitempty"` + + // deploy VM console proxy resources in SSP operator + // +optional + // +kubebuilder:default=false + // +default=false + DeployVMConsoleProxy *bool `json:"deployVmConsoleProxy,omitempty"` + + // EnableApplicationAwareQuota if true, enables the Application Aware Quota feature + // +optional + // +kubebuilder:default=false + // +default=false + EnableApplicationAwareQuota *bool `json:"enableApplicationAwareQuota,omitempty"` + + // LiveUpdateConfiguration holds the cluster configuration for live update of virtual machines - max cpu sockets, + // max guest memory and max hotplug ratio. This setting can affect VM CPU and memory settings. + // +optional + LiveUpdateConfiguration *v1.LiveUpdateConfiguration `json:"liveUpdateConfiguration,omitempty"` +} + +// CertRotateConfigCA contains the tunables for TLS certificates. +// +k8s:openapi-gen=true +type CertRotateConfigCA struct { + // The requested 'duration' (i.e. lifetime) of the Certificate. + // This should comply with golang's ParseDuration format (https://golang.org/pkg/time/#ParseDuration) + // +kubebuilder:default="48h0m0s" + // +default="48h0m0s" + // +optional + Duration *metav1.Duration `json:"duration,omitempty"` + + // The amount of time before the currently issued certificate's `notAfter` + // time that we will begin to attempt to renew the certificate. + // This should comply with golang's ParseDuration format (https://golang.org/pkg/time/#ParseDuration) + // +kubebuilder:default="24h0m0s" + // +default="24h0m0s" + // +optional + RenewBefore *metav1.Duration `json:"renewBefore,omitempty"` +} + +// CertRotateConfigServer contains the tunables for TLS certificates. +// +k8s:openapi-gen=true +type CertRotateConfigServer struct { + // The requested 'duration' (i.e. lifetime) of the Certificate. + // This should comply with golang's ParseDuration format (https://golang.org/pkg/time/#ParseDuration) + // +kubebuilder:default="24h0m0s" + // +default="24h0m0s" + // +optional + Duration *metav1.Duration `json:"duration,omitempty"` + + // The amount of time before the currently issued certificate's `notAfter` + // time that we will begin to attempt to renew the certificate. + // This should comply with golang's ParseDuration format (https://golang.org/pkg/time/#ParseDuration) + // +kubebuilder:default="12h0m0s" + // +default="12h0m0s" + // +optional + RenewBefore *metav1.Duration `json:"renewBefore,omitempty"` +} + +// HyperConvergedCertConfig holds the CertConfig entries for the HCO operands +// +k8s:openapi-gen=true +type HyperConvergedCertConfig struct { + // CA configuration - + // CA certs are kept in the CA bundle as long as they are valid + // +kubebuilder:default={"duration": "48h0m0s", "renewBefore": "24h0m0s"} + // +optional + CA CertRotateConfigCA `json:"ca,omitempty"` + + // Server configuration - + // Certs are rotated and discarded + // +kubebuilder:default={"duration": "24h0m0s", "renewBefore": "12h0m0s"} + // +optional + Server CertRotateConfigServer `json:"server,omitempty"` +} + +// HyperConvergedConfig defines a set of configurations to pass to components +type HyperConvergedConfig struct { + // NodePlacement describes node scheduling configuration. + // +optional + NodePlacement *sdkapi.NodePlacement `json:"nodePlacement,omitempty"` +} + +// LiveMigrationConfigurations - Live migration limits and timeouts are applied so that migration processes do not +// overwhelm the cluster. +// +k8s:openapi-gen=true +type LiveMigrationConfigurations struct { + // Number of migrations running in parallel in the cluster. + // +optional + // +kubebuilder:default=5 + // +default=5 + ParallelMigrationsPerCluster *uint32 `json:"parallelMigrationsPerCluster,omitempty"` + + // Maximum number of outbound migrations per node. + // +optional + // +kubebuilder:default=2 + // +default=2 + ParallelOutboundMigrationsPerNode *uint32 `json:"parallelOutboundMigrationsPerNode,omitempty"` + + // Bandwidth limit of each migration, the value is quantity of bytes per second (e.g. 2048Mi = 2048MiB/sec) + // +optional + // +kubebuilder:validation:Pattern=^(\+|-)?(([0-9]+(\.[0-9]*)?)|(\.[0-9]+))(([KMGTPE]i)|[numkMGTPE]|([eE](\+|-)?(([0-9]+(\.[0-9]*)?)|(\.[0-9]+))))?$ + BandwidthPerMigration *string `json:"bandwidthPerMigration,omitempty"` + + // If a migrating VM is big and busy, while the connection to the destination node + // is slow, migration may never converge. The completion timeout is calculated + // based on completionTimeoutPerGiB times the size of the guest (both RAM and + // migrated disks, if any). For example, with completionTimeoutPerGiB set to 800, + // a virtual machine instance with 6GiB memory will timeout if it has not + // completed migration in 1h20m. Use a lower completionTimeoutPerGiB to induce + // quicker failure, so that another destination or post-copy is attempted. Use a + // higher completionTimeoutPerGiB to let workload with spikes in its memory dirty + // rate to converge. + // The format is a number. + // +kubebuilder:default=150 + // +default=150 + // +optional + CompletionTimeoutPerGiB *int64 `json:"completionTimeoutPerGiB,omitempty"` + + // The migration will be canceled if memory copy fails to make progress in this time, in seconds. + // +kubebuilder:default=150 + // +default=150 + // +optional + ProgressTimeout *int64 `json:"progressTimeout,omitempty"` + + // The migrations will be performed over a dedicated multus network to minimize disruption to tenant workloads due to network saturation when VM live migrations are triggered. + // +optional + Network *string `json:"network,omitempty"` + + // AllowAutoConverge allows the platform to compromise performance/availability of VMIs to + // guarantee successful VMI live migrations. Defaults to false + // +optional + // +kubebuilder:default=false + // +default=false + AllowAutoConverge *bool `json:"allowAutoConverge,omitempty"` + + // When enabled, KubeVirt attempts to use post-copy live-migration in case it + // reaches its completion timeout while attempting pre-copy live-migration. + // Post-copy migrations allow even the busiest VMs to successfully live-migrate. + // However, events like a network failure or a failure in any of the source or + // destination nodes can cause the migrated VM to crash or reach inconsistency. + // Enable this option when evicting nodes is more important than keeping VMs + // alive. + // Defaults to false. + // +optional + // +kubebuilder:default=false + // +default=false + AllowPostCopy *bool `json:"allowPostCopy,omitempty"` +} + +// VirtualMachineOptions holds the cluster level information regarding the virtual machine. +type VirtualMachineOptions struct { + // DisableFreePageReporting disable the free page reporting of + // memory balloon device https://libvirt.org/formatdomain.html#memory-balloon-device. + // This will have effect only if AutoattachMemBalloon is not false and the vmi is not + // requesting any high performance feature (dedicatedCPU/realtime/hugePages), in which free page reporting is always disabled. + // +optional + // +kubebuilder:default=false + // +default=false + DisableFreePageReporting *bool `json:"disableFreePageReporting,omitempty"` + + // DisableSerialConsoleLog disables logging the auto-attached default serial console. + // If not set, serial console logs will be written to a file and then streamed from a container named `guest-console-log`. + // The value can be individually overridden for each VM, not relevant if AutoattachSerialConsole is disabled for the VM. + // +optional + // +kubebuilder:default=false + // +default=false + DisableSerialConsoleLog *bool `json:"disableSerialConsoleLog,omitempty"` +} + +// PermittedHostDevices holds information about devices allowed for passthrough +// +k8s:openapi-gen=true +type PermittedHostDevices struct { + // +listType=map + // +listMapKey=pciDeviceSelector + PciHostDevices []PciHostDevice `json:"pciHostDevices,omitempty"` + // +listType=map + // +listMapKey=resourceName + USBHostDevices []USBHostDevice `json:"usbHostDevices,omitempty"` + // +listType=map + // +listMapKey=mdevNameSelector + MediatedDevices []MediatedHostDevice `json:"mediatedDevices,omitempty"` +} + +// PciHostDevice represents a host PCI device allowed for passthrough +// +k8s:openapi-gen=true +type PciHostDevice struct { + // a combination of a vendor_id:product_id required to identify a PCI device on a host. + PCIDeviceSelector string `json:"pciDeviceSelector"` + // name by which a device is advertised and being requested + ResourceName string `json:"resourceName"` + // indicates that this resource is being provided by an external device plugin + // +optional + ExternalResourceProvider bool `json:"externalResourceProvider,omitempty"` + // HCO enforces the existence of several PciHostDevice objects. Set disabled field to true instead of remove + // these objects. + // +optional + Disabled bool `json:"disabled,omitempty"` +} + +// USBSelector represents a selector for a USB device allowed for passthrough +// +k8s:openapi-gen=true +type USBSelector struct { + Vendor string `json:"vendor"` + Product string `json:"product"` +} + +// USBHostDevice represents a host USB device allowed for passthrough +// +k8s:openapi-gen=true +type USBHostDevice struct { + // Identifies the list of USB host devices. + // e.g: kubevirt.io/storage, kubevirt.io/bootable-usb, etc + ResourceName string `json:"resourceName"` + // +listType=atomic + Selectors []USBSelector `json:"selectors,omitempty"` + // If true, KubeVirt will leave the allocation and monitoring to an + // external device plugin + ExternalResourceProvider bool `json:"externalResourceProvider,omitempty"` + // HCO enforces the existence of several USBHostDevice objects. Set disabled field to true instead of remove + // these objects. + // +optional + Disabled bool `json:"disabled,omitempty"` +} + +// MediatedHostDevice represents a host mediated device allowed for passthrough +// +k8s:openapi-gen=true +type MediatedHostDevice struct { + // name of a mediated device type required to identify a mediated device on a host + MDEVNameSelector string `json:"mdevNameSelector"` + // name by which a device is advertised and being requested + ResourceName string `json:"resourceName"` + // indicates that this resource is being provided by an external device plugin + // +optional + ExternalResourceProvider bool `json:"externalResourceProvider,omitempty"` + // HCO enforces the existence of several MediatedHostDevice objects. Set disabled field to true instead of remove + // these objects. + // +optional + Disabled bool `json:"disabled,omitempty"` +} + +// MediatedDevicesConfiguration holds information about MDEV types to be defined, if available +// +k8s:openapi-gen=true +type MediatedDevicesConfiguration struct { + // +optional + // +listType=atomic + MediatedDeviceTypes []string `json:"mediatedDeviceTypes"` + + // +optional + // +listType=atomic + NodeMediatedDeviceTypes []NodeMediatedDeviceTypesConfig `json:"nodeMediatedDeviceTypes,omitempty"` +} + +// NodeMediatedDeviceTypesConfig holds information about MDEV types to be defined in a specific node that matches the NodeSelector field. +// +k8s:openapi-gen=true +type NodeMediatedDeviceTypesConfig struct { + + // NodeSelector is a selector which must be true for the vmi to fit on a node. + // Selector which must match a node's labels for the vmi to be scheduled on that node. + // More info: https://kubernetes.io/docs/concepts/configuration/assign-pod-node/ + NodeSelector map[string]string `json:"nodeSelector"` + + // +listType=atomic + // +optional + MediatedDeviceTypes []string `json:"mediatedDeviceTypes"` +} + +// OperandResourceRequirements is a list of resource requirements for the operand workloads pods +// +k8s:openapi-gen=true +type OperandResourceRequirements struct { + // StorageWorkloads defines the resources requirements for storage workloads. It will propagate to the CDI custom + // resource + // +optional + StorageWorkloads *corev1.ResourceRequirements `json:"storageWorkloads,omitempty"` + + // VmiCPUAllocationRatio defines, for each requested virtual CPU, + // how much physical CPU to request per VMI from the + // hosting node. The value is in fraction of a CPU thread (or + // core on non-hyperthreaded nodes). + // VMI POD CPU request = number of vCPUs * 1/vmiCPUAllocationRatio + // For example, a value of 1 means 1 physical CPU thread per VMI CPU thread. + // A value of 100 would be 1% of a physical thread allocated for each + // requested VMI thread. + // This option has no effect on VMIs that request dedicated CPUs. + // Defaults to 10 + // +kubebuilder:default=10 + // +kubebuilder:validation:Minimum=1 + // +default=10 + // +optional + VmiCPUAllocationRatio *int `json:"vmiCPUAllocationRatio,omitempty"` + + // When set, AutoCPULimitNamespaceLabelSelector will set a CPU limit on virt-launcher for VMIs running inside + // namespaces that match the label selector. + // The CPU limit will equal the number of requested vCPUs. + // This setting does not apply to VMIs with dedicated CPUs. + // +optional + AutoCPULimitNamespaceLabelSelector *metav1.LabelSelector `json:"autoCPULimitNamespaceLabelSelector,omitempty"` +} + +// HyperConvergedObsoleteCPUs allows avoiding scheduling of VMs for obsolete CPU models +// +k8s:openapi-gen=true +type HyperConvergedObsoleteCPUs struct { + // CPUModels is a list of obsolete CPU models. When the node-labeller obtains the list of obsolete CPU models, it + // eliminates those CPU models and creates labels for valid CPU models. + // The default values for this field is nil, however, HCO uses opinionated values, and adding values to this list + // will add them to the opinionated values. + // +listType=set + // +optional + CPUModels []string `json:"cpuModels,omitempty"` +} + +// StorageImportConfig contains configuration for importing containerized data +// +k8s:openapi-gen=true +type StorageImportConfig struct { + // InsecureRegistries is a list of image registries URLs that are not secured. Setting an insecure registry URL + // in this list allows pulling images from this registry. + // +listType=set + // +optional + InsecureRegistries []string `json:"insecureRegistries,omitempty"` +} + +// HyperConvergedWorkloadUpdateStrategy defines options related to updating a KubeVirt install +// +// +k8s:openapi-gen=true +type HyperConvergedWorkloadUpdateStrategy struct { + // WorkloadUpdateMethods defines the methods that can be used to disrupt workloads + // during automated workload updates. + // When multiple methods are present, the least disruptive method takes + // precedence over more disruptive methods. For example if both LiveMigrate and Evict + // methods are listed, only VMs which are not live migratable will be restarted/shutdown. + // An empty list defaults to no automated workload updating. + // + // +listType=atomic + // +kubebuilder:default={"LiveMigrate"} + // +default=["LiveMigrate"] + WorkloadUpdateMethods []string `json:"workloadUpdateMethods"` + + // BatchEvictionSize Represents the number of VMIs that can be forced updated per + // the BatchShutdownInterval interval + // + // +kubebuilder:default=10 + // +default=10 + // +optional + BatchEvictionSize *int `json:"batchEvictionSize,omitempty"` + + // BatchEvictionInterval Represents the interval to wait before issuing the next + // batch of shutdowns + // + // +kubebuilder:default="1m0s" + // +default="1m0s" + // +optional + BatchEvictionInterval *metav1.Duration `json:"batchEvictionInterval,omitempty"` +} + +// HyperConvergedStatus defines the observed state of HyperConverged +// +k8s:openapi-gen=true +type HyperConvergedStatus struct { + // Conditions describes the state of the HyperConverged resource. + // +listType=atomic + // +patchMergeKey=type + // +patchStrategy=merge + // +optional + Conditions []metav1.Condition `json:"conditions,omitempty" patchStrategy:"merge" patchMergeKey:"type"` + + // RelatedObjects is a list of objects created and maintained by this + // operator. Object references will be added to this list after they have + // been created AND found in the cluster. + // +listType=atomic + // +optional + RelatedObjects []corev1.ObjectReference `json:"relatedObjects,omitempty"` + + // Versions is a list of HCO component versions, as name/version pairs. The version with a name of "operator" + // is the HCO version itself, as described here: + // https://github.com/openshift/cluster-version-operator/blob/master/docs/dev/clusteroperator.md#version + // +listType=atomic + // +optional + Versions []Version `json:"versions,omitempty"` + + // ObservedGeneration reflects the HyperConverged resource generation. If the ObservedGeneration is less than the + // resource generation in metadata, the status is out of date + // +optional + ObservedGeneration int64 `json:"observedGeneration,omitempty"` + + // DataImportSchedule is the cron expression that is used in for the hard-coded data import cron templates. HCO + // generates the value of this field once and stored in the status field, so will survive restart. + // +optional + DataImportSchedule string `json:"dataImportSchedule,omitempty"` + + // DataImportCronTemplates is a list of the actual DataImportCronTemplates as HCO update in the SSP CR. The list + // contains both the common and the custom templates, including any modification done by HCO. + DataImportCronTemplates []DataImportCronTemplateStatus `json:"dataImportCronTemplates,omitempty"` + + // SystemHealthStatus reflects the health of HCO and its secondary resources, based on the aggregated conditions. + // +optional + SystemHealthStatus string `json:"systemHealthStatus,omitempty"` + + // InfrastructureHighlyAvailable describes whether the cluster has only one worker node + // (false) or more (true). + // +optional + InfrastructureHighlyAvailable *bool `json:"infrastructureHighlyAvailable,omitempty"` + + // NodeInfo holds information about the cluster nodes + NodeInfo NodeInfoStatus `json:"nodeInfo,omitempty"` +} + +type Version struct { + Name string `json:"name,omitempty"` + Version string `json:"version,omitempty"` +} + +// LogVerbosityConfiguration configures log verbosity for different components +// +k8s:openapi-gen=true +type LogVerbosityConfiguration struct { + // Kubevirt is a struct that allows specifying the log verbosity level that controls the amount of information + // logged for each Kubevirt component. + // +optional + Kubevirt *v1.LogVerbosity `json:"kubevirt,omitempty"` + + // CDI indicates the log verbosity level that controls the amount of information logged for CDI components. + // +optional + CDI *int32 `json:"cdi,omitempty"` +} + +// DataImportCronStatus is the status field of the DIC template +type DataImportCronStatus struct { + // Conditions is a list of conditions that describe the state of the DataImportCronTemplate. + Conditions []metav1.Condition `json:"conditions,omitempty"` + + // CommonTemplate indicates whether this is a common template (true), or a custom one (false) + CommonTemplate bool `json:"commonTemplate,omitempty"` + + // Modified indicates if a common template was customized. Always false for custom templates. + Modified bool `json:"modified,omitempty"` + + // OriginalSupportedArchitectures is a comma-separated list of CPU architectures that the original + // template supports. + OriginalSupportedArchitectures string `json:"originalSupportedArchitectures,omitempty"` +} + +// DataImportCronTemplate defines the template type for DataImportCrons. +// It requires metadata.name to be specified while leaving namespace as optional. +type DataImportCronTemplate struct { + metav1.ObjectMeta `json:"metadata,omitempty"` + + Spec *cdiv1beta1.DataImportCronSpec `json:"spec,omitempty"` +} + +// DataImportCronTemplateStatus is a copy of a dataImportCronTemplate as defined in the spec, or in the HCO image. +type DataImportCronTemplateStatus struct { + DataImportCronTemplate `json:",inline"` + + Status DataImportCronStatus `json:"status,omitempty"` +} + +// NodeInfoStatus holds information about the cluster nodes +type NodeInfoStatus struct { + // WorkloadsArchitectures is a distinct list of the CPU architectures of the workloads nodes in the cluster. + WorkloadsArchitectures []string `json:"workloadsArchitectures,omitempty"` + // ControlPlaneArchitectures is a distinct list of the CPU architecture of the control-plane nodes. + ControlPlaneArchitectures []string `json:"controlPlaneArchitectures,omitempty"` +} + +// ApplicationAwareConfigurations holds the AAQ configurations +// +k8s:openapi-gen=true +type ApplicationAwareConfigurations struct { + // VmiCalcConfigName determine how resource allocation will be done with ApplicationsResourceQuota. + // allowed values are: VmiPodUsage, VirtualResources, DedicatedVirtualResources or IgnoreVmiCalculator + // +kubebuilder:validation:Enum=VmiPodUsage;VirtualResources;DedicatedVirtualResources;IgnoreVmiCalculator + // +kubebuilder:default=DedicatedVirtualResources + VmiCalcConfigName *aaqv1alpha1.VmiCalcConfigName `json:"vmiCalcConfigName,omitempty"` + + // NamespaceSelector determines in which namespaces scheduling gate will be added to pods.. + NamespaceSelector *metav1.LabelSelector `json:"namespaceSelector,omitempty"` + + // AllowApplicationAwareClusterResourceQuota if set to true, allows creation and management of ClusterAppsResourceQuota + // +kubebuilder:default=false + AllowApplicationAwareClusterResourceQuota bool `json:"allowApplicationAwareClusterResourceQuota,omitempty"` +} + +// HigherWorkloadDensity holds configuration aimed to increase virtual machine density +type HigherWorkloadDensityConfiguration struct { + // MemoryOvercommitPercentage is the percentage of memory we want to give VMIs compared to the amount + // given to its parent pod (virt-launcher). For example, a value of 102 means the VMI will + // "see" 2% more memory than its parent pod. Values under 100 are effectively "undercommits". + // Overcommits can lead to memory exhaustion, which in turn can lead to crashes. Use carefully. + // +kubebuilder:validation:Minimum=10 + // +kubebuilder:default=100 + // +default=100 + MemoryOvercommitPercentage int `json:"memoryOvercommitPercentage,omitempty"` +} + +// KubeMacPoolConfig defines kubemacpool MAC address range configuration +// +k8s:openapi-gen=true +// +kubebuilder:validation:XValidation:rule="(has(self.rangeStart) && has(self.rangeEnd)) || (!has(self.rangeStart) && !has(self.rangeEnd))",message="both rangeStart and rangeEnd must be configured together, or both omitted" +type KubeMacPoolConfig struct { + // RangeStart defines the first MAC address in the kubemacpool range. + // The MAC address format should be AA:BB:CC:DD:EE:FF. + // +optional + // +kubebuilder:validation:Pattern=`^([0-9a-fA-F]{2}:){5}[0-9a-fA-F]{2}$` + RangeStart *string `json:"rangeStart,omitempty"` + // RangeEnd defines the last MAC address in the kubemacpool range. + // The MAC address format should be AA:BB:CC:DD:EE:FF. + // +optional + // +kubebuilder:validation:Pattern=`^([0-9a-fA-F]{2}:){5}[0-9a-fA-F]{2}$` + RangeEnd *string `json:"rangeEnd,omitempty"` +} + +const ( + ConditionAvailable = "Available" + + // ConditionProgressing indicates that the operator is actively making changes to the resources maintained by the + // operator + ConditionProgressing = "Progressing" + + // ConditionDegraded indicates that the resources maintained by the operator are not functioning completely. + // An example of a degraded state would be if not all pods in a deployment were running. + // It may still be available, but it is degraded + ConditionDegraded = "Degraded" + + // ConditionUpgradeable indicates whether the resources maintained by the operator are in a state that is safe to upgrade. + // When `False`, the resources maintained by the operator should not be upgraded and the + // message field should contain a human-readable description of what the administrator should do to + // allow the operator to successfully update the resources maintained by the operator. + ConditionUpgradeable = "Upgradeable" + + // ConditionReconcileComplete communicates the status of the HyperConverged resource's + // reconcile functionality. Basically, is the Reconcile function running to completion. + ConditionReconcileComplete = "ReconcileComplete" + + // ConditionTaintedConfiguration indicates that a hidden/debug configuration + // has been applied to the HyperConverged resource via a specialized annotation. + // This condition is exposed only when its value is True, and is otherwise hidden. + ConditionTaintedConfiguration = "TaintedConfiguration" +) + +// +k8s:deepcopy-gen:interfaces=k8s.io/apimachinery/pkg/runtime.Object + +// HyperConverged is the Schema for the hyperconvergeds API +// +k8s:openapi-gen=true +// +kubebuilder:printcolumn:name="Age",type=date,JSONPath=`.metadata.creationTimestamp` +// +kubebuilder:resource:scope=Namespaced,categories={all},shortName={hco,hcos} +// +kubebuilder:subresource:status +type HyperConverged struct { + metav1.TypeMeta `json:",inline"` + metav1.ObjectMeta `json:"metadata,omitempty"` + + // +kubebuilder:default={"certConfig": {"ca": {"duration": "48h0m0s", "renewBefore": "24h0m0s"}, "server": {"duration": "24h0m0s", "renewBefore": "12h0m0s"}}, "liveMigrationConfig": {"completionTimeoutPerGiB": 150, "parallelMigrationsPerCluster": 5, "parallelOutboundMigrationsPerNode": 2, "progressTimeout": 150, "allowAutoConverge": false, "allowPostCopy": false}, "resourceRequirements": {"vmiCPUAllocationRatio": 10}, "uninstallStrategy": "BlockUninstallIfWorkloadsExist", "virtualMachineOptions": {"disableFreePageReporting": false, "disableSerialConsoleLog": false}, "enableApplicationAwareQuota": false, "enableCommonBootImageImport": true, "deployVmConsoleProxy": false} + // +optional + Spec HyperConvergedSpec `json:"spec,omitempty"` + Status HyperConvergedStatus `json:"status,omitempty"` +} + +// +k8s:deepcopy-gen:interfaces=k8s.io/apimachinery/pkg/runtime.Object + +// HyperConvergedList contains a list of HyperConverged +type HyperConvergedList struct { + metav1.TypeMeta `json:",inline"` + metav1.ListMeta `json:"metadata,omitempty"` + Items []HyperConverged `json:"items"` +} diff --git a/api/v1/register.go b/api/v1/register.go new file mode 100644 index 0000000000..ce1ce67453 --- /dev/null +++ b/api/v1/register.go @@ -0,0 +1,33 @@ +// NOTE: Boilerplate only. Ignore this file. + +package v1 + +import ( + metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" + "k8s.io/apimachinery/pkg/runtime" + "k8s.io/apimachinery/pkg/runtime/schema" +) + +const ( + APIVersionV1 = "v1" + CurrentAPIVersion = APIVersionV1 + APIVersionGroup = "hco.kubevirt.io" + APIVersion = APIVersionGroup + "/" + CurrentAPIVersion +) + +var ( + // SchemeGroupVersion is group version used to register these objects + SchemeGroupVersion = schema.GroupVersion{Group: APIVersionGroup, Version: APIVersionV1} + + // schemeBuilder is used to add go types to the GroupVersionKind scheme + schemeBuilder = runtime.NewSchemeBuilder(addKnownTypes) + + // AddToScheme tbd + AddToScheme = schemeBuilder.AddToScheme +) + +func addKnownTypes(scheme *runtime.Scheme) error { + scheme.AddKnownTypes(SchemeGroupVersion, &HyperConverged{}, &HyperConvergedList{}) + metav1.AddToGroupVersion(scheme, SchemeGroupVersion) + return nil +} diff --git a/api/v1/zz_generated.deepcopy.go b/api/v1/zz_generated.deepcopy.go new file mode 100644 index 0000000000..0929c5be5d --- /dev/null +++ b/api/v1/zz_generated.deepcopy.go @@ -0,0 +1,953 @@ +//go:build !ignore_autogenerated +// +build !ignore_autogenerated + +/* + * This file is part of the KubeVirt project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + * Copyright 2026 Red Hat, Inc. + * + */ + +// Code generated by deepcopy-gen. DO NOT EDIT. + +package v1 + +import ( + featuregates "github.com/kubevirt/hyperconverged-cluster-operator/api/v1/featuregates" + configv1 "github.com/openshift/api/config/v1" + apicorev1 "k8s.io/api/core/v1" + metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" + runtime "k8s.io/apimachinery/pkg/runtime" + corev1 "kubevirt.io/api/core/v1" + v1alpha1 "kubevirt.io/application-aware-quota/staging/src/kubevirt.io/application-aware-quota-api/pkg/apis/core/v1alpha1" + v1beta1 "kubevirt.io/containerized-data-importer-api/pkg/apis/core/v1beta1" +) + +// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. +func (in *ApplicationAwareConfigurations) DeepCopyInto(out *ApplicationAwareConfigurations) { + *out = *in + if in.VmiCalcConfigName != nil { + in, out := &in.VmiCalcConfigName, &out.VmiCalcConfigName + *out = new(v1alpha1.VmiCalcConfigName) + **out = **in + } + if in.NamespaceSelector != nil { + in, out := &in.NamespaceSelector, &out.NamespaceSelector + *out = new(metav1.LabelSelector) + (*in).DeepCopyInto(*out) + } + return +} + +// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new ApplicationAwareConfigurations. +func (in *ApplicationAwareConfigurations) DeepCopy() *ApplicationAwareConfigurations { + if in == nil { + return nil + } + out := new(ApplicationAwareConfigurations) + in.DeepCopyInto(out) + return out +} + +// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. +func (in *CertRotateConfigCA) DeepCopyInto(out *CertRotateConfigCA) { + *out = *in + if in.Duration != nil { + in, out := &in.Duration, &out.Duration + *out = new(metav1.Duration) + **out = **in + } + if in.RenewBefore != nil { + in, out := &in.RenewBefore, &out.RenewBefore + *out = new(metav1.Duration) + **out = **in + } + return +} + +// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new CertRotateConfigCA. +func (in *CertRotateConfigCA) DeepCopy() *CertRotateConfigCA { + if in == nil { + return nil + } + out := new(CertRotateConfigCA) + in.DeepCopyInto(out) + return out +} + +// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. +func (in *CertRotateConfigServer) DeepCopyInto(out *CertRotateConfigServer) { + *out = *in + if in.Duration != nil { + in, out := &in.Duration, &out.Duration + *out = new(metav1.Duration) + **out = **in + } + if in.RenewBefore != nil { + in, out := &in.RenewBefore, &out.RenewBefore + *out = new(metav1.Duration) + **out = **in + } + return +} + +// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new CertRotateConfigServer. +func (in *CertRotateConfigServer) DeepCopy() *CertRotateConfigServer { + if in == nil { + return nil + } + out := new(CertRotateConfigServer) + in.DeepCopyInto(out) + return out +} + +// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. +func (in *DataImportCronStatus) DeepCopyInto(out *DataImportCronStatus) { + *out = *in + if in.Conditions != nil { + in, out := &in.Conditions, &out.Conditions + *out = make([]metav1.Condition, len(*in)) + for i := range *in { + (*in)[i].DeepCopyInto(&(*out)[i]) + } + } + return +} + +// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new DataImportCronStatus. +func (in *DataImportCronStatus) DeepCopy() *DataImportCronStatus { + if in == nil { + return nil + } + out := new(DataImportCronStatus) + in.DeepCopyInto(out) + return out +} + +// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. +func (in *DataImportCronTemplate) DeepCopyInto(out *DataImportCronTemplate) { + *out = *in + in.ObjectMeta.DeepCopyInto(&out.ObjectMeta) + if in.Spec != nil { + in, out := &in.Spec, &out.Spec + *out = new(v1beta1.DataImportCronSpec) + (*in).DeepCopyInto(*out) + } + return +} + +// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new DataImportCronTemplate. +func (in *DataImportCronTemplate) DeepCopy() *DataImportCronTemplate { + if in == nil { + return nil + } + out := new(DataImportCronTemplate) + in.DeepCopyInto(out) + return out +} + +// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. +func (in *DataImportCronTemplateStatus) DeepCopyInto(out *DataImportCronTemplateStatus) { + *out = *in + in.DataImportCronTemplate.DeepCopyInto(&out.DataImportCronTemplate) + in.Status.DeepCopyInto(&out.Status) + return +} + +// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new DataImportCronTemplateStatus. +func (in *DataImportCronTemplateStatus) DeepCopy() *DataImportCronTemplateStatus { + if in == nil { + return nil + } + out := new(DataImportCronTemplateStatus) + in.DeepCopyInto(out) + return out +} + +// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. +func (in *HigherWorkloadDensityConfiguration) DeepCopyInto(out *HigherWorkloadDensityConfiguration) { + *out = *in + return +} + +// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new HigherWorkloadDensityConfiguration. +func (in *HigherWorkloadDensityConfiguration) DeepCopy() *HigherWorkloadDensityConfiguration { + if in == nil { + return nil + } + out := new(HigherWorkloadDensityConfiguration) + in.DeepCopyInto(out) + return out +} + +// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. +func (in *HyperConverged) DeepCopyInto(out *HyperConverged) { + *out = *in + out.TypeMeta = in.TypeMeta + in.ObjectMeta.DeepCopyInto(&out.ObjectMeta) + in.Spec.DeepCopyInto(&out.Spec) + in.Status.DeepCopyInto(&out.Status) + return +} + +// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new HyperConverged. +func (in *HyperConverged) DeepCopy() *HyperConverged { + if in == nil { + return nil + } + out := new(HyperConverged) + in.DeepCopyInto(out) + return out +} + +// DeepCopyObject is an autogenerated deepcopy function, copying the receiver, creating a new runtime.Object. +func (in *HyperConverged) DeepCopyObject() runtime.Object { + if c := in.DeepCopy(); c != nil { + return c + } + return nil +} + +// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. +func (in *HyperConvergedCertConfig) DeepCopyInto(out *HyperConvergedCertConfig) { + *out = *in + in.CA.DeepCopyInto(&out.CA) + in.Server.DeepCopyInto(&out.Server) + return +} + +// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new HyperConvergedCertConfig. +func (in *HyperConvergedCertConfig) DeepCopy() *HyperConvergedCertConfig { + if in == nil { + return nil + } + out := new(HyperConvergedCertConfig) + in.DeepCopyInto(out) + return out +} + +// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. +func (in *HyperConvergedConfig) DeepCopyInto(out *HyperConvergedConfig) { + *out = *in + if in.NodePlacement != nil { + in, out := &in.NodePlacement, &out.NodePlacement + *out = (*in).DeepCopy() + } + return +} + +// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new HyperConvergedConfig. +func (in *HyperConvergedConfig) DeepCopy() *HyperConvergedConfig { + if in == nil { + return nil + } + out := new(HyperConvergedConfig) + in.DeepCopyInto(out) + return out +} + +// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. +func (in *HyperConvergedList) DeepCopyInto(out *HyperConvergedList) { + *out = *in + out.TypeMeta = in.TypeMeta + in.ListMeta.DeepCopyInto(&out.ListMeta) + if in.Items != nil { + in, out := &in.Items, &out.Items + *out = make([]HyperConverged, len(*in)) + for i := range *in { + (*in)[i].DeepCopyInto(&(*out)[i]) + } + } + return +} + +// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new HyperConvergedList. +func (in *HyperConvergedList) DeepCopy() *HyperConvergedList { + if in == nil { + return nil + } + out := new(HyperConvergedList) + in.DeepCopyInto(out) + return out +} + +// DeepCopyObject is an autogenerated deepcopy function, copying the receiver, creating a new runtime.Object. +func (in *HyperConvergedList) DeepCopyObject() runtime.Object { + if c := in.DeepCopy(); c != nil { + return c + } + return nil +} + +// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. +func (in *HyperConvergedObsoleteCPUs) DeepCopyInto(out *HyperConvergedObsoleteCPUs) { + *out = *in + if in.CPUModels != nil { + in, out := &in.CPUModels, &out.CPUModels + *out = make([]string, len(*in)) + copy(*out, *in) + } + return +} + +// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new HyperConvergedObsoleteCPUs. +func (in *HyperConvergedObsoleteCPUs) DeepCopy() *HyperConvergedObsoleteCPUs { + if in == nil { + return nil + } + out := new(HyperConvergedObsoleteCPUs) + in.DeepCopyInto(out) + return out +} + +// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. +func (in *HyperConvergedSpec) DeepCopyInto(out *HyperConvergedSpec) { + *out = *in + in.Infra.DeepCopyInto(&out.Infra) + in.Workloads.DeepCopyInto(&out.Workloads) + if in.FeatureGates != nil { + in, out := &in.FeatureGates, &out.FeatureGates + *out = make(featuregates.HyperConvergedFeatureGates, len(*in)) + for i := range *in { + (*in)[i].DeepCopyInto(&(*out)[i]) + } + } + in.LiveMigrationConfig.DeepCopyInto(&out.LiveMigrationConfig) + if in.PermittedHostDevices != nil { + in, out := &in.PermittedHostDevices, &out.PermittedHostDevices + *out = new(PermittedHostDevices) + (*in).DeepCopyInto(*out) + } + if in.MediatedDevicesConfiguration != nil { + in, out := &in.MediatedDevicesConfiguration, &out.MediatedDevicesConfiguration + *out = new(MediatedDevicesConfiguration) + (*in).DeepCopyInto(*out) + } + in.CertConfig.DeepCopyInto(&out.CertConfig) + if in.ResourceRequirements != nil { + in, out := &in.ResourceRequirements, &out.ResourceRequirements + *out = new(OperandResourceRequirements) + (*in).DeepCopyInto(*out) + } + if in.ScratchSpaceStorageClass != nil { + in, out := &in.ScratchSpaceStorageClass, &out.ScratchSpaceStorageClass + *out = new(string) + **out = **in + } + if in.DefaultCPUModel != nil { + in, out := &in.DefaultCPUModel, &out.DefaultCPUModel + *out = new(string) + **out = **in + } + if in.DefaultRuntimeClass != nil { + in, out := &in.DefaultRuntimeClass, &out.DefaultRuntimeClass + *out = new(string) + **out = **in + } + if in.ObsoleteCPUs != nil { + in, out := &in.ObsoleteCPUs, &out.ObsoleteCPUs + *out = new(HyperConvergedObsoleteCPUs) + (*in).DeepCopyInto(*out) + } + if in.CommonTemplatesNamespace != nil { + in, out := &in.CommonTemplatesNamespace, &out.CommonTemplatesNamespace + *out = new(string) + **out = **in + } + if in.StorageImport != nil { + in, out := &in.StorageImport, &out.StorageImport + *out = new(StorageImportConfig) + (*in).DeepCopyInto(*out) + } + in.WorkloadUpdateStrategy.DeepCopyInto(&out.WorkloadUpdateStrategy) + if in.DataImportCronTemplates != nil { + in, out := &in.DataImportCronTemplates, &out.DataImportCronTemplates + *out = make([]DataImportCronTemplate, len(*in)) + for i := range *in { + (*in)[i].DeepCopyInto(&(*out)[i]) + } + } + if in.FilesystemOverhead != nil { + in, out := &in.FilesystemOverhead, &out.FilesystemOverhead + *out = new(v1beta1.FilesystemOverhead) + (*in).DeepCopyInto(*out) + } + if in.LogVerbosityConfig != nil { + in, out := &in.LogVerbosityConfig, &out.LogVerbosityConfig + *out = new(LogVerbosityConfiguration) + (*in).DeepCopyInto(*out) + } + if in.TLSSecurityProfile != nil { + in, out := &in.TLSSecurityProfile, &out.TLSSecurityProfile + *out = new(configv1.TLSSecurityProfile) + (*in).DeepCopyInto(*out) + } + if in.KubeSecondaryDNSNameServerIP != nil { + in, out := &in.KubeSecondaryDNSNameServerIP, &out.KubeSecondaryDNSNameServerIP + *out = new(string) + **out = **in + } + if in.KubeMacPoolConfiguration != nil { + in, out := &in.KubeMacPoolConfiguration, &out.KubeMacPoolConfiguration + *out = new(KubeMacPoolConfig) + (*in).DeepCopyInto(*out) + } + if in.EvictionStrategy != nil { + in, out := &in.EvictionStrategy, &out.EvictionStrategy + *out = new(corev1.EvictionStrategy) + **out = **in + } + if in.VMStateStorageClass != nil { + in, out := &in.VMStateStorageClass, &out.VMStateStorageClass + *out = new(string) + **out = **in + } + if in.VirtualMachineOptions != nil { + in, out := &in.VirtualMachineOptions, &out.VirtualMachineOptions + *out = new(VirtualMachineOptions) + (*in).DeepCopyInto(*out) + } + if in.CommonBootImageNamespace != nil { + in, out := &in.CommonBootImageNamespace, &out.CommonBootImageNamespace + *out = new(string) + **out = **in + } + if in.KSMConfiguration != nil { + in, out := &in.KSMConfiguration, &out.KSMConfiguration + *out = new(corev1.KSMConfiguration) + (*in).DeepCopyInto(*out) + } + if in.NetworkBinding != nil { + in, out := &in.NetworkBinding, &out.NetworkBinding + *out = make(map[string]corev1.InterfaceBindingPlugin, len(*in)) + for key, val := range *in { + (*out)[key] = *val.DeepCopy() + } + } + if in.ApplicationAwareConfig != nil { + in, out := &in.ApplicationAwareConfig, &out.ApplicationAwareConfig + *out = new(ApplicationAwareConfigurations) + (*in).DeepCopyInto(*out) + } + if in.HigherWorkloadDensity != nil { + in, out := &in.HigherWorkloadDensity, &out.HigherWorkloadDensity + *out = new(HigherWorkloadDensityConfiguration) + **out = **in + } + if in.EnableCommonBootImageImport != nil { + in, out := &in.EnableCommonBootImageImport, &out.EnableCommonBootImageImport + *out = new(bool) + **out = **in + } + if in.InstancetypeConfig != nil { + in, out := &in.InstancetypeConfig, &out.InstancetypeConfig + *out = new(corev1.InstancetypeConfiguration) + (*in).DeepCopyInto(*out) + } + if in.CommonInstancetypesDeployment != nil { + in, out := &in.CommonInstancetypesDeployment, &out.CommonInstancetypesDeployment + *out = new(corev1.CommonInstancetypesDeployment) + (*in).DeepCopyInto(*out) + } + if in.DeployVMConsoleProxy != nil { + in, out := &in.DeployVMConsoleProxy, &out.DeployVMConsoleProxy + *out = new(bool) + **out = **in + } + if in.EnableApplicationAwareQuota != nil { + in, out := &in.EnableApplicationAwareQuota, &out.EnableApplicationAwareQuota + *out = new(bool) + **out = **in + } + if in.LiveUpdateConfiguration != nil { + in, out := &in.LiveUpdateConfiguration, &out.LiveUpdateConfiguration + *out = new(corev1.LiveUpdateConfiguration) + (*in).DeepCopyInto(*out) + } + return +} + +// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new HyperConvergedSpec. +func (in *HyperConvergedSpec) DeepCopy() *HyperConvergedSpec { + if in == nil { + return nil + } + out := new(HyperConvergedSpec) + in.DeepCopyInto(out) + return out +} + +// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. +func (in *HyperConvergedStatus) DeepCopyInto(out *HyperConvergedStatus) { + *out = *in + if in.Conditions != nil { + in, out := &in.Conditions, &out.Conditions + *out = make([]metav1.Condition, len(*in)) + for i := range *in { + (*in)[i].DeepCopyInto(&(*out)[i]) + } + } + if in.RelatedObjects != nil { + in, out := &in.RelatedObjects, &out.RelatedObjects + *out = make([]apicorev1.ObjectReference, len(*in)) + copy(*out, *in) + } + if in.Versions != nil { + in, out := &in.Versions, &out.Versions + *out = make([]Version, len(*in)) + copy(*out, *in) + } + if in.DataImportCronTemplates != nil { + in, out := &in.DataImportCronTemplates, &out.DataImportCronTemplates + *out = make([]DataImportCronTemplateStatus, len(*in)) + for i := range *in { + (*in)[i].DeepCopyInto(&(*out)[i]) + } + } + if in.InfrastructureHighlyAvailable != nil { + in, out := &in.InfrastructureHighlyAvailable, &out.InfrastructureHighlyAvailable + *out = new(bool) + **out = **in + } + in.NodeInfo.DeepCopyInto(&out.NodeInfo) + return +} + +// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new HyperConvergedStatus. +func (in *HyperConvergedStatus) DeepCopy() *HyperConvergedStatus { + if in == nil { + return nil + } + out := new(HyperConvergedStatus) + in.DeepCopyInto(out) + return out +} + +// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. +func (in *HyperConvergedWorkloadUpdateStrategy) DeepCopyInto(out *HyperConvergedWorkloadUpdateStrategy) { + *out = *in + if in.WorkloadUpdateMethods != nil { + in, out := &in.WorkloadUpdateMethods, &out.WorkloadUpdateMethods + *out = make([]string, len(*in)) + copy(*out, *in) + } + if in.BatchEvictionSize != nil { + in, out := &in.BatchEvictionSize, &out.BatchEvictionSize + *out = new(int) + **out = **in + } + if in.BatchEvictionInterval != nil { + in, out := &in.BatchEvictionInterval, &out.BatchEvictionInterval + *out = new(metav1.Duration) + **out = **in + } + return +} + +// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new HyperConvergedWorkloadUpdateStrategy. +func (in *HyperConvergedWorkloadUpdateStrategy) DeepCopy() *HyperConvergedWorkloadUpdateStrategy { + if in == nil { + return nil + } + out := new(HyperConvergedWorkloadUpdateStrategy) + in.DeepCopyInto(out) + return out +} + +// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. +func (in *KubeMacPoolConfig) DeepCopyInto(out *KubeMacPoolConfig) { + *out = *in + if in.RangeStart != nil { + in, out := &in.RangeStart, &out.RangeStart + *out = new(string) + **out = **in + } + if in.RangeEnd != nil { + in, out := &in.RangeEnd, &out.RangeEnd + *out = new(string) + **out = **in + } + return +} + +// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new KubeMacPoolConfig. +func (in *KubeMacPoolConfig) DeepCopy() *KubeMacPoolConfig { + if in == nil { + return nil + } + out := new(KubeMacPoolConfig) + in.DeepCopyInto(out) + return out +} + +// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. +func (in *LiveMigrationConfigurations) DeepCopyInto(out *LiveMigrationConfigurations) { + *out = *in + if in.ParallelMigrationsPerCluster != nil { + in, out := &in.ParallelMigrationsPerCluster, &out.ParallelMigrationsPerCluster + *out = new(uint32) + **out = **in + } + if in.ParallelOutboundMigrationsPerNode != nil { + in, out := &in.ParallelOutboundMigrationsPerNode, &out.ParallelOutboundMigrationsPerNode + *out = new(uint32) + **out = **in + } + if in.BandwidthPerMigration != nil { + in, out := &in.BandwidthPerMigration, &out.BandwidthPerMigration + *out = new(string) + **out = **in + } + if in.CompletionTimeoutPerGiB != nil { + in, out := &in.CompletionTimeoutPerGiB, &out.CompletionTimeoutPerGiB + *out = new(int64) + **out = **in + } + if in.ProgressTimeout != nil { + in, out := &in.ProgressTimeout, &out.ProgressTimeout + *out = new(int64) + **out = **in + } + if in.Network != nil { + in, out := &in.Network, &out.Network + *out = new(string) + **out = **in + } + if in.AllowAutoConverge != nil { + in, out := &in.AllowAutoConverge, &out.AllowAutoConverge + *out = new(bool) + **out = **in + } + if in.AllowPostCopy != nil { + in, out := &in.AllowPostCopy, &out.AllowPostCopy + *out = new(bool) + **out = **in + } + return +} + +// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new LiveMigrationConfigurations. +func (in *LiveMigrationConfigurations) DeepCopy() *LiveMigrationConfigurations { + if in == nil { + return nil + } + out := new(LiveMigrationConfigurations) + in.DeepCopyInto(out) + return out +} + +// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. +func (in *LogVerbosityConfiguration) DeepCopyInto(out *LogVerbosityConfiguration) { + *out = *in + if in.Kubevirt != nil { + in, out := &in.Kubevirt, &out.Kubevirt + *out = new(corev1.LogVerbosity) + (*in).DeepCopyInto(*out) + } + if in.CDI != nil { + in, out := &in.CDI, &out.CDI + *out = new(int32) + **out = **in + } + return +} + +// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new LogVerbosityConfiguration. +func (in *LogVerbosityConfiguration) DeepCopy() *LogVerbosityConfiguration { + if in == nil { + return nil + } + out := new(LogVerbosityConfiguration) + in.DeepCopyInto(out) + return out +} + +// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. +func (in *MediatedDevicesConfiguration) DeepCopyInto(out *MediatedDevicesConfiguration) { + *out = *in + if in.MediatedDeviceTypes != nil { + in, out := &in.MediatedDeviceTypes, &out.MediatedDeviceTypes + *out = make([]string, len(*in)) + copy(*out, *in) + } + if in.NodeMediatedDeviceTypes != nil { + in, out := &in.NodeMediatedDeviceTypes, &out.NodeMediatedDeviceTypes + *out = make([]NodeMediatedDeviceTypesConfig, len(*in)) + for i := range *in { + (*in)[i].DeepCopyInto(&(*out)[i]) + } + } + return +} + +// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new MediatedDevicesConfiguration. +func (in *MediatedDevicesConfiguration) DeepCopy() *MediatedDevicesConfiguration { + if in == nil { + return nil + } + out := new(MediatedDevicesConfiguration) + in.DeepCopyInto(out) + return out +} + +// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. +func (in *MediatedHostDevice) DeepCopyInto(out *MediatedHostDevice) { + *out = *in + return +} + +// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new MediatedHostDevice. +func (in *MediatedHostDevice) DeepCopy() *MediatedHostDevice { + if in == nil { + return nil + } + out := new(MediatedHostDevice) + in.DeepCopyInto(out) + return out +} + +// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. +func (in *NodeInfoStatus) DeepCopyInto(out *NodeInfoStatus) { + *out = *in + if in.WorkloadsArchitectures != nil { + in, out := &in.WorkloadsArchitectures, &out.WorkloadsArchitectures + *out = make([]string, len(*in)) + copy(*out, *in) + } + if in.ControlPlaneArchitectures != nil { + in, out := &in.ControlPlaneArchitectures, &out.ControlPlaneArchitectures + *out = make([]string, len(*in)) + copy(*out, *in) + } + return +} + +// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new NodeInfoStatus. +func (in *NodeInfoStatus) DeepCopy() *NodeInfoStatus { + if in == nil { + return nil + } + out := new(NodeInfoStatus) + in.DeepCopyInto(out) + return out +} + +// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. +func (in *NodeMediatedDeviceTypesConfig) DeepCopyInto(out *NodeMediatedDeviceTypesConfig) { + *out = *in + if in.NodeSelector != nil { + in, out := &in.NodeSelector, &out.NodeSelector + *out = make(map[string]string, len(*in)) + for key, val := range *in { + (*out)[key] = val + } + } + if in.MediatedDeviceTypes != nil { + in, out := &in.MediatedDeviceTypes, &out.MediatedDeviceTypes + *out = make([]string, len(*in)) + copy(*out, *in) + } + return +} + +// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new NodeMediatedDeviceTypesConfig. +func (in *NodeMediatedDeviceTypesConfig) DeepCopy() *NodeMediatedDeviceTypesConfig { + if in == nil { + return nil + } + out := new(NodeMediatedDeviceTypesConfig) + in.DeepCopyInto(out) + return out +} + +// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. +func (in *OperandResourceRequirements) DeepCopyInto(out *OperandResourceRequirements) { + *out = *in + if in.StorageWorkloads != nil { + in, out := &in.StorageWorkloads, &out.StorageWorkloads + *out = new(apicorev1.ResourceRequirements) + (*in).DeepCopyInto(*out) + } + if in.VmiCPUAllocationRatio != nil { + in, out := &in.VmiCPUAllocationRatio, &out.VmiCPUAllocationRatio + *out = new(int) + **out = **in + } + if in.AutoCPULimitNamespaceLabelSelector != nil { + in, out := &in.AutoCPULimitNamespaceLabelSelector, &out.AutoCPULimitNamespaceLabelSelector + *out = new(metav1.LabelSelector) + (*in).DeepCopyInto(*out) + } + return +} + +// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new OperandResourceRequirements. +func (in *OperandResourceRequirements) DeepCopy() *OperandResourceRequirements { + if in == nil { + return nil + } + out := new(OperandResourceRequirements) + in.DeepCopyInto(out) + return out +} + +// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. +func (in *PciHostDevice) DeepCopyInto(out *PciHostDevice) { + *out = *in + return +} + +// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new PciHostDevice. +func (in *PciHostDevice) DeepCopy() *PciHostDevice { + if in == nil { + return nil + } + out := new(PciHostDevice) + in.DeepCopyInto(out) + return out +} + +// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. +func (in *PermittedHostDevices) DeepCopyInto(out *PermittedHostDevices) { + *out = *in + if in.PciHostDevices != nil { + in, out := &in.PciHostDevices, &out.PciHostDevices + *out = make([]PciHostDevice, len(*in)) + copy(*out, *in) + } + if in.USBHostDevices != nil { + in, out := &in.USBHostDevices, &out.USBHostDevices + *out = make([]USBHostDevice, len(*in)) + for i := range *in { + (*in)[i].DeepCopyInto(&(*out)[i]) + } + } + if in.MediatedDevices != nil { + in, out := &in.MediatedDevices, &out.MediatedDevices + *out = make([]MediatedHostDevice, len(*in)) + copy(*out, *in) + } + return +} + +// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new PermittedHostDevices. +func (in *PermittedHostDevices) DeepCopy() *PermittedHostDevices { + if in == nil { + return nil + } + out := new(PermittedHostDevices) + in.DeepCopyInto(out) + return out +} + +// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. +func (in *StorageImportConfig) DeepCopyInto(out *StorageImportConfig) { + *out = *in + if in.InsecureRegistries != nil { + in, out := &in.InsecureRegistries, &out.InsecureRegistries + *out = make([]string, len(*in)) + copy(*out, *in) + } + return +} + +// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new StorageImportConfig. +func (in *StorageImportConfig) DeepCopy() *StorageImportConfig { + if in == nil { + return nil + } + out := new(StorageImportConfig) + in.DeepCopyInto(out) + return out +} + +// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. +func (in *USBHostDevice) DeepCopyInto(out *USBHostDevice) { + *out = *in + if in.Selectors != nil { + in, out := &in.Selectors, &out.Selectors + *out = make([]USBSelector, len(*in)) + copy(*out, *in) + } + return +} + +// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new USBHostDevice. +func (in *USBHostDevice) DeepCopy() *USBHostDevice { + if in == nil { + return nil + } + out := new(USBHostDevice) + in.DeepCopyInto(out) + return out +} + +// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. +func (in *USBSelector) DeepCopyInto(out *USBSelector) { + *out = *in + return +} + +// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new USBSelector. +func (in *USBSelector) DeepCopy() *USBSelector { + if in == nil { + return nil + } + out := new(USBSelector) + in.DeepCopyInto(out) + return out +} + +// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. +func (in *Version) DeepCopyInto(out *Version) { + *out = *in + return +} + +// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new Version. +func (in *Version) DeepCopy() *Version { + if in == nil { + return nil + } + out := new(Version) + in.DeepCopyInto(out) + return out +} + +// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. +func (in *VirtualMachineOptions) DeepCopyInto(out *VirtualMachineOptions) { + *out = *in + if in.DisableFreePageReporting != nil { + in, out := &in.DisableFreePageReporting, &out.DisableFreePageReporting + *out = new(bool) + **out = **in + } + if in.DisableSerialConsoleLog != nil { + in, out := &in.DisableSerialConsoleLog, &out.DisableSerialConsoleLog + *out = new(bool) + **out = **in + } + return +} + +// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new VirtualMachineOptions. +func (in *VirtualMachineOptions) DeepCopy() *VirtualMachineOptions { + if in == nil { + return nil + } + out := new(VirtualMachineOptions) + in.DeepCopyInto(out) + return out +} diff --git a/api/v1/zz_generated.defaults.go b/api/v1/zz_generated.defaults.go new file mode 100644 index 0000000000..3deca0c2ac --- /dev/null +++ b/api/v1/zz_generated.defaults.go @@ -0,0 +1,154 @@ +//go:build !ignore_autogenerated +// +build !ignore_autogenerated + +/* + * This file is part of the KubeVirt project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + * Copyright 2026 Red Hat, Inc. + * + */ + +// Code generated by defaulter-gen. DO NOT EDIT. + +package v1 + +import ( + json "encoding/json" + + runtime "k8s.io/apimachinery/pkg/runtime" +) + +// RegisterDefaults adds defaulters functions to the given scheme. +// Public to allow building arbitrary schemes. +// All generated defaulters are covering - they call all nested defaulters. +func RegisterDefaults(scheme *runtime.Scheme) error { + scheme.AddTypeDefaultingFunc(&HyperConverged{}, func(obj interface{}) { SetObjectDefaults_HyperConverged(obj.(*HyperConverged)) }) + scheme.AddTypeDefaultingFunc(&HyperConvergedList{}, func(obj interface{}) { SetObjectDefaults_HyperConvergedList(obj.(*HyperConvergedList)) }) + return nil +} + +func SetObjectDefaults_HyperConverged(in *HyperConverged) { + if in.Spec.LiveMigrationConfig.ParallelMigrationsPerCluster == nil { + var ptrVar1 uint32 = 5 + in.Spec.LiveMigrationConfig.ParallelMigrationsPerCluster = &ptrVar1 + } + if in.Spec.LiveMigrationConfig.ParallelOutboundMigrationsPerNode == nil { + var ptrVar1 uint32 = 2 + in.Spec.LiveMigrationConfig.ParallelOutboundMigrationsPerNode = &ptrVar1 + } + if in.Spec.LiveMigrationConfig.CompletionTimeoutPerGiB == nil { + var ptrVar1 int64 = 150 + in.Spec.LiveMigrationConfig.CompletionTimeoutPerGiB = &ptrVar1 + } + if in.Spec.LiveMigrationConfig.ProgressTimeout == nil { + var ptrVar1 int64 = 150 + in.Spec.LiveMigrationConfig.ProgressTimeout = &ptrVar1 + } + if in.Spec.LiveMigrationConfig.AllowAutoConverge == nil { + var ptrVar1 bool = false + in.Spec.LiveMigrationConfig.AllowAutoConverge = &ptrVar1 + } + if in.Spec.LiveMigrationConfig.AllowPostCopy == nil { + var ptrVar1 bool = false + in.Spec.LiveMigrationConfig.AllowPostCopy = &ptrVar1 + } + if in.Spec.CertConfig.CA.Duration == nil { + if err := json.Unmarshal([]byte(`"48h0m0s"`), &in.Spec.CertConfig.CA.Duration); err != nil { + panic(err) + } + } + if in.Spec.CertConfig.CA.RenewBefore == nil { + if err := json.Unmarshal([]byte(`"24h0m0s"`), &in.Spec.CertConfig.CA.RenewBefore); err != nil { + panic(err) + } + } + if in.Spec.CertConfig.Server.Duration == nil { + if err := json.Unmarshal([]byte(`"24h0m0s"`), &in.Spec.CertConfig.Server.Duration); err != nil { + panic(err) + } + } + if in.Spec.CertConfig.Server.RenewBefore == nil { + if err := json.Unmarshal([]byte(`"12h0m0s"`), &in.Spec.CertConfig.Server.RenewBefore); err != nil { + panic(err) + } + } + if in.Spec.ResourceRequirements != nil { + if in.Spec.ResourceRequirements.VmiCPUAllocationRatio == nil { + var ptrVar1 int = 10 + in.Spec.ResourceRequirements.VmiCPUAllocationRatio = &ptrVar1 + } + } + if in.Spec.WorkloadUpdateStrategy.WorkloadUpdateMethods == nil { + if err := json.Unmarshal([]byte(`["LiveMigrate"]`), &in.Spec.WorkloadUpdateStrategy.WorkloadUpdateMethods); err != nil { + panic(err) + } + } + if in.Spec.WorkloadUpdateStrategy.BatchEvictionSize == nil { + var ptrVar1 int = 10 + in.Spec.WorkloadUpdateStrategy.BatchEvictionSize = &ptrVar1 + } + if in.Spec.WorkloadUpdateStrategy.BatchEvictionInterval == nil { + if err := json.Unmarshal([]byte(`"1m0s"`), &in.Spec.WorkloadUpdateStrategy.BatchEvictionInterval); err != nil { + panic(err) + } + } + if in.Spec.UninstallStrategy == "" { + in.Spec.UninstallStrategy = "BlockUninstallIfWorkloadsExist" + } + if in.Spec.VirtualMachineOptions == nil { + if err := json.Unmarshal([]byte(`{"disableFreePageReporting": false, "disableSerialConsoleLog": false}`), &in.Spec.VirtualMachineOptions); err != nil { + panic(err) + } + } + if in.Spec.VirtualMachineOptions != nil { + if in.Spec.VirtualMachineOptions.DisableFreePageReporting == nil { + var ptrVar1 bool = false + in.Spec.VirtualMachineOptions.DisableFreePageReporting = &ptrVar1 + } + if in.Spec.VirtualMachineOptions.DisableSerialConsoleLog == nil { + var ptrVar1 bool = false + in.Spec.VirtualMachineOptions.DisableSerialConsoleLog = &ptrVar1 + } + } + if in.Spec.HigherWorkloadDensity == nil { + if err := json.Unmarshal([]byte(`{"memoryOvercommitPercentage": 100}`), &in.Spec.HigherWorkloadDensity); err != nil { + panic(err) + } + } + if in.Spec.HigherWorkloadDensity != nil { + if in.Spec.HigherWorkloadDensity.MemoryOvercommitPercentage == 0 { + in.Spec.HigherWorkloadDensity.MemoryOvercommitPercentage = 100 + } + } + if in.Spec.EnableCommonBootImageImport == nil { + var ptrVar1 bool = true + in.Spec.EnableCommonBootImageImport = &ptrVar1 + } + if in.Spec.DeployVMConsoleProxy == nil { + var ptrVar1 bool = false + in.Spec.DeployVMConsoleProxy = &ptrVar1 + } + if in.Spec.EnableApplicationAwareQuota == nil { + var ptrVar1 bool = false + in.Spec.EnableApplicationAwareQuota = &ptrVar1 + } +} + +func SetObjectDefaults_HyperConvergedList(in *HyperConvergedList) { + for i := range in.Items { + a := &in.Items[i] + SetObjectDefaults_HyperConverged(a) + } +} diff --git a/api/v1/zz_generated.openapi.go b/api/v1/zz_generated.openapi.go new file mode 100644 index 0000000000..9cf096f9a0 --- /dev/null +++ b/api/v1/zz_generated.openapi.go @@ -0,0 +1,1272 @@ +//go:build !ignore_autogenerated +// +build !ignore_autogenerated + +/* + * This file is part of the KubeVirt project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + * Copyright 2026 Red Hat, Inc. + * + */ + +// Code generated by openapi-gen. DO NOT EDIT. + +package v1 + +import ( + common "k8s.io/kube-openapi/pkg/common" + spec "k8s.io/kube-openapi/pkg/validation/spec" +) + +func GetOpenAPIDefinitions(ref common.ReferenceCallback) map[string]common.OpenAPIDefinition { + return map[string]common.OpenAPIDefinition{ + "github.com/kubevirt/hyperconverged-cluster-operator/api/v1.ApplicationAwareConfigurations": schema_kubevirt_hyperconverged_cluster_operator_api_v1_ApplicationAwareConfigurations(ref), + "github.com/kubevirt/hyperconverged-cluster-operator/api/v1.CertRotateConfigCA": schema_kubevirt_hyperconverged_cluster_operator_api_v1_CertRotateConfigCA(ref), + "github.com/kubevirt/hyperconverged-cluster-operator/api/v1.CertRotateConfigServer": schema_kubevirt_hyperconverged_cluster_operator_api_v1_CertRotateConfigServer(ref), + "github.com/kubevirt/hyperconverged-cluster-operator/api/v1.HyperConverged": schema_kubevirt_hyperconverged_cluster_operator_api_v1_HyperConverged(ref), + "github.com/kubevirt/hyperconverged-cluster-operator/api/v1.HyperConvergedCertConfig": schema_kubevirt_hyperconverged_cluster_operator_api_v1_HyperConvergedCertConfig(ref), + "github.com/kubevirt/hyperconverged-cluster-operator/api/v1.HyperConvergedObsoleteCPUs": schema_kubevirt_hyperconverged_cluster_operator_api_v1_HyperConvergedObsoleteCPUs(ref), + "github.com/kubevirt/hyperconverged-cluster-operator/api/v1.HyperConvergedSpec": schema_kubevirt_hyperconverged_cluster_operator_api_v1_HyperConvergedSpec(ref), + "github.com/kubevirt/hyperconverged-cluster-operator/api/v1.HyperConvergedStatus": schema_kubevirt_hyperconverged_cluster_operator_api_v1_HyperConvergedStatus(ref), + "github.com/kubevirt/hyperconverged-cluster-operator/api/v1.HyperConvergedWorkloadUpdateStrategy": schema_kubevirt_hyperconverged_cluster_operator_api_v1_HyperConvergedWorkloadUpdateStrategy(ref), + "github.com/kubevirt/hyperconverged-cluster-operator/api/v1.KubeMacPoolConfig": schema_kubevirt_hyperconverged_cluster_operator_api_v1_KubeMacPoolConfig(ref), + "github.com/kubevirt/hyperconverged-cluster-operator/api/v1.LiveMigrationConfigurations": schema_kubevirt_hyperconverged_cluster_operator_api_v1_LiveMigrationConfigurations(ref), + "github.com/kubevirt/hyperconverged-cluster-operator/api/v1.LogVerbosityConfiguration": schema_kubevirt_hyperconverged_cluster_operator_api_v1_LogVerbosityConfiguration(ref), + "github.com/kubevirt/hyperconverged-cluster-operator/api/v1.MediatedDevicesConfiguration": schema_kubevirt_hyperconverged_cluster_operator_api_v1_MediatedDevicesConfiguration(ref), + "github.com/kubevirt/hyperconverged-cluster-operator/api/v1.MediatedHostDevice": schema_kubevirt_hyperconverged_cluster_operator_api_v1_MediatedHostDevice(ref), + "github.com/kubevirt/hyperconverged-cluster-operator/api/v1.NodeMediatedDeviceTypesConfig": schema_kubevirt_hyperconverged_cluster_operator_api_v1_NodeMediatedDeviceTypesConfig(ref), + "github.com/kubevirt/hyperconverged-cluster-operator/api/v1.OperandResourceRequirements": schema_kubevirt_hyperconverged_cluster_operator_api_v1_OperandResourceRequirements(ref), + "github.com/kubevirt/hyperconverged-cluster-operator/api/v1.PciHostDevice": schema_kubevirt_hyperconverged_cluster_operator_api_v1_PciHostDevice(ref), + "github.com/kubevirt/hyperconverged-cluster-operator/api/v1.PermittedHostDevices": schema_kubevirt_hyperconverged_cluster_operator_api_v1_PermittedHostDevices(ref), + "github.com/kubevirt/hyperconverged-cluster-operator/api/v1.StorageImportConfig": schema_kubevirt_hyperconverged_cluster_operator_api_v1_StorageImportConfig(ref), + "github.com/kubevirt/hyperconverged-cluster-operator/api/v1.USBHostDevice": schema_kubevirt_hyperconverged_cluster_operator_api_v1_USBHostDevice(ref), + "github.com/kubevirt/hyperconverged-cluster-operator/api/v1.USBSelector": schema_kubevirt_hyperconverged_cluster_operator_api_v1_USBSelector(ref), + } +} + +func schema_kubevirt_hyperconverged_cluster_operator_api_v1_ApplicationAwareConfigurations(ref common.ReferenceCallback) common.OpenAPIDefinition { + return common.OpenAPIDefinition{ + Schema: spec.Schema{ + SchemaProps: spec.SchemaProps{ + Description: "ApplicationAwareConfigurations holds the AAQ configurations", + Type: []string{"object"}, + Properties: map[string]spec.Schema{ + "vmiCalcConfigName": { + SchemaProps: spec.SchemaProps{ + Description: "VmiCalcConfigName determine how resource allocation will be done with ApplicationsResourceQuota. allowed values are: VmiPodUsage, VirtualResources, DedicatedVirtualResources or IgnoreVmiCalculator", + Type: []string{"string"}, + Format: "", + }, + }, + "namespaceSelector": { + SchemaProps: spec.SchemaProps{ + Description: "NamespaceSelector determines in which namespaces scheduling gate will be added to pods..", + Ref: ref("k8s.io/apimachinery/pkg/apis/meta/v1.LabelSelector"), + }, + }, + "allowApplicationAwareClusterResourceQuota": { + SchemaProps: spec.SchemaProps{ + Description: "AllowApplicationAwareClusterResourceQuota if set to true, allows creation and management of ClusterAppsResourceQuota", + Type: []string{"boolean"}, + Format: "", + }, + }, + }, + }, + }, + Dependencies: []string{ + "k8s.io/apimachinery/pkg/apis/meta/v1.LabelSelector"}, + } +} + +func schema_kubevirt_hyperconverged_cluster_operator_api_v1_CertRotateConfigCA(ref common.ReferenceCallback) common.OpenAPIDefinition { + return common.OpenAPIDefinition{ + Schema: spec.Schema{ + SchemaProps: spec.SchemaProps{ + Description: "CertRotateConfigCA contains the tunables for TLS certificates.", + Type: []string{"object"}, + Properties: map[string]spec.Schema{ + "duration": { + SchemaProps: spec.SchemaProps{ + Description: "The requested 'duration' (i.e. lifetime) of the Certificate. This should comply with golang's ParseDuration format (https://golang.org/pkg/time/#ParseDuration)", + Default: "48h0m0s", + Ref: ref("k8s.io/apimachinery/pkg/apis/meta/v1.Duration"), + }, + }, + "renewBefore": { + SchemaProps: spec.SchemaProps{ + Description: "The amount of time before the currently issued certificate's `notAfter` time that we will begin to attempt to renew the certificate. This should comply with golang's ParseDuration format (https://golang.org/pkg/time/#ParseDuration)", + Default: "24h0m0s", + Ref: ref("k8s.io/apimachinery/pkg/apis/meta/v1.Duration"), + }, + }, + }, + }, + }, + Dependencies: []string{ + "k8s.io/apimachinery/pkg/apis/meta/v1.Duration"}, + } +} + +func schema_kubevirt_hyperconverged_cluster_operator_api_v1_CertRotateConfigServer(ref common.ReferenceCallback) common.OpenAPIDefinition { + return common.OpenAPIDefinition{ + Schema: spec.Schema{ + SchemaProps: spec.SchemaProps{ + Description: "CertRotateConfigServer contains the tunables for TLS certificates.", + Type: []string{"object"}, + Properties: map[string]spec.Schema{ + "duration": { + SchemaProps: spec.SchemaProps{ + Description: "The requested 'duration' (i.e. lifetime) of the Certificate. This should comply with golang's ParseDuration format (https://golang.org/pkg/time/#ParseDuration)", + Default: "24h0m0s", + Ref: ref("k8s.io/apimachinery/pkg/apis/meta/v1.Duration"), + }, + }, + "renewBefore": { + SchemaProps: spec.SchemaProps{ + Description: "The amount of time before the currently issued certificate's `notAfter` time that we will begin to attempt to renew the certificate. This should comply with golang's ParseDuration format (https://golang.org/pkg/time/#ParseDuration)", + Default: "12h0m0s", + Ref: ref("k8s.io/apimachinery/pkg/apis/meta/v1.Duration"), + }, + }, + }, + }, + }, + Dependencies: []string{ + "k8s.io/apimachinery/pkg/apis/meta/v1.Duration"}, + } +} + +func schema_kubevirt_hyperconverged_cluster_operator_api_v1_HyperConverged(ref common.ReferenceCallback) common.OpenAPIDefinition { + return common.OpenAPIDefinition{ + Schema: spec.Schema{ + SchemaProps: spec.SchemaProps{ + Description: "HyperConverged is the Schema for the hyperconvergeds API", + Type: []string{"object"}, + Properties: map[string]spec.Schema{ + "kind": { + SchemaProps: spec.SchemaProps{ + Description: "Kind is a string value representing the REST resource this object represents. Servers may infer this from the endpoint the client submits requests to. Cannot be updated. In CamelCase. More info: https://git.k8s.io/community/contributors/devel/sig-architecture/api-conventions.md#types-kinds", + Type: []string{"string"}, + Format: "", + }, + }, + "apiVersion": { + SchemaProps: spec.SchemaProps{ + Description: "APIVersion defines the versioned schema of this representation of an object. Servers should convert recognized schemas to the latest internal value, and may reject unrecognized values. More info: https://git.k8s.io/community/contributors/devel/sig-architecture/api-conventions.md#resources", + Type: []string{"string"}, + Format: "", + }, + }, + "metadata": { + SchemaProps: spec.SchemaProps{ + Default: map[string]interface{}{}, + Ref: ref("k8s.io/apimachinery/pkg/apis/meta/v1.ObjectMeta"), + }, + }, + "spec": { + SchemaProps: spec.SchemaProps{ + Default: map[string]interface{}{}, + Ref: ref("github.com/kubevirt/hyperconverged-cluster-operator/api/v1.HyperConvergedSpec"), + }, + }, + "status": { + SchemaProps: spec.SchemaProps{ + Default: map[string]interface{}{}, + Ref: ref("github.com/kubevirt/hyperconverged-cluster-operator/api/v1.HyperConvergedStatus"), + }, + }, + }, + }, + }, + Dependencies: []string{ + "github.com/kubevirt/hyperconverged-cluster-operator/api/v1.HyperConvergedSpec", "github.com/kubevirt/hyperconverged-cluster-operator/api/v1.HyperConvergedStatus", "k8s.io/apimachinery/pkg/apis/meta/v1.ObjectMeta"}, + } +} + +func schema_kubevirt_hyperconverged_cluster_operator_api_v1_HyperConvergedCertConfig(ref common.ReferenceCallback) common.OpenAPIDefinition { + return common.OpenAPIDefinition{ + Schema: spec.Schema{ + SchemaProps: spec.SchemaProps{ + Description: "HyperConvergedCertConfig holds the CertConfig entries for the HCO operands", + Type: []string{"object"}, + Properties: map[string]spec.Schema{ + "ca": { + SchemaProps: spec.SchemaProps{ + Description: "CA configuration - CA certs are kept in the CA bundle as long as they are valid", + Default: map[string]interface{}{}, + Ref: ref("github.com/kubevirt/hyperconverged-cluster-operator/api/v1.CertRotateConfigCA"), + }, + }, + "server": { + SchemaProps: spec.SchemaProps{ + Description: "Server configuration - Certs are rotated and discarded", + Default: map[string]interface{}{}, + Ref: ref("github.com/kubevirt/hyperconverged-cluster-operator/api/v1.CertRotateConfigServer"), + }, + }, + }, + }, + }, + Dependencies: []string{ + "github.com/kubevirt/hyperconverged-cluster-operator/api/v1.CertRotateConfigCA", "github.com/kubevirt/hyperconverged-cluster-operator/api/v1.CertRotateConfigServer"}, + } +} + +func schema_kubevirt_hyperconverged_cluster_operator_api_v1_HyperConvergedObsoleteCPUs(ref common.ReferenceCallback) common.OpenAPIDefinition { + return common.OpenAPIDefinition{ + Schema: spec.Schema{ + SchemaProps: spec.SchemaProps{ + Description: "HyperConvergedObsoleteCPUs allows avoiding scheduling of VMs for obsolete CPU models", + Type: []string{"object"}, + Properties: map[string]spec.Schema{ + "cpuModels": { + VendorExtensible: spec.VendorExtensible{ + Extensions: spec.Extensions{ + "x-kubernetes-list-type": "set", + }, + }, + SchemaProps: spec.SchemaProps{ + Description: "CPUModels is a list of obsolete CPU models. When the node-labeller obtains the list of obsolete CPU models, it eliminates those CPU models and creates labels for valid CPU models. The default values for this field is nil, however, HCO uses opinionated values, and adding values to this list will add them to the opinionated values.", + Type: []string{"array"}, + Items: &spec.SchemaOrArray{ + Schema: &spec.Schema{ + SchemaProps: spec.SchemaProps{ + Default: "", + Type: []string{"string"}, + Format: "", + }, + }, + }, + }, + }, + }, + }, + }, + } +} + +func schema_kubevirt_hyperconverged_cluster_operator_api_v1_HyperConvergedSpec(ref common.ReferenceCallback) common.OpenAPIDefinition { + return common.OpenAPIDefinition{ + Schema: spec.Schema{ + SchemaProps: spec.SchemaProps{ + Description: "HyperConvergedSpec defines the desired state of HyperConverged", + Type: []string{"object"}, + Properties: map[string]spec.Schema{ + "tuningPolicy": { + SchemaProps: spec.SchemaProps{ + Description: "TuningPolicy allows to configure the mode in which the RateLimits of kubevirt are set. If TuningPolicy is not present the default kubevirt values are used. It can be set to `annotation` for fine-tuning the kubevirt queryPerSeconds (qps) and burst values. Qps and burst values are taken from the annotation hco.kubevirt.io/tuningPolicy", + Type: []string{"string"}, + Format: "", + }, + }, + "infra": { + SchemaProps: spec.SchemaProps{ + Description: "infra HyperConvergedConfig influences the pod configuration (currently only placement) for all the infra components needed on the virtualization enabled cluster but not necessarily directly on each node running VMs/VMIs.", + Default: map[string]interface{}{}, + Ref: ref("github.com/kubevirt/hyperconverged-cluster-operator/api/v1.HyperConvergedConfig"), + }, + }, + "workloads": { + SchemaProps: spec.SchemaProps{ + Description: "workloads HyperConvergedConfig influences the pod configuration (currently only placement) of components which need to be running on a node where virtualization workloads should be able to run. Changes to Workloads HyperConvergedConfig can be applied only without existing workload.", + Default: map[string]interface{}{}, + Ref: ref("github.com/kubevirt/hyperconverged-cluster-operator/api/v1.HyperConvergedConfig"), + }, + }, + "featureGates": { + SchemaProps: spec.SchemaProps{ + Description: "FeatureGates is a set of optional feature gates to enable or disable new features that are not generally available yet. Add a new FeatureGate Object to this set, to enable a feature that is disabled by default, or to disable a feature that is enabled by default.\n\nA feature gate may be in the following phases: * Alpha: the feature is in dev-preview. It is disabled by default, but can\n be enabled.\n* Beta: the feature gate is in tech-preview. It is enabled by default, but\n can be disabled.\n* GA: the feature is graduated and is always enabled. There is no way to\n disable it.\n* Deprecated: the feature is no longer supported. There is no way to enable\n it\n\nFeature-Gate list: * alignCPUs:\n Enable KubeVirt to request up to two additional dedicated CPUs in order to\n complete the total CPU count to an even parity when using emulator thread\n isolation.\n Note: this feature is in Developer Preview.\n Phase: Alpha\n\n* decentralizedLiveMigration:\n enables the decentralized live migration (cross-cluster migration) feature.\n This feature allows live migration of VirtualMachineInstances between\n different clusters.\n Note: This feature is in Developer Preview.\n Phase: Alpha\n\n* declarativeHotplugVolumes:\n enables the use of the declarative volume hotplug feature in KubeVirt.\n When enabled, the \"DeclarativeHotplugVolumes\" feature gate is enabled in\n the KubeVirt CR, instead of the \"HotplugVolumes\" feature gate.\n When disabled, the \"HotplugVolumes\" feature gate is enabled (default\n behavior).\n Phase: Alpha\n\n* deployKubeSecondaryDNS:\n Deploy KubeSecondaryDNS by CNAO\n Phase: Alpha\n\n* disableMDevConfiguration:\n Disable mediated devices handling on KubeVirt\n Phase: Alpha\n\n* downwardMetrics:\n Allow to expose a limited set of host metrics to guests.\n Phase: Alpha\n\n* enableMultiArchBootImageImport:\n allows the HCO to run on heterogeneous clusters with different CPU\n architectures.\n Enabling this feature gate will allow the HCO to create Golden Images for\n different CPU architectures.\n Phase: Alpha\n\n* objectGraph:\n enables the ObjectGraph VM and VMI subresource in KubeVirt.\n This subresource returns a structured list of k8s objects that are related\n to the specified VM or VMI, enabling better dependency tracking.\n Phase: Alpha\n\n* persistentReservation:\n Enable persistent reservation of a LUN through the SCSI Persistent Reserve\n commands on Kubevirt.\n In order to issue privileged SCSI ioctls, the VM requires activation of the\n persistent reservation flag.\n Once this feature gate is enabled, then the additional container with the\n qemu-pr-helper is deployed inside the virt-handler pod.\n Enabling (or removing) the feature gate causes the redeployment of the\n virt-handler pod.\n Phase: Alpha\n\n* videoConfig:\n allows users to configure video device types for their virtual machines.\n This can be useful for workloads that require specific video capabilities\n or architectures.\n Phase: Beta\n\n* autoResourceLimits:\n Phase: Deprecated\n\n* deployKubevirtIpamController:\n Phase: Deprecated\n\n* deployTektonTaskResources:\n Phase: Deprecated\n\n* deployVmConsoleProxy:\n Phase: Deprecated\n\n* enableApplicationAwareQuota:\n This feature gate is ignored. Use spec.enableApplicationAwareQuota field instead\n Phase: Deprecated\n\n* enableCommonBootImageImport:\n This feature gate is ignored. Use spec.enableCommonBootImageImport field instead\n Phase: Deprecated\n\n* enableManagedTenantQuota:\n Phase: Deprecated\n\n* nonRoot:\n Phase: Deprecated\n\n* primaryUserDefinedNetworkBinding:\n Phase: Deprecated\n\n* withHostPassthroughCPU:\n Phase: Deprecated", + Type: []string{"array"}, + Items: &spec.SchemaOrArray{ + Schema: &spec.Schema{ + SchemaProps: spec.SchemaProps{ + Ref: ref("github.com/kubevirt/hyperconverged-cluster-operator/api/v1/featuregates.FeatureGate"), + }, + }, + }, + }, + }, + "liveMigrationConfig": { + SchemaProps: spec.SchemaProps{ + Description: "Live migration limits and timeouts are applied so that migration processes do not overwhelm the cluster.", + Default: map[string]interface{}{}, + Ref: ref("github.com/kubevirt/hyperconverged-cluster-operator/api/v1.LiveMigrationConfigurations"), + }, + }, + "permittedHostDevices": { + SchemaProps: spec.SchemaProps{ + Description: "PermittedHostDevices holds information about devices allowed for passthrough", + Ref: ref("github.com/kubevirt/hyperconverged-cluster-operator/api/v1.PermittedHostDevices"), + }, + }, + "mediatedDevicesConfiguration": { + SchemaProps: spec.SchemaProps{ + Description: "MediatedDevicesConfiguration holds information about MDEV types to be defined on nodes, if available", + Ref: ref("github.com/kubevirt/hyperconverged-cluster-operator/api/v1.MediatedDevicesConfiguration"), + }, + }, + "certConfig": { + SchemaProps: spec.SchemaProps{ + Description: "certConfig holds the rotation policy for internal, self-signed certificates", + Default: map[string]interface{}{}, + Ref: ref("github.com/kubevirt/hyperconverged-cluster-operator/api/v1.HyperConvergedCertConfig"), + }, + }, + "resourceRequirements": { + SchemaProps: spec.SchemaProps{ + Description: "ResourceRequirements describes the resource requirements for the operand workloads.", + Ref: ref("github.com/kubevirt/hyperconverged-cluster-operator/api/v1.OperandResourceRequirements"), + }, + }, + "scratchSpaceStorageClass": { + SchemaProps: spec.SchemaProps{ + Description: "Override the storage class used for scratch space during transfer operations. The scratch space storage class is determined in the following order: value of scratchSpaceStorageClass, if that doesn't exist, use the default storage class, if there is no default storage class, use the storage class of the DataVolume, if no storage class specified, use no storage class for scratch space", + Type: []string{"string"}, + Format: "", + }, + }, + "defaultCPUModel": { + SchemaProps: spec.SchemaProps{ + Description: "DefaultCPUModel defines a cluster default for CPU model: default CPU model is set when VMI doesn't have any CPU model. When VMI has CPU model set, then VMI's CPU model is preferred. When default CPU model is not set and VMI's CPU model is not set too, host-model will be set. Default CPU model can be changed when kubevirt is running.", + Type: []string{"string"}, + Format: "", + }, + }, + "defaultRuntimeClass": { + SchemaProps: spec.SchemaProps{ + Description: "DefaultRuntimeClass defines a cluster default for the RuntimeClass to be used for VMIs pods if not set there. Default RuntimeClass can be changed when kubevirt is running, existing VMIs are not impacted till the next restart/live-migration when they are eventually going to consume the new default RuntimeClass.", + Type: []string{"string"}, + Format: "", + }, + }, + "obsoleteCPUs": { + SchemaProps: spec.SchemaProps{ + Description: "ObsoleteCPUs allows avoiding scheduling of VMs for obsolete CPU models", + Ref: ref("github.com/kubevirt/hyperconverged-cluster-operator/api/v1.HyperConvergedObsoleteCPUs"), + }, + }, + "commonTemplatesNamespace": { + SchemaProps: spec.SchemaProps{ + Description: "CommonTemplatesNamespace defines namespace in which common templates will be deployed. It overrides the default openshift namespace.", + Type: []string{"string"}, + Format: "", + }, + }, + "storageImport": { + SchemaProps: spec.SchemaProps{ + Description: "StorageImport contains configuration for importing containerized data", + Ref: ref("github.com/kubevirt/hyperconverged-cluster-operator/api/v1.StorageImportConfig"), + }, + }, + "workloadUpdateStrategy": { + SchemaProps: spec.SchemaProps{ + Description: "WorkloadUpdateStrategy defines at the cluster level how to handle automated workload updates", + Default: map[string]interface{}{}, + Ref: ref("github.com/kubevirt/hyperconverged-cluster-operator/api/v1.HyperConvergedWorkloadUpdateStrategy"), + }, + }, + "dataImportCronTemplates": { + VendorExtensible: spec.VendorExtensible{ + Extensions: spec.Extensions{ + "x-kubernetes-list-type": "atomic", + }, + }, + SchemaProps: spec.SchemaProps{ + Description: "DataImportCronTemplates holds list of data import cron templates (golden images)", + Type: []string{"array"}, + Items: &spec.SchemaOrArray{ + Schema: &spec.Schema{ + SchemaProps: spec.SchemaProps{ + Default: map[string]interface{}{}, + Ref: ref("github.com/kubevirt/hyperconverged-cluster-operator/api/v1.DataImportCronTemplate"), + }, + }, + }, + }, + }, + "filesystemOverhead": { + SchemaProps: spec.SchemaProps{ + Description: "FilesystemOverhead describes the space reserved for overhead when using Filesystem volumes. A value is between 0 and 1, if not defined it is 0.055 (5.5 percent overhead)", + Ref: ref("kubevirt.io/containerized-data-importer-api/pkg/apis/core/v1beta1.FilesystemOverhead"), + }, + }, + "uninstallStrategy": { + SchemaProps: spec.SchemaProps{ + Description: "UninstallStrategy defines how to proceed on uninstall when workloads (VirtualMachines, DataVolumes) still exist. BlockUninstallIfWorkloadsExist will prevent the CR from being removed when workloads still exist. BlockUninstallIfWorkloadsExist is the safest choice to protect your workloads from accidental data loss, so it's strongly advised. RemoveWorkloads will cause all the workloads to be cascading deleted on uninstallation. WARNING: please notice that RemoveWorkloads will cause your workloads to be deleted as soon as this CR will be, even accidentally, deleted. Please correctly consider the implications of this option before setting it. BlockUninstallIfWorkloadsExist is the default behaviour.", + Default: "BlockUninstallIfWorkloadsExist", + Type: []string{"string"}, + Format: "", + }, + }, + "logVerbosityConfig": { + SchemaProps: spec.SchemaProps{ + Description: "LogVerbosityConfig configures the verbosity level of Kubevirt's different components. The higher the value - the higher the log verbosity.", + Ref: ref("github.com/kubevirt/hyperconverged-cluster-operator/api/v1.LogVerbosityConfiguration"), + }, + }, + "tlsSecurityProfile": { + SchemaProps: spec.SchemaProps{ + Description: "TLSSecurityProfile specifies the settings for TLS connections to be propagated to all kubevirt-hyperconverged components. If unset, the hyperconverged cluster operator will consume the value set on the APIServer CR on OCP/OKD or Intermediate if on vanilla k8s. Note that only Old, Intermediate and Custom profiles are currently supported, and the maximum available MinTLSVersions is VersionTLS12.", + Ref: ref("github.com/openshift/api/config/v1.TLSSecurityProfile"), + }, + }, + "kubeSecondaryDNSNameServerIP": { + SchemaProps: spec.SchemaProps{ + Description: "KubeSecondaryDNSNameServerIP defines name server IP used by KubeSecondaryDNS", + Type: []string{"string"}, + Format: "", + }, + }, + "kubeMacPoolConfiguration": { + SchemaProps: spec.SchemaProps{ + Description: "KubeMacPoolConfiguration holds kubemacpool MAC address range configuration.", + Ref: ref("github.com/kubevirt/hyperconverged-cluster-operator/api/v1.KubeMacPoolConfig"), + }, + }, + "evictionStrategy": { + SchemaProps: spec.SchemaProps{ + Description: "EvictionStrategy defines at the cluster level if the VirtualMachineInstance should be migrated instead of shut-off in case of a node drain. If the VirtualMachineInstance specific field is set it overrides the cluster level one. Allowed values: - `None` no eviction strategy at cluster level. - `LiveMigrate` migrate the VM on eviction; a not live migratable VM with no specific strategy will block the drain of the node util manually evicted. - `LiveMigrateIfPossible` migrate the VM on eviction if live migration is possible, otherwise directly evict. - `External` block the drain, track eviction and notify an external controller. Defaults to LiveMigrate with multiple worker nodes, None on single worker clusters.", + Type: []string{"string"}, + Format: "", + }, + }, + "vmStateStorageClass": { + SchemaProps: spec.SchemaProps{ + Description: "VMStateStorageClass is the name of the storage class to use for the PVCs created to preserve VM state, like TPM.", + Type: []string{"string"}, + Format: "", + }, + }, + "virtualMachineOptions": { + SchemaProps: spec.SchemaProps{ + Description: "VirtualMachineOptions holds the cluster level information regarding the virtual machine.", + Default: map[string]interface{}{"disableFreePageReporting": false, "disableSerialConsoleLog": false}, + Ref: ref("github.com/kubevirt/hyperconverged-cluster-operator/api/v1.VirtualMachineOptions"), + }, + }, + "commonBootImageNamespace": { + SchemaProps: spec.SchemaProps{ + Description: "CommonBootImageNamespace override the default namespace of the common boot images, in order to hide them.\n\nIf not set, HCO won't set any namespace, letting SSP to use the default. If set, use the namespace to create the DataImportCronTemplates and the common image streams, with this namespace. This field is not set by default.", + Type: []string{"string"}, + Format: "", + }, + }, + "ksmConfiguration": { + SchemaProps: spec.SchemaProps{ + Description: "KSMConfiguration holds the information regarding the enabling the KSM in the nodes (if available).", + Ref: ref("kubevirt.io/api/core/v1.KSMConfiguration"), + }, + }, + "networkBinding": { + SchemaProps: spec.SchemaProps{ + Description: "NetworkBinding defines the network binding plugins. Those bindings can be used when defining virtual machine interfaces.", + Type: []string{"object"}, + AdditionalProperties: &spec.SchemaOrBool{ + Allows: true, + Schema: &spec.Schema{ + SchemaProps: spec.SchemaProps{ + Default: map[string]interface{}{}, + Ref: ref("kubevirt.io/api/core/v1.InterfaceBindingPlugin"), + }, + }, + }, + }, + }, + "applicationAwareConfig": { + SchemaProps: spec.SchemaProps{ + Description: "ApplicationAwareConfig set the AAQ configurations", + Ref: ref("github.com/kubevirt/hyperconverged-cluster-operator/api/v1.ApplicationAwareConfigurations"), + }, + }, + "higherWorkloadDensity": { + SchemaProps: spec.SchemaProps{ + Description: "HigherWorkloadDensity holds configuration aimed to increase virtual machine density", + Default: map[string]interface{}{"memoryOvercommitPercentage": 100}, + Ref: ref("github.com/kubevirt/hyperconverged-cluster-operator/api/v1.HigherWorkloadDensityConfiguration"), + }, + }, + "enableCommonBootImageImport": { + SchemaProps: spec.SchemaProps{ + Description: "Opt-in to automatic delivery/updates of the common data import cron templates. There are two sources for the data import cron templates: hard coded list of common templates, and custom (user defined) templates that can be added to the dataImportCronTemplates field. This field only controls the common templates. It is possible to use custom templates by adding them to the dataImportCronTemplates field.", + Default: true, + Type: []string{"boolean"}, + Format: "", + }, + }, + "instancetypeConfig": { + SchemaProps: spec.SchemaProps{ + Description: "InstancetypeConfig holds the configuration of instance type related functionality within KubeVirt.", + Ref: ref("kubevirt.io/api/core/v1.InstancetypeConfiguration"), + }, + }, + "CommonInstancetypesDeployment": { + SchemaProps: spec.SchemaProps{ + Description: "CommonInstancetypesDeployment holds the configuration of common-instancetypes deployment within KubeVirt.", + Ref: ref("kubevirt.io/api/core/v1.CommonInstancetypesDeployment"), + }, + }, + "deployVmConsoleProxy": { + SchemaProps: spec.SchemaProps{ + Description: "deploy VM console proxy resources in SSP operator", + Default: false, + Type: []string{"boolean"}, + Format: "", + }, + }, + "enableApplicationAwareQuota": { + SchemaProps: spec.SchemaProps{ + Description: "EnableApplicationAwareQuota if true, enables the Application Aware Quota feature", + Default: false, + Type: []string{"boolean"}, + Format: "", + }, + }, + "liveUpdateConfiguration": { + SchemaProps: spec.SchemaProps{ + Description: "LiveUpdateConfiguration holds the cluster configuration for live update of virtual machines - max cpu sockets, max guest memory and max hotplug ratio. This setting can affect VM CPU and memory settings.", + Ref: ref("kubevirt.io/api/core/v1.LiveUpdateConfiguration"), + }, + }, + }, + }, + }, + Dependencies: []string{ + "github.com/kubevirt/hyperconverged-cluster-operator/api/v1.ApplicationAwareConfigurations", "github.com/kubevirt/hyperconverged-cluster-operator/api/v1.DataImportCronTemplate", "github.com/kubevirt/hyperconverged-cluster-operator/api/v1.HigherWorkloadDensityConfiguration", "github.com/kubevirt/hyperconverged-cluster-operator/api/v1.HyperConvergedCertConfig", "github.com/kubevirt/hyperconverged-cluster-operator/api/v1.HyperConvergedConfig", "github.com/kubevirt/hyperconverged-cluster-operator/api/v1.HyperConvergedObsoleteCPUs", "github.com/kubevirt/hyperconverged-cluster-operator/api/v1.HyperConvergedWorkloadUpdateStrategy", "github.com/kubevirt/hyperconverged-cluster-operator/api/v1.KubeMacPoolConfig", "github.com/kubevirt/hyperconverged-cluster-operator/api/v1.LiveMigrationConfigurations", "github.com/kubevirt/hyperconverged-cluster-operator/api/v1.LogVerbosityConfiguration", "github.com/kubevirt/hyperconverged-cluster-operator/api/v1.MediatedDevicesConfiguration", "github.com/kubevirt/hyperconverged-cluster-operator/api/v1.OperandResourceRequirements", "github.com/kubevirt/hyperconverged-cluster-operator/api/v1.PermittedHostDevices", "github.com/kubevirt/hyperconverged-cluster-operator/api/v1.StorageImportConfig", "github.com/kubevirt/hyperconverged-cluster-operator/api/v1.VirtualMachineOptions", "github.com/kubevirt/hyperconverged-cluster-operator/api/v1/featuregates.FeatureGate", "github.com/openshift/api/config/v1.TLSSecurityProfile", "kubevirt.io/api/core/v1.CommonInstancetypesDeployment", "kubevirt.io/api/core/v1.InstancetypeConfiguration", "kubevirt.io/api/core/v1.InterfaceBindingPlugin", "kubevirt.io/api/core/v1.KSMConfiguration", "kubevirt.io/api/core/v1.LiveUpdateConfiguration", "kubevirt.io/containerized-data-importer-api/pkg/apis/core/v1beta1.FilesystemOverhead"}, + } +} + +func schema_kubevirt_hyperconverged_cluster_operator_api_v1_HyperConvergedStatus(ref common.ReferenceCallback) common.OpenAPIDefinition { + return common.OpenAPIDefinition{ + Schema: spec.Schema{ + SchemaProps: spec.SchemaProps{ + Description: "HyperConvergedStatus defines the observed state of HyperConverged", + Type: []string{"object"}, + Properties: map[string]spec.Schema{ + "conditions": { + VendorExtensible: spec.VendorExtensible{ + Extensions: spec.Extensions{ + "x-kubernetes-list-type": "atomic", + "x-kubernetes-patch-merge-key": "type", + "x-kubernetes-patch-strategy": "merge", + }, + }, + SchemaProps: spec.SchemaProps{ + Description: "Conditions describes the state of the HyperConverged resource.", + Type: []string{"array"}, + Items: &spec.SchemaOrArray{ + Schema: &spec.Schema{ + SchemaProps: spec.SchemaProps{ + Default: map[string]interface{}{}, + Ref: ref("k8s.io/apimachinery/pkg/apis/meta/v1.Condition"), + }, + }, + }, + }, + }, + "relatedObjects": { + VendorExtensible: spec.VendorExtensible{ + Extensions: spec.Extensions{ + "x-kubernetes-list-type": "atomic", + }, + }, + SchemaProps: spec.SchemaProps{ + Description: "RelatedObjects is a list of objects created and maintained by this operator. Object references will be added to this list after they have been created AND found in the cluster.", + Type: []string{"array"}, + Items: &spec.SchemaOrArray{ + Schema: &spec.Schema{ + SchemaProps: spec.SchemaProps{ + Default: map[string]interface{}{}, + Ref: ref("k8s.io/api/core/v1.ObjectReference"), + }, + }, + }, + }, + }, + "versions": { + VendorExtensible: spec.VendorExtensible{ + Extensions: spec.Extensions{ + "x-kubernetes-list-type": "atomic", + }, + }, + SchemaProps: spec.SchemaProps{ + Description: "Versions is a list of HCO component versions, as name/version pairs. The version with a name of \"operator\" is the HCO version itself, as described here: https://github.com/openshift/cluster-version-operator/blob/master/docs/dev/clusteroperator.md#version", + Type: []string{"array"}, + Items: &spec.SchemaOrArray{ + Schema: &spec.Schema{ + SchemaProps: spec.SchemaProps{ + Default: map[string]interface{}{}, + Ref: ref("github.com/kubevirt/hyperconverged-cluster-operator/api/v1.Version"), + }, + }, + }, + }, + }, + "observedGeneration": { + SchemaProps: spec.SchemaProps{ + Description: "ObservedGeneration reflects the HyperConverged resource generation. If the ObservedGeneration is less than the resource generation in metadata, the status is out of date", + Type: []string{"integer"}, + Format: "int64", + }, + }, + "dataImportSchedule": { + SchemaProps: spec.SchemaProps{ + Description: "DataImportSchedule is the cron expression that is used in for the hard-coded data import cron templates. HCO generates the value of this field once and stored in the status field, so will survive restart.", + Type: []string{"string"}, + Format: "", + }, + }, + "dataImportCronTemplates": { + SchemaProps: spec.SchemaProps{ + Description: "DataImportCronTemplates is a list of the actual DataImportCronTemplates as HCO update in the SSP CR. The list contains both the common and the custom templates, including any modification done by HCO.", + Type: []string{"array"}, + Items: &spec.SchemaOrArray{ + Schema: &spec.Schema{ + SchemaProps: spec.SchemaProps{ + Default: map[string]interface{}{}, + Ref: ref("github.com/kubevirt/hyperconverged-cluster-operator/api/v1.DataImportCronTemplateStatus"), + }, + }, + }, + }, + }, + "systemHealthStatus": { + SchemaProps: spec.SchemaProps{ + Description: "SystemHealthStatus reflects the health of HCO and its secondary resources, based on the aggregated conditions.", + Type: []string{"string"}, + Format: "", + }, + }, + "infrastructureHighlyAvailable": { + SchemaProps: spec.SchemaProps{ + Description: "InfrastructureHighlyAvailable describes whether the cluster has only one worker node (false) or more (true).", + Type: []string{"boolean"}, + Format: "", + }, + }, + "nodeInfo": { + SchemaProps: spec.SchemaProps{ + Description: "NodeInfo holds information about the cluster nodes", + Default: map[string]interface{}{}, + Ref: ref("github.com/kubevirt/hyperconverged-cluster-operator/api/v1.NodeInfoStatus"), + }, + }, + }, + }, + }, + Dependencies: []string{ + "github.com/kubevirt/hyperconverged-cluster-operator/api/v1.DataImportCronTemplateStatus", "github.com/kubevirt/hyperconverged-cluster-operator/api/v1.NodeInfoStatus", "github.com/kubevirt/hyperconverged-cluster-operator/api/v1.Version", "k8s.io/api/core/v1.ObjectReference", "k8s.io/apimachinery/pkg/apis/meta/v1.Condition"}, + } +} + +func schema_kubevirt_hyperconverged_cluster_operator_api_v1_HyperConvergedWorkloadUpdateStrategy(ref common.ReferenceCallback) common.OpenAPIDefinition { + return common.OpenAPIDefinition{ + Schema: spec.Schema{ + SchemaProps: spec.SchemaProps{ + Description: "HyperConvergedWorkloadUpdateStrategy defines options related to updating a KubeVirt install", + Type: []string{"object"}, + Properties: map[string]spec.Schema{ + "workloadUpdateMethods": { + VendorExtensible: spec.VendorExtensible{ + Extensions: spec.Extensions{ + "x-kubernetes-list-type": "atomic", + }, + }, + SchemaProps: spec.SchemaProps{ + Description: "WorkloadUpdateMethods defines the methods that can be used to disrupt workloads during automated workload updates. When multiple methods are present, the least disruptive method takes precedence over more disruptive methods. For example if both LiveMigrate and Evict methods are listed, only VMs which are not live migratable will be restarted/shutdown. An empty list defaults to no automated workload updating.", + Default: []interface{}{"LiveMigrate"}, + Type: []string{"array"}, + Items: &spec.SchemaOrArray{ + Schema: &spec.Schema{ + SchemaProps: spec.SchemaProps{ + Default: "", + Type: []string{"string"}, + Format: "", + }, + }, + }, + }, + }, + "batchEvictionSize": { + SchemaProps: spec.SchemaProps{ + Description: "BatchEvictionSize Represents the number of VMIs that can be forced updated per the BatchShutdownInterval interval", + Default: 10, + Type: []string{"integer"}, + Format: "int32", + }, + }, + "batchEvictionInterval": { + SchemaProps: spec.SchemaProps{ + Description: "BatchEvictionInterval Represents the interval to wait before issuing the next batch of shutdowns", + Default: "1m0s", + Ref: ref("k8s.io/apimachinery/pkg/apis/meta/v1.Duration"), + }, + }, + }, + Required: []string{"workloadUpdateMethods"}, + }, + }, + Dependencies: []string{ + "k8s.io/apimachinery/pkg/apis/meta/v1.Duration"}, + } +} + +func schema_kubevirt_hyperconverged_cluster_operator_api_v1_KubeMacPoolConfig(ref common.ReferenceCallback) common.OpenAPIDefinition { + return common.OpenAPIDefinition{ + Schema: spec.Schema{ + SchemaProps: spec.SchemaProps{ + Description: "KubeMacPoolConfig defines kubemacpool MAC address range configuration", + Type: []string{"object"}, + Properties: map[string]spec.Schema{ + "rangeStart": { + SchemaProps: spec.SchemaProps{ + Description: "RangeStart defines the first MAC address in the kubemacpool range. The MAC address format should be AA:BB:CC:DD:EE:FF.", + Type: []string{"string"}, + Format: "", + }, + }, + "rangeEnd": { + SchemaProps: spec.SchemaProps{ + Description: "RangeEnd defines the last MAC address in the kubemacpool range. The MAC address format should be AA:BB:CC:DD:EE:FF.", + Type: []string{"string"}, + Format: "", + }, + }, + }, + }, + }, + } +} + +func schema_kubevirt_hyperconverged_cluster_operator_api_v1_LiveMigrationConfigurations(ref common.ReferenceCallback) common.OpenAPIDefinition { + return common.OpenAPIDefinition{ + Schema: spec.Schema{ + SchemaProps: spec.SchemaProps{ + Description: "LiveMigrationConfigurations - Live migration limits and timeouts are applied so that migration processes do not overwhelm the cluster.", + Type: []string{"object"}, + Properties: map[string]spec.Schema{ + "parallelMigrationsPerCluster": { + SchemaProps: spec.SchemaProps{ + Description: "Number of migrations running in parallel in the cluster.", + Default: 5, + Type: []string{"integer"}, + Format: "int64", + }, + }, + "parallelOutboundMigrationsPerNode": { + SchemaProps: spec.SchemaProps{ + Description: "Maximum number of outbound migrations per node.", + Default: 2, + Type: []string{"integer"}, + Format: "int64", + }, + }, + "bandwidthPerMigration": { + SchemaProps: spec.SchemaProps{ + Description: "Bandwidth limit of each migration, the value is quantity of bytes per second (e.g. 2048Mi = 2048MiB/sec)", + Type: []string{"string"}, + Format: "", + }, + }, + "completionTimeoutPerGiB": { + SchemaProps: spec.SchemaProps{ + Description: "If a migrating VM is big and busy, while the connection to the destination node is slow, migration may never converge. The completion timeout is calculated based on completionTimeoutPerGiB times the size of the guest (both RAM and migrated disks, if any). For example, with completionTimeoutPerGiB set to 800, a virtual machine instance with 6GiB memory will timeout if it has not completed migration in 1h20m. Use a lower completionTimeoutPerGiB to induce quicker failure, so that another destination or post-copy is attempted. Use a higher completionTimeoutPerGiB to let workload with spikes in its memory dirty rate to converge. The format is a number.", + Default: 150, + Type: []string{"integer"}, + Format: "int64", + }, + }, + "progressTimeout": { + SchemaProps: spec.SchemaProps{ + Description: "The migration will be canceled if memory copy fails to make progress in this time, in seconds.", + Default: 150, + Type: []string{"integer"}, + Format: "int64", + }, + }, + "network": { + SchemaProps: spec.SchemaProps{ + Description: "The migrations will be performed over a dedicated multus network to minimize disruption to tenant workloads due to network saturation when VM live migrations are triggered.", + Type: []string{"string"}, + Format: "", + }, + }, + "allowAutoConverge": { + SchemaProps: spec.SchemaProps{ + Description: "AllowAutoConverge allows the platform to compromise performance/availability of VMIs to guarantee successful VMI live migrations. Defaults to false", + Default: false, + Type: []string{"boolean"}, + Format: "", + }, + }, + "allowPostCopy": { + SchemaProps: spec.SchemaProps{ + Description: "When enabled, KubeVirt attempts to use post-copy live-migration in case it reaches its completion timeout while attempting pre-copy live-migration. Post-copy migrations allow even the busiest VMs to successfully live-migrate. However, events like a network failure or a failure in any of the source or destination nodes can cause the migrated VM to crash or reach inconsistency. Enable this option when evicting nodes is more important than keeping VMs alive. Defaults to false.", + Default: false, + Type: []string{"boolean"}, + Format: "", + }, + }, + }, + }, + }, + } +} + +func schema_kubevirt_hyperconverged_cluster_operator_api_v1_LogVerbosityConfiguration(ref common.ReferenceCallback) common.OpenAPIDefinition { + return common.OpenAPIDefinition{ + Schema: spec.Schema{ + SchemaProps: spec.SchemaProps{ + Description: "LogVerbosityConfiguration configures log verbosity for different components", + Type: []string{"object"}, + Properties: map[string]spec.Schema{ + "kubevirt": { + SchemaProps: spec.SchemaProps{ + Description: "Kubevirt is a struct that allows specifying the log verbosity level that controls the amount of information logged for each Kubevirt component.", + Ref: ref("kubevirt.io/api/core/v1.LogVerbosity"), + }, + }, + "cdi": { + SchemaProps: spec.SchemaProps{ + Description: "CDI indicates the log verbosity level that controls the amount of information logged for CDI components.", + Type: []string{"integer"}, + Format: "int32", + }, + }, + }, + }, + }, + Dependencies: []string{ + "kubevirt.io/api/core/v1.LogVerbosity"}, + } +} + +func schema_kubevirt_hyperconverged_cluster_operator_api_v1_MediatedDevicesConfiguration(ref common.ReferenceCallback) common.OpenAPIDefinition { + return common.OpenAPIDefinition{ + Schema: spec.Schema{ + SchemaProps: spec.SchemaProps{ + Description: "MediatedDevicesConfiguration holds information about MDEV types to be defined, if available", + Type: []string{"object"}, + Properties: map[string]spec.Schema{ + "mediatedDeviceTypes": { + VendorExtensible: spec.VendorExtensible{ + Extensions: spec.Extensions{ + "x-kubernetes-list-type": "atomic", + }, + }, + SchemaProps: spec.SchemaProps{ + Type: []string{"array"}, + Items: &spec.SchemaOrArray{ + Schema: &spec.Schema{ + SchemaProps: spec.SchemaProps{ + Default: "", + Type: []string{"string"}, + Format: "", + }, + }, + }, + }, + }, + "nodeMediatedDeviceTypes": { + VendorExtensible: spec.VendorExtensible{ + Extensions: spec.Extensions{ + "x-kubernetes-list-type": "atomic", + }, + }, + SchemaProps: spec.SchemaProps{ + Type: []string{"array"}, + Items: &spec.SchemaOrArray{ + Schema: &spec.Schema{ + SchemaProps: spec.SchemaProps{ + Default: map[string]interface{}{}, + Ref: ref("github.com/kubevirt/hyperconverged-cluster-operator/api/v1.NodeMediatedDeviceTypesConfig"), + }, + }, + }, + }, + }, + }, + }, + }, + Dependencies: []string{ + "github.com/kubevirt/hyperconverged-cluster-operator/api/v1.NodeMediatedDeviceTypesConfig"}, + } +} + +func schema_kubevirt_hyperconverged_cluster_operator_api_v1_MediatedHostDevice(ref common.ReferenceCallback) common.OpenAPIDefinition { + return common.OpenAPIDefinition{ + Schema: spec.Schema{ + SchemaProps: spec.SchemaProps{ + Description: "MediatedHostDevice represents a host mediated device allowed for passthrough", + Type: []string{"object"}, + Properties: map[string]spec.Schema{ + "mdevNameSelector": { + SchemaProps: spec.SchemaProps{ + Description: "name of a mediated device type required to identify a mediated device on a host", + Default: "", + Type: []string{"string"}, + Format: "", + }, + }, + "resourceName": { + SchemaProps: spec.SchemaProps{ + Description: "name by which a device is advertised and being requested", + Default: "", + Type: []string{"string"}, + Format: "", + }, + }, + "externalResourceProvider": { + SchemaProps: spec.SchemaProps{ + Description: "indicates that this resource is being provided by an external device plugin", + Type: []string{"boolean"}, + Format: "", + }, + }, + "disabled": { + SchemaProps: spec.SchemaProps{ + Description: "HCO enforces the existence of several MediatedHostDevice objects. Set disabled field to true instead of remove these objects.", + Type: []string{"boolean"}, + Format: "", + }, + }, + }, + Required: []string{"mdevNameSelector", "resourceName"}, + }, + }, + } +} + +func schema_kubevirt_hyperconverged_cluster_operator_api_v1_NodeMediatedDeviceTypesConfig(ref common.ReferenceCallback) common.OpenAPIDefinition { + return common.OpenAPIDefinition{ + Schema: spec.Schema{ + SchemaProps: spec.SchemaProps{ + Description: "NodeMediatedDeviceTypesConfig holds information about MDEV types to be defined in a specific node that matches the NodeSelector field.", + Type: []string{"object"}, + Properties: map[string]spec.Schema{ + "nodeSelector": { + SchemaProps: spec.SchemaProps{ + Description: "NodeSelector is a selector which must be true for the vmi to fit on a node. Selector which must match a node's labels for the vmi to be scheduled on that node. More info: https://kubernetes.io/docs/concepts/configuration/assign-pod-node/", + Type: []string{"object"}, + AdditionalProperties: &spec.SchemaOrBool{ + Allows: true, + Schema: &spec.Schema{ + SchemaProps: spec.SchemaProps{ + Default: "", + Type: []string{"string"}, + Format: "", + }, + }, + }, + }, + }, + "mediatedDeviceTypes": { + VendorExtensible: spec.VendorExtensible{ + Extensions: spec.Extensions{ + "x-kubernetes-list-type": "atomic", + }, + }, + SchemaProps: spec.SchemaProps{ + Type: []string{"array"}, + Items: &spec.SchemaOrArray{ + Schema: &spec.Schema{ + SchemaProps: spec.SchemaProps{ + Default: "", + Type: []string{"string"}, + Format: "", + }, + }, + }, + }, + }, + }, + Required: []string{"nodeSelector"}, + }, + }, + } +} + +func schema_kubevirt_hyperconverged_cluster_operator_api_v1_OperandResourceRequirements(ref common.ReferenceCallback) common.OpenAPIDefinition { + return common.OpenAPIDefinition{ + Schema: spec.Schema{ + SchemaProps: spec.SchemaProps{ + Description: "OperandResourceRequirements is a list of resource requirements for the operand workloads pods", + Type: []string{"object"}, + Properties: map[string]spec.Schema{ + "storageWorkloads": { + SchemaProps: spec.SchemaProps{ + Description: "StorageWorkloads defines the resources requirements for storage workloads. It will propagate to the CDI custom resource", + Ref: ref("k8s.io/api/core/v1.ResourceRequirements"), + }, + }, + "vmiCPUAllocationRatio": { + SchemaProps: spec.SchemaProps{ + Description: "VmiCPUAllocationRatio defines, for each requested virtual CPU, how much physical CPU to request per VMI from the hosting node. The value is in fraction of a CPU thread (or core on non-hyperthreaded nodes). VMI POD CPU request = number of vCPUs * 1/vmiCPUAllocationRatio For example, a value of 1 means 1 physical CPU thread per VMI CPU thread. A value of 100 would be 1% of a physical thread allocated for each requested VMI thread. This option has no effect on VMIs that request dedicated CPUs. Defaults to 10", + Default: 10, + Type: []string{"integer"}, + Format: "int32", + }, + }, + "autoCPULimitNamespaceLabelSelector": { + SchemaProps: spec.SchemaProps{ + Description: "When set, AutoCPULimitNamespaceLabelSelector will set a CPU limit on virt-launcher for VMIs running inside namespaces that match the label selector. The CPU limit will equal the number of requested vCPUs. This setting does not apply to VMIs with dedicated CPUs.", + Ref: ref("k8s.io/apimachinery/pkg/apis/meta/v1.LabelSelector"), + }, + }, + }, + }, + }, + Dependencies: []string{ + "k8s.io/api/core/v1.ResourceRequirements", "k8s.io/apimachinery/pkg/apis/meta/v1.LabelSelector"}, + } +} + +func schema_kubevirt_hyperconverged_cluster_operator_api_v1_PciHostDevice(ref common.ReferenceCallback) common.OpenAPIDefinition { + return common.OpenAPIDefinition{ + Schema: spec.Schema{ + SchemaProps: spec.SchemaProps{ + Description: "PciHostDevice represents a host PCI device allowed for passthrough", + Type: []string{"object"}, + Properties: map[string]spec.Schema{ + "pciDeviceSelector": { + SchemaProps: spec.SchemaProps{ + Description: "a combination of a vendor_id:product_id required to identify a PCI device on a host.", + Default: "", + Type: []string{"string"}, + Format: "", + }, + }, + "resourceName": { + SchemaProps: spec.SchemaProps{ + Description: "name by which a device is advertised and being requested", + Default: "", + Type: []string{"string"}, + Format: "", + }, + }, + "externalResourceProvider": { + SchemaProps: spec.SchemaProps{ + Description: "indicates that this resource is being provided by an external device plugin", + Type: []string{"boolean"}, + Format: "", + }, + }, + "disabled": { + SchemaProps: spec.SchemaProps{ + Description: "HCO enforces the existence of several PciHostDevice objects. Set disabled field to true instead of remove these objects.", + Type: []string{"boolean"}, + Format: "", + }, + }, + }, + Required: []string{"pciDeviceSelector", "resourceName"}, + }, + }, + } +} + +func schema_kubevirt_hyperconverged_cluster_operator_api_v1_PermittedHostDevices(ref common.ReferenceCallback) common.OpenAPIDefinition { + return common.OpenAPIDefinition{ + Schema: spec.Schema{ + SchemaProps: spec.SchemaProps{ + Description: "PermittedHostDevices holds information about devices allowed for passthrough", + Type: []string{"object"}, + Properties: map[string]spec.Schema{ + "pciHostDevices": { + VendorExtensible: spec.VendorExtensible{ + Extensions: spec.Extensions{ + "x-kubernetes-list-map-keys": []interface{}{ + "pciDeviceSelector", + }, + "x-kubernetes-list-type": "map", + }, + }, + SchemaProps: spec.SchemaProps{ + Type: []string{"array"}, + Items: &spec.SchemaOrArray{ + Schema: &spec.Schema{ + SchemaProps: spec.SchemaProps{ + Default: map[string]interface{}{}, + Ref: ref("github.com/kubevirt/hyperconverged-cluster-operator/api/v1.PciHostDevice"), + }, + }, + }, + }, + }, + "usbHostDevices": { + VendorExtensible: spec.VendorExtensible{ + Extensions: spec.Extensions{ + "x-kubernetes-list-map-keys": []interface{}{ + "resourceName", + }, + "x-kubernetes-list-type": "map", + }, + }, + SchemaProps: spec.SchemaProps{ + Type: []string{"array"}, + Items: &spec.SchemaOrArray{ + Schema: &spec.Schema{ + SchemaProps: spec.SchemaProps{ + Default: map[string]interface{}{}, + Ref: ref("github.com/kubevirt/hyperconverged-cluster-operator/api/v1.USBHostDevice"), + }, + }, + }, + }, + }, + "mediatedDevices": { + VendorExtensible: spec.VendorExtensible{ + Extensions: spec.Extensions{ + "x-kubernetes-list-map-keys": []interface{}{ + "mdevNameSelector", + }, + "x-kubernetes-list-type": "map", + }, + }, + SchemaProps: spec.SchemaProps{ + Type: []string{"array"}, + Items: &spec.SchemaOrArray{ + Schema: &spec.Schema{ + SchemaProps: spec.SchemaProps{ + Default: map[string]interface{}{}, + Ref: ref("github.com/kubevirt/hyperconverged-cluster-operator/api/v1.MediatedHostDevice"), + }, + }, + }, + }, + }, + }, + }, + }, + Dependencies: []string{ + "github.com/kubevirt/hyperconverged-cluster-operator/api/v1.MediatedHostDevice", "github.com/kubevirt/hyperconverged-cluster-operator/api/v1.PciHostDevice", "github.com/kubevirt/hyperconverged-cluster-operator/api/v1.USBHostDevice"}, + } +} + +func schema_kubevirt_hyperconverged_cluster_operator_api_v1_StorageImportConfig(ref common.ReferenceCallback) common.OpenAPIDefinition { + return common.OpenAPIDefinition{ + Schema: spec.Schema{ + SchemaProps: spec.SchemaProps{ + Description: "StorageImportConfig contains configuration for importing containerized data", + Type: []string{"object"}, + Properties: map[string]spec.Schema{ + "insecureRegistries": { + VendorExtensible: spec.VendorExtensible{ + Extensions: spec.Extensions{ + "x-kubernetes-list-type": "set", + }, + }, + SchemaProps: spec.SchemaProps{ + Description: "InsecureRegistries is a list of image registries URLs that are not secured. Setting an insecure registry URL in this list allows pulling images from this registry.", + Type: []string{"array"}, + Items: &spec.SchemaOrArray{ + Schema: &spec.Schema{ + SchemaProps: spec.SchemaProps{ + Default: "", + Type: []string{"string"}, + Format: "", + }, + }, + }, + }, + }, + }, + }, + }, + } +} + +func schema_kubevirt_hyperconverged_cluster_operator_api_v1_USBHostDevice(ref common.ReferenceCallback) common.OpenAPIDefinition { + return common.OpenAPIDefinition{ + Schema: spec.Schema{ + SchemaProps: spec.SchemaProps{ + Description: "USBHostDevice represents a host USB device allowed for passthrough", + Type: []string{"object"}, + Properties: map[string]spec.Schema{ + "resourceName": { + SchemaProps: spec.SchemaProps{ + Description: "Identifies the list of USB host devices. e.g: kubevirt.io/storage, kubevirt.io/bootable-usb, etc", + Default: "", + Type: []string{"string"}, + Format: "", + }, + }, + "selectors": { + VendorExtensible: spec.VendorExtensible{ + Extensions: spec.Extensions{ + "x-kubernetes-list-type": "atomic", + }, + }, + SchemaProps: spec.SchemaProps{ + Type: []string{"array"}, + Items: &spec.SchemaOrArray{ + Schema: &spec.Schema{ + SchemaProps: spec.SchemaProps{ + Default: map[string]interface{}{}, + Ref: ref("github.com/kubevirt/hyperconverged-cluster-operator/api/v1.USBSelector"), + }, + }, + }, + }, + }, + "externalResourceProvider": { + SchemaProps: spec.SchemaProps{ + Description: "If true, KubeVirt will leave the allocation and monitoring to an external device plugin", + Type: []string{"boolean"}, + Format: "", + }, + }, + "disabled": { + SchemaProps: spec.SchemaProps{ + Description: "HCO enforces the existence of several USBHostDevice objects. Set disabled field to true instead of remove these objects.", + Type: []string{"boolean"}, + Format: "", + }, + }, + }, + Required: []string{"resourceName"}, + }, + }, + Dependencies: []string{ + "github.com/kubevirt/hyperconverged-cluster-operator/api/v1.USBSelector"}, + } +} + +func schema_kubevirt_hyperconverged_cluster_operator_api_v1_USBSelector(ref common.ReferenceCallback) common.OpenAPIDefinition { + return common.OpenAPIDefinition{ + Schema: spec.Schema{ + SchemaProps: spec.SchemaProps{ + Description: "USBSelector represents a selector for a USB device allowed for passthrough", + Type: []string{"object"}, + Properties: map[string]spec.Schema{ + "vendor": { + SchemaProps: spec.SchemaProps{ + Default: "", + Type: []string{"string"}, + Format: "", + }, + }, + "product": { + SchemaProps: spec.SchemaProps{ + Default: "", + Type: []string{"string"}, + Format: "", + }, + }, + }, + Required: []string{"vendor", "product"}, + }, + }, + } +} diff --git a/api/v1beta1/conversion.go b/api/v1beta1/conversion.go new file mode 100644 index 0000000000..17797d25d7 --- /dev/null +++ b/api/v1beta1/conversion.go @@ -0,0 +1,94 @@ +package v1beta1 + +import ( + "k8s.io/utils/ptr" + "sigs.k8s.io/controller-runtime/pkg/conversion" + + hcov1 "github.com/kubevirt/hyperconverged-cluster-operator/api/v1" + "github.com/kubevirt/hyperconverged-cluster-operator/api/v1/featuregates" +) + +//nolint:revive +func (src *HyperConverged) ConvertTo(dstRaw conversion.Hub) error { + dst := dstRaw.(*hcov1.HyperConverged) + + if err := Convert_v1beta1_HyperConverged_To_v1_HyperConverged(src, dst, nil); err != nil { + return err + } + + dst.Spec.FeatureGates = ConvertV1Beta1FGsToV1FGs(src.Spec.FeatureGates) + + return nil +} + +//nolint:revive +func (dst *HyperConverged) ConvertFrom(srcRaw conversion.Hub) error { + src := srcRaw.(*hcov1.HyperConverged) + + if err := Convert_v1_HyperConverged_To_v1beta1_HyperConverged(src, dst, nil); err != nil { + return err + } + + ConvertV1FGsToV1Beta1FGs(src.Spec.FeatureGates, &dst.Spec.FeatureGates) + + return nil +} + +func ConvertV1Beta1FGsToV1FGs(src HyperConvergedFeatureGates) featuregates.HyperConvergedFeatureGates { + var v1FGs featuregates.HyperConvergedFeatureGates + + if ptr.Deref(src.DownwardMetrics, false) { + v1FGs.Enable("downwardMetrics") + } + + if ptr.Deref(src.DeployKubeSecondaryDNS, false) { + v1FGs.Enable("deployKubeSecondaryDNS") + } + + if ptr.Deref(src.DisableMDevConfiguration, false) { + v1FGs.Enable("disableMDevConfiguration") + } + + if ptr.Deref(src.PersistentReservation, false) { + v1FGs.Enable("persistentReservation") + } + + if ptr.Deref(src.AlignCPUs, false) { + v1FGs.Enable("alignCPUs") + } + + if ptr.Deref(src.EnableMultiArchBootImageImport, false) { + v1FGs.Enable("enableMultiArchBootImageImport") + } + + if ptr.Deref(src.DecentralizedLiveMigration, false) { + v1FGs.Enable("decentralizedLiveMigration") + } + + if ptr.Deref(src.DeclarativeHotplugVolumes, false) { + v1FGs.Enable("declarativeHotplugVolumes") + } + + if !ptr.Deref(src.VideoConfig, true) { + v1FGs.Disable("videoConfig") + } + + if ptr.Deref(src.ObjectGraph, false) { + v1FGs.Enable("objectGraph") + } + + return v1FGs +} + +func ConvertV1FGsToV1Beta1FGs(src featuregates.HyperConvergedFeatureGates, dst *HyperConvergedFeatureGates) { + dst.DownwardMetrics = ptr.To(src.IsEnabled("downwardMetrics")) + dst.DeployKubeSecondaryDNS = ptr.To(src.IsEnabled("deployKubeSecondaryDNS")) + dst.DisableMDevConfiguration = ptr.To(src.IsEnabled("disableMDevConfiguration")) + dst.PersistentReservation = ptr.To(src.IsEnabled("persistentReservation")) + dst.AlignCPUs = ptr.To(src.IsEnabled("alignCPUs")) + dst.EnableMultiArchBootImageImport = ptr.To(src.IsEnabled("enableMultiArchBootImageImport")) + dst.DecentralizedLiveMigration = ptr.To(src.IsEnabled("decentralizedLiveMigration")) + dst.DeclarativeHotplugVolumes = ptr.To(src.IsEnabled("declarativeHotplugVolumes")) + dst.VideoConfig = ptr.To(src.IsEnabled("videoConfig")) + dst.ObjectGraph = ptr.To(src.IsEnabled("objectGraph")) +} diff --git a/api/v1beta1/conversion_test.go b/api/v1beta1/conversion_test.go new file mode 100644 index 0000000000..2cd462bc07 --- /dev/null +++ b/api/v1beta1/conversion_test.go @@ -0,0 +1,461 @@ +package v1beta1_test + +import ( + "testing" + + . "github.com/onsi/ginkgo/v2" + . "github.com/onsi/gomega" + "k8s.io/utils/ptr" + + "github.com/kubevirt/hyperconverged-cluster-operator/api/v1/featuregates" + hcov1beta1 "github.com/kubevirt/hyperconverged-cluster-operator/api/v1beta1" +) + +func TestConversionSuite(t *testing.T) { + RegisterFailHandler(Fail) + RunSpecs(t, "Conversion Suite") +} + +var _ = Describe("Feature Gates Conversion", func() { + + Describe("ConvertV1Beta1FGsToV1FGs", func() { + + It("should return empty slice when all feature gates are nil", func() { + src := hcov1beta1.HyperConvergedFeatureGates{} + + result := hcov1beta1.ConvertV1Beta1FGsToV1FGs(src) + + Expect(result).To(BeEmpty()) + }) + + It("should return empty slice when all feature gates are false", func() { + src := hcov1beta1.HyperConvergedFeatureGates{ + DownwardMetrics: ptr.To(false), + DeployKubeSecondaryDNS: ptr.To(false), + DisableMDevConfiguration: ptr.To(false), + PersistentReservation: ptr.To(false), + AlignCPUs: ptr.To(false), + EnableMultiArchBootImageImport: ptr.To(false), + DecentralizedLiveMigration: ptr.To(false), + DeclarativeHotplugVolumes: ptr.To(false), + VideoConfig: ptr.To(true), // beta FG is enabled by default + ObjectGraph: ptr.To(false), + } + + result := hcov1beta1.ConvertV1Beta1FGsToV1FGs(src) + + Expect(result).To(BeEmpty()) + }) + + It("should enable downwardMetrics when set to true", func() { + src := hcov1beta1.HyperConvergedFeatureGates{ + DownwardMetrics: ptr.To(true), + } + + result := hcov1beta1.ConvertV1Beta1FGsToV1FGs(src) + + Expect(result).To(HaveLen(1)) + Expect(result).To(ContainElement(featuregates.FeatureGate{ + Name: "downwardMetrics", + Enabled: ptr.To(featuregates.Enabled), + })) + }) + + It("should enable deployKubeSecondaryDNS when set to true", func() { + src := hcov1beta1.HyperConvergedFeatureGates{ + DeployKubeSecondaryDNS: ptr.To(true), + } + + result := hcov1beta1.ConvertV1Beta1FGsToV1FGs(src) + + Expect(result).To(HaveLen(1)) + Expect(result).To(ContainElement(featuregates.FeatureGate{ + Name: "deployKubeSecondaryDNS", + Enabled: ptr.To(featuregates.Enabled), + })) + }) + + It("should enable disableMDevConfiguration when set to true", func() { + src := hcov1beta1.HyperConvergedFeatureGates{ + DisableMDevConfiguration: ptr.To(true), + } + + result := hcov1beta1.ConvertV1Beta1FGsToV1FGs(src) + + Expect(result).To(HaveLen(1)) + Expect(result).To(ContainElement(featuregates.FeatureGate{ + Name: "disableMDevConfiguration", + Enabled: ptr.To(featuregates.Enabled), + })) + }) + + It("should enable persistentReservation when set to true", func() { + src := hcov1beta1.HyperConvergedFeatureGates{ + PersistentReservation: ptr.To(true), + } + + result := hcov1beta1.ConvertV1Beta1FGsToV1FGs(src) + + Expect(result).To(HaveLen(1)) + Expect(result).To(ContainElement(featuregates.FeatureGate{ + Name: "persistentReservation", + Enabled: ptr.To(featuregates.Enabled), + })) + }) + + It("should enable alignCPUs when set to true", func() { + src := hcov1beta1.HyperConvergedFeatureGates{ + AlignCPUs: ptr.To(true), + } + + result := hcov1beta1.ConvertV1Beta1FGsToV1FGs(src) + + Expect(result).To(HaveLen(1)) + Expect(result).To(ContainElement(featuregates.FeatureGate{ + Name: "alignCPUs", + Enabled: ptr.To(featuregates.Enabled), + })) + }) + + It("should enable enableMultiArchBootImageImport when set to true", func() { + src := hcov1beta1.HyperConvergedFeatureGates{ + EnableMultiArchBootImageImport: ptr.To(true), + } + + result := hcov1beta1.ConvertV1Beta1FGsToV1FGs(src) + + Expect(result).To(HaveLen(1)) + Expect(result).To(ContainElement(featuregates.FeatureGate{ + Name: "enableMultiArchBootImageImport", + Enabled: ptr.To(featuregates.Enabled), + })) + }) + + It("should enable decentralizedLiveMigration when set to true", func() { + src := hcov1beta1.HyperConvergedFeatureGates{ + DecentralizedLiveMigration: ptr.To(true), + } + + result := hcov1beta1.ConvertV1Beta1FGsToV1FGs(src) + + Expect(result).To(HaveLen(1)) + Expect(result).To(ContainElement(featuregates.FeatureGate{ + Name: "decentralizedLiveMigration", + Enabled: ptr.To(featuregates.Enabled), + })) + }) + + It("should enable declarativeHotplugVolumes when set to true", func() { + src := hcov1beta1.HyperConvergedFeatureGates{ + DeclarativeHotplugVolumes: ptr.To(true), + } + + result := hcov1beta1.ConvertV1Beta1FGsToV1FGs(src) + + Expect(result).To(HaveLen(1)) + Expect(result).To(ContainElement(featuregates.FeatureGate{ + Name: "declarativeHotplugVolumes", + Enabled: ptr.To(featuregates.Enabled), + })) + }) + + It("should disable videoConfig when set to false", func() { + src := hcov1beta1.HyperConvergedFeatureGates{ + VideoConfig: ptr.To(false), + } + + result := hcov1beta1.ConvertV1Beta1FGsToV1FGs(src) + + Expect(result).To(HaveLen(1)) + Expect(result).To(ContainElement(featuregates.FeatureGate{ + Name: "videoConfig", + Enabled: ptr.To(featuregates.Disabled), + })) + }) + + It("should enable objectGraph when set to true", func() { + src := hcov1beta1.HyperConvergedFeatureGates{ + ObjectGraph: ptr.To(true), + } + + result := hcov1beta1.ConvertV1Beta1FGsToV1FGs(src) + + Expect(result).To(HaveLen(1)) + Expect(result).To(ContainElement(featuregates.FeatureGate{ + Name: "objectGraph", + Enabled: ptr.To(featuregates.Enabled), + })) + }) + + It("should convert multiple enabled feature gates", func() { + src := hcov1beta1.HyperConvergedFeatureGates{ + DownwardMetrics: ptr.To(true), + AlignCPUs: ptr.To(true), + VideoConfig: ptr.To(false), + PersistentReservation: ptr.To(true), + } + + result := hcov1beta1.ConvertV1Beta1FGsToV1FGs(src) + + Expect(result).To(HaveLen(4)) + Expect(result).To(ContainElement(featuregates.FeatureGate{ + Name: "downwardMetrics", + Enabled: ptr.To(featuregates.Enabled), + })) + Expect(result).To(ContainElement(featuregates.FeatureGate{ + Name: "alignCPUs", + Enabled: ptr.To(featuregates.Enabled), + })) + Expect(result).To(ContainElement(featuregates.FeatureGate{ + Name: "videoConfig", + Enabled: ptr.To(featuregates.Disabled), + })) + Expect(result).To(ContainElement(featuregates.FeatureGate{ + Name: "persistentReservation", + Enabled: ptr.To(featuregates.Enabled), + })) + }) + + It("should convert all feature gates when all are enabled", func() { + src := hcov1beta1.HyperConvergedFeatureGates{ + DownwardMetrics: ptr.To(true), + DeployKubeSecondaryDNS: ptr.To(true), + DisableMDevConfiguration: ptr.To(true), + PersistentReservation: ptr.To(true), + AlignCPUs: ptr.To(true), + EnableMultiArchBootImageImport: ptr.To(true), + DecentralizedLiveMigration: ptr.To(true), + DeclarativeHotplugVolumes: ptr.To(true), + VideoConfig: ptr.To(false), // false means disable, so entry is added + ObjectGraph: ptr.To(true), + } + + result := hcov1beta1.ConvertV1Beta1FGsToV1FGs(src) + + Expect(result).To(HaveLen(10)) + }) + + }) + + Describe("ConvertV1FGsToV1Beta1FGs", func() { + + It("should set all fields to false when source is empty", func() { + src := featuregates.HyperConvergedFeatureGates{} + dst := hcov1beta1.HyperConvergedFeatureGates{} + + hcov1beta1.ConvertV1FGsToV1Beta1FGs(src, &dst) + + Expect(dst.DownwardMetrics).To(HaveValue(BeFalse())) + Expect(dst.DeployKubeSecondaryDNS).To(HaveValue(BeFalse())) + Expect(dst.DisableMDevConfiguration).To(HaveValue(BeFalse())) + Expect(dst.PersistentReservation).To(HaveValue(BeFalse())) + Expect(dst.AlignCPUs).To(HaveValue(BeFalse())) + Expect(dst.EnableMultiArchBootImageImport).To(HaveValue(BeFalse())) + Expect(dst.DecentralizedLiveMigration).To(HaveValue(BeFalse())) + Expect(dst.DeclarativeHotplugVolumes).To(HaveValue(BeFalse())) + // videoConfig is beta, so it defaults to enabled (true) when not in list + Expect(dst.VideoConfig).To(HaveValue(BeTrue())) + Expect(dst.ObjectGraph).To(HaveValue(BeFalse())) + }) + + It("should set downwardMetrics to true when enabled in source", func() { + src := featuregates.HyperConvergedFeatureGates{ + {Name: "downwardMetrics", Enabled: ptr.To(featuregates.Enabled)}, + } + dst := hcov1beta1.HyperConvergedFeatureGates{} + + hcov1beta1.ConvertV1FGsToV1Beta1FGs(src, &dst) + + Expect(dst.DownwardMetrics).To(HaveValue(BeTrue())) + }) + + It("should set deployKubeSecondaryDNS to true when enabled in source", func() { + src := featuregates.HyperConvergedFeatureGates{ + {Name: "deployKubeSecondaryDNS", Enabled: ptr.To(featuregates.Enabled)}, + } + dst := hcov1beta1.HyperConvergedFeatureGates{} + + hcov1beta1.ConvertV1FGsToV1Beta1FGs(src, &dst) + + Expect(dst.DeployKubeSecondaryDNS).To(HaveValue(BeTrue())) + }) + + It("should set disableMDevConfiguration to true when enabled in source", func() { + src := featuregates.HyperConvergedFeatureGates{ + {Name: "disableMDevConfiguration", Enabled: ptr.To(featuregates.Enabled)}, + } + dst := hcov1beta1.HyperConvergedFeatureGates{} + + hcov1beta1.ConvertV1FGsToV1Beta1FGs(src, &dst) + + Expect(dst.DisableMDevConfiguration).To(HaveValue(BeTrue())) + }) + + It("should set persistentReservation to true when enabled in source", func() { + src := featuregates.HyperConvergedFeatureGates{ + {Name: "persistentReservation", Enabled: ptr.To(featuregates.Enabled)}, + } + dst := hcov1beta1.HyperConvergedFeatureGates{} + + hcov1beta1.ConvertV1FGsToV1Beta1FGs(src, &dst) + + Expect(dst.PersistentReservation).To(HaveValue(BeTrue())) + }) + + It("should set alignCPUs to true when enabled in source", func() { + src := featuregates.HyperConvergedFeatureGates{ + {Name: "alignCPUs", Enabled: ptr.To(featuregates.Enabled)}, + } + dst := hcov1beta1.HyperConvergedFeatureGates{} + + hcov1beta1.ConvertV1FGsToV1Beta1FGs(src, &dst) + + Expect(dst.AlignCPUs).To(HaveValue(BeTrue())) + }) + + It("should set enableMultiArchBootImageImport to true when enabled in source", func() { + src := featuregates.HyperConvergedFeatureGates{ + {Name: "enableMultiArchBootImageImport", Enabled: ptr.To(featuregates.Enabled)}, + } + dst := hcov1beta1.HyperConvergedFeatureGates{} + + hcov1beta1.ConvertV1FGsToV1Beta1FGs(src, &dst) + + Expect(dst.EnableMultiArchBootImageImport).To(HaveValue(BeTrue())) + }) + + It("should set decentralizedLiveMigration to true when enabled in source", func() { + src := featuregates.HyperConvergedFeatureGates{ + {Name: "decentralizedLiveMigration", Enabled: ptr.To(featuregates.Enabled)}, + } + dst := hcov1beta1.HyperConvergedFeatureGates{} + + hcov1beta1.ConvertV1FGsToV1Beta1FGs(src, &dst) + + Expect(dst.DecentralizedLiveMigration).To(HaveValue(BeTrue())) + }) + + It("should set declarativeHotplugVolumes to true when enabled in source", func() { + src := featuregates.HyperConvergedFeatureGates{ + {Name: "declarativeHotplugVolumes", Enabled: ptr.To(featuregates.Enabled)}, + } + dst := hcov1beta1.HyperConvergedFeatureGates{} + + hcov1beta1.ConvertV1FGsToV1Beta1FGs(src, &dst) + + Expect(dst.DeclarativeHotplugVolumes).To(HaveValue(BeTrue())) + }) + + It("should set videoConfig to false when disabled in source", func() { + src := featuregates.HyperConvergedFeatureGates{ + {Name: "videoConfig", Enabled: ptr.To(featuregates.Disabled)}, + } + dst := hcov1beta1.HyperConvergedFeatureGates{} + + hcov1beta1.ConvertV1FGsToV1Beta1FGs(src, &dst) + + Expect(dst.VideoConfig).To(HaveValue(BeFalse())) + }) + + It("should set objectGraph to true when enabled in source", func() { + src := featuregates.HyperConvergedFeatureGates{ + {Name: "objectGraph", Enabled: ptr.To(featuregates.Enabled)}, + } + dst := hcov1beta1.HyperConvergedFeatureGates{} + + hcov1beta1.ConvertV1FGsToV1Beta1FGs(src, &dst) + + Expect(dst.ObjectGraph).To(HaveValue(BeTrue())) + }) + + It("should convert multiple feature gates", func() { + src := featuregates.HyperConvergedFeatureGates{ + {Name: "downwardMetrics", Enabled: ptr.To(featuregates.Enabled)}, + {Name: "alignCPUs", Enabled: ptr.To(featuregates.Enabled)}, + {Name: "videoConfig", Enabled: ptr.To(featuregates.Disabled)}, + {Name: "persistentReservation", Enabled: ptr.To(featuregates.Enabled)}, + } + dst := hcov1beta1.HyperConvergedFeatureGates{} + + hcov1beta1.ConvertV1FGsToV1Beta1FGs(src, &dst) + + Expect(dst.DownwardMetrics).To(HaveValue(BeTrue())) + Expect(dst.AlignCPUs).To(HaveValue(BeTrue())) + Expect(dst.VideoConfig).To(HaveValue(BeFalse())) + Expect(dst.PersistentReservation).To(HaveValue(BeTrue())) + }) + + }) + + Describe("Round-trip conversion", func() { + + It("should preserve enabled feature gates through v1beta1 -> v1 -> v1beta1 conversion", func() { + original := hcov1beta1.HyperConvergedFeatureGates{ + DownwardMetrics: ptr.To(true), + DeployKubeSecondaryDNS: ptr.To(true), + DisableMDevConfiguration: ptr.To(false), + PersistentReservation: ptr.To(true), + AlignCPUs: ptr.To(false), + EnableMultiArchBootImageImport: ptr.To(true), + DecentralizedLiveMigration: ptr.To(false), + DeclarativeHotplugVolumes: ptr.To(true), + VideoConfig: ptr.To(false), + ObjectGraph: ptr.To(true), + } + + // Convert to v1 + v1FGs := hcov1beta1.ConvertV1Beta1FGsToV1FGs(original) + + // Convert back to v1beta1 + result := hcov1beta1.HyperConvergedFeatureGates{} + hcov1beta1.ConvertV1FGsToV1Beta1FGs(v1FGs, &result) + + Expect(result.DownwardMetrics).To(HaveValue(Equal(*original.DownwardMetrics))) + Expect(result.DeployKubeSecondaryDNS).To(HaveValue(Equal(*original.DeployKubeSecondaryDNS))) + Expect(result.DisableMDevConfiguration).To(HaveValue(Equal(*original.DisableMDevConfiguration))) + Expect(result.PersistentReservation).To(HaveValue(Equal(*original.PersistentReservation))) + Expect(result.AlignCPUs).To(HaveValue(Equal(*original.AlignCPUs))) + Expect(result.EnableMultiArchBootImageImport).To(HaveValue(Equal(*original.EnableMultiArchBootImageImport))) + Expect(result.DecentralizedLiveMigration).To(HaveValue(Equal(*original.DecentralizedLiveMigration))) + Expect(result.DeclarativeHotplugVolumes).To(HaveValue(Equal(*original.DeclarativeHotplugVolumes))) + Expect(result.VideoConfig).To(HaveValue(Equal(*original.VideoConfig))) + Expect(result.ObjectGraph).To(HaveValue(Equal(*original.ObjectGraph))) + }) + + It("should preserve feature gates through v1 -> v1beta1 -> v1 conversion", func() { + original := featuregates.HyperConvergedFeatureGates{ + {Name: "downwardMetrics", Enabled: ptr.To(featuregates.Enabled)}, + {Name: "deployKubeSecondaryDNS", Enabled: ptr.To(featuregates.Enabled)}, + {Name: "alignCPUs", Enabled: ptr.To(featuregates.Enabled)}, + {Name: "videoConfig", Enabled: ptr.To(featuregates.Disabled)}, + } + + // Convert to v1beta1 + v1beta1FGs := hcov1beta1.HyperConvergedFeatureGates{} + hcov1beta1.ConvertV1FGsToV1Beta1FGs(original, &v1beta1FGs) + + // Convert back to v1 + result := hcov1beta1.ConvertV1Beta1FGsToV1FGs(v1beta1FGs) + + // Check that the enabled feature gates are preserved + Expect(result).To(ContainElement(featuregates.FeatureGate{ + Name: "downwardMetrics", + Enabled: ptr.To(featuregates.Enabled), + })) + Expect(result).To(ContainElement(featuregates.FeatureGate{ + Name: "deployKubeSecondaryDNS", + Enabled: ptr.To(featuregates.Enabled), + })) + Expect(result).To(ContainElement(featuregates.FeatureGate{ + Name: "alignCPUs", + Enabled: ptr.To(featuregates.Enabled), + })) + Expect(result).To(ContainElement(featuregates.FeatureGate{ + Name: "videoConfig", + Enabled: ptr.To(featuregates.Disabled), + })) + }) + + }) + +}) diff --git a/api/v1beta1/doc.go b/api/v1beta1/doc.go index ec1ac2d1a8..2686e5e7ba 100644 --- a/api/v1beta1/doc.go +++ b/api/v1beta1/doc.go @@ -1,5 +1,6 @@ -// package v1beta1 contains API Schema definitions for the hco v1beta1 API group +// Package v1beta1 contains API Schema definitions for the hco v1beta1 API group // +k8s:deepcopy-gen=package,register // +k8s:defaulter-gen=TypeMeta // +groupName=hco.kubevirt.io +// +k8s:conversion-gen=github.com/kubevirt/hyperconverged-cluster-operator/api/v1 package v1beta1 diff --git a/api/v1beta1/hyperconverged_types.go b/api/v1beta1/hyperconverged_types.go index 03b50241de..890e856479 100644 --- a/api/v1beta1/hyperconverged_types.go +++ b/api/v1beta1/hyperconverged_types.go @@ -43,6 +43,7 @@ type HyperConvergedSpec struct { // Add custom validation using kubebuilder tags: https://book.kubebuilder.io/beyond_basics/generating_crd.html // Deprecated: LocalStorageClassName the name of the local storage class. + // +k8s:conversion-gen=false LocalStorageClassName string `json:"localStorageClassName,omitempty"` // TuningPolicy allows to configure the mode in which the RateLimits of kubevirt are set. @@ -69,6 +70,7 @@ type HyperConvergedSpec struct { // the feature. Setting `false` or removing the feature gate, disables the feature. // +kubebuilder:default={"downwardMetrics": false, "deployKubeSecondaryDNS": false, "disableMDevConfiguration": false, "persistentReservation": false, "enableMultiArchBootImageImport": false, "decentralizedLiveMigration": false, "declarativeHotplugVolumes": false, "videoConfig": true, "objectGraph": false} // +optional + // +k8s:conversion-gen=false FeatureGates HyperConvergedFeatureGates `json:"featureGates,omitempty"` // Live migration limits and timeouts are applied so that migration processes do not @@ -108,6 +110,7 @@ type HyperConvergedSpec struct { // // Deprecated: please use the Migration Toolkit for Virtualization // +optional + // +k8s:conversion-gen=false VddkInitImage *string `json:"vddkInitImage,omitempty"` // DefaultCPUModel defines a cluster default for CPU model: default CPU model is set when VMI doesn't have any CPU model. @@ -180,6 +183,7 @@ type HyperConvergedSpec struct { // +optional // +kubebuilder:deprecatedversion:warning="tektonPipelinesNamespace field is ignored" // Deprecated: This field is ignored. + // +k8s:conversion-gen=false TektonPipelinesNamespace *string `json:"tektonPipelinesNamespace,omitempty"` // TektonTasksNamespace defines namespace in which tekton tasks will be deployed. @@ -187,6 +191,7 @@ type HyperConvergedSpec struct { // +optional // +kubebuilder:deprecatedversion:warning="tektonTasksNamespace field is ignored" // Deprecated: This field is ignored. + // +k8s:conversion-gen=false TektonTasksNamespace *string `json:"tektonTasksNamespace,omitempty"` // KubeSecondaryDNSNameServerIP defines name server IP used by KubeSecondaryDNS @@ -434,6 +439,7 @@ type VirtualMachineOptions struct { // HyperConvergedFeatureGates is a set of optional feature gates to enable or disable new features that are not enabled // by default yet. // +k8s:openapi-gen=true +// +k8s:conversion-gen=false type HyperConvergedFeatureGates struct { // Allow to expose a limited set of host metrics to guests. // +optional @@ -633,6 +639,7 @@ type MediatedDevicesConfiguration struct { // Deprecated: please use mediatedDeviceTypes instead. // +optional // +listType=atomic + // +k8s:conversion-gen=false MediatedDevicesTypes []string `json:"mediatedDevicesTypes,omitempty"` // +optional @@ -657,6 +664,7 @@ type NodeMediatedDeviceTypesConfig struct { // Deprecated: please use mediatedDeviceTypes instead. // +listType=atomic // +optional + // +k8s:conversion-gen=false MediatedDevicesTypes []string `json:"mediatedDevicesTypes"` } @@ -697,6 +705,7 @@ type OperandResourceRequirements struct { type HyperConvergedObsoleteCPUs struct { // MinCPUModel is not in use // Deprecated: This field is not in use and is ignored. + // +k8s:conversion-gen=false MinCPUModel string `json:"minCPUModel,omitempty"` // CPUModels is a list of obsolete CPU models. When the node-labeller obtains the list of obsolete CPU models, it // eliminates those CPU models and creates labels for valid CPU models. @@ -957,7 +966,3 @@ type HyperConvergedList struct { metav1.ListMeta `json:"metadata,omitempty"` Items []HyperConverged `json:"items"` } - -func init() { - SchemeBuilder.Register(&HyperConverged{}, &HyperConvergedList{}) -} diff --git a/api/v1beta1/register.go b/api/v1beta1/register.go index 84ae61659e..cbf8960469 100644 --- a/api/v1beta1/register.go +++ b/api/v1beta1/register.go @@ -7,8 +7,9 @@ package v1beta1 import ( + metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" + "k8s.io/apimachinery/pkg/runtime" "k8s.io/apimachinery/pkg/runtime/schema" - "sigs.k8s.io/controller-runtime/pkg/scheme" ) const ( @@ -22,9 +23,18 @@ var ( // SchemeGroupVersion is group version used to register these objects SchemeGroupVersion = schema.GroupVersion{Group: APIVersionGroup, Version: APIVersionBeta} - // SchemeBuilder is used to add go types to the GroupVersionKind scheme - SchemeBuilder = &scheme.Builder{GroupVersion: SchemeGroupVersion} + // schemeBuilder is used to add go types to the GroupVersionKind scheme + schemeBuilder = runtime.NewSchemeBuilder(addKnownTypes) + + // localSchemeBuilder is used for type conversions. + localSchemeBuilder = &schemeBuilder // AddToScheme tbd - AddToScheme = SchemeBuilder.AddToScheme + AddToScheme = schemeBuilder.AddToScheme ) + +func addKnownTypes(scheme *runtime.Scheme) error { + scheme.AddKnownTypes(SchemeGroupVersion, &HyperConverged{}, &HyperConvergedList{}) + metav1.AddToGroupVersion(scheme, SchemeGroupVersion) + return nil +} diff --git a/api/v1beta1/zz_generated.conversion.go b/api/v1beta1/zz_generated.conversion.go new file mode 100644 index 0000000000..d055cbad2c --- /dev/null +++ b/api/v1beta1/zz_generated.conversion.go @@ -0,0 +1,1251 @@ +//go:build !ignore_autogenerated +// +build !ignore_autogenerated + +/* + * This file is part of the KubeVirt project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + * Copyright 2026 Red Hat, Inc. + * + */ + +// Code generated by conversion-gen. DO NOT EDIT. + +package v1beta1 + +import ( + unsafe "unsafe" + + v1 "github.com/kubevirt/hyperconverged-cluster-operator/api/v1" + configv1 "github.com/openshift/api/config/v1" + apicorev1 "k8s.io/api/core/v1" + metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" + conversion "k8s.io/apimachinery/pkg/conversion" + runtime "k8s.io/apimachinery/pkg/runtime" + corev1 "kubevirt.io/api/core/v1" + v1alpha1 "kubevirt.io/application-aware-quota/staging/src/kubevirt.io/application-aware-quota-api/pkg/apis/core/v1alpha1" + corev1beta1 "kubevirt.io/containerized-data-importer-api/pkg/apis/core/v1beta1" + api "kubevirt.io/controller-lifecycle-operator-sdk/api" +) + +func init() { + localSchemeBuilder.Register(RegisterConversions) +} + +// RegisterConversions adds conversion functions to the given scheme. +// Public to allow building arbitrary schemes. +func RegisterConversions(s *runtime.Scheme) error { + if err := s.AddGeneratedConversionFunc((*ApplicationAwareConfigurations)(nil), (*v1.ApplicationAwareConfigurations)(nil), func(a, b interface{}, scope conversion.Scope) error { + return Convert_v1beta1_ApplicationAwareConfigurations_To_v1_ApplicationAwareConfigurations(a.(*ApplicationAwareConfigurations), b.(*v1.ApplicationAwareConfigurations), scope) + }); err != nil { + return err + } + if err := s.AddGeneratedConversionFunc((*v1.ApplicationAwareConfigurations)(nil), (*ApplicationAwareConfigurations)(nil), func(a, b interface{}, scope conversion.Scope) error { + return Convert_v1_ApplicationAwareConfigurations_To_v1beta1_ApplicationAwareConfigurations(a.(*v1.ApplicationAwareConfigurations), b.(*ApplicationAwareConfigurations), scope) + }); err != nil { + return err + } + if err := s.AddGeneratedConversionFunc((*CertRotateConfigCA)(nil), (*v1.CertRotateConfigCA)(nil), func(a, b interface{}, scope conversion.Scope) error { + return Convert_v1beta1_CertRotateConfigCA_To_v1_CertRotateConfigCA(a.(*CertRotateConfigCA), b.(*v1.CertRotateConfigCA), scope) + }); err != nil { + return err + } + if err := s.AddGeneratedConversionFunc((*v1.CertRotateConfigCA)(nil), (*CertRotateConfigCA)(nil), func(a, b interface{}, scope conversion.Scope) error { + return Convert_v1_CertRotateConfigCA_To_v1beta1_CertRotateConfigCA(a.(*v1.CertRotateConfigCA), b.(*CertRotateConfigCA), scope) + }); err != nil { + return err + } + if err := s.AddGeneratedConversionFunc((*CertRotateConfigServer)(nil), (*v1.CertRotateConfigServer)(nil), func(a, b interface{}, scope conversion.Scope) error { + return Convert_v1beta1_CertRotateConfigServer_To_v1_CertRotateConfigServer(a.(*CertRotateConfigServer), b.(*v1.CertRotateConfigServer), scope) + }); err != nil { + return err + } + if err := s.AddGeneratedConversionFunc((*v1.CertRotateConfigServer)(nil), (*CertRotateConfigServer)(nil), func(a, b interface{}, scope conversion.Scope) error { + return Convert_v1_CertRotateConfigServer_To_v1beta1_CertRotateConfigServer(a.(*v1.CertRotateConfigServer), b.(*CertRotateConfigServer), scope) + }); err != nil { + return err + } + if err := s.AddGeneratedConversionFunc((*DataImportCronStatus)(nil), (*v1.DataImportCronStatus)(nil), func(a, b interface{}, scope conversion.Scope) error { + return Convert_v1beta1_DataImportCronStatus_To_v1_DataImportCronStatus(a.(*DataImportCronStatus), b.(*v1.DataImportCronStatus), scope) + }); err != nil { + return err + } + if err := s.AddGeneratedConversionFunc((*v1.DataImportCronStatus)(nil), (*DataImportCronStatus)(nil), func(a, b interface{}, scope conversion.Scope) error { + return Convert_v1_DataImportCronStatus_To_v1beta1_DataImportCronStatus(a.(*v1.DataImportCronStatus), b.(*DataImportCronStatus), scope) + }); err != nil { + return err + } + if err := s.AddGeneratedConversionFunc((*DataImportCronTemplate)(nil), (*v1.DataImportCronTemplate)(nil), func(a, b interface{}, scope conversion.Scope) error { + return Convert_v1beta1_DataImportCronTemplate_To_v1_DataImportCronTemplate(a.(*DataImportCronTemplate), b.(*v1.DataImportCronTemplate), scope) + }); err != nil { + return err + } + if err := s.AddGeneratedConversionFunc((*v1.DataImportCronTemplate)(nil), (*DataImportCronTemplate)(nil), func(a, b interface{}, scope conversion.Scope) error { + return Convert_v1_DataImportCronTemplate_To_v1beta1_DataImportCronTemplate(a.(*v1.DataImportCronTemplate), b.(*DataImportCronTemplate), scope) + }); err != nil { + return err + } + if err := s.AddGeneratedConversionFunc((*DataImportCronTemplateStatus)(nil), (*v1.DataImportCronTemplateStatus)(nil), func(a, b interface{}, scope conversion.Scope) error { + return Convert_v1beta1_DataImportCronTemplateStatus_To_v1_DataImportCronTemplateStatus(a.(*DataImportCronTemplateStatus), b.(*v1.DataImportCronTemplateStatus), scope) + }); err != nil { + return err + } + if err := s.AddGeneratedConversionFunc((*v1.DataImportCronTemplateStatus)(nil), (*DataImportCronTemplateStatus)(nil), func(a, b interface{}, scope conversion.Scope) error { + return Convert_v1_DataImportCronTemplateStatus_To_v1beta1_DataImportCronTemplateStatus(a.(*v1.DataImportCronTemplateStatus), b.(*DataImportCronTemplateStatus), scope) + }); err != nil { + return err + } + if err := s.AddGeneratedConversionFunc((*HigherWorkloadDensityConfiguration)(nil), (*v1.HigherWorkloadDensityConfiguration)(nil), func(a, b interface{}, scope conversion.Scope) error { + return Convert_v1beta1_HigherWorkloadDensityConfiguration_To_v1_HigherWorkloadDensityConfiguration(a.(*HigherWorkloadDensityConfiguration), b.(*v1.HigherWorkloadDensityConfiguration), scope) + }); err != nil { + return err + } + if err := s.AddGeneratedConversionFunc((*v1.HigherWorkloadDensityConfiguration)(nil), (*HigherWorkloadDensityConfiguration)(nil), func(a, b interface{}, scope conversion.Scope) error { + return Convert_v1_HigherWorkloadDensityConfiguration_To_v1beta1_HigherWorkloadDensityConfiguration(a.(*v1.HigherWorkloadDensityConfiguration), b.(*HigherWorkloadDensityConfiguration), scope) + }); err != nil { + return err + } + if err := s.AddGeneratedConversionFunc((*HyperConverged)(nil), (*v1.HyperConverged)(nil), func(a, b interface{}, scope conversion.Scope) error { + return Convert_v1beta1_HyperConverged_To_v1_HyperConverged(a.(*HyperConverged), b.(*v1.HyperConverged), scope) + }); err != nil { + return err + } + if err := s.AddGeneratedConversionFunc((*v1.HyperConverged)(nil), (*HyperConverged)(nil), func(a, b interface{}, scope conversion.Scope) error { + return Convert_v1_HyperConverged_To_v1beta1_HyperConverged(a.(*v1.HyperConverged), b.(*HyperConverged), scope) + }); err != nil { + return err + } + if err := s.AddGeneratedConversionFunc((*HyperConvergedCertConfig)(nil), (*v1.HyperConvergedCertConfig)(nil), func(a, b interface{}, scope conversion.Scope) error { + return Convert_v1beta1_HyperConvergedCertConfig_To_v1_HyperConvergedCertConfig(a.(*HyperConvergedCertConfig), b.(*v1.HyperConvergedCertConfig), scope) + }); err != nil { + return err + } + if err := s.AddGeneratedConversionFunc((*v1.HyperConvergedCertConfig)(nil), (*HyperConvergedCertConfig)(nil), func(a, b interface{}, scope conversion.Scope) error { + return Convert_v1_HyperConvergedCertConfig_To_v1beta1_HyperConvergedCertConfig(a.(*v1.HyperConvergedCertConfig), b.(*HyperConvergedCertConfig), scope) + }); err != nil { + return err + } + if err := s.AddGeneratedConversionFunc((*HyperConvergedConfig)(nil), (*v1.HyperConvergedConfig)(nil), func(a, b interface{}, scope conversion.Scope) error { + return Convert_v1beta1_HyperConvergedConfig_To_v1_HyperConvergedConfig(a.(*HyperConvergedConfig), b.(*v1.HyperConvergedConfig), scope) + }); err != nil { + return err + } + if err := s.AddGeneratedConversionFunc((*v1.HyperConvergedConfig)(nil), (*HyperConvergedConfig)(nil), func(a, b interface{}, scope conversion.Scope) error { + return Convert_v1_HyperConvergedConfig_To_v1beta1_HyperConvergedConfig(a.(*v1.HyperConvergedConfig), b.(*HyperConvergedConfig), scope) + }); err != nil { + return err + } + if err := s.AddGeneratedConversionFunc((*HyperConvergedList)(nil), (*v1.HyperConvergedList)(nil), func(a, b interface{}, scope conversion.Scope) error { + return Convert_v1beta1_HyperConvergedList_To_v1_HyperConvergedList(a.(*HyperConvergedList), b.(*v1.HyperConvergedList), scope) + }); err != nil { + return err + } + if err := s.AddGeneratedConversionFunc((*v1.HyperConvergedList)(nil), (*HyperConvergedList)(nil), func(a, b interface{}, scope conversion.Scope) error { + return Convert_v1_HyperConvergedList_To_v1beta1_HyperConvergedList(a.(*v1.HyperConvergedList), b.(*HyperConvergedList), scope) + }); err != nil { + return err + } + if err := s.AddGeneratedConversionFunc((*HyperConvergedObsoleteCPUs)(nil), (*v1.HyperConvergedObsoleteCPUs)(nil), func(a, b interface{}, scope conversion.Scope) error { + return Convert_v1beta1_HyperConvergedObsoleteCPUs_To_v1_HyperConvergedObsoleteCPUs(a.(*HyperConvergedObsoleteCPUs), b.(*v1.HyperConvergedObsoleteCPUs), scope) + }); err != nil { + return err + } + if err := s.AddGeneratedConversionFunc((*v1.HyperConvergedObsoleteCPUs)(nil), (*HyperConvergedObsoleteCPUs)(nil), func(a, b interface{}, scope conversion.Scope) error { + return Convert_v1_HyperConvergedObsoleteCPUs_To_v1beta1_HyperConvergedObsoleteCPUs(a.(*v1.HyperConvergedObsoleteCPUs), b.(*HyperConvergedObsoleteCPUs), scope) + }); err != nil { + return err + } + if err := s.AddGeneratedConversionFunc((*HyperConvergedSpec)(nil), (*v1.HyperConvergedSpec)(nil), func(a, b interface{}, scope conversion.Scope) error { + return Convert_v1beta1_HyperConvergedSpec_To_v1_HyperConvergedSpec(a.(*HyperConvergedSpec), b.(*v1.HyperConvergedSpec), scope) + }); err != nil { + return err + } + if err := s.AddGeneratedConversionFunc((*v1.HyperConvergedSpec)(nil), (*HyperConvergedSpec)(nil), func(a, b interface{}, scope conversion.Scope) error { + return Convert_v1_HyperConvergedSpec_To_v1beta1_HyperConvergedSpec(a.(*v1.HyperConvergedSpec), b.(*HyperConvergedSpec), scope) + }); err != nil { + return err + } + if err := s.AddGeneratedConversionFunc((*HyperConvergedStatus)(nil), (*v1.HyperConvergedStatus)(nil), func(a, b interface{}, scope conversion.Scope) error { + return Convert_v1beta1_HyperConvergedStatus_To_v1_HyperConvergedStatus(a.(*HyperConvergedStatus), b.(*v1.HyperConvergedStatus), scope) + }); err != nil { + return err + } + if err := s.AddGeneratedConversionFunc((*v1.HyperConvergedStatus)(nil), (*HyperConvergedStatus)(nil), func(a, b interface{}, scope conversion.Scope) error { + return Convert_v1_HyperConvergedStatus_To_v1beta1_HyperConvergedStatus(a.(*v1.HyperConvergedStatus), b.(*HyperConvergedStatus), scope) + }); err != nil { + return err + } + if err := s.AddGeneratedConversionFunc((*HyperConvergedWorkloadUpdateStrategy)(nil), (*v1.HyperConvergedWorkloadUpdateStrategy)(nil), func(a, b interface{}, scope conversion.Scope) error { + return Convert_v1beta1_HyperConvergedWorkloadUpdateStrategy_To_v1_HyperConvergedWorkloadUpdateStrategy(a.(*HyperConvergedWorkloadUpdateStrategy), b.(*v1.HyperConvergedWorkloadUpdateStrategy), scope) + }); err != nil { + return err + } + if err := s.AddGeneratedConversionFunc((*v1.HyperConvergedWorkloadUpdateStrategy)(nil), (*HyperConvergedWorkloadUpdateStrategy)(nil), func(a, b interface{}, scope conversion.Scope) error { + return Convert_v1_HyperConvergedWorkloadUpdateStrategy_To_v1beta1_HyperConvergedWorkloadUpdateStrategy(a.(*v1.HyperConvergedWorkloadUpdateStrategy), b.(*HyperConvergedWorkloadUpdateStrategy), scope) + }); err != nil { + return err + } + if err := s.AddGeneratedConversionFunc((*KubeMacPoolConfig)(nil), (*v1.KubeMacPoolConfig)(nil), func(a, b interface{}, scope conversion.Scope) error { + return Convert_v1beta1_KubeMacPoolConfig_To_v1_KubeMacPoolConfig(a.(*KubeMacPoolConfig), b.(*v1.KubeMacPoolConfig), scope) + }); err != nil { + return err + } + if err := s.AddGeneratedConversionFunc((*v1.KubeMacPoolConfig)(nil), (*KubeMacPoolConfig)(nil), func(a, b interface{}, scope conversion.Scope) error { + return Convert_v1_KubeMacPoolConfig_To_v1beta1_KubeMacPoolConfig(a.(*v1.KubeMacPoolConfig), b.(*KubeMacPoolConfig), scope) + }); err != nil { + return err + } + if err := s.AddGeneratedConversionFunc((*LiveMigrationConfigurations)(nil), (*v1.LiveMigrationConfigurations)(nil), func(a, b interface{}, scope conversion.Scope) error { + return Convert_v1beta1_LiveMigrationConfigurations_To_v1_LiveMigrationConfigurations(a.(*LiveMigrationConfigurations), b.(*v1.LiveMigrationConfigurations), scope) + }); err != nil { + return err + } + if err := s.AddGeneratedConversionFunc((*v1.LiveMigrationConfigurations)(nil), (*LiveMigrationConfigurations)(nil), func(a, b interface{}, scope conversion.Scope) error { + return Convert_v1_LiveMigrationConfigurations_To_v1beta1_LiveMigrationConfigurations(a.(*v1.LiveMigrationConfigurations), b.(*LiveMigrationConfigurations), scope) + }); err != nil { + return err + } + if err := s.AddGeneratedConversionFunc((*LogVerbosityConfiguration)(nil), (*v1.LogVerbosityConfiguration)(nil), func(a, b interface{}, scope conversion.Scope) error { + return Convert_v1beta1_LogVerbosityConfiguration_To_v1_LogVerbosityConfiguration(a.(*LogVerbosityConfiguration), b.(*v1.LogVerbosityConfiguration), scope) + }); err != nil { + return err + } + if err := s.AddGeneratedConversionFunc((*v1.LogVerbosityConfiguration)(nil), (*LogVerbosityConfiguration)(nil), func(a, b interface{}, scope conversion.Scope) error { + return Convert_v1_LogVerbosityConfiguration_To_v1beta1_LogVerbosityConfiguration(a.(*v1.LogVerbosityConfiguration), b.(*LogVerbosityConfiguration), scope) + }); err != nil { + return err + } + if err := s.AddGeneratedConversionFunc((*MediatedDevicesConfiguration)(nil), (*v1.MediatedDevicesConfiguration)(nil), func(a, b interface{}, scope conversion.Scope) error { + return Convert_v1beta1_MediatedDevicesConfiguration_To_v1_MediatedDevicesConfiguration(a.(*MediatedDevicesConfiguration), b.(*v1.MediatedDevicesConfiguration), scope) + }); err != nil { + return err + } + if err := s.AddGeneratedConversionFunc((*v1.MediatedDevicesConfiguration)(nil), (*MediatedDevicesConfiguration)(nil), func(a, b interface{}, scope conversion.Scope) error { + return Convert_v1_MediatedDevicesConfiguration_To_v1beta1_MediatedDevicesConfiguration(a.(*v1.MediatedDevicesConfiguration), b.(*MediatedDevicesConfiguration), scope) + }); err != nil { + return err + } + if err := s.AddGeneratedConversionFunc((*MediatedHostDevice)(nil), (*v1.MediatedHostDevice)(nil), func(a, b interface{}, scope conversion.Scope) error { + return Convert_v1beta1_MediatedHostDevice_To_v1_MediatedHostDevice(a.(*MediatedHostDevice), b.(*v1.MediatedHostDevice), scope) + }); err != nil { + return err + } + if err := s.AddGeneratedConversionFunc((*v1.MediatedHostDevice)(nil), (*MediatedHostDevice)(nil), func(a, b interface{}, scope conversion.Scope) error { + return Convert_v1_MediatedHostDevice_To_v1beta1_MediatedHostDevice(a.(*v1.MediatedHostDevice), b.(*MediatedHostDevice), scope) + }); err != nil { + return err + } + if err := s.AddGeneratedConversionFunc((*NodeInfoStatus)(nil), (*v1.NodeInfoStatus)(nil), func(a, b interface{}, scope conversion.Scope) error { + return Convert_v1beta1_NodeInfoStatus_To_v1_NodeInfoStatus(a.(*NodeInfoStatus), b.(*v1.NodeInfoStatus), scope) + }); err != nil { + return err + } + if err := s.AddGeneratedConversionFunc((*v1.NodeInfoStatus)(nil), (*NodeInfoStatus)(nil), func(a, b interface{}, scope conversion.Scope) error { + return Convert_v1_NodeInfoStatus_To_v1beta1_NodeInfoStatus(a.(*v1.NodeInfoStatus), b.(*NodeInfoStatus), scope) + }); err != nil { + return err + } + if err := s.AddGeneratedConversionFunc((*NodeMediatedDeviceTypesConfig)(nil), (*v1.NodeMediatedDeviceTypesConfig)(nil), func(a, b interface{}, scope conversion.Scope) error { + return Convert_v1beta1_NodeMediatedDeviceTypesConfig_To_v1_NodeMediatedDeviceTypesConfig(a.(*NodeMediatedDeviceTypesConfig), b.(*v1.NodeMediatedDeviceTypesConfig), scope) + }); err != nil { + return err + } + if err := s.AddGeneratedConversionFunc((*v1.NodeMediatedDeviceTypesConfig)(nil), (*NodeMediatedDeviceTypesConfig)(nil), func(a, b interface{}, scope conversion.Scope) error { + return Convert_v1_NodeMediatedDeviceTypesConfig_To_v1beta1_NodeMediatedDeviceTypesConfig(a.(*v1.NodeMediatedDeviceTypesConfig), b.(*NodeMediatedDeviceTypesConfig), scope) + }); err != nil { + return err + } + if err := s.AddGeneratedConversionFunc((*OperandResourceRequirements)(nil), (*v1.OperandResourceRequirements)(nil), func(a, b interface{}, scope conversion.Scope) error { + return Convert_v1beta1_OperandResourceRequirements_To_v1_OperandResourceRequirements(a.(*OperandResourceRequirements), b.(*v1.OperandResourceRequirements), scope) + }); err != nil { + return err + } + if err := s.AddGeneratedConversionFunc((*v1.OperandResourceRequirements)(nil), (*OperandResourceRequirements)(nil), func(a, b interface{}, scope conversion.Scope) error { + return Convert_v1_OperandResourceRequirements_To_v1beta1_OperandResourceRequirements(a.(*v1.OperandResourceRequirements), b.(*OperandResourceRequirements), scope) + }); err != nil { + return err + } + if err := s.AddGeneratedConversionFunc((*PciHostDevice)(nil), (*v1.PciHostDevice)(nil), func(a, b interface{}, scope conversion.Scope) error { + return Convert_v1beta1_PciHostDevice_To_v1_PciHostDevice(a.(*PciHostDevice), b.(*v1.PciHostDevice), scope) + }); err != nil { + return err + } + if err := s.AddGeneratedConversionFunc((*v1.PciHostDevice)(nil), (*PciHostDevice)(nil), func(a, b interface{}, scope conversion.Scope) error { + return Convert_v1_PciHostDevice_To_v1beta1_PciHostDevice(a.(*v1.PciHostDevice), b.(*PciHostDevice), scope) + }); err != nil { + return err + } + if err := s.AddGeneratedConversionFunc((*PermittedHostDevices)(nil), (*v1.PermittedHostDevices)(nil), func(a, b interface{}, scope conversion.Scope) error { + return Convert_v1beta1_PermittedHostDevices_To_v1_PermittedHostDevices(a.(*PermittedHostDevices), b.(*v1.PermittedHostDevices), scope) + }); err != nil { + return err + } + if err := s.AddGeneratedConversionFunc((*v1.PermittedHostDevices)(nil), (*PermittedHostDevices)(nil), func(a, b interface{}, scope conversion.Scope) error { + return Convert_v1_PermittedHostDevices_To_v1beta1_PermittedHostDevices(a.(*v1.PermittedHostDevices), b.(*PermittedHostDevices), scope) + }); err != nil { + return err + } + if err := s.AddGeneratedConversionFunc((*StorageImportConfig)(nil), (*v1.StorageImportConfig)(nil), func(a, b interface{}, scope conversion.Scope) error { + return Convert_v1beta1_StorageImportConfig_To_v1_StorageImportConfig(a.(*StorageImportConfig), b.(*v1.StorageImportConfig), scope) + }); err != nil { + return err + } + if err := s.AddGeneratedConversionFunc((*v1.StorageImportConfig)(nil), (*StorageImportConfig)(nil), func(a, b interface{}, scope conversion.Scope) error { + return Convert_v1_StorageImportConfig_To_v1beta1_StorageImportConfig(a.(*v1.StorageImportConfig), b.(*StorageImportConfig), scope) + }); err != nil { + return err + } + if err := s.AddGeneratedConversionFunc((*USBHostDevice)(nil), (*v1.USBHostDevice)(nil), func(a, b interface{}, scope conversion.Scope) error { + return Convert_v1beta1_USBHostDevice_To_v1_USBHostDevice(a.(*USBHostDevice), b.(*v1.USBHostDevice), scope) + }); err != nil { + return err + } + if err := s.AddGeneratedConversionFunc((*v1.USBHostDevice)(nil), (*USBHostDevice)(nil), func(a, b interface{}, scope conversion.Scope) error { + return Convert_v1_USBHostDevice_To_v1beta1_USBHostDevice(a.(*v1.USBHostDevice), b.(*USBHostDevice), scope) + }); err != nil { + return err + } + if err := s.AddGeneratedConversionFunc((*USBSelector)(nil), (*v1.USBSelector)(nil), func(a, b interface{}, scope conversion.Scope) error { + return Convert_v1beta1_USBSelector_To_v1_USBSelector(a.(*USBSelector), b.(*v1.USBSelector), scope) + }); err != nil { + return err + } + if err := s.AddGeneratedConversionFunc((*v1.USBSelector)(nil), (*USBSelector)(nil), func(a, b interface{}, scope conversion.Scope) error { + return Convert_v1_USBSelector_To_v1beta1_USBSelector(a.(*v1.USBSelector), b.(*USBSelector), scope) + }); err != nil { + return err + } + if err := s.AddGeneratedConversionFunc((*Version)(nil), (*v1.Version)(nil), func(a, b interface{}, scope conversion.Scope) error { + return Convert_v1beta1_Version_To_v1_Version(a.(*Version), b.(*v1.Version), scope) + }); err != nil { + return err + } + if err := s.AddGeneratedConversionFunc((*v1.Version)(nil), (*Version)(nil), func(a, b interface{}, scope conversion.Scope) error { + return Convert_v1_Version_To_v1beta1_Version(a.(*v1.Version), b.(*Version), scope) + }); err != nil { + return err + } + if err := s.AddGeneratedConversionFunc((*VirtualMachineOptions)(nil), (*v1.VirtualMachineOptions)(nil), func(a, b interface{}, scope conversion.Scope) error { + return Convert_v1beta1_VirtualMachineOptions_To_v1_VirtualMachineOptions(a.(*VirtualMachineOptions), b.(*v1.VirtualMachineOptions), scope) + }); err != nil { + return err + } + if err := s.AddGeneratedConversionFunc((*v1.VirtualMachineOptions)(nil), (*VirtualMachineOptions)(nil), func(a, b interface{}, scope conversion.Scope) error { + return Convert_v1_VirtualMachineOptions_To_v1beta1_VirtualMachineOptions(a.(*v1.VirtualMachineOptions), b.(*VirtualMachineOptions), scope) + }); err != nil { + return err + } + return nil +} + +func autoConvert_v1beta1_ApplicationAwareConfigurations_To_v1_ApplicationAwareConfigurations(in *ApplicationAwareConfigurations, out *v1.ApplicationAwareConfigurations, s conversion.Scope) error { + out.VmiCalcConfigName = (*v1alpha1.VmiCalcConfigName)(unsafe.Pointer(in.VmiCalcConfigName)) + out.NamespaceSelector = (*metav1.LabelSelector)(unsafe.Pointer(in.NamespaceSelector)) + out.AllowApplicationAwareClusterResourceQuota = in.AllowApplicationAwareClusterResourceQuota + return nil +} + +// Convert_v1beta1_ApplicationAwareConfigurations_To_v1_ApplicationAwareConfigurations is an autogenerated conversion function. +func Convert_v1beta1_ApplicationAwareConfigurations_To_v1_ApplicationAwareConfigurations(in *ApplicationAwareConfigurations, out *v1.ApplicationAwareConfigurations, s conversion.Scope) error { + return autoConvert_v1beta1_ApplicationAwareConfigurations_To_v1_ApplicationAwareConfigurations(in, out, s) +} + +func autoConvert_v1_ApplicationAwareConfigurations_To_v1beta1_ApplicationAwareConfigurations(in *v1.ApplicationAwareConfigurations, out *ApplicationAwareConfigurations, s conversion.Scope) error { + out.VmiCalcConfigName = (*v1alpha1.VmiCalcConfigName)(unsafe.Pointer(in.VmiCalcConfigName)) + out.NamespaceSelector = (*metav1.LabelSelector)(unsafe.Pointer(in.NamespaceSelector)) + out.AllowApplicationAwareClusterResourceQuota = in.AllowApplicationAwareClusterResourceQuota + return nil +} + +// Convert_v1_ApplicationAwareConfigurations_To_v1beta1_ApplicationAwareConfigurations is an autogenerated conversion function. +func Convert_v1_ApplicationAwareConfigurations_To_v1beta1_ApplicationAwareConfigurations(in *v1.ApplicationAwareConfigurations, out *ApplicationAwareConfigurations, s conversion.Scope) error { + return autoConvert_v1_ApplicationAwareConfigurations_To_v1beta1_ApplicationAwareConfigurations(in, out, s) +} + +func autoConvert_v1beta1_CertRotateConfigCA_To_v1_CertRotateConfigCA(in *CertRotateConfigCA, out *v1.CertRotateConfigCA, s conversion.Scope) error { + out.Duration = (*metav1.Duration)(unsafe.Pointer(in.Duration)) + out.RenewBefore = (*metav1.Duration)(unsafe.Pointer(in.RenewBefore)) + return nil +} + +// Convert_v1beta1_CertRotateConfigCA_To_v1_CertRotateConfigCA is an autogenerated conversion function. +func Convert_v1beta1_CertRotateConfigCA_To_v1_CertRotateConfigCA(in *CertRotateConfigCA, out *v1.CertRotateConfigCA, s conversion.Scope) error { + return autoConvert_v1beta1_CertRotateConfigCA_To_v1_CertRotateConfigCA(in, out, s) +} + +func autoConvert_v1_CertRotateConfigCA_To_v1beta1_CertRotateConfigCA(in *v1.CertRotateConfigCA, out *CertRotateConfigCA, s conversion.Scope) error { + out.Duration = (*metav1.Duration)(unsafe.Pointer(in.Duration)) + out.RenewBefore = (*metav1.Duration)(unsafe.Pointer(in.RenewBefore)) + return nil +} + +// Convert_v1_CertRotateConfigCA_To_v1beta1_CertRotateConfigCA is an autogenerated conversion function. +func Convert_v1_CertRotateConfigCA_To_v1beta1_CertRotateConfigCA(in *v1.CertRotateConfigCA, out *CertRotateConfigCA, s conversion.Scope) error { + return autoConvert_v1_CertRotateConfigCA_To_v1beta1_CertRotateConfigCA(in, out, s) +} + +func autoConvert_v1beta1_CertRotateConfigServer_To_v1_CertRotateConfigServer(in *CertRotateConfigServer, out *v1.CertRotateConfigServer, s conversion.Scope) error { + out.Duration = (*metav1.Duration)(unsafe.Pointer(in.Duration)) + out.RenewBefore = (*metav1.Duration)(unsafe.Pointer(in.RenewBefore)) + return nil +} + +// Convert_v1beta1_CertRotateConfigServer_To_v1_CertRotateConfigServer is an autogenerated conversion function. +func Convert_v1beta1_CertRotateConfigServer_To_v1_CertRotateConfigServer(in *CertRotateConfigServer, out *v1.CertRotateConfigServer, s conversion.Scope) error { + return autoConvert_v1beta1_CertRotateConfigServer_To_v1_CertRotateConfigServer(in, out, s) +} + +func autoConvert_v1_CertRotateConfigServer_To_v1beta1_CertRotateConfigServer(in *v1.CertRotateConfigServer, out *CertRotateConfigServer, s conversion.Scope) error { + out.Duration = (*metav1.Duration)(unsafe.Pointer(in.Duration)) + out.RenewBefore = (*metav1.Duration)(unsafe.Pointer(in.RenewBefore)) + return nil +} + +// Convert_v1_CertRotateConfigServer_To_v1beta1_CertRotateConfigServer is an autogenerated conversion function. +func Convert_v1_CertRotateConfigServer_To_v1beta1_CertRotateConfigServer(in *v1.CertRotateConfigServer, out *CertRotateConfigServer, s conversion.Scope) error { + return autoConvert_v1_CertRotateConfigServer_To_v1beta1_CertRotateConfigServer(in, out, s) +} + +func autoConvert_v1beta1_DataImportCronStatus_To_v1_DataImportCronStatus(in *DataImportCronStatus, out *v1.DataImportCronStatus, s conversion.Scope) error { + out.Conditions = *(*[]metav1.Condition)(unsafe.Pointer(&in.Conditions)) + out.CommonTemplate = in.CommonTemplate + out.Modified = in.Modified + out.OriginalSupportedArchitectures = in.OriginalSupportedArchitectures + return nil +} + +// Convert_v1beta1_DataImportCronStatus_To_v1_DataImportCronStatus is an autogenerated conversion function. +func Convert_v1beta1_DataImportCronStatus_To_v1_DataImportCronStatus(in *DataImportCronStatus, out *v1.DataImportCronStatus, s conversion.Scope) error { + return autoConvert_v1beta1_DataImportCronStatus_To_v1_DataImportCronStatus(in, out, s) +} + +func autoConvert_v1_DataImportCronStatus_To_v1beta1_DataImportCronStatus(in *v1.DataImportCronStatus, out *DataImportCronStatus, s conversion.Scope) error { + out.Conditions = *(*[]metav1.Condition)(unsafe.Pointer(&in.Conditions)) + out.CommonTemplate = in.CommonTemplate + out.Modified = in.Modified + out.OriginalSupportedArchitectures = in.OriginalSupportedArchitectures + return nil +} + +// Convert_v1_DataImportCronStatus_To_v1beta1_DataImportCronStatus is an autogenerated conversion function. +func Convert_v1_DataImportCronStatus_To_v1beta1_DataImportCronStatus(in *v1.DataImportCronStatus, out *DataImportCronStatus, s conversion.Scope) error { + return autoConvert_v1_DataImportCronStatus_To_v1beta1_DataImportCronStatus(in, out, s) +} + +func autoConvert_v1beta1_DataImportCronTemplate_To_v1_DataImportCronTemplate(in *DataImportCronTemplate, out *v1.DataImportCronTemplate, s conversion.Scope) error { + out.ObjectMeta = in.ObjectMeta + out.Spec = (*corev1beta1.DataImportCronSpec)(unsafe.Pointer(in.Spec)) + return nil +} + +// Convert_v1beta1_DataImportCronTemplate_To_v1_DataImportCronTemplate is an autogenerated conversion function. +func Convert_v1beta1_DataImportCronTemplate_To_v1_DataImportCronTemplate(in *DataImportCronTemplate, out *v1.DataImportCronTemplate, s conversion.Scope) error { + return autoConvert_v1beta1_DataImportCronTemplate_To_v1_DataImportCronTemplate(in, out, s) +} + +func autoConvert_v1_DataImportCronTemplate_To_v1beta1_DataImportCronTemplate(in *v1.DataImportCronTemplate, out *DataImportCronTemplate, s conversion.Scope) error { + out.ObjectMeta = in.ObjectMeta + out.Spec = (*corev1beta1.DataImportCronSpec)(unsafe.Pointer(in.Spec)) + return nil +} + +// Convert_v1_DataImportCronTemplate_To_v1beta1_DataImportCronTemplate is an autogenerated conversion function. +func Convert_v1_DataImportCronTemplate_To_v1beta1_DataImportCronTemplate(in *v1.DataImportCronTemplate, out *DataImportCronTemplate, s conversion.Scope) error { + return autoConvert_v1_DataImportCronTemplate_To_v1beta1_DataImportCronTemplate(in, out, s) +} + +func autoConvert_v1beta1_DataImportCronTemplateStatus_To_v1_DataImportCronTemplateStatus(in *DataImportCronTemplateStatus, out *v1.DataImportCronTemplateStatus, s conversion.Scope) error { + if err := Convert_v1beta1_DataImportCronTemplate_To_v1_DataImportCronTemplate(&in.DataImportCronTemplate, &out.DataImportCronTemplate, s); err != nil { + return err + } + if err := Convert_v1beta1_DataImportCronStatus_To_v1_DataImportCronStatus(&in.Status, &out.Status, s); err != nil { + return err + } + return nil +} + +// Convert_v1beta1_DataImportCronTemplateStatus_To_v1_DataImportCronTemplateStatus is an autogenerated conversion function. +func Convert_v1beta1_DataImportCronTemplateStatus_To_v1_DataImportCronTemplateStatus(in *DataImportCronTemplateStatus, out *v1.DataImportCronTemplateStatus, s conversion.Scope) error { + return autoConvert_v1beta1_DataImportCronTemplateStatus_To_v1_DataImportCronTemplateStatus(in, out, s) +} + +func autoConvert_v1_DataImportCronTemplateStatus_To_v1beta1_DataImportCronTemplateStatus(in *v1.DataImportCronTemplateStatus, out *DataImportCronTemplateStatus, s conversion.Scope) error { + if err := Convert_v1_DataImportCronTemplate_To_v1beta1_DataImportCronTemplate(&in.DataImportCronTemplate, &out.DataImportCronTemplate, s); err != nil { + return err + } + if err := Convert_v1_DataImportCronStatus_To_v1beta1_DataImportCronStatus(&in.Status, &out.Status, s); err != nil { + return err + } + return nil +} + +// Convert_v1_DataImportCronTemplateStatus_To_v1beta1_DataImportCronTemplateStatus is an autogenerated conversion function. +func Convert_v1_DataImportCronTemplateStatus_To_v1beta1_DataImportCronTemplateStatus(in *v1.DataImportCronTemplateStatus, out *DataImportCronTemplateStatus, s conversion.Scope) error { + return autoConvert_v1_DataImportCronTemplateStatus_To_v1beta1_DataImportCronTemplateStatus(in, out, s) +} + +func autoConvert_v1beta1_HigherWorkloadDensityConfiguration_To_v1_HigherWorkloadDensityConfiguration(in *HigherWorkloadDensityConfiguration, out *v1.HigherWorkloadDensityConfiguration, s conversion.Scope) error { + out.MemoryOvercommitPercentage = in.MemoryOvercommitPercentage + return nil +} + +// Convert_v1beta1_HigherWorkloadDensityConfiguration_To_v1_HigherWorkloadDensityConfiguration is an autogenerated conversion function. +func Convert_v1beta1_HigherWorkloadDensityConfiguration_To_v1_HigherWorkloadDensityConfiguration(in *HigherWorkloadDensityConfiguration, out *v1.HigherWorkloadDensityConfiguration, s conversion.Scope) error { + return autoConvert_v1beta1_HigherWorkloadDensityConfiguration_To_v1_HigherWorkloadDensityConfiguration(in, out, s) +} + +func autoConvert_v1_HigherWorkloadDensityConfiguration_To_v1beta1_HigherWorkloadDensityConfiguration(in *v1.HigherWorkloadDensityConfiguration, out *HigherWorkloadDensityConfiguration, s conversion.Scope) error { + out.MemoryOvercommitPercentage = in.MemoryOvercommitPercentage + return nil +} + +// Convert_v1_HigherWorkloadDensityConfiguration_To_v1beta1_HigherWorkloadDensityConfiguration is an autogenerated conversion function. +func Convert_v1_HigherWorkloadDensityConfiguration_To_v1beta1_HigherWorkloadDensityConfiguration(in *v1.HigherWorkloadDensityConfiguration, out *HigherWorkloadDensityConfiguration, s conversion.Scope) error { + return autoConvert_v1_HigherWorkloadDensityConfiguration_To_v1beta1_HigherWorkloadDensityConfiguration(in, out, s) +} + +func autoConvert_v1beta1_HyperConverged_To_v1_HyperConverged(in *HyperConverged, out *v1.HyperConverged, s conversion.Scope) error { + out.ObjectMeta = in.ObjectMeta + if err := Convert_v1beta1_HyperConvergedSpec_To_v1_HyperConvergedSpec(&in.Spec, &out.Spec, s); err != nil { + return err + } + if err := Convert_v1beta1_HyperConvergedStatus_To_v1_HyperConvergedStatus(&in.Status, &out.Status, s); err != nil { + return err + } + return nil +} + +// Convert_v1beta1_HyperConverged_To_v1_HyperConverged is an autogenerated conversion function. +func Convert_v1beta1_HyperConverged_To_v1_HyperConverged(in *HyperConverged, out *v1.HyperConverged, s conversion.Scope) error { + return autoConvert_v1beta1_HyperConverged_To_v1_HyperConverged(in, out, s) +} + +func autoConvert_v1_HyperConverged_To_v1beta1_HyperConverged(in *v1.HyperConverged, out *HyperConverged, s conversion.Scope) error { + out.ObjectMeta = in.ObjectMeta + if err := Convert_v1_HyperConvergedSpec_To_v1beta1_HyperConvergedSpec(&in.Spec, &out.Spec, s); err != nil { + return err + } + if err := Convert_v1_HyperConvergedStatus_To_v1beta1_HyperConvergedStatus(&in.Status, &out.Status, s); err != nil { + return err + } + return nil +} + +// Convert_v1_HyperConverged_To_v1beta1_HyperConverged is an autogenerated conversion function. +func Convert_v1_HyperConverged_To_v1beta1_HyperConverged(in *v1.HyperConverged, out *HyperConverged, s conversion.Scope) error { + return autoConvert_v1_HyperConverged_To_v1beta1_HyperConverged(in, out, s) +} + +func autoConvert_v1beta1_HyperConvergedCertConfig_To_v1_HyperConvergedCertConfig(in *HyperConvergedCertConfig, out *v1.HyperConvergedCertConfig, s conversion.Scope) error { + if err := Convert_v1beta1_CertRotateConfigCA_To_v1_CertRotateConfigCA(&in.CA, &out.CA, s); err != nil { + return err + } + if err := Convert_v1beta1_CertRotateConfigServer_To_v1_CertRotateConfigServer(&in.Server, &out.Server, s); err != nil { + return err + } + return nil +} + +// Convert_v1beta1_HyperConvergedCertConfig_To_v1_HyperConvergedCertConfig is an autogenerated conversion function. +func Convert_v1beta1_HyperConvergedCertConfig_To_v1_HyperConvergedCertConfig(in *HyperConvergedCertConfig, out *v1.HyperConvergedCertConfig, s conversion.Scope) error { + return autoConvert_v1beta1_HyperConvergedCertConfig_To_v1_HyperConvergedCertConfig(in, out, s) +} + +func autoConvert_v1_HyperConvergedCertConfig_To_v1beta1_HyperConvergedCertConfig(in *v1.HyperConvergedCertConfig, out *HyperConvergedCertConfig, s conversion.Scope) error { + if err := Convert_v1_CertRotateConfigCA_To_v1beta1_CertRotateConfigCA(&in.CA, &out.CA, s); err != nil { + return err + } + if err := Convert_v1_CertRotateConfigServer_To_v1beta1_CertRotateConfigServer(&in.Server, &out.Server, s); err != nil { + return err + } + return nil +} + +// Convert_v1_HyperConvergedCertConfig_To_v1beta1_HyperConvergedCertConfig is an autogenerated conversion function. +func Convert_v1_HyperConvergedCertConfig_To_v1beta1_HyperConvergedCertConfig(in *v1.HyperConvergedCertConfig, out *HyperConvergedCertConfig, s conversion.Scope) error { + return autoConvert_v1_HyperConvergedCertConfig_To_v1beta1_HyperConvergedCertConfig(in, out, s) +} + +func autoConvert_v1beta1_HyperConvergedConfig_To_v1_HyperConvergedConfig(in *HyperConvergedConfig, out *v1.HyperConvergedConfig, s conversion.Scope) error { + out.NodePlacement = (*api.NodePlacement)(unsafe.Pointer(in.NodePlacement)) + return nil +} + +// Convert_v1beta1_HyperConvergedConfig_To_v1_HyperConvergedConfig is an autogenerated conversion function. +func Convert_v1beta1_HyperConvergedConfig_To_v1_HyperConvergedConfig(in *HyperConvergedConfig, out *v1.HyperConvergedConfig, s conversion.Scope) error { + return autoConvert_v1beta1_HyperConvergedConfig_To_v1_HyperConvergedConfig(in, out, s) +} + +func autoConvert_v1_HyperConvergedConfig_To_v1beta1_HyperConvergedConfig(in *v1.HyperConvergedConfig, out *HyperConvergedConfig, s conversion.Scope) error { + out.NodePlacement = (*api.NodePlacement)(unsafe.Pointer(in.NodePlacement)) + return nil +} + +// Convert_v1_HyperConvergedConfig_To_v1beta1_HyperConvergedConfig is an autogenerated conversion function. +func Convert_v1_HyperConvergedConfig_To_v1beta1_HyperConvergedConfig(in *v1.HyperConvergedConfig, out *HyperConvergedConfig, s conversion.Scope) error { + return autoConvert_v1_HyperConvergedConfig_To_v1beta1_HyperConvergedConfig(in, out, s) +} + +func autoConvert_v1beta1_HyperConvergedList_To_v1_HyperConvergedList(in *HyperConvergedList, out *v1.HyperConvergedList, s conversion.Scope) error { + out.ListMeta = in.ListMeta + if in.Items != nil { + in, out := &in.Items, &out.Items + *out = make([]v1.HyperConverged, len(*in)) + for i := range *in { + if err := Convert_v1beta1_HyperConverged_To_v1_HyperConverged(&(*in)[i], &(*out)[i], s); err != nil { + return err + } + } + } else { + out.Items = nil + } + return nil +} + +// Convert_v1beta1_HyperConvergedList_To_v1_HyperConvergedList is an autogenerated conversion function. +func Convert_v1beta1_HyperConvergedList_To_v1_HyperConvergedList(in *HyperConvergedList, out *v1.HyperConvergedList, s conversion.Scope) error { + return autoConvert_v1beta1_HyperConvergedList_To_v1_HyperConvergedList(in, out, s) +} + +func autoConvert_v1_HyperConvergedList_To_v1beta1_HyperConvergedList(in *v1.HyperConvergedList, out *HyperConvergedList, s conversion.Scope) error { + out.ListMeta = in.ListMeta + if in.Items != nil { + in, out := &in.Items, &out.Items + *out = make([]HyperConverged, len(*in)) + for i := range *in { + if err := Convert_v1_HyperConverged_To_v1beta1_HyperConverged(&(*in)[i], &(*out)[i], s); err != nil { + return err + } + } + } else { + out.Items = nil + } + return nil +} + +// Convert_v1_HyperConvergedList_To_v1beta1_HyperConvergedList is an autogenerated conversion function. +func Convert_v1_HyperConvergedList_To_v1beta1_HyperConvergedList(in *v1.HyperConvergedList, out *HyperConvergedList, s conversion.Scope) error { + return autoConvert_v1_HyperConvergedList_To_v1beta1_HyperConvergedList(in, out, s) +} + +func autoConvert_v1beta1_HyperConvergedObsoleteCPUs_To_v1_HyperConvergedObsoleteCPUs(in *HyperConvergedObsoleteCPUs, out *v1.HyperConvergedObsoleteCPUs, s conversion.Scope) error { + // INFO: in.MinCPUModel opted out of conversion generation + out.CPUModels = *(*[]string)(unsafe.Pointer(&in.CPUModels)) + return nil +} + +// Convert_v1beta1_HyperConvergedObsoleteCPUs_To_v1_HyperConvergedObsoleteCPUs is an autogenerated conversion function. +func Convert_v1beta1_HyperConvergedObsoleteCPUs_To_v1_HyperConvergedObsoleteCPUs(in *HyperConvergedObsoleteCPUs, out *v1.HyperConvergedObsoleteCPUs, s conversion.Scope) error { + return autoConvert_v1beta1_HyperConvergedObsoleteCPUs_To_v1_HyperConvergedObsoleteCPUs(in, out, s) +} + +func autoConvert_v1_HyperConvergedObsoleteCPUs_To_v1beta1_HyperConvergedObsoleteCPUs(in *v1.HyperConvergedObsoleteCPUs, out *HyperConvergedObsoleteCPUs, s conversion.Scope) error { + out.CPUModels = *(*[]string)(unsafe.Pointer(&in.CPUModels)) + return nil +} + +// Convert_v1_HyperConvergedObsoleteCPUs_To_v1beta1_HyperConvergedObsoleteCPUs is an autogenerated conversion function. +func Convert_v1_HyperConvergedObsoleteCPUs_To_v1beta1_HyperConvergedObsoleteCPUs(in *v1.HyperConvergedObsoleteCPUs, out *HyperConvergedObsoleteCPUs, s conversion.Scope) error { + return autoConvert_v1_HyperConvergedObsoleteCPUs_To_v1beta1_HyperConvergedObsoleteCPUs(in, out, s) +} + +func autoConvert_v1beta1_HyperConvergedSpec_To_v1_HyperConvergedSpec(in *HyperConvergedSpec, out *v1.HyperConvergedSpec, s conversion.Scope) error { + // INFO: in.LocalStorageClassName opted out of conversion generation + out.TuningPolicy = v1.HyperConvergedTuningPolicy(in.TuningPolicy) + if err := Convert_v1beta1_HyperConvergedConfig_To_v1_HyperConvergedConfig(&in.Infra, &out.Infra, s); err != nil { + return err + } + if err := Convert_v1beta1_HyperConvergedConfig_To_v1_HyperConvergedConfig(&in.Workloads, &out.Workloads, s); err != nil { + return err + } + // INFO: in.FeatureGates opted out of conversion generation + if err := Convert_v1beta1_LiveMigrationConfigurations_To_v1_LiveMigrationConfigurations(&in.LiveMigrationConfig, &out.LiveMigrationConfig, s); err != nil { + return err + } + out.PermittedHostDevices = (*v1.PermittedHostDevices)(unsafe.Pointer(in.PermittedHostDevices)) + if in.MediatedDevicesConfiguration != nil { + in, out := &in.MediatedDevicesConfiguration, &out.MediatedDevicesConfiguration + *out = new(v1.MediatedDevicesConfiguration) + if err := Convert_v1beta1_MediatedDevicesConfiguration_To_v1_MediatedDevicesConfiguration(*in, *out, s); err != nil { + return err + } + } else { + out.MediatedDevicesConfiguration = nil + } + if err := Convert_v1beta1_HyperConvergedCertConfig_To_v1_HyperConvergedCertConfig(&in.CertConfig, &out.CertConfig, s); err != nil { + return err + } + out.ResourceRequirements = (*v1.OperandResourceRequirements)(unsafe.Pointer(in.ResourceRequirements)) + out.ScratchSpaceStorageClass = (*string)(unsafe.Pointer(in.ScratchSpaceStorageClass)) + // INFO: in.VddkInitImage opted out of conversion generation + out.DefaultCPUModel = (*string)(unsafe.Pointer(in.DefaultCPUModel)) + out.DefaultRuntimeClass = (*string)(unsafe.Pointer(in.DefaultRuntimeClass)) + if in.ObsoleteCPUs != nil { + in, out := &in.ObsoleteCPUs, &out.ObsoleteCPUs + *out = new(v1.HyperConvergedObsoleteCPUs) + if err := Convert_v1beta1_HyperConvergedObsoleteCPUs_To_v1_HyperConvergedObsoleteCPUs(*in, *out, s); err != nil { + return err + } + } else { + out.ObsoleteCPUs = nil + } + out.CommonTemplatesNamespace = (*string)(unsafe.Pointer(in.CommonTemplatesNamespace)) + out.StorageImport = (*v1.StorageImportConfig)(unsafe.Pointer(in.StorageImport)) + if err := Convert_v1beta1_HyperConvergedWorkloadUpdateStrategy_To_v1_HyperConvergedWorkloadUpdateStrategy(&in.WorkloadUpdateStrategy, &out.WorkloadUpdateStrategy, s); err != nil { + return err + } + out.DataImportCronTemplates = *(*[]v1.DataImportCronTemplate)(unsafe.Pointer(&in.DataImportCronTemplates)) + out.FilesystemOverhead = (*corev1beta1.FilesystemOverhead)(unsafe.Pointer(in.FilesystemOverhead)) + out.UninstallStrategy = v1.HyperConvergedUninstallStrategy(in.UninstallStrategy) + out.LogVerbosityConfig = (*v1.LogVerbosityConfiguration)(unsafe.Pointer(in.LogVerbosityConfig)) + out.TLSSecurityProfile = (*configv1.TLSSecurityProfile)(unsafe.Pointer(in.TLSSecurityProfile)) + // INFO: in.TektonPipelinesNamespace opted out of conversion generation + // INFO: in.TektonTasksNamespace opted out of conversion generation + out.KubeSecondaryDNSNameServerIP = (*string)(unsafe.Pointer(in.KubeSecondaryDNSNameServerIP)) + out.KubeMacPoolConfiguration = (*v1.KubeMacPoolConfig)(unsafe.Pointer(in.KubeMacPoolConfiguration)) + out.EvictionStrategy = (*corev1.EvictionStrategy)(unsafe.Pointer(in.EvictionStrategy)) + out.VMStateStorageClass = (*string)(unsafe.Pointer(in.VMStateStorageClass)) + out.VirtualMachineOptions = (*v1.VirtualMachineOptions)(unsafe.Pointer(in.VirtualMachineOptions)) + out.CommonBootImageNamespace = (*string)(unsafe.Pointer(in.CommonBootImageNamespace)) + out.KSMConfiguration = (*corev1.KSMConfiguration)(unsafe.Pointer(in.KSMConfiguration)) + out.NetworkBinding = *(*map[string]corev1.InterfaceBindingPlugin)(unsafe.Pointer(&in.NetworkBinding)) + out.ApplicationAwareConfig = (*v1.ApplicationAwareConfigurations)(unsafe.Pointer(in.ApplicationAwareConfig)) + out.HigherWorkloadDensity = (*v1.HigherWorkloadDensityConfiguration)(unsafe.Pointer(in.HigherWorkloadDensity)) + out.EnableCommonBootImageImport = (*bool)(unsafe.Pointer(in.EnableCommonBootImageImport)) + out.InstancetypeConfig = (*corev1.InstancetypeConfiguration)(unsafe.Pointer(in.InstancetypeConfig)) + out.CommonInstancetypesDeployment = (*corev1.CommonInstancetypesDeployment)(unsafe.Pointer(in.CommonInstancetypesDeployment)) + out.DeployVMConsoleProxy = (*bool)(unsafe.Pointer(in.DeployVMConsoleProxy)) + out.EnableApplicationAwareQuota = (*bool)(unsafe.Pointer(in.EnableApplicationAwareQuota)) + out.LiveUpdateConfiguration = (*corev1.LiveUpdateConfiguration)(unsafe.Pointer(in.LiveUpdateConfiguration)) + return nil +} + +// Convert_v1beta1_HyperConvergedSpec_To_v1_HyperConvergedSpec is an autogenerated conversion function. +func Convert_v1beta1_HyperConvergedSpec_To_v1_HyperConvergedSpec(in *HyperConvergedSpec, out *v1.HyperConvergedSpec, s conversion.Scope) error { + return autoConvert_v1beta1_HyperConvergedSpec_To_v1_HyperConvergedSpec(in, out, s) +} + +func autoConvert_v1_HyperConvergedSpec_To_v1beta1_HyperConvergedSpec(in *v1.HyperConvergedSpec, out *HyperConvergedSpec, s conversion.Scope) error { + out.TuningPolicy = HyperConvergedTuningPolicy(in.TuningPolicy) + if err := Convert_v1_HyperConvergedConfig_To_v1beta1_HyperConvergedConfig(&in.Infra, &out.Infra, s); err != nil { + return err + } + if err := Convert_v1_HyperConvergedConfig_To_v1beta1_HyperConvergedConfig(&in.Workloads, &out.Workloads, s); err != nil { + return err + } + // INFO: in.FeatureGates opted out of conversion generation + if err := Convert_v1_LiveMigrationConfigurations_To_v1beta1_LiveMigrationConfigurations(&in.LiveMigrationConfig, &out.LiveMigrationConfig, s); err != nil { + return err + } + out.PermittedHostDevices = (*PermittedHostDevices)(unsafe.Pointer(in.PermittedHostDevices)) + if in.MediatedDevicesConfiguration != nil { + in, out := &in.MediatedDevicesConfiguration, &out.MediatedDevicesConfiguration + *out = new(MediatedDevicesConfiguration) + if err := Convert_v1_MediatedDevicesConfiguration_To_v1beta1_MediatedDevicesConfiguration(*in, *out, s); err != nil { + return err + } + } else { + out.MediatedDevicesConfiguration = nil + } + if err := Convert_v1_HyperConvergedCertConfig_To_v1beta1_HyperConvergedCertConfig(&in.CertConfig, &out.CertConfig, s); err != nil { + return err + } + out.ResourceRequirements = (*OperandResourceRequirements)(unsafe.Pointer(in.ResourceRequirements)) + out.ScratchSpaceStorageClass = (*string)(unsafe.Pointer(in.ScratchSpaceStorageClass)) + out.DefaultCPUModel = (*string)(unsafe.Pointer(in.DefaultCPUModel)) + out.DefaultRuntimeClass = (*string)(unsafe.Pointer(in.DefaultRuntimeClass)) + if in.ObsoleteCPUs != nil { + in, out := &in.ObsoleteCPUs, &out.ObsoleteCPUs + *out = new(HyperConvergedObsoleteCPUs) + if err := Convert_v1_HyperConvergedObsoleteCPUs_To_v1beta1_HyperConvergedObsoleteCPUs(*in, *out, s); err != nil { + return err + } + } else { + out.ObsoleteCPUs = nil + } + out.CommonTemplatesNamespace = (*string)(unsafe.Pointer(in.CommonTemplatesNamespace)) + out.StorageImport = (*StorageImportConfig)(unsafe.Pointer(in.StorageImport)) + if err := Convert_v1_HyperConvergedWorkloadUpdateStrategy_To_v1beta1_HyperConvergedWorkloadUpdateStrategy(&in.WorkloadUpdateStrategy, &out.WorkloadUpdateStrategy, s); err != nil { + return err + } + out.DataImportCronTemplates = *(*[]DataImportCronTemplate)(unsafe.Pointer(&in.DataImportCronTemplates)) + out.FilesystemOverhead = (*corev1beta1.FilesystemOverhead)(unsafe.Pointer(in.FilesystemOverhead)) + out.UninstallStrategy = HyperConvergedUninstallStrategy(in.UninstallStrategy) + out.LogVerbosityConfig = (*LogVerbosityConfiguration)(unsafe.Pointer(in.LogVerbosityConfig)) + out.TLSSecurityProfile = (*configv1.TLSSecurityProfile)(unsafe.Pointer(in.TLSSecurityProfile)) + out.KubeSecondaryDNSNameServerIP = (*string)(unsafe.Pointer(in.KubeSecondaryDNSNameServerIP)) + out.KubeMacPoolConfiguration = (*KubeMacPoolConfig)(unsafe.Pointer(in.KubeMacPoolConfiguration)) + out.EvictionStrategy = (*corev1.EvictionStrategy)(unsafe.Pointer(in.EvictionStrategy)) + out.VMStateStorageClass = (*string)(unsafe.Pointer(in.VMStateStorageClass)) + out.VirtualMachineOptions = (*VirtualMachineOptions)(unsafe.Pointer(in.VirtualMachineOptions)) + out.CommonBootImageNamespace = (*string)(unsafe.Pointer(in.CommonBootImageNamespace)) + out.KSMConfiguration = (*corev1.KSMConfiguration)(unsafe.Pointer(in.KSMConfiguration)) + out.NetworkBinding = *(*map[string]corev1.InterfaceBindingPlugin)(unsafe.Pointer(&in.NetworkBinding)) + out.ApplicationAwareConfig = (*ApplicationAwareConfigurations)(unsafe.Pointer(in.ApplicationAwareConfig)) + out.HigherWorkloadDensity = (*HigherWorkloadDensityConfiguration)(unsafe.Pointer(in.HigherWorkloadDensity)) + out.EnableCommonBootImageImport = (*bool)(unsafe.Pointer(in.EnableCommonBootImageImport)) + out.InstancetypeConfig = (*corev1.InstancetypeConfiguration)(unsafe.Pointer(in.InstancetypeConfig)) + out.CommonInstancetypesDeployment = (*corev1.CommonInstancetypesDeployment)(unsafe.Pointer(in.CommonInstancetypesDeployment)) + out.DeployVMConsoleProxy = (*bool)(unsafe.Pointer(in.DeployVMConsoleProxy)) + out.EnableApplicationAwareQuota = (*bool)(unsafe.Pointer(in.EnableApplicationAwareQuota)) + out.LiveUpdateConfiguration = (*corev1.LiveUpdateConfiguration)(unsafe.Pointer(in.LiveUpdateConfiguration)) + return nil +} + +// Convert_v1_HyperConvergedSpec_To_v1beta1_HyperConvergedSpec is an autogenerated conversion function. +func Convert_v1_HyperConvergedSpec_To_v1beta1_HyperConvergedSpec(in *v1.HyperConvergedSpec, out *HyperConvergedSpec, s conversion.Scope) error { + return autoConvert_v1_HyperConvergedSpec_To_v1beta1_HyperConvergedSpec(in, out, s) +} + +func autoConvert_v1beta1_HyperConvergedStatus_To_v1_HyperConvergedStatus(in *HyperConvergedStatus, out *v1.HyperConvergedStatus, s conversion.Scope) error { + out.Conditions = *(*[]metav1.Condition)(unsafe.Pointer(&in.Conditions)) + out.RelatedObjects = *(*[]apicorev1.ObjectReference)(unsafe.Pointer(&in.RelatedObjects)) + out.Versions = *(*[]v1.Version)(unsafe.Pointer(&in.Versions)) + out.ObservedGeneration = in.ObservedGeneration + out.DataImportSchedule = in.DataImportSchedule + out.DataImportCronTemplates = *(*[]v1.DataImportCronTemplateStatus)(unsafe.Pointer(&in.DataImportCronTemplates)) + out.SystemHealthStatus = in.SystemHealthStatus + out.InfrastructureHighlyAvailable = (*bool)(unsafe.Pointer(in.InfrastructureHighlyAvailable)) + if err := Convert_v1beta1_NodeInfoStatus_To_v1_NodeInfoStatus(&in.NodeInfo, &out.NodeInfo, s); err != nil { + return err + } + return nil +} + +// Convert_v1beta1_HyperConvergedStatus_To_v1_HyperConvergedStatus is an autogenerated conversion function. +func Convert_v1beta1_HyperConvergedStatus_To_v1_HyperConvergedStatus(in *HyperConvergedStatus, out *v1.HyperConvergedStatus, s conversion.Scope) error { + return autoConvert_v1beta1_HyperConvergedStatus_To_v1_HyperConvergedStatus(in, out, s) +} + +func autoConvert_v1_HyperConvergedStatus_To_v1beta1_HyperConvergedStatus(in *v1.HyperConvergedStatus, out *HyperConvergedStatus, s conversion.Scope) error { + out.Conditions = *(*[]metav1.Condition)(unsafe.Pointer(&in.Conditions)) + out.RelatedObjects = *(*[]apicorev1.ObjectReference)(unsafe.Pointer(&in.RelatedObjects)) + out.Versions = *(*[]Version)(unsafe.Pointer(&in.Versions)) + out.ObservedGeneration = in.ObservedGeneration + out.DataImportSchedule = in.DataImportSchedule + out.DataImportCronTemplates = *(*[]DataImportCronTemplateStatus)(unsafe.Pointer(&in.DataImportCronTemplates)) + out.SystemHealthStatus = in.SystemHealthStatus + out.InfrastructureHighlyAvailable = (*bool)(unsafe.Pointer(in.InfrastructureHighlyAvailable)) + if err := Convert_v1_NodeInfoStatus_To_v1beta1_NodeInfoStatus(&in.NodeInfo, &out.NodeInfo, s); err != nil { + return err + } + return nil +} + +// Convert_v1_HyperConvergedStatus_To_v1beta1_HyperConvergedStatus is an autogenerated conversion function. +func Convert_v1_HyperConvergedStatus_To_v1beta1_HyperConvergedStatus(in *v1.HyperConvergedStatus, out *HyperConvergedStatus, s conversion.Scope) error { + return autoConvert_v1_HyperConvergedStatus_To_v1beta1_HyperConvergedStatus(in, out, s) +} + +func autoConvert_v1beta1_HyperConvergedWorkloadUpdateStrategy_To_v1_HyperConvergedWorkloadUpdateStrategy(in *HyperConvergedWorkloadUpdateStrategy, out *v1.HyperConvergedWorkloadUpdateStrategy, s conversion.Scope) error { + out.WorkloadUpdateMethods = *(*[]string)(unsafe.Pointer(&in.WorkloadUpdateMethods)) + out.BatchEvictionSize = (*int)(unsafe.Pointer(in.BatchEvictionSize)) + out.BatchEvictionInterval = (*metav1.Duration)(unsafe.Pointer(in.BatchEvictionInterval)) + return nil +} + +// Convert_v1beta1_HyperConvergedWorkloadUpdateStrategy_To_v1_HyperConvergedWorkloadUpdateStrategy is an autogenerated conversion function. +func Convert_v1beta1_HyperConvergedWorkloadUpdateStrategy_To_v1_HyperConvergedWorkloadUpdateStrategy(in *HyperConvergedWorkloadUpdateStrategy, out *v1.HyperConvergedWorkloadUpdateStrategy, s conversion.Scope) error { + return autoConvert_v1beta1_HyperConvergedWorkloadUpdateStrategy_To_v1_HyperConvergedWorkloadUpdateStrategy(in, out, s) +} + +func autoConvert_v1_HyperConvergedWorkloadUpdateStrategy_To_v1beta1_HyperConvergedWorkloadUpdateStrategy(in *v1.HyperConvergedWorkloadUpdateStrategy, out *HyperConvergedWorkloadUpdateStrategy, s conversion.Scope) error { + out.WorkloadUpdateMethods = *(*[]string)(unsafe.Pointer(&in.WorkloadUpdateMethods)) + out.BatchEvictionSize = (*int)(unsafe.Pointer(in.BatchEvictionSize)) + out.BatchEvictionInterval = (*metav1.Duration)(unsafe.Pointer(in.BatchEvictionInterval)) + return nil +} + +// Convert_v1_HyperConvergedWorkloadUpdateStrategy_To_v1beta1_HyperConvergedWorkloadUpdateStrategy is an autogenerated conversion function. +func Convert_v1_HyperConvergedWorkloadUpdateStrategy_To_v1beta1_HyperConvergedWorkloadUpdateStrategy(in *v1.HyperConvergedWorkloadUpdateStrategy, out *HyperConvergedWorkloadUpdateStrategy, s conversion.Scope) error { + return autoConvert_v1_HyperConvergedWorkloadUpdateStrategy_To_v1beta1_HyperConvergedWorkloadUpdateStrategy(in, out, s) +} + +func autoConvert_v1beta1_KubeMacPoolConfig_To_v1_KubeMacPoolConfig(in *KubeMacPoolConfig, out *v1.KubeMacPoolConfig, s conversion.Scope) error { + out.RangeStart = (*string)(unsafe.Pointer(in.RangeStart)) + out.RangeEnd = (*string)(unsafe.Pointer(in.RangeEnd)) + return nil +} + +// Convert_v1beta1_KubeMacPoolConfig_To_v1_KubeMacPoolConfig is an autogenerated conversion function. +func Convert_v1beta1_KubeMacPoolConfig_To_v1_KubeMacPoolConfig(in *KubeMacPoolConfig, out *v1.KubeMacPoolConfig, s conversion.Scope) error { + return autoConvert_v1beta1_KubeMacPoolConfig_To_v1_KubeMacPoolConfig(in, out, s) +} + +func autoConvert_v1_KubeMacPoolConfig_To_v1beta1_KubeMacPoolConfig(in *v1.KubeMacPoolConfig, out *KubeMacPoolConfig, s conversion.Scope) error { + out.RangeStart = (*string)(unsafe.Pointer(in.RangeStart)) + out.RangeEnd = (*string)(unsafe.Pointer(in.RangeEnd)) + return nil +} + +// Convert_v1_KubeMacPoolConfig_To_v1beta1_KubeMacPoolConfig is an autogenerated conversion function. +func Convert_v1_KubeMacPoolConfig_To_v1beta1_KubeMacPoolConfig(in *v1.KubeMacPoolConfig, out *KubeMacPoolConfig, s conversion.Scope) error { + return autoConvert_v1_KubeMacPoolConfig_To_v1beta1_KubeMacPoolConfig(in, out, s) +} + +func autoConvert_v1beta1_LiveMigrationConfigurations_To_v1_LiveMigrationConfigurations(in *LiveMigrationConfigurations, out *v1.LiveMigrationConfigurations, s conversion.Scope) error { + out.ParallelMigrationsPerCluster = (*uint32)(unsafe.Pointer(in.ParallelMigrationsPerCluster)) + out.ParallelOutboundMigrationsPerNode = (*uint32)(unsafe.Pointer(in.ParallelOutboundMigrationsPerNode)) + out.BandwidthPerMigration = (*string)(unsafe.Pointer(in.BandwidthPerMigration)) + out.CompletionTimeoutPerGiB = (*int64)(unsafe.Pointer(in.CompletionTimeoutPerGiB)) + out.ProgressTimeout = (*int64)(unsafe.Pointer(in.ProgressTimeout)) + out.Network = (*string)(unsafe.Pointer(in.Network)) + out.AllowAutoConverge = (*bool)(unsafe.Pointer(in.AllowAutoConverge)) + out.AllowPostCopy = (*bool)(unsafe.Pointer(in.AllowPostCopy)) + return nil +} + +// Convert_v1beta1_LiveMigrationConfigurations_To_v1_LiveMigrationConfigurations is an autogenerated conversion function. +func Convert_v1beta1_LiveMigrationConfigurations_To_v1_LiveMigrationConfigurations(in *LiveMigrationConfigurations, out *v1.LiveMigrationConfigurations, s conversion.Scope) error { + return autoConvert_v1beta1_LiveMigrationConfigurations_To_v1_LiveMigrationConfigurations(in, out, s) +} + +func autoConvert_v1_LiveMigrationConfigurations_To_v1beta1_LiveMigrationConfigurations(in *v1.LiveMigrationConfigurations, out *LiveMigrationConfigurations, s conversion.Scope) error { + out.ParallelMigrationsPerCluster = (*uint32)(unsafe.Pointer(in.ParallelMigrationsPerCluster)) + out.ParallelOutboundMigrationsPerNode = (*uint32)(unsafe.Pointer(in.ParallelOutboundMigrationsPerNode)) + out.BandwidthPerMigration = (*string)(unsafe.Pointer(in.BandwidthPerMigration)) + out.CompletionTimeoutPerGiB = (*int64)(unsafe.Pointer(in.CompletionTimeoutPerGiB)) + out.ProgressTimeout = (*int64)(unsafe.Pointer(in.ProgressTimeout)) + out.Network = (*string)(unsafe.Pointer(in.Network)) + out.AllowAutoConverge = (*bool)(unsafe.Pointer(in.AllowAutoConverge)) + out.AllowPostCopy = (*bool)(unsafe.Pointer(in.AllowPostCopy)) + return nil +} + +// Convert_v1_LiveMigrationConfigurations_To_v1beta1_LiveMigrationConfigurations is an autogenerated conversion function. +func Convert_v1_LiveMigrationConfigurations_To_v1beta1_LiveMigrationConfigurations(in *v1.LiveMigrationConfigurations, out *LiveMigrationConfigurations, s conversion.Scope) error { + return autoConvert_v1_LiveMigrationConfigurations_To_v1beta1_LiveMigrationConfigurations(in, out, s) +} + +func autoConvert_v1beta1_LogVerbosityConfiguration_To_v1_LogVerbosityConfiguration(in *LogVerbosityConfiguration, out *v1.LogVerbosityConfiguration, s conversion.Scope) error { + out.Kubevirt = (*corev1.LogVerbosity)(unsafe.Pointer(in.Kubevirt)) + out.CDI = (*int32)(unsafe.Pointer(in.CDI)) + return nil +} + +// Convert_v1beta1_LogVerbosityConfiguration_To_v1_LogVerbosityConfiguration is an autogenerated conversion function. +func Convert_v1beta1_LogVerbosityConfiguration_To_v1_LogVerbosityConfiguration(in *LogVerbosityConfiguration, out *v1.LogVerbosityConfiguration, s conversion.Scope) error { + return autoConvert_v1beta1_LogVerbosityConfiguration_To_v1_LogVerbosityConfiguration(in, out, s) +} + +func autoConvert_v1_LogVerbosityConfiguration_To_v1beta1_LogVerbosityConfiguration(in *v1.LogVerbosityConfiguration, out *LogVerbosityConfiguration, s conversion.Scope) error { + out.Kubevirt = (*corev1.LogVerbosity)(unsafe.Pointer(in.Kubevirt)) + out.CDI = (*int32)(unsafe.Pointer(in.CDI)) + return nil +} + +// Convert_v1_LogVerbosityConfiguration_To_v1beta1_LogVerbosityConfiguration is an autogenerated conversion function. +func Convert_v1_LogVerbosityConfiguration_To_v1beta1_LogVerbosityConfiguration(in *v1.LogVerbosityConfiguration, out *LogVerbosityConfiguration, s conversion.Scope) error { + return autoConvert_v1_LogVerbosityConfiguration_To_v1beta1_LogVerbosityConfiguration(in, out, s) +} + +func autoConvert_v1beta1_MediatedDevicesConfiguration_To_v1_MediatedDevicesConfiguration(in *MediatedDevicesConfiguration, out *v1.MediatedDevicesConfiguration, s conversion.Scope) error { + out.MediatedDeviceTypes = *(*[]string)(unsafe.Pointer(&in.MediatedDeviceTypes)) + // INFO: in.MediatedDevicesTypes opted out of conversion generation + if in.NodeMediatedDeviceTypes != nil { + in, out := &in.NodeMediatedDeviceTypes, &out.NodeMediatedDeviceTypes + *out = make([]v1.NodeMediatedDeviceTypesConfig, len(*in)) + for i := range *in { + if err := Convert_v1beta1_NodeMediatedDeviceTypesConfig_To_v1_NodeMediatedDeviceTypesConfig(&(*in)[i], &(*out)[i], s); err != nil { + return err + } + } + } else { + out.NodeMediatedDeviceTypes = nil + } + return nil +} + +// Convert_v1beta1_MediatedDevicesConfiguration_To_v1_MediatedDevicesConfiguration is an autogenerated conversion function. +func Convert_v1beta1_MediatedDevicesConfiguration_To_v1_MediatedDevicesConfiguration(in *MediatedDevicesConfiguration, out *v1.MediatedDevicesConfiguration, s conversion.Scope) error { + return autoConvert_v1beta1_MediatedDevicesConfiguration_To_v1_MediatedDevicesConfiguration(in, out, s) +} + +func autoConvert_v1_MediatedDevicesConfiguration_To_v1beta1_MediatedDevicesConfiguration(in *v1.MediatedDevicesConfiguration, out *MediatedDevicesConfiguration, s conversion.Scope) error { + out.MediatedDeviceTypes = *(*[]string)(unsafe.Pointer(&in.MediatedDeviceTypes)) + if in.NodeMediatedDeviceTypes != nil { + in, out := &in.NodeMediatedDeviceTypes, &out.NodeMediatedDeviceTypes + *out = make([]NodeMediatedDeviceTypesConfig, len(*in)) + for i := range *in { + if err := Convert_v1_NodeMediatedDeviceTypesConfig_To_v1beta1_NodeMediatedDeviceTypesConfig(&(*in)[i], &(*out)[i], s); err != nil { + return err + } + } + } else { + out.NodeMediatedDeviceTypes = nil + } + return nil +} + +// Convert_v1_MediatedDevicesConfiguration_To_v1beta1_MediatedDevicesConfiguration is an autogenerated conversion function. +func Convert_v1_MediatedDevicesConfiguration_To_v1beta1_MediatedDevicesConfiguration(in *v1.MediatedDevicesConfiguration, out *MediatedDevicesConfiguration, s conversion.Scope) error { + return autoConvert_v1_MediatedDevicesConfiguration_To_v1beta1_MediatedDevicesConfiguration(in, out, s) +} + +func autoConvert_v1beta1_MediatedHostDevice_To_v1_MediatedHostDevice(in *MediatedHostDevice, out *v1.MediatedHostDevice, s conversion.Scope) error { + out.MDEVNameSelector = in.MDEVNameSelector + out.ResourceName = in.ResourceName + out.ExternalResourceProvider = in.ExternalResourceProvider + out.Disabled = in.Disabled + return nil +} + +// Convert_v1beta1_MediatedHostDevice_To_v1_MediatedHostDevice is an autogenerated conversion function. +func Convert_v1beta1_MediatedHostDevice_To_v1_MediatedHostDevice(in *MediatedHostDevice, out *v1.MediatedHostDevice, s conversion.Scope) error { + return autoConvert_v1beta1_MediatedHostDevice_To_v1_MediatedHostDevice(in, out, s) +} + +func autoConvert_v1_MediatedHostDevice_To_v1beta1_MediatedHostDevice(in *v1.MediatedHostDevice, out *MediatedHostDevice, s conversion.Scope) error { + out.MDEVNameSelector = in.MDEVNameSelector + out.ResourceName = in.ResourceName + out.ExternalResourceProvider = in.ExternalResourceProvider + out.Disabled = in.Disabled + return nil +} + +// Convert_v1_MediatedHostDevice_To_v1beta1_MediatedHostDevice is an autogenerated conversion function. +func Convert_v1_MediatedHostDevice_To_v1beta1_MediatedHostDevice(in *v1.MediatedHostDevice, out *MediatedHostDevice, s conversion.Scope) error { + return autoConvert_v1_MediatedHostDevice_To_v1beta1_MediatedHostDevice(in, out, s) +} + +func autoConvert_v1beta1_NodeInfoStatus_To_v1_NodeInfoStatus(in *NodeInfoStatus, out *v1.NodeInfoStatus, s conversion.Scope) error { + out.WorkloadsArchitectures = *(*[]string)(unsafe.Pointer(&in.WorkloadsArchitectures)) + out.ControlPlaneArchitectures = *(*[]string)(unsafe.Pointer(&in.ControlPlaneArchitectures)) + return nil +} + +// Convert_v1beta1_NodeInfoStatus_To_v1_NodeInfoStatus is an autogenerated conversion function. +func Convert_v1beta1_NodeInfoStatus_To_v1_NodeInfoStatus(in *NodeInfoStatus, out *v1.NodeInfoStatus, s conversion.Scope) error { + return autoConvert_v1beta1_NodeInfoStatus_To_v1_NodeInfoStatus(in, out, s) +} + +func autoConvert_v1_NodeInfoStatus_To_v1beta1_NodeInfoStatus(in *v1.NodeInfoStatus, out *NodeInfoStatus, s conversion.Scope) error { + out.WorkloadsArchitectures = *(*[]string)(unsafe.Pointer(&in.WorkloadsArchitectures)) + out.ControlPlaneArchitectures = *(*[]string)(unsafe.Pointer(&in.ControlPlaneArchitectures)) + return nil +} + +// Convert_v1_NodeInfoStatus_To_v1beta1_NodeInfoStatus is an autogenerated conversion function. +func Convert_v1_NodeInfoStatus_To_v1beta1_NodeInfoStatus(in *v1.NodeInfoStatus, out *NodeInfoStatus, s conversion.Scope) error { + return autoConvert_v1_NodeInfoStatus_To_v1beta1_NodeInfoStatus(in, out, s) +} + +func autoConvert_v1beta1_NodeMediatedDeviceTypesConfig_To_v1_NodeMediatedDeviceTypesConfig(in *NodeMediatedDeviceTypesConfig, out *v1.NodeMediatedDeviceTypesConfig, s conversion.Scope) error { + out.NodeSelector = *(*map[string]string)(unsafe.Pointer(&in.NodeSelector)) + out.MediatedDeviceTypes = *(*[]string)(unsafe.Pointer(&in.MediatedDeviceTypes)) + // INFO: in.MediatedDevicesTypes opted out of conversion generation + return nil +} + +// Convert_v1beta1_NodeMediatedDeviceTypesConfig_To_v1_NodeMediatedDeviceTypesConfig is an autogenerated conversion function. +func Convert_v1beta1_NodeMediatedDeviceTypesConfig_To_v1_NodeMediatedDeviceTypesConfig(in *NodeMediatedDeviceTypesConfig, out *v1.NodeMediatedDeviceTypesConfig, s conversion.Scope) error { + return autoConvert_v1beta1_NodeMediatedDeviceTypesConfig_To_v1_NodeMediatedDeviceTypesConfig(in, out, s) +} + +func autoConvert_v1_NodeMediatedDeviceTypesConfig_To_v1beta1_NodeMediatedDeviceTypesConfig(in *v1.NodeMediatedDeviceTypesConfig, out *NodeMediatedDeviceTypesConfig, s conversion.Scope) error { + out.NodeSelector = *(*map[string]string)(unsafe.Pointer(&in.NodeSelector)) + out.MediatedDeviceTypes = *(*[]string)(unsafe.Pointer(&in.MediatedDeviceTypes)) + return nil +} + +// Convert_v1_NodeMediatedDeviceTypesConfig_To_v1beta1_NodeMediatedDeviceTypesConfig is an autogenerated conversion function. +func Convert_v1_NodeMediatedDeviceTypesConfig_To_v1beta1_NodeMediatedDeviceTypesConfig(in *v1.NodeMediatedDeviceTypesConfig, out *NodeMediatedDeviceTypesConfig, s conversion.Scope) error { + return autoConvert_v1_NodeMediatedDeviceTypesConfig_To_v1beta1_NodeMediatedDeviceTypesConfig(in, out, s) +} + +func autoConvert_v1beta1_OperandResourceRequirements_To_v1_OperandResourceRequirements(in *OperandResourceRequirements, out *v1.OperandResourceRequirements, s conversion.Scope) error { + out.StorageWorkloads = (*apicorev1.ResourceRequirements)(unsafe.Pointer(in.StorageWorkloads)) + out.VmiCPUAllocationRatio = (*int)(unsafe.Pointer(in.VmiCPUAllocationRatio)) + out.AutoCPULimitNamespaceLabelSelector = (*metav1.LabelSelector)(unsafe.Pointer(in.AutoCPULimitNamespaceLabelSelector)) + return nil +} + +// Convert_v1beta1_OperandResourceRequirements_To_v1_OperandResourceRequirements is an autogenerated conversion function. +func Convert_v1beta1_OperandResourceRequirements_To_v1_OperandResourceRequirements(in *OperandResourceRequirements, out *v1.OperandResourceRequirements, s conversion.Scope) error { + return autoConvert_v1beta1_OperandResourceRequirements_To_v1_OperandResourceRequirements(in, out, s) +} + +func autoConvert_v1_OperandResourceRequirements_To_v1beta1_OperandResourceRequirements(in *v1.OperandResourceRequirements, out *OperandResourceRequirements, s conversion.Scope) error { + out.StorageWorkloads = (*apicorev1.ResourceRequirements)(unsafe.Pointer(in.StorageWorkloads)) + out.VmiCPUAllocationRatio = (*int)(unsafe.Pointer(in.VmiCPUAllocationRatio)) + out.AutoCPULimitNamespaceLabelSelector = (*metav1.LabelSelector)(unsafe.Pointer(in.AutoCPULimitNamespaceLabelSelector)) + return nil +} + +// Convert_v1_OperandResourceRequirements_To_v1beta1_OperandResourceRequirements is an autogenerated conversion function. +func Convert_v1_OperandResourceRequirements_To_v1beta1_OperandResourceRequirements(in *v1.OperandResourceRequirements, out *OperandResourceRequirements, s conversion.Scope) error { + return autoConvert_v1_OperandResourceRequirements_To_v1beta1_OperandResourceRequirements(in, out, s) +} + +func autoConvert_v1beta1_PciHostDevice_To_v1_PciHostDevice(in *PciHostDevice, out *v1.PciHostDevice, s conversion.Scope) error { + out.PCIDeviceSelector = in.PCIDeviceSelector + out.ResourceName = in.ResourceName + out.ExternalResourceProvider = in.ExternalResourceProvider + out.Disabled = in.Disabled + return nil +} + +// Convert_v1beta1_PciHostDevice_To_v1_PciHostDevice is an autogenerated conversion function. +func Convert_v1beta1_PciHostDevice_To_v1_PciHostDevice(in *PciHostDevice, out *v1.PciHostDevice, s conversion.Scope) error { + return autoConvert_v1beta1_PciHostDevice_To_v1_PciHostDevice(in, out, s) +} + +func autoConvert_v1_PciHostDevice_To_v1beta1_PciHostDevice(in *v1.PciHostDevice, out *PciHostDevice, s conversion.Scope) error { + out.PCIDeviceSelector = in.PCIDeviceSelector + out.ResourceName = in.ResourceName + out.ExternalResourceProvider = in.ExternalResourceProvider + out.Disabled = in.Disabled + return nil +} + +// Convert_v1_PciHostDevice_To_v1beta1_PciHostDevice is an autogenerated conversion function. +func Convert_v1_PciHostDevice_To_v1beta1_PciHostDevice(in *v1.PciHostDevice, out *PciHostDevice, s conversion.Scope) error { + return autoConvert_v1_PciHostDevice_To_v1beta1_PciHostDevice(in, out, s) +} + +func autoConvert_v1beta1_PermittedHostDevices_To_v1_PermittedHostDevices(in *PermittedHostDevices, out *v1.PermittedHostDevices, s conversion.Scope) error { + out.PciHostDevices = *(*[]v1.PciHostDevice)(unsafe.Pointer(&in.PciHostDevices)) + out.USBHostDevices = *(*[]v1.USBHostDevice)(unsafe.Pointer(&in.USBHostDevices)) + out.MediatedDevices = *(*[]v1.MediatedHostDevice)(unsafe.Pointer(&in.MediatedDevices)) + return nil +} + +// Convert_v1beta1_PermittedHostDevices_To_v1_PermittedHostDevices is an autogenerated conversion function. +func Convert_v1beta1_PermittedHostDevices_To_v1_PermittedHostDevices(in *PermittedHostDevices, out *v1.PermittedHostDevices, s conversion.Scope) error { + return autoConvert_v1beta1_PermittedHostDevices_To_v1_PermittedHostDevices(in, out, s) +} + +func autoConvert_v1_PermittedHostDevices_To_v1beta1_PermittedHostDevices(in *v1.PermittedHostDevices, out *PermittedHostDevices, s conversion.Scope) error { + out.PciHostDevices = *(*[]PciHostDevice)(unsafe.Pointer(&in.PciHostDevices)) + out.USBHostDevices = *(*[]USBHostDevice)(unsafe.Pointer(&in.USBHostDevices)) + out.MediatedDevices = *(*[]MediatedHostDevice)(unsafe.Pointer(&in.MediatedDevices)) + return nil +} + +// Convert_v1_PermittedHostDevices_To_v1beta1_PermittedHostDevices is an autogenerated conversion function. +func Convert_v1_PermittedHostDevices_To_v1beta1_PermittedHostDevices(in *v1.PermittedHostDevices, out *PermittedHostDevices, s conversion.Scope) error { + return autoConvert_v1_PermittedHostDevices_To_v1beta1_PermittedHostDevices(in, out, s) +} + +func autoConvert_v1beta1_StorageImportConfig_To_v1_StorageImportConfig(in *StorageImportConfig, out *v1.StorageImportConfig, s conversion.Scope) error { + out.InsecureRegistries = *(*[]string)(unsafe.Pointer(&in.InsecureRegistries)) + return nil +} + +// Convert_v1beta1_StorageImportConfig_To_v1_StorageImportConfig is an autogenerated conversion function. +func Convert_v1beta1_StorageImportConfig_To_v1_StorageImportConfig(in *StorageImportConfig, out *v1.StorageImportConfig, s conversion.Scope) error { + return autoConvert_v1beta1_StorageImportConfig_To_v1_StorageImportConfig(in, out, s) +} + +func autoConvert_v1_StorageImportConfig_To_v1beta1_StorageImportConfig(in *v1.StorageImportConfig, out *StorageImportConfig, s conversion.Scope) error { + out.InsecureRegistries = *(*[]string)(unsafe.Pointer(&in.InsecureRegistries)) + return nil +} + +// Convert_v1_StorageImportConfig_To_v1beta1_StorageImportConfig is an autogenerated conversion function. +func Convert_v1_StorageImportConfig_To_v1beta1_StorageImportConfig(in *v1.StorageImportConfig, out *StorageImportConfig, s conversion.Scope) error { + return autoConvert_v1_StorageImportConfig_To_v1beta1_StorageImportConfig(in, out, s) +} + +func autoConvert_v1beta1_USBHostDevice_To_v1_USBHostDevice(in *USBHostDevice, out *v1.USBHostDevice, s conversion.Scope) error { + out.ResourceName = in.ResourceName + out.Selectors = *(*[]v1.USBSelector)(unsafe.Pointer(&in.Selectors)) + out.ExternalResourceProvider = in.ExternalResourceProvider + out.Disabled = in.Disabled + return nil +} + +// Convert_v1beta1_USBHostDevice_To_v1_USBHostDevice is an autogenerated conversion function. +func Convert_v1beta1_USBHostDevice_To_v1_USBHostDevice(in *USBHostDevice, out *v1.USBHostDevice, s conversion.Scope) error { + return autoConvert_v1beta1_USBHostDevice_To_v1_USBHostDevice(in, out, s) +} + +func autoConvert_v1_USBHostDevice_To_v1beta1_USBHostDevice(in *v1.USBHostDevice, out *USBHostDevice, s conversion.Scope) error { + out.ResourceName = in.ResourceName + out.Selectors = *(*[]USBSelector)(unsafe.Pointer(&in.Selectors)) + out.ExternalResourceProvider = in.ExternalResourceProvider + out.Disabled = in.Disabled + return nil +} + +// Convert_v1_USBHostDevice_To_v1beta1_USBHostDevice is an autogenerated conversion function. +func Convert_v1_USBHostDevice_To_v1beta1_USBHostDevice(in *v1.USBHostDevice, out *USBHostDevice, s conversion.Scope) error { + return autoConvert_v1_USBHostDevice_To_v1beta1_USBHostDevice(in, out, s) +} + +func autoConvert_v1beta1_USBSelector_To_v1_USBSelector(in *USBSelector, out *v1.USBSelector, s conversion.Scope) error { + out.Vendor = in.Vendor + out.Product = in.Product + return nil +} + +// Convert_v1beta1_USBSelector_To_v1_USBSelector is an autogenerated conversion function. +func Convert_v1beta1_USBSelector_To_v1_USBSelector(in *USBSelector, out *v1.USBSelector, s conversion.Scope) error { + return autoConvert_v1beta1_USBSelector_To_v1_USBSelector(in, out, s) +} + +func autoConvert_v1_USBSelector_To_v1beta1_USBSelector(in *v1.USBSelector, out *USBSelector, s conversion.Scope) error { + out.Vendor = in.Vendor + out.Product = in.Product + return nil +} + +// Convert_v1_USBSelector_To_v1beta1_USBSelector is an autogenerated conversion function. +func Convert_v1_USBSelector_To_v1beta1_USBSelector(in *v1.USBSelector, out *USBSelector, s conversion.Scope) error { + return autoConvert_v1_USBSelector_To_v1beta1_USBSelector(in, out, s) +} + +func autoConvert_v1beta1_Version_To_v1_Version(in *Version, out *v1.Version, s conversion.Scope) error { + out.Name = in.Name + out.Version = in.Version + return nil +} + +// Convert_v1beta1_Version_To_v1_Version is an autogenerated conversion function. +func Convert_v1beta1_Version_To_v1_Version(in *Version, out *v1.Version, s conversion.Scope) error { + return autoConvert_v1beta1_Version_To_v1_Version(in, out, s) +} + +func autoConvert_v1_Version_To_v1beta1_Version(in *v1.Version, out *Version, s conversion.Scope) error { + out.Name = in.Name + out.Version = in.Version + return nil +} + +// Convert_v1_Version_To_v1beta1_Version is an autogenerated conversion function. +func Convert_v1_Version_To_v1beta1_Version(in *v1.Version, out *Version, s conversion.Scope) error { + return autoConvert_v1_Version_To_v1beta1_Version(in, out, s) +} + +func autoConvert_v1beta1_VirtualMachineOptions_To_v1_VirtualMachineOptions(in *VirtualMachineOptions, out *v1.VirtualMachineOptions, s conversion.Scope) error { + out.DisableFreePageReporting = (*bool)(unsafe.Pointer(in.DisableFreePageReporting)) + out.DisableSerialConsoleLog = (*bool)(unsafe.Pointer(in.DisableSerialConsoleLog)) + return nil +} + +// Convert_v1beta1_VirtualMachineOptions_To_v1_VirtualMachineOptions is an autogenerated conversion function. +func Convert_v1beta1_VirtualMachineOptions_To_v1_VirtualMachineOptions(in *VirtualMachineOptions, out *v1.VirtualMachineOptions, s conversion.Scope) error { + return autoConvert_v1beta1_VirtualMachineOptions_To_v1_VirtualMachineOptions(in, out, s) +} + +func autoConvert_v1_VirtualMachineOptions_To_v1beta1_VirtualMachineOptions(in *v1.VirtualMachineOptions, out *VirtualMachineOptions, s conversion.Scope) error { + out.DisableFreePageReporting = (*bool)(unsafe.Pointer(in.DisableFreePageReporting)) + out.DisableSerialConsoleLog = (*bool)(unsafe.Pointer(in.DisableSerialConsoleLog)) + return nil +} + +// Convert_v1_VirtualMachineOptions_To_v1beta1_VirtualMachineOptions is an autogenerated conversion function. +func Convert_v1_VirtualMachineOptions_To_v1beta1_VirtualMachineOptions(in *v1.VirtualMachineOptions, out *VirtualMachineOptions, s conversion.Scope) error { + return autoConvert_v1_VirtualMachineOptions_To_v1beta1_VirtualMachineOptions(in, out, s) +} diff --git a/cmd/hyperconverged-cluster-webhook/main.go b/cmd/hyperconverged-cluster-webhook/main.go index bb95d32aa7..5431ac7672 100644 --- a/cmd/hyperconverged-cluster-webhook/main.go +++ b/cmd/hyperconverged-cluster-webhook/main.go @@ -6,6 +6,7 @@ import ( "fmt" "os" "path/filepath" + "time" openshiftconfigv1 "github.com/openshift/api/config/v1" csvv1alpha1 "github.com/operator-framework/api/pkg/operators/v1alpha1" @@ -20,6 +21,7 @@ import ( apiruntime "k8s.io/apimachinery/pkg/runtime" _ "k8s.io/client-go/plugin/pkg/client/auth/gcp" "k8s.io/client-go/tools/leaderelection/resourcelock" + "k8s.io/utils/ptr" "sigs.k8s.io/controller-runtime/pkg/cache" "sigs.k8s.io/controller-runtime/pkg/client" "sigs.k8s.io/controller-runtime/pkg/client/config" @@ -40,6 +42,7 @@ import ( "github.com/kubevirt/hyperconverged-cluster-operator/cmd/cmdcommon" whapiservercontrollers "github.com/kubevirt/hyperconverged-cluster-operator/controllers/webhooks/apiserver-controller" bearertokencontroller "github.com/kubevirt/hyperconverged-cluster-operator/controllers/webhooks/bearer-token-controller" + conversionwebhookcontroller "github.com/kubevirt/hyperconverged-cluster-operator/controllers/webhooks/conversion-webhook-controller" "github.com/kubevirt/hyperconverged-cluster-operator/pkg/authorization" "github.com/kubevirt/hyperconverged-cluster-operator/pkg/ownresources" hcoutil "github.com/kubevirt/hyperconverged-cluster-operator/pkg/util" @@ -173,6 +176,10 @@ func main() { err = bearertokencontroller.RegisterReconciler(mgr, ci, eventEmitter) cmdHelper.ExitOnError(err, "Cannot register the Bearer Token reconciler") + logger.Info("Registering the Conversion Webhook reconciler") + err = conversionwebhookcontroller.RegisterReconciler(mgr) + cmdHelper.ExitOnError(err, "Cannot register the Conversion Webhook reconciler") + if err = webhooks.SetupWebhookWithManager(mgr, ci.IsOpenshift(), hcoTLSSecurityProfile); err != nil { logger.Error(err, "unable to create webhook", "webhook", "HyperConverged") eventEmitter.EmitEvent(nil, corev1.EventTypeWarning, "InitError", "Unable to create webhook") @@ -208,13 +215,16 @@ func getCacheOption(operatorNamespace string, ci hcoutil.ClusterInfo) cache.Opti Field: namespaceSelector, }, &corev1.Secret{}: { - Label: labelSelector, Field: namespaceSelector, }, &monitoringv1.ServiceMonitor{}: { Label: labelSelector, Field: namespaceSelector, }, + &apiextensionsv1.CustomResourceDefinition{}: { + SyncPeriod: ptr.To(time.Minute * 5), + Field: fields.Set{"metadata.name": hcoutil.HyperConvergedCRDName}.AsSelector(), + }, }, } diff --git a/config/crd/bases/hco.kubevirt.io_hyperconvergeds.yaml b/config/crd/bases/hco.kubevirt.io_hyperconvergeds.yaml index d7b0d4cb77..a1cebffd93 100644 --- a/config/crd/bases/hco.kubevirt.io_hyperconvergeds.yaml +++ b/config/crd/bases/hco.kubevirt.io_hyperconvergeds.yaml @@ -17,6 +17,5186 @@ spec: singular: hyperconverged scope: Namespaced versions: + - additionalPrinterColumns: + - jsonPath: .metadata.creationTimestamp + name: Age + type: date + name: v1 + schema: + openAPIV3Schema: + description: HyperConverged is the Schema for the hyperconvergeds API + properties: + apiVersion: + description: |- + APIVersion defines the versioned schema of this representation of an object. + Servers should convert recognized schemas to the latest internal value, and + may reject unrecognized values. + More info: https://git.k8s.io/community/contributors/devel/sig-architecture/api-conventions.md#resources + type: string + kind: + description: |- + Kind is a string value representing the REST resource this object represents. + Servers may infer this from the endpoint the client submits requests to. + Cannot be updated. + In CamelCase. + More info: https://git.k8s.io/community/contributors/devel/sig-architecture/api-conventions.md#types-kinds + type: string + metadata: + properties: + name: + pattern: kubevirt-hyperconverged + type: string + type: object + spec: + default: + certConfig: + ca: + duration: 48h0m0s + renewBefore: 24h0m0s + server: + duration: 24h0m0s + renewBefore: 12h0m0s + deployVmConsoleProxy: false + enableApplicationAwareQuota: false + enableCommonBootImageImport: true + liveMigrationConfig: + allowAutoConverge: false + allowPostCopy: false + completionTimeoutPerGiB: 150 + parallelMigrationsPerCluster: 5 + parallelOutboundMigrationsPerNode: 2 + progressTimeout: 150 + resourceRequirements: + vmiCPUAllocationRatio: 10 + uninstallStrategy: BlockUninstallIfWorkloadsExist + virtualMachineOptions: + disableFreePageReporting: false + disableSerialConsoleLog: false + description: HyperConvergedSpec defines the desired state of HyperConverged + properties: + CommonInstancetypesDeployment: + description: CommonInstancetypesDeployment holds the configuration + of common-instancetypes deployment within KubeVirt. + properties: + enabled: + description: Enabled controls the deployment of common-instancetypes + resources, defaults to True. + nullable: true + type: boolean + type: object + applicationAwareConfig: + description: ApplicationAwareConfig set the AAQ configurations + properties: + allowApplicationAwareClusterResourceQuota: + default: false + description: AllowApplicationAwareClusterResourceQuota if set + to true, allows creation and management of ClusterAppsResourceQuota + type: boolean + namespaceSelector: + description: NamespaceSelector determines in which namespaces + scheduling gate will be added to pods.. + properties: + matchExpressions: + description: matchExpressions is a list of label selector + requirements. The requirements are ANDed. + items: + description: |- + A label selector requirement is a selector that contains values, a key, and an operator that + relates the key and values. + properties: + key: + description: key is the label key that the selector + applies to. + type: string + operator: + description: |- + operator represents a key's relationship to a set of values. + Valid operators are In, NotIn, Exists and DoesNotExist. + type: string + values: + description: |- + values is an array of string values. If the operator is In or NotIn, + the values array must be non-empty. If the operator is Exists or DoesNotExist, + the values array must be empty. This array is replaced during a strategic + merge patch. + items: + type: string + type: array + x-kubernetes-list-type: atomic + required: + - key + - operator + type: object + type: array + x-kubernetes-list-type: atomic + matchLabels: + additionalProperties: + type: string + description: |- + matchLabels is a map of {key,value} pairs. A single {key,value} in the matchLabels + map is equivalent to an element of matchExpressions, whose key field is "key", the + operator is "In", and the values array contains only "value". The requirements are ANDed. + type: object + type: object + x-kubernetes-map-type: atomic + vmiCalcConfigName: + default: DedicatedVirtualResources + description: |- + VmiCalcConfigName determine how resource allocation will be done with ApplicationsResourceQuota. + allowed values are: VmiPodUsage, VirtualResources, DedicatedVirtualResources or IgnoreVmiCalculator + enum: + - VmiPodUsage + - VirtualResources + - DedicatedVirtualResources + - IgnoreVmiCalculator + type: string + type: object + certConfig: + default: + ca: + duration: 48h0m0s + renewBefore: 24h0m0s + server: + duration: 24h0m0s + renewBefore: 12h0m0s + description: certConfig holds the rotation policy for internal, self-signed + certificates + properties: + ca: + default: + duration: 48h0m0s + renewBefore: 24h0m0s + description: |- + CA configuration - + CA certs are kept in the CA bundle as long as they are valid + properties: + duration: + default: 48h0m0s + description: |- + The requested 'duration' (i.e. lifetime) of the Certificate. + This should comply with golang's ParseDuration format (https://golang.org/pkg/time/#ParseDuration) + type: string + renewBefore: + default: 24h0m0s + description: |- + The amount of time before the currently issued certificate's `notAfter` + time that we will begin to attempt to renew the certificate. + This should comply with golang's ParseDuration format (https://golang.org/pkg/time/#ParseDuration) + type: string + type: object + server: + default: + duration: 24h0m0s + renewBefore: 12h0m0s + description: |- + Server configuration - + Certs are rotated and discarded + properties: + duration: + default: 24h0m0s + description: |- + The requested 'duration' (i.e. lifetime) of the Certificate. + This should comply with golang's ParseDuration format (https://golang.org/pkg/time/#ParseDuration) + type: string + renewBefore: + default: 12h0m0s + description: |- + The amount of time before the currently issued certificate's `notAfter` + time that we will begin to attempt to renew the certificate. + This should comply with golang's ParseDuration format (https://golang.org/pkg/time/#ParseDuration) + type: string + type: object + type: object + commonBootImageNamespace: + description: |- + CommonBootImageNamespace override the default namespace of the common boot images, in order to hide them. + + If not set, HCO won't set any namespace, letting SSP to use the default. If set, use the namespace to create the + DataImportCronTemplates and the common image streams, with this namespace. This field is not set by default. + type: string + commonTemplatesNamespace: + description: |- + CommonTemplatesNamespace defines namespace in which common templates will + be deployed. It overrides the default openshift namespace. + type: string + dataImportCronTemplates: + description: DataImportCronTemplates holds list of data import cron + templates (golden images) + items: + description: |- + DataImportCronTemplate defines the template type for DataImportCrons. + It requires metadata.name to be specified while leaving namespace as optional. + properties: + metadata: + properties: + annotations: + additionalProperties: + type: string + type: object + finalizers: + items: + type: string + type: array + labels: + additionalProperties: + type: string + type: object + name: + type: string + namespace: + type: string + type: object + spec: + description: DataImportCronSpec defines specification for DataImportCron + properties: + garbageCollect: + description: |- + GarbageCollect specifies whether old PVCs should be cleaned up after a new PVC is imported. + Options are currently "Outdated" and "Never", defaults to "Outdated". + type: string + importsToKeep: + description: Number of import PVCs to keep when garbage + collecting. Default is 3. + format: int32 + type: integer + managedDataSource: + description: |- + ManagedDataSource specifies the name of the corresponding DataSource this cron will manage. + DataSource has to be in the same namespace. + type: string + retentionPolicy: + description: RetentionPolicy specifies whether the created + DataVolumes and DataSources are retained when their DataImportCron + is deleted. Default is RatainAll. + type: string + schedule: + description: Schedule specifies in cron format when and + how often to look for new imports + type: string + serviceAccountName: + description: ServiceAccountName is the name of the ServiceAccount + for creating DataVolumes. + minLength: 1 + type: string + template: + description: Template specifies template for the DVs to + be created + properties: + apiVersion: + description: |- + APIVersion defines the versioned schema of this representation of an object. + Servers should convert recognized schemas to the latest internal value, and + may reject unrecognized values. + More info: https://git.k8s.io/community/contributors/devel/sig-architecture/api-conventions.md#resources + type: string + kind: + description: |- + Kind is a string value representing the REST resource this object represents. + Servers may infer this from the endpoint the client submits requests to. + Cannot be updated. + In CamelCase. + More info: https://git.k8s.io/community/contributors/devel/sig-architecture/api-conventions.md#types-kinds + type: string + metadata: + properties: + annotations: + additionalProperties: + type: string + type: object + finalizers: + items: + type: string + type: array + labels: + additionalProperties: + type: string + type: object + name: + type: string + namespace: + type: string + type: object + spec: + description: DataVolumeSpec defines the DataVolume type + specification + properties: + checkpoints: + description: Checkpoints is a list of DataVolumeCheckpoints, + representing stages in a multistage import. + items: + description: DataVolumeCheckpoint defines a stage + in a warm migration. + properties: + current: + description: Current is the identifier of + the snapshot created for this checkpoint. + type: string + previous: + description: Previous is the identifier of + the snapshot from the previous checkpoint. + type: string + required: + - current + - previous + type: object + type: array + contentType: + description: 'DataVolumeContentType options: "kubevirt", + "archive"' + enum: + - kubevirt + - archive + type: string + finalCheckpoint: + description: FinalCheckpoint indicates whether the + current DataVolumeCheckpoint is the final checkpoint. + type: boolean + preallocation: + description: Preallocation controls whether storage + for DataVolumes should be allocated in advance. + type: boolean + priorityClassName: + description: PriorityClassName for Importer, Cloner + and Uploader pod + type: string + pvc: + description: PVC is the PVC specification + properties: + accessModes: + description: |- + accessModes contains the desired access modes the volume should have. + More info: https://kubernetes.io/docs/concepts/storage/persistent-volumes#access-modes-1 + items: + type: string + type: array + x-kubernetes-list-type: atomic + dataSource: + description: |- + dataSource field can be used to specify either: + * An existing VolumeSnapshot object (snapshot.storage.k8s.io/VolumeSnapshot) + * An existing PVC (PersistentVolumeClaim) + If the provisioner or an external controller can support the specified data source, + it will create a new volume based on the contents of the specified data source. + When the AnyVolumeDataSource feature gate is enabled, dataSource contents will be copied to dataSourceRef, + and dataSourceRef contents will be copied to dataSource when dataSourceRef.namespace is not specified. + If the namespace is specified, then dataSourceRef will not be copied to dataSource. + properties: + apiGroup: + description: |- + APIGroup is the group for the resource being referenced. + If APIGroup is not specified, the specified Kind must be in the core API group. + For any other third-party types, APIGroup is required. + type: string + kind: + description: Kind is the type of resource + being referenced + type: string + name: + description: Name is the name of resource + being referenced + type: string + required: + - kind + - name + type: object + x-kubernetes-map-type: atomic + dataSourceRef: + description: |- + dataSourceRef specifies the object from which to populate the volume with data, if a non-empty + volume is desired. This may be any object from a non-empty API group (non + core object) or a PersistentVolumeClaim object. + When this field is specified, volume binding will only succeed if the type of + the specified object matches some installed volume populator or dynamic + provisioner. + This field will replace the functionality of the dataSource field and as such + if both fields are non-empty, they must have the same value. For backwards + compatibility, when namespace isn't specified in dataSourceRef, + both fields (dataSource and dataSourceRef) will be set to the same + value automatically if one of them is empty and the other is non-empty. + When namespace is specified in dataSourceRef, + dataSource isn't set to the same value and must be empty. + There are three important differences between dataSource and dataSourceRef: + * While dataSource only allows two specific types of objects, dataSourceRef + allows any non-core object, as well as PersistentVolumeClaim objects. + * While dataSource ignores disallowed values (dropping them), dataSourceRef + preserves all values, and generates an error if a disallowed value is + specified. + * While dataSource only allows local objects, dataSourceRef allows objects + in any namespaces. + (Beta) Using this field requires the AnyVolumeDataSource feature gate to be enabled. + (Alpha) Using the namespace field of dataSourceRef requires the CrossNamespaceVolumeDataSource feature gate to be enabled. + properties: + apiGroup: + description: |- + APIGroup is the group for the resource being referenced. + If APIGroup is not specified, the specified Kind must be in the core API group. + For any other third-party types, APIGroup is required. + type: string + kind: + description: Kind is the type of resource + being referenced + type: string + name: + description: Name is the name of resource + being referenced + type: string + namespace: + description: |- + Namespace is the namespace of resource being referenced + Note that when a namespace is specified, a gateway.networking.k8s.io/ReferenceGrant object is required in the referent namespace to allow that namespace's owner to accept the reference. See the ReferenceGrant documentation for details. + (Alpha) This field requires the CrossNamespaceVolumeDataSource feature gate to be enabled. + type: string + required: + - kind + - name + type: object + resources: + description: |- + resources represents the minimum resources the volume should have. + If RecoverVolumeExpansionFailure feature is enabled users are allowed to specify resource requirements + that are lower than previous value but must still be higher than capacity recorded in the + status field of the claim. + More info: https://kubernetes.io/docs/concepts/storage/persistent-volumes#resources + properties: + limits: + additionalProperties: + anyOf: + - type: integer + - type: string + pattern: ^(\+|-)?(([0-9]+(\.[0-9]*)?)|(\.[0-9]+))(([KMGTPE]i)|[numkMGTPE]|([eE](\+|-)?(([0-9]+(\.[0-9]*)?)|(\.[0-9]+))))?$ + x-kubernetes-int-or-string: true + description: |- + Limits describes the maximum amount of compute resources allowed. + More info: https://kubernetes.io/docs/concepts/configuration/manage-resources-containers/ + type: object + requests: + additionalProperties: + anyOf: + - type: integer + - type: string + pattern: ^(\+|-)?(([0-9]+(\.[0-9]*)?)|(\.[0-9]+))(([KMGTPE]i)|[numkMGTPE]|([eE](\+|-)?(([0-9]+(\.[0-9]*)?)|(\.[0-9]+))))?$ + x-kubernetes-int-or-string: true + description: |- + Requests describes the minimum amount of compute resources required. + If Requests is omitted for a container, it defaults to Limits if that is explicitly specified, + otherwise to an implementation-defined value. Requests cannot exceed Limits. + More info: https://kubernetes.io/docs/concepts/configuration/manage-resources-containers/ + type: object + type: object + selector: + description: selector is a label query over + volumes to consider for binding. + properties: + matchExpressions: + description: matchExpressions is a list + of label selector requirements. The requirements + are ANDed. + items: + description: |- + A label selector requirement is a selector that contains values, a key, and an operator that + relates the key and values. + properties: + key: + description: key is the label key + that the selector applies to. + type: string + operator: + description: |- + operator represents a key's relationship to a set of values. + Valid operators are In, NotIn, Exists and DoesNotExist. + type: string + values: + description: |- + values is an array of string values. If the operator is In or NotIn, + the values array must be non-empty. If the operator is Exists or DoesNotExist, + the values array must be empty. This array is replaced during a strategic + merge patch. + items: + type: string + type: array + x-kubernetes-list-type: atomic + required: + - key + - operator + type: object + type: array + x-kubernetes-list-type: atomic + matchLabels: + additionalProperties: + type: string + description: |- + matchLabels is a map of {key,value} pairs. A single {key,value} in the matchLabels + map is equivalent to an element of matchExpressions, whose key field is "key", the + operator is "In", and the values array contains only "value". The requirements are ANDed. + type: object + type: object + x-kubernetes-map-type: atomic + storageClassName: + description: |- + storageClassName is the name of the StorageClass required by the claim. + More info: https://kubernetes.io/docs/concepts/storage/persistent-volumes#class-1 + type: string + volumeAttributesClassName: + description: |- + volumeAttributesClassName may be used to set the VolumeAttributesClass used by this claim. + If specified, the CSI driver will create or update the volume with the attributes defined + in the corresponding VolumeAttributesClass. This has a different purpose than storageClassName, + it can be changed after the claim is created. An empty string or nil value indicates that no + VolumeAttributesClass will be applied to the claim. If the claim enters an Infeasible error state, + this field can be reset to its previous value (including nil) to cancel the modification. + If the resource referred to by volumeAttributesClass does not exist, this PersistentVolumeClaim will be + set to a Pending state, as reflected by the modifyVolumeStatus field, until such as a resource + exists. + More info: https://kubernetes.io/docs/concepts/storage/volume-attributes-classes/ + type: string + volumeMode: + description: |- + volumeMode defines what type of volume is required by the claim. + Value of Filesystem is implied when not included in claim spec. + type: string + volumeName: + description: volumeName is the binding reference + to the PersistentVolume backing this claim. + type: string + type: object + source: + description: Source is the src of the data for the + requested DataVolume + properties: + blank: + description: DataVolumeBlankImage provides the + parameters to create a new raw blank image + for the PVC + type: object + gcs: + description: DataVolumeSourceGCS provides the + parameters to create a Data Volume from an + GCS source + properties: + secretRef: + description: SecretRef provides the secret + reference needed to access the GCS source + type: string + url: + description: URL is the url of the GCS source + type: string + required: + - url + type: object + http: + description: DataVolumeSourceHTTP can be either + an http or https endpoint, with an optional + basic auth user name and password, and an + optional configmap containing additional CAs + properties: + certConfigMap: + description: CertConfigMap is a configmap + reference, containing a Certificate Authority(CA) + public key, and a base64 encoded pem certificate + type: string + extraHeaders: + description: ExtraHeaders is a list of strings + containing extra headers to include with + HTTP transfer requests + items: + type: string + type: array + secretExtraHeaders: + description: SecretExtraHeaders is a list + of Secret references, each containing + an extra HTTP header that may include + sensitive information + items: + type: string + type: array + secretRef: + description: SecretRef A Secret reference, + the secret should contain accessKeyId + (user name) base64 encoded, and secretKey + (password) also base64 encoded + type: string + url: + description: URL is the URL of the http(s) + endpoint + type: string + required: + - url + type: object + imageio: + description: DataVolumeSourceImageIO provides + the parameters to create a Data Volume from + an imageio source + properties: + certConfigMap: + description: CertConfigMap provides a reference + to the CA cert + type: string + diskId: + description: DiskID provides id of a disk + to be imported + type: string + insecureSkipVerify: + description: InsecureSkipVerify is a flag + to skip certificate verification + type: boolean + secretRef: + description: SecretRef provides the secret + reference needed to access the ovirt-engine + type: string + url: + description: URL is the URL of the ovirt-engine + type: string + required: + - diskId + - url + type: object + pvc: + description: DataVolumeSourcePVC provides the + parameters to create a Data Volume from an + existing PVC + properties: + name: + description: The name of the source PVC + type: string + namespace: + description: The namespace of the source + PVC + type: string + required: + - name + - namespace + type: object + registry: + description: DataVolumeSourceRegistry provides + the parameters to create a Data Volume from + an registry source + properties: + certConfigMap: + description: CertConfigMap provides a reference + to the Registry certs + type: string + imageStream: + description: ImageStream is the name of + image stream for import + type: string + platform: + description: Platform describes the minimum + runtime requirements of the image + properties: + architecture: + description: Architecture specifies + the image target CPU architecture + type: string + type: object + pullMethod: + description: PullMethod can be either "pod" + (default import), or "node" (node docker + cache based import) + type: string + secretRef: + description: SecretRef provides the secret + reference needed to access the Registry + source + type: string + url: + description: 'URL is the url of the registry + source (starting with the scheme: docker, + oci-archive)' + type: string + type: object + s3: + description: DataVolumeSourceS3 provides the + parameters to create a Data Volume from an + S3 source + properties: + certConfigMap: + description: CertConfigMap is a configmap + reference, containing a Certificate Authority(CA) + public key, and a base64 encoded pem certificate + type: string + secretRef: + description: SecretRef provides the secret + reference needed to access the S3 source + type: string + url: + description: URL is the url of the S3 source + type: string + required: + - url + type: object + snapshot: + description: DataVolumeSourceSnapshot provides + the parameters to create a Data Volume from + an existing VolumeSnapshot + properties: + name: + description: The name of the source VolumeSnapshot + type: string + namespace: + description: The namespace of the source + VolumeSnapshot + type: string + required: + - name + - namespace + type: object + upload: + description: DataVolumeSourceUpload provides + the parameters to create a Data Volume by + uploading the source + type: object + vddk: + description: DataVolumeSourceVDDK provides the + parameters to create a Data Volume from a + Vmware source + properties: + backingFile: + description: BackingFile is the path to + the virtual hard disk to migrate from + vCenter/ESXi + type: string + extraArgs: + description: ExtraArgs is a reference to + a ConfigMap containing extra arguments + to pass directly to the VDDK library + type: string + initImageURL: + description: InitImageURL is an optional + URL to an image containing an extracted + VDDK library, overrides v2v-vmware config + map + type: string + secretRef: + description: SecretRef provides a reference + to a secret containing the username and + password needed to access the vCenter + or ESXi host + type: string + thumbprint: + description: Thumbprint is the certificate + thumbprint of the vCenter or ESXi host + type: string + url: + description: URL is the URL of the vCenter + or ESXi host with the VM to migrate + type: string + uuid: + description: UUID is the UUID of the virtual + machine that the backing file is attached + to in vCenter/ESXi + type: string + type: object + type: object + sourceRef: + description: SourceRef is an indirect reference + to the source of data for the requested DataVolume + properties: + kind: + description: The kind of the source reference, + currently only "DataSource" is supported + type: string + name: + description: The name of the source reference + type: string + namespace: + description: The namespace of the source reference, + defaults to the DataVolume namespace + type: string + required: + - kind + - name + type: object + storage: + description: Storage is the requested storage specification + properties: + accessModes: + description: |- + AccessModes contains the desired access modes the volume should have. + More info: https://kubernetes.io/docs/concepts/storage/persistent-volumes#access-modes-1 + items: + type: string + type: array + dataSource: + description: |- + This field can be used to specify either: * An existing VolumeSnapshot object (snapshot.storage.k8s.io/VolumeSnapshot) * An existing PVC (PersistentVolumeClaim) * An existing custom resource that implements data population (Alpha) In order to use custom resource types that implement data population, the AnyVolumeDataSource feature gate must be enabled. If the provisioner or an external controller can support the specified data source, it will create a new volume based on the contents of the specified data source. + If the AnyVolumeDataSource feature gate is enabled, this field will always have the same contents as the DataSourceRef field. + properties: + apiGroup: + description: |- + APIGroup is the group for the resource being referenced. + If APIGroup is not specified, the specified Kind must be in the core API group. + For any other third-party types, APIGroup is required. + type: string + kind: + description: Kind is the type of resource + being referenced + type: string + name: + description: Name is the name of resource + being referenced + type: string + required: + - kind + - name + type: object + x-kubernetes-map-type: atomic + dataSourceRef: + description: |- + Specifies the object from which to populate the volume with data, if a non-empty volume is desired. This may be any local object from a non-empty API group (non core object) or a PersistentVolumeClaim object. When this field is specified, volume binding will only succeed if the type of the specified object matches some installed volume populator or dynamic provisioner. + This field will replace the functionality of the DataSource field and as such if both fields are non-empty, they must have the same value. For backwards compatibility, both fields (DataSource and DataSourceRef) will be set to the same value automatically if one of them is empty and the other is non-empty. + There are two important differences between DataSource and DataSourceRef: + * While DataSource only allows two specific types of objects, DataSourceRef allows any non-core object, as well as PersistentVolumeClaim objects. + * While DataSource ignores disallowed values (dropping them), DataSourceRef preserves all values, and generates an error if a disallowed value is specified. + (Beta) Using this field requires the AnyVolumeDataSource feature gate to be enabled. + properties: + apiGroup: + description: |- + APIGroup is the group for the resource being referenced. + If APIGroup is not specified, the specified Kind must be in the core API group. + For any other third-party types, APIGroup is required. + type: string + kind: + description: Kind is the type of resource + being referenced + type: string + name: + description: Name is the name of resource + being referenced + type: string + namespace: + description: |- + Namespace is the namespace of resource being referenced + Note that when a namespace is specified, a gateway.networking.k8s.io/ReferenceGrant object is required in the referent namespace to allow that namespace's owner to accept the reference. See the ReferenceGrant documentation for details. + (Alpha) This field requires the CrossNamespaceVolumeDataSource feature gate to be enabled. + type: string + required: + - kind + - name + type: object + resources: + description: |- + Resources represents the minimum resources the volume should have. + More info: https://kubernetes.io/docs/concepts/storage/persistent-volumes#resources + properties: + limits: + additionalProperties: + anyOf: + - type: integer + - type: string + pattern: ^(\+|-)?(([0-9]+(\.[0-9]*)?)|(\.[0-9]+))(([KMGTPE]i)|[numkMGTPE]|([eE](\+|-)?(([0-9]+(\.[0-9]*)?)|(\.[0-9]+))))?$ + x-kubernetes-int-or-string: true + description: |- + Limits describes the maximum amount of compute resources allowed. + More info: https://kubernetes.io/docs/concepts/configuration/manage-resources-containers/ + type: object + requests: + additionalProperties: + anyOf: + - type: integer + - type: string + pattern: ^(\+|-)?(([0-9]+(\.[0-9]*)?)|(\.[0-9]+))(([KMGTPE]i)|[numkMGTPE]|([eE](\+|-)?(([0-9]+(\.[0-9]*)?)|(\.[0-9]+))))?$ + x-kubernetes-int-or-string: true + description: |- + Requests describes the minimum amount of compute resources required. + If Requests is omitted for a container, it defaults to Limits if that is explicitly specified, + otherwise to an implementation-defined value. Requests cannot exceed Limits. + More info: https://kubernetes.io/docs/concepts/configuration/manage-resources-containers/ + type: object + type: object + selector: + description: A label query over volumes to consider + for binding. + properties: + matchExpressions: + description: matchExpressions is a list + of label selector requirements. The requirements + are ANDed. + items: + description: |- + A label selector requirement is a selector that contains values, a key, and an operator that + relates the key and values. + properties: + key: + description: key is the label key + that the selector applies to. + type: string + operator: + description: |- + operator represents a key's relationship to a set of values. + Valid operators are In, NotIn, Exists and DoesNotExist. + type: string + values: + description: |- + values is an array of string values. If the operator is In or NotIn, + the values array must be non-empty. If the operator is Exists or DoesNotExist, + the values array must be empty. This array is replaced during a strategic + merge patch. + items: + type: string + type: array + x-kubernetes-list-type: atomic + required: + - key + - operator + type: object + type: array + x-kubernetes-list-type: atomic + matchLabels: + additionalProperties: + type: string + description: |- + matchLabels is a map of {key,value} pairs. A single {key,value} in the matchLabels + map is equivalent to an element of matchExpressions, whose key field is "key", the + operator is "In", and the values array contains only "value". The requirements are ANDed. + type: object + type: object + x-kubernetes-map-type: atomic + storageClassName: + description: |- + Name of the StorageClass required by the claim. + More info: https://kubernetes.io/docs/concepts/storage/persistent-volumes#class-1 + type: string + volumeMode: + description: |- + volumeMode defines what type of volume is required by the claim. + Value of Filesystem is implied when not included in claim spec. + type: string + volumeName: + description: VolumeName is the binding reference + to the PersistentVolume backing this claim. + type: string + type: object + type: object + status: + description: DataVolumeStatus contains the current status + of the DataVolume + properties: + claimName: + description: ClaimName is the name of the underlying + PVC used by the DataVolume. + type: string + conditions: + items: + description: DataVolumeCondition represents the + state of a data volume condition. + properties: + lastHeartbeatTime: + format: date-time + type: string + lastTransitionTime: + format: date-time + type: string + message: + type: string + reason: + type: string + status: + type: string + type: + description: DataVolumeConditionType is the + string representation of known condition + types + type: string + required: + - status + - type + type: object + type: array + phase: + description: Phase is the current phase of the data + volume + type: string + progress: + description: DataVolumeProgress is the current progress + of the DataVolume transfer operation. Value between + 0 and 100 inclusive, N/A if not available + type: string + restartCount: + description: RestartCount is the number of times + the pod populating the DataVolume has restarted + format: int32 + type: integer + type: object + required: + - spec + type: object + required: + - managedDataSource + - schedule + - template + type: object + type: object + type: array + x-kubernetes-list-type: atomic + defaultCPUModel: + description: |- + DefaultCPUModel defines a cluster default for CPU model: default CPU model is set when VMI doesn't have any CPU model. + When VMI has CPU model set, then VMI's CPU model is preferred. + When default CPU model is not set and VMI's CPU model is not set too, host-model will be set. + Default CPU model can be changed when kubevirt is running. + type: string + defaultRuntimeClass: + description: |- + DefaultRuntimeClass defines a cluster default for the RuntimeClass to be used for VMIs pods if not set there. + Default RuntimeClass can be changed when kubevirt is running, existing VMIs are not impacted till + the next restart/live-migration when they are eventually going to consume the new default RuntimeClass. + type: string + deployVmConsoleProxy: + default: false + description: deploy VM console proxy resources in SSP operator + type: boolean + enableApplicationAwareQuota: + default: false + description: EnableApplicationAwareQuota if true, enables the Application + Aware Quota feature + type: boolean + enableCommonBootImageImport: + default: true + description: |- + Opt-in to automatic delivery/updates of the common data import cron templates. + There are two sources for the data import cron templates: hard coded list of common templates, and custom (user + defined) templates that can be added to the dataImportCronTemplates field. This field only controls the common + templates. It is possible to use custom templates by adding them to the dataImportCronTemplates field. + type: boolean + evictionStrategy: + description: |- + EvictionStrategy defines at the cluster level if the VirtualMachineInstance should be + migrated instead of shut-off in case of a node drain. If the VirtualMachineInstance specific + field is set it overrides the cluster level one. + Allowed values: + - `None` no eviction strategy at cluster level. + - `LiveMigrate` migrate the VM on eviction; a not live migratable VM with no specific strategy will block the drain of the node util manually evicted. + - `LiveMigrateIfPossible` migrate the VM on eviction if live migration is possible, otherwise directly evict. + - `External` block the drain, track eviction and notify an external controller. + Defaults to LiveMigrate with multiple worker nodes, None on single worker clusters. + enum: + - None + - LiveMigrate + - LiveMigrateIfPossible + - External + type: string + featureGates: + description: |- + FeatureGates is a set of optional feature gates to enable or disable new + features that are not generally available yet. + Add a new FeatureGate Object to this set, to enable a feature that is + disabled by default, or to disable a feature that is enabled by default. + + A feature gate may be in the following phases: + * Alpha: the feature is in dev-preview. It is disabled by default, but can + be enabled. + * Beta: the feature gate is in tech-preview. It is enabled by default, but + can be disabled. + * GA: the feature is graduated and is always enabled. There is no way to + disable it. + * Deprecated: the feature is no longer supported. There is no way to enable + it + + Feature-Gate list: + * alignCPUs: + Enable KubeVirt to request up to two additional dedicated CPUs in order to + complete the total CPU count to an even parity when using emulator thread + isolation. + Note: this feature is in Developer Preview. + Phase: Alpha + + * decentralizedLiveMigration: + enables the decentralized live migration (cross-cluster migration) feature. + This feature allows live migration of VirtualMachineInstances between + different clusters. + Note: This feature is in Developer Preview. + Phase: Alpha + + * declarativeHotplugVolumes: + enables the use of the declarative volume hotplug feature in KubeVirt. + When enabled, the "DeclarativeHotplugVolumes" feature gate is enabled in + the KubeVirt CR, instead of the "HotplugVolumes" feature gate. + When disabled, the "HotplugVolumes" feature gate is enabled (default + behavior). + Phase: Alpha + + * deployKubeSecondaryDNS: + Deploy KubeSecondaryDNS by CNAO + Phase: Alpha + + * disableMDevConfiguration: + Disable mediated devices handling on KubeVirt + Phase: Alpha + + * downwardMetrics: + Allow to expose a limited set of host metrics to guests. + Phase: Alpha + + * enableMultiArchBootImageImport: + allows the HCO to run on heterogeneous clusters with different CPU + architectures. + Enabling this feature gate will allow the HCO to create Golden Images for + different CPU architectures. + Phase: Alpha + + * objectGraph: + enables the ObjectGraph VM and VMI subresource in KubeVirt. + This subresource returns a structured list of k8s objects that are related + to the specified VM or VMI, enabling better dependency tracking. + Phase: Alpha + + * persistentReservation: + Enable persistent reservation of a LUN through the SCSI Persistent Reserve + commands on Kubevirt. + In order to issue privileged SCSI ioctls, the VM requires activation of the + persistent reservation flag. + Once this feature gate is enabled, then the additional container with the + qemu-pr-helper is deployed inside the virt-handler pod. + Enabling (or removing) the feature gate causes the redeployment of the + virt-handler pod. + Phase: Alpha + + * videoConfig: + allows users to configure video device types for their virtual machines. + This can be useful for workloads that require specific video capabilities + or architectures. + Phase: Beta + + * autoResourceLimits: + Phase: Deprecated + + * deployKubevirtIpamController: + Phase: Deprecated + + * deployTektonTaskResources: + Phase: Deprecated + + * deployVmConsoleProxy: + Phase: Deprecated + + * enableApplicationAwareQuota: + This feature gate is ignored. Use spec.enableApplicationAwareQuota field instead + Phase: Deprecated + + * enableCommonBootImageImport: + This feature gate is ignored. Use spec.enableCommonBootImageImport field instead + Phase: Deprecated + + * enableManagedTenantQuota: + Phase: Deprecated + + * nonRoot: + Phase: Deprecated + + * primaryUserDefinedNetworkBinding: + Phase: Deprecated + + * withHostPassthroughCPU: + Phase: Deprecated + items: + description: FeatureGate is an optional feature gate to enable or + disable a new feature that is not generally available yet. + properties: + name: + description: Name is the feature gate name + type: string + state: + description: State determines if the feature gate is enabled + ("Enabled"), or disabled ("False"). The default value is "Disabled". + enum: + - Enabled + - Disabled + type: string + required: + - name + type: object + type: array + filesystemOverhead: + description: |- + FilesystemOverhead describes the space reserved for overhead when using Filesystem volumes. + A value is between 0 and 1, if not defined it is 0.055 (5.5 percent overhead) + properties: + global: + description: Global is how much space of a Filesystem volume should + be reserved for overhead. This value is used unless overridden + by a more specific value (per storageClass) + pattern: ^(0(?:\.\d{1,3})?|1)$ + type: string + storageClass: + additionalProperties: + description: |- + Percent is a string that can only be a value between [0,1) + (Note: we actually rely on reconcile to reject invalid values) + pattern: ^(0(?:\.\d{1,3})?|1)$ + type: string + description: StorageClass specifies how much space of a Filesystem + volume should be reserved for safety. The keys are the storageClass + and the values are the overhead. This value overrides the global + value + type: object + type: object + higherWorkloadDensity: + default: + memoryOvercommitPercentage: 100 + description: HigherWorkloadDensity holds configuration aimed to increase + virtual machine density + properties: + memoryOvercommitPercentage: + default: 100 + description: |- + MemoryOvercommitPercentage is the percentage of memory we want to give VMIs compared to the amount + given to its parent pod (virt-launcher). For example, a value of 102 means the VMI will + "see" 2% more memory than its parent pod. Values under 100 are effectively "undercommits". + Overcommits can lead to memory exhaustion, which in turn can lead to crashes. Use carefully. + minimum: 10 + type: integer + type: object + infra: + description: |- + infra HyperConvergedConfig influences the pod configuration (currently only placement) + for all the infra components needed on the virtualization enabled cluster + but not necessarily directly on each node running VMs/VMIs. + properties: + nodePlacement: + description: NodePlacement describes node scheduling configuration. + properties: + affinity: + description: |- + affinity enables pod affinity/anti-affinity placement expanding the types of constraints + that can be expressed with nodeSelector. + affinity is going to be applied to the relevant kind of pods in parallel with nodeSelector + See https://kubernetes.io/docs/concepts/scheduling-eviction/assign-pod-node/#affinity-and-anti-affinity + properties: + nodeAffinity: + description: Describes node affinity scheduling rules + for the pod. + properties: + preferredDuringSchedulingIgnoredDuringExecution: + description: |- + The scheduler will prefer to schedule pods to nodes that satisfy + the affinity expressions specified by this field, but it may choose + a node that violates one or more of the expressions. The node that is + most preferred is the one with the greatest sum of weights, i.e. + for each node that meets all of the scheduling requirements (resource + request, requiredDuringScheduling affinity expressions, etc.), + compute a sum by iterating through the elements of this field and adding + "weight" to the sum if the node matches the corresponding matchExpressions; the + node(s) with the highest sum are the most preferred. + items: + description: |- + An empty preferred scheduling term matches all objects with implicit weight 0 + (i.e. it's a no-op). A null preferred scheduling term matches no objects (i.e. is also a no-op). + properties: + preference: + description: A node selector term, associated + with the corresponding weight. + properties: + matchExpressions: + description: A list of node selector requirements + by node's labels. + items: + description: |- + A node selector requirement is a selector that contains values, a key, and an operator + that relates the key and values. + properties: + key: + description: The label key that the + selector applies to. + type: string + operator: + description: |- + Represents a key's relationship to a set of values. + Valid operators are In, NotIn, Exists, DoesNotExist. Gt, and Lt. + type: string + values: + description: |- + An array of string values. If the operator is In or NotIn, + the values array must be non-empty. If the operator is Exists or DoesNotExist, + the values array must be empty. If the operator is Gt or Lt, the values + array must have a single element, which will be interpreted as an integer. + This array is replaced during a strategic merge patch. + items: + type: string + type: array + x-kubernetes-list-type: atomic + required: + - key + - operator + type: object + type: array + x-kubernetes-list-type: atomic + matchFields: + description: A list of node selector requirements + by node's fields. + items: + description: |- + A node selector requirement is a selector that contains values, a key, and an operator + that relates the key and values. + properties: + key: + description: The label key that the + selector applies to. + type: string + operator: + description: |- + Represents a key's relationship to a set of values. + Valid operators are In, NotIn, Exists, DoesNotExist. Gt, and Lt. + type: string + values: + description: |- + An array of string values. If the operator is In or NotIn, + the values array must be non-empty. If the operator is Exists or DoesNotExist, + the values array must be empty. If the operator is Gt or Lt, the values + array must have a single element, which will be interpreted as an integer. + This array is replaced during a strategic merge patch. + items: + type: string + type: array + x-kubernetes-list-type: atomic + required: + - key + - operator + type: object + type: array + x-kubernetes-list-type: atomic + type: object + x-kubernetes-map-type: atomic + weight: + description: Weight associated with matching + the corresponding nodeSelectorTerm, in the + range 1-100. + format: int32 + type: integer + required: + - preference + - weight + type: object + type: array + x-kubernetes-list-type: atomic + requiredDuringSchedulingIgnoredDuringExecution: + description: |- + If the affinity requirements specified by this field are not met at + scheduling time, the pod will not be scheduled onto the node. + If the affinity requirements specified by this field cease to be met + at some point during pod execution (e.g. due to an update), the system + may or may not try to eventually evict the pod from its node. + properties: + nodeSelectorTerms: + description: Required. A list of node selector + terms. The terms are ORed. + items: + description: |- + A null or empty node selector term matches no objects. The requirements of + them are ANDed. + The TopologySelectorTerm type implements a subset of the NodeSelectorTerm. + properties: + matchExpressions: + description: A list of node selector requirements + by node's labels. + items: + description: |- + A node selector requirement is a selector that contains values, a key, and an operator + that relates the key and values. + properties: + key: + description: The label key that the + selector applies to. + type: string + operator: + description: |- + Represents a key's relationship to a set of values. + Valid operators are In, NotIn, Exists, DoesNotExist. Gt, and Lt. + type: string + values: + description: |- + An array of string values. If the operator is In or NotIn, + the values array must be non-empty. If the operator is Exists or DoesNotExist, + the values array must be empty. If the operator is Gt or Lt, the values + array must have a single element, which will be interpreted as an integer. + This array is replaced during a strategic merge patch. + items: + type: string + type: array + x-kubernetes-list-type: atomic + required: + - key + - operator + type: object + type: array + x-kubernetes-list-type: atomic + matchFields: + description: A list of node selector requirements + by node's fields. + items: + description: |- + A node selector requirement is a selector that contains values, a key, and an operator + that relates the key and values. + properties: + key: + description: The label key that the + selector applies to. + type: string + operator: + description: |- + Represents a key's relationship to a set of values. + Valid operators are In, NotIn, Exists, DoesNotExist. Gt, and Lt. + type: string + values: + description: |- + An array of string values. If the operator is In or NotIn, + the values array must be non-empty. If the operator is Exists or DoesNotExist, + the values array must be empty. If the operator is Gt or Lt, the values + array must have a single element, which will be interpreted as an integer. + This array is replaced during a strategic merge patch. + items: + type: string + type: array + x-kubernetes-list-type: atomic + required: + - key + - operator + type: object + type: array + x-kubernetes-list-type: atomic + type: object + x-kubernetes-map-type: atomic + type: array + x-kubernetes-list-type: atomic + required: + - nodeSelectorTerms + type: object + x-kubernetes-map-type: atomic + type: object + podAffinity: + description: Describes pod affinity scheduling rules (e.g. + co-locate this pod in the same node, zone, etc. as some + other pod(s)). + properties: + preferredDuringSchedulingIgnoredDuringExecution: + description: |- + The scheduler will prefer to schedule pods to nodes that satisfy + the affinity expressions specified by this field, but it may choose + a node that violates one or more of the expressions. The node that is + most preferred is the one with the greatest sum of weights, i.e. + for each node that meets all of the scheduling requirements (resource + request, requiredDuringScheduling affinity expressions, etc.), + compute a sum by iterating through the elements of this field and adding + "weight" to the sum if the node has pods which matches the corresponding podAffinityTerm; the + node(s) with the highest sum are the most preferred. + items: + description: The weights of all of the matched WeightedPodAffinityTerm + fields are added per-node to find the most preferred + node(s) + properties: + podAffinityTerm: + description: Required. A pod affinity term, + associated with the corresponding weight. + properties: + labelSelector: + description: |- + A label query over a set of resources, in this case pods. + If it's null, this PodAffinityTerm matches with no Pods. + properties: + matchExpressions: + description: matchExpressions is a list + of label selector requirements. The + requirements are ANDed. + items: + description: |- + A label selector requirement is a selector that contains values, a key, and an operator that + relates the key and values. + properties: + key: + description: key is the label + key that the selector applies + to. + type: string + operator: + description: |- + operator represents a key's relationship to a set of values. + Valid operators are In, NotIn, Exists and DoesNotExist. + type: string + values: + description: |- + values is an array of string values. If the operator is In or NotIn, + the values array must be non-empty. If the operator is Exists or DoesNotExist, + the values array must be empty. This array is replaced during a strategic + merge patch. + items: + type: string + type: array + x-kubernetes-list-type: atomic + required: + - key + - operator + type: object + type: array + x-kubernetes-list-type: atomic + matchLabels: + additionalProperties: + type: string + description: |- + matchLabels is a map of {key,value} pairs. A single {key,value} in the matchLabels + map is equivalent to an element of matchExpressions, whose key field is "key", the + operator is "In", and the values array contains only "value". The requirements are ANDed. + type: object + type: object + x-kubernetes-map-type: atomic + matchLabelKeys: + description: |- + MatchLabelKeys is a set of pod label keys to select which pods will + be taken into consideration. The keys are used to lookup values from the + incoming pod labels, those key-value labels are merged with `labelSelector` as `key in (value)` + to select the group of existing pods which pods will be taken into consideration + for the incoming pod's pod (anti) affinity. Keys that don't exist in the incoming + pod labels will be ignored. The default value is empty. + The same key is forbidden to exist in both matchLabelKeys and labelSelector. + Also, matchLabelKeys cannot be set when labelSelector isn't set. + items: + type: string + type: array + x-kubernetes-list-type: atomic + mismatchLabelKeys: + description: |- + MismatchLabelKeys is a set of pod label keys to select which pods will + be taken into consideration. The keys are used to lookup values from the + incoming pod labels, those key-value labels are merged with `labelSelector` as `key notin (value)` + to select the group of existing pods which pods will be taken into consideration + for the incoming pod's pod (anti) affinity. Keys that don't exist in the incoming + pod labels will be ignored. The default value is empty. + The same key is forbidden to exist in both mismatchLabelKeys and labelSelector. + Also, mismatchLabelKeys cannot be set when labelSelector isn't set. + items: + type: string + type: array + x-kubernetes-list-type: atomic + namespaceSelector: + description: |- + A label query over the set of namespaces that the term applies to. + The term is applied to the union of the namespaces selected by this field + and the ones listed in the namespaces field. + null selector and null or empty namespaces list means "this pod's namespace". + An empty selector ({}) matches all namespaces. + properties: + matchExpressions: + description: matchExpressions is a list + of label selector requirements. The + requirements are ANDed. + items: + description: |- + A label selector requirement is a selector that contains values, a key, and an operator that + relates the key and values. + properties: + key: + description: key is the label + key that the selector applies + to. + type: string + operator: + description: |- + operator represents a key's relationship to a set of values. + Valid operators are In, NotIn, Exists and DoesNotExist. + type: string + values: + description: |- + values is an array of string values. If the operator is In or NotIn, + the values array must be non-empty. If the operator is Exists or DoesNotExist, + the values array must be empty. This array is replaced during a strategic + merge patch. + items: + type: string + type: array + x-kubernetes-list-type: atomic + required: + - key + - operator + type: object + type: array + x-kubernetes-list-type: atomic + matchLabels: + additionalProperties: + type: string + description: |- + matchLabels is a map of {key,value} pairs. A single {key,value} in the matchLabels + map is equivalent to an element of matchExpressions, whose key field is "key", the + operator is "In", and the values array contains only "value". The requirements are ANDed. + type: object + type: object + x-kubernetes-map-type: atomic + namespaces: + description: |- + namespaces specifies a static list of namespace names that the term applies to. + The term is applied to the union of the namespaces listed in this field + and the ones selected by namespaceSelector. + null or empty namespaces list and null namespaceSelector means "this pod's namespace". + items: + type: string + type: array + x-kubernetes-list-type: atomic + topologyKey: + description: |- + This pod should be co-located (affinity) or not co-located (anti-affinity) with the pods matching + the labelSelector in the specified namespaces, where co-located is defined as running on a node + whose value of the label with key topologyKey matches that of any node on which any of the + selected pods is running. + Empty topologyKey is not allowed. + type: string + required: + - topologyKey + type: object + weight: + description: |- + weight associated with matching the corresponding podAffinityTerm, + in the range 1-100. + format: int32 + type: integer + required: + - podAffinityTerm + - weight + type: object + type: array + x-kubernetes-list-type: atomic + requiredDuringSchedulingIgnoredDuringExecution: + description: |- + If the affinity requirements specified by this field are not met at + scheduling time, the pod will not be scheduled onto the node. + If the affinity requirements specified by this field cease to be met + at some point during pod execution (e.g. due to a pod label update), the + system may or may not try to eventually evict the pod from its node. + When there are multiple elements, the lists of nodes corresponding to each + podAffinityTerm are intersected, i.e. all terms must be satisfied. + items: + description: |- + Defines a set of pods (namely those matching the labelSelector + relative to the given namespace(s)) that this pod should be + co-located (affinity) or not co-located (anti-affinity) with, + where co-located is defined as running on a node whose value of + the label with key matches that of any node on which + a pod of the set of pods is running + properties: + labelSelector: + description: |- + A label query over a set of resources, in this case pods. + If it's null, this PodAffinityTerm matches with no Pods. + properties: + matchExpressions: + description: matchExpressions is a list + of label selector requirements. The requirements + are ANDed. + items: + description: |- + A label selector requirement is a selector that contains values, a key, and an operator that + relates the key and values. + properties: + key: + description: key is the label key + that the selector applies to. + type: string + operator: + description: |- + operator represents a key's relationship to a set of values. + Valid operators are In, NotIn, Exists and DoesNotExist. + type: string + values: + description: |- + values is an array of string values. If the operator is In or NotIn, + the values array must be non-empty. If the operator is Exists or DoesNotExist, + the values array must be empty. This array is replaced during a strategic + merge patch. + items: + type: string + type: array + x-kubernetes-list-type: atomic + required: + - key + - operator + type: object + type: array + x-kubernetes-list-type: atomic + matchLabels: + additionalProperties: + type: string + description: |- + matchLabels is a map of {key,value} pairs. A single {key,value} in the matchLabels + map is equivalent to an element of matchExpressions, whose key field is "key", the + operator is "In", and the values array contains only "value". The requirements are ANDed. + type: object + type: object + x-kubernetes-map-type: atomic + matchLabelKeys: + description: |- + MatchLabelKeys is a set of pod label keys to select which pods will + be taken into consideration. The keys are used to lookup values from the + incoming pod labels, those key-value labels are merged with `labelSelector` as `key in (value)` + to select the group of existing pods which pods will be taken into consideration + for the incoming pod's pod (anti) affinity. Keys that don't exist in the incoming + pod labels will be ignored. The default value is empty. + The same key is forbidden to exist in both matchLabelKeys and labelSelector. + Also, matchLabelKeys cannot be set when labelSelector isn't set. + items: + type: string + type: array + x-kubernetes-list-type: atomic + mismatchLabelKeys: + description: |- + MismatchLabelKeys is a set of pod label keys to select which pods will + be taken into consideration. The keys are used to lookup values from the + incoming pod labels, those key-value labels are merged with `labelSelector` as `key notin (value)` + to select the group of existing pods which pods will be taken into consideration + for the incoming pod's pod (anti) affinity. Keys that don't exist in the incoming + pod labels will be ignored. The default value is empty. + The same key is forbidden to exist in both mismatchLabelKeys and labelSelector. + Also, mismatchLabelKeys cannot be set when labelSelector isn't set. + items: + type: string + type: array + x-kubernetes-list-type: atomic + namespaceSelector: + description: |- + A label query over the set of namespaces that the term applies to. + The term is applied to the union of the namespaces selected by this field + and the ones listed in the namespaces field. + null selector and null or empty namespaces list means "this pod's namespace". + An empty selector ({}) matches all namespaces. + properties: + matchExpressions: + description: matchExpressions is a list + of label selector requirements. The requirements + are ANDed. + items: + description: |- + A label selector requirement is a selector that contains values, a key, and an operator that + relates the key and values. + properties: + key: + description: key is the label key + that the selector applies to. + type: string + operator: + description: |- + operator represents a key's relationship to a set of values. + Valid operators are In, NotIn, Exists and DoesNotExist. + type: string + values: + description: |- + values is an array of string values. If the operator is In or NotIn, + the values array must be non-empty. If the operator is Exists or DoesNotExist, + the values array must be empty. This array is replaced during a strategic + merge patch. + items: + type: string + type: array + x-kubernetes-list-type: atomic + required: + - key + - operator + type: object + type: array + x-kubernetes-list-type: atomic + matchLabels: + additionalProperties: + type: string + description: |- + matchLabels is a map of {key,value} pairs. A single {key,value} in the matchLabels + map is equivalent to an element of matchExpressions, whose key field is "key", the + operator is "In", and the values array contains only "value". The requirements are ANDed. + type: object + type: object + x-kubernetes-map-type: atomic + namespaces: + description: |- + namespaces specifies a static list of namespace names that the term applies to. + The term is applied to the union of the namespaces listed in this field + and the ones selected by namespaceSelector. + null or empty namespaces list and null namespaceSelector means "this pod's namespace". + items: + type: string + type: array + x-kubernetes-list-type: atomic + topologyKey: + description: |- + This pod should be co-located (affinity) or not co-located (anti-affinity) with the pods matching + the labelSelector in the specified namespaces, where co-located is defined as running on a node + whose value of the label with key topologyKey matches that of any node on which any of the + selected pods is running. + Empty topologyKey is not allowed. + type: string + required: + - topologyKey + type: object + type: array + x-kubernetes-list-type: atomic + type: object + podAntiAffinity: + description: Describes pod anti-affinity scheduling rules + (e.g. avoid putting this pod in the same node, zone, + etc. as some other pod(s)). + properties: + preferredDuringSchedulingIgnoredDuringExecution: + description: |- + The scheduler will prefer to schedule pods to nodes that satisfy + the anti-affinity expressions specified by this field, but it may choose + a node that violates one or more of the expressions. The node that is + most preferred is the one with the greatest sum of weights, i.e. + for each node that meets all of the scheduling requirements (resource + request, requiredDuringScheduling anti-affinity expressions, etc.), + compute a sum by iterating through the elements of this field and subtracting + "weight" from the sum if the node has pods which matches the corresponding podAffinityTerm; the + node(s) with the highest sum are the most preferred. + items: + description: The weights of all of the matched WeightedPodAffinityTerm + fields are added per-node to find the most preferred + node(s) + properties: + podAffinityTerm: + description: Required. A pod affinity term, + associated with the corresponding weight. + properties: + labelSelector: + description: |- + A label query over a set of resources, in this case pods. + If it's null, this PodAffinityTerm matches with no Pods. + properties: + matchExpressions: + description: matchExpressions is a list + of label selector requirements. The + requirements are ANDed. + items: + description: |- + A label selector requirement is a selector that contains values, a key, and an operator that + relates the key and values. + properties: + key: + description: key is the label + key that the selector applies + to. + type: string + operator: + description: |- + operator represents a key's relationship to a set of values. + Valid operators are In, NotIn, Exists and DoesNotExist. + type: string + values: + description: |- + values is an array of string values. If the operator is In or NotIn, + the values array must be non-empty. If the operator is Exists or DoesNotExist, + the values array must be empty. This array is replaced during a strategic + merge patch. + items: + type: string + type: array + x-kubernetes-list-type: atomic + required: + - key + - operator + type: object + type: array + x-kubernetes-list-type: atomic + matchLabels: + additionalProperties: + type: string + description: |- + matchLabels is a map of {key,value} pairs. A single {key,value} in the matchLabels + map is equivalent to an element of matchExpressions, whose key field is "key", the + operator is "In", and the values array contains only "value". The requirements are ANDed. + type: object + type: object + x-kubernetes-map-type: atomic + matchLabelKeys: + description: |- + MatchLabelKeys is a set of pod label keys to select which pods will + be taken into consideration. The keys are used to lookup values from the + incoming pod labels, those key-value labels are merged with `labelSelector` as `key in (value)` + to select the group of existing pods which pods will be taken into consideration + for the incoming pod's pod (anti) affinity. Keys that don't exist in the incoming + pod labels will be ignored. The default value is empty. + The same key is forbidden to exist in both matchLabelKeys and labelSelector. + Also, matchLabelKeys cannot be set when labelSelector isn't set. + items: + type: string + type: array + x-kubernetes-list-type: atomic + mismatchLabelKeys: + description: |- + MismatchLabelKeys is a set of pod label keys to select which pods will + be taken into consideration. The keys are used to lookup values from the + incoming pod labels, those key-value labels are merged with `labelSelector` as `key notin (value)` + to select the group of existing pods which pods will be taken into consideration + for the incoming pod's pod (anti) affinity. Keys that don't exist in the incoming + pod labels will be ignored. The default value is empty. + The same key is forbidden to exist in both mismatchLabelKeys and labelSelector. + Also, mismatchLabelKeys cannot be set when labelSelector isn't set. + items: + type: string + type: array + x-kubernetes-list-type: atomic + namespaceSelector: + description: |- + A label query over the set of namespaces that the term applies to. + The term is applied to the union of the namespaces selected by this field + and the ones listed in the namespaces field. + null selector and null or empty namespaces list means "this pod's namespace". + An empty selector ({}) matches all namespaces. + properties: + matchExpressions: + description: matchExpressions is a list + of label selector requirements. The + requirements are ANDed. + items: + description: |- + A label selector requirement is a selector that contains values, a key, and an operator that + relates the key and values. + properties: + key: + description: key is the label + key that the selector applies + to. + type: string + operator: + description: |- + operator represents a key's relationship to a set of values. + Valid operators are In, NotIn, Exists and DoesNotExist. + type: string + values: + description: |- + values is an array of string values. If the operator is In or NotIn, + the values array must be non-empty. If the operator is Exists or DoesNotExist, + the values array must be empty. This array is replaced during a strategic + merge patch. + items: + type: string + type: array + x-kubernetes-list-type: atomic + required: + - key + - operator + type: object + type: array + x-kubernetes-list-type: atomic + matchLabels: + additionalProperties: + type: string + description: |- + matchLabels is a map of {key,value} pairs. A single {key,value} in the matchLabels + map is equivalent to an element of matchExpressions, whose key field is "key", the + operator is "In", and the values array contains only "value". The requirements are ANDed. + type: object + type: object + x-kubernetes-map-type: atomic + namespaces: + description: |- + namespaces specifies a static list of namespace names that the term applies to. + The term is applied to the union of the namespaces listed in this field + and the ones selected by namespaceSelector. + null or empty namespaces list and null namespaceSelector means "this pod's namespace". + items: + type: string + type: array + x-kubernetes-list-type: atomic + topologyKey: + description: |- + This pod should be co-located (affinity) or not co-located (anti-affinity) with the pods matching + the labelSelector in the specified namespaces, where co-located is defined as running on a node + whose value of the label with key topologyKey matches that of any node on which any of the + selected pods is running. + Empty topologyKey is not allowed. + type: string + required: + - topologyKey + type: object + weight: + description: |- + weight associated with matching the corresponding podAffinityTerm, + in the range 1-100. + format: int32 + type: integer + required: + - podAffinityTerm + - weight + type: object + type: array + x-kubernetes-list-type: atomic + requiredDuringSchedulingIgnoredDuringExecution: + description: |- + If the anti-affinity requirements specified by this field are not met at + scheduling time, the pod will not be scheduled onto the node. + If the anti-affinity requirements specified by this field cease to be met + at some point during pod execution (e.g. due to a pod label update), the + system may or may not try to eventually evict the pod from its node. + When there are multiple elements, the lists of nodes corresponding to each + podAffinityTerm are intersected, i.e. all terms must be satisfied. + items: + description: |- + Defines a set of pods (namely those matching the labelSelector + relative to the given namespace(s)) that this pod should be + co-located (affinity) or not co-located (anti-affinity) with, + where co-located is defined as running on a node whose value of + the label with key matches that of any node on which + a pod of the set of pods is running + properties: + labelSelector: + description: |- + A label query over a set of resources, in this case pods. + If it's null, this PodAffinityTerm matches with no Pods. + properties: + matchExpressions: + description: matchExpressions is a list + of label selector requirements. The requirements + are ANDed. + items: + description: |- + A label selector requirement is a selector that contains values, a key, and an operator that + relates the key and values. + properties: + key: + description: key is the label key + that the selector applies to. + type: string + operator: + description: |- + operator represents a key's relationship to a set of values. + Valid operators are In, NotIn, Exists and DoesNotExist. + type: string + values: + description: |- + values is an array of string values. If the operator is In or NotIn, + the values array must be non-empty. If the operator is Exists or DoesNotExist, + the values array must be empty. This array is replaced during a strategic + merge patch. + items: + type: string + type: array + x-kubernetes-list-type: atomic + required: + - key + - operator + type: object + type: array + x-kubernetes-list-type: atomic + matchLabels: + additionalProperties: + type: string + description: |- + matchLabels is a map of {key,value} pairs. A single {key,value} in the matchLabels + map is equivalent to an element of matchExpressions, whose key field is "key", the + operator is "In", and the values array contains only "value". The requirements are ANDed. + type: object + type: object + x-kubernetes-map-type: atomic + matchLabelKeys: + description: |- + MatchLabelKeys is a set of pod label keys to select which pods will + be taken into consideration. The keys are used to lookup values from the + incoming pod labels, those key-value labels are merged with `labelSelector` as `key in (value)` + to select the group of existing pods which pods will be taken into consideration + for the incoming pod's pod (anti) affinity. Keys that don't exist in the incoming + pod labels will be ignored. The default value is empty. + The same key is forbidden to exist in both matchLabelKeys and labelSelector. + Also, matchLabelKeys cannot be set when labelSelector isn't set. + items: + type: string + type: array + x-kubernetes-list-type: atomic + mismatchLabelKeys: + description: |- + MismatchLabelKeys is a set of pod label keys to select which pods will + be taken into consideration. The keys are used to lookup values from the + incoming pod labels, those key-value labels are merged with `labelSelector` as `key notin (value)` + to select the group of existing pods which pods will be taken into consideration + for the incoming pod's pod (anti) affinity. Keys that don't exist in the incoming + pod labels will be ignored. The default value is empty. + The same key is forbidden to exist in both mismatchLabelKeys and labelSelector. + Also, mismatchLabelKeys cannot be set when labelSelector isn't set. + items: + type: string + type: array + x-kubernetes-list-type: atomic + namespaceSelector: + description: |- + A label query over the set of namespaces that the term applies to. + The term is applied to the union of the namespaces selected by this field + and the ones listed in the namespaces field. + null selector and null or empty namespaces list means "this pod's namespace". + An empty selector ({}) matches all namespaces. + properties: + matchExpressions: + description: matchExpressions is a list + of label selector requirements. The requirements + are ANDed. + items: + description: |- + A label selector requirement is a selector that contains values, a key, and an operator that + relates the key and values. + properties: + key: + description: key is the label key + that the selector applies to. + type: string + operator: + description: |- + operator represents a key's relationship to a set of values. + Valid operators are In, NotIn, Exists and DoesNotExist. + type: string + values: + description: |- + values is an array of string values. If the operator is In or NotIn, + the values array must be non-empty. If the operator is Exists or DoesNotExist, + the values array must be empty. This array is replaced during a strategic + merge patch. + items: + type: string + type: array + x-kubernetes-list-type: atomic + required: + - key + - operator + type: object + type: array + x-kubernetes-list-type: atomic + matchLabels: + additionalProperties: + type: string + description: |- + matchLabels is a map of {key,value} pairs. A single {key,value} in the matchLabels + map is equivalent to an element of matchExpressions, whose key field is "key", the + operator is "In", and the values array contains only "value". The requirements are ANDed. + type: object + type: object + x-kubernetes-map-type: atomic + namespaces: + description: |- + namespaces specifies a static list of namespace names that the term applies to. + The term is applied to the union of the namespaces listed in this field + and the ones selected by namespaceSelector. + null or empty namespaces list and null namespaceSelector means "this pod's namespace". + items: + type: string + type: array + x-kubernetes-list-type: atomic + topologyKey: + description: |- + This pod should be co-located (affinity) or not co-located (anti-affinity) with the pods matching + the labelSelector in the specified namespaces, where co-located is defined as running on a node + whose value of the label with key topologyKey matches that of any node on which any of the + selected pods is running. + Empty topologyKey is not allowed. + type: string + required: + - topologyKey + type: object + type: array + x-kubernetes-list-type: atomic + type: object + type: object + nodeSelector: + additionalProperties: + type: string + description: |- + nodeSelector is the node selector applied to the relevant kind of pods + It specifies a map of key-value pairs: for the pod to be eligible to run on a node, + the node must have each of the indicated key-value pairs as labels + (it can have additional labels as well). + See https://kubernetes.io/docs/concepts/configuration/assign-pod-node/#nodeselector + type: object + tolerations: + description: |- + tolerations is a list of tolerations applied to the relevant kind of pods + See https://kubernetes.io/docs/concepts/configuration/taint-and-toleration/ for more info. + These are additional tolerations other than default ones. + items: + description: |- + The pod this Toleration is attached to tolerates any taint that matches + the triple using the matching operator . + properties: + effect: + description: |- + Effect indicates the taint effect to match. Empty means match all taint effects. + When specified, allowed values are NoSchedule, PreferNoSchedule and NoExecute. + type: string + key: + description: |- + Key is the taint key that the toleration applies to. Empty means match all taint keys. + If the key is empty, operator must be Exists; this combination means to match all values and all keys. + type: string + operator: + description: |- + Operator represents a key's relationship to the value. + Valid operators are Exists and Equal. Defaults to Equal. + Exists is equivalent to wildcard for value, so that a pod can + tolerate all taints of a particular category. + type: string + tolerationSeconds: + description: |- + TolerationSeconds represents the period of time the toleration (which must be + of effect NoExecute, otherwise this field is ignored) tolerates the taint. By default, + it is not set, which means tolerate the taint forever (do not evict). Zero and + negative values will be treated as 0 (evict immediately) by the system. + format: int64 + type: integer + value: + description: |- + Value is the taint value the toleration matches to. + If the operator is Exists, the value should be empty, otherwise just a regular string. + type: string + type: object + type: array + type: object + type: object + instancetypeConfig: + description: InstancetypeConfig holds the configuration of instance + type related functionality within KubeVirt. + properties: + referencePolicy: + description: |- + ReferencePolicy defines how an instance type or preference should be referenced by the VM after submission, supported values are: + reference (default) - Where a copy of the original object is stashed in a ControllerRevision and referenced by the VM. + expand - Where the instance type or preference are expanded into the VM if no revisionNames have been populated. + expandAll - Where the instance type or preference are expanded into the VM regardless of revisionNames previously being populated. + enum: + - reference + - expand + - expandAll + nullable: true + type: string + type: object + ksmConfiguration: + description: |- + KSMConfiguration holds the information regarding + the enabling the KSM in the nodes (if available). + properties: + nodeLabelSelector: + description: |- + NodeLabelSelector is a selector that filters in which nodes the KSM will be enabled. + Empty NodeLabelSelector will enable ksm for every node. + properties: + matchExpressions: + description: matchExpressions is a list of label selector + requirements. The requirements are ANDed. + items: + description: |- + A label selector requirement is a selector that contains values, a key, and an operator that + relates the key and values. + properties: + key: + description: key is the label key that the selector + applies to. + type: string + operator: + description: |- + operator represents a key's relationship to a set of values. + Valid operators are In, NotIn, Exists and DoesNotExist. + type: string + values: + description: |- + values is an array of string values. If the operator is In or NotIn, + the values array must be non-empty. If the operator is Exists or DoesNotExist, + the values array must be empty. This array is replaced during a strategic + merge patch. + items: + type: string + type: array + x-kubernetes-list-type: atomic + required: + - key + - operator + type: object + type: array + x-kubernetes-list-type: atomic + matchLabels: + additionalProperties: + type: string + description: |- + matchLabels is a map of {key,value} pairs. A single {key,value} in the matchLabels + map is equivalent to an element of matchExpressions, whose key field is "key", the + operator is "In", and the values array contains only "value". The requirements are ANDed. + type: object + type: object + x-kubernetes-map-type: atomic + type: object + kubeMacPoolConfiguration: + description: KubeMacPoolConfiguration holds kubemacpool MAC address + range configuration. + properties: + rangeEnd: + description: |- + RangeEnd defines the last MAC address in the kubemacpool range. + The MAC address format should be AA:BB:CC:DD:EE:FF. + pattern: ^([0-9a-fA-F]{2}:){5}[0-9a-fA-F]{2}$ + type: string + rangeStart: + description: |- + RangeStart defines the first MAC address in the kubemacpool range. + The MAC address format should be AA:BB:CC:DD:EE:FF. + pattern: ^([0-9a-fA-F]{2}:){5}[0-9a-fA-F]{2}$ + type: string + type: object + x-kubernetes-validations: + - message: both rangeStart and rangeEnd must be configured together, + or both omitted + rule: (has(self.rangeStart) && has(self.rangeEnd)) || (!has(self.rangeStart) + && !has(self.rangeEnd)) + kubeSecondaryDNSNameServerIP: + description: KubeSecondaryDNSNameServerIP defines name server IP used + by KubeSecondaryDNS + type: string + liveMigrationConfig: + default: + allowAutoConverge: false + allowPostCopy: false + completionTimeoutPerGiB: 150 + parallelMigrationsPerCluster: 5 + parallelOutboundMigrationsPerNode: 2 + progressTimeout: 150 + description: |- + Live migration limits and timeouts are applied so that migration processes do not + overwhelm the cluster. + properties: + allowAutoConverge: + default: false + description: |- + AllowAutoConverge allows the platform to compromise performance/availability of VMIs to + guarantee successful VMI live migrations. Defaults to false + type: boolean + allowPostCopy: + default: false + description: |- + When enabled, KubeVirt attempts to use post-copy live-migration in case it + reaches its completion timeout while attempting pre-copy live-migration. + Post-copy migrations allow even the busiest VMs to successfully live-migrate. + However, events like a network failure or a failure in any of the source or + destination nodes can cause the migrated VM to crash or reach inconsistency. + Enable this option when evicting nodes is more important than keeping VMs + alive. + Defaults to false. + type: boolean + bandwidthPerMigration: + description: Bandwidth limit of each migration, the value is quantity + of bytes per second (e.g. 2048Mi = 2048MiB/sec) + pattern: ^(\+|-)?(([0-9]+(\.[0-9]*)?)|(\.[0-9]+))(([KMGTPE]i)|[numkMGTPE]|([eE](\+|-)?(([0-9]+(\.[0-9]*)?)|(\.[0-9]+))))?$ + type: string + completionTimeoutPerGiB: + default: 150 + description: |- + If a migrating VM is big and busy, while the connection to the destination node + is slow, migration may never converge. The completion timeout is calculated + based on completionTimeoutPerGiB times the size of the guest (both RAM and + migrated disks, if any). For example, with completionTimeoutPerGiB set to 800, + a virtual machine instance with 6GiB memory will timeout if it has not + completed migration in 1h20m. Use a lower completionTimeoutPerGiB to induce + quicker failure, so that another destination or post-copy is attempted. Use a + higher completionTimeoutPerGiB to let workload with spikes in its memory dirty + rate to converge. + The format is a number. + format: int64 + type: integer + network: + description: The migrations will be performed over a dedicated + multus network to minimize disruption to tenant workloads due + to network saturation when VM live migrations are triggered. + type: string + parallelMigrationsPerCluster: + default: 5 + description: Number of migrations running in parallel in the cluster. + format: int32 + type: integer + parallelOutboundMigrationsPerNode: + default: 2 + description: Maximum number of outbound migrations per node. + format: int32 + type: integer + progressTimeout: + default: 150 + description: The migration will be canceled if memory copy fails + to make progress in this time, in seconds. + format: int64 + type: integer + type: object + liveUpdateConfiguration: + description: |- + LiveUpdateConfiguration holds the cluster configuration for live update of virtual machines - max cpu sockets, + max guest memory and max hotplug ratio. This setting can affect VM CPU and memory settings. + properties: + maxCpuSockets: + description: |- + MaxCpuSockets provides a MaxSockets value for VMs that do not provide their own. + For VMs with more sockets than maximum the MaxSockets will be set to equal number of sockets. + format: int32 + type: integer + maxGuest: + anyOf: + - type: integer + - type: string + description: |- + MaxGuest defines the maximum amount memory that can be allocated + to the guest using hotplug. + pattern: ^(\+|-)?(([0-9]+(\.[0-9]*)?)|(\.[0-9]+))(([KMGTPE]i)|[numkMGTPE]|([eE](\+|-)?(([0-9]+(\.[0-9]*)?)|(\.[0-9]+))))?$ + x-kubernetes-int-or-string: true + maxHotplugRatio: + description: |- + MaxHotplugRatio is the ratio used to define the max amount + of a hotplug resource that can be made available to a VM + when the specific Max* setting is not defined (MaxCpuSockets, MaxGuest) + Example: VM is configured with 512Mi of guest memory, if MaxGuest is not + defined and MaxHotplugRatio is 2 then MaxGuest = 1Gi + defaults to 4 + format: int32 + type: integer + type: object + logVerbosityConfig: + description: |- + LogVerbosityConfig configures the verbosity level of Kubevirt's different components. The higher + the value - the higher the log verbosity. + properties: + cdi: + description: CDI indicates the log verbosity level that controls + the amount of information logged for CDI components. + format: int32 + type: integer + kubevirt: + description: |- + Kubevirt is a struct that allows specifying the log verbosity level that controls the amount of information + logged for each Kubevirt component. + properties: + nodeVerbosity: + additionalProperties: + type: integer + description: NodeVerbosity represents a map of nodes with + a specific verbosity level + type: object + virtAPI: + type: integer + virtController: + type: integer + virtHandler: + type: integer + virtLauncher: + type: integer + virtOperator: + type: integer + virtSynchronizationController: + type: integer + type: object + type: object + mediatedDevicesConfiguration: + description: MediatedDevicesConfiguration holds information about + MDEV types to be defined on nodes, if available + properties: + mediatedDeviceTypes: + items: + type: string + type: array + x-kubernetes-list-type: atomic + nodeMediatedDeviceTypes: + items: + description: NodeMediatedDeviceTypesConfig holds information + about MDEV types to be defined in a specific node that matches + the NodeSelector field. + properties: + mediatedDeviceTypes: + items: + type: string + type: array + x-kubernetes-list-type: atomic + nodeSelector: + additionalProperties: + type: string + description: |- + NodeSelector is a selector which must be true for the vmi to fit on a node. + Selector which must match a node's labels for the vmi to be scheduled on that node. + More info: https://kubernetes.io/docs/concepts/configuration/assign-pod-node/ + type: object + required: + - nodeSelector + type: object + type: array + x-kubernetes-list-type: atomic + type: object + networkBinding: + additionalProperties: + properties: + computeResourceOverhead: + description: |- + ComputeResourceOverhead specifies the resource overhead that should be added to the compute container when using the binding. + version: v1alphav1 + properties: + limits: + additionalProperties: + anyOf: + - type: integer + - type: string + pattern: ^(\+|-)?(([0-9]+(\.[0-9]*)?)|(\.[0-9]+))(([KMGTPE]i)|[numkMGTPE]|([eE](\+|-)?(([0-9]+(\.[0-9]*)?)|(\.[0-9]+))))?$ + x-kubernetes-int-or-string: true + description: |- + Limits describes the maximum amount of compute resources allowed. + More info: https://kubernetes.io/docs/concepts/configuration/manage-resources-containers/ + type: object + requests: + additionalProperties: + anyOf: + - type: integer + - type: string + pattern: ^(\+|-)?(([0-9]+(\.[0-9]*)?)|(\.[0-9]+))(([KMGTPE]i)|[numkMGTPE]|([eE](\+|-)?(([0-9]+(\.[0-9]*)?)|(\.[0-9]+))))?$ + x-kubernetes-int-or-string: true + description: |- + Requests describes the minimum amount of compute resources required. + If Requests is omitted for a container, it defaults to Limits if that is explicitly specified, + otherwise to an implementation-defined value. Requests cannot exceed Limits. + More info: https://kubernetes.io/docs/concepts/configuration/manage-resources-containers/ + type: object + type: object + domainAttachmentType: + description: |- + DomainAttachmentType is a standard domain network attachment method kubevirt supports. + Supported values: "tap", "managedTap" (since v1.4). + The standard domain attachment can be used instead or in addition to the sidecarImage. + version: 1alphav1 + type: string + downwardAPI: + description: |- + DownwardAPI specifies what kind of data should be exposed to the binding plugin sidecar. + Supported values: "device-info" + version: v1alphav1 + type: string + migration: + description: |- + Migration means the VM using the plugin can be safely migrated + version: 1alphav1 + properties: + method: + description: |- + Method defines a pre-defined migration methodology + version: 1alphav1 + type: string + type: object + networkAttachmentDefinition: + description: |- + NetworkAttachmentDefinition references to a NetworkAttachmentDefinition CR object. + Format: , /. + If namespace is not specified, VMI namespace is assumed. + version: 1alphav1 + type: string + sidecarImage: + description: |- + SidecarImage references a container image that runs in the virt-launcher pod. + The sidecar handles (libvirt) domain configuration and optional services. + version: 1alphav1 + type: string + type: object + description: |- + NetworkBinding defines the network binding plugins. + Those bindings can be used when defining virtual machine interfaces. + type: object + obsoleteCPUs: + description: ObsoleteCPUs allows avoiding scheduling of VMs for obsolete + CPU models + properties: + cpuModels: + description: |- + CPUModels is a list of obsolete CPU models. When the node-labeller obtains the list of obsolete CPU models, it + eliminates those CPU models and creates labels for valid CPU models. + The default values for this field is nil, however, HCO uses opinionated values, and adding values to this list + will add them to the opinionated values. + items: + type: string + type: array + x-kubernetes-list-type: set + type: object + permittedHostDevices: + description: PermittedHostDevices holds information about devices + allowed for passthrough + properties: + mediatedDevices: + items: + description: MediatedHostDevice represents a host mediated device + allowed for passthrough + properties: + disabled: + description: |- + HCO enforces the existence of several MediatedHostDevice objects. Set disabled field to true instead of remove + these objects. + type: boolean + externalResourceProvider: + description: indicates that this resource is being provided + by an external device plugin + type: boolean + mdevNameSelector: + description: name of a mediated device type required to + identify a mediated device on a host + type: string + resourceName: + description: name by which a device is advertised and being + requested + type: string + required: + - mdevNameSelector + - resourceName + type: object + type: array + x-kubernetes-list-map-keys: + - mdevNameSelector + x-kubernetes-list-type: map + pciHostDevices: + items: + description: PciHostDevice represents a host PCI device allowed + for passthrough + properties: + disabled: + description: |- + HCO enforces the existence of several PciHostDevice objects. Set disabled field to true instead of remove + these objects. + type: boolean + externalResourceProvider: + description: indicates that this resource is being provided + by an external device plugin + type: boolean + pciDeviceSelector: + description: a combination of a vendor_id:product_id required + to identify a PCI device on a host. + type: string + resourceName: + description: name by which a device is advertised and being + requested + type: string + required: + - pciDeviceSelector + - resourceName + type: object + type: array + x-kubernetes-list-map-keys: + - pciDeviceSelector + x-kubernetes-list-type: map + usbHostDevices: + items: + description: USBHostDevice represents a host USB device allowed + for passthrough + properties: + disabled: + description: |- + HCO enforces the existence of several USBHostDevice objects. Set disabled field to true instead of remove + these objects. + type: boolean + externalResourceProvider: + description: |- + If true, KubeVirt will leave the allocation and monitoring to an + external device plugin + type: boolean + resourceName: + description: |- + Identifies the list of USB host devices. + e.g: kubevirt.io/storage, kubevirt.io/bootable-usb, etc + type: string + selectors: + items: + description: USBSelector represents a selector for a USB + device allowed for passthrough + properties: + product: + type: string + vendor: + type: string + required: + - product + - vendor + type: object + type: array + x-kubernetes-list-type: atomic + required: + - resourceName + type: object + type: array + x-kubernetes-list-map-keys: + - resourceName + x-kubernetes-list-type: map + type: object + resourceRequirements: + default: + vmiCPUAllocationRatio: 10 + description: ResourceRequirements describes the resource requirements + for the operand workloads. + properties: + autoCPULimitNamespaceLabelSelector: + description: |- + When set, AutoCPULimitNamespaceLabelSelector will set a CPU limit on virt-launcher for VMIs running inside + namespaces that match the label selector. + The CPU limit will equal the number of requested vCPUs. + This setting does not apply to VMIs with dedicated CPUs. + properties: + matchExpressions: + description: matchExpressions is a list of label selector + requirements. The requirements are ANDed. + items: + description: |- + A label selector requirement is a selector that contains values, a key, and an operator that + relates the key and values. + properties: + key: + description: key is the label key that the selector + applies to. + type: string + operator: + description: |- + operator represents a key's relationship to a set of values. + Valid operators are In, NotIn, Exists and DoesNotExist. + type: string + values: + description: |- + values is an array of string values. If the operator is In or NotIn, + the values array must be non-empty. If the operator is Exists or DoesNotExist, + the values array must be empty. This array is replaced during a strategic + merge patch. + items: + type: string + type: array + x-kubernetes-list-type: atomic + required: + - key + - operator + type: object + type: array + x-kubernetes-list-type: atomic + matchLabels: + additionalProperties: + type: string + description: |- + matchLabels is a map of {key,value} pairs. A single {key,value} in the matchLabels + map is equivalent to an element of matchExpressions, whose key field is "key", the + operator is "In", and the values array contains only "value". The requirements are ANDed. + type: object + type: object + x-kubernetes-map-type: atomic + storageWorkloads: + description: |- + StorageWorkloads defines the resources requirements for storage workloads. It will propagate to the CDI custom + resource + properties: + claims: + description: |- + Claims lists the names of resources, defined in spec.resourceClaims, + that are used by this container. + + This field depends on the + DynamicResourceAllocation feature gate. + + This field is immutable. It can only be set for containers. + items: + description: ResourceClaim references one entry in PodSpec.ResourceClaims. + properties: + name: + description: |- + Name must match the name of one entry in pod.spec.resourceClaims of + the Pod where this field is used. It makes that resource available + inside a container. + type: string + request: + description: |- + Request is the name chosen for a request in the referenced claim. + If empty, everything from the claim is made available, otherwise + only the result of this request. + type: string + required: + - name + type: object + type: array + x-kubernetes-list-map-keys: + - name + x-kubernetes-list-type: map + limits: + additionalProperties: + anyOf: + - type: integer + - type: string + pattern: ^(\+|-)?(([0-9]+(\.[0-9]*)?)|(\.[0-9]+))(([KMGTPE]i)|[numkMGTPE]|([eE](\+|-)?(([0-9]+(\.[0-9]*)?)|(\.[0-9]+))))?$ + x-kubernetes-int-or-string: true + description: |- + Limits describes the maximum amount of compute resources allowed. + More info: https://kubernetes.io/docs/concepts/configuration/manage-resources-containers/ + type: object + requests: + additionalProperties: + anyOf: + - type: integer + - type: string + pattern: ^(\+|-)?(([0-9]+(\.[0-9]*)?)|(\.[0-9]+))(([KMGTPE]i)|[numkMGTPE]|([eE](\+|-)?(([0-9]+(\.[0-9]*)?)|(\.[0-9]+))))?$ + x-kubernetes-int-or-string: true + description: |- + Requests describes the minimum amount of compute resources required. + If Requests is omitted for a container, it defaults to Limits if that is explicitly specified, + otherwise to an implementation-defined value. Requests cannot exceed Limits. + More info: https://kubernetes.io/docs/concepts/configuration/manage-resources-containers/ + type: object + type: object + vmiCPUAllocationRatio: + default: 10 + description: |- + VmiCPUAllocationRatio defines, for each requested virtual CPU, + how much physical CPU to request per VMI from the + hosting node. The value is in fraction of a CPU thread (or + core on non-hyperthreaded nodes). + VMI POD CPU request = number of vCPUs * 1/vmiCPUAllocationRatio + For example, a value of 1 means 1 physical CPU thread per VMI CPU thread. + A value of 100 would be 1% of a physical thread allocated for each + requested VMI thread. + This option has no effect on VMIs that request dedicated CPUs. + Defaults to 10 + minimum: 1 + type: integer + type: object + x-kubernetes-validations: + - message: vmiCPUAllocationRatio must be greater than 0 + rule: '!has(self.vmiCPUAllocationRatio) || self.vmiCPUAllocationRatio + > 0' + scratchSpaceStorageClass: + description: |- + Override the storage class used for scratch space during transfer operations. The scratch space storage class + is determined in the following order: + value of scratchSpaceStorageClass, if that doesn't exist, use the default storage class, if there is no default + storage class, use the storage class of the DataVolume, if no storage class specified, use no storage class for + scratch space + type: string + storageImport: + description: StorageImport contains configuration for importing containerized + data + properties: + insecureRegistries: + description: |- + InsecureRegistries is a list of image registries URLs that are not secured. Setting an insecure registry URL + in this list allows pulling images from this registry. + items: + type: string + type: array + x-kubernetes-list-type: set + type: object + tlsSecurityProfile: + description: |- + TLSSecurityProfile specifies the settings for TLS connections to be propagated to all kubevirt-hyperconverged components. + If unset, the hyperconverged cluster operator will consume the value set on the APIServer CR on OCP/OKD or Intermediate if on vanilla k8s. + Note that only Old, Intermediate and Custom profiles are currently supported, and the maximum available + MinTLSVersions is VersionTLS12. + properties: + custom: + description: |- + custom is a user-defined TLS security profile. Be extremely careful using a custom + profile as invalid configurations can be catastrophic. An example custom profile + looks like this: + + ciphers: + + - ECDHE-ECDSA-CHACHA20-POLY1305 + + - ECDHE-RSA-CHACHA20-POLY1305 + + - ECDHE-RSA-AES128-GCM-SHA256 + + - ECDHE-ECDSA-AES128-GCM-SHA256 + + minTLSVersion: VersionTLS11 + nullable: true + properties: + ciphers: + description: |- + ciphers is used to specify the cipher algorithms that are negotiated + during the TLS handshake. Operators may remove entries their operands + do not support. For example, to use DES-CBC3-SHA (yaml): + + ciphers: + - DES-CBC3-SHA + items: + type: string + type: array + x-kubernetes-list-type: atomic + minTLSVersion: + description: |- + minTLSVersion is used to specify the minimal version of the TLS protocol + that is negotiated during the TLS handshake. For example, to use TLS + versions 1.1, 1.2 and 1.3 (yaml): + + minTLSVersion: VersionTLS11 + + NOTE: currently the highest minTLSVersion allowed is VersionTLS12 + enum: + - VersionTLS10 + - VersionTLS11 + - VersionTLS12 + - VersionTLS13 + type: string + type: object + intermediate: + description: |- + intermediate is a TLS security profile based on: + + https://wiki.mozilla.org/Security/Server_Side_TLS#Intermediate_compatibility_.28recommended.29 + + and looks like this (yaml): + + ciphers: + + - TLS_AES_128_GCM_SHA256 + + - TLS_AES_256_GCM_SHA384 + + - TLS_CHACHA20_POLY1305_SHA256 + + - ECDHE-ECDSA-AES128-GCM-SHA256 + + - ECDHE-RSA-AES128-GCM-SHA256 + + - ECDHE-ECDSA-AES256-GCM-SHA384 + + - ECDHE-RSA-AES256-GCM-SHA384 + + - ECDHE-ECDSA-CHACHA20-POLY1305 + + - ECDHE-RSA-CHACHA20-POLY1305 + + - DHE-RSA-AES128-GCM-SHA256 + + - DHE-RSA-AES256-GCM-SHA384 + + minTLSVersion: VersionTLS12 + nullable: true + type: object + modern: + description: |- + modern is a TLS security profile based on: + + https://wiki.mozilla.org/Security/Server_Side_TLS#Modern_compatibility + + and looks like this (yaml): + + ciphers: + + - TLS_AES_128_GCM_SHA256 + + - TLS_AES_256_GCM_SHA384 + + - TLS_CHACHA20_POLY1305_SHA256 + + minTLSVersion: VersionTLS13 + nullable: true + type: object + old: + description: |- + old is a TLS security profile based on: + + https://wiki.mozilla.org/Security/Server_Side_TLS#Old_backward_compatibility + + and looks like this (yaml): + + ciphers: + + - TLS_AES_128_GCM_SHA256 + + - TLS_AES_256_GCM_SHA384 + + - TLS_CHACHA20_POLY1305_SHA256 + + - ECDHE-ECDSA-AES128-GCM-SHA256 + + - ECDHE-RSA-AES128-GCM-SHA256 + + - ECDHE-ECDSA-AES256-GCM-SHA384 + + - ECDHE-RSA-AES256-GCM-SHA384 + + - ECDHE-ECDSA-CHACHA20-POLY1305 + + - ECDHE-RSA-CHACHA20-POLY1305 + + - DHE-RSA-AES128-GCM-SHA256 + + - DHE-RSA-AES256-GCM-SHA384 + + - DHE-RSA-CHACHA20-POLY1305 + + - ECDHE-ECDSA-AES128-SHA256 + + - ECDHE-RSA-AES128-SHA256 + + - ECDHE-ECDSA-AES128-SHA + + - ECDHE-RSA-AES128-SHA + + - ECDHE-ECDSA-AES256-SHA384 + + - ECDHE-RSA-AES256-SHA384 + + - ECDHE-ECDSA-AES256-SHA + + - ECDHE-RSA-AES256-SHA + + - DHE-RSA-AES128-SHA256 + + - DHE-RSA-AES256-SHA256 + + - AES128-GCM-SHA256 + + - AES256-GCM-SHA384 + + - AES128-SHA256 + + - AES256-SHA256 + + - AES128-SHA + + - AES256-SHA + + - DES-CBC3-SHA + + minTLSVersion: VersionTLS10 + nullable: true + type: object + type: + description: |- + type is one of Old, Intermediate, Modern or Custom. Custom provides + the ability to specify individual TLS security profile parameters. + Old, Intermediate and Modern are TLS security profiles based on: + + https://wiki.mozilla.org/Security/Server_Side_TLS#Recommended_configurations + + The profiles are intent based, so they may change over time as new ciphers are developed and existing ciphers + are found to be insecure. Depending on precisely which ciphers are available to a process, the list may be + reduced. + + Note that the Modern profile is currently not supported because it is not + yet well adopted by common software libraries. + enum: + - Old + - Intermediate + - Modern + - Custom + type: string + type: object + tuningPolicy: + description: |- + TuningPolicy allows to configure the mode in which the RateLimits of kubevirt are set. + If TuningPolicy is not present the default kubevirt values are used. + It can be set to `annotation` for fine-tuning the kubevirt queryPerSeconds (qps) and burst values. + Qps and burst values are taken from the annotation hco.kubevirt.io/tuningPolicy + enum: + - annotation + - highBurst + type: string + uninstallStrategy: + default: BlockUninstallIfWorkloadsExist + description: |- + UninstallStrategy defines how to proceed on uninstall when workloads (VirtualMachines, DataVolumes) still exist. + BlockUninstallIfWorkloadsExist will prevent the CR from being removed when workloads still exist. + BlockUninstallIfWorkloadsExist is the safest choice to protect your workloads from accidental data loss, so it's strongly advised. + RemoveWorkloads will cause all the workloads to be cascading deleted on uninstallation. + WARNING: please notice that RemoveWorkloads will cause your workloads to be deleted as soon as this CR will be, even accidentally, deleted. + Please correctly consider the implications of this option before setting it. + BlockUninstallIfWorkloadsExist is the default behaviour. + enum: + - RemoveWorkloads + - BlockUninstallIfWorkloadsExist + type: string + virtualMachineOptions: + default: + disableFreePageReporting: false + disableSerialConsoleLog: false + description: VirtualMachineOptions holds the cluster level information + regarding the virtual machine. + properties: + disableFreePageReporting: + default: false + description: |- + DisableFreePageReporting disable the free page reporting of + memory balloon device https://libvirt.org/formatdomain.html#memory-balloon-device. + This will have effect only if AutoattachMemBalloon is not false and the vmi is not + requesting any high performance feature (dedicatedCPU/realtime/hugePages), in which free page reporting is always disabled. + type: boolean + disableSerialConsoleLog: + default: false + description: |- + DisableSerialConsoleLog disables logging the auto-attached default serial console. + If not set, serial console logs will be written to a file and then streamed from a container named `guest-console-log`. + The value can be individually overridden for each VM, not relevant if AutoattachSerialConsole is disabled for the VM. + type: boolean + type: object + vmStateStorageClass: + description: VMStateStorageClass is the name of the storage class + to use for the PVCs created to preserve VM state, like TPM. + type: string + workloadUpdateStrategy: + default: + batchEvictionInterval: 1m0s + batchEvictionSize: 10 + workloadUpdateMethods: + - LiveMigrate + description: WorkloadUpdateStrategy defines at the cluster level how + to handle automated workload updates + properties: + batchEvictionInterval: + default: 1m0s + description: |- + BatchEvictionInterval Represents the interval to wait before issuing the next + batch of shutdowns + type: string + batchEvictionSize: + default: 10 + description: |- + BatchEvictionSize Represents the number of VMIs that can be forced updated per + the BatchShutdownInterval interval + type: integer + workloadUpdateMethods: + default: + - LiveMigrate + description: |- + WorkloadUpdateMethods defines the methods that can be used to disrupt workloads + during automated workload updates. + When multiple methods are present, the least disruptive method takes + precedence over more disruptive methods. For example if both LiveMigrate and Evict + methods are listed, only VMs which are not live migratable will be restarted/shutdown. + An empty list defaults to no automated workload updating. + items: + type: string + type: array + x-kubernetes-list-type: atomic + required: + - workloadUpdateMethods + type: object + workloads: + description: |- + workloads HyperConvergedConfig influences the pod configuration (currently only placement) of components + which need to be running on a node where virtualization workloads should be able to run. + Changes to Workloads HyperConvergedConfig can be applied only without existing workload. + properties: + nodePlacement: + description: NodePlacement describes node scheduling configuration. + properties: + affinity: + description: |- + affinity enables pod affinity/anti-affinity placement expanding the types of constraints + that can be expressed with nodeSelector. + affinity is going to be applied to the relevant kind of pods in parallel with nodeSelector + See https://kubernetes.io/docs/concepts/scheduling-eviction/assign-pod-node/#affinity-and-anti-affinity + properties: + nodeAffinity: + description: Describes node affinity scheduling rules + for the pod. + properties: + preferredDuringSchedulingIgnoredDuringExecution: + description: |- + The scheduler will prefer to schedule pods to nodes that satisfy + the affinity expressions specified by this field, but it may choose + a node that violates one or more of the expressions. The node that is + most preferred is the one with the greatest sum of weights, i.e. + for each node that meets all of the scheduling requirements (resource + request, requiredDuringScheduling affinity expressions, etc.), + compute a sum by iterating through the elements of this field and adding + "weight" to the sum if the node matches the corresponding matchExpressions; the + node(s) with the highest sum are the most preferred. + items: + description: |- + An empty preferred scheduling term matches all objects with implicit weight 0 + (i.e. it's a no-op). A null preferred scheduling term matches no objects (i.e. is also a no-op). + properties: + preference: + description: A node selector term, associated + with the corresponding weight. + properties: + matchExpressions: + description: A list of node selector requirements + by node's labels. + items: + description: |- + A node selector requirement is a selector that contains values, a key, and an operator + that relates the key and values. + properties: + key: + description: The label key that the + selector applies to. + type: string + operator: + description: |- + Represents a key's relationship to a set of values. + Valid operators are In, NotIn, Exists, DoesNotExist. Gt, and Lt. + type: string + values: + description: |- + An array of string values. If the operator is In or NotIn, + the values array must be non-empty. If the operator is Exists or DoesNotExist, + the values array must be empty. If the operator is Gt or Lt, the values + array must have a single element, which will be interpreted as an integer. + This array is replaced during a strategic merge patch. + items: + type: string + type: array + x-kubernetes-list-type: atomic + required: + - key + - operator + type: object + type: array + x-kubernetes-list-type: atomic + matchFields: + description: A list of node selector requirements + by node's fields. + items: + description: |- + A node selector requirement is a selector that contains values, a key, and an operator + that relates the key and values. + properties: + key: + description: The label key that the + selector applies to. + type: string + operator: + description: |- + Represents a key's relationship to a set of values. + Valid operators are In, NotIn, Exists, DoesNotExist. Gt, and Lt. + type: string + values: + description: |- + An array of string values. If the operator is In or NotIn, + the values array must be non-empty. If the operator is Exists or DoesNotExist, + the values array must be empty. If the operator is Gt or Lt, the values + array must have a single element, which will be interpreted as an integer. + This array is replaced during a strategic merge patch. + items: + type: string + type: array + x-kubernetes-list-type: atomic + required: + - key + - operator + type: object + type: array + x-kubernetes-list-type: atomic + type: object + x-kubernetes-map-type: atomic + weight: + description: Weight associated with matching + the corresponding nodeSelectorTerm, in the + range 1-100. + format: int32 + type: integer + required: + - preference + - weight + type: object + type: array + x-kubernetes-list-type: atomic + requiredDuringSchedulingIgnoredDuringExecution: + description: |- + If the affinity requirements specified by this field are not met at + scheduling time, the pod will not be scheduled onto the node. + If the affinity requirements specified by this field cease to be met + at some point during pod execution (e.g. due to an update), the system + may or may not try to eventually evict the pod from its node. + properties: + nodeSelectorTerms: + description: Required. A list of node selector + terms. The terms are ORed. + items: + description: |- + A null or empty node selector term matches no objects. The requirements of + them are ANDed. + The TopologySelectorTerm type implements a subset of the NodeSelectorTerm. + properties: + matchExpressions: + description: A list of node selector requirements + by node's labels. + items: + description: |- + A node selector requirement is a selector that contains values, a key, and an operator + that relates the key and values. + properties: + key: + description: The label key that the + selector applies to. + type: string + operator: + description: |- + Represents a key's relationship to a set of values. + Valid operators are In, NotIn, Exists, DoesNotExist. Gt, and Lt. + type: string + values: + description: |- + An array of string values. If the operator is In or NotIn, + the values array must be non-empty. If the operator is Exists or DoesNotExist, + the values array must be empty. If the operator is Gt or Lt, the values + array must have a single element, which will be interpreted as an integer. + This array is replaced during a strategic merge patch. + items: + type: string + type: array + x-kubernetes-list-type: atomic + required: + - key + - operator + type: object + type: array + x-kubernetes-list-type: atomic + matchFields: + description: A list of node selector requirements + by node's fields. + items: + description: |- + A node selector requirement is a selector that contains values, a key, and an operator + that relates the key and values. + properties: + key: + description: The label key that the + selector applies to. + type: string + operator: + description: |- + Represents a key's relationship to a set of values. + Valid operators are In, NotIn, Exists, DoesNotExist. Gt, and Lt. + type: string + values: + description: |- + An array of string values. If the operator is In or NotIn, + the values array must be non-empty. If the operator is Exists or DoesNotExist, + the values array must be empty. If the operator is Gt or Lt, the values + array must have a single element, which will be interpreted as an integer. + This array is replaced during a strategic merge patch. + items: + type: string + type: array + x-kubernetes-list-type: atomic + required: + - key + - operator + type: object + type: array + x-kubernetes-list-type: atomic + type: object + x-kubernetes-map-type: atomic + type: array + x-kubernetes-list-type: atomic + required: + - nodeSelectorTerms + type: object + x-kubernetes-map-type: atomic + type: object + podAffinity: + description: Describes pod affinity scheduling rules (e.g. + co-locate this pod in the same node, zone, etc. as some + other pod(s)). + properties: + preferredDuringSchedulingIgnoredDuringExecution: + description: |- + The scheduler will prefer to schedule pods to nodes that satisfy + the affinity expressions specified by this field, but it may choose + a node that violates one or more of the expressions. The node that is + most preferred is the one with the greatest sum of weights, i.e. + for each node that meets all of the scheduling requirements (resource + request, requiredDuringScheduling affinity expressions, etc.), + compute a sum by iterating through the elements of this field and adding + "weight" to the sum if the node has pods which matches the corresponding podAffinityTerm; the + node(s) with the highest sum are the most preferred. + items: + description: The weights of all of the matched WeightedPodAffinityTerm + fields are added per-node to find the most preferred + node(s) + properties: + podAffinityTerm: + description: Required. A pod affinity term, + associated with the corresponding weight. + properties: + labelSelector: + description: |- + A label query over a set of resources, in this case pods. + If it's null, this PodAffinityTerm matches with no Pods. + properties: + matchExpressions: + description: matchExpressions is a list + of label selector requirements. The + requirements are ANDed. + items: + description: |- + A label selector requirement is a selector that contains values, a key, and an operator that + relates the key and values. + properties: + key: + description: key is the label + key that the selector applies + to. + type: string + operator: + description: |- + operator represents a key's relationship to a set of values. + Valid operators are In, NotIn, Exists and DoesNotExist. + type: string + values: + description: |- + values is an array of string values. If the operator is In or NotIn, + the values array must be non-empty. If the operator is Exists or DoesNotExist, + the values array must be empty. This array is replaced during a strategic + merge patch. + items: + type: string + type: array + x-kubernetes-list-type: atomic + required: + - key + - operator + type: object + type: array + x-kubernetes-list-type: atomic + matchLabels: + additionalProperties: + type: string + description: |- + matchLabels is a map of {key,value} pairs. A single {key,value} in the matchLabels + map is equivalent to an element of matchExpressions, whose key field is "key", the + operator is "In", and the values array contains only "value". The requirements are ANDed. + type: object + type: object + x-kubernetes-map-type: atomic + matchLabelKeys: + description: |- + MatchLabelKeys is a set of pod label keys to select which pods will + be taken into consideration. The keys are used to lookup values from the + incoming pod labels, those key-value labels are merged with `labelSelector` as `key in (value)` + to select the group of existing pods which pods will be taken into consideration + for the incoming pod's pod (anti) affinity. Keys that don't exist in the incoming + pod labels will be ignored. The default value is empty. + The same key is forbidden to exist in both matchLabelKeys and labelSelector. + Also, matchLabelKeys cannot be set when labelSelector isn't set. + items: + type: string + type: array + x-kubernetes-list-type: atomic + mismatchLabelKeys: + description: |- + MismatchLabelKeys is a set of pod label keys to select which pods will + be taken into consideration. The keys are used to lookup values from the + incoming pod labels, those key-value labels are merged with `labelSelector` as `key notin (value)` + to select the group of existing pods which pods will be taken into consideration + for the incoming pod's pod (anti) affinity. Keys that don't exist in the incoming + pod labels will be ignored. The default value is empty. + The same key is forbidden to exist in both mismatchLabelKeys and labelSelector. + Also, mismatchLabelKeys cannot be set when labelSelector isn't set. + items: + type: string + type: array + x-kubernetes-list-type: atomic + namespaceSelector: + description: |- + A label query over the set of namespaces that the term applies to. + The term is applied to the union of the namespaces selected by this field + and the ones listed in the namespaces field. + null selector and null or empty namespaces list means "this pod's namespace". + An empty selector ({}) matches all namespaces. + properties: + matchExpressions: + description: matchExpressions is a list + of label selector requirements. The + requirements are ANDed. + items: + description: |- + A label selector requirement is a selector that contains values, a key, and an operator that + relates the key and values. + properties: + key: + description: key is the label + key that the selector applies + to. + type: string + operator: + description: |- + operator represents a key's relationship to a set of values. + Valid operators are In, NotIn, Exists and DoesNotExist. + type: string + values: + description: |- + values is an array of string values. If the operator is In or NotIn, + the values array must be non-empty. If the operator is Exists or DoesNotExist, + the values array must be empty. This array is replaced during a strategic + merge patch. + items: + type: string + type: array + x-kubernetes-list-type: atomic + required: + - key + - operator + type: object + type: array + x-kubernetes-list-type: atomic + matchLabels: + additionalProperties: + type: string + description: |- + matchLabels is a map of {key,value} pairs. A single {key,value} in the matchLabels + map is equivalent to an element of matchExpressions, whose key field is "key", the + operator is "In", and the values array contains only "value". The requirements are ANDed. + type: object + type: object + x-kubernetes-map-type: atomic + namespaces: + description: |- + namespaces specifies a static list of namespace names that the term applies to. + The term is applied to the union of the namespaces listed in this field + and the ones selected by namespaceSelector. + null or empty namespaces list and null namespaceSelector means "this pod's namespace". + items: + type: string + type: array + x-kubernetes-list-type: atomic + topologyKey: + description: |- + This pod should be co-located (affinity) or not co-located (anti-affinity) with the pods matching + the labelSelector in the specified namespaces, where co-located is defined as running on a node + whose value of the label with key topologyKey matches that of any node on which any of the + selected pods is running. + Empty topologyKey is not allowed. + type: string + required: + - topologyKey + type: object + weight: + description: |- + weight associated with matching the corresponding podAffinityTerm, + in the range 1-100. + format: int32 + type: integer + required: + - podAffinityTerm + - weight + type: object + type: array + x-kubernetes-list-type: atomic + requiredDuringSchedulingIgnoredDuringExecution: + description: |- + If the affinity requirements specified by this field are not met at + scheduling time, the pod will not be scheduled onto the node. + If the affinity requirements specified by this field cease to be met + at some point during pod execution (e.g. due to a pod label update), the + system may or may not try to eventually evict the pod from its node. + When there are multiple elements, the lists of nodes corresponding to each + podAffinityTerm are intersected, i.e. all terms must be satisfied. + items: + description: |- + Defines a set of pods (namely those matching the labelSelector + relative to the given namespace(s)) that this pod should be + co-located (affinity) or not co-located (anti-affinity) with, + where co-located is defined as running on a node whose value of + the label with key matches that of any node on which + a pod of the set of pods is running + properties: + labelSelector: + description: |- + A label query over a set of resources, in this case pods. + If it's null, this PodAffinityTerm matches with no Pods. + properties: + matchExpressions: + description: matchExpressions is a list + of label selector requirements. The requirements + are ANDed. + items: + description: |- + A label selector requirement is a selector that contains values, a key, and an operator that + relates the key and values. + properties: + key: + description: key is the label key + that the selector applies to. + type: string + operator: + description: |- + operator represents a key's relationship to a set of values. + Valid operators are In, NotIn, Exists and DoesNotExist. + type: string + values: + description: |- + values is an array of string values. If the operator is In or NotIn, + the values array must be non-empty. If the operator is Exists or DoesNotExist, + the values array must be empty. This array is replaced during a strategic + merge patch. + items: + type: string + type: array + x-kubernetes-list-type: atomic + required: + - key + - operator + type: object + type: array + x-kubernetes-list-type: atomic + matchLabels: + additionalProperties: + type: string + description: |- + matchLabels is a map of {key,value} pairs. A single {key,value} in the matchLabels + map is equivalent to an element of matchExpressions, whose key field is "key", the + operator is "In", and the values array contains only "value". The requirements are ANDed. + type: object + type: object + x-kubernetes-map-type: atomic + matchLabelKeys: + description: |- + MatchLabelKeys is a set of pod label keys to select which pods will + be taken into consideration. The keys are used to lookup values from the + incoming pod labels, those key-value labels are merged with `labelSelector` as `key in (value)` + to select the group of existing pods which pods will be taken into consideration + for the incoming pod's pod (anti) affinity. Keys that don't exist in the incoming + pod labels will be ignored. The default value is empty. + The same key is forbidden to exist in both matchLabelKeys and labelSelector. + Also, matchLabelKeys cannot be set when labelSelector isn't set. + items: + type: string + type: array + x-kubernetes-list-type: atomic + mismatchLabelKeys: + description: |- + MismatchLabelKeys is a set of pod label keys to select which pods will + be taken into consideration. The keys are used to lookup values from the + incoming pod labels, those key-value labels are merged with `labelSelector` as `key notin (value)` + to select the group of existing pods which pods will be taken into consideration + for the incoming pod's pod (anti) affinity. Keys that don't exist in the incoming + pod labels will be ignored. The default value is empty. + The same key is forbidden to exist in both mismatchLabelKeys and labelSelector. + Also, mismatchLabelKeys cannot be set when labelSelector isn't set. + items: + type: string + type: array + x-kubernetes-list-type: atomic + namespaceSelector: + description: |- + A label query over the set of namespaces that the term applies to. + The term is applied to the union of the namespaces selected by this field + and the ones listed in the namespaces field. + null selector and null or empty namespaces list means "this pod's namespace". + An empty selector ({}) matches all namespaces. + properties: + matchExpressions: + description: matchExpressions is a list + of label selector requirements. The requirements + are ANDed. + items: + description: |- + A label selector requirement is a selector that contains values, a key, and an operator that + relates the key and values. + properties: + key: + description: key is the label key + that the selector applies to. + type: string + operator: + description: |- + operator represents a key's relationship to a set of values. + Valid operators are In, NotIn, Exists and DoesNotExist. + type: string + values: + description: |- + values is an array of string values. If the operator is In or NotIn, + the values array must be non-empty. If the operator is Exists or DoesNotExist, + the values array must be empty. This array is replaced during a strategic + merge patch. + items: + type: string + type: array + x-kubernetes-list-type: atomic + required: + - key + - operator + type: object + type: array + x-kubernetes-list-type: atomic + matchLabels: + additionalProperties: + type: string + description: |- + matchLabels is a map of {key,value} pairs. A single {key,value} in the matchLabels + map is equivalent to an element of matchExpressions, whose key field is "key", the + operator is "In", and the values array contains only "value". The requirements are ANDed. + type: object + type: object + x-kubernetes-map-type: atomic + namespaces: + description: |- + namespaces specifies a static list of namespace names that the term applies to. + The term is applied to the union of the namespaces listed in this field + and the ones selected by namespaceSelector. + null or empty namespaces list and null namespaceSelector means "this pod's namespace". + items: + type: string + type: array + x-kubernetes-list-type: atomic + topologyKey: + description: |- + This pod should be co-located (affinity) or not co-located (anti-affinity) with the pods matching + the labelSelector in the specified namespaces, where co-located is defined as running on a node + whose value of the label with key topologyKey matches that of any node on which any of the + selected pods is running. + Empty topologyKey is not allowed. + type: string + required: + - topologyKey + type: object + type: array + x-kubernetes-list-type: atomic + type: object + podAntiAffinity: + description: Describes pod anti-affinity scheduling rules + (e.g. avoid putting this pod in the same node, zone, + etc. as some other pod(s)). + properties: + preferredDuringSchedulingIgnoredDuringExecution: + description: |- + The scheduler will prefer to schedule pods to nodes that satisfy + the anti-affinity expressions specified by this field, but it may choose + a node that violates one or more of the expressions. The node that is + most preferred is the one with the greatest sum of weights, i.e. + for each node that meets all of the scheduling requirements (resource + request, requiredDuringScheduling anti-affinity expressions, etc.), + compute a sum by iterating through the elements of this field and subtracting + "weight" from the sum if the node has pods which matches the corresponding podAffinityTerm; the + node(s) with the highest sum are the most preferred. + items: + description: The weights of all of the matched WeightedPodAffinityTerm + fields are added per-node to find the most preferred + node(s) + properties: + podAffinityTerm: + description: Required. A pod affinity term, + associated with the corresponding weight. + properties: + labelSelector: + description: |- + A label query over a set of resources, in this case pods. + If it's null, this PodAffinityTerm matches with no Pods. + properties: + matchExpressions: + description: matchExpressions is a list + of label selector requirements. The + requirements are ANDed. + items: + description: |- + A label selector requirement is a selector that contains values, a key, and an operator that + relates the key and values. + properties: + key: + description: key is the label + key that the selector applies + to. + type: string + operator: + description: |- + operator represents a key's relationship to a set of values. + Valid operators are In, NotIn, Exists and DoesNotExist. + type: string + values: + description: |- + values is an array of string values. If the operator is In or NotIn, + the values array must be non-empty. If the operator is Exists or DoesNotExist, + the values array must be empty. This array is replaced during a strategic + merge patch. + items: + type: string + type: array + x-kubernetes-list-type: atomic + required: + - key + - operator + type: object + type: array + x-kubernetes-list-type: atomic + matchLabels: + additionalProperties: + type: string + description: |- + matchLabels is a map of {key,value} pairs. A single {key,value} in the matchLabels + map is equivalent to an element of matchExpressions, whose key field is "key", the + operator is "In", and the values array contains only "value". The requirements are ANDed. + type: object + type: object + x-kubernetes-map-type: atomic + matchLabelKeys: + description: |- + MatchLabelKeys is a set of pod label keys to select which pods will + be taken into consideration. The keys are used to lookup values from the + incoming pod labels, those key-value labels are merged with `labelSelector` as `key in (value)` + to select the group of existing pods which pods will be taken into consideration + for the incoming pod's pod (anti) affinity. Keys that don't exist in the incoming + pod labels will be ignored. The default value is empty. + The same key is forbidden to exist in both matchLabelKeys and labelSelector. + Also, matchLabelKeys cannot be set when labelSelector isn't set. + items: + type: string + type: array + x-kubernetes-list-type: atomic + mismatchLabelKeys: + description: |- + MismatchLabelKeys is a set of pod label keys to select which pods will + be taken into consideration. The keys are used to lookup values from the + incoming pod labels, those key-value labels are merged with `labelSelector` as `key notin (value)` + to select the group of existing pods which pods will be taken into consideration + for the incoming pod's pod (anti) affinity. Keys that don't exist in the incoming + pod labels will be ignored. The default value is empty. + The same key is forbidden to exist in both mismatchLabelKeys and labelSelector. + Also, mismatchLabelKeys cannot be set when labelSelector isn't set. + items: + type: string + type: array + x-kubernetes-list-type: atomic + namespaceSelector: + description: |- + A label query over the set of namespaces that the term applies to. + The term is applied to the union of the namespaces selected by this field + and the ones listed in the namespaces field. + null selector and null or empty namespaces list means "this pod's namespace". + An empty selector ({}) matches all namespaces. + properties: + matchExpressions: + description: matchExpressions is a list + of label selector requirements. The + requirements are ANDed. + items: + description: |- + A label selector requirement is a selector that contains values, a key, and an operator that + relates the key and values. + properties: + key: + description: key is the label + key that the selector applies + to. + type: string + operator: + description: |- + operator represents a key's relationship to a set of values. + Valid operators are In, NotIn, Exists and DoesNotExist. + type: string + values: + description: |- + values is an array of string values. If the operator is In or NotIn, + the values array must be non-empty. If the operator is Exists or DoesNotExist, + the values array must be empty. This array is replaced during a strategic + merge patch. + items: + type: string + type: array + x-kubernetes-list-type: atomic + required: + - key + - operator + type: object + type: array + x-kubernetes-list-type: atomic + matchLabels: + additionalProperties: + type: string + description: |- + matchLabels is a map of {key,value} pairs. A single {key,value} in the matchLabels + map is equivalent to an element of matchExpressions, whose key field is "key", the + operator is "In", and the values array contains only "value". The requirements are ANDed. + type: object + type: object + x-kubernetes-map-type: atomic + namespaces: + description: |- + namespaces specifies a static list of namespace names that the term applies to. + The term is applied to the union of the namespaces listed in this field + and the ones selected by namespaceSelector. + null or empty namespaces list and null namespaceSelector means "this pod's namespace". + items: + type: string + type: array + x-kubernetes-list-type: atomic + topologyKey: + description: |- + This pod should be co-located (affinity) or not co-located (anti-affinity) with the pods matching + the labelSelector in the specified namespaces, where co-located is defined as running on a node + whose value of the label with key topologyKey matches that of any node on which any of the + selected pods is running. + Empty topologyKey is not allowed. + type: string + required: + - topologyKey + type: object + weight: + description: |- + weight associated with matching the corresponding podAffinityTerm, + in the range 1-100. + format: int32 + type: integer + required: + - podAffinityTerm + - weight + type: object + type: array + x-kubernetes-list-type: atomic + requiredDuringSchedulingIgnoredDuringExecution: + description: |- + If the anti-affinity requirements specified by this field are not met at + scheduling time, the pod will not be scheduled onto the node. + If the anti-affinity requirements specified by this field cease to be met + at some point during pod execution (e.g. due to a pod label update), the + system may or may not try to eventually evict the pod from its node. + When there are multiple elements, the lists of nodes corresponding to each + podAffinityTerm are intersected, i.e. all terms must be satisfied. + items: + description: |- + Defines a set of pods (namely those matching the labelSelector + relative to the given namespace(s)) that this pod should be + co-located (affinity) or not co-located (anti-affinity) with, + where co-located is defined as running on a node whose value of + the label with key matches that of any node on which + a pod of the set of pods is running + properties: + labelSelector: + description: |- + A label query over a set of resources, in this case pods. + If it's null, this PodAffinityTerm matches with no Pods. + properties: + matchExpressions: + description: matchExpressions is a list + of label selector requirements. The requirements + are ANDed. + items: + description: |- + A label selector requirement is a selector that contains values, a key, and an operator that + relates the key and values. + properties: + key: + description: key is the label key + that the selector applies to. + type: string + operator: + description: |- + operator represents a key's relationship to a set of values. + Valid operators are In, NotIn, Exists and DoesNotExist. + type: string + values: + description: |- + values is an array of string values. If the operator is In or NotIn, + the values array must be non-empty. If the operator is Exists or DoesNotExist, + the values array must be empty. This array is replaced during a strategic + merge patch. + items: + type: string + type: array + x-kubernetes-list-type: atomic + required: + - key + - operator + type: object + type: array + x-kubernetes-list-type: atomic + matchLabels: + additionalProperties: + type: string + description: |- + matchLabels is a map of {key,value} pairs. A single {key,value} in the matchLabels + map is equivalent to an element of matchExpressions, whose key field is "key", the + operator is "In", and the values array contains only "value". The requirements are ANDed. + type: object + type: object + x-kubernetes-map-type: atomic + matchLabelKeys: + description: |- + MatchLabelKeys is a set of pod label keys to select which pods will + be taken into consideration. The keys are used to lookup values from the + incoming pod labels, those key-value labels are merged with `labelSelector` as `key in (value)` + to select the group of existing pods which pods will be taken into consideration + for the incoming pod's pod (anti) affinity. Keys that don't exist in the incoming + pod labels will be ignored. The default value is empty. + The same key is forbidden to exist in both matchLabelKeys and labelSelector. + Also, matchLabelKeys cannot be set when labelSelector isn't set. + items: + type: string + type: array + x-kubernetes-list-type: atomic + mismatchLabelKeys: + description: |- + MismatchLabelKeys is a set of pod label keys to select which pods will + be taken into consideration. The keys are used to lookup values from the + incoming pod labels, those key-value labels are merged with `labelSelector` as `key notin (value)` + to select the group of existing pods which pods will be taken into consideration + for the incoming pod's pod (anti) affinity. Keys that don't exist in the incoming + pod labels will be ignored. The default value is empty. + The same key is forbidden to exist in both mismatchLabelKeys and labelSelector. + Also, mismatchLabelKeys cannot be set when labelSelector isn't set. + items: + type: string + type: array + x-kubernetes-list-type: atomic + namespaceSelector: + description: |- + A label query over the set of namespaces that the term applies to. + The term is applied to the union of the namespaces selected by this field + and the ones listed in the namespaces field. + null selector and null or empty namespaces list means "this pod's namespace". + An empty selector ({}) matches all namespaces. + properties: + matchExpressions: + description: matchExpressions is a list + of label selector requirements. The requirements + are ANDed. + items: + description: |- + A label selector requirement is a selector that contains values, a key, and an operator that + relates the key and values. + properties: + key: + description: key is the label key + that the selector applies to. + type: string + operator: + description: |- + operator represents a key's relationship to a set of values. + Valid operators are In, NotIn, Exists and DoesNotExist. + type: string + values: + description: |- + values is an array of string values. If the operator is In or NotIn, + the values array must be non-empty. If the operator is Exists or DoesNotExist, + the values array must be empty. This array is replaced during a strategic + merge patch. + items: + type: string + type: array + x-kubernetes-list-type: atomic + required: + - key + - operator + type: object + type: array + x-kubernetes-list-type: atomic + matchLabels: + additionalProperties: + type: string + description: |- + matchLabels is a map of {key,value} pairs. A single {key,value} in the matchLabels + map is equivalent to an element of matchExpressions, whose key field is "key", the + operator is "In", and the values array contains only "value". The requirements are ANDed. + type: object + type: object + x-kubernetes-map-type: atomic + namespaces: + description: |- + namespaces specifies a static list of namespace names that the term applies to. + The term is applied to the union of the namespaces listed in this field + and the ones selected by namespaceSelector. + null or empty namespaces list and null namespaceSelector means "this pod's namespace". + items: + type: string + type: array + x-kubernetes-list-type: atomic + topologyKey: + description: |- + This pod should be co-located (affinity) or not co-located (anti-affinity) with the pods matching + the labelSelector in the specified namespaces, where co-located is defined as running on a node + whose value of the label with key topologyKey matches that of any node on which any of the + selected pods is running. + Empty topologyKey is not allowed. + type: string + required: + - topologyKey + type: object + type: array + x-kubernetes-list-type: atomic + type: object + type: object + nodeSelector: + additionalProperties: + type: string + description: |- + nodeSelector is the node selector applied to the relevant kind of pods + It specifies a map of key-value pairs: for the pod to be eligible to run on a node, + the node must have each of the indicated key-value pairs as labels + (it can have additional labels as well). + See https://kubernetes.io/docs/concepts/configuration/assign-pod-node/#nodeselector + type: object + tolerations: + description: |- + tolerations is a list of tolerations applied to the relevant kind of pods + See https://kubernetes.io/docs/concepts/configuration/taint-and-toleration/ for more info. + These are additional tolerations other than default ones. + items: + description: |- + The pod this Toleration is attached to tolerates any taint that matches + the triple using the matching operator . + properties: + effect: + description: |- + Effect indicates the taint effect to match. Empty means match all taint effects. + When specified, allowed values are NoSchedule, PreferNoSchedule and NoExecute. + type: string + key: + description: |- + Key is the taint key that the toleration applies to. Empty means match all taint keys. + If the key is empty, operator must be Exists; this combination means to match all values and all keys. + type: string + operator: + description: |- + Operator represents a key's relationship to the value. + Valid operators are Exists and Equal. Defaults to Equal. + Exists is equivalent to wildcard for value, so that a pod can + tolerate all taints of a particular category. + type: string + tolerationSeconds: + description: |- + TolerationSeconds represents the period of time the toleration (which must be + of effect NoExecute, otherwise this field is ignored) tolerates the taint. By default, + it is not set, which means tolerate the taint forever (do not evict). Zero and + negative values will be treated as 0 (evict immediately) by the system. + format: int64 + type: integer + value: + description: |- + Value is the taint value the toleration matches to. + If the operator is Exists, the value should be empty, otherwise just a regular string. + type: string + type: object + type: array + type: object + type: object + type: object + status: + description: HyperConvergedStatus defines the observed state of HyperConverged + properties: + conditions: + description: Conditions describes the state of the HyperConverged + resource. + items: + description: Condition contains details for one aspect of the current + state of this API Resource. + properties: + lastTransitionTime: + description: |- + lastTransitionTime is the last time the condition transitioned from one status to another. + This should be when the underlying condition changed. If that is not known, then using the time when the API field changed is acceptable. + format: date-time + type: string + message: + description: |- + message is a human readable message indicating details about the transition. + This may be an empty string. + maxLength: 32768 + type: string + observedGeneration: + description: |- + observedGeneration represents the .metadata.generation that the condition was set based upon. + For instance, if .metadata.generation is currently 12, but the .status.conditions[x].observedGeneration is 9, the condition is out of date + with respect to the current state of the instance. + format: int64 + minimum: 0 + type: integer + reason: + description: |- + reason contains a programmatic identifier indicating the reason for the condition's last transition. + Producers of specific condition types may define expected values and meanings for this field, + and whether the values are considered a guaranteed API. + The value should be a CamelCase string. + This field may not be empty. + maxLength: 1024 + minLength: 1 + pattern: ^[A-Za-z]([A-Za-z0-9_,:]*[A-Za-z0-9_])?$ + type: string + status: + description: status of the condition, one of True, False, Unknown. + enum: + - "True" + - "False" + - Unknown + type: string + type: + description: type of condition in CamelCase or in foo.example.com/CamelCase. + maxLength: 316 + pattern: ^([a-z0-9]([-a-z0-9]*[a-z0-9])?(\.[a-z0-9]([-a-z0-9]*[a-z0-9])?)*/)?(([A-Za-z0-9][-A-Za-z0-9_.]*)?[A-Za-z0-9])$ + type: string + required: + - lastTransitionTime + - message + - reason + - status + - type + type: object + type: array + x-kubernetes-list-type: atomic + dataImportCronTemplates: + description: |- + DataImportCronTemplates is a list of the actual DataImportCronTemplates as HCO update in the SSP CR. The list + contains both the common and the custom templates, including any modification done by HCO. + items: + description: DataImportCronTemplateStatus is a copy of a dataImportCronTemplate + as defined in the spec, or in the HCO image. + properties: + metadata: + properties: + annotations: + additionalProperties: + type: string + type: object + finalizers: + items: + type: string + type: array + labels: + additionalProperties: + type: string + type: object + name: + type: string + namespace: + type: string + type: object + spec: + description: DataImportCronSpec defines specification for DataImportCron + properties: + garbageCollect: + description: |- + GarbageCollect specifies whether old PVCs should be cleaned up after a new PVC is imported. + Options are currently "Outdated" and "Never", defaults to "Outdated". + type: string + importsToKeep: + description: Number of import PVCs to keep when garbage + collecting. Default is 3. + format: int32 + type: integer + managedDataSource: + description: |- + ManagedDataSource specifies the name of the corresponding DataSource this cron will manage. + DataSource has to be in the same namespace. + type: string + retentionPolicy: + description: RetentionPolicy specifies whether the created + DataVolumes and DataSources are retained when their DataImportCron + is deleted. Default is RatainAll. + type: string + schedule: + description: Schedule specifies in cron format when and + how often to look for new imports + type: string + serviceAccountName: + description: ServiceAccountName is the name of the ServiceAccount + for creating DataVolumes. + minLength: 1 + type: string + template: + description: Template specifies template for the DVs to + be created + properties: + apiVersion: + description: |- + APIVersion defines the versioned schema of this representation of an object. + Servers should convert recognized schemas to the latest internal value, and + may reject unrecognized values. + More info: https://git.k8s.io/community/contributors/devel/sig-architecture/api-conventions.md#resources + type: string + kind: + description: |- + Kind is a string value representing the REST resource this object represents. + Servers may infer this from the endpoint the client submits requests to. + Cannot be updated. + In CamelCase. + More info: https://git.k8s.io/community/contributors/devel/sig-architecture/api-conventions.md#types-kinds + type: string + metadata: + properties: + annotations: + additionalProperties: + type: string + type: object + finalizers: + items: + type: string + type: array + labels: + additionalProperties: + type: string + type: object + name: + type: string + namespace: + type: string + type: object + spec: + description: DataVolumeSpec defines the DataVolume type + specification + properties: + checkpoints: + description: Checkpoints is a list of DataVolumeCheckpoints, + representing stages in a multistage import. + items: + description: DataVolumeCheckpoint defines a stage + in a warm migration. + properties: + current: + description: Current is the identifier of + the snapshot created for this checkpoint. + type: string + previous: + description: Previous is the identifier of + the snapshot from the previous checkpoint. + type: string + required: + - current + - previous + type: object + type: array + contentType: + description: 'DataVolumeContentType options: "kubevirt", + "archive"' + enum: + - kubevirt + - archive + type: string + finalCheckpoint: + description: FinalCheckpoint indicates whether the + current DataVolumeCheckpoint is the final checkpoint. + type: boolean + preallocation: + description: Preallocation controls whether storage + for DataVolumes should be allocated in advance. + type: boolean + priorityClassName: + description: PriorityClassName for Importer, Cloner + and Uploader pod + type: string + pvc: + description: PVC is the PVC specification + properties: + accessModes: + description: |- + accessModes contains the desired access modes the volume should have. + More info: https://kubernetes.io/docs/concepts/storage/persistent-volumes#access-modes-1 + items: + type: string + type: array + x-kubernetes-list-type: atomic + dataSource: + description: |- + dataSource field can be used to specify either: + * An existing VolumeSnapshot object (snapshot.storage.k8s.io/VolumeSnapshot) + * An existing PVC (PersistentVolumeClaim) + If the provisioner or an external controller can support the specified data source, + it will create a new volume based on the contents of the specified data source. + When the AnyVolumeDataSource feature gate is enabled, dataSource contents will be copied to dataSourceRef, + and dataSourceRef contents will be copied to dataSource when dataSourceRef.namespace is not specified. + If the namespace is specified, then dataSourceRef will not be copied to dataSource. + properties: + apiGroup: + description: |- + APIGroup is the group for the resource being referenced. + If APIGroup is not specified, the specified Kind must be in the core API group. + For any other third-party types, APIGroup is required. + type: string + kind: + description: Kind is the type of resource + being referenced + type: string + name: + description: Name is the name of resource + being referenced + type: string + required: + - kind + - name + type: object + x-kubernetes-map-type: atomic + dataSourceRef: + description: |- + dataSourceRef specifies the object from which to populate the volume with data, if a non-empty + volume is desired. This may be any object from a non-empty API group (non + core object) or a PersistentVolumeClaim object. + When this field is specified, volume binding will only succeed if the type of + the specified object matches some installed volume populator or dynamic + provisioner. + This field will replace the functionality of the dataSource field and as such + if both fields are non-empty, they must have the same value. For backwards + compatibility, when namespace isn't specified in dataSourceRef, + both fields (dataSource and dataSourceRef) will be set to the same + value automatically if one of them is empty and the other is non-empty. + When namespace is specified in dataSourceRef, + dataSource isn't set to the same value and must be empty. + There are three important differences between dataSource and dataSourceRef: + * While dataSource only allows two specific types of objects, dataSourceRef + allows any non-core object, as well as PersistentVolumeClaim objects. + * While dataSource ignores disallowed values (dropping them), dataSourceRef + preserves all values, and generates an error if a disallowed value is + specified. + * While dataSource only allows local objects, dataSourceRef allows objects + in any namespaces. + (Beta) Using this field requires the AnyVolumeDataSource feature gate to be enabled. + (Alpha) Using the namespace field of dataSourceRef requires the CrossNamespaceVolumeDataSource feature gate to be enabled. + properties: + apiGroup: + description: |- + APIGroup is the group for the resource being referenced. + If APIGroup is not specified, the specified Kind must be in the core API group. + For any other third-party types, APIGroup is required. + type: string + kind: + description: Kind is the type of resource + being referenced + type: string + name: + description: Name is the name of resource + being referenced + type: string + namespace: + description: |- + Namespace is the namespace of resource being referenced + Note that when a namespace is specified, a gateway.networking.k8s.io/ReferenceGrant object is required in the referent namespace to allow that namespace's owner to accept the reference. See the ReferenceGrant documentation for details. + (Alpha) This field requires the CrossNamespaceVolumeDataSource feature gate to be enabled. + type: string + required: + - kind + - name + type: object + resources: + description: |- + resources represents the minimum resources the volume should have. + If RecoverVolumeExpansionFailure feature is enabled users are allowed to specify resource requirements + that are lower than previous value but must still be higher than capacity recorded in the + status field of the claim. + More info: https://kubernetes.io/docs/concepts/storage/persistent-volumes#resources + properties: + limits: + additionalProperties: + anyOf: + - type: integer + - type: string + pattern: ^(\+|-)?(([0-9]+(\.[0-9]*)?)|(\.[0-9]+))(([KMGTPE]i)|[numkMGTPE]|([eE](\+|-)?(([0-9]+(\.[0-9]*)?)|(\.[0-9]+))))?$ + x-kubernetes-int-or-string: true + description: |- + Limits describes the maximum amount of compute resources allowed. + More info: https://kubernetes.io/docs/concepts/configuration/manage-resources-containers/ + type: object + requests: + additionalProperties: + anyOf: + - type: integer + - type: string + pattern: ^(\+|-)?(([0-9]+(\.[0-9]*)?)|(\.[0-9]+))(([KMGTPE]i)|[numkMGTPE]|([eE](\+|-)?(([0-9]+(\.[0-9]*)?)|(\.[0-9]+))))?$ + x-kubernetes-int-or-string: true + description: |- + Requests describes the minimum amount of compute resources required. + If Requests is omitted for a container, it defaults to Limits if that is explicitly specified, + otherwise to an implementation-defined value. Requests cannot exceed Limits. + More info: https://kubernetes.io/docs/concepts/configuration/manage-resources-containers/ + type: object + type: object + selector: + description: selector is a label query over + volumes to consider for binding. + properties: + matchExpressions: + description: matchExpressions is a list + of label selector requirements. The requirements + are ANDed. + items: + description: |- + A label selector requirement is a selector that contains values, a key, and an operator that + relates the key and values. + properties: + key: + description: key is the label key + that the selector applies to. + type: string + operator: + description: |- + operator represents a key's relationship to a set of values. + Valid operators are In, NotIn, Exists and DoesNotExist. + type: string + values: + description: |- + values is an array of string values. If the operator is In or NotIn, + the values array must be non-empty. If the operator is Exists or DoesNotExist, + the values array must be empty. This array is replaced during a strategic + merge patch. + items: + type: string + type: array + x-kubernetes-list-type: atomic + required: + - key + - operator + type: object + type: array + x-kubernetes-list-type: atomic + matchLabels: + additionalProperties: + type: string + description: |- + matchLabels is a map of {key,value} pairs. A single {key,value} in the matchLabels + map is equivalent to an element of matchExpressions, whose key field is "key", the + operator is "In", and the values array contains only "value". The requirements are ANDed. + type: object + type: object + x-kubernetes-map-type: atomic + storageClassName: + description: |- + storageClassName is the name of the StorageClass required by the claim. + More info: https://kubernetes.io/docs/concepts/storage/persistent-volumes#class-1 + type: string + volumeAttributesClassName: + description: |- + volumeAttributesClassName may be used to set the VolumeAttributesClass used by this claim. + If specified, the CSI driver will create or update the volume with the attributes defined + in the corresponding VolumeAttributesClass. This has a different purpose than storageClassName, + it can be changed after the claim is created. An empty string or nil value indicates that no + VolumeAttributesClass will be applied to the claim. If the claim enters an Infeasible error state, + this field can be reset to its previous value (including nil) to cancel the modification. + If the resource referred to by volumeAttributesClass does not exist, this PersistentVolumeClaim will be + set to a Pending state, as reflected by the modifyVolumeStatus field, until such as a resource + exists. + More info: https://kubernetes.io/docs/concepts/storage/volume-attributes-classes/ + type: string + volumeMode: + description: |- + volumeMode defines what type of volume is required by the claim. + Value of Filesystem is implied when not included in claim spec. + type: string + volumeName: + description: volumeName is the binding reference + to the PersistentVolume backing this claim. + type: string + type: object + source: + description: Source is the src of the data for the + requested DataVolume + properties: + blank: + description: DataVolumeBlankImage provides the + parameters to create a new raw blank image + for the PVC + type: object + gcs: + description: DataVolumeSourceGCS provides the + parameters to create a Data Volume from an + GCS source + properties: + secretRef: + description: SecretRef provides the secret + reference needed to access the GCS source + type: string + url: + description: URL is the url of the GCS source + type: string + required: + - url + type: object + http: + description: DataVolumeSourceHTTP can be either + an http or https endpoint, with an optional + basic auth user name and password, and an + optional configmap containing additional CAs + properties: + certConfigMap: + description: CertConfigMap is a configmap + reference, containing a Certificate Authority(CA) + public key, and a base64 encoded pem certificate + type: string + extraHeaders: + description: ExtraHeaders is a list of strings + containing extra headers to include with + HTTP transfer requests + items: + type: string + type: array + secretExtraHeaders: + description: SecretExtraHeaders is a list + of Secret references, each containing + an extra HTTP header that may include + sensitive information + items: + type: string + type: array + secretRef: + description: SecretRef A Secret reference, + the secret should contain accessKeyId + (user name) base64 encoded, and secretKey + (password) also base64 encoded + type: string + url: + description: URL is the URL of the http(s) + endpoint + type: string + required: + - url + type: object + imageio: + description: DataVolumeSourceImageIO provides + the parameters to create a Data Volume from + an imageio source + properties: + certConfigMap: + description: CertConfigMap provides a reference + to the CA cert + type: string + diskId: + description: DiskID provides id of a disk + to be imported + type: string + insecureSkipVerify: + description: InsecureSkipVerify is a flag + to skip certificate verification + type: boolean + secretRef: + description: SecretRef provides the secret + reference needed to access the ovirt-engine + type: string + url: + description: URL is the URL of the ovirt-engine + type: string + required: + - diskId + - url + type: object + pvc: + description: DataVolumeSourcePVC provides the + parameters to create a Data Volume from an + existing PVC + properties: + name: + description: The name of the source PVC + type: string + namespace: + description: The namespace of the source + PVC + type: string + required: + - name + - namespace + type: object + registry: + description: DataVolumeSourceRegistry provides + the parameters to create a Data Volume from + an registry source + properties: + certConfigMap: + description: CertConfigMap provides a reference + to the Registry certs + type: string + imageStream: + description: ImageStream is the name of + image stream for import + type: string + platform: + description: Platform describes the minimum + runtime requirements of the image + properties: + architecture: + description: Architecture specifies + the image target CPU architecture + type: string + type: object + pullMethod: + description: PullMethod can be either "pod" + (default import), or "node" (node docker + cache based import) + type: string + secretRef: + description: SecretRef provides the secret + reference needed to access the Registry + source + type: string + url: + description: 'URL is the url of the registry + source (starting with the scheme: docker, + oci-archive)' + type: string + type: object + s3: + description: DataVolumeSourceS3 provides the + parameters to create a Data Volume from an + S3 source + properties: + certConfigMap: + description: CertConfigMap is a configmap + reference, containing a Certificate Authority(CA) + public key, and a base64 encoded pem certificate + type: string + secretRef: + description: SecretRef provides the secret + reference needed to access the S3 source + type: string + url: + description: URL is the url of the S3 source + type: string + required: + - url + type: object + snapshot: + description: DataVolumeSourceSnapshot provides + the parameters to create a Data Volume from + an existing VolumeSnapshot + properties: + name: + description: The name of the source VolumeSnapshot + type: string + namespace: + description: The namespace of the source + VolumeSnapshot + type: string + required: + - name + - namespace + type: object + upload: + description: DataVolumeSourceUpload provides + the parameters to create a Data Volume by + uploading the source + type: object + vddk: + description: DataVolumeSourceVDDK provides the + parameters to create a Data Volume from a + Vmware source + properties: + backingFile: + description: BackingFile is the path to + the virtual hard disk to migrate from + vCenter/ESXi + type: string + extraArgs: + description: ExtraArgs is a reference to + a ConfigMap containing extra arguments + to pass directly to the VDDK library + type: string + initImageURL: + description: InitImageURL is an optional + URL to an image containing an extracted + VDDK library, overrides v2v-vmware config + map + type: string + secretRef: + description: SecretRef provides a reference + to a secret containing the username and + password needed to access the vCenter + or ESXi host + type: string + thumbprint: + description: Thumbprint is the certificate + thumbprint of the vCenter or ESXi host + type: string + url: + description: URL is the URL of the vCenter + or ESXi host with the VM to migrate + type: string + uuid: + description: UUID is the UUID of the virtual + machine that the backing file is attached + to in vCenter/ESXi + type: string + type: object + type: object + sourceRef: + description: SourceRef is an indirect reference + to the source of data for the requested DataVolume + properties: + kind: + description: The kind of the source reference, + currently only "DataSource" is supported + type: string + name: + description: The name of the source reference + type: string + namespace: + description: The namespace of the source reference, + defaults to the DataVolume namespace + type: string + required: + - kind + - name + type: object + storage: + description: Storage is the requested storage specification + properties: + accessModes: + description: |- + AccessModes contains the desired access modes the volume should have. + More info: https://kubernetes.io/docs/concepts/storage/persistent-volumes#access-modes-1 + items: + type: string + type: array + dataSource: + description: |- + This field can be used to specify either: * An existing VolumeSnapshot object (snapshot.storage.k8s.io/VolumeSnapshot) * An existing PVC (PersistentVolumeClaim) * An existing custom resource that implements data population (Alpha) In order to use custom resource types that implement data population, the AnyVolumeDataSource feature gate must be enabled. If the provisioner or an external controller can support the specified data source, it will create a new volume based on the contents of the specified data source. + If the AnyVolumeDataSource feature gate is enabled, this field will always have the same contents as the DataSourceRef field. + properties: + apiGroup: + description: |- + APIGroup is the group for the resource being referenced. + If APIGroup is not specified, the specified Kind must be in the core API group. + For any other third-party types, APIGroup is required. + type: string + kind: + description: Kind is the type of resource + being referenced + type: string + name: + description: Name is the name of resource + being referenced + type: string + required: + - kind + - name + type: object + x-kubernetes-map-type: atomic + dataSourceRef: + description: |- + Specifies the object from which to populate the volume with data, if a non-empty volume is desired. This may be any local object from a non-empty API group (non core object) or a PersistentVolumeClaim object. When this field is specified, volume binding will only succeed if the type of the specified object matches some installed volume populator or dynamic provisioner. + This field will replace the functionality of the DataSource field and as such if both fields are non-empty, they must have the same value. For backwards compatibility, both fields (DataSource and DataSourceRef) will be set to the same value automatically if one of them is empty and the other is non-empty. + There are two important differences between DataSource and DataSourceRef: + * While DataSource only allows two specific types of objects, DataSourceRef allows any non-core object, as well as PersistentVolumeClaim objects. + * While DataSource ignores disallowed values (dropping them), DataSourceRef preserves all values, and generates an error if a disallowed value is specified. + (Beta) Using this field requires the AnyVolumeDataSource feature gate to be enabled. + properties: + apiGroup: + description: |- + APIGroup is the group for the resource being referenced. + If APIGroup is not specified, the specified Kind must be in the core API group. + For any other third-party types, APIGroup is required. + type: string + kind: + description: Kind is the type of resource + being referenced + type: string + name: + description: Name is the name of resource + being referenced + type: string + namespace: + description: |- + Namespace is the namespace of resource being referenced + Note that when a namespace is specified, a gateway.networking.k8s.io/ReferenceGrant object is required in the referent namespace to allow that namespace's owner to accept the reference. See the ReferenceGrant documentation for details. + (Alpha) This field requires the CrossNamespaceVolumeDataSource feature gate to be enabled. + type: string + required: + - kind + - name + type: object + resources: + description: |- + Resources represents the minimum resources the volume should have. + More info: https://kubernetes.io/docs/concepts/storage/persistent-volumes#resources + properties: + limits: + additionalProperties: + anyOf: + - type: integer + - type: string + pattern: ^(\+|-)?(([0-9]+(\.[0-9]*)?)|(\.[0-9]+))(([KMGTPE]i)|[numkMGTPE]|([eE](\+|-)?(([0-9]+(\.[0-9]*)?)|(\.[0-9]+))))?$ + x-kubernetes-int-or-string: true + description: |- + Limits describes the maximum amount of compute resources allowed. + More info: https://kubernetes.io/docs/concepts/configuration/manage-resources-containers/ + type: object + requests: + additionalProperties: + anyOf: + - type: integer + - type: string + pattern: ^(\+|-)?(([0-9]+(\.[0-9]*)?)|(\.[0-9]+))(([KMGTPE]i)|[numkMGTPE]|([eE](\+|-)?(([0-9]+(\.[0-9]*)?)|(\.[0-9]+))))?$ + x-kubernetes-int-or-string: true + description: |- + Requests describes the minimum amount of compute resources required. + If Requests is omitted for a container, it defaults to Limits if that is explicitly specified, + otherwise to an implementation-defined value. Requests cannot exceed Limits. + More info: https://kubernetes.io/docs/concepts/configuration/manage-resources-containers/ + type: object + type: object + selector: + description: A label query over volumes to consider + for binding. + properties: + matchExpressions: + description: matchExpressions is a list + of label selector requirements. The requirements + are ANDed. + items: + description: |- + A label selector requirement is a selector that contains values, a key, and an operator that + relates the key and values. + properties: + key: + description: key is the label key + that the selector applies to. + type: string + operator: + description: |- + operator represents a key's relationship to a set of values. + Valid operators are In, NotIn, Exists and DoesNotExist. + type: string + values: + description: |- + values is an array of string values. If the operator is In or NotIn, + the values array must be non-empty. If the operator is Exists or DoesNotExist, + the values array must be empty. This array is replaced during a strategic + merge patch. + items: + type: string + type: array + x-kubernetes-list-type: atomic + required: + - key + - operator + type: object + type: array + x-kubernetes-list-type: atomic + matchLabels: + additionalProperties: + type: string + description: |- + matchLabels is a map of {key,value} pairs. A single {key,value} in the matchLabels + map is equivalent to an element of matchExpressions, whose key field is "key", the + operator is "In", and the values array contains only "value". The requirements are ANDed. + type: object + type: object + x-kubernetes-map-type: atomic + storageClassName: + description: |- + Name of the StorageClass required by the claim. + More info: https://kubernetes.io/docs/concepts/storage/persistent-volumes#class-1 + type: string + volumeMode: + description: |- + volumeMode defines what type of volume is required by the claim. + Value of Filesystem is implied when not included in claim spec. + type: string + volumeName: + description: VolumeName is the binding reference + to the PersistentVolume backing this claim. + type: string + type: object + type: object + status: + description: DataVolumeStatus contains the current status + of the DataVolume + properties: + claimName: + description: ClaimName is the name of the underlying + PVC used by the DataVolume. + type: string + conditions: + items: + description: DataVolumeCondition represents the + state of a data volume condition. + properties: + lastHeartbeatTime: + format: date-time + type: string + lastTransitionTime: + format: date-time + type: string + message: + type: string + reason: + type: string + status: + type: string + type: + description: DataVolumeConditionType is the + string representation of known condition + types + type: string + required: + - status + - type + type: object + type: array + phase: + description: Phase is the current phase of the data + volume + type: string + progress: + description: DataVolumeProgress is the current progress + of the DataVolume transfer operation. Value between + 0 and 100 inclusive, N/A if not available + type: string + restartCount: + description: RestartCount is the number of times + the pod populating the DataVolume has restarted + format: int32 + type: integer + type: object + required: + - spec + type: object + required: + - managedDataSource + - schedule + - template + type: object + status: + description: DataImportCronStatus is the status field of the + DIC template + properties: + commonTemplate: + description: CommonTemplate indicates whether this is a + common template (true), or a custom one (false) + type: boolean + conditions: + description: Conditions is a list of conditions that describe + the state of the DataImportCronTemplate. + items: + description: Condition contains details for one aspect + of the current state of this API Resource. + properties: + lastTransitionTime: + description: |- + lastTransitionTime is the last time the condition transitioned from one status to another. + This should be when the underlying condition changed. If that is not known, then using the time when the API field changed is acceptable. + format: date-time + type: string + message: + description: |- + message is a human readable message indicating details about the transition. + This may be an empty string. + maxLength: 32768 + type: string + observedGeneration: + description: |- + observedGeneration represents the .metadata.generation that the condition was set based upon. + For instance, if .metadata.generation is currently 12, but the .status.conditions[x].observedGeneration is 9, the condition is out of date + with respect to the current state of the instance. + format: int64 + minimum: 0 + type: integer + reason: + description: |- + reason contains a programmatic identifier indicating the reason for the condition's last transition. + Producers of specific condition types may define expected values and meanings for this field, + and whether the values are considered a guaranteed API. + The value should be a CamelCase string. + This field may not be empty. + maxLength: 1024 + minLength: 1 + pattern: ^[A-Za-z]([A-Za-z0-9_,:]*[A-Za-z0-9_])?$ + type: string + status: + description: status of the condition, one of True, + False, Unknown. + enum: + - "True" + - "False" + - Unknown + type: string + type: + description: type of condition in CamelCase or in + foo.example.com/CamelCase. + maxLength: 316 + pattern: ^([a-z0-9]([-a-z0-9]*[a-z0-9])?(\.[a-z0-9]([-a-z0-9]*[a-z0-9])?)*/)?(([A-Za-z0-9][-A-Za-z0-9_.]*)?[A-Za-z0-9])$ + type: string + required: + - lastTransitionTime + - message + - reason + - status + - type + type: object + type: array + modified: + description: Modified indicates if a common template was + customized. Always false for custom templates. + type: boolean + originalSupportedArchitectures: + description: |- + OriginalSupportedArchitectures is a comma-separated list of CPU architectures that the original + template supports. + type: string + type: object + type: object + type: array + dataImportSchedule: + description: |- + DataImportSchedule is the cron expression that is used in for the hard-coded data import cron templates. HCO + generates the value of this field once and stored in the status field, so will survive restart. + type: string + infrastructureHighlyAvailable: + description: |- + InfrastructureHighlyAvailable describes whether the cluster has only one worker node + (false) or more (true). + type: boolean + nodeInfo: + description: NodeInfo holds information about the cluster nodes + properties: + controlPlaneArchitectures: + description: ControlPlaneArchitectures is a distinct list of the + CPU architecture of the control-plane nodes. + items: + type: string + type: array + workloadsArchitectures: + description: WorkloadsArchitectures is a distinct list of the + CPU architectures of the workloads nodes in the cluster. + items: + type: string + type: array + type: object + observedGeneration: + description: |- + ObservedGeneration reflects the HyperConverged resource generation. If the ObservedGeneration is less than the + resource generation in metadata, the status is out of date + format: int64 + type: integer + relatedObjects: + description: |- + RelatedObjects is a list of objects created and maintained by this + operator. Object references will be added to this list after they have + been created AND found in the cluster. + items: + description: ObjectReference contains enough information to let + you inspect or modify the referred object. + properties: + apiVersion: + description: API version of the referent. + type: string + fieldPath: + description: |- + If referring to a piece of an object instead of an entire object, this string + should contain a valid JSON/Go field access statement, such as desiredState.manifest.containers[2]. + For example, if the object reference is to a container within a pod, this would take on a value like: + "spec.containers{name}" (where "name" refers to the name of the container that triggered + the event) or if no container name is specified "spec.containers[2]" (container with + index 2 in this pod). This syntax is chosen only to have some well-defined way of + referencing a part of an object. + type: string + kind: + description: |- + Kind of the referent. + More info: https://git.k8s.io/community/contributors/devel/sig-architecture/api-conventions.md#types-kinds + type: string + name: + description: |- + Name of the referent. + More info: https://kubernetes.io/docs/concepts/overview/working-with-objects/names/#names + type: string + namespace: + description: |- + Namespace of the referent. + More info: https://kubernetes.io/docs/concepts/overview/working-with-objects/namespaces/ + type: string + resourceVersion: + description: |- + Specific resourceVersion to which this reference is made, if any. + More info: https://git.k8s.io/community/contributors/devel/sig-architecture/api-conventions.md#concurrency-control-and-consistency + type: string + uid: + description: |- + UID of the referent. + More info: https://kubernetes.io/docs/concepts/overview/working-with-objects/names/#uids + type: string + type: object + x-kubernetes-map-type: atomic + type: array + x-kubernetes-list-type: atomic + systemHealthStatus: + description: SystemHealthStatus reflects the health of HCO and its + secondary resources, based on the aggregated conditions. + type: string + versions: + description: |- + Versions is a list of HCO component versions, as name/version pairs. The version with a name of "operator" + is the HCO version itself, as described here: + https://github.com/openshift/cluster-version-operator/blob/master/docs/dev/clusteroperator.md#version + items: + properties: + name: + type: string + version: + type: string + type: object + type: array + x-kubernetes-list-type: atomic + type: object + type: object + served: true + storage: false + subresources: + status: {} - additionalPrinterColumns: - jsonPath: .metadata.creationTimestamp name: Age diff --git a/controllers/commontestutils/testUtils.go b/controllers/commontestutils/testUtils.go index 08ae8dbd41..868f64dd32 100644 --- a/controllers/commontestutils/testUtils.go +++ b/controllers/commontestutils/testUtils.go @@ -6,6 +6,7 @@ import ( "sync" "github.com/go-logr/logr" + netattdefv1 "github.com/k8snetworkplumbingwg/network-attachment-definition-client/pkg/apis/k8s.cni.cncf.io/v1" . "github.com/onsi/ginkgo/v2" . "github.com/onsi/gomega" "github.com/onsi/gomega/gstruct" @@ -33,8 +34,6 @@ import ( "sigs.k8s.io/controller-runtime/pkg/log/zap" "sigs.k8s.io/controller-runtime/pkg/reconcile" - netattdefv1 "github.com/k8snetworkplumbingwg/network-attachment-definition-client/pkg/apis/k8s.cni.cncf.io/v1" - networkaddonsv1 "github.com/kubevirt/cluster-network-addons-operator/pkg/apis/networkaddonsoperator/v1" kubevirtcorev1 "kubevirt.io/api/core/v1" aaqv1alpha1 "kubevirt.io/application-aware-quota/staging/src/kubevirt.io/application-aware-quota-api/pkg/apis/core/v1alpha1" @@ -44,6 +43,7 @@ import ( sspv1beta3 "kubevirt.io/ssp-operator/api/v1beta3" "github.com/kubevirt/hyperconverged-cluster-operator/api" + hcov1 "github.com/kubevirt/hyperconverged-cluster-operator/api/v1" hcov1beta1 "github.com/kubevirt/hyperconverged-cluster-operator/api/v1beta1" "github.com/kubevirt/hyperconverged-cluster-operator/controllers/common" "github.com/kubevirt/hyperconverged-cluster-operator/pkg/components" @@ -73,6 +73,23 @@ func NewHco() *hcov1beta1.HyperConverged { return hco } +func NewV1HCO() *hcov1.HyperConverged { + defaultScheme := runtime.NewScheme() + _ = hcov1.AddToScheme(defaultScheme) + _ = hcov1.RegisterDefaults(defaultScheme) + defaultHco := &hcov1.HyperConverged{ + TypeMeta: metav1.TypeMeta{ + APIVersion: hcov1.APIVersion, + Kind: hcoutil.HyperConvergedKind, + }, + ObjectMeta: metav1.ObjectMeta{ + Name: hcoutil.HyperConvergedName, + }} + defaultScheme.Default(defaultHco) + + return defaultHco +} + func NewHcoNamespace() *corev1.Namespace { return &corev1.Namespace{ ObjectMeta: metav1.ObjectMeta{ diff --git a/controllers/webhooks/conversion-webhook-controller/controller.go b/controllers/webhooks/conversion-webhook-controller/controller.go new file mode 100644 index 0000000000..7bdef7d3c0 --- /dev/null +++ b/controllers/webhooks/conversion-webhook-controller/controller.go @@ -0,0 +1,256 @@ +package conversion_webhook_controller + +import ( + "context" + "errors" + "slices" + + corev1 "k8s.io/api/core/v1" + apiextensionsv1 "k8s.io/apiextensions-apiserver/pkg/apis/apiextensions/v1" + apierrors "k8s.io/apimachinery/pkg/api/errors" + "k8s.io/utils/ptr" + "sigs.k8s.io/controller-runtime/pkg/client" + "sigs.k8s.io/controller-runtime/pkg/controller" + "sigs.k8s.io/controller-runtime/pkg/handler" + logf "sigs.k8s.io/controller-runtime/pkg/log" + "sigs.k8s.io/controller-runtime/pkg/manager" + "sigs.k8s.io/controller-runtime/pkg/predicate" + "sigs.k8s.io/controller-runtime/pkg/reconcile" + "sigs.k8s.io/controller-runtime/pkg/source" + + hcov1 "github.com/kubevirt/hyperconverged-cluster-operator/api/v1" + hcov1beta1 "github.com/kubevirt/hyperconverged-cluster-operator/api/v1beta1" + "github.com/kubevirt/hyperconverged-cluster-operator/pkg/ownresources" + hcoutil "github.com/kubevirt/hyperconverged-cluster-operator/pkg/util" +) + +const ( + k8sCertInjectionAnnotationName = "cert-manager.io/inject-ca-from" + + openshiftCertInjectionAnnotationName = "service.beta.openshift.io/inject-cabundle" + + olmCaBundleKey = "olmCAKey" +) + +var ( + setupLogger = logf.Log.WithName("conversion-webhook-controller") +) + +// ReconcileConversionWebhook reconciles the HyperConverged CRD conversion webhook configuration +type ReconcileConversionWebhook struct { + client client.Client + namespace string + secretName string + serviceName string + certAnnotationName string + certAnnotationVal string + managedByOLM bool +} + +// RegisterReconciler creates a new conversion webhook controller and registers it into manager. +func RegisterReconciler(mgr manager.Manager) error { + deploymentName := ownresources.GetDeploymentRef().Name + if deploymentName == "" { + setupLogger.Info("Deployment reference not available, skipping conversion webhook controller registration") + return nil + } + + secretName := deploymentName + "-service-cert" + serviceName := deploymentName + "-service" + namespace := hcoutil.GetOperatorNamespaceFromEnv() + + return add(mgr, newReconciler(mgr, namespace, secretName, serviceName)) +} + +func newReconciler(mgr manager.Manager, namespace, secretName, serviceName string) *ReconcileConversionWebhook { + r := &ReconcileConversionWebhook{ + client: mgr.GetClient(), + namespace: namespace, + secretName: secretName, + serviceName: serviceName, + } + + if hcoutil.GetClusterInfo().IsOpenshift() { + r.certAnnotationName = openshiftCertInjectionAnnotationName + r.certAnnotationVal = "true" + } else { + r.certAnnotationName = k8sCertInjectionAnnotationName + r.certAnnotationVal = namespace + "/" + secretName + } + + r.managedByOLM = hcoutil.GetClusterInfo().IsManagedByOLM() + + return r +} + +func add(mgr manager.Manager, r *ReconcileConversionWebhook) error { + setupLogger.Info("Setting up conversion webhook controller") + + c, err := controller.New("conversion-webhook-controller", mgr, controller.Options{Reconciler: r}) + if err != nil { + return err + } + + err = c.Watch( + source.Kind[*apiextensionsv1.CustomResourceDefinition]( + mgr.GetCache(), + &apiextensionsv1.CustomResourceDefinition{}, + &handler.TypedEnqueueRequestForObject[*apiextensionsv1.CustomResourceDefinition]{}, + predicate.And( + predicate.NewTypedPredicateFuncs(func(crd *apiextensionsv1.CustomResourceDefinition) bool { + return crd.Name == hcoutil.HyperConvergedCRDName + }), + predicate.Or[*apiextensionsv1.CustomResourceDefinition]( + predicate.TypedGenerationChangedPredicate[*apiextensionsv1.CustomResourceDefinition]{}, + predicate.TypedAnnotationChangedPredicate[*apiextensionsv1.CustomResourceDefinition]{}), + ), + ), + ) + + if err != nil { + return err + } + + if r.managedByOLM { + return c.Watch( + source.Kind[*corev1.Secret]( + mgr.GetCache(), + &corev1.Secret{}, + &handler.TypedEnqueueRequestForObject[*corev1.Secret]{}, + predicate.NewTypedPredicateFuncs(func(secret *corev1.Secret) bool { + return secret.Name == r.secretName + }), + ), + ) + } + + return nil +} + +func (r *ReconcileConversionWebhook) Reconcile(ctx context.Context, request reconcile.Request) (reconcile.Result, error) { + logger := logf.FromContext(ctx).WithName("conversion-webhook-controller").WithValues("Request.Name", request.Name) + if request.Name == hcoutil.HyperConvergedCRDName { + logger.Info("Reconciling CRD") + } else { + logger = logger.WithValues("Request.Namespace", request.Namespace) + logger.Info("Reconciling Secret") + } + + // Get the HyperConverged CRD + crd := &apiextensionsv1.CustomResourceDefinition{} + if err := r.client.Get(ctx, client.ObjectKey{Name: hcoutil.HyperConvergedCRDName}, crd); err != nil { + if apierrors.IsNotFound(err) { + logger.Info("HyperConverged CRD not found, skipping reconciliation") + return reconcile.Result{}, nil + } + return reconcile.Result{}, err + } + + var caBundle []byte + var err error + if r.managedByOLM { + caBundle, err = r.getOLMCaBundle(ctx) + if err != nil { + return reconcile.Result{}, err + } + } + + // Check if update is needed + if !r.needsUpdate(crd, caBundle) { + logger.Info("CRD conversion webhook configuration is up to date") + return reconcile.Result{}, nil + } + + // Update CRD with conversion webhook configuration + if err = r.updateCRDConversion(ctx, crd, caBundle); err != nil { + logger.Error(err, "Failed to update CRD conversion webhook configuration") + return reconcile.Result{}, err + } + + logger.Info("Successfully updated CRD conversion webhook configuration") + return reconcile.Result{}, nil +} + +func (r *ReconcileConversionWebhook) needsUpdate(crd *apiextensionsv1.CustomResourceDefinition, caBundle []byte) bool { + if !r.managedByOLM && crd.Annotations[r.certAnnotationName] != r.certAnnotationVal { + return true + } + + if crd.Spec.Conversion == nil { + return true + } + + if crd.Spec.Conversion.Strategy != apiextensionsv1.WebhookConverter { + return true + } + + if crd.Spec.Conversion.Webhook == nil { + return true + } + + webhook := crd.Spec.Conversion.Webhook + if webhook.ClientConfig == nil { + return true + } + + clientConfig := webhook.ClientConfig + if clientConfig.Service == nil { + return true + } + + if r.managedByOLM && slices.Compare(caBundle, clientConfig.CABundle) != 0 { + return true + } + + service := clientConfig.Service + return service.Name != r.serviceName || + service.Namespace != r.namespace || + ptr.Deref(service.Path, "") != hcoutil.HCOConversionWebhookPath || + ptr.Deref(service.Port, 0) != int32(hcoutil.WebhookPort) +} + +func (r *ReconcileConversionWebhook) updateCRDConversion(ctx context.Context, crd *apiextensionsv1.CustomResourceDefinition, caBundle []byte) error { + if !r.managedByOLM { + if crd.Annotations == nil { + crd.Annotations = map[string]string{} + } + + crd.Annotations[r.certAnnotationName] = r.certAnnotationVal + } + + crd.Spec.Conversion = &apiextensionsv1.CustomResourceConversion{ + Strategy: apiextensionsv1.WebhookConverter, + Webhook: &apiextensionsv1.WebhookConversion{ + ClientConfig: &apiextensionsv1.WebhookClientConfig{ + Service: &apiextensionsv1.ServiceReference{ + Namespace: r.namespace, + Name: r.serviceName, + Path: ptr.To(hcoutil.HCOConversionWebhookPath), + Port: ptr.To(int32(hcoutil.WebhookPort)), + }, + }, + ConversionReviewVersions: []string{hcov1.APIVersionV1, hcov1beta1.APIVersionBeta}, + }, + } + + if caBundle != nil { + crd.Spec.Conversion.Webhook.ClientConfig.CABundle = caBundle + } + + return r.client.Update(ctx, crd) +} + +func (r *ReconcileConversionWebhook) getOLMCaBundle(ctx context.Context) ([]byte, error) { + secret := &corev1.Secret{} + err := r.client.Get(ctx, client.ObjectKey{Name: r.secretName, Namespace: r.namespace}, secret) + if err != nil { + return nil, err + } + + caBundle, ok := secret.Data[olmCaBundleKey] + if !ok { + return nil, errors.New("can't find caBundle") + } + + return caBundle, nil +} diff --git a/controllers/webhooks/conversion-webhook-controller/controller_test.go b/controllers/webhooks/conversion-webhook-controller/controller_test.go new file mode 100644 index 0000000000..2140c40fdc --- /dev/null +++ b/controllers/webhooks/conversion-webhook-controller/controller_test.go @@ -0,0 +1,585 @@ +package conversion_webhook_controller + +import ( + "context" + "os" + + "github.com/go-logr/logr" + . "github.com/onsi/ginkgo/v2" + . "github.com/onsi/gomega" + corev1 "k8s.io/api/core/v1" + apiextensionsv1 "k8s.io/apiextensions-apiserver/pkg/apis/apiextensions/v1" + metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" + "k8s.io/apimachinery/pkg/types" + "k8s.io/client-go/rest" + "k8s.io/utils/ptr" + "sigs.k8s.io/controller-runtime/pkg/client" + "sigs.k8s.io/controller-runtime/pkg/manager" + "sigs.k8s.io/controller-runtime/pkg/reconcile" + + hcov1 "github.com/kubevirt/hyperconverged-cluster-operator/api/v1" + hcov1beta1 "github.com/kubevirt/hyperconverged-cluster-operator/api/v1beta1" + "github.com/kubevirt/hyperconverged-cluster-operator/controllers/commontestutils" + fakeownresources "github.com/kubevirt/hyperconverged-cluster-operator/pkg/ownresources/fake" + hcoutil "github.com/kubevirt/hyperconverged-cluster-operator/pkg/util" + "github.com/kubevirt/hyperconverged-cluster-operator/pkg/util/fake/clusterinfo" +) + +const ( + testSecretName = "hco-operator-service-cert" + testServiceName = "hco-operator-service" +) + +var _ = Describe("ConversionWebhookController", func() { + + BeforeEach(func() { + origGetClusterInfo := hcoutil.GetClusterInfo + hcoutil.GetClusterInfo = clusterinfo.NewGetClusterInfo(clusterinfo.WithIsOpenshift(true)) + + DeferCleanup(func() { + hcoutil.GetClusterInfo = origGetClusterInfo + }) + }) + + Describe("Reconcile", func() { + + var ( + request reconcile.Request + ) + + BeforeEach(func() { + Expect(os.Setenv(hcoutil.OperatorNamespaceEnv, commontestutils.Namespace)).To(Succeed()) + fakeownresources.OLMV0OwnResourcesMock() + + request = reconcile.Request{ + NamespacedName: types.NamespacedName{ + Name: hcoutil.HyperConvergedCRDName, + }, + } + + DeferCleanup(func() { + Expect(os.Unsetenv(hcoutil.OperatorNamespaceEnv)).To(Succeed()) + fakeownresources.ResetOwnResources() + }) + }) + + Context("CRD conversion configuration", func() { + + It("should update CRD when conversion is nil", func(ctx context.Context) { + ctx = logr.NewContext(ctx, GinkgoLogr) + crd := newHyperConvergedCRD() + resources := []client.Object{crd} + cl := commontestutils.InitClient(resources) + + reconciler := getReconciler(cl) + + result, err := reconciler.Reconcile(ctx, request) + Expect(err).ToNot(HaveOccurred()) + Expect(result).To(Equal(reconcile.Result{})) + + updatedCRD := &apiextensionsv1.CustomResourceDefinition{} + Expect(cl.Get(ctx, client.ObjectKey{Name: hcoutil.HyperConvergedCRDName}, updatedCRD)).To(Succeed()) + verifyConversionWebhookConfig(updatedCRD) + + Expect(updatedCRD.Annotations).To(HaveKeyWithValue(openshiftCertInjectionAnnotationName, "true")) + Expect(updatedCRD.ResourceVersion).ToNot(Equal(crd.ResourceVersion)) + }) + + It("should set k8s annotation when not running on openshift", func(ctx context.Context) { + ctx = logr.NewContext(ctx, GinkgoLogr) + crd := newHyperConvergedCRD() + resources := []client.Object{crd} + cl := commontestutils.InitClient(resources) + + hcoutil.GetClusterInfo = clusterinfo.NewGetClusterInfo(clusterinfo.WithIsOpenshift(false)) + + reconciler := getReconciler(cl) + + result, err := reconciler.Reconcile(ctx, request) + Expect(err).ToNot(HaveOccurred()) + Expect(result).To(Equal(reconcile.Result{})) + + updatedCRD := &apiextensionsv1.CustomResourceDefinition{} + Expect(cl.Get(ctx, client.ObjectKey{Name: hcoutil.HyperConvergedCRDName}, updatedCRD)).To(Succeed()) + verifyConversionWebhookConfig(updatedCRD) + + Expect(updatedCRD.Annotations).To(HaveKeyWithValue(k8sCertInjectionAnnotationName, commontestutils.Namespace+"/"+testSecretName)) + Expect(updatedCRD.ResourceVersion).ToNot(Equal(crd.ResourceVersion)) + }) + + It("should update CRD when strategy is not Webhook", func(ctx context.Context) { + ctx = logr.NewContext(ctx, GinkgoLogr) + crd := newHyperConvergedCRDWithConversion(&apiextensionsv1.CustomResourceConversion{ + Strategy: apiextensionsv1.NoneConverter, + }) + + resources := []client.Object{crd} + cl := commontestutils.InitClient(resources) + + reconciler := getReconciler(cl) + + result, err := reconciler.Reconcile(ctx, request) + Expect(err).ToNot(HaveOccurred()) + Expect(result).To(Equal(reconcile.Result{})) + + updatedCRD := &apiextensionsv1.CustomResourceDefinition{} + Expect(cl.Get(ctx, client.ObjectKey{Name: hcoutil.HyperConvergedCRDName}, updatedCRD)).To(Succeed()) + verifyConversionWebhookConfig(updatedCRD) + + Expect(updatedCRD.Annotations).To(HaveKeyWithValue(openshiftCertInjectionAnnotationName, "true")) + }) + + It("should update CRD when webhook is nil", func(ctx context.Context) { + ctx = logr.NewContext(ctx, GinkgoLogr) + crd := newHyperConvergedCRDWithConversion(&apiextensionsv1.CustomResourceConversion{ + Strategy: apiextensionsv1.WebhookConverter, + Webhook: nil, + }) + + resources := []client.Object{crd} + cl := commontestutils.InitClient(resources) + + reconciler := getReconciler(cl) + + result, err := reconciler.Reconcile(ctx, request) + Expect(err).ToNot(HaveOccurred()) + Expect(result).To(Equal(reconcile.Result{})) + + updatedCRD := &apiextensionsv1.CustomResourceDefinition{} + Expect(cl.Get(ctx, client.ObjectKey{Name: hcoutil.HyperConvergedCRDName}, updatedCRD)).To(Succeed()) + verifyConversionWebhookConfig(updatedCRD) + + Expect(updatedCRD.Annotations).To(HaveKeyWithValue(openshiftCertInjectionAnnotationName, "true")) + }) + + It("should update CRD when client config is nil", func(ctx context.Context) { + ctx = logr.NewContext(ctx, GinkgoLogr) + crd := newHyperConvergedCRDWithConversion(&apiextensionsv1.CustomResourceConversion{ + Strategy: apiextensionsv1.WebhookConverter, + Webhook: &apiextensionsv1.WebhookConversion{ + ClientConfig: nil, + }, + }) + resources := []client.Object{crd} + cl := commontestutils.InitClient(resources) + + reconciler := getReconciler(cl) + + result, err := reconciler.Reconcile(ctx, request) + Expect(err).ToNot(HaveOccurred()) + Expect(result).To(Equal(reconcile.Result{})) + + updatedCRD := &apiextensionsv1.CustomResourceDefinition{} + Expect(cl.Get(ctx, client.ObjectKey{Name: hcoutil.HyperConvergedCRDName}, updatedCRD)).To(Succeed()) + verifyConversionWebhookConfig(updatedCRD) + + Expect(updatedCRD.Annotations).To(HaveKeyWithValue(openshiftCertInjectionAnnotationName, "true")) + }) + + It("should update CRD when service is nil", func(ctx context.Context) { + ctx = logr.NewContext(ctx, GinkgoLogr) + crd := newHyperConvergedCRDWithConversion(&apiextensionsv1.CustomResourceConversion{ + Strategy: apiextensionsv1.WebhookConverter, + Webhook: &apiextensionsv1.WebhookConversion{ + ClientConfig: &apiextensionsv1.WebhookClientConfig{ + Service: nil, + }, + }, + }) + + resources := []client.Object{crd} + cl := commontestutils.InitClient(resources) + + reconciler := getReconciler(cl) + + result, err := reconciler.Reconcile(ctx, request) + Expect(err).ToNot(HaveOccurred()) + Expect(result).To(Equal(reconcile.Result{})) + + updatedCRD := &apiextensionsv1.CustomResourceDefinition{} + Expect(cl.Get(ctx, client.ObjectKey{Name: hcoutil.HyperConvergedCRDName}, updatedCRD)).To(Succeed()) + verifyConversionWebhookConfig(updatedCRD) + + Expect(updatedCRD.Annotations).To(HaveKeyWithValue(openshiftCertInjectionAnnotationName, "true")) + }) + + It("should update CRD when service name is different", func(ctx context.Context) { + ctx = logr.NewContext(ctx, GinkgoLogr) + crd := newHyperConvergedCRDWithConversion(newValidConversion("wrong-service", commontestutils.Namespace)) + resources := []client.Object{crd} + cl := commontestutils.InitClient(resources) + + reconciler := getReconciler(cl) + + result, err := reconciler.Reconcile(ctx, request) + Expect(err).ToNot(HaveOccurred()) + Expect(result).To(Equal(reconcile.Result{})) + + updatedCRD := &apiextensionsv1.CustomResourceDefinition{} + Expect(cl.Get(ctx, client.ObjectKey{Name: hcoutil.HyperConvergedCRDName}, updatedCRD)).To(Succeed()) + verifyConversionWebhookConfig(updatedCRD) + + Expect(updatedCRD.Annotations).To(HaveKeyWithValue(openshiftCertInjectionAnnotationName, "true")) + }) + + It("should update CRD when service namespace is different", func(ctx context.Context) { + ctx = logr.NewContext(ctx, GinkgoLogr) + crd := newHyperConvergedCRDWithConversion(newValidConversion(testServiceName, "wrong-namespace")) + + resources := []client.Object{crd} + cl := commontestutils.InitClient(resources) + + reconciler := getReconciler(cl) + + result, err := reconciler.Reconcile(ctx, request) + Expect(err).ToNot(HaveOccurred()) + Expect(result).To(Equal(reconcile.Result{})) + + updatedCRD := &apiextensionsv1.CustomResourceDefinition{} + Expect(cl.Get(ctx, client.ObjectKey{Name: hcoutil.HyperConvergedCRDName}, updatedCRD)).To(Succeed()) + verifyConversionWebhookConfig(updatedCRD) + + Expect(updatedCRD.Annotations).To(HaveKeyWithValue(openshiftCertInjectionAnnotationName, "true")) + }) + + It("should update CRD when path is different", func(ctx context.Context) { + ctx = logr.NewContext(ctx, GinkgoLogr) + conversion := newValidConversion(testServiceName, commontestutils.Namespace) + conversion.Webhook.ClientConfig.Service.Path = ptr.To("/wrong-path") + crd := newHyperConvergedCRDWithConversion(conversion) + + resources := []client.Object{crd} + cl := commontestutils.InitClient(resources) + + reconciler := getReconciler(cl) + + result, err := reconciler.Reconcile(ctx, request) + Expect(err).ToNot(HaveOccurred()) + Expect(result).To(Equal(reconcile.Result{})) + + updatedCRD := &apiextensionsv1.CustomResourceDefinition{} + Expect(cl.Get(ctx, client.ObjectKey{Name: hcoutil.HyperConvergedCRDName}, updatedCRD)).To(Succeed()) + verifyConversionWebhookConfig(updatedCRD) + + Expect(updatedCRD.Annotations).To(HaveKeyWithValue(openshiftCertInjectionAnnotationName, "true")) + }) + + It("should update CRD when port is different", func(ctx context.Context) { + ctx = logr.NewContext(ctx, GinkgoLogr) + conversion := newValidConversion(testServiceName, commontestutils.Namespace) + conversion.Webhook.ClientConfig.Service.Port = ptr.To(int32(9999)) + crd := newHyperConvergedCRDWithConversion(conversion) + + resources := []client.Object{crd} + cl := commontestutils.InitClient(resources) + + reconciler := getReconciler(cl) + + result, err := reconciler.Reconcile(ctx, request) + Expect(err).ToNot(HaveOccurred()) + Expect(result).To(Equal(reconcile.Result{})) + + updatedCRD := &apiextensionsv1.CustomResourceDefinition{} + Expect(cl.Get(ctx, client.ObjectKey{Name: hcoutil.HyperConvergedCRDName}, updatedCRD)).To(Succeed()) + verifyConversionWebhookConfig(updatedCRD) + + Expect(updatedCRD.Annotations).To(HaveKeyWithValue(openshiftCertInjectionAnnotationName, "true")) + }) + + It("should update CRD when caBundle was changed", func(ctx context.Context) { + ctx = logr.NewContext(ctx, GinkgoLogr) + + hcoutil.GetClusterInfo = clusterinfo.NewGetClusterInfo(clusterinfo.WithIsManagedByOLM(true)) + + conversion := newValidConversion(testServiceName, commontestutils.Namespace) + conversion.Webhook.ClientConfig.CABundle = []byte("old-secret") + crd := newHyperConvergedCRDWithConversion(conversion) + crd.Annotations = nil + + secret := &corev1.Secret{ + ObjectMeta: metav1.ObjectMeta{ + Name: testSecretName, + Namespace: commontestutils.Namespace, + }, + Data: map[string][]byte{ + olmCaBundleKey: []byte("my-secret-content"), + }, + } + + resources := []client.Object{crd, secret} + cl := commontestutils.InitClient(resources) + + reconciler := getReconciler(cl) + + result, err := reconciler.Reconcile(ctx, request) + Expect(err).ToNot(HaveOccurred()) + Expect(result).To(Equal(reconcile.Result{})) + + updatedCRD := &apiextensionsv1.CustomResourceDefinition{} + Expect(cl.Get(ctx, client.ObjectKey{Name: hcoutil.HyperConvergedCRDName}, updatedCRD)).To(Succeed()) + verifyConversionWebhookConfig(updatedCRD) + + Expect(updatedCRD.Annotations).To(BeNil()) + Expect(updatedCRD.Spec.Conversion.Webhook.ClientConfig.CABundle).To(Equal([]byte("my-secret-content"))) + }) + + It("should not update CRD when configuration is already correct", func(ctx context.Context) { + ctx = logr.NewContext(ctx, GinkgoLogr) + conversion := newValidConversion(testServiceName, commontestutils.Namespace) + crd := newHyperConvergedCRDWithConversion(conversion) + crd.Annotations = map[string]string{ + openshiftCertInjectionAnnotationName: "true", + } + resources := []client.Object{crd} + cl := commontestutils.InitClient(resources) + + reconciler := getReconciler(cl) + + result, err := reconciler.Reconcile(ctx, request) + Expect(err).ToNot(HaveOccurred()) + Expect(result).To(Equal(reconcile.Result{})) + + // Verify CRD was not updated (resource version should remain the same) + updatedCRD := &apiextensionsv1.CustomResourceDefinition{} + Expect(cl.Get(ctx, client.ObjectKey{Name: hcoutil.HyperConvergedCRDName}, updatedCRD)).To(Succeed()) + Expect(updatedCRD.ResourceVersion).To(Equal(crd.ResourceVersion)) + }) + + It("Managed by OLM: should not update CRD when configuration is already correct", func(ctx context.Context) { + ctx = logr.NewContext(ctx, GinkgoLogr) + + hcoutil.GetClusterInfo = clusterinfo.NewGetClusterInfo(clusterinfo.WithIsManagedByOLM(true)) + + conversion := newValidConversion(testServiceName, commontestutils.Namespace) + crd := newHyperConvergedCRDWithConversion(conversion) + conversion.Webhook.ClientConfig.CABundle = []byte("my-secret-content") + crd.Annotations = nil + + secret := &corev1.Secret{ + ObjectMeta: metav1.ObjectMeta{ + Name: testSecretName, + Namespace: commontestutils.Namespace, + }, + Data: map[string][]byte{ + olmCaBundleKey: []byte("my-secret-content"), + }, + } + + resources := []client.Object{crd, secret} + cl := commontestutils.InitClient(resources) + + reconciler := getReconciler(cl) + + result, err := reconciler.Reconcile(ctx, request) + Expect(err).ToNot(HaveOccurred()) + Expect(result).To(Equal(reconcile.Result{})) + + // Verify CRD was not updated (resource version should remain the same) + updatedCRD := &apiextensionsv1.CustomResourceDefinition{} + Expect(cl.Get(ctx, client.ObjectKey{Name: hcoutil.HyperConvergedCRDName}, updatedCRD)).To(Succeed()) + Expect(updatedCRD.ResourceVersion).To(Equal(crd.ResourceVersion)) + }) + }) + + }) + + Describe("needsUpdate", func() { + + var reconciler *ReconcileConversionWebhook + + BeforeEach(func() { + reconciler = &ReconcileConversionWebhook{ + namespace: commontestutils.Namespace, + serviceName: testServiceName, + certAnnotationName: openshiftCertInjectionAnnotationName, + certAnnotationVal: "true", + } + }) + + It("should return true when conversion is nil", func() { + crd := newHyperConvergedCRD() + Expect(reconciler.needsUpdate(crd, nil)).To(BeTrue()) + }) + + It("should return true when strategy is not Webhook", func() { + crd := newHyperConvergedCRDWithConversion(&apiextensionsv1.CustomResourceConversion{ + Strategy: apiextensionsv1.NoneConverter, + }) + Expect(reconciler.needsUpdate(crd, nil)).To(BeTrue()) + }) + + It("should return true when webhook is nil", func() { + crd := newHyperConvergedCRDWithConversion(&apiextensionsv1.CustomResourceConversion{ + Strategy: apiextensionsv1.WebhookConverter, + Webhook: nil, + }) + Expect(reconciler.needsUpdate(crd, nil)).To(BeTrue()) + }) + + It("should return true when client config is nil", func() { + crd := newHyperConvergedCRDWithConversion(&apiextensionsv1.CustomResourceConversion{ + Strategy: apiextensionsv1.WebhookConverter, + Webhook: &apiextensionsv1.WebhookConversion{ + ClientConfig: nil, + }, + }) + Expect(reconciler.needsUpdate(crd, nil)).To(BeTrue()) + }) + + It("should return true when service is nil", func() { + crd := newHyperConvergedCRDWithConversion(&apiextensionsv1.CustomResourceConversion{ + Strategy: apiextensionsv1.WebhookConverter, + Webhook: &apiextensionsv1.WebhookConversion{ + ClientConfig: &apiextensionsv1.WebhookClientConfig{ + Service: nil, + }, + }, + }) + Expect(reconciler.needsUpdate(crd, nil)).To(BeTrue()) + }) + + It("should return true when service name is different", func() { + crd := newHyperConvergedCRDWithConversion(newValidConversion("wrong-name", commontestutils.Namespace)) + Expect(reconciler.needsUpdate(crd, nil)).To(BeTrue()) + }) + + It("should return true when service namespace is different", func() { + crd := newHyperConvergedCRDWithConversion(newValidConversion(testServiceName, "wrong-namespace")) + Expect(reconciler.needsUpdate(crd, nil)).To(BeTrue()) + }) + + It("should return true when path is different", func() { + conversion := newValidConversion(testServiceName, commontestutils.Namespace) + conversion.Webhook.ClientConfig.Service.Path = ptr.To("/wrong-path") + crd := newHyperConvergedCRDWithConversion(conversion) + Expect(reconciler.needsUpdate(crd, nil)).To(BeTrue()) + }) + + It("should return true when port is different", func() { + conversion := newValidConversion(testServiceName, commontestutils.Namespace) + conversion.Webhook.ClientConfig.Service.Port = ptr.To(int32(9999)) + crd := newHyperConvergedCRDWithConversion(conversion) + Expect(reconciler.needsUpdate(crd, nil)).To(BeTrue()) + }) + + It("should return true when annotation value is missing", func() { + crd := newHyperConvergedCRDWithConversion(newValidConversion(testServiceName, commontestutils.Namespace)) + delete(crd.Annotations, openshiftCertInjectionAnnotationName) + Expect(reconciler.needsUpdate(crd, nil)).To(BeTrue()) + }) + + It("should return true when annotation value is wrong", func() { + crd := newHyperConvergedCRDWithConversion(newValidConversion(testServiceName, commontestutils.Namespace)) + crd.Annotations[openshiftCertInjectionAnnotationName] = "false" + Expect(reconciler.needsUpdate(crd, nil)).To(BeTrue()) + }) + + It("should return false when everything matches", func() { + crd := newHyperConvergedCRDWithConversion(newValidConversion(testServiceName, commontestutils.Namespace)) + Expect(reconciler.needsUpdate(crd, nil)).To(BeFalse()) + }) + + Context("Managed by OLM", func() { + const secretContent = "a secret" + + var ( + crd *apiextensionsv1.CustomResourceDefinition + secretBytes []byte + ) + + BeforeEach(func() { + crd = newHyperConvergedCRDWithConversion(newValidConversion(testServiceName, commontestutils.Namespace)) + delete(crd.Annotations, openshiftCertInjectionAnnotationName) + + secretBytes = []byte(secretContent) + crd.Spec.Conversion.Webhook.ClientConfig.CABundle = secretBytes + + reconciler.managedByOLM = true + }) + + It("Managed by OLM: should return true caBundle was not set", func() { + crd.Spec.Conversion.Webhook.ClientConfig.CABundle = nil + Expect(reconciler.needsUpdate(crd, secretBytes)).To(BeTrue()) + }) + + It("Managed by OLM: should return true when caBundle was changed", func() { + Expect(reconciler.needsUpdate(crd, []byte("new secret"))).To(BeTrue()) + }) + + It("should return false when everything matches", func() { + Expect(reconciler.needsUpdate(crd, secretBytes)).To(BeFalse()) + }) + }) + }) +}) + +// Helper functions + +func newHyperConvergedCRD() *apiextensionsv1.CustomResourceDefinition { + return &apiextensionsv1.CustomResourceDefinition{ + ObjectMeta: metav1.ObjectMeta{ + Name: hcoutil.HyperConvergedCRDName, + }, + Spec: apiextensionsv1.CustomResourceDefinitionSpec{ + Group: "hco.kubevirt.io", + Names: apiextensionsv1.CustomResourceDefinitionNames{ + Plural: "hyperconvergeds", + Singular: "hyperconverged", + Kind: "HyperConverged", + }, + Scope: apiextensionsv1.ClusterScoped, + Versions: []apiextensionsv1.CustomResourceDefinitionVersion{ + {Name: "v1", Served: true, Storage: true}, + {Name: "v1beta1", Served: true, Storage: false}, + }, + }, + } +} + +func newHyperConvergedCRDWithConversion(conversion *apiextensionsv1.CustomResourceConversion) *apiextensionsv1.CustomResourceDefinition { + crd := newHyperConvergedCRD() + crd.Spec.Conversion = conversion + crd.Annotations = map[string]string{ + openshiftCertInjectionAnnotationName: "true", + } + return crd +} + +func newValidConversion(serviceName, namespace string) *apiextensionsv1.CustomResourceConversion { + return &apiextensionsv1.CustomResourceConversion{ + Strategy: apiextensionsv1.WebhookConverter, + Webhook: &apiextensionsv1.WebhookConversion{ + ClientConfig: &apiextensionsv1.WebhookClientConfig{ + Service: &apiextensionsv1.ServiceReference{ + Namespace: namespace, + Name: serviceName, + Path: ptr.To(hcoutil.HCOConversionWebhookPath), + Port: ptr.To(int32(hcoutil.WebhookPort)), + }, + }, + ConversionReviewVersions: []string{hcov1.APIVersionV1, hcov1beta1.APIVersionBeta}, + }, + } +} + +func verifyConversionWebhookConfig(crd *apiextensionsv1.CustomResourceDefinition) { + GinkgoHelper() + + Expect(crd.Spec.Conversion).ToNot(BeNil()) + Expect(crd.Spec.Conversion.Strategy).To(Equal(apiextensionsv1.WebhookConverter)) + Expect(crd.Spec.Conversion.Webhook).ToNot(BeNil()) + Expect(crd.Spec.Conversion.Webhook.ClientConfig).ToNot(BeNil()) + Expect(crd.Spec.Conversion.Webhook.ClientConfig.Service).ToNot(BeNil()) + Expect(crd.Spec.Conversion.Webhook.ClientConfig.Service.Namespace).To(Equal(commontestutils.Namespace)) + Expect(crd.Spec.Conversion.Webhook.ClientConfig.Service.Name).To(Equal(testServiceName)) + Expect(crd.Spec.Conversion.Webhook.ClientConfig.Service.Path).To(HaveValue(Equal(hcoutil.HCOConversionWebhookPath))) + Expect(crd.Spec.Conversion.Webhook.ClientConfig.Service.Port).To(HaveValue(Equal(int32(hcoutil.WebhookPort)))) + Expect(crd.Spec.Conversion.Webhook.ConversionReviewVersions).To(ContainElements(hcov1.APIVersionV1, hcov1beta1.APIVersionBeta)) +} + +func getReconciler(cl client.Client) reconcile.Reconciler { + mgr, err := commontestutils.NewManagerMock(&rest.Config{}, manager.Options{Scheme: commontestutils.GetScheme()}, cl, GinkgoLogr) + Expect(err).ToNot(HaveOccurred()) + + return newReconciler(mgr, commontestutils.Namespace, testSecretName, testServiceName) +} diff --git a/controllers/webhooks/conversion-webhook-controller/webhooks_suite_test.go b/controllers/webhooks/conversion-webhook-controller/webhooks_suite_test.go new file mode 100644 index 0000000000..8fc291a653 --- /dev/null +++ b/controllers/webhooks/conversion-webhook-controller/webhooks_suite_test.go @@ -0,0 +1,13 @@ +package conversion_webhook_controller + +import ( + "testing" + + . "github.com/onsi/ginkgo/v2" + . "github.com/onsi/gomega" +) + +func TestConversionWebhookController(t *testing.T) { + RegisterFailHandler(Fail) + RunSpecs(t, "Conversion Webhook Controller Suite") +} diff --git a/deploy/cluster_role.yaml b/deploy/cluster_role.yaml index 7504911401..c9f4bb29b0 100644 --- a/deploy/cluster_role.yaml +++ b/deploy/cluster_role.yaml @@ -1041,6 +1041,8 @@ rules: verbs: - get - list + - update + - patch - watch - delete - apiGroups: diff --git a/deploy/crds/hco00.crd.yaml b/deploy/crds/hco00.crd.yaml index d7b0d4cb77..a1cebffd93 100644 --- a/deploy/crds/hco00.crd.yaml +++ b/deploy/crds/hco00.crd.yaml @@ -17,6 +17,5186 @@ spec: singular: hyperconverged scope: Namespaced versions: + - additionalPrinterColumns: + - jsonPath: .metadata.creationTimestamp + name: Age + type: date + name: v1 + schema: + openAPIV3Schema: + description: HyperConverged is the Schema for the hyperconvergeds API + properties: + apiVersion: + description: |- + APIVersion defines the versioned schema of this representation of an object. + Servers should convert recognized schemas to the latest internal value, and + may reject unrecognized values. + More info: https://git.k8s.io/community/contributors/devel/sig-architecture/api-conventions.md#resources + type: string + kind: + description: |- + Kind is a string value representing the REST resource this object represents. + Servers may infer this from the endpoint the client submits requests to. + Cannot be updated. + In CamelCase. + More info: https://git.k8s.io/community/contributors/devel/sig-architecture/api-conventions.md#types-kinds + type: string + metadata: + properties: + name: + pattern: kubevirt-hyperconverged + type: string + type: object + spec: + default: + certConfig: + ca: + duration: 48h0m0s + renewBefore: 24h0m0s + server: + duration: 24h0m0s + renewBefore: 12h0m0s + deployVmConsoleProxy: false + enableApplicationAwareQuota: false + enableCommonBootImageImport: true + liveMigrationConfig: + allowAutoConverge: false + allowPostCopy: false + completionTimeoutPerGiB: 150 + parallelMigrationsPerCluster: 5 + parallelOutboundMigrationsPerNode: 2 + progressTimeout: 150 + resourceRequirements: + vmiCPUAllocationRatio: 10 + uninstallStrategy: BlockUninstallIfWorkloadsExist + virtualMachineOptions: + disableFreePageReporting: false + disableSerialConsoleLog: false + description: HyperConvergedSpec defines the desired state of HyperConverged + properties: + CommonInstancetypesDeployment: + description: CommonInstancetypesDeployment holds the configuration + of common-instancetypes deployment within KubeVirt. + properties: + enabled: + description: Enabled controls the deployment of common-instancetypes + resources, defaults to True. + nullable: true + type: boolean + type: object + applicationAwareConfig: + description: ApplicationAwareConfig set the AAQ configurations + properties: + allowApplicationAwareClusterResourceQuota: + default: false + description: AllowApplicationAwareClusterResourceQuota if set + to true, allows creation and management of ClusterAppsResourceQuota + type: boolean + namespaceSelector: + description: NamespaceSelector determines in which namespaces + scheduling gate will be added to pods.. + properties: + matchExpressions: + description: matchExpressions is a list of label selector + requirements. The requirements are ANDed. + items: + description: |- + A label selector requirement is a selector that contains values, a key, and an operator that + relates the key and values. + properties: + key: + description: key is the label key that the selector + applies to. + type: string + operator: + description: |- + operator represents a key's relationship to a set of values. + Valid operators are In, NotIn, Exists and DoesNotExist. + type: string + values: + description: |- + values is an array of string values. If the operator is In or NotIn, + the values array must be non-empty. If the operator is Exists or DoesNotExist, + the values array must be empty. This array is replaced during a strategic + merge patch. + items: + type: string + type: array + x-kubernetes-list-type: atomic + required: + - key + - operator + type: object + type: array + x-kubernetes-list-type: atomic + matchLabels: + additionalProperties: + type: string + description: |- + matchLabels is a map of {key,value} pairs. A single {key,value} in the matchLabels + map is equivalent to an element of matchExpressions, whose key field is "key", the + operator is "In", and the values array contains only "value". The requirements are ANDed. + type: object + type: object + x-kubernetes-map-type: atomic + vmiCalcConfigName: + default: DedicatedVirtualResources + description: |- + VmiCalcConfigName determine how resource allocation will be done with ApplicationsResourceQuota. + allowed values are: VmiPodUsage, VirtualResources, DedicatedVirtualResources or IgnoreVmiCalculator + enum: + - VmiPodUsage + - VirtualResources + - DedicatedVirtualResources + - IgnoreVmiCalculator + type: string + type: object + certConfig: + default: + ca: + duration: 48h0m0s + renewBefore: 24h0m0s + server: + duration: 24h0m0s + renewBefore: 12h0m0s + description: certConfig holds the rotation policy for internal, self-signed + certificates + properties: + ca: + default: + duration: 48h0m0s + renewBefore: 24h0m0s + description: |- + CA configuration - + CA certs are kept in the CA bundle as long as they are valid + properties: + duration: + default: 48h0m0s + description: |- + The requested 'duration' (i.e. lifetime) of the Certificate. + This should comply with golang's ParseDuration format (https://golang.org/pkg/time/#ParseDuration) + type: string + renewBefore: + default: 24h0m0s + description: |- + The amount of time before the currently issued certificate's `notAfter` + time that we will begin to attempt to renew the certificate. + This should comply with golang's ParseDuration format (https://golang.org/pkg/time/#ParseDuration) + type: string + type: object + server: + default: + duration: 24h0m0s + renewBefore: 12h0m0s + description: |- + Server configuration - + Certs are rotated and discarded + properties: + duration: + default: 24h0m0s + description: |- + The requested 'duration' (i.e. lifetime) of the Certificate. + This should comply with golang's ParseDuration format (https://golang.org/pkg/time/#ParseDuration) + type: string + renewBefore: + default: 12h0m0s + description: |- + The amount of time before the currently issued certificate's `notAfter` + time that we will begin to attempt to renew the certificate. + This should comply with golang's ParseDuration format (https://golang.org/pkg/time/#ParseDuration) + type: string + type: object + type: object + commonBootImageNamespace: + description: |- + CommonBootImageNamespace override the default namespace of the common boot images, in order to hide them. + + If not set, HCO won't set any namespace, letting SSP to use the default. If set, use the namespace to create the + DataImportCronTemplates and the common image streams, with this namespace. This field is not set by default. + type: string + commonTemplatesNamespace: + description: |- + CommonTemplatesNamespace defines namespace in which common templates will + be deployed. It overrides the default openshift namespace. + type: string + dataImportCronTemplates: + description: DataImportCronTemplates holds list of data import cron + templates (golden images) + items: + description: |- + DataImportCronTemplate defines the template type for DataImportCrons. + It requires metadata.name to be specified while leaving namespace as optional. + properties: + metadata: + properties: + annotations: + additionalProperties: + type: string + type: object + finalizers: + items: + type: string + type: array + labels: + additionalProperties: + type: string + type: object + name: + type: string + namespace: + type: string + type: object + spec: + description: DataImportCronSpec defines specification for DataImportCron + properties: + garbageCollect: + description: |- + GarbageCollect specifies whether old PVCs should be cleaned up after a new PVC is imported. + Options are currently "Outdated" and "Never", defaults to "Outdated". + type: string + importsToKeep: + description: Number of import PVCs to keep when garbage + collecting. Default is 3. + format: int32 + type: integer + managedDataSource: + description: |- + ManagedDataSource specifies the name of the corresponding DataSource this cron will manage. + DataSource has to be in the same namespace. + type: string + retentionPolicy: + description: RetentionPolicy specifies whether the created + DataVolumes and DataSources are retained when their DataImportCron + is deleted. Default is RatainAll. + type: string + schedule: + description: Schedule specifies in cron format when and + how often to look for new imports + type: string + serviceAccountName: + description: ServiceAccountName is the name of the ServiceAccount + for creating DataVolumes. + minLength: 1 + type: string + template: + description: Template specifies template for the DVs to + be created + properties: + apiVersion: + description: |- + APIVersion defines the versioned schema of this representation of an object. + Servers should convert recognized schemas to the latest internal value, and + may reject unrecognized values. + More info: https://git.k8s.io/community/contributors/devel/sig-architecture/api-conventions.md#resources + type: string + kind: + description: |- + Kind is a string value representing the REST resource this object represents. + Servers may infer this from the endpoint the client submits requests to. + Cannot be updated. + In CamelCase. + More info: https://git.k8s.io/community/contributors/devel/sig-architecture/api-conventions.md#types-kinds + type: string + metadata: + properties: + annotations: + additionalProperties: + type: string + type: object + finalizers: + items: + type: string + type: array + labels: + additionalProperties: + type: string + type: object + name: + type: string + namespace: + type: string + type: object + spec: + description: DataVolumeSpec defines the DataVolume type + specification + properties: + checkpoints: + description: Checkpoints is a list of DataVolumeCheckpoints, + representing stages in a multistage import. + items: + description: DataVolumeCheckpoint defines a stage + in a warm migration. + properties: + current: + description: Current is the identifier of + the snapshot created for this checkpoint. + type: string + previous: + description: Previous is the identifier of + the snapshot from the previous checkpoint. + type: string + required: + - current + - previous + type: object + type: array + contentType: + description: 'DataVolumeContentType options: "kubevirt", + "archive"' + enum: + - kubevirt + - archive + type: string + finalCheckpoint: + description: FinalCheckpoint indicates whether the + current DataVolumeCheckpoint is the final checkpoint. + type: boolean + preallocation: + description: Preallocation controls whether storage + for DataVolumes should be allocated in advance. + type: boolean + priorityClassName: + description: PriorityClassName for Importer, Cloner + and Uploader pod + type: string + pvc: + description: PVC is the PVC specification + properties: + accessModes: + description: |- + accessModes contains the desired access modes the volume should have. + More info: https://kubernetes.io/docs/concepts/storage/persistent-volumes#access-modes-1 + items: + type: string + type: array + x-kubernetes-list-type: atomic + dataSource: + description: |- + dataSource field can be used to specify either: + * An existing VolumeSnapshot object (snapshot.storage.k8s.io/VolumeSnapshot) + * An existing PVC (PersistentVolumeClaim) + If the provisioner or an external controller can support the specified data source, + it will create a new volume based on the contents of the specified data source. + When the AnyVolumeDataSource feature gate is enabled, dataSource contents will be copied to dataSourceRef, + and dataSourceRef contents will be copied to dataSource when dataSourceRef.namespace is not specified. + If the namespace is specified, then dataSourceRef will not be copied to dataSource. + properties: + apiGroup: + description: |- + APIGroup is the group for the resource being referenced. + If APIGroup is not specified, the specified Kind must be in the core API group. + For any other third-party types, APIGroup is required. + type: string + kind: + description: Kind is the type of resource + being referenced + type: string + name: + description: Name is the name of resource + being referenced + type: string + required: + - kind + - name + type: object + x-kubernetes-map-type: atomic + dataSourceRef: + description: |- + dataSourceRef specifies the object from which to populate the volume with data, if a non-empty + volume is desired. This may be any object from a non-empty API group (non + core object) or a PersistentVolumeClaim object. + When this field is specified, volume binding will only succeed if the type of + the specified object matches some installed volume populator or dynamic + provisioner. + This field will replace the functionality of the dataSource field and as such + if both fields are non-empty, they must have the same value. For backwards + compatibility, when namespace isn't specified in dataSourceRef, + both fields (dataSource and dataSourceRef) will be set to the same + value automatically if one of them is empty and the other is non-empty. + When namespace is specified in dataSourceRef, + dataSource isn't set to the same value and must be empty. + There are three important differences between dataSource and dataSourceRef: + * While dataSource only allows two specific types of objects, dataSourceRef + allows any non-core object, as well as PersistentVolumeClaim objects. + * While dataSource ignores disallowed values (dropping them), dataSourceRef + preserves all values, and generates an error if a disallowed value is + specified. + * While dataSource only allows local objects, dataSourceRef allows objects + in any namespaces. + (Beta) Using this field requires the AnyVolumeDataSource feature gate to be enabled. + (Alpha) Using the namespace field of dataSourceRef requires the CrossNamespaceVolumeDataSource feature gate to be enabled. + properties: + apiGroup: + description: |- + APIGroup is the group for the resource being referenced. + If APIGroup is not specified, the specified Kind must be in the core API group. + For any other third-party types, APIGroup is required. + type: string + kind: + description: Kind is the type of resource + being referenced + type: string + name: + description: Name is the name of resource + being referenced + type: string + namespace: + description: |- + Namespace is the namespace of resource being referenced + Note that when a namespace is specified, a gateway.networking.k8s.io/ReferenceGrant object is required in the referent namespace to allow that namespace's owner to accept the reference. See the ReferenceGrant documentation for details. + (Alpha) This field requires the CrossNamespaceVolumeDataSource feature gate to be enabled. + type: string + required: + - kind + - name + type: object + resources: + description: |- + resources represents the minimum resources the volume should have. + If RecoverVolumeExpansionFailure feature is enabled users are allowed to specify resource requirements + that are lower than previous value but must still be higher than capacity recorded in the + status field of the claim. + More info: https://kubernetes.io/docs/concepts/storage/persistent-volumes#resources + properties: + limits: + additionalProperties: + anyOf: + - type: integer + - type: string + pattern: ^(\+|-)?(([0-9]+(\.[0-9]*)?)|(\.[0-9]+))(([KMGTPE]i)|[numkMGTPE]|([eE](\+|-)?(([0-9]+(\.[0-9]*)?)|(\.[0-9]+))))?$ + x-kubernetes-int-or-string: true + description: |- + Limits describes the maximum amount of compute resources allowed. + More info: https://kubernetes.io/docs/concepts/configuration/manage-resources-containers/ + type: object + requests: + additionalProperties: + anyOf: + - type: integer + - type: string + pattern: ^(\+|-)?(([0-9]+(\.[0-9]*)?)|(\.[0-9]+))(([KMGTPE]i)|[numkMGTPE]|([eE](\+|-)?(([0-9]+(\.[0-9]*)?)|(\.[0-9]+))))?$ + x-kubernetes-int-or-string: true + description: |- + Requests describes the minimum amount of compute resources required. + If Requests is omitted for a container, it defaults to Limits if that is explicitly specified, + otherwise to an implementation-defined value. Requests cannot exceed Limits. + More info: https://kubernetes.io/docs/concepts/configuration/manage-resources-containers/ + type: object + type: object + selector: + description: selector is a label query over + volumes to consider for binding. + properties: + matchExpressions: + description: matchExpressions is a list + of label selector requirements. The requirements + are ANDed. + items: + description: |- + A label selector requirement is a selector that contains values, a key, and an operator that + relates the key and values. + properties: + key: + description: key is the label key + that the selector applies to. + type: string + operator: + description: |- + operator represents a key's relationship to a set of values. + Valid operators are In, NotIn, Exists and DoesNotExist. + type: string + values: + description: |- + values is an array of string values. If the operator is In or NotIn, + the values array must be non-empty. If the operator is Exists or DoesNotExist, + the values array must be empty. This array is replaced during a strategic + merge patch. + items: + type: string + type: array + x-kubernetes-list-type: atomic + required: + - key + - operator + type: object + type: array + x-kubernetes-list-type: atomic + matchLabels: + additionalProperties: + type: string + description: |- + matchLabels is a map of {key,value} pairs. A single {key,value} in the matchLabels + map is equivalent to an element of matchExpressions, whose key field is "key", the + operator is "In", and the values array contains only "value". The requirements are ANDed. + type: object + type: object + x-kubernetes-map-type: atomic + storageClassName: + description: |- + storageClassName is the name of the StorageClass required by the claim. + More info: https://kubernetes.io/docs/concepts/storage/persistent-volumes#class-1 + type: string + volumeAttributesClassName: + description: |- + volumeAttributesClassName may be used to set the VolumeAttributesClass used by this claim. + If specified, the CSI driver will create or update the volume with the attributes defined + in the corresponding VolumeAttributesClass. This has a different purpose than storageClassName, + it can be changed after the claim is created. An empty string or nil value indicates that no + VolumeAttributesClass will be applied to the claim. If the claim enters an Infeasible error state, + this field can be reset to its previous value (including nil) to cancel the modification. + If the resource referred to by volumeAttributesClass does not exist, this PersistentVolumeClaim will be + set to a Pending state, as reflected by the modifyVolumeStatus field, until such as a resource + exists. + More info: https://kubernetes.io/docs/concepts/storage/volume-attributes-classes/ + type: string + volumeMode: + description: |- + volumeMode defines what type of volume is required by the claim. + Value of Filesystem is implied when not included in claim spec. + type: string + volumeName: + description: volumeName is the binding reference + to the PersistentVolume backing this claim. + type: string + type: object + source: + description: Source is the src of the data for the + requested DataVolume + properties: + blank: + description: DataVolumeBlankImage provides the + parameters to create a new raw blank image + for the PVC + type: object + gcs: + description: DataVolumeSourceGCS provides the + parameters to create a Data Volume from an + GCS source + properties: + secretRef: + description: SecretRef provides the secret + reference needed to access the GCS source + type: string + url: + description: URL is the url of the GCS source + type: string + required: + - url + type: object + http: + description: DataVolumeSourceHTTP can be either + an http or https endpoint, with an optional + basic auth user name and password, and an + optional configmap containing additional CAs + properties: + certConfigMap: + description: CertConfigMap is a configmap + reference, containing a Certificate Authority(CA) + public key, and a base64 encoded pem certificate + type: string + extraHeaders: + description: ExtraHeaders is a list of strings + containing extra headers to include with + HTTP transfer requests + items: + type: string + type: array + secretExtraHeaders: + description: SecretExtraHeaders is a list + of Secret references, each containing + an extra HTTP header that may include + sensitive information + items: + type: string + type: array + secretRef: + description: SecretRef A Secret reference, + the secret should contain accessKeyId + (user name) base64 encoded, and secretKey + (password) also base64 encoded + type: string + url: + description: URL is the URL of the http(s) + endpoint + type: string + required: + - url + type: object + imageio: + description: DataVolumeSourceImageIO provides + the parameters to create a Data Volume from + an imageio source + properties: + certConfigMap: + description: CertConfigMap provides a reference + to the CA cert + type: string + diskId: + description: DiskID provides id of a disk + to be imported + type: string + insecureSkipVerify: + description: InsecureSkipVerify is a flag + to skip certificate verification + type: boolean + secretRef: + description: SecretRef provides the secret + reference needed to access the ovirt-engine + type: string + url: + description: URL is the URL of the ovirt-engine + type: string + required: + - diskId + - url + type: object + pvc: + description: DataVolumeSourcePVC provides the + parameters to create a Data Volume from an + existing PVC + properties: + name: + description: The name of the source PVC + type: string + namespace: + description: The namespace of the source + PVC + type: string + required: + - name + - namespace + type: object + registry: + description: DataVolumeSourceRegistry provides + the parameters to create a Data Volume from + an registry source + properties: + certConfigMap: + description: CertConfigMap provides a reference + to the Registry certs + type: string + imageStream: + description: ImageStream is the name of + image stream for import + type: string + platform: + description: Platform describes the minimum + runtime requirements of the image + properties: + architecture: + description: Architecture specifies + the image target CPU architecture + type: string + type: object + pullMethod: + description: PullMethod can be either "pod" + (default import), or "node" (node docker + cache based import) + type: string + secretRef: + description: SecretRef provides the secret + reference needed to access the Registry + source + type: string + url: + description: 'URL is the url of the registry + source (starting with the scheme: docker, + oci-archive)' + type: string + type: object + s3: + description: DataVolumeSourceS3 provides the + parameters to create a Data Volume from an + S3 source + properties: + certConfigMap: + description: CertConfigMap is a configmap + reference, containing a Certificate Authority(CA) + public key, and a base64 encoded pem certificate + type: string + secretRef: + description: SecretRef provides the secret + reference needed to access the S3 source + type: string + url: + description: URL is the url of the S3 source + type: string + required: + - url + type: object + snapshot: + description: DataVolumeSourceSnapshot provides + the parameters to create a Data Volume from + an existing VolumeSnapshot + properties: + name: + description: The name of the source VolumeSnapshot + type: string + namespace: + description: The namespace of the source + VolumeSnapshot + type: string + required: + - name + - namespace + type: object + upload: + description: DataVolumeSourceUpload provides + the parameters to create a Data Volume by + uploading the source + type: object + vddk: + description: DataVolumeSourceVDDK provides the + parameters to create a Data Volume from a + Vmware source + properties: + backingFile: + description: BackingFile is the path to + the virtual hard disk to migrate from + vCenter/ESXi + type: string + extraArgs: + description: ExtraArgs is a reference to + a ConfigMap containing extra arguments + to pass directly to the VDDK library + type: string + initImageURL: + description: InitImageURL is an optional + URL to an image containing an extracted + VDDK library, overrides v2v-vmware config + map + type: string + secretRef: + description: SecretRef provides a reference + to a secret containing the username and + password needed to access the vCenter + or ESXi host + type: string + thumbprint: + description: Thumbprint is the certificate + thumbprint of the vCenter or ESXi host + type: string + url: + description: URL is the URL of the vCenter + or ESXi host with the VM to migrate + type: string + uuid: + description: UUID is the UUID of the virtual + machine that the backing file is attached + to in vCenter/ESXi + type: string + type: object + type: object + sourceRef: + description: SourceRef is an indirect reference + to the source of data for the requested DataVolume + properties: + kind: + description: The kind of the source reference, + currently only "DataSource" is supported + type: string + name: + description: The name of the source reference + type: string + namespace: + description: The namespace of the source reference, + defaults to the DataVolume namespace + type: string + required: + - kind + - name + type: object + storage: + description: Storage is the requested storage specification + properties: + accessModes: + description: |- + AccessModes contains the desired access modes the volume should have. + More info: https://kubernetes.io/docs/concepts/storage/persistent-volumes#access-modes-1 + items: + type: string + type: array + dataSource: + description: |- + This field can be used to specify either: * An existing VolumeSnapshot object (snapshot.storage.k8s.io/VolumeSnapshot) * An existing PVC (PersistentVolumeClaim) * An existing custom resource that implements data population (Alpha) In order to use custom resource types that implement data population, the AnyVolumeDataSource feature gate must be enabled. If the provisioner or an external controller can support the specified data source, it will create a new volume based on the contents of the specified data source. + If the AnyVolumeDataSource feature gate is enabled, this field will always have the same contents as the DataSourceRef field. + properties: + apiGroup: + description: |- + APIGroup is the group for the resource being referenced. + If APIGroup is not specified, the specified Kind must be in the core API group. + For any other third-party types, APIGroup is required. + type: string + kind: + description: Kind is the type of resource + being referenced + type: string + name: + description: Name is the name of resource + being referenced + type: string + required: + - kind + - name + type: object + x-kubernetes-map-type: atomic + dataSourceRef: + description: |- + Specifies the object from which to populate the volume with data, if a non-empty volume is desired. This may be any local object from a non-empty API group (non core object) or a PersistentVolumeClaim object. When this field is specified, volume binding will only succeed if the type of the specified object matches some installed volume populator or dynamic provisioner. + This field will replace the functionality of the DataSource field and as such if both fields are non-empty, they must have the same value. For backwards compatibility, both fields (DataSource and DataSourceRef) will be set to the same value automatically if one of them is empty and the other is non-empty. + There are two important differences between DataSource and DataSourceRef: + * While DataSource only allows two specific types of objects, DataSourceRef allows any non-core object, as well as PersistentVolumeClaim objects. + * While DataSource ignores disallowed values (dropping them), DataSourceRef preserves all values, and generates an error if a disallowed value is specified. + (Beta) Using this field requires the AnyVolumeDataSource feature gate to be enabled. + properties: + apiGroup: + description: |- + APIGroup is the group for the resource being referenced. + If APIGroup is not specified, the specified Kind must be in the core API group. + For any other third-party types, APIGroup is required. + type: string + kind: + description: Kind is the type of resource + being referenced + type: string + name: + description: Name is the name of resource + being referenced + type: string + namespace: + description: |- + Namespace is the namespace of resource being referenced + Note that when a namespace is specified, a gateway.networking.k8s.io/ReferenceGrant object is required in the referent namespace to allow that namespace's owner to accept the reference. See the ReferenceGrant documentation for details. + (Alpha) This field requires the CrossNamespaceVolumeDataSource feature gate to be enabled. + type: string + required: + - kind + - name + type: object + resources: + description: |- + Resources represents the minimum resources the volume should have. + More info: https://kubernetes.io/docs/concepts/storage/persistent-volumes#resources + properties: + limits: + additionalProperties: + anyOf: + - type: integer + - type: string + pattern: ^(\+|-)?(([0-9]+(\.[0-9]*)?)|(\.[0-9]+))(([KMGTPE]i)|[numkMGTPE]|([eE](\+|-)?(([0-9]+(\.[0-9]*)?)|(\.[0-9]+))))?$ + x-kubernetes-int-or-string: true + description: |- + Limits describes the maximum amount of compute resources allowed. + More info: https://kubernetes.io/docs/concepts/configuration/manage-resources-containers/ + type: object + requests: + additionalProperties: + anyOf: + - type: integer + - type: string + pattern: ^(\+|-)?(([0-9]+(\.[0-9]*)?)|(\.[0-9]+))(([KMGTPE]i)|[numkMGTPE]|([eE](\+|-)?(([0-9]+(\.[0-9]*)?)|(\.[0-9]+))))?$ + x-kubernetes-int-or-string: true + description: |- + Requests describes the minimum amount of compute resources required. + If Requests is omitted for a container, it defaults to Limits if that is explicitly specified, + otherwise to an implementation-defined value. Requests cannot exceed Limits. + More info: https://kubernetes.io/docs/concepts/configuration/manage-resources-containers/ + type: object + type: object + selector: + description: A label query over volumes to consider + for binding. + properties: + matchExpressions: + description: matchExpressions is a list + of label selector requirements. The requirements + are ANDed. + items: + description: |- + A label selector requirement is a selector that contains values, a key, and an operator that + relates the key and values. + properties: + key: + description: key is the label key + that the selector applies to. + type: string + operator: + description: |- + operator represents a key's relationship to a set of values. + Valid operators are In, NotIn, Exists and DoesNotExist. + type: string + values: + description: |- + values is an array of string values. If the operator is In or NotIn, + the values array must be non-empty. If the operator is Exists or DoesNotExist, + the values array must be empty. This array is replaced during a strategic + merge patch. + items: + type: string + type: array + x-kubernetes-list-type: atomic + required: + - key + - operator + type: object + type: array + x-kubernetes-list-type: atomic + matchLabels: + additionalProperties: + type: string + description: |- + matchLabels is a map of {key,value} pairs. A single {key,value} in the matchLabels + map is equivalent to an element of matchExpressions, whose key field is "key", the + operator is "In", and the values array contains only "value". The requirements are ANDed. + type: object + type: object + x-kubernetes-map-type: atomic + storageClassName: + description: |- + Name of the StorageClass required by the claim. + More info: https://kubernetes.io/docs/concepts/storage/persistent-volumes#class-1 + type: string + volumeMode: + description: |- + volumeMode defines what type of volume is required by the claim. + Value of Filesystem is implied when not included in claim spec. + type: string + volumeName: + description: VolumeName is the binding reference + to the PersistentVolume backing this claim. + type: string + type: object + type: object + status: + description: DataVolumeStatus contains the current status + of the DataVolume + properties: + claimName: + description: ClaimName is the name of the underlying + PVC used by the DataVolume. + type: string + conditions: + items: + description: DataVolumeCondition represents the + state of a data volume condition. + properties: + lastHeartbeatTime: + format: date-time + type: string + lastTransitionTime: + format: date-time + type: string + message: + type: string + reason: + type: string + status: + type: string + type: + description: DataVolumeConditionType is the + string representation of known condition + types + type: string + required: + - status + - type + type: object + type: array + phase: + description: Phase is the current phase of the data + volume + type: string + progress: + description: DataVolumeProgress is the current progress + of the DataVolume transfer operation. Value between + 0 and 100 inclusive, N/A if not available + type: string + restartCount: + description: RestartCount is the number of times + the pod populating the DataVolume has restarted + format: int32 + type: integer + type: object + required: + - spec + type: object + required: + - managedDataSource + - schedule + - template + type: object + type: object + type: array + x-kubernetes-list-type: atomic + defaultCPUModel: + description: |- + DefaultCPUModel defines a cluster default for CPU model: default CPU model is set when VMI doesn't have any CPU model. + When VMI has CPU model set, then VMI's CPU model is preferred. + When default CPU model is not set and VMI's CPU model is not set too, host-model will be set. + Default CPU model can be changed when kubevirt is running. + type: string + defaultRuntimeClass: + description: |- + DefaultRuntimeClass defines a cluster default for the RuntimeClass to be used for VMIs pods if not set there. + Default RuntimeClass can be changed when kubevirt is running, existing VMIs are not impacted till + the next restart/live-migration when they are eventually going to consume the new default RuntimeClass. + type: string + deployVmConsoleProxy: + default: false + description: deploy VM console proxy resources in SSP operator + type: boolean + enableApplicationAwareQuota: + default: false + description: EnableApplicationAwareQuota if true, enables the Application + Aware Quota feature + type: boolean + enableCommonBootImageImport: + default: true + description: |- + Opt-in to automatic delivery/updates of the common data import cron templates. + There are two sources for the data import cron templates: hard coded list of common templates, and custom (user + defined) templates that can be added to the dataImportCronTemplates field. This field only controls the common + templates. It is possible to use custom templates by adding them to the dataImportCronTemplates field. + type: boolean + evictionStrategy: + description: |- + EvictionStrategy defines at the cluster level if the VirtualMachineInstance should be + migrated instead of shut-off in case of a node drain. If the VirtualMachineInstance specific + field is set it overrides the cluster level one. + Allowed values: + - `None` no eviction strategy at cluster level. + - `LiveMigrate` migrate the VM on eviction; a not live migratable VM with no specific strategy will block the drain of the node util manually evicted. + - `LiveMigrateIfPossible` migrate the VM on eviction if live migration is possible, otherwise directly evict. + - `External` block the drain, track eviction and notify an external controller. + Defaults to LiveMigrate with multiple worker nodes, None on single worker clusters. + enum: + - None + - LiveMigrate + - LiveMigrateIfPossible + - External + type: string + featureGates: + description: |- + FeatureGates is a set of optional feature gates to enable or disable new + features that are not generally available yet. + Add a new FeatureGate Object to this set, to enable a feature that is + disabled by default, or to disable a feature that is enabled by default. + + A feature gate may be in the following phases: + * Alpha: the feature is in dev-preview. It is disabled by default, but can + be enabled. + * Beta: the feature gate is in tech-preview. It is enabled by default, but + can be disabled. + * GA: the feature is graduated and is always enabled. There is no way to + disable it. + * Deprecated: the feature is no longer supported. There is no way to enable + it + + Feature-Gate list: + * alignCPUs: + Enable KubeVirt to request up to two additional dedicated CPUs in order to + complete the total CPU count to an even parity when using emulator thread + isolation. + Note: this feature is in Developer Preview. + Phase: Alpha + + * decentralizedLiveMigration: + enables the decentralized live migration (cross-cluster migration) feature. + This feature allows live migration of VirtualMachineInstances between + different clusters. + Note: This feature is in Developer Preview. + Phase: Alpha + + * declarativeHotplugVolumes: + enables the use of the declarative volume hotplug feature in KubeVirt. + When enabled, the "DeclarativeHotplugVolumes" feature gate is enabled in + the KubeVirt CR, instead of the "HotplugVolumes" feature gate. + When disabled, the "HotplugVolumes" feature gate is enabled (default + behavior). + Phase: Alpha + + * deployKubeSecondaryDNS: + Deploy KubeSecondaryDNS by CNAO + Phase: Alpha + + * disableMDevConfiguration: + Disable mediated devices handling on KubeVirt + Phase: Alpha + + * downwardMetrics: + Allow to expose a limited set of host metrics to guests. + Phase: Alpha + + * enableMultiArchBootImageImport: + allows the HCO to run on heterogeneous clusters with different CPU + architectures. + Enabling this feature gate will allow the HCO to create Golden Images for + different CPU architectures. + Phase: Alpha + + * objectGraph: + enables the ObjectGraph VM and VMI subresource in KubeVirt. + This subresource returns a structured list of k8s objects that are related + to the specified VM or VMI, enabling better dependency tracking. + Phase: Alpha + + * persistentReservation: + Enable persistent reservation of a LUN through the SCSI Persistent Reserve + commands on Kubevirt. + In order to issue privileged SCSI ioctls, the VM requires activation of the + persistent reservation flag. + Once this feature gate is enabled, then the additional container with the + qemu-pr-helper is deployed inside the virt-handler pod. + Enabling (or removing) the feature gate causes the redeployment of the + virt-handler pod. + Phase: Alpha + + * videoConfig: + allows users to configure video device types for their virtual machines. + This can be useful for workloads that require specific video capabilities + or architectures. + Phase: Beta + + * autoResourceLimits: + Phase: Deprecated + + * deployKubevirtIpamController: + Phase: Deprecated + + * deployTektonTaskResources: + Phase: Deprecated + + * deployVmConsoleProxy: + Phase: Deprecated + + * enableApplicationAwareQuota: + This feature gate is ignored. Use spec.enableApplicationAwareQuota field instead + Phase: Deprecated + + * enableCommonBootImageImport: + This feature gate is ignored. Use spec.enableCommonBootImageImport field instead + Phase: Deprecated + + * enableManagedTenantQuota: + Phase: Deprecated + + * nonRoot: + Phase: Deprecated + + * primaryUserDefinedNetworkBinding: + Phase: Deprecated + + * withHostPassthroughCPU: + Phase: Deprecated + items: + description: FeatureGate is an optional feature gate to enable or + disable a new feature that is not generally available yet. + properties: + name: + description: Name is the feature gate name + type: string + state: + description: State determines if the feature gate is enabled + ("Enabled"), or disabled ("False"). The default value is "Disabled". + enum: + - Enabled + - Disabled + type: string + required: + - name + type: object + type: array + filesystemOverhead: + description: |- + FilesystemOverhead describes the space reserved for overhead when using Filesystem volumes. + A value is between 0 and 1, if not defined it is 0.055 (5.5 percent overhead) + properties: + global: + description: Global is how much space of a Filesystem volume should + be reserved for overhead. This value is used unless overridden + by a more specific value (per storageClass) + pattern: ^(0(?:\.\d{1,3})?|1)$ + type: string + storageClass: + additionalProperties: + description: |- + Percent is a string that can only be a value between [0,1) + (Note: we actually rely on reconcile to reject invalid values) + pattern: ^(0(?:\.\d{1,3})?|1)$ + type: string + description: StorageClass specifies how much space of a Filesystem + volume should be reserved for safety. The keys are the storageClass + and the values are the overhead. This value overrides the global + value + type: object + type: object + higherWorkloadDensity: + default: + memoryOvercommitPercentage: 100 + description: HigherWorkloadDensity holds configuration aimed to increase + virtual machine density + properties: + memoryOvercommitPercentage: + default: 100 + description: |- + MemoryOvercommitPercentage is the percentage of memory we want to give VMIs compared to the amount + given to its parent pod (virt-launcher). For example, a value of 102 means the VMI will + "see" 2% more memory than its parent pod. Values under 100 are effectively "undercommits". + Overcommits can lead to memory exhaustion, which in turn can lead to crashes. Use carefully. + minimum: 10 + type: integer + type: object + infra: + description: |- + infra HyperConvergedConfig influences the pod configuration (currently only placement) + for all the infra components needed on the virtualization enabled cluster + but not necessarily directly on each node running VMs/VMIs. + properties: + nodePlacement: + description: NodePlacement describes node scheduling configuration. + properties: + affinity: + description: |- + affinity enables pod affinity/anti-affinity placement expanding the types of constraints + that can be expressed with nodeSelector. + affinity is going to be applied to the relevant kind of pods in parallel with nodeSelector + See https://kubernetes.io/docs/concepts/scheduling-eviction/assign-pod-node/#affinity-and-anti-affinity + properties: + nodeAffinity: + description: Describes node affinity scheduling rules + for the pod. + properties: + preferredDuringSchedulingIgnoredDuringExecution: + description: |- + The scheduler will prefer to schedule pods to nodes that satisfy + the affinity expressions specified by this field, but it may choose + a node that violates one or more of the expressions. The node that is + most preferred is the one with the greatest sum of weights, i.e. + for each node that meets all of the scheduling requirements (resource + request, requiredDuringScheduling affinity expressions, etc.), + compute a sum by iterating through the elements of this field and adding + "weight" to the sum if the node matches the corresponding matchExpressions; the + node(s) with the highest sum are the most preferred. + items: + description: |- + An empty preferred scheduling term matches all objects with implicit weight 0 + (i.e. it's a no-op). A null preferred scheduling term matches no objects (i.e. is also a no-op). + properties: + preference: + description: A node selector term, associated + with the corresponding weight. + properties: + matchExpressions: + description: A list of node selector requirements + by node's labels. + items: + description: |- + A node selector requirement is a selector that contains values, a key, and an operator + that relates the key and values. + properties: + key: + description: The label key that the + selector applies to. + type: string + operator: + description: |- + Represents a key's relationship to a set of values. + Valid operators are In, NotIn, Exists, DoesNotExist. Gt, and Lt. + type: string + values: + description: |- + An array of string values. If the operator is In or NotIn, + the values array must be non-empty. If the operator is Exists or DoesNotExist, + the values array must be empty. If the operator is Gt or Lt, the values + array must have a single element, which will be interpreted as an integer. + This array is replaced during a strategic merge patch. + items: + type: string + type: array + x-kubernetes-list-type: atomic + required: + - key + - operator + type: object + type: array + x-kubernetes-list-type: atomic + matchFields: + description: A list of node selector requirements + by node's fields. + items: + description: |- + A node selector requirement is a selector that contains values, a key, and an operator + that relates the key and values. + properties: + key: + description: The label key that the + selector applies to. + type: string + operator: + description: |- + Represents a key's relationship to a set of values. + Valid operators are In, NotIn, Exists, DoesNotExist. Gt, and Lt. + type: string + values: + description: |- + An array of string values. If the operator is In or NotIn, + the values array must be non-empty. If the operator is Exists or DoesNotExist, + the values array must be empty. If the operator is Gt or Lt, the values + array must have a single element, which will be interpreted as an integer. + This array is replaced during a strategic merge patch. + items: + type: string + type: array + x-kubernetes-list-type: atomic + required: + - key + - operator + type: object + type: array + x-kubernetes-list-type: atomic + type: object + x-kubernetes-map-type: atomic + weight: + description: Weight associated with matching + the corresponding nodeSelectorTerm, in the + range 1-100. + format: int32 + type: integer + required: + - preference + - weight + type: object + type: array + x-kubernetes-list-type: atomic + requiredDuringSchedulingIgnoredDuringExecution: + description: |- + If the affinity requirements specified by this field are not met at + scheduling time, the pod will not be scheduled onto the node. + If the affinity requirements specified by this field cease to be met + at some point during pod execution (e.g. due to an update), the system + may or may not try to eventually evict the pod from its node. + properties: + nodeSelectorTerms: + description: Required. A list of node selector + terms. The terms are ORed. + items: + description: |- + A null or empty node selector term matches no objects. The requirements of + them are ANDed. + The TopologySelectorTerm type implements a subset of the NodeSelectorTerm. + properties: + matchExpressions: + description: A list of node selector requirements + by node's labels. + items: + description: |- + A node selector requirement is a selector that contains values, a key, and an operator + that relates the key and values. + properties: + key: + description: The label key that the + selector applies to. + type: string + operator: + description: |- + Represents a key's relationship to a set of values. + Valid operators are In, NotIn, Exists, DoesNotExist. Gt, and Lt. + type: string + values: + description: |- + An array of string values. If the operator is In or NotIn, + the values array must be non-empty. If the operator is Exists or DoesNotExist, + the values array must be empty. If the operator is Gt or Lt, the values + array must have a single element, which will be interpreted as an integer. + This array is replaced during a strategic merge patch. + items: + type: string + type: array + x-kubernetes-list-type: atomic + required: + - key + - operator + type: object + type: array + x-kubernetes-list-type: atomic + matchFields: + description: A list of node selector requirements + by node's fields. + items: + description: |- + A node selector requirement is a selector that contains values, a key, and an operator + that relates the key and values. + properties: + key: + description: The label key that the + selector applies to. + type: string + operator: + description: |- + Represents a key's relationship to a set of values. + Valid operators are In, NotIn, Exists, DoesNotExist. Gt, and Lt. + type: string + values: + description: |- + An array of string values. If the operator is In or NotIn, + the values array must be non-empty. If the operator is Exists or DoesNotExist, + the values array must be empty. If the operator is Gt or Lt, the values + array must have a single element, which will be interpreted as an integer. + This array is replaced during a strategic merge patch. + items: + type: string + type: array + x-kubernetes-list-type: atomic + required: + - key + - operator + type: object + type: array + x-kubernetes-list-type: atomic + type: object + x-kubernetes-map-type: atomic + type: array + x-kubernetes-list-type: atomic + required: + - nodeSelectorTerms + type: object + x-kubernetes-map-type: atomic + type: object + podAffinity: + description: Describes pod affinity scheduling rules (e.g. + co-locate this pod in the same node, zone, etc. as some + other pod(s)). + properties: + preferredDuringSchedulingIgnoredDuringExecution: + description: |- + The scheduler will prefer to schedule pods to nodes that satisfy + the affinity expressions specified by this field, but it may choose + a node that violates one or more of the expressions. The node that is + most preferred is the one with the greatest sum of weights, i.e. + for each node that meets all of the scheduling requirements (resource + request, requiredDuringScheduling affinity expressions, etc.), + compute a sum by iterating through the elements of this field and adding + "weight" to the sum if the node has pods which matches the corresponding podAffinityTerm; the + node(s) with the highest sum are the most preferred. + items: + description: The weights of all of the matched WeightedPodAffinityTerm + fields are added per-node to find the most preferred + node(s) + properties: + podAffinityTerm: + description: Required. A pod affinity term, + associated with the corresponding weight. + properties: + labelSelector: + description: |- + A label query over a set of resources, in this case pods. + If it's null, this PodAffinityTerm matches with no Pods. + properties: + matchExpressions: + description: matchExpressions is a list + of label selector requirements. The + requirements are ANDed. + items: + description: |- + A label selector requirement is a selector that contains values, a key, and an operator that + relates the key and values. + properties: + key: + description: key is the label + key that the selector applies + to. + type: string + operator: + description: |- + operator represents a key's relationship to a set of values. + Valid operators are In, NotIn, Exists and DoesNotExist. + type: string + values: + description: |- + values is an array of string values. If the operator is In or NotIn, + the values array must be non-empty. If the operator is Exists or DoesNotExist, + the values array must be empty. This array is replaced during a strategic + merge patch. + items: + type: string + type: array + x-kubernetes-list-type: atomic + required: + - key + - operator + type: object + type: array + x-kubernetes-list-type: atomic + matchLabels: + additionalProperties: + type: string + description: |- + matchLabels is a map of {key,value} pairs. A single {key,value} in the matchLabels + map is equivalent to an element of matchExpressions, whose key field is "key", the + operator is "In", and the values array contains only "value". The requirements are ANDed. + type: object + type: object + x-kubernetes-map-type: atomic + matchLabelKeys: + description: |- + MatchLabelKeys is a set of pod label keys to select which pods will + be taken into consideration. The keys are used to lookup values from the + incoming pod labels, those key-value labels are merged with `labelSelector` as `key in (value)` + to select the group of existing pods which pods will be taken into consideration + for the incoming pod's pod (anti) affinity. Keys that don't exist in the incoming + pod labels will be ignored. The default value is empty. + The same key is forbidden to exist in both matchLabelKeys and labelSelector. + Also, matchLabelKeys cannot be set when labelSelector isn't set. + items: + type: string + type: array + x-kubernetes-list-type: atomic + mismatchLabelKeys: + description: |- + MismatchLabelKeys is a set of pod label keys to select which pods will + be taken into consideration. The keys are used to lookup values from the + incoming pod labels, those key-value labels are merged with `labelSelector` as `key notin (value)` + to select the group of existing pods which pods will be taken into consideration + for the incoming pod's pod (anti) affinity. Keys that don't exist in the incoming + pod labels will be ignored. The default value is empty. + The same key is forbidden to exist in both mismatchLabelKeys and labelSelector. + Also, mismatchLabelKeys cannot be set when labelSelector isn't set. + items: + type: string + type: array + x-kubernetes-list-type: atomic + namespaceSelector: + description: |- + A label query over the set of namespaces that the term applies to. + The term is applied to the union of the namespaces selected by this field + and the ones listed in the namespaces field. + null selector and null or empty namespaces list means "this pod's namespace". + An empty selector ({}) matches all namespaces. + properties: + matchExpressions: + description: matchExpressions is a list + of label selector requirements. The + requirements are ANDed. + items: + description: |- + A label selector requirement is a selector that contains values, a key, and an operator that + relates the key and values. + properties: + key: + description: key is the label + key that the selector applies + to. + type: string + operator: + description: |- + operator represents a key's relationship to a set of values. + Valid operators are In, NotIn, Exists and DoesNotExist. + type: string + values: + description: |- + values is an array of string values. If the operator is In or NotIn, + the values array must be non-empty. If the operator is Exists or DoesNotExist, + the values array must be empty. This array is replaced during a strategic + merge patch. + items: + type: string + type: array + x-kubernetes-list-type: atomic + required: + - key + - operator + type: object + type: array + x-kubernetes-list-type: atomic + matchLabels: + additionalProperties: + type: string + description: |- + matchLabels is a map of {key,value} pairs. A single {key,value} in the matchLabels + map is equivalent to an element of matchExpressions, whose key field is "key", the + operator is "In", and the values array contains only "value". The requirements are ANDed. + type: object + type: object + x-kubernetes-map-type: atomic + namespaces: + description: |- + namespaces specifies a static list of namespace names that the term applies to. + The term is applied to the union of the namespaces listed in this field + and the ones selected by namespaceSelector. + null or empty namespaces list and null namespaceSelector means "this pod's namespace". + items: + type: string + type: array + x-kubernetes-list-type: atomic + topologyKey: + description: |- + This pod should be co-located (affinity) or not co-located (anti-affinity) with the pods matching + the labelSelector in the specified namespaces, where co-located is defined as running on a node + whose value of the label with key topologyKey matches that of any node on which any of the + selected pods is running. + Empty topologyKey is not allowed. + type: string + required: + - topologyKey + type: object + weight: + description: |- + weight associated with matching the corresponding podAffinityTerm, + in the range 1-100. + format: int32 + type: integer + required: + - podAffinityTerm + - weight + type: object + type: array + x-kubernetes-list-type: atomic + requiredDuringSchedulingIgnoredDuringExecution: + description: |- + If the affinity requirements specified by this field are not met at + scheduling time, the pod will not be scheduled onto the node. + If the affinity requirements specified by this field cease to be met + at some point during pod execution (e.g. due to a pod label update), the + system may or may not try to eventually evict the pod from its node. + When there are multiple elements, the lists of nodes corresponding to each + podAffinityTerm are intersected, i.e. all terms must be satisfied. + items: + description: |- + Defines a set of pods (namely those matching the labelSelector + relative to the given namespace(s)) that this pod should be + co-located (affinity) or not co-located (anti-affinity) with, + where co-located is defined as running on a node whose value of + the label with key matches that of any node on which + a pod of the set of pods is running + properties: + labelSelector: + description: |- + A label query over a set of resources, in this case pods. + If it's null, this PodAffinityTerm matches with no Pods. + properties: + matchExpressions: + description: matchExpressions is a list + of label selector requirements. The requirements + are ANDed. + items: + description: |- + A label selector requirement is a selector that contains values, a key, and an operator that + relates the key and values. + properties: + key: + description: key is the label key + that the selector applies to. + type: string + operator: + description: |- + operator represents a key's relationship to a set of values. + Valid operators are In, NotIn, Exists and DoesNotExist. + type: string + values: + description: |- + values is an array of string values. If the operator is In or NotIn, + the values array must be non-empty. If the operator is Exists or DoesNotExist, + the values array must be empty. This array is replaced during a strategic + merge patch. + items: + type: string + type: array + x-kubernetes-list-type: atomic + required: + - key + - operator + type: object + type: array + x-kubernetes-list-type: atomic + matchLabels: + additionalProperties: + type: string + description: |- + matchLabels is a map of {key,value} pairs. A single {key,value} in the matchLabels + map is equivalent to an element of matchExpressions, whose key field is "key", the + operator is "In", and the values array contains only "value". The requirements are ANDed. + type: object + type: object + x-kubernetes-map-type: atomic + matchLabelKeys: + description: |- + MatchLabelKeys is a set of pod label keys to select which pods will + be taken into consideration. The keys are used to lookup values from the + incoming pod labels, those key-value labels are merged with `labelSelector` as `key in (value)` + to select the group of existing pods which pods will be taken into consideration + for the incoming pod's pod (anti) affinity. Keys that don't exist in the incoming + pod labels will be ignored. The default value is empty. + The same key is forbidden to exist in both matchLabelKeys and labelSelector. + Also, matchLabelKeys cannot be set when labelSelector isn't set. + items: + type: string + type: array + x-kubernetes-list-type: atomic + mismatchLabelKeys: + description: |- + MismatchLabelKeys is a set of pod label keys to select which pods will + be taken into consideration. The keys are used to lookup values from the + incoming pod labels, those key-value labels are merged with `labelSelector` as `key notin (value)` + to select the group of existing pods which pods will be taken into consideration + for the incoming pod's pod (anti) affinity. Keys that don't exist in the incoming + pod labels will be ignored. The default value is empty. + The same key is forbidden to exist in both mismatchLabelKeys and labelSelector. + Also, mismatchLabelKeys cannot be set when labelSelector isn't set. + items: + type: string + type: array + x-kubernetes-list-type: atomic + namespaceSelector: + description: |- + A label query over the set of namespaces that the term applies to. + The term is applied to the union of the namespaces selected by this field + and the ones listed in the namespaces field. + null selector and null or empty namespaces list means "this pod's namespace". + An empty selector ({}) matches all namespaces. + properties: + matchExpressions: + description: matchExpressions is a list + of label selector requirements. The requirements + are ANDed. + items: + description: |- + A label selector requirement is a selector that contains values, a key, and an operator that + relates the key and values. + properties: + key: + description: key is the label key + that the selector applies to. + type: string + operator: + description: |- + operator represents a key's relationship to a set of values. + Valid operators are In, NotIn, Exists and DoesNotExist. + type: string + values: + description: |- + values is an array of string values. If the operator is In or NotIn, + the values array must be non-empty. If the operator is Exists or DoesNotExist, + the values array must be empty. This array is replaced during a strategic + merge patch. + items: + type: string + type: array + x-kubernetes-list-type: atomic + required: + - key + - operator + type: object + type: array + x-kubernetes-list-type: atomic + matchLabels: + additionalProperties: + type: string + description: |- + matchLabels is a map of {key,value} pairs. A single {key,value} in the matchLabels + map is equivalent to an element of matchExpressions, whose key field is "key", the + operator is "In", and the values array contains only "value". The requirements are ANDed. + type: object + type: object + x-kubernetes-map-type: atomic + namespaces: + description: |- + namespaces specifies a static list of namespace names that the term applies to. + The term is applied to the union of the namespaces listed in this field + and the ones selected by namespaceSelector. + null or empty namespaces list and null namespaceSelector means "this pod's namespace". + items: + type: string + type: array + x-kubernetes-list-type: atomic + topologyKey: + description: |- + This pod should be co-located (affinity) or not co-located (anti-affinity) with the pods matching + the labelSelector in the specified namespaces, where co-located is defined as running on a node + whose value of the label with key topologyKey matches that of any node on which any of the + selected pods is running. + Empty topologyKey is not allowed. + type: string + required: + - topologyKey + type: object + type: array + x-kubernetes-list-type: atomic + type: object + podAntiAffinity: + description: Describes pod anti-affinity scheduling rules + (e.g. avoid putting this pod in the same node, zone, + etc. as some other pod(s)). + properties: + preferredDuringSchedulingIgnoredDuringExecution: + description: |- + The scheduler will prefer to schedule pods to nodes that satisfy + the anti-affinity expressions specified by this field, but it may choose + a node that violates one or more of the expressions. The node that is + most preferred is the one with the greatest sum of weights, i.e. + for each node that meets all of the scheduling requirements (resource + request, requiredDuringScheduling anti-affinity expressions, etc.), + compute a sum by iterating through the elements of this field and subtracting + "weight" from the sum if the node has pods which matches the corresponding podAffinityTerm; the + node(s) with the highest sum are the most preferred. + items: + description: The weights of all of the matched WeightedPodAffinityTerm + fields are added per-node to find the most preferred + node(s) + properties: + podAffinityTerm: + description: Required. A pod affinity term, + associated with the corresponding weight. + properties: + labelSelector: + description: |- + A label query over a set of resources, in this case pods. + If it's null, this PodAffinityTerm matches with no Pods. + properties: + matchExpressions: + description: matchExpressions is a list + of label selector requirements. The + requirements are ANDed. + items: + description: |- + A label selector requirement is a selector that contains values, a key, and an operator that + relates the key and values. + properties: + key: + description: key is the label + key that the selector applies + to. + type: string + operator: + description: |- + operator represents a key's relationship to a set of values. + Valid operators are In, NotIn, Exists and DoesNotExist. + type: string + values: + description: |- + values is an array of string values. If the operator is In or NotIn, + the values array must be non-empty. If the operator is Exists or DoesNotExist, + the values array must be empty. This array is replaced during a strategic + merge patch. + items: + type: string + type: array + x-kubernetes-list-type: atomic + required: + - key + - operator + type: object + type: array + x-kubernetes-list-type: atomic + matchLabels: + additionalProperties: + type: string + description: |- + matchLabels is a map of {key,value} pairs. A single {key,value} in the matchLabels + map is equivalent to an element of matchExpressions, whose key field is "key", the + operator is "In", and the values array contains only "value". The requirements are ANDed. + type: object + type: object + x-kubernetes-map-type: atomic + matchLabelKeys: + description: |- + MatchLabelKeys is a set of pod label keys to select which pods will + be taken into consideration. The keys are used to lookup values from the + incoming pod labels, those key-value labels are merged with `labelSelector` as `key in (value)` + to select the group of existing pods which pods will be taken into consideration + for the incoming pod's pod (anti) affinity. Keys that don't exist in the incoming + pod labels will be ignored. The default value is empty. + The same key is forbidden to exist in both matchLabelKeys and labelSelector. + Also, matchLabelKeys cannot be set when labelSelector isn't set. + items: + type: string + type: array + x-kubernetes-list-type: atomic + mismatchLabelKeys: + description: |- + MismatchLabelKeys is a set of pod label keys to select which pods will + be taken into consideration. The keys are used to lookup values from the + incoming pod labels, those key-value labels are merged with `labelSelector` as `key notin (value)` + to select the group of existing pods which pods will be taken into consideration + for the incoming pod's pod (anti) affinity. Keys that don't exist in the incoming + pod labels will be ignored. The default value is empty. + The same key is forbidden to exist in both mismatchLabelKeys and labelSelector. + Also, mismatchLabelKeys cannot be set when labelSelector isn't set. + items: + type: string + type: array + x-kubernetes-list-type: atomic + namespaceSelector: + description: |- + A label query over the set of namespaces that the term applies to. + The term is applied to the union of the namespaces selected by this field + and the ones listed in the namespaces field. + null selector and null or empty namespaces list means "this pod's namespace". + An empty selector ({}) matches all namespaces. + properties: + matchExpressions: + description: matchExpressions is a list + of label selector requirements. The + requirements are ANDed. + items: + description: |- + A label selector requirement is a selector that contains values, a key, and an operator that + relates the key and values. + properties: + key: + description: key is the label + key that the selector applies + to. + type: string + operator: + description: |- + operator represents a key's relationship to a set of values. + Valid operators are In, NotIn, Exists and DoesNotExist. + type: string + values: + description: |- + values is an array of string values. If the operator is In or NotIn, + the values array must be non-empty. If the operator is Exists or DoesNotExist, + the values array must be empty. This array is replaced during a strategic + merge patch. + items: + type: string + type: array + x-kubernetes-list-type: atomic + required: + - key + - operator + type: object + type: array + x-kubernetes-list-type: atomic + matchLabels: + additionalProperties: + type: string + description: |- + matchLabels is a map of {key,value} pairs. A single {key,value} in the matchLabels + map is equivalent to an element of matchExpressions, whose key field is "key", the + operator is "In", and the values array contains only "value". The requirements are ANDed. + type: object + type: object + x-kubernetes-map-type: atomic + namespaces: + description: |- + namespaces specifies a static list of namespace names that the term applies to. + The term is applied to the union of the namespaces listed in this field + and the ones selected by namespaceSelector. + null or empty namespaces list and null namespaceSelector means "this pod's namespace". + items: + type: string + type: array + x-kubernetes-list-type: atomic + topologyKey: + description: |- + This pod should be co-located (affinity) or not co-located (anti-affinity) with the pods matching + the labelSelector in the specified namespaces, where co-located is defined as running on a node + whose value of the label with key topologyKey matches that of any node on which any of the + selected pods is running. + Empty topologyKey is not allowed. + type: string + required: + - topologyKey + type: object + weight: + description: |- + weight associated with matching the corresponding podAffinityTerm, + in the range 1-100. + format: int32 + type: integer + required: + - podAffinityTerm + - weight + type: object + type: array + x-kubernetes-list-type: atomic + requiredDuringSchedulingIgnoredDuringExecution: + description: |- + If the anti-affinity requirements specified by this field are not met at + scheduling time, the pod will not be scheduled onto the node. + If the anti-affinity requirements specified by this field cease to be met + at some point during pod execution (e.g. due to a pod label update), the + system may or may not try to eventually evict the pod from its node. + When there are multiple elements, the lists of nodes corresponding to each + podAffinityTerm are intersected, i.e. all terms must be satisfied. + items: + description: |- + Defines a set of pods (namely those matching the labelSelector + relative to the given namespace(s)) that this pod should be + co-located (affinity) or not co-located (anti-affinity) with, + where co-located is defined as running on a node whose value of + the label with key matches that of any node on which + a pod of the set of pods is running + properties: + labelSelector: + description: |- + A label query over a set of resources, in this case pods. + If it's null, this PodAffinityTerm matches with no Pods. + properties: + matchExpressions: + description: matchExpressions is a list + of label selector requirements. The requirements + are ANDed. + items: + description: |- + A label selector requirement is a selector that contains values, a key, and an operator that + relates the key and values. + properties: + key: + description: key is the label key + that the selector applies to. + type: string + operator: + description: |- + operator represents a key's relationship to a set of values. + Valid operators are In, NotIn, Exists and DoesNotExist. + type: string + values: + description: |- + values is an array of string values. If the operator is In or NotIn, + the values array must be non-empty. If the operator is Exists or DoesNotExist, + the values array must be empty. This array is replaced during a strategic + merge patch. + items: + type: string + type: array + x-kubernetes-list-type: atomic + required: + - key + - operator + type: object + type: array + x-kubernetes-list-type: atomic + matchLabels: + additionalProperties: + type: string + description: |- + matchLabels is a map of {key,value} pairs. A single {key,value} in the matchLabels + map is equivalent to an element of matchExpressions, whose key field is "key", the + operator is "In", and the values array contains only "value". The requirements are ANDed. + type: object + type: object + x-kubernetes-map-type: atomic + matchLabelKeys: + description: |- + MatchLabelKeys is a set of pod label keys to select which pods will + be taken into consideration. The keys are used to lookup values from the + incoming pod labels, those key-value labels are merged with `labelSelector` as `key in (value)` + to select the group of existing pods which pods will be taken into consideration + for the incoming pod's pod (anti) affinity. Keys that don't exist in the incoming + pod labels will be ignored. The default value is empty. + The same key is forbidden to exist in both matchLabelKeys and labelSelector. + Also, matchLabelKeys cannot be set when labelSelector isn't set. + items: + type: string + type: array + x-kubernetes-list-type: atomic + mismatchLabelKeys: + description: |- + MismatchLabelKeys is a set of pod label keys to select which pods will + be taken into consideration. The keys are used to lookup values from the + incoming pod labels, those key-value labels are merged with `labelSelector` as `key notin (value)` + to select the group of existing pods which pods will be taken into consideration + for the incoming pod's pod (anti) affinity. Keys that don't exist in the incoming + pod labels will be ignored. The default value is empty. + The same key is forbidden to exist in both mismatchLabelKeys and labelSelector. + Also, mismatchLabelKeys cannot be set when labelSelector isn't set. + items: + type: string + type: array + x-kubernetes-list-type: atomic + namespaceSelector: + description: |- + A label query over the set of namespaces that the term applies to. + The term is applied to the union of the namespaces selected by this field + and the ones listed in the namespaces field. + null selector and null or empty namespaces list means "this pod's namespace". + An empty selector ({}) matches all namespaces. + properties: + matchExpressions: + description: matchExpressions is a list + of label selector requirements. The requirements + are ANDed. + items: + description: |- + A label selector requirement is a selector that contains values, a key, and an operator that + relates the key and values. + properties: + key: + description: key is the label key + that the selector applies to. + type: string + operator: + description: |- + operator represents a key's relationship to a set of values. + Valid operators are In, NotIn, Exists and DoesNotExist. + type: string + values: + description: |- + values is an array of string values. If the operator is In or NotIn, + the values array must be non-empty. If the operator is Exists or DoesNotExist, + the values array must be empty. This array is replaced during a strategic + merge patch. + items: + type: string + type: array + x-kubernetes-list-type: atomic + required: + - key + - operator + type: object + type: array + x-kubernetes-list-type: atomic + matchLabels: + additionalProperties: + type: string + description: |- + matchLabels is a map of {key,value} pairs. A single {key,value} in the matchLabels + map is equivalent to an element of matchExpressions, whose key field is "key", the + operator is "In", and the values array contains only "value". The requirements are ANDed. + type: object + type: object + x-kubernetes-map-type: atomic + namespaces: + description: |- + namespaces specifies a static list of namespace names that the term applies to. + The term is applied to the union of the namespaces listed in this field + and the ones selected by namespaceSelector. + null or empty namespaces list and null namespaceSelector means "this pod's namespace". + items: + type: string + type: array + x-kubernetes-list-type: atomic + topologyKey: + description: |- + This pod should be co-located (affinity) or not co-located (anti-affinity) with the pods matching + the labelSelector in the specified namespaces, where co-located is defined as running on a node + whose value of the label with key topologyKey matches that of any node on which any of the + selected pods is running. + Empty topologyKey is not allowed. + type: string + required: + - topologyKey + type: object + type: array + x-kubernetes-list-type: atomic + type: object + type: object + nodeSelector: + additionalProperties: + type: string + description: |- + nodeSelector is the node selector applied to the relevant kind of pods + It specifies a map of key-value pairs: for the pod to be eligible to run on a node, + the node must have each of the indicated key-value pairs as labels + (it can have additional labels as well). + See https://kubernetes.io/docs/concepts/configuration/assign-pod-node/#nodeselector + type: object + tolerations: + description: |- + tolerations is a list of tolerations applied to the relevant kind of pods + See https://kubernetes.io/docs/concepts/configuration/taint-and-toleration/ for more info. + These are additional tolerations other than default ones. + items: + description: |- + The pod this Toleration is attached to tolerates any taint that matches + the triple using the matching operator . + properties: + effect: + description: |- + Effect indicates the taint effect to match. Empty means match all taint effects. + When specified, allowed values are NoSchedule, PreferNoSchedule and NoExecute. + type: string + key: + description: |- + Key is the taint key that the toleration applies to. Empty means match all taint keys. + If the key is empty, operator must be Exists; this combination means to match all values and all keys. + type: string + operator: + description: |- + Operator represents a key's relationship to the value. + Valid operators are Exists and Equal. Defaults to Equal. + Exists is equivalent to wildcard for value, so that a pod can + tolerate all taints of a particular category. + type: string + tolerationSeconds: + description: |- + TolerationSeconds represents the period of time the toleration (which must be + of effect NoExecute, otherwise this field is ignored) tolerates the taint. By default, + it is not set, which means tolerate the taint forever (do not evict). Zero and + negative values will be treated as 0 (evict immediately) by the system. + format: int64 + type: integer + value: + description: |- + Value is the taint value the toleration matches to. + If the operator is Exists, the value should be empty, otherwise just a regular string. + type: string + type: object + type: array + type: object + type: object + instancetypeConfig: + description: InstancetypeConfig holds the configuration of instance + type related functionality within KubeVirt. + properties: + referencePolicy: + description: |- + ReferencePolicy defines how an instance type or preference should be referenced by the VM after submission, supported values are: + reference (default) - Where a copy of the original object is stashed in a ControllerRevision and referenced by the VM. + expand - Where the instance type or preference are expanded into the VM if no revisionNames have been populated. + expandAll - Where the instance type or preference are expanded into the VM regardless of revisionNames previously being populated. + enum: + - reference + - expand + - expandAll + nullable: true + type: string + type: object + ksmConfiguration: + description: |- + KSMConfiguration holds the information regarding + the enabling the KSM in the nodes (if available). + properties: + nodeLabelSelector: + description: |- + NodeLabelSelector is a selector that filters in which nodes the KSM will be enabled. + Empty NodeLabelSelector will enable ksm for every node. + properties: + matchExpressions: + description: matchExpressions is a list of label selector + requirements. The requirements are ANDed. + items: + description: |- + A label selector requirement is a selector that contains values, a key, and an operator that + relates the key and values. + properties: + key: + description: key is the label key that the selector + applies to. + type: string + operator: + description: |- + operator represents a key's relationship to a set of values. + Valid operators are In, NotIn, Exists and DoesNotExist. + type: string + values: + description: |- + values is an array of string values. If the operator is In or NotIn, + the values array must be non-empty. If the operator is Exists or DoesNotExist, + the values array must be empty. This array is replaced during a strategic + merge patch. + items: + type: string + type: array + x-kubernetes-list-type: atomic + required: + - key + - operator + type: object + type: array + x-kubernetes-list-type: atomic + matchLabels: + additionalProperties: + type: string + description: |- + matchLabels is a map of {key,value} pairs. A single {key,value} in the matchLabels + map is equivalent to an element of matchExpressions, whose key field is "key", the + operator is "In", and the values array contains only "value". The requirements are ANDed. + type: object + type: object + x-kubernetes-map-type: atomic + type: object + kubeMacPoolConfiguration: + description: KubeMacPoolConfiguration holds kubemacpool MAC address + range configuration. + properties: + rangeEnd: + description: |- + RangeEnd defines the last MAC address in the kubemacpool range. + The MAC address format should be AA:BB:CC:DD:EE:FF. + pattern: ^([0-9a-fA-F]{2}:){5}[0-9a-fA-F]{2}$ + type: string + rangeStart: + description: |- + RangeStart defines the first MAC address in the kubemacpool range. + The MAC address format should be AA:BB:CC:DD:EE:FF. + pattern: ^([0-9a-fA-F]{2}:){5}[0-9a-fA-F]{2}$ + type: string + type: object + x-kubernetes-validations: + - message: both rangeStart and rangeEnd must be configured together, + or both omitted + rule: (has(self.rangeStart) && has(self.rangeEnd)) || (!has(self.rangeStart) + && !has(self.rangeEnd)) + kubeSecondaryDNSNameServerIP: + description: KubeSecondaryDNSNameServerIP defines name server IP used + by KubeSecondaryDNS + type: string + liveMigrationConfig: + default: + allowAutoConverge: false + allowPostCopy: false + completionTimeoutPerGiB: 150 + parallelMigrationsPerCluster: 5 + parallelOutboundMigrationsPerNode: 2 + progressTimeout: 150 + description: |- + Live migration limits and timeouts are applied so that migration processes do not + overwhelm the cluster. + properties: + allowAutoConverge: + default: false + description: |- + AllowAutoConverge allows the platform to compromise performance/availability of VMIs to + guarantee successful VMI live migrations. Defaults to false + type: boolean + allowPostCopy: + default: false + description: |- + When enabled, KubeVirt attempts to use post-copy live-migration in case it + reaches its completion timeout while attempting pre-copy live-migration. + Post-copy migrations allow even the busiest VMs to successfully live-migrate. + However, events like a network failure or a failure in any of the source or + destination nodes can cause the migrated VM to crash or reach inconsistency. + Enable this option when evicting nodes is more important than keeping VMs + alive. + Defaults to false. + type: boolean + bandwidthPerMigration: + description: Bandwidth limit of each migration, the value is quantity + of bytes per second (e.g. 2048Mi = 2048MiB/sec) + pattern: ^(\+|-)?(([0-9]+(\.[0-9]*)?)|(\.[0-9]+))(([KMGTPE]i)|[numkMGTPE]|([eE](\+|-)?(([0-9]+(\.[0-9]*)?)|(\.[0-9]+))))?$ + type: string + completionTimeoutPerGiB: + default: 150 + description: |- + If a migrating VM is big and busy, while the connection to the destination node + is slow, migration may never converge. The completion timeout is calculated + based on completionTimeoutPerGiB times the size of the guest (both RAM and + migrated disks, if any). For example, with completionTimeoutPerGiB set to 800, + a virtual machine instance with 6GiB memory will timeout if it has not + completed migration in 1h20m. Use a lower completionTimeoutPerGiB to induce + quicker failure, so that another destination or post-copy is attempted. Use a + higher completionTimeoutPerGiB to let workload with spikes in its memory dirty + rate to converge. + The format is a number. + format: int64 + type: integer + network: + description: The migrations will be performed over a dedicated + multus network to minimize disruption to tenant workloads due + to network saturation when VM live migrations are triggered. + type: string + parallelMigrationsPerCluster: + default: 5 + description: Number of migrations running in parallel in the cluster. + format: int32 + type: integer + parallelOutboundMigrationsPerNode: + default: 2 + description: Maximum number of outbound migrations per node. + format: int32 + type: integer + progressTimeout: + default: 150 + description: The migration will be canceled if memory copy fails + to make progress in this time, in seconds. + format: int64 + type: integer + type: object + liveUpdateConfiguration: + description: |- + LiveUpdateConfiguration holds the cluster configuration for live update of virtual machines - max cpu sockets, + max guest memory and max hotplug ratio. This setting can affect VM CPU and memory settings. + properties: + maxCpuSockets: + description: |- + MaxCpuSockets provides a MaxSockets value for VMs that do not provide their own. + For VMs with more sockets than maximum the MaxSockets will be set to equal number of sockets. + format: int32 + type: integer + maxGuest: + anyOf: + - type: integer + - type: string + description: |- + MaxGuest defines the maximum amount memory that can be allocated + to the guest using hotplug. + pattern: ^(\+|-)?(([0-9]+(\.[0-9]*)?)|(\.[0-9]+))(([KMGTPE]i)|[numkMGTPE]|([eE](\+|-)?(([0-9]+(\.[0-9]*)?)|(\.[0-9]+))))?$ + x-kubernetes-int-or-string: true + maxHotplugRatio: + description: |- + MaxHotplugRatio is the ratio used to define the max amount + of a hotplug resource that can be made available to a VM + when the specific Max* setting is not defined (MaxCpuSockets, MaxGuest) + Example: VM is configured with 512Mi of guest memory, if MaxGuest is not + defined and MaxHotplugRatio is 2 then MaxGuest = 1Gi + defaults to 4 + format: int32 + type: integer + type: object + logVerbosityConfig: + description: |- + LogVerbosityConfig configures the verbosity level of Kubevirt's different components. The higher + the value - the higher the log verbosity. + properties: + cdi: + description: CDI indicates the log verbosity level that controls + the amount of information logged for CDI components. + format: int32 + type: integer + kubevirt: + description: |- + Kubevirt is a struct that allows specifying the log verbosity level that controls the amount of information + logged for each Kubevirt component. + properties: + nodeVerbosity: + additionalProperties: + type: integer + description: NodeVerbosity represents a map of nodes with + a specific verbosity level + type: object + virtAPI: + type: integer + virtController: + type: integer + virtHandler: + type: integer + virtLauncher: + type: integer + virtOperator: + type: integer + virtSynchronizationController: + type: integer + type: object + type: object + mediatedDevicesConfiguration: + description: MediatedDevicesConfiguration holds information about + MDEV types to be defined on nodes, if available + properties: + mediatedDeviceTypes: + items: + type: string + type: array + x-kubernetes-list-type: atomic + nodeMediatedDeviceTypes: + items: + description: NodeMediatedDeviceTypesConfig holds information + about MDEV types to be defined in a specific node that matches + the NodeSelector field. + properties: + mediatedDeviceTypes: + items: + type: string + type: array + x-kubernetes-list-type: atomic + nodeSelector: + additionalProperties: + type: string + description: |- + NodeSelector is a selector which must be true for the vmi to fit on a node. + Selector which must match a node's labels for the vmi to be scheduled on that node. + More info: https://kubernetes.io/docs/concepts/configuration/assign-pod-node/ + type: object + required: + - nodeSelector + type: object + type: array + x-kubernetes-list-type: atomic + type: object + networkBinding: + additionalProperties: + properties: + computeResourceOverhead: + description: |- + ComputeResourceOverhead specifies the resource overhead that should be added to the compute container when using the binding. + version: v1alphav1 + properties: + limits: + additionalProperties: + anyOf: + - type: integer + - type: string + pattern: ^(\+|-)?(([0-9]+(\.[0-9]*)?)|(\.[0-9]+))(([KMGTPE]i)|[numkMGTPE]|([eE](\+|-)?(([0-9]+(\.[0-9]*)?)|(\.[0-9]+))))?$ + x-kubernetes-int-or-string: true + description: |- + Limits describes the maximum amount of compute resources allowed. + More info: https://kubernetes.io/docs/concepts/configuration/manage-resources-containers/ + type: object + requests: + additionalProperties: + anyOf: + - type: integer + - type: string + pattern: ^(\+|-)?(([0-9]+(\.[0-9]*)?)|(\.[0-9]+))(([KMGTPE]i)|[numkMGTPE]|([eE](\+|-)?(([0-9]+(\.[0-9]*)?)|(\.[0-9]+))))?$ + x-kubernetes-int-or-string: true + description: |- + Requests describes the minimum amount of compute resources required. + If Requests is omitted for a container, it defaults to Limits if that is explicitly specified, + otherwise to an implementation-defined value. Requests cannot exceed Limits. + More info: https://kubernetes.io/docs/concepts/configuration/manage-resources-containers/ + type: object + type: object + domainAttachmentType: + description: |- + DomainAttachmentType is a standard domain network attachment method kubevirt supports. + Supported values: "tap", "managedTap" (since v1.4). + The standard domain attachment can be used instead or in addition to the sidecarImage. + version: 1alphav1 + type: string + downwardAPI: + description: |- + DownwardAPI specifies what kind of data should be exposed to the binding plugin sidecar. + Supported values: "device-info" + version: v1alphav1 + type: string + migration: + description: |- + Migration means the VM using the plugin can be safely migrated + version: 1alphav1 + properties: + method: + description: |- + Method defines a pre-defined migration methodology + version: 1alphav1 + type: string + type: object + networkAttachmentDefinition: + description: |- + NetworkAttachmentDefinition references to a NetworkAttachmentDefinition CR object. + Format: , /. + If namespace is not specified, VMI namespace is assumed. + version: 1alphav1 + type: string + sidecarImage: + description: |- + SidecarImage references a container image that runs in the virt-launcher pod. + The sidecar handles (libvirt) domain configuration and optional services. + version: 1alphav1 + type: string + type: object + description: |- + NetworkBinding defines the network binding plugins. + Those bindings can be used when defining virtual machine interfaces. + type: object + obsoleteCPUs: + description: ObsoleteCPUs allows avoiding scheduling of VMs for obsolete + CPU models + properties: + cpuModels: + description: |- + CPUModels is a list of obsolete CPU models. When the node-labeller obtains the list of obsolete CPU models, it + eliminates those CPU models and creates labels for valid CPU models. + The default values for this field is nil, however, HCO uses opinionated values, and adding values to this list + will add them to the opinionated values. + items: + type: string + type: array + x-kubernetes-list-type: set + type: object + permittedHostDevices: + description: PermittedHostDevices holds information about devices + allowed for passthrough + properties: + mediatedDevices: + items: + description: MediatedHostDevice represents a host mediated device + allowed for passthrough + properties: + disabled: + description: |- + HCO enforces the existence of several MediatedHostDevice objects. Set disabled field to true instead of remove + these objects. + type: boolean + externalResourceProvider: + description: indicates that this resource is being provided + by an external device plugin + type: boolean + mdevNameSelector: + description: name of a mediated device type required to + identify a mediated device on a host + type: string + resourceName: + description: name by which a device is advertised and being + requested + type: string + required: + - mdevNameSelector + - resourceName + type: object + type: array + x-kubernetes-list-map-keys: + - mdevNameSelector + x-kubernetes-list-type: map + pciHostDevices: + items: + description: PciHostDevice represents a host PCI device allowed + for passthrough + properties: + disabled: + description: |- + HCO enforces the existence of several PciHostDevice objects. Set disabled field to true instead of remove + these objects. + type: boolean + externalResourceProvider: + description: indicates that this resource is being provided + by an external device plugin + type: boolean + pciDeviceSelector: + description: a combination of a vendor_id:product_id required + to identify a PCI device on a host. + type: string + resourceName: + description: name by which a device is advertised and being + requested + type: string + required: + - pciDeviceSelector + - resourceName + type: object + type: array + x-kubernetes-list-map-keys: + - pciDeviceSelector + x-kubernetes-list-type: map + usbHostDevices: + items: + description: USBHostDevice represents a host USB device allowed + for passthrough + properties: + disabled: + description: |- + HCO enforces the existence of several USBHostDevice objects. Set disabled field to true instead of remove + these objects. + type: boolean + externalResourceProvider: + description: |- + If true, KubeVirt will leave the allocation and monitoring to an + external device plugin + type: boolean + resourceName: + description: |- + Identifies the list of USB host devices. + e.g: kubevirt.io/storage, kubevirt.io/bootable-usb, etc + type: string + selectors: + items: + description: USBSelector represents a selector for a USB + device allowed for passthrough + properties: + product: + type: string + vendor: + type: string + required: + - product + - vendor + type: object + type: array + x-kubernetes-list-type: atomic + required: + - resourceName + type: object + type: array + x-kubernetes-list-map-keys: + - resourceName + x-kubernetes-list-type: map + type: object + resourceRequirements: + default: + vmiCPUAllocationRatio: 10 + description: ResourceRequirements describes the resource requirements + for the operand workloads. + properties: + autoCPULimitNamespaceLabelSelector: + description: |- + When set, AutoCPULimitNamespaceLabelSelector will set a CPU limit on virt-launcher for VMIs running inside + namespaces that match the label selector. + The CPU limit will equal the number of requested vCPUs. + This setting does not apply to VMIs with dedicated CPUs. + properties: + matchExpressions: + description: matchExpressions is a list of label selector + requirements. The requirements are ANDed. + items: + description: |- + A label selector requirement is a selector that contains values, a key, and an operator that + relates the key and values. + properties: + key: + description: key is the label key that the selector + applies to. + type: string + operator: + description: |- + operator represents a key's relationship to a set of values. + Valid operators are In, NotIn, Exists and DoesNotExist. + type: string + values: + description: |- + values is an array of string values. If the operator is In or NotIn, + the values array must be non-empty. If the operator is Exists or DoesNotExist, + the values array must be empty. This array is replaced during a strategic + merge patch. + items: + type: string + type: array + x-kubernetes-list-type: atomic + required: + - key + - operator + type: object + type: array + x-kubernetes-list-type: atomic + matchLabels: + additionalProperties: + type: string + description: |- + matchLabels is a map of {key,value} pairs. A single {key,value} in the matchLabels + map is equivalent to an element of matchExpressions, whose key field is "key", the + operator is "In", and the values array contains only "value". The requirements are ANDed. + type: object + type: object + x-kubernetes-map-type: atomic + storageWorkloads: + description: |- + StorageWorkloads defines the resources requirements for storage workloads. It will propagate to the CDI custom + resource + properties: + claims: + description: |- + Claims lists the names of resources, defined in spec.resourceClaims, + that are used by this container. + + This field depends on the + DynamicResourceAllocation feature gate. + + This field is immutable. It can only be set for containers. + items: + description: ResourceClaim references one entry in PodSpec.ResourceClaims. + properties: + name: + description: |- + Name must match the name of one entry in pod.spec.resourceClaims of + the Pod where this field is used. It makes that resource available + inside a container. + type: string + request: + description: |- + Request is the name chosen for a request in the referenced claim. + If empty, everything from the claim is made available, otherwise + only the result of this request. + type: string + required: + - name + type: object + type: array + x-kubernetes-list-map-keys: + - name + x-kubernetes-list-type: map + limits: + additionalProperties: + anyOf: + - type: integer + - type: string + pattern: ^(\+|-)?(([0-9]+(\.[0-9]*)?)|(\.[0-9]+))(([KMGTPE]i)|[numkMGTPE]|([eE](\+|-)?(([0-9]+(\.[0-9]*)?)|(\.[0-9]+))))?$ + x-kubernetes-int-or-string: true + description: |- + Limits describes the maximum amount of compute resources allowed. + More info: https://kubernetes.io/docs/concepts/configuration/manage-resources-containers/ + type: object + requests: + additionalProperties: + anyOf: + - type: integer + - type: string + pattern: ^(\+|-)?(([0-9]+(\.[0-9]*)?)|(\.[0-9]+))(([KMGTPE]i)|[numkMGTPE]|([eE](\+|-)?(([0-9]+(\.[0-9]*)?)|(\.[0-9]+))))?$ + x-kubernetes-int-or-string: true + description: |- + Requests describes the minimum amount of compute resources required. + If Requests is omitted for a container, it defaults to Limits if that is explicitly specified, + otherwise to an implementation-defined value. Requests cannot exceed Limits. + More info: https://kubernetes.io/docs/concepts/configuration/manage-resources-containers/ + type: object + type: object + vmiCPUAllocationRatio: + default: 10 + description: |- + VmiCPUAllocationRatio defines, for each requested virtual CPU, + how much physical CPU to request per VMI from the + hosting node. The value is in fraction of a CPU thread (or + core on non-hyperthreaded nodes). + VMI POD CPU request = number of vCPUs * 1/vmiCPUAllocationRatio + For example, a value of 1 means 1 physical CPU thread per VMI CPU thread. + A value of 100 would be 1% of a physical thread allocated for each + requested VMI thread. + This option has no effect on VMIs that request dedicated CPUs. + Defaults to 10 + minimum: 1 + type: integer + type: object + x-kubernetes-validations: + - message: vmiCPUAllocationRatio must be greater than 0 + rule: '!has(self.vmiCPUAllocationRatio) || self.vmiCPUAllocationRatio + > 0' + scratchSpaceStorageClass: + description: |- + Override the storage class used for scratch space during transfer operations. The scratch space storage class + is determined in the following order: + value of scratchSpaceStorageClass, if that doesn't exist, use the default storage class, if there is no default + storage class, use the storage class of the DataVolume, if no storage class specified, use no storage class for + scratch space + type: string + storageImport: + description: StorageImport contains configuration for importing containerized + data + properties: + insecureRegistries: + description: |- + InsecureRegistries is a list of image registries URLs that are not secured. Setting an insecure registry URL + in this list allows pulling images from this registry. + items: + type: string + type: array + x-kubernetes-list-type: set + type: object + tlsSecurityProfile: + description: |- + TLSSecurityProfile specifies the settings for TLS connections to be propagated to all kubevirt-hyperconverged components. + If unset, the hyperconverged cluster operator will consume the value set on the APIServer CR on OCP/OKD or Intermediate if on vanilla k8s. + Note that only Old, Intermediate and Custom profiles are currently supported, and the maximum available + MinTLSVersions is VersionTLS12. + properties: + custom: + description: |- + custom is a user-defined TLS security profile. Be extremely careful using a custom + profile as invalid configurations can be catastrophic. An example custom profile + looks like this: + + ciphers: + + - ECDHE-ECDSA-CHACHA20-POLY1305 + + - ECDHE-RSA-CHACHA20-POLY1305 + + - ECDHE-RSA-AES128-GCM-SHA256 + + - ECDHE-ECDSA-AES128-GCM-SHA256 + + minTLSVersion: VersionTLS11 + nullable: true + properties: + ciphers: + description: |- + ciphers is used to specify the cipher algorithms that are negotiated + during the TLS handshake. Operators may remove entries their operands + do not support. For example, to use DES-CBC3-SHA (yaml): + + ciphers: + - DES-CBC3-SHA + items: + type: string + type: array + x-kubernetes-list-type: atomic + minTLSVersion: + description: |- + minTLSVersion is used to specify the minimal version of the TLS protocol + that is negotiated during the TLS handshake. For example, to use TLS + versions 1.1, 1.2 and 1.3 (yaml): + + minTLSVersion: VersionTLS11 + + NOTE: currently the highest minTLSVersion allowed is VersionTLS12 + enum: + - VersionTLS10 + - VersionTLS11 + - VersionTLS12 + - VersionTLS13 + type: string + type: object + intermediate: + description: |- + intermediate is a TLS security profile based on: + + https://wiki.mozilla.org/Security/Server_Side_TLS#Intermediate_compatibility_.28recommended.29 + + and looks like this (yaml): + + ciphers: + + - TLS_AES_128_GCM_SHA256 + + - TLS_AES_256_GCM_SHA384 + + - TLS_CHACHA20_POLY1305_SHA256 + + - ECDHE-ECDSA-AES128-GCM-SHA256 + + - ECDHE-RSA-AES128-GCM-SHA256 + + - ECDHE-ECDSA-AES256-GCM-SHA384 + + - ECDHE-RSA-AES256-GCM-SHA384 + + - ECDHE-ECDSA-CHACHA20-POLY1305 + + - ECDHE-RSA-CHACHA20-POLY1305 + + - DHE-RSA-AES128-GCM-SHA256 + + - DHE-RSA-AES256-GCM-SHA384 + + minTLSVersion: VersionTLS12 + nullable: true + type: object + modern: + description: |- + modern is a TLS security profile based on: + + https://wiki.mozilla.org/Security/Server_Side_TLS#Modern_compatibility + + and looks like this (yaml): + + ciphers: + + - TLS_AES_128_GCM_SHA256 + + - TLS_AES_256_GCM_SHA384 + + - TLS_CHACHA20_POLY1305_SHA256 + + minTLSVersion: VersionTLS13 + nullable: true + type: object + old: + description: |- + old is a TLS security profile based on: + + https://wiki.mozilla.org/Security/Server_Side_TLS#Old_backward_compatibility + + and looks like this (yaml): + + ciphers: + + - TLS_AES_128_GCM_SHA256 + + - TLS_AES_256_GCM_SHA384 + + - TLS_CHACHA20_POLY1305_SHA256 + + - ECDHE-ECDSA-AES128-GCM-SHA256 + + - ECDHE-RSA-AES128-GCM-SHA256 + + - ECDHE-ECDSA-AES256-GCM-SHA384 + + - ECDHE-RSA-AES256-GCM-SHA384 + + - ECDHE-ECDSA-CHACHA20-POLY1305 + + - ECDHE-RSA-CHACHA20-POLY1305 + + - DHE-RSA-AES128-GCM-SHA256 + + - DHE-RSA-AES256-GCM-SHA384 + + - DHE-RSA-CHACHA20-POLY1305 + + - ECDHE-ECDSA-AES128-SHA256 + + - ECDHE-RSA-AES128-SHA256 + + - ECDHE-ECDSA-AES128-SHA + + - ECDHE-RSA-AES128-SHA + + - ECDHE-ECDSA-AES256-SHA384 + + - ECDHE-RSA-AES256-SHA384 + + - ECDHE-ECDSA-AES256-SHA + + - ECDHE-RSA-AES256-SHA + + - DHE-RSA-AES128-SHA256 + + - DHE-RSA-AES256-SHA256 + + - AES128-GCM-SHA256 + + - AES256-GCM-SHA384 + + - AES128-SHA256 + + - AES256-SHA256 + + - AES128-SHA + + - AES256-SHA + + - DES-CBC3-SHA + + minTLSVersion: VersionTLS10 + nullable: true + type: object + type: + description: |- + type is one of Old, Intermediate, Modern or Custom. Custom provides + the ability to specify individual TLS security profile parameters. + Old, Intermediate and Modern are TLS security profiles based on: + + https://wiki.mozilla.org/Security/Server_Side_TLS#Recommended_configurations + + The profiles are intent based, so they may change over time as new ciphers are developed and existing ciphers + are found to be insecure. Depending on precisely which ciphers are available to a process, the list may be + reduced. + + Note that the Modern profile is currently not supported because it is not + yet well adopted by common software libraries. + enum: + - Old + - Intermediate + - Modern + - Custom + type: string + type: object + tuningPolicy: + description: |- + TuningPolicy allows to configure the mode in which the RateLimits of kubevirt are set. + If TuningPolicy is not present the default kubevirt values are used. + It can be set to `annotation` for fine-tuning the kubevirt queryPerSeconds (qps) and burst values. + Qps and burst values are taken from the annotation hco.kubevirt.io/tuningPolicy + enum: + - annotation + - highBurst + type: string + uninstallStrategy: + default: BlockUninstallIfWorkloadsExist + description: |- + UninstallStrategy defines how to proceed on uninstall when workloads (VirtualMachines, DataVolumes) still exist. + BlockUninstallIfWorkloadsExist will prevent the CR from being removed when workloads still exist. + BlockUninstallIfWorkloadsExist is the safest choice to protect your workloads from accidental data loss, so it's strongly advised. + RemoveWorkloads will cause all the workloads to be cascading deleted on uninstallation. + WARNING: please notice that RemoveWorkloads will cause your workloads to be deleted as soon as this CR will be, even accidentally, deleted. + Please correctly consider the implications of this option before setting it. + BlockUninstallIfWorkloadsExist is the default behaviour. + enum: + - RemoveWorkloads + - BlockUninstallIfWorkloadsExist + type: string + virtualMachineOptions: + default: + disableFreePageReporting: false + disableSerialConsoleLog: false + description: VirtualMachineOptions holds the cluster level information + regarding the virtual machine. + properties: + disableFreePageReporting: + default: false + description: |- + DisableFreePageReporting disable the free page reporting of + memory balloon device https://libvirt.org/formatdomain.html#memory-balloon-device. + This will have effect only if AutoattachMemBalloon is not false and the vmi is not + requesting any high performance feature (dedicatedCPU/realtime/hugePages), in which free page reporting is always disabled. + type: boolean + disableSerialConsoleLog: + default: false + description: |- + DisableSerialConsoleLog disables logging the auto-attached default serial console. + If not set, serial console logs will be written to a file and then streamed from a container named `guest-console-log`. + The value can be individually overridden for each VM, not relevant if AutoattachSerialConsole is disabled for the VM. + type: boolean + type: object + vmStateStorageClass: + description: VMStateStorageClass is the name of the storage class + to use for the PVCs created to preserve VM state, like TPM. + type: string + workloadUpdateStrategy: + default: + batchEvictionInterval: 1m0s + batchEvictionSize: 10 + workloadUpdateMethods: + - LiveMigrate + description: WorkloadUpdateStrategy defines at the cluster level how + to handle automated workload updates + properties: + batchEvictionInterval: + default: 1m0s + description: |- + BatchEvictionInterval Represents the interval to wait before issuing the next + batch of shutdowns + type: string + batchEvictionSize: + default: 10 + description: |- + BatchEvictionSize Represents the number of VMIs that can be forced updated per + the BatchShutdownInterval interval + type: integer + workloadUpdateMethods: + default: + - LiveMigrate + description: |- + WorkloadUpdateMethods defines the methods that can be used to disrupt workloads + during automated workload updates. + When multiple methods are present, the least disruptive method takes + precedence over more disruptive methods. For example if both LiveMigrate and Evict + methods are listed, only VMs which are not live migratable will be restarted/shutdown. + An empty list defaults to no automated workload updating. + items: + type: string + type: array + x-kubernetes-list-type: atomic + required: + - workloadUpdateMethods + type: object + workloads: + description: |- + workloads HyperConvergedConfig influences the pod configuration (currently only placement) of components + which need to be running on a node where virtualization workloads should be able to run. + Changes to Workloads HyperConvergedConfig can be applied only without existing workload. + properties: + nodePlacement: + description: NodePlacement describes node scheduling configuration. + properties: + affinity: + description: |- + affinity enables pod affinity/anti-affinity placement expanding the types of constraints + that can be expressed with nodeSelector. + affinity is going to be applied to the relevant kind of pods in parallel with nodeSelector + See https://kubernetes.io/docs/concepts/scheduling-eviction/assign-pod-node/#affinity-and-anti-affinity + properties: + nodeAffinity: + description: Describes node affinity scheduling rules + for the pod. + properties: + preferredDuringSchedulingIgnoredDuringExecution: + description: |- + The scheduler will prefer to schedule pods to nodes that satisfy + the affinity expressions specified by this field, but it may choose + a node that violates one or more of the expressions. The node that is + most preferred is the one with the greatest sum of weights, i.e. + for each node that meets all of the scheduling requirements (resource + request, requiredDuringScheduling affinity expressions, etc.), + compute a sum by iterating through the elements of this field and adding + "weight" to the sum if the node matches the corresponding matchExpressions; the + node(s) with the highest sum are the most preferred. + items: + description: |- + An empty preferred scheduling term matches all objects with implicit weight 0 + (i.e. it's a no-op). A null preferred scheduling term matches no objects (i.e. is also a no-op). + properties: + preference: + description: A node selector term, associated + with the corresponding weight. + properties: + matchExpressions: + description: A list of node selector requirements + by node's labels. + items: + description: |- + A node selector requirement is a selector that contains values, a key, and an operator + that relates the key and values. + properties: + key: + description: The label key that the + selector applies to. + type: string + operator: + description: |- + Represents a key's relationship to a set of values. + Valid operators are In, NotIn, Exists, DoesNotExist. Gt, and Lt. + type: string + values: + description: |- + An array of string values. If the operator is In or NotIn, + the values array must be non-empty. If the operator is Exists or DoesNotExist, + the values array must be empty. If the operator is Gt or Lt, the values + array must have a single element, which will be interpreted as an integer. + This array is replaced during a strategic merge patch. + items: + type: string + type: array + x-kubernetes-list-type: atomic + required: + - key + - operator + type: object + type: array + x-kubernetes-list-type: atomic + matchFields: + description: A list of node selector requirements + by node's fields. + items: + description: |- + A node selector requirement is a selector that contains values, a key, and an operator + that relates the key and values. + properties: + key: + description: The label key that the + selector applies to. + type: string + operator: + description: |- + Represents a key's relationship to a set of values. + Valid operators are In, NotIn, Exists, DoesNotExist. Gt, and Lt. + type: string + values: + description: |- + An array of string values. If the operator is In or NotIn, + the values array must be non-empty. If the operator is Exists or DoesNotExist, + the values array must be empty. If the operator is Gt or Lt, the values + array must have a single element, which will be interpreted as an integer. + This array is replaced during a strategic merge patch. + items: + type: string + type: array + x-kubernetes-list-type: atomic + required: + - key + - operator + type: object + type: array + x-kubernetes-list-type: atomic + type: object + x-kubernetes-map-type: atomic + weight: + description: Weight associated with matching + the corresponding nodeSelectorTerm, in the + range 1-100. + format: int32 + type: integer + required: + - preference + - weight + type: object + type: array + x-kubernetes-list-type: atomic + requiredDuringSchedulingIgnoredDuringExecution: + description: |- + If the affinity requirements specified by this field are not met at + scheduling time, the pod will not be scheduled onto the node. + If the affinity requirements specified by this field cease to be met + at some point during pod execution (e.g. due to an update), the system + may or may not try to eventually evict the pod from its node. + properties: + nodeSelectorTerms: + description: Required. A list of node selector + terms. The terms are ORed. + items: + description: |- + A null or empty node selector term matches no objects. The requirements of + them are ANDed. + The TopologySelectorTerm type implements a subset of the NodeSelectorTerm. + properties: + matchExpressions: + description: A list of node selector requirements + by node's labels. + items: + description: |- + A node selector requirement is a selector that contains values, a key, and an operator + that relates the key and values. + properties: + key: + description: The label key that the + selector applies to. + type: string + operator: + description: |- + Represents a key's relationship to a set of values. + Valid operators are In, NotIn, Exists, DoesNotExist. Gt, and Lt. + type: string + values: + description: |- + An array of string values. If the operator is In or NotIn, + the values array must be non-empty. If the operator is Exists or DoesNotExist, + the values array must be empty. If the operator is Gt or Lt, the values + array must have a single element, which will be interpreted as an integer. + This array is replaced during a strategic merge patch. + items: + type: string + type: array + x-kubernetes-list-type: atomic + required: + - key + - operator + type: object + type: array + x-kubernetes-list-type: atomic + matchFields: + description: A list of node selector requirements + by node's fields. + items: + description: |- + A node selector requirement is a selector that contains values, a key, and an operator + that relates the key and values. + properties: + key: + description: The label key that the + selector applies to. + type: string + operator: + description: |- + Represents a key's relationship to a set of values. + Valid operators are In, NotIn, Exists, DoesNotExist. Gt, and Lt. + type: string + values: + description: |- + An array of string values. If the operator is In or NotIn, + the values array must be non-empty. If the operator is Exists or DoesNotExist, + the values array must be empty. If the operator is Gt or Lt, the values + array must have a single element, which will be interpreted as an integer. + This array is replaced during a strategic merge patch. + items: + type: string + type: array + x-kubernetes-list-type: atomic + required: + - key + - operator + type: object + type: array + x-kubernetes-list-type: atomic + type: object + x-kubernetes-map-type: atomic + type: array + x-kubernetes-list-type: atomic + required: + - nodeSelectorTerms + type: object + x-kubernetes-map-type: atomic + type: object + podAffinity: + description: Describes pod affinity scheduling rules (e.g. + co-locate this pod in the same node, zone, etc. as some + other pod(s)). + properties: + preferredDuringSchedulingIgnoredDuringExecution: + description: |- + The scheduler will prefer to schedule pods to nodes that satisfy + the affinity expressions specified by this field, but it may choose + a node that violates one or more of the expressions. The node that is + most preferred is the one with the greatest sum of weights, i.e. + for each node that meets all of the scheduling requirements (resource + request, requiredDuringScheduling affinity expressions, etc.), + compute a sum by iterating through the elements of this field and adding + "weight" to the sum if the node has pods which matches the corresponding podAffinityTerm; the + node(s) with the highest sum are the most preferred. + items: + description: The weights of all of the matched WeightedPodAffinityTerm + fields are added per-node to find the most preferred + node(s) + properties: + podAffinityTerm: + description: Required. A pod affinity term, + associated with the corresponding weight. + properties: + labelSelector: + description: |- + A label query over a set of resources, in this case pods. + If it's null, this PodAffinityTerm matches with no Pods. + properties: + matchExpressions: + description: matchExpressions is a list + of label selector requirements. The + requirements are ANDed. + items: + description: |- + A label selector requirement is a selector that contains values, a key, and an operator that + relates the key and values. + properties: + key: + description: key is the label + key that the selector applies + to. + type: string + operator: + description: |- + operator represents a key's relationship to a set of values. + Valid operators are In, NotIn, Exists and DoesNotExist. + type: string + values: + description: |- + values is an array of string values. If the operator is In or NotIn, + the values array must be non-empty. If the operator is Exists or DoesNotExist, + the values array must be empty. This array is replaced during a strategic + merge patch. + items: + type: string + type: array + x-kubernetes-list-type: atomic + required: + - key + - operator + type: object + type: array + x-kubernetes-list-type: atomic + matchLabels: + additionalProperties: + type: string + description: |- + matchLabels is a map of {key,value} pairs. A single {key,value} in the matchLabels + map is equivalent to an element of matchExpressions, whose key field is "key", the + operator is "In", and the values array contains only "value". The requirements are ANDed. + type: object + type: object + x-kubernetes-map-type: atomic + matchLabelKeys: + description: |- + MatchLabelKeys is a set of pod label keys to select which pods will + be taken into consideration. The keys are used to lookup values from the + incoming pod labels, those key-value labels are merged with `labelSelector` as `key in (value)` + to select the group of existing pods which pods will be taken into consideration + for the incoming pod's pod (anti) affinity. Keys that don't exist in the incoming + pod labels will be ignored. The default value is empty. + The same key is forbidden to exist in both matchLabelKeys and labelSelector. + Also, matchLabelKeys cannot be set when labelSelector isn't set. + items: + type: string + type: array + x-kubernetes-list-type: atomic + mismatchLabelKeys: + description: |- + MismatchLabelKeys is a set of pod label keys to select which pods will + be taken into consideration. The keys are used to lookup values from the + incoming pod labels, those key-value labels are merged with `labelSelector` as `key notin (value)` + to select the group of existing pods which pods will be taken into consideration + for the incoming pod's pod (anti) affinity. Keys that don't exist in the incoming + pod labels will be ignored. The default value is empty. + The same key is forbidden to exist in both mismatchLabelKeys and labelSelector. + Also, mismatchLabelKeys cannot be set when labelSelector isn't set. + items: + type: string + type: array + x-kubernetes-list-type: atomic + namespaceSelector: + description: |- + A label query over the set of namespaces that the term applies to. + The term is applied to the union of the namespaces selected by this field + and the ones listed in the namespaces field. + null selector and null or empty namespaces list means "this pod's namespace". + An empty selector ({}) matches all namespaces. + properties: + matchExpressions: + description: matchExpressions is a list + of label selector requirements. The + requirements are ANDed. + items: + description: |- + A label selector requirement is a selector that contains values, a key, and an operator that + relates the key and values. + properties: + key: + description: key is the label + key that the selector applies + to. + type: string + operator: + description: |- + operator represents a key's relationship to a set of values. + Valid operators are In, NotIn, Exists and DoesNotExist. + type: string + values: + description: |- + values is an array of string values. If the operator is In or NotIn, + the values array must be non-empty. If the operator is Exists or DoesNotExist, + the values array must be empty. This array is replaced during a strategic + merge patch. + items: + type: string + type: array + x-kubernetes-list-type: atomic + required: + - key + - operator + type: object + type: array + x-kubernetes-list-type: atomic + matchLabels: + additionalProperties: + type: string + description: |- + matchLabels is a map of {key,value} pairs. A single {key,value} in the matchLabels + map is equivalent to an element of matchExpressions, whose key field is "key", the + operator is "In", and the values array contains only "value". The requirements are ANDed. + type: object + type: object + x-kubernetes-map-type: atomic + namespaces: + description: |- + namespaces specifies a static list of namespace names that the term applies to. + The term is applied to the union of the namespaces listed in this field + and the ones selected by namespaceSelector. + null or empty namespaces list and null namespaceSelector means "this pod's namespace". + items: + type: string + type: array + x-kubernetes-list-type: atomic + topologyKey: + description: |- + This pod should be co-located (affinity) or not co-located (anti-affinity) with the pods matching + the labelSelector in the specified namespaces, where co-located is defined as running on a node + whose value of the label with key topologyKey matches that of any node on which any of the + selected pods is running. + Empty topologyKey is not allowed. + type: string + required: + - topologyKey + type: object + weight: + description: |- + weight associated with matching the corresponding podAffinityTerm, + in the range 1-100. + format: int32 + type: integer + required: + - podAffinityTerm + - weight + type: object + type: array + x-kubernetes-list-type: atomic + requiredDuringSchedulingIgnoredDuringExecution: + description: |- + If the affinity requirements specified by this field are not met at + scheduling time, the pod will not be scheduled onto the node. + If the affinity requirements specified by this field cease to be met + at some point during pod execution (e.g. due to a pod label update), the + system may or may not try to eventually evict the pod from its node. + When there are multiple elements, the lists of nodes corresponding to each + podAffinityTerm are intersected, i.e. all terms must be satisfied. + items: + description: |- + Defines a set of pods (namely those matching the labelSelector + relative to the given namespace(s)) that this pod should be + co-located (affinity) or not co-located (anti-affinity) with, + where co-located is defined as running on a node whose value of + the label with key matches that of any node on which + a pod of the set of pods is running + properties: + labelSelector: + description: |- + A label query over a set of resources, in this case pods. + If it's null, this PodAffinityTerm matches with no Pods. + properties: + matchExpressions: + description: matchExpressions is a list + of label selector requirements. The requirements + are ANDed. + items: + description: |- + A label selector requirement is a selector that contains values, a key, and an operator that + relates the key and values. + properties: + key: + description: key is the label key + that the selector applies to. + type: string + operator: + description: |- + operator represents a key's relationship to a set of values. + Valid operators are In, NotIn, Exists and DoesNotExist. + type: string + values: + description: |- + values is an array of string values. If the operator is In or NotIn, + the values array must be non-empty. If the operator is Exists or DoesNotExist, + the values array must be empty. This array is replaced during a strategic + merge patch. + items: + type: string + type: array + x-kubernetes-list-type: atomic + required: + - key + - operator + type: object + type: array + x-kubernetes-list-type: atomic + matchLabels: + additionalProperties: + type: string + description: |- + matchLabels is a map of {key,value} pairs. A single {key,value} in the matchLabels + map is equivalent to an element of matchExpressions, whose key field is "key", the + operator is "In", and the values array contains only "value". The requirements are ANDed. + type: object + type: object + x-kubernetes-map-type: atomic + matchLabelKeys: + description: |- + MatchLabelKeys is a set of pod label keys to select which pods will + be taken into consideration. The keys are used to lookup values from the + incoming pod labels, those key-value labels are merged with `labelSelector` as `key in (value)` + to select the group of existing pods which pods will be taken into consideration + for the incoming pod's pod (anti) affinity. Keys that don't exist in the incoming + pod labels will be ignored. The default value is empty. + The same key is forbidden to exist in both matchLabelKeys and labelSelector. + Also, matchLabelKeys cannot be set when labelSelector isn't set. + items: + type: string + type: array + x-kubernetes-list-type: atomic + mismatchLabelKeys: + description: |- + MismatchLabelKeys is a set of pod label keys to select which pods will + be taken into consideration. The keys are used to lookup values from the + incoming pod labels, those key-value labels are merged with `labelSelector` as `key notin (value)` + to select the group of existing pods which pods will be taken into consideration + for the incoming pod's pod (anti) affinity. Keys that don't exist in the incoming + pod labels will be ignored. The default value is empty. + The same key is forbidden to exist in both mismatchLabelKeys and labelSelector. + Also, mismatchLabelKeys cannot be set when labelSelector isn't set. + items: + type: string + type: array + x-kubernetes-list-type: atomic + namespaceSelector: + description: |- + A label query over the set of namespaces that the term applies to. + The term is applied to the union of the namespaces selected by this field + and the ones listed in the namespaces field. + null selector and null or empty namespaces list means "this pod's namespace". + An empty selector ({}) matches all namespaces. + properties: + matchExpressions: + description: matchExpressions is a list + of label selector requirements. The requirements + are ANDed. + items: + description: |- + A label selector requirement is a selector that contains values, a key, and an operator that + relates the key and values. + properties: + key: + description: key is the label key + that the selector applies to. + type: string + operator: + description: |- + operator represents a key's relationship to a set of values. + Valid operators are In, NotIn, Exists and DoesNotExist. + type: string + values: + description: |- + values is an array of string values. If the operator is In or NotIn, + the values array must be non-empty. If the operator is Exists or DoesNotExist, + the values array must be empty. This array is replaced during a strategic + merge patch. + items: + type: string + type: array + x-kubernetes-list-type: atomic + required: + - key + - operator + type: object + type: array + x-kubernetes-list-type: atomic + matchLabels: + additionalProperties: + type: string + description: |- + matchLabels is a map of {key,value} pairs. A single {key,value} in the matchLabels + map is equivalent to an element of matchExpressions, whose key field is "key", the + operator is "In", and the values array contains only "value". The requirements are ANDed. + type: object + type: object + x-kubernetes-map-type: atomic + namespaces: + description: |- + namespaces specifies a static list of namespace names that the term applies to. + The term is applied to the union of the namespaces listed in this field + and the ones selected by namespaceSelector. + null or empty namespaces list and null namespaceSelector means "this pod's namespace". + items: + type: string + type: array + x-kubernetes-list-type: atomic + topologyKey: + description: |- + This pod should be co-located (affinity) or not co-located (anti-affinity) with the pods matching + the labelSelector in the specified namespaces, where co-located is defined as running on a node + whose value of the label with key topologyKey matches that of any node on which any of the + selected pods is running. + Empty topologyKey is not allowed. + type: string + required: + - topologyKey + type: object + type: array + x-kubernetes-list-type: atomic + type: object + podAntiAffinity: + description: Describes pod anti-affinity scheduling rules + (e.g. avoid putting this pod in the same node, zone, + etc. as some other pod(s)). + properties: + preferredDuringSchedulingIgnoredDuringExecution: + description: |- + The scheduler will prefer to schedule pods to nodes that satisfy + the anti-affinity expressions specified by this field, but it may choose + a node that violates one or more of the expressions. The node that is + most preferred is the one with the greatest sum of weights, i.e. + for each node that meets all of the scheduling requirements (resource + request, requiredDuringScheduling anti-affinity expressions, etc.), + compute a sum by iterating through the elements of this field and subtracting + "weight" from the sum if the node has pods which matches the corresponding podAffinityTerm; the + node(s) with the highest sum are the most preferred. + items: + description: The weights of all of the matched WeightedPodAffinityTerm + fields are added per-node to find the most preferred + node(s) + properties: + podAffinityTerm: + description: Required. A pod affinity term, + associated with the corresponding weight. + properties: + labelSelector: + description: |- + A label query over a set of resources, in this case pods. + If it's null, this PodAffinityTerm matches with no Pods. + properties: + matchExpressions: + description: matchExpressions is a list + of label selector requirements. The + requirements are ANDed. + items: + description: |- + A label selector requirement is a selector that contains values, a key, and an operator that + relates the key and values. + properties: + key: + description: key is the label + key that the selector applies + to. + type: string + operator: + description: |- + operator represents a key's relationship to a set of values. + Valid operators are In, NotIn, Exists and DoesNotExist. + type: string + values: + description: |- + values is an array of string values. If the operator is In or NotIn, + the values array must be non-empty. If the operator is Exists or DoesNotExist, + the values array must be empty. This array is replaced during a strategic + merge patch. + items: + type: string + type: array + x-kubernetes-list-type: atomic + required: + - key + - operator + type: object + type: array + x-kubernetes-list-type: atomic + matchLabels: + additionalProperties: + type: string + description: |- + matchLabels is a map of {key,value} pairs. A single {key,value} in the matchLabels + map is equivalent to an element of matchExpressions, whose key field is "key", the + operator is "In", and the values array contains only "value". The requirements are ANDed. + type: object + type: object + x-kubernetes-map-type: atomic + matchLabelKeys: + description: |- + MatchLabelKeys is a set of pod label keys to select which pods will + be taken into consideration. The keys are used to lookup values from the + incoming pod labels, those key-value labels are merged with `labelSelector` as `key in (value)` + to select the group of existing pods which pods will be taken into consideration + for the incoming pod's pod (anti) affinity. Keys that don't exist in the incoming + pod labels will be ignored. The default value is empty. + The same key is forbidden to exist in both matchLabelKeys and labelSelector. + Also, matchLabelKeys cannot be set when labelSelector isn't set. + items: + type: string + type: array + x-kubernetes-list-type: atomic + mismatchLabelKeys: + description: |- + MismatchLabelKeys is a set of pod label keys to select which pods will + be taken into consideration. The keys are used to lookup values from the + incoming pod labels, those key-value labels are merged with `labelSelector` as `key notin (value)` + to select the group of existing pods which pods will be taken into consideration + for the incoming pod's pod (anti) affinity. Keys that don't exist in the incoming + pod labels will be ignored. The default value is empty. + The same key is forbidden to exist in both mismatchLabelKeys and labelSelector. + Also, mismatchLabelKeys cannot be set when labelSelector isn't set. + items: + type: string + type: array + x-kubernetes-list-type: atomic + namespaceSelector: + description: |- + A label query over the set of namespaces that the term applies to. + The term is applied to the union of the namespaces selected by this field + and the ones listed in the namespaces field. + null selector and null or empty namespaces list means "this pod's namespace". + An empty selector ({}) matches all namespaces. + properties: + matchExpressions: + description: matchExpressions is a list + of label selector requirements. The + requirements are ANDed. + items: + description: |- + A label selector requirement is a selector that contains values, a key, and an operator that + relates the key and values. + properties: + key: + description: key is the label + key that the selector applies + to. + type: string + operator: + description: |- + operator represents a key's relationship to a set of values. + Valid operators are In, NotIn, Exists and DoesNotExist. + type: string + values: + description: |- + values is an array of string values. If the operator is In or NotIn, + the values array must be non-empty. If the operator is Exists or DoesNotExist, + the values array must be empty. This array is replaced during a strategic + merge patch. + items: + type: string + type: array + x-kubernetes-list-type: atomic + required: + - key + - operator + type: object + type: array + x-kubernetes-list-type: atomic + matchLabels: + additionalProperties: + type: string + description: |- + matchLabels is a map of {key,value} pairs. A single {key,value} in the matchLabels + map is equivalent to an element of matchExpressions, whose key field is "key", the + operator is "In", and the values array contains only "value". The requirements are ANDed. + type: object + type: object + x-kubernetes-map-type: atomic + namespaces: + description: |- + namespaces specifies a static list of namespace names that the term applies to. + The term is applied to the union of the namespaces listed in this field + and the ones selected by namespaceSelector. + null or empty namespaces list and null namespaceSelector means "this pod's namespace". + items: + type: string + type: array + x-kubernetes-list-type: atomic + topologyKey: + description: |- + This pod should be co-located (affinity) or not co-located (anti-affinity) with the pods matching + the labelSelector in the specified namespaces, where co-located is defined as running on a node + whose value of the label with key topologyKey matches that of any node on which any of the + selected pods is running. + Empty topologyKey is not allowed. + type: string + required: + - topologyKey + type: object + weight: + description: |- + weight associated with matching the corresponding podAffinityTerm, + in the range 1-100. + format: int32 + type: integer + required: + - podAffinityTerm + - weight + type: object + type: array + x-kubernetes-list-type: atomic + requiredDuringSchedulingIgnoredDuringExecution: + description: |- + If the anti-affinity requirements specified by this field are not met at + scheduling time, the pod will not be scheduled onto the node. + If the anti-affinity requirements specified by this field cease to be met + at some point during pod execution (e.g. due to a pod label update), the + system may or may not try to eventually evict the pod from its node. + When there are multiple elements, the lists of nodes corresponding to each + podAffinityTerm are intersected, i.e. all terms must be satisfied. + items: + description: |- + Defines a set of pods (namely those matching the labelSelector + relative to the given namespace(s)) that this pod should be + co-located (affinity) or not co-located (anti-affinity) with, + where co-located is defined as running on a node whose value of + the label with key matches that of any node on which + a pod of the set of pods is running + properties: + labelSelector: + description: |- + A label query over a set of resources, in this case pods. + If it's null, this PodAffinityTerm matches with no Pods. + properties: + matchExpressions: + description: matchExpressions is a list + of label selector requirements. The requirements + are ANDed. + items: + description: |- + A label selector requirement is a selector that contains values, a key, and an operator that + relates the key and values. + properties: + key: + description: key is the label key + that the selector applies to. + type: string + operator: + description: |- + operator represents a key's relationship to a set of values. + Valid operators are In, NotIn, Exists and DoesNotExist. + type: string + values: + description: |- + values is an array of string values. If the operator is In or NotIn, + the values array must be non-empty. If the operator is Exists or DoesNotExist, + the values array must be empty. This array is replaced during a strategic + merge patch. + items: + type: string + type: array + x-kubernetes-list-type: atomic + required: + - key + - operator + type: object + type: array + x-kubernetes-list-type: atomic + matchLabels: + additionalProperties: + type: string + description: |- + matchLabels is a map of {key,value} pairs. A single {key,value} in the matchLabels + map is equivalent to an element of matchExpressions, whose key field is "key", the + operator is "In", and the values array contains only "value". The requirements are ANDed. + type: object + type: object + x-kubernetes-map-type: atomic + matchLabelKeys: + description: |- + MatchLabelKeys is a set of pod label keys to select which pods will + be taken into consideration. The keys are used to lookup values from the + incoming pod labels, those key-value labels are merged with `labelSelector` as `key in (value)` + to select the group of existing pods which pods will be taken into consideration + for the incoming pod's pod (anti) affinity. Keys that don't exist in the incoming + pod labels will be ignored. The default value is empty. + The same key is forbidden to exist in both matchLabelKeys and labelSelector. + Also, matchLabelKeys cannot be set when labelSelector isn't set. + items: + type: string + type: array + x-kubernetes-list-type: atomic + mismatchLabelKeys: + description: |- + MismatchLabelKeys is a set of pod label keys to select which pods will + be taken into consideration. The keys are used to lookup values from the + incoming pod labels, those key-value labels are merged with `labelSelector` as `key notin (value)` + to select the group of existing pods which pods will be taken into consideration + for the incoming pod's pod (anti) affinity. Keys that don't exist in the incoming + pod labels will be ignored. The default value is empty. + The same key is forbidden to exist in both mismatchLabelKeys and labelSelector. + Also, mismatchLabelKeys cannot be set when labelSelector isn't set. + items: + type: string + type: array + x-kubernetes-list-type: atomic + namespaceSelector: + description: |- + A label query over the set of namespaces that the term applies to. + The term is applied to the union of the namespaces selected by this field + and the ones listed in the namespaces field. + null selector and null or empty namespaces list means "this pod's namespace". + An empty selector ({}) matches all namespaces. + properties: + matchExpressions: + description: matchExpressions is a list + of label selector requirements. The requirements + are ANDed. + items: + description: |- + A label selector requirement is a selector that contains values, a key, and an operator that + relates the key and values. + properties: + key: + description: key is the label key + that the selector applies to. + type: string + operator: + description: |- + operator represents a key's relationship to a set of values. + Valid operators are In, NotIn, Exists and DoesNotExist. + type: string + values: + description: |- + values is an array of string values. If the operator is In or NotIn, + the values array must be non-empty. If the operator is Exists or DoesNotExist, + the values array must be empty. This array is replaced during a strategic + merge patch. + items: + type: string + type: array + x-kubernetes-list-type: atomic + required: + - key + - operator + type: object + type: array + x-kubernetes-list-type: atomic + matchLabels: + additionalProperties: + type: string + description: |- + matchLabels is a map of {key,value} pairs. A single {key,value} in the matchLabels + map is equivalent to an element of matchExpressions, whose key field is "key", the + operator is "In", and the values array contains only "value". The requirements are ANDed. + type: object + type: object + x-kubernetes-map-type: atomic + namespaces: + description: |- + namespaces specifies a static list of namespace names that the term applies to. + The term is applied to the union of the namespaces listed in this field + and the ones selected by namespaceSelector. + null or empty namespaces list and null namespaceSelector means "this pod's namespace". + items: + type: string + type: array + x-kubernetes-list-type: atomic + topologyKey: + description: |- + This pod should be co-located (affinity) or not co-located (anti-affinity) with the pods matching + the labelSelector in the specified namespaces, where co-located is defined as running on a node + whose value of the label with key topologyKey matches that of any node on which any of the + selected pods is running. + Empty topologyKey is not allowed. + type: string + required: + - topologyKey + type: object + type: array + x-kubernetes-list-type: atomic + type: object + type: object + nodeSelector: + additionalProperties: + type: string + description: |- + nodeSelector is the node selector applied to the relevant kind of pods + It specifies a map of key-value pairs: for the pod to be eligible to run on a node, + the node must have each of the indicated key-value pairs as labels + (it can have additional labels as well). + See https://kubernetes.io/docs/concepts/configuration/assign-pod-node/#nodeselector + type: object + tolerations: + description: |- + tolerations is a list of tolerations applied to the relevant kind of pods + See https://kubernetes.io/docs/concepts/configuration/taint-and-toleration/ for more info. + These are additional tolerations other than default ones. + items: + description: |- + The pod this Toleration is attached to tolerates any taint that matches + the triple using the matching operator . + properties: + effect: + description: |- + Effect indicates the taint effect to match. Empty means match all taint effects. + When specified, allowed values are NoSchedule, PreferNoSchedule and NoExecute. + type: string + key: + description: |- + Key is the taint key that the toleration applies to. Empty means match all taint keys. + If the key is empty, operator must be Exists; this combination means to match all values and all keys. + type: string + operator: + description: |- + Operator represents a key's relationship to the value. + Valid operators are Exists and Equal. Defaults to Equal. + Exists is equivalent to wildcard for value, so that a pod can + tolerate all taints of a particular category. + type: string + tolerationSeconds: + description: |- + TolerationSeconds represents the period of time the toleration (which must be + of effect NoExecute, otherwise this field is ignored) tolerates the taint. By default, + it is not set, which means tolerate the taint forever (do not evict). Zero and + negative values will be treated as 0 (evict immediately) by the system. + format: int64 + type: integer + value: + description: |- + Value is the taint value the toleration matches to. + If the operator is Exists, the value should be empty, otherwise just a regular string. + type: string + type: object + type: array + type: object + type: object + type: object + status: + description: HyperConvergedStatus defines the observed state of HyperConverged + properties: + conditions: + description: Conditions describes the state of the HyperConverged + resource. + items: + description: Condition contains details for one aspect of the current + state of this API Resource. + properties: + lastTransitionTime: + description: |- + lastTransitionTime is the last time the condition transitioned from one status to another. + This should be when the underlying condition changed. If that is not known, then using the time when the API field changed is acceptable. + format: date-time + type: string + message: + description: |- + message is a human readable message indicating details about the transition. + This may be an empty string. + maxLength: 32768 + type: string + observedGeneration: + description: |- + observedGeneration represents the .metadata.generation that the condition was set based upon. + For instance, if .metadata.generation is currently 12, but the .status.conditions[x].observedGeneration is 9, the condition is out of date + with respect to the current state of the instance. + format: int64 + minimum: 0 + type: integer + reason: + description: |- + reason contains a programmatic identifier indicating the reason for the condition's last transition. + Producers of specific condition types may define expected values and meanings for this field, + and whether the values are considered a guaranteed API. + The value should be a CamelCase string. + This field may not be empty. + maxLength: 1024 + minLength: 1 + pattern: ^[A-Za-z]([A-Za-z0-9_,:]*[A-Za-z0-9_])?$ + type: string + status: + description: status of the condition, one of True, False, Unknown. + enum: + - "True" + - "False" + - Unknown + type: string + type: + description: type of condition in CamelCase or in foo.example.com/CamelCase. + maxLength: 316 + pattern: ^([a-z0-9]([-a-z0-9]*[a-z0-9])?(\.[a-z0-9]([-a-z0-9]*[a-z0-9])?)*/)?(([A-Za-z0-9][-A-Za-z0-9_.]*)?[A-Za-z0-9])$ + type: string + required: + - lastTransitionTime + - message + - reason + - status + - type + type: object + type: array + x-kubernetes-list-type: atomic + dataImportCronTemplates: + description: |- + DataImportCronTemplates is a list of the actual DataImportCronTemplates as HCO update in the SSP CR. The list + contains both the common and the custom templates, including any modification done by HCO. + items: + description: DataImportCronTemplateStatus is a copy of a dataImportCronTemplate + as defined in the spec, or in the HCO image. + properties: + metadata: + properties: + annotations: + additionalProperties: + type: string + type: object + finalizers: + items: + type: string + type: array + labels: + additionalProperties: + type: string + type: object + name: + type: string + namespace: + type: string + type: object + spec: + description: DataImportCronSpec defines specification for DataImportCron + properties: + garbageCollect: + description: |- + GarbageCollect specifies whether old PVCs should be cleaned up after a new PVC is imported. + Options are currently "Outdated" and "Never", defaults to "Outdated". + type: string + importsToKeep: + description: Number of import PVCs to keep when garbage + collecting. Default is 3. + format: int32 + type: integer + managedDataSource: + description: |- + ManagedDataSource specifies the name of the corresponding DataSource this cron will manage. + DataSource has to be in the same namespace. + type: string + retentionPolicy: + description: RetentionPolicy specifies whether the created + DataVolumes and DataSources are retained when their DataImportCron + is deleted. Default is RatainAll. + type: string + schedule: + description: Schedule specifies in cron format when and + how often to look for new imports + type: string + serviceAccountName: + description: ServiceAccountName is the name of the ServiceAccount + for creating DataVolumes. + minLength: 1 + type: string + template: + description: Template specifies template for the DVs to + be created + properties: + apiVersion: + description: |- + APIVersion defines the versioned schema of this representation of an object. + Servers should convert recognized schemas to the latest internal value, and + may reject unrecognized values. + More info: https://git.k8s.io/community/contributors/devel/sig-architecture/api-conventions.md#resources + type: string + kind: + description: |- + Kind is a string value representing the REST resource this object represents. + Servers may infer this from the endpoint the client submits requests to. + Cannot be updated. + In CamelCase. + More info: https://git.k8s.io/community/contributors/devel/sig-architecture/api-conventions.md#types-kinds + type: string + metadata: + properties: + annotations: + additionalProperties: + type: string + type: object + finalizers: + items: + type: string + type: array + labels: + additionalProperties: + type: string + type: object + name: + type: string + namespace: + type: string + type: object + spec: + description: DataVolumeSpec defines the DataVolume type + specification + properties: + checkpoints: + description: Checkpoints is a list of DataVolumeCheckpoints, + representing stages in a multistage import. + items: + description: DataVolumeCheckpoint defines a stage + in a warm migration. + properties: + current: + description: Current is the identifier of + the snapshot created for this checkpoint. + type: string + previous: + description: Previous is the identifier of + the snapshot from the previous checkpoint. + type: string + required: + - current + - previous + type: object + type: array + contentType: + description: 'DataVolumeContentType options: "kubevirt", + "archive"' + enum: + - kubevirt + - archive + type: string + finalCheckpoint: + description: FinalCheckpoint indicates whether the + current DataVolumeCheckpoint is the final checkpoint. + type: boolean + preallocation: + description: Preallocation controls whether storage + for DataVolumes should be allocated in advance. + type: boolean + priorityClassName: + description: PriorityClassName for Importer, Cloner + and Uploader pod + type: string + pvc: + description: PVC is the PVC specification + properties: + accessModes: + description: |- + accessModes contains the desired access modes the volume should have. + More info: https://kubernetes.io/docs/concepts/storage/persistent-volumes#access-modes-1 + items: + type: string + type: array + x-kubernetes-list-type: atomic + dataSource: + description: |- + dataSource field can be used to specify either: + * An existing VolumeSnapshot object (snapshot.storage.k8s.io/VolumeSnapshot) + * An existing PVC (PersistentVolumeClaim) + If the provisioner or an external controller can support the specified data source, + it will create a new volume based on the contents of the specified data source. + When the AnyVolumeDataSource feature gate is enabled, dataSource contents will be copied to dataSourceRef, + and dataSourceRef contents will be copied to dataSource when dataSourceRef.namespace is not specified. + If the namespace is specified, then dataSourceRef will not be copied to dataSource. + properties: + apiGroup: + description: |- + APIGroup is the group for the resource being referenced. + If APIGroup is not specified, the specified Kind must be in the core API group. + For any other third-party types, APIGroup is required. + type: string + kind: + description: Kind is the type of resource + being referenced + type: string + name: + description: Name is the name of resource + being referenced + type: string + required: + - kind + - name + type: object + x-kubernetes-map-type: atomic + dataSourceRef: + description: |- + dataSourceRef specifies the object from which to populate the volume with data, if a non-empty + volume is desired. This may be any object from a non-empty API group (non + core object) or a PersistentVolumeClaim object. + When this field is specified, volume binding will only succeed if the type of + the specified object matches some installed volume populator or dynamic + provisioner. + This field will replace the functionality of the dataSource field and as such + if both fields are non-empty, they must have the same value. For backwards + compatibility, when namespace isn't specified in dataSourceRef, + both fields (dataSource and dataSourceRef) will be set to the same + value automatically if one of them is empty and the other is non-empty. + When namespace is specified in dataSourceRef, + dataSource isn't set to the same value and must be empty. + There are three important differences between dataSource and dataSourceRef: + * While dataSource only allows two specific types of objects, dataSourceRef + allows any non-core object, as well as PersistentVolumeClaim objects. + * While dataSource ignores disallowed values (dropping them), dataSourceRef + preserves all values, and generates an error if a disallowed value is + specified. + * While dataSource only allows local objects, dataSourceRef allows objects + in any namespaces. + (Beta) Using this field requires the AnyVolumeDataSource feature gate to be enabled. + (Alpha) Using the namespace field of dataSourceRef requires the CrossNamespaceVolumeDataSource feature gate to be enabled. + properties: + apiGroup: + description: |- + APIGroup is the group for the resource being referenced. + If APIGroup is not specified, the specified Kind must be in the core API group. + For any other third-party types, APIGroup is required. + type: string + kind: + description: Kind is the type of resource + being referenced + type: string + name: + description: Name is the name of resource + being referenced + type: string + namespace: + description: |- + Namespace is the namespace of resource being referenced + Note that when a namespace is specified, a gateway.networking.k8s.io/ReferenceGrant object is required in the referent namespace to allow that namespace's owner to accept the reference. See the ReferenceGrant documentation for details. + (Alpha) This field requires the CrossNamespaceVolumeDataSource feature gate to be enabled. + type: string + required: + - kind + - name + type: object + resources: + description: |- + resources represents the minimum resources the volume should have. + If RecoverVolumeExpansionFailure feature is enabled users are allowed to specify resource requirements + that are lower than previous value but must still be higher than capacity recorded in the + status field of the claim. + More info: https://kubernetes.io/docs/concepts/storage/persistent-volumes#resources + properties: + limits: + additionalProperties: + anyOf: + - type: integer + - type: string + pattern: ^(\+|-)?(([0-9]+(\.[0-9]*)?)|(\.[0-9]+))(([KMGTPE]i)|[numkMGTPE]|([eE](\+|-)?(([0-9]+(\.[0-9]*)?)|(\.[0-9]+))))?$ + x-kubernetes-int-or-string: true + description: |- + Limits describes the maximum amount of compute resources allowed. + More info: https://kubernetes.io/docs/concepts/configuration/manage-resources-containers/ + type: object + requests: + additionalProperties: + anyOf: + - type: integer + - type: string + pattern: ^(\+|-)?(([0-9]+(\.[0-9]*)?)|(\.[0-9]+))(([KMGTPE]i)|[numkMGTPE]|([eE](\+|-)?(([0-9]+(\.[0-9]*)?)|(\.[0-9]+))))?$ + x-kubernetes-int-or-string: true + description: |- + Requests describes the minimum amount of compute resources required. + If Requests is omitted for a container, it defaults to Limits if that is explicitly specified, + otherwise to an implementation-defined value. Requests cannot exceed Limits. + More info: https://kubernetes.io/docs/concepts/configuration/manage-resources-containers/ + type: object + type: object + selector: + description: selector is a label query over + volumes to consider for binding. + properties: + matchExpressions: + description: matchExpressions is a list + of label selector requirements. The requirements + are ANDed. + items: + description: |- + A label selector requirement is a selector that contains values, a key, and an operator that + relates the key and values. + properties: + key: + description: key is the label key + that the selector applies to. + type: string + operator: + description: |- + operator represents a key's relationship to a set of values. + Valid operators are In, NotIn, Exists and DoesNotExist. + type: string + values: + description: |- + values is an array of string values. If the operator is In or NotIn, + the values array must be non-empty. If the operator is Exists or DoesNotExist, + the values array must be empty. This array is replaced during a strategic + merge patch. + items: + type: string + type: array + x-kubernetes-list-type: atomic + required: + - key + - operator + type: object + type: array + x-kubernetes-list-type: atomic + matchLabels: + additionalProperties: + type: string + description: |- + matchLabels is a map of {key,value} pairs. A single {key,value} in the matchLabels + map is equivalent to an element of matchExpressions, whose key field is "key", the + operator is "In", and the values array contains only "value". The requirements are ANDed. + type: object + type: object + x-kubernetes-map-type: atomic + storageClassName: + description: |- + storageClassName is the name of the StorageClass required by the claim. + More info: https://kubernetes.io/docs/concepts/storage/persistent-volumes#class-1 + type: string + volumeAttributesClassName: + description: |- + volumeAttributesClassName may be used to set the VolumeAttributesClass used by this claim. + If specified, the CSI driver will create or update the volume with the attributes defined + in the corresponding VolumeAttributesClass. This has a different purpose than storageClassName, + it can be changed after the claim is created. An empty string or nil value indicates that no + VolumeAttributesClass will be applied to the claim. If the claim enters an Infeasible error state, + this field can be reset to its previous value (including nil) to cancel the modification. + If the resource referred to by volumeAttributesClass does not exist, this PersistentVolumeClaim will be + set to a Pending state, as reflected by the modifyVolumeStatus field, until such as a resource + exists. + More info: https://kubernetes.io/docs/concepts/storage/volume-attributes-classes/ + type: string + volumeMode: + description: |- + volumeMode defines what type of volume is required by the claim. + Value of Filesystem is implied when not included in claim spec. + type: string + volumeName: + description: volumeName is the binding reference + to the PersistentVolume backing this claim. + type: string + type: object + source: + description: Source is the src of the data for the + requested DataVolume + properties: + blank: + description: DataVolumeBlankImage provides the + parameters to create a new raw blank image + for the PVC + type: object + gcs: + description: DataVolumeSourceGCS provides the + parameters to create a Data Volume from an + GCS source + properties: + secretRef: + description: SecretRef provides the secret + reference needed to access the GCS source + type: string + url: + description: URL is the url of the GCS source + type: string + required: + - url + type: object + http: + description: DataVolumeSourceHTTP can be either + an http or https endpoint, with an optional + basic auth user name and password, and an + optional configmap containing additional CAs + properties: + certConfigMap: + description: CertConfigMap is a configmap + reference, containing a Certificate Authority(CA) + public key, and a base64 encoded pem certificate + type: string + extraHeaders: + description: ExtraHeaders is a list of strings + containing extra headers to include with + HTTP transfer requests + items: + type: string + type: array + secretExtraHeaders: + description: SecretExtraHeaders is a list + of Secret references, each containing + an extra HTTP header that may include + sensitive information + items: + type: string + type: array + secretRef: + description: SecretRef A Secret reference, + the secret should contain accessKeyId + (user name) base64 encoded, and secretKey + (password) also base64 encoded + type: string + url: + description: URL is the URL of the http(s) + endpoint + type: string + required: + - url + type: object + imageio: + description: DataVolumeSourceImageIO provides + the parameters to create a Data Volume from + an imageio source + properties: + certConfigMap: + description: CertConfigMap provides a reference + to the CA cert + type: string + diskId: + description: DiskID provides id of a disk + to be imported + type: string + insecureSkipVerify: + description: InsecureSkipVerify is a flag + to skip certificate verification + type: boolean + secretRef: + description: SecretRef provides the secret + reference needed to access the ovirt-engine + type: string + url: + description: URL is the URL of the ovirt-engine + type: string + required: + - diskId + - url + type: object + pvc: + description: DataVolumeSourcePVC provides the + parameters to create a Data Volume from an + existing PVC + properties: + name: + description: The name of the source PVC + type: string + namespace: + description: The namespace of the source + PVC + type: string + required: + - name + - namespace + type: object + registry: + description: DataVolumeSourceRegistry provides + the parameters to create a Data Volume from + an registry source + properties: + certConfigMap: + description: CertConfigMap provides a reference + to the Registry certs + type: string + imageStream: + description: ImageStream is the name of + image stream for import + type: string + platform: + description: Platform describes the minimum + runtime requirements of the image + properties: + architecture: + description: Architecture specifies + the image target CPU architecture + type: string + type: object + pullMethod: + description: PullMethod can be either "pod" + (default import), or "node" (node docker + cache based import) + type: string + secretRef: + description: SecretRef provides the secret + reference needed to access the Registry + source + type: string + url: + description: 'URL is the url of the registry + source (starting with the scheme: docker, + oci-archive)' + type: string + type: object + s3: + description: DataVolumeSourceS3 provides the + parameters to create a Data Volume from an + S3 source + properties: + certConfigMap: + description: CertConfigMap is a configmap + reference, containing a Certificate Authority(CA) + public key, and a base64 encoded pem certificate + type: string + secretRef: + description: SecretRef provides the secret + reference needed to access the S3 source + type: string + url: + description: URL is the url of the S3 source + type: string + required: + - url + type: object + snapshot: + description: DataVolumeSourceSnapshot provides + the parameters to create a Data Volume from + an existing VolumeSnapshot + properties: + name: + description: The name of the source VolumeSnapshot + type: string + namespace: + description: The namespace of the source + VolumeSnapshot + type: string + required: + - name + - namespace + type: object + upload: + description: DataVolumeSourceUpload provides + the parameters to create a Data Volume by + uploading the source + type: object + vddk: + description: DataVolumeSourceVDDK provides the + parameters to create a Data Volume from a + Vmware source + properties: + backingFile: + description: BackingFile is the path to + the virtual hard disk to migrate from + vCenter/ESXi + type: string + extraArgs: + description: ExtraArgs is a reference to + a ConfigMap containing extra arguments + to pass directly to the VDDK library + type: string + initImageURL: + description: InitImageURL is an optional + URL to an image containing an extracted + VDDK library, overrides v2v-vmware config + map + type: string + secretRef: + description: SecretRef provides a reference + to a secret containing the username and + password needed to access the vCenter + or ESXi host + type: string + thumbprint: + description: Thumbprint is the certificate + thumbprint of the vCenter or ESXi host + type: string + url: + description: URL is the URL of the vCenter + or ESXi host with the VM to migrate + type: string + uuid: + description: UUID is the UUID of the virtual + machine that the backing file is attached + to in vCenter/ESXi + type: string + type: object + type: object + sourceRef: + description: SourceRef is an indirect reference + to the source of data for the requested DataVolume + properties: + kind: + description: The kind of the source reference, + currently only "DataSource" is supported + type: string + name: + description: The name of the source reference + type: string + namespace: + description: The namespace of the source reference, + defaults to the DataVolume namespace + type: string + required: + - kind + - name + type: object + storage: + description: Storage is the requested storage specification + properties: + accessModes: + description: |- + AccessModes contains the desired access modes the volume should have. + More info: https://kubernetes.io/docs/concepts/storage/persistent-volumes#access-modes-1 + items: + type: string + type: array + dataSource: + description: |- + This field can be used to specify either: * An existing VolumeSnapshot object (snapshot.storage.k8s.io/VolumeSnapshot) * An existing PVC (PersistentVolumeClaim) * An existing custom resource that implements data population (Alpha) In order to use custom resource types that implement data population, the AnyVolumeDataSource feature gate must be enabled. If the provisioner or an external controller can support the specified data source, it will create a new volume based on the contents of the specified data source. + If the AnyVolumeDataSource feature gate is enabled, this field will always have the same contents as the DataSourceRef field. + properties: + apiGroup: + description: |- + APIGroup is the group for the resource being referenced. + If APIGroup is not specified, the specified Kind must be in the core API group. + For any other third-party types, APIGroup is required. + type: string + kind: + description: Kind is the type of resource + being referenced + type: string + name: + description: Name is the name of resource + being referenced + type: string + required: + - kind + - name + type: object + x-kubernetes-map-type: atomic + dataSourceRef: + description: |- + Specifies the object from which to populate the volume with data, if a non-empty volume is desired. This may be any local object from a non-empty API group (non core object) or a PersistentVolumeClaim object. When this field is specified, volume binding will only succeed if the type of the specified object matches some installed volume populator or dynamic provisioner. + This field will replace the functionality of the DataSource field and as such if both fields are non-empty, they must have the same value. For backwards compatibility, both fields (DataSource and DataSourceRef) will be set to the same value automatically if one of them is empty and the other is non-empty. + There are two important differences between DataSource and DataSourceRef: + * While DataSource only allows two specific types of objects, DataSourceRef allows any non-core object, as well as PersistentVolumeClaim objects. + * While DataSource ignores disallowed values (dropping them), DataSourceRef preserves all values, and generates an error if a disallowed value is specified. + (Beta) Using this field requires the AnyVolumeDataSource feature gate to be enabled. + properties: + apiGroup: + description: |- + APIGroup is the group for the resource being referenced. + If APIGroup is not specified, the specified Kind must be in the core API group. + For any other third-party types, APIGroup is required. + type: string + kind: + description: Kind is the type of resource + being referenced + type: string + name: + description: Name is the name of resource + being referenced + type: string + namespace: + description: |- + Namespace is the namespace of resource being referenced + Note that when a namespace is specified, a gateway.networking.k8s.io/ReferenceGrant object is required in the referent namespace to allow that namespace's owner to accept the reference. See the ReferenceGrant documentation for details. + (Alpha) This field requires the CrossNamespaceVolumeDataSource feature gate to be enabled. + type: string + required: + - kind + - name + type: object + resources: + description: |- + Resources represents the minimum resources the volume should have. + More info: https://kubernetes.io/docs/concepts/storage/persistent-volumes#resources + properties: + limits: + additionalProperties: + anyOf: + - type: integer + - type: string + pattern: ^(\+|-)?(([0-9]+(\.[0-9]*)?)|(\.[0-9]+))(([KMGTPE]i)|[numkMGTPE]|([eE](\+|-)?(([0-9]+(\.[0-9]*)?)|(\.[0-9]+))))?$ + x-kubernetes-int-or-string: true + description: |- + Limits describes the maximum amount of compute resources allowed. + More info: https://kubernetes.io/docs/concepts/configuration/manage-resources-containers/ + type: object + requests: + additionalProperties: + anyOf: + - type: integer + - type: string + pattern: ^(\+|-)?(([0-9]+(\.[0-9]*)?)|(\.[0-9]+))(([KMGTPE]i)|[numkMGTPE]|([eE](\+|-)?(([0-9]+(\.[0-9]*)?)|(\.[0-9]+))))?$ + x-kubernetes-int-or-string: true + description: |- + Requests describes the minimum amount of compute resources required. + If Requests is omitted for a container, it defaults to Limits if that is explicitly specified, + otherwise to an implementation-defined value. Requests cannot exceed Limits. + More info: https://kubernetes.io/docs/concepts/configuration/manage-resources-containers/ + type: object + type: object + selector: + description: A label query over volumes to consider + for binding. + properties: + matchExpressions: + description: matchExpressions is a list + of label selector requirements. The requirements + are ANDed. + items: + description: |- + A label selector requirement is a selector that contains values, a key, and an operator that + relates the key and values. + properties: + key: + description: key is the label key + that the selector applies to. + type: string + operator: + description: |- + operator represents a key's relationship to a set of values. + Valid operators are In, NotIn, Exists and DoesNotExist. + type: string + values: + description: |- + values is an array of string values. If the operator is In or NotIn, + the values array must be non-empty. If the operator is Exists or DoesNotExist, + the values array must be empty. This array is replaced during a strategic + merge patch. + items: + type: string + type: array + x-kubernetes-list-type: atomic + required: + - key + - operator + type: object + type: array + x-kubernetes-list-type: atomic + matchLabels: + additionalProperties: + type: string + description: |- + matchLabels is a map of {key,value} pairs. A single {key,value} in the matchLabels + map is equivalent to an element of matchExpressions, whose key field is "key", the + operator is "In", and the values array contains only "value". The requirements are ANDed. + type: object + type: object + x-kubernetes-map-type: atomic + storageClassName: + description: |- + Name of the StorageClass required by the claim. + More info: https://kubernetes.io/docs/concepts/storage/persistent-volumes#class-1 + type: string + volumeMode: + description: |- + volumeMode defines what type of volume is required by the claim. + Value of Filesystem is implied when not included in claim spec. + type: string + volumeName: + description: VolumeName is the binding reference + to the PersistentVolume backing this claim. + type: string + type: object + type: object + status: + description: DataVolumeStatus contains the current status + of the DataVolume + properties: + claimName: + description: ClaimName is the name of the underlying + PVC used by the DataVolume. + type: string + conditions: + items: + description: DataVolumeCondition represents the + state of a data volume condition. + properties: + lastHeartbeatTime: + format: date-time + type: string + lastTransitionTime: + format: date-time + type: string + message: + type: string + reason: + type: string + status: + type: string + type: + description: DataVolumeConditionType is the + string representation of known condition + types + type: string + required: + - status + - type + type: object + type: array + phase: + description: Phase is the current phase of the data + volume + type: string + progress: + description: DataVolumeProgress is the current progress + of the DataVolume transfer operation. Value between + 0 and 100 inclusive, N/A if not available + type: string + restartCount: + description: RestartCount is the number of times + the pod populating the DataVolume has restarted + format: int32 + type: integer + type: object + required: + - spec + type: object + required: + - managedDataSource + - schedule + - template + type: object + status: + description: DataImportCronStatus is the status field of the + DIC template + properties: + commonTemplate: + description: CommonTemplate indicates whether this is a + common template (true), or a custom one (false) + type: boolean + conditions: + description: Conditions is a list of conditions that describe + the state of the DataImportCronTemplate. + items: + description: Condition contains details for one aspect + of the current state of this API Resource. + properties: + lastTransitionTime: + description: |- + lastTransitionTime is the last time the condition transitioned from one status to another. + This should be when the underlying condition changed. If that is not known, then using the time when the API field changed is acceptable. + format: date-time + type: string + message: + description: |- + message is a human readable message indicating details about the transition. + This may be an empty string. + maxLength: 32768 + type: string + observedGeneration: + description: |- + observedGeneration represents the .metadata.generation that the condition was set based upon. + For instance, if .metadata.generation is currently 12, but the .status.conditions[x].observedGeneration is 9, the condition is out of date + with respect to the current state of the instance. + format: int64 + minimum: 0 + type: integer + reason: + description: |- + reason contains a programmatic identifier indicating the reason for the condition's last transition. + Producers of specific condition types may define expected values and meanings for this field, + and whether the values are considered a guaranteed API. + The value should be a CamelCase string. + This field may not be empty. + maxLength: 1024 + minLength: 1 + pattern: ^[A-Za-z]([A-Za-z0-9_,:]*[A-Za-z0-9_])?$ + type: string + status: + description: status of the condition, one of True, + False, Unknown. + enum: + - "True" + - "False" + - Unknown + type: string + type: + description: type of condition in CamelCase or in + foo.example.com/CamelCase. + maxLength: 316 + pattern: ^([a-z0-9]([-a-z0-9]*[a-z0-9])?(\.[a-z0-9]([-a-z0-9]*[a-z0-9])?)*/)?(([A-Za-z0-9][-A-Za-z0-9_.]*)?[A-Za-z0-9])$ + type: string + required: + - lastTransitionTime + - message + - reason + - status + - type + type: object + type: array + modified: + description: Modified indicates if a common template was + customized. Always false for custom templates. + type: boolean + originalSupportedArchitectures: + description: |- + OriginalSupportedArchitectures is a comma-separated list of CPU architectures that the original + template supports. + type: string + type: object + type: object + type: array + dataImportSchedule: + description: |- + DataImportSchedule is the cron expression that is used in for the hard-coded data import cron templates. HCO + generates the value of this field once and stored in the status field, so will survive restart. + type: string + infrastructureHighlyAvailable: + description: |- + InfrastructureHighlyAvailable describes whether the cluster has only one worker node + (false) or more (true). + type: boolean + nodeInfo: + description: NodeInfo holds information about the cluster nodes + properties: + controlPlaneArchitectures: + description: ControlPlaneArchitectures is a distinct list of the + CPU architecture of the control-plane nodes. + items: + type: string + type: array + workloadsArchitectures: + description: WorkloadsArchitectures is a distinct list of the + CPU architectures of the workloads nodes in the cluster. + items: + type: string + type: array + type: object + observedGeneration: + description: |- + ObservedGeneration reflects the HyperConverged resource generation. If the ObservedGeneration is less than the + resource generation in metadata, the status is out of date + format: int64 + type: integer + relatedObjects: + description: |- + RelatedObjects is a list of objects created and maintained by this + operator. Object references will be added to this list after they have + been created AND found in the cluster. + items: + description: ObjectReference contains enough information to let + you inspect or modify the referred object. + properties: + apiVersion: + description: API version of the referent. + type: string + fieldPath: + description: |- + If referring to a piece of an object instead of an entire object, this string + should contain a valid JSON/Go field access statement, such as desiredState.manifest.containers[2]. + For example, if the object reference is to a container within a pod, this would take on a value like: + "spec.containers{name}" (where "name" refers to the name of the container that triggered + the event) or if no container name is specified "spec.containers[2]" (container with + index 2 in this pod). This syntax is chosen only to have some well-defined way of + referencing a part of an object. + type: string + kind: + description: |- + Kind of the referent. + More info: https://git.k8s.io/community/contributors/devel/sig-architecture/api-conventions.md#types-kinds + type: string + name: + description: |- + Name of the referent. + More info: https://kubernetes.io/docs/concepts/overview/working-with-objects/names/#names + type: string + namespace: + description: |- + Namespace of the referent. + More info: https://kubernetes.io/docs/concepts/overview/working-with-objects/namespaces/ + type: string + resourceVersion: + description: |- + Specific resourceVersion to which this reference is made, if any. + More info: https://git.k8s.io/community/contributors/devel/sig-architecture/api-conventions.md#concurrency-control-and-consistency + type: string + uid: + description: |- + UID of the referent. + More info: https://kubernetes.io/docs/concepts/overview/working-with-objects/names/#uids + type: string + type: object + x-kubernetes-map-type: atomic + type: array + x-kubernetes-list-type: atomic + systemHealthStatus: + description: SystemHealthStatus reflects the health of HCO and its + secondary resources, based on the aggregated conditions. + type: string + versions: + description: |- + Versions is a list of HCO component versions, as name/version pairs. The version with a name of "operator" + is the HCO version itself, as described here: + https://github.com/openshift/cluster-version-operator/blob/master/docs/dev/clusteroperator.md#version + items: + properties: + name: + type: string + version: + type: string + type: object + type: array + x-kubernetes-list-type: atomic + type: object + type: object + served: true + storage: false + subresources: + status: {} - additionalPrinterColumns: - jsonPath: .metadata.creationTimestamp name: Age diff --git a/deploy/index-image/community-kubevirt-hyperconverged/1.18.0/manifests/hco00.crd.yaml b/deploy/index-image/community-kubevirt-hyperconverged/1.18.0/manifests/hco00.crd.yaml index d7b0d4cb77..a1cebffd93 100644 --- a/deploy/index-image/community-kubevirt-hyperconverged/1.18.0/manifests/hco00.crd.yaml +++ b/deploy/index-image/community-kubevirt-hyperconverged/1.18.0/manifests/hco00.crd.yaml @@ -17,6 +17,5186 @@ spec: singular: hyperconverged scope: Namespaced versions: + - additionalPrinterColumns: + - jsonPath: .metadata.creationTimestamp + name: Age + type: date + name: v1 + schema: + openAPIV3Schema: + description: HyperConverged is the Schema for the hyperconvergeds API + properties: + apiVersion: + description: |- + APIVersion defines the versioned schema of this representation of an object. + Servers should convert recognized schemas to the latest internal value, and + may reject unrecognized values. + More info: https://git.k8s.io/community/contributors/devel/sig-architecture/api-conventions.md#resources + type: string + kind: + description: |- + Kind is a string value representing the REST resource this object represents. + Servers may infer this from the endpoint the client submits requests to. + Cannot be updated. + In CamelCase. + More info: https://git.k8s.io/community/contributors/devel/sig-architecture/api-conventions.md#types-kinds + type: string + metadata: + properties: + name: + pattern: kubevirt-hyperconverged + type: string + type: object + spec: + default: + certConfig: + ca: + duration: 48h0m0s + renewBefore: 24h0m0s + server: + duration: 24h0m0s + renewBefore: 12h0m0s + deployVmConsoleProxy: false + enableApplicationAwareQuota: false + enableCommonBootImageImport: true + liveMigrationConfig: + allowAutoConverge: false + allowPostCopy: false + completionTimeoutPerGiB: 150 + parallelMigrationsPerCluster: 5 + parallelOutboundMigrationsPerNode: 2 + progressTimeout: 150 + resourceRequirements: + vmiCPUAllocationRatio: 10 + uninstallStrategy: BlockUninstallIfWorkloadsExist + virtualMachineOptions: + disableFreePageReporting: false + disableSerialConsoleLog: false + description: HyperConvergedSpec defines the desired state of HyperConverged + properties: + CommonInstancetypesDeployment: + description: CommonInstancetypesDeployment holds the configuration + of common-instancetypes deployment within KubeVirt. + properties: + enabled: + description: Enabled controls the deployment of common-instancetypes + resources, defaults to True. + nullable: true + type: boolean + type: object + applicationAwareConfig: + description: ApplicationAwareConfig set the AAQ configurations + properties: + allowApplicationAwareClusterResourceQuota: + default: false + description: AllowApplicationAwareClusterResourceQuota if set + to true, allows creation and management of ClusterAppsResourceQuota + type: boolean + namespaceSelector: + description: NamespaceSelector determines in which namespaces + scheduling gate will be added to pods.. + properties: + matchExpressions: + description: matchExpressions is a list of label selector + requirements. The requirements are ANDed. + items: + description: |- + A label selector requirement is a selector that contains values, a key, and an operator that + relates the key and values. + properties: + key: + description: key is the label key that the selector + applies to. + type: string + operator: + description: |- + operator represents a key's relationship to a set of values. + Valid operators are In, NotIn, Exists and DoesNotExist. + type: string + values: + description: |- + values is an array of string values. If the operator is In or NotIn, + the values array must be non-empty. If the operator is Exists or DoesNotExist, + the values array must be empty. This array is replaced during a strategic + merge patch. + items: + type: string + type: array + x-kubernetes-list-type: atomic + required: + - key + - operator + type: object + type: array + x-kubernetes-list-type: atomic + matchLabels: + additionalProperties: + type: string + description: |- + matchLabels is a map of {key,value} pairs. A single {key,value} in the matchLabels + map is equivalent to an element of matchExpressions, whose key field is "key", the + operator is "In", and the values array contains only "value". The requirements are ANDed. + type: object + type: object + x-kubernetes-map-type: atomic + vmiCalcConfigName: + default: DedicatedVirtualResources + description: |- + VmiCalcConfigName determine how resource allocation will be done with ApplicationsResourceQuota. + allowed values are: VmiPodUsage, VirtualResources, DedicatedVirtualResources or IgnoreVmiCalculator + enum: + - VmiPodUsage + - VirtualResources + - DedicatedVirtualResources + - IgnoreVmiCalculator + type: string + type: object + certConfig: + default: + ca: + duration: 48h0m0s + renewBefore: 24h0m0s + server: + duration: 24h0m0s + renewBefore: 12h0m0s + description: certConfig holds the rotation policy for internal, self-signed + certificates + properties: + ca: + default: + duration: 48h0m0s + renewBefore: 24h0m0s + description: |- + CA configuration - + CA certs are kept in the CA bundle as long as they are valid + properties: + duration: + default: 48h0m0s + description: |- + The requested 'duration' (i.e. lifetime) of the Certificate. + This should comply with golang's ParseDuration format (https://golang.org/pkg/time/#ParseDuration) + type: string + renewBefore: + default: 24h0m0s + description: |- + The amount of time before the currently issued certificate's `notAfter` + time that we will begin to attempt to renew the certificate. + This should comply with golang's ParseDuration format (https://golang.org/pkg/time/#ParseDuration) + type: string + type: object + server: + default: + duration: 24h0m0s + renewBefore: 12h0m0s + description: |- + Server configuration - + Certs are rotated and discarded + properties: + duration: + default: 24h0m0s + description: |- + The requested 'duration' (i.e. lifetime) of the Certificate. + This should comply with golang's ParseDuration format (https://golang.org/pkg/time/#ParseDuration) + type: string + renewBefore: + default: 12h0m0s + description: |- + The amount of time before the currently issued certificate's `notAfter` + time that we will begin to attempt to renew the certificate. + This should comply with golang's ParseDuration format (https://golang.org/pkg/time/#ParseDuration) + type: string + type: object + type: object + commonBootImageNamespace: + description: |- + CommonBootImageNamespace override the default namespace of the common boot images, in order to hide them. + + If not set, HCO won't set any namespace, letting SSP to use the default. If set, use the namespace to create the + DataImportCronTemplates and the common image streams, with this namespace. This field is not set by default. + type: string + commonTemplatesNamespace: + description: |- + CommonTemplatesNamespace defines namespace in which common templates will + be deployed. It overrides the default openshift namespace. + type: string + dataImportCronTemplates: + description: DataImportCronTemplates holds list of data import cron + templates (golden images) + items: + description: |- + DataImportCronTemplate defines the template type for DataImportCrons. + It requires metadata.name to be specified while leaving namespace as optional. + properties: + metadata: + properties: + annotations: + additionalProperties: + type: string + type: object + finalizers: + items: + type: string + type: array + labels: + additionalProperties: + type: string + type: object + name: + type: string + namespace: + type: string + type: object + spec: + description: DataImportCronSpec defines specification for DataImportCron + properties: + garbageCollect: + description: |- + GarbageCollect specifies whether old PVCs should be cleaned up after a new PVC is imported. + Options are currently "Outdated" and "Never", defaults to "Outdated". + type: string + importsToKeep: + description: Number of import PVCs to keep when garbage + collecting. Default is 3. + format: int32 + type: integer + managedDataSource: + description: |- + ManagedDataSource specifies the name of the corresponding DataSource this cron will manage. + DataSource has to be in the same namespace. + type: string + retentionPolicy: + description: RetentionPolicy specifies whether the created + DataVolumes and DataSources are retained when their DataImportCron + is deleted. Default is RatainAll. + type: string + schedule: + description: Schedule specifies in cron format when and + how often to look for new imports + type: string + serviceAccountName: + description: ServiceAccountName is the name of the ServiceAccount + for creating DataVolumes. + minLength: 1 + type: string + template: + description: Template specifies template for the DVs to + be created + properties: + apiVersion: + description: |- + APIVersion defines the versioned schema of this representation of an object. + Servers should convert recognized schemas to the latest internal value, and + may reject unrecognized values. + More info: https://git.k8s.io/community/contributors/devel/sig-architecture/api-conventions.md#resources + type: string + kind: + description: |- + Kind is a string value representing the REST resource this object represents. + Servers may infer this from the endpoint the client submits requests to. + Cannot be updated. + In CamelCase. + More info: https://git.k8s.io/community/contributors/devel/sig-architecture/api-conventions.md#types-kinds + type: string + metadata: + properties: + annotations: + additionalProperties: + type: string + type: object + finalizers: + items: + type: string + type: array + labels: + additionalProperties: + type: string + type: object + name: + type: string + namespace: + type: string + type: object + spec: + description: DataVolumeSpec defines the DataVolume type + specification + properties: + checkpoints: + description: Checkpoints is a list of DataVolumeCheckpoints, + representing stages in a multistage import. + items: + description: DataVolumeCheckpoint defines a stage + in a warm migration. + properties: + current: + description: Current is the identifier of + the snapshot created for this checkpoint. + type: string + previous: + description: Previous is the identifier of + the snapshot from the previous checkpoint. + type: string + required: + - current + - previous + type: object + type: array + contentType: + description: 'DataVolumeContentType options: "kubevirt", + "archive"' + enum: + - kubevirt + - archive + type: string + finalCheckpoint: + description: FinalCheckpoint indicates whether the + current DataVolumeCheckpoint is the final checkpoint. + type: boolean + preallocation: + description: Preallocation controls whether storage + for DataVolumes should be allocated in advance. + type: boolean + priorityClassName: + description: PriorityClassName for Importer, Cloner + and Uploader pod + type: string + pvc: + description: PVC is the PVC specification + properties: + accessModes: + description: |- + accessModes contains the desired access modes the volume should have. + More info: https://kubernetes.io/docs/concepts/storage/persistent-volumes#access-modes-1 + items: + type: string + type: array + x-kubernetes-list-type: atomic + dataSource: + description: |- + dataSource field can be used to specify either: + * An existing VolumeSnapshot object (snapshot.storage.k8s.io/VolumeSnapshot) + * An existing PVC (PersistentVolumeClaim) + If the provisioner or an external controller can support the specified data source, + it will create a new volume based on the contents of the specified data source. + When the AnyVolumeDataSource feature gate is enabled, dataSource contents will be copied to dataSourceRef, + and dataSourceRef contents will be copied to dataSource when dataSourceRef.namespace is not specified. + If the namespace is specified, then dataSourceRef will not be copied to dataSource. + properties: + apiGroup: + description: |- + APIGroup is the group for the resource being referenced. + If APIGroup is not specified, the specified Kind must be in the core API group. + For any other third-party types, APIGroup is required. + type: string + kind: + description: Kind is the type of resource + being referenced + type: string + name: + description: Name is the name of resource + being referenced + type: string + required: + - kind + - name + type: object + x-kubernetes-map-type: atomic + dataSourceRef: + description: |- + dataSourceRef specifies the object from which to populate the volume with data, if a non-empty + volume is desired. This may be any object from a non-empty API group (non + core object) or a PersistentVolumeClaim object. + When this field is specified, volume binding will only succeed if the type of + the specified object matches some installed volume populator or dynamic + provisioner. + This field will replace the functionality of the dataSource field and as such + if both fields are non-empty, they must have the same value. For backwards + compatibility, when namespace isn't specified in dataSourceRef, + both fields (dataSource and dataSourceRef) will be set to the same + value automatically if one of them is empty and the other is non-empty. + When namespace is specified in dataSourceRef, + dataSource isn't set to the same value and must be empty. + There are three important differences between dataSource and dataSourceRef: + * While dataSource only allows two specific types of objects, dataSourceRef + allows any non-core object, as well as PersistentVolumeClaim objects. + * While dataSource ignores disallowed values (dropping them), dataSourceRef + preserves all values, and generates an error if a disallowed value is + specified. + * While dataSource only allows local objects, dataSourceRef allows objects + in any namespaces. + (Beta) Using this field requires the AnyVolumeDataSource feature gate to be enabled. + (Alpha) Using the namespace field of dataSourceRef requires the CrossNamespaceVolumeDataSource feature gate to be enabled. + properties: + apiGroup: + description: |- + APIGroup is the group for the resource being referenced. + If APIGroup is not specified, the specified Kind must be in the core API group. + For any other third-party types, APIGroup is required. + type: string + kind: + description: Kind is the type of resource + being referenced + type: string + name: + description: Name is the name of resource + being referenced + type: string + namespace: + description: |- + Namespace is the namespace of resource being referenced + Note that when a namespace is specified, a gateway.networking.k8s.io/ReferenceGrant object is required in the referent namespace to allow that namespace's owner to accept the reference. See the ReferenceGrant documentation for details. + (Alpha) This field requires the CrossNamespaceVolumeDataSource feature gate to be enabled. + type: string + required: + - kind + - name + type: object + resources: + description: |- + resources represents the minimum resources the volume should have. + If RecoverVolumeExpansionFailure feature is enabled users are allowed to specify resource requirements + that are lower than previous value but must still be higher than capacity recorded in the + status field of the claim. + More info: https://kubernetes.io/docs/concepts/storage/persistent-volumes#resources + properties: + limits: + additionalProperties: + anyOf: + - type: integer + - type: string + pattern: ^(\+|-)?(([0-9]+(\.[0-9]*)?)|(\.[0-9]+))(([KMGTPE]i)|[numkMGTPE]|([eE](\+|-)?(([0-9]+(\.[0-9]*)?)|(\.[0-9]+))))?$ + x-kubernetes-int-or-string: true + description: |- + Limits describes the maximum amount of compute resources allowed. + More info: https://kubernetes.io/docs/concepts/configuration/manage-resources-containers/ + type: object + requests: + additionalProperties: + anyOf: + - type: integer + - type: string + pattern: ^(\+|-)?(([0-9]+(\.[0-9]*)?)|(\.[0-9]+))(([KMGTPE]i)|[numkMGTPE]|([eE](\+|-)?(([0-9]+(\.[0-9]*)?)|(\.[0-9]+))))?$ + x-kubernetes-int-or-string: true + description: |- + Requests describes the minimum amount of compute resources required. + If Requests is omitted for a container, it defaults to Limits if that is explicitly specified, + otherwise to an implementation-defined value. Requests cannot exceed Limits. + More info: https://kubernetes.io/docs/concepts/configuration/manage-resources-containers/ + type: object + type: object + selector: + description: selector is a label query over + volumes to consider for binding. + properties: + matchExpressions: + description: matchExpressions is a list + of label selector requirements. The requirements + are ANDed. + items: + description: |- + A label selector requirement is a selector that contains values, a key, and an operator that + relates the key and values. + properties: + key: + description: key is the label key + that the selector applies to. + type: string + operator: + description: |- + operator represents a key's relationship to a set of values. + Valid operators are In, NotIn, Exists and DoesNotExist. + type: string + values: + description: |- + values is an array of string values. If the operator is In or NotIn, + the values array must be non-empty. If the operator is Exists or DoesNotExist, + the values array must be empty. This array is replaced during a strategic + merge patch. + items: + type: string + type: array + x-kubernetes-list-type: atomic + required: + - key + - operator + type: object + type: array + x-kubernetes-list-type: atomic + matchLabels: + additionalProperties: + type: string + description: |- + matchLabels is a map of {key,value} pairs. A single {key,value} in the matchLabels + map is equivalent to an element of matchExpressions, whose key field is "key", the + operator is "In", and the values array contains only "value". The requirements are ANDed. + type: object + type: object + x-kubernetes-map-type: atomic + storageClassName: + description: |- + storageClassName is the name of the StorageClass required by the claim. + More info: https://kubernetes.io/docs/concepts/storage/persistent-volumes#class-1 + type: string + volumeAttributesClassName: + description: |- + volumeAttributesClassName may be used to set the VolumeAttributesClass used by this claim. + If specified, the CSI driver will create or update the volume with the attributes defined + in the corresponding VolumeAttributesClass. This has a different purpose than storageClassName, + it can be changed after the claim is created. An empty string or nil value indicates that no + VolumeAttributesClass will be applied to the claim. If the claim enters an Infeasible error state, + this field can be reset to its previous value (including nil) to cancel the modification. + If the resource referred to by volumeAttributesClass does not exist, this PersistentVolumeClaim will be + set to a Pending state, as reflected by the modifyVolumeStatus field, until such as a resource + exists. + More info: https://kubernetes.io/docs/concepts/storage/volume-attributes-classes/ + type: string + volumeMode: + description: |- + volumeMode defines what type of volume is required by the claim. + Value of Filesystem is implied when not included in claim spec. + type: string + volumeName: + description: volumeName is the binding reference + to the PersistentVolume backing this claim. + type: string + type: object + source: + description: Source is the src of the data for the + requested DataVolume + properties: + blank: + description: DataVolumeBlankImage provides the + parameters to create a new raw blank image + for the PVC + type: object + gcs: + description: DataVolumeSourceGCS provides the + parameters to create a Data Volume from an + GCS source + properties: + secretRef: + description: SecretRef provides the secret + reference needed to access the GCS source + type: string + url: + description: URL is the url of the GCS source + type: string + required: + - url + type: object + http: + description: DataVolumeSourceHTTP can be either + an http or https endpoint, with an optional + basic auth user name and password, and an + optional configmap containing additional CAs + properties: + certConfigMap: + description: CertConfigMap is a configmap + reference, containing a Certificate Authority(CA) + public key, and a base64 encoded pem certificate + type: string + extraHeaders: + description: ExtraHeaders is a list of strings + containing extra headers to include with + HTTP transfer requests + items: + type: string + type: array + secretExtraHeaders: + description: SecretExtraHeaders is a list + of Secret references, each containing + an extra HTTP header that may include + sensitive information + items: + type: string + type: array + secretRef: + description: SecretRef A Secret reference, + the secret should contain accessKeyId + (user name) base64 encoded, and secretKey + (password) also base64 encoded + type: string + url: + description: URL is the URL of the http(s) + endpoint + type: string + required: + - url + type: object + imageio: + description: DataVolumeSourceImageIO provides + the parameters to create a Data Volume from + an imageio source + properties: + certConfigMap: + description: CertConfigMap provides a reference + to the CA cert + type: string + diskId: + description: DiskID provides id of a disk + to be imported + type: string + insecureSkipVerify: + description: InsecureSkipVerify is a flag + to skip certificate verification + type: boolean + secretRef: + description: SecretRef provides the secret + reference needed to access the ovirt-engine + type: string + url: + description: URL is the URL of the ovirt-engine + type: string + required: + - diskId + - url + type: object + pvc: + description: DataVolumeSourcePVC provides the + parameters to create a Data Volume from an + existing PVC + properties: + name: + description: The name of the source PVC + type: string + namespace: + description: The namespace of the source + PVC + type: string + required: + - name + - namespace + type: object + registry: + description: DataVolumeSourceRegistry provides + the parameters to create a Data Volume from + an registry source + properties: + certConfigMap: + description: CertConfigMap provides a reference + to the Registry certs + type: string + imageStream: + description: ImageStream is the name of + image stream for import + type: string + platform: + description: Platform describes the minimum + runtime requirements of the image + properties: + architecture: + description: Architecture specifies + the image target CPU architecture + type: string + type: object + pullMethod: + description: PullMethod can be either "pod" + (default import), or "node" (node docker + cache based import) + type: string + secretRef: + description: SecretRef provides the secret + reference needed to access the Registry + source + type: string + url: + description: 'URL is the url of the registry + source (starting with the scheme: docker, + oci-archive)' + type: string + type: object + s3: + description: DataVolumeSourceS3 provides the + parameters to create a Data Volume from an + S3 source + properties: + certConfigMap: + description: CertConfigMap is a configmap + reference, containing a Certificate Authority(CA) + public key, and a base64 encoded pem certificate + type: string + secretRef: + description: SecretRef provides the secret + reference needed to access the S3 source + type: string + url: + description: URL is the url of the S3 source + type: string + required: + - url + type: object + snapshot: + description: DataVolumeSourceSnapshot provides + the parameters to create a Data Volume from + an existing VolumeSnapshot + properties: + name: + description: The name of the source VolumeSnapshot + type: string + namespace: + description: The namespace of the source + VolumeSnapshot + type: string + required: + - name + - namespace + type: object + upload: + description: DataVolumeSourceUpload provides + the parameters to create a Data Volume by + uploading the source + type: object + vddk: + description: DataVolumeSourceVDDK provides the + parameters to create a Data Volume from a + Vmware source + properties: + backingFile: + description: BackingFile is the path to + the virtual hard disk to migrate from + vCenter/ESXi + type: string + extraArgs: + description: ExtraArgs is a reference to + a ConfigMap containing extra arguments + to pass directly to the VDDK library + type: string + initImageURL: + description: InitImageURL is an optional + URL to an image containing an extracted + VDDK library, overrides v2v-vmware config + map + type: string + secretRef: + description: SecretRef provides a reference + to a secret containing the username and + password needed to access the vCenter + or ESXi host + type: string + thumbprint: + description: Thumbprint is the certificate + thumbprint of the vCenter or ESXi host + type: string + url: + description: URL is the URL of the vCenter + or ESXi host with the VM to migrate + type: string + uuid: + description: UUID is the UUID of the virtual + machine that the backing file is attached + to in vCenter/ESXi + type: string + type: object + type: object + sourceRef: + description: SourceRef is an indirect reference + to the source of data for the requested DataVolume + properties: + kind: + description: The kind of the source reference, + currently only "DataSource" is supported + type: string + name: + description: The name of the source reference + type: string + namespace: + description: The namespace of the source reference, + defaults to the DataVolume namespace + type: string + required: + - kind + - name + type: object + storage: + description: Storage is the requested storage specification + properties: + accessModes: + description: |- + AccessModes contains the desired access modes the volume should have. + More info: https://kubernetes.io/docs/concepts/storage/persistent-volumes#access-modes-1 + items: + type: string + type: array + dataSource: + description: |- + This field can be used to specify either: * An existing VolumeSnapshot object (snapshot.storage.k8s.io/VolumeSnapshot) * An existing PVC (PersistentVolumeClaim) * An existing custom resource that implements data population (Alpha) In order to use custom resource types that implement data population, the AnyVolumeDataSource feature gate must be enabled. If the provisioner or an external controller can support the specified data source, it will create a new volume based on the contents of the specified data source. + If the AnyVolumeDataSource feature gate is enabled, this field will always have the same contents as the DataSourceRef field. + properties: + apiGroup: + description: |- + APIGroup is the group for the resource being referenced. + If APIGroup is not specified, the specified Kind must be in the core API group. + For any other third-party types, APIGroup is required. + type: string + kind: + description: Kind is the type of resource + being referenced + type: string + name: + description: Name is the name of resource + being referenced + type: string + required: + - kind + - name + type: object + x-kubernetes-map-type: atomic + dataSourceRef: + description: |- + Specifies the object from which to populate the volume with data, if a non-empty volume is desired. This may be any local object from a non-empty API group (non core object) or a PersistentVolumeClaim object. When this field is specified, volume binding will only succeed if the type of the specified object matches some installed volume populator or dynamic provisioner. + This field will replace the functionality of the DataSource field and as such if both fields are non-empty, they must have the same value. For backwards compatibility, both fields (DataSource and DataSourceRef) will be set to the same value automatically if one of them is empty and the other is non-empty. + There are two important differences between DataSource and DataSourceRef: + * While DataSource only allows two specific types of objects, DataSourceRef allows any non-core object, as well as PersistentVolumeClaim objects. + * While DataSource ignores disallowed values (dropping them), DataSourceRef preserves all values, and generates an error if a disallowed value is specified. + (Beta) Using this field requires the AnyVolumeDataSource feature gate to be enabled. + properties: + apiGroup: + description: |- + APIGroup is the group for the resource being referenced. + If APIGroup is not specified, the specified Kind must be in the core API group. + For any other third-party types, APIGroup is required. + type: string + kind: + description: Kind is the type of resource + being referenced + type: string + name: + description: Name is the name of resource + being referenced + type: string + namespace: + description: |- + Namespace is the namespace of resource being referenced + Note that when a namespace is specified, a gateway.networking.k8s.io/ReferenceGrant object is required in the referent namespace to allow that namespace's owner to accept the reference. See the ReferenceGrant documentation for details. + (Alpha) This field requires the CrossNamespaceVolumeDataSource feature gate to be enabled. + type: string + required: + - kind + - name + type: object + resources: + description: |- + Resources represents the minimum resources the volume should have. + More info: https://kubernetes.io/docs/concepts/storage/persistent-volumes#resources + properties: + limits: + additionalProperties: + anyOf: + - type: integer + - type: string + pattern: ^(\+|-)?(([0-9]+(\.[0-9]*)?)|(\.[0-9]+))(([KMGTPE]i)|[numkMGTPE]|([eE](\+|-)?(([0-9]+(\.[0-9]*)?)|(\.[0-9]+))))?$ + x-kubernetes-int-or-string: true + description: |- + Limits describes the maximum amount of compute resources allowed. + More info: https://kubernetes.io/docs/concepts/configuration/manage-resources-containers/ + type: object + requests: + additionalProperties: + anyOf: + - type: integer + - type: string + pattern: ^(\+|-)?(([0-9]+(\.[0-9]*)?)|(\.[0-9]+))(([KMGTPE]i)|[numkMGTPE]|([eE](\+|-)?(([0-9]+(\.[0-9]*)?)|(\.[0-9]+))))?$ + x-kubernetes-int-or-string: true + description: |- + Requests describes the minimum amount of compute resources required. + If Requests is omitted for a container, it defaults to Limits if that is explicitly specified, + otherwise to an implementation-defined value. Requests cannot exceed Limits. + More info: https://kubernetes.io/docs/concepts/configuration/manage-resources-containers/ + type: object + type: object + selector: + description: A label query over volumes to consider + for binding. + properties: + matchExpressions: + description: matchExpressions is a list + of label selector requirements. The requirements + are ANDed. + items: + description: |- + A label selector requirement is a selector that contains values, a key, and an operator that + relates the key and values. + properties: + key: + description: key is the label key + that the selector applies to. + type: string + operator: + description: |- + operator represents a key's relationship to a set of values. + Valid operators are In, NotIn, Exists and DoesNotExist. + type: string + values: + description: |- + values is an array of string values. If the operator is In or NotIn, + the values array must be non-empty. If the operator is Exists or DoesNotExist, + the values array must be empty. This array is replaced during a strategic + merge patch. + items: + type: string + type: array + x-kubernetes-list-type: atomic + required: + - key + - operator + type: object + type: array + x-kubernetes-list-type: atomic + matchLabels: + additionalProperties: + type: string + description: |- + matchLabels is a map of {key,value} pairs. A single {key,value} in the matchLabels + map is equivalent to an element of matchExpressions, whose key field is "key", the + operator is "In", and the values array contains only "value". The requirements are ANDed. + type: object + type: object + x-kubernetes-map-type: atomic + storageClassName: + description: |- + Name of the StorageClass required by the claim. + More info: https://kubernetes.io/docs/concepts/storage/persistent-volumes#class-1 + type: string + volumeMode: + description: |- + volumeMode defines what type of volume is required by the claim. + Value of Filesystem is implied when not included in claim spec. + type: string + volumeName: + description: VolumeName is the binding reference + to the PersistentVolume backing this claim. + type: string + type: object + type: object + status: + description: DataVolumeStatus contains the current status + of the DataVolume + properties: + claimName: + description: ClaimName is the name of the underlying + PVC used by the DataVolume. + type: string + conditions: + items: + description: DataVolumeCondition represents the + state of a data volume condition. + properties: + lastHeartbeatTime: + format: date-time + type: string + lastTransitionTime: + format: date-time + type: string + message: + type: string + reason: + type: string + status: + type: string + type: + description: DataVolumeConditionType is the + string representation of known condition + types + type: string + required: + - status + - type + type: object + type: array + phase: + description: Phase is the current phase of the data + volume + type: string + progress: + description: DataVolumeProgress is the current progress + of the DataVolume transfer operation. Value between + 0 and 100 inclusive, N/A if not available + type: string + restartCount: + description: RestartCount is the number of times + the pod populating the DataVolume has restarted + format: int32 + type: integer + type: object + required: + - spec + type: object + required: + - managedDataSource + - schedule + - template + type: object + type: object + type: array + x-kubernetes-list-type: atomic + defaultCPUModel: + description: |- + DefaultCPUModel defines a cluster default for CPU model: default CPU model is set when VMI doesn't have any CPU model. + When VMI has CPU model set, then VMI's CPU model is preferred. + When default CPU model is not set and VMI's CPU model is not set too, host-model will be set. + Default CPU model can be changed when kubevirt is running. + type: string + defaultRuntimeClass: + description: |- + DefaultRuntimeClass defines a cluster default for the RuntimeClass to be used for VMIs pods if not set there. + Default RuntimeClass can be changed when kubevirt is running, existing VMIs are not impacted till + the next restart/live-migration when they are eventually going to consume the new default RuntimeClass. + type: string + deployVmConsoleProxy: + default: false + description: deploy VM console proxy resources in SSP operator + type: boolean + enableApplicationAwareQuota: + default: false + description: EnableApplicationAwareQuota if true, enables the Application + Aware Quota feature + type: boolean + enableCommonBootImageImport: + default: true + description: |- + Opt-in to automatic delivery/updates of the common data import cron templates. + There are two sources for the data import cron templates: hard coded list of common templates, and custom (user + defined) templates that can be added to the dataImportCronTemplates field. This field only controls the common + templates. It is possible to use custom templates by adding them to the dataImportCronTemplates field. + type: boolean + evictionStrategy: + description: |- + EvictionStrategy defines at the cluster level if the VirtualMachineInstance should be + migrated instead of shut-off in case of a node drain. If the VirtualMachineInstance specific + field is set it overrides the cluster level one. + Allowed values: + - `None` no eviction strategy at cluster level. + - `LiveMigrate` migrate the VM on eviction; a not live migratable VM with no specific strategy will block the drain of the node util manually evicted. + - `LiveMigrateIfPossible` migrate the VM on eviction if live migration is possible, otherwise directly evict. + - `External` block the drain, track eviction and notify an external controller. + Defaults to LiveMigrate with multiple worker nodes, None on single worker clusters. + enum: + - None + - LiveMigrate + - LiveMigrateIfPossible + - External + type: string + featureGates: + description: |- + FeatureGates is a set of optional feature gates to enable or disable new + features that are not generally available yet. + Add a new FeatureGate Object to this set, to enable a feature that is + disabled by default, or to disable a feature that is enabled by default. + + A feature gate may be in the following phases: + * Alpha: the feature is in dev-preview. It is disabled by default, but can + be enabled. + * Beta: the feature gate is in tech-preview. It is enabled by default, but + can be disabled. + * GA: the feature is graduated and is always enabled. There is no way to + disable it. + * Deprecated: the feature is no longer supported. There is no way to enable + it + + Feature-Gate list: + * alignCPUs: + Enable KubeVirt to request up to two additional dedicated CPUs in order to + complete the total CPU count to an even parity when using emulator thread + isolation. + Note: this feature is in Developer Preview. + Phase: Alpha + + * decentralizedLiveMigration: + enables the decentralized live migration (cross-cluster migration) feature. + This feature allows live migration of VirtualMachineInstances between + different clusters. + Note: This feature is in Developer Preview. + Phase: Alpha + + * declarativeHotplugVolumes: + enables the use of the declarative volume hotplug feature in KubeVirt. + When enabled, the "DeclarativeHotplugVolumes" feature gate is enabled in + the KubeVirt CR, instead of the "HotplugVolumes" feature gate. + When disabled, the "HotplugVolumes" feature gate is enabled (default + behavior). + Phase: Alpha + + * deployKubeSecondaryDNS: + Deploy KubeSecondaryDNS by CNAO + Phase: Alpha + + * disableMDevConfiguration: + Disable mediated devices handling on KubeVirt + Phase: Alpha + + * downwardMetrics: + Allow to expose a limited set of host metrics to guests. + Phase: Alpha + + * enableMultiArchBootImageImport: + allows the HCO to run on heterogeneous clusters with different CPU + architectures. + Enabling this feature gate will allow the HCO to create Golden Images for + different CPU architectures. + Phase: Alpha + + * objectGraph: + enables the ObjectGraph VM and VMI subresource in KubeVirt. + This subresource returns a structured list of k8s objects that are related + to the specified VM or VMI, enabling better dependency tracking. + Phase: Alpha + + * persistentReservation: + Enable persistent reservation of a LUN through the SCSI Persistent Reserve + commands on Kubevirt. + In order to issue privileged SCSI ioctls, the VM requires activation of the + persistent reservation flag. + Once this feature gate is enabled, then the additional container with the + qemu-pr-helper is deployed inside the virt-handler pod. + Enabling (or removing) the feature gate causes the redeployment of the + virt-handler pod. + Phase: Alpha + + * videoConfig: + allows users to configure video device types for their virtual machines. + This can be useful for workloads that require specific video capabilities + or architectures. + Phase: Beta + + * autoResourceLimits: + Phase: Deprecated + + * deployKubevirtIpamController: + Phase: Deprecated + + * deployTektonTaskResources: + Phase: Deprecated + + * deployVmConsoleProxy: + Phase: Deprecated + + * enableApplicationAwareQuota: + This feature gate is ignored. Use spec.enableApplicationAwareQuota field instead + Phase: Deprecated + + * enableCommonBootImageImport: + This feature gate is ignored. Use spec.enableCommonBootImageImport field instead + Phase: Deprecated + + * enableManagedTenantQuota: + Phase: Deprecated + + * nonRoot: + Phase: Deprecated + + * primaryUserDefinedNetworkBinding: + Phase: Deprecated + + * withHostPassthroughCPU: + Phase: Deprecated + items: + description: FeatureGate is an optional feature gate to enable or + disable a new feature that is not generally available yet. + properties: + name: + description: Name is the feature gate name + type: string + state: + description: State determines if the feature gate is enabled + ("Enabled"), or disabled ("False"). The default value is "Disabled". + enum: + - Enabled + - Disabled + type: string + required: + - name + type: object + type: array + filesystemOverhead: + description: |- + FilesystemOverhead describes the space reserved for overhead when using Filesystem volumes. + A value is between 0 and 1, if not defined it is 0.055 (5.5 percent overhead) + properties: + global: + description: Global is how much space of a Filesystem volume should + be reserved for overhead. This value is used unless overridden + by a more specific value (per storageClass) + pattern: ^(0(?:\.\d{1,3})?|1)$ + type: string + storageClass: + additionalProperties: + description: |- + Percent is a string that can only be a value between [0,1) + (Note: we actually rely on reconcile to reject invalid values) + pattern: ^(0(?:\.\d{1,3})?|1)$ + type: string + description: StorageClass specifies how much space of a Filesystem + volume should be reserved for safety. The keys are the storageClass + and the values are the overhead. This value overrides the global + value + type: object + type: object + higherWorkloadDensity: + default: + memoryOvercommitPercentage: 100 + description: HigherWorkloadDensity holds configuration aimed to increase + virtual machine density + properties: + memoryOvercommitPercentage: + default: 100 + description: |- + MemoryOvercommitPercentage is the percentage of memory we want to give VMIs compared to the amount + given to its parent pod (virt-launcher). For example, a value of 102 means the VMI will + "see" 2% more memory than its parent pod. Values under 100 are effectively "undercommits". + Overcommits can lead to memory exhaustion, which in turn can lead to crashes. Use carefully. + minimum: 10 + type: integer + type: object + infra: + description: |- + infra HyperConvergedConfig influences the pod configuration (currently only placement) + for all the infra components needed on the virtualization enabled cluster + but not necessarily directly on each node running VMs/VMIs. + properties: + nodePlacement: + description: NodePlacement describes node scheduling configuration. + properties: + affinity: + description: |- + affinity enables pod affinity/anti-affinity placement expanding the types of constraints + that can be expressed with nodeSelector. + affinity is going to be applied to the relevant kind of pods in parallel with nodeSelector + See https://kubernetes.io/docs/concepts/scheduling-eviction/assign-pod-node/#affinity-and-anti-affinity + properties: + nodeAffinity: + description: Describes node affinity scheduling rules + for the pod. + properties: + preferredDuringSchedulingIgnoredDuringExecution: + description: |- + The scheduler will prefer to schedule pods to nodes that satisfy + the affinity expressions specified by this field, but it may choose + a node that violates one or more of the expressions. The node that is + most preferred is the one with the greatest sum of weights, i.e. + for each node that meets all of the scheduling requirements (resource + request, requiredDuringScheduling affinity expressions, etc.), + compute a sum by iterating through the elements of this field and adding + "weight" to the sum if the node matches the corresponding matchExpressions; the + node(s) with the highest sum are the most preferred. + items: + description: |- + An empty preferred scheduling term matches all objects with implicit weight 0 + (i.e. it's a no-op). A null preferred scheduling term matches no objects (i.e. is also a no-op). + properties: + preference: + description: A node selector term, associated + with the corresponding weight. + properties: + matchExpressions: + description: A list of node selector requirements + by node's labels. + items: + description: |- + A node selector requirement is a selector that contains values, a key, and an operator + that relates the key and values. + properties: + key: + description: The label key that the + selector applies to. + type: string + operator: + description: |- + Represents a key's relationship to a set of values. + Valid operators are In, NotIn, Exists, DoesNotExist. Gt, and Lt. + type: string + values: + description: |- + An array of string values. If the operator is In or NotIn, + the values array must be non-empty. If the operator is Exists or DoesNotExist, + the values array must be empty. If the operator is Gt or Lt, the values + array must have a single element, which will be interpreted as an integer. + This array is replaced during a strategic merge patch. + items: + type: string + type: array + x-kubernetes-list-type: atomic + required: + - key + - operator + type: object + type: array + x-kubernetes-list-type: atomic + matchFields: + description: A list of node selector requirements + by node's fields. + items: + description: |- + A node selector requirement is a selector that contains values, a key, and an operator + that relates the key and values. + properties: + key: + description: The label key that the + selector applies to. + type: string + operator: + description: |- + Represents a key's relationship to a set of values. + Valid operators are In, NotIn, Exists, DoesNotExist. Gt, and Lt. + type: string + values: + description: |- + An array of string values. If the operator is In or NotIn, + the values array must be non-empty. If the operator is Exists or DoesNotExist, + the values array must be empty. If the operator is Gt or Lt, the values + array must have a single element, which will be interpreted as an integer. + This array is replaced during a strategic merge patch. + items: + type: string + type: array + x-kubernetes-list-type: atomic + required: + - key + - operator + type: object + type: array + x-kubernetes-list-type: atomic + type: object + x-kubernetes-map-type: atomic + weight: + description: Weight associated with matching + the corresponding nodeSelectorTerm, in the + range 1-100. + format: int32 + type: integer + required: + - preference + - weight + type: object + type: array + x-kubernetes-list-type: atomic + requiredDuringSchedulingIgnoredDuringExecution: + description: |- + If the affinity requirements specified by this field are not met at + scheduling time, the pod will not be scheduled onto the node. + If the affinity requirements specified by this field cease to be met + at some point during pod execution (e.g. due to an update), the system + may or may not try to eventually evict the pod from its node. + properties: + nodeSelectorTerms: + description: Required. A list of node selector + terms. The terms are ORed. + items: + description: |- + A null or empty node selector term matches no objects. The requirements of + them are ANDed. + The TopologySelectorTerm type implements a subset of the NodeSelectorTerm. + properties: + matchExpressions: + description: A list of node selector requirements + by node's labels. + items: + description: |- + A node selector requirement is a selector that contains values, a key, and an operator + that relates the key and values. + properties: + key: + description: The label key that the + selector applies to. + type: string + operator: + description: |- + Represents a key's relationship to a set of values. + Valid operators are In, NotIn, Exists, DoesNotExist. Gt, and Lt. + type: string + values: + description: |- + An array of string values. If the operator is In or NotIn, + the values array must be non-empty. If the operator is Exists or DoesNotExist, + the values array must be empty. If the operator is Gt or Lt, the values + array must have a single element, which will be interpreted as an integer. + This array is replaced during a strategic merge patch. + items: + type: string + type: array + x-kubernetes-list-type: atomic + required: + - key + - operator + type: object + type: array + x-kubernetes-list-type: atomic + matchFields: + description: A list of node selector requirements + by node's fields. + items: + description: |- + A node selector requirement is a selector that contains values, a key, and an operator + that relates the key and values. + properties: + key: + description: The label key that the + selector applies to. + type: string + operator: + description: |- + Represents a key's relationship to a set of values. + Valid operators are In, NotIn, Exists, DoesNotExist. Gt, and Lt. + type: string + values: + description: |- + An array of string values. If the operator is In or NotIn, + the values array must be non-empty. If the operator is Exists or DoesNotExist, + the values array must be empty. If the operator is Gt or Lt, the values + array must have a single element, which will be interpreted as an integer. + This array is replaced during a strategic merge patch. + items: + type: string + type: array + x-kubernetes-list-type: atomic + required: + - key + - operator + type: object + type: array + x-kubernetes-list-type: atomic + type: object + x-kubernetes-map-type: atomic + type: array + x-kubernetes-list-type: atomic + required: + - nodeSelectorTerms + type: object + x-kubernetes-map-type: atomic + type: object + podAffinity: + description: Describes pod affinity scheduling rules (e.g. + co-locate this pod in the same node, zone, etc. as some + other pod(s)). + properties: + preferredDuringSchedulingIgnoredDuringExecution: + description: |- + The scheduler will prefer to schedule pods to nodes that satisfy + the affinity expressions specified by this field, but it may choose + a node that violates one or more of the expressions. The node that is + most preferred is the one with the greatest sum of weights, i.e. + for each node that meets all of the scheduling requirements (resource + request, requiredDuringScheduling affinity expressions, etc.), + compute a sum by iterating through the elements of this field and adding + "weight" to the sum if the node has pods which matches the corresponding podAffinityTerm; the + node(s) with the highest sum are the most preferred. + items: + description: The weights of all of the matched WeightedPodAffinityTerm + fields are added per-node to find the most preferred + node(s) + properties: + podAffinityTerm: + description: Required. A pod affinity term, + associated with the corresponding weight. + properties: + labelSelector: + description: |- + A label query over a set of resources, in this case pods. + If it's null, this PodAffinityTerm matches with no Pods. + properties: + matchExpressions: + description: matchExpressions is a list + of label selector requirements. The + requirements are ANDed. + items: + description: |- + A label selector requirement is a selector that contains values, a key, and an operator that + relates the key and values. + properties: + key: + description: key is the label + key that the selector applies + to. + type: string + operator: + description: |- + operator represents a key's relationship to a set of values. + Valid operators are In, NotIn, Exists and DoesNotExist. + type: string + values: + description: |- + values is an array of string values. If the operator is In or NotIn, + the values array must be non-empty. If the operator is Exists or DoesNotExist, + the values array must be empty. This array is replaced during a strategic + merge patch. + items: + type: string + type: array + x-kubernetes-list-type: atomic + required: + - key + - operator + type: object + type: array + x-kubernetes-list-type: atomic + matchLabels: + additionalProperties: + type: string + description: |- + matchLabels is a map of {key,value} pairs. A single {key,value} in the matchLabels + map is equivalent to an element of matchExpressions, whose key field is "key", the + operator is "In", and the values array contains only "value". The requirements are ANDed. + type: object + type: object + x-kubernetes-map-type: atomic + matchLabelKeys: + description: |- + MatchLabelKeys is a set of pod label keys to select which pods will + be taken into consideration. The keys are used to lookup values from the + incoming pod labels, those key-value labels are merged with `labelSelector` as `key in (value)` + to select the group of existing pods which pods will be taken into consideration + for the incoming pod's pod (anti) affinity. Keys that don't exist in the incoming + pod labels will be ignored. The default value is empty. + The same key is forbidden to exist in both matchLabelKeys and labelSelector. + Also, matchLabelKeys cannot be set when labelSelector isn't set. + items: + type: string + type: array + x-kubernetes-list-type: atomic + mismatchLabelKeys: + description: |- + MismatchLabelKeys is a set of pod label keys to select which pods will + be taken into consideration. The keys are used to lookup values from the + incoming pod labels, those key-value labels are merged with `labelSelector` as `key notin (value)` + to select the group of existing pods which pods will be taken into consideration + for the incoming pod's pod (anti) affinity. Keys that don't exist in the incoming + pod labels will be ignored. The default value is empty. + The same key is forbidden to exist in both mismatchLabelKeys and labelSelector. + Also, mismatchLabelKeys cannot be set when labelSelector isn't set. + items: + type: string + type: array + x-kubernetes-list-type: atomic + namespaceSelector: + description: |- + A label query over the set of namespaces that the term applies to. + The term is applied to the union of the namespaces selected by this field + and the ones listed in the namespaces field. + null selector and null or empty namespaces list means "this pod's namespace". + An empty selector ({}) matches all namespaces. + properties: + matchExpressions: + description: matchExpressions is a list + of label selector requirements. The + requirements are ANDed. + items: + description: |- + A label selector requirement is a selector that contains values, a key, and an operator that + relates the key and values. + properties: + key: + description: key is the label + key that the selector applies + to. + type: string + operator: + description: |- + operator represents a key's relationship to a set of values. + Valid operators are In, NotIn, Exists and DoesNotExist. + type: string + values: + description: |- + values is an array of string values. If the operator is In or NotIn, + the values array must be non-empty. If the operator is Exists or DoesNotExist, + the values array must be empty. This array is replaced during a strategic + merge patch. + items: + type: string + type: array + x-kubernetes-list-type: atomic + required: + - key + - operator + type: object + type: array + x-kubernetes-list-type: atomic + matchLabels: + additionalProperties: + type: string + description: |- + matchLabels is a map of {key,value} pairs. A single {key,value} in the matchLabels + map is equivalent to an element of matchExpressions, whose key field is "key", the + operator is "In", and the values array contains only "value". The requirements are ANDed. + type: object + type: object + x-kubernetes-map-type: atomic + namespaces: + description: |- + namespaces specifies a static list of namespace names that the term applies to. + The term is applied to the union of the namespaces listed in this field + and the ones selected by namespaceSelector. + null or empty namespaces list and null namespaceSelector means "this pod's namespace". + items: + type: string + type: array + x-kubernetes-list-type: atomic + topologyKey: + description: |- + This pod should be co-located (affinity) or not co-located (anti-affinity) with the pods matching + the labelSelector in the specified namespaces, where co-located is defined as running on a node + whose value of the label with key topologyKey matches that of any node on which any of the + selected pods is running. + Empty topologyKey is not allowed. + type: string + required: + - topologyKey + type: object + weight: + description: |- + weight associated with matching the corresponding podAffinityTerm, + in the range 1-100. + format: int32 + type: integer + required: + - podAffinityTerm + - weight + type: object + type: array + x-kubernetes-list-type: atomic + requiredDuringSchedulingIgnoredDuringExecution: + description: |- + If the affinity requirements specified by this field are not met at + scheduling time, the pod will not be scheduled onto the node. + If the affinity requirements specified by this field cease to be met + at some point during pod execution (e.g. due to a pod label update), the + system may or may not try to eventually evict the pod from its node. + When there are multiple elements, the lists of nodes corresponding to each + podAffinityTerm are intersected, i.e. all terms must be satisfied. + items: + description: |- + Defines a set of pods (namely those matching the labelSelector + relative to the given namespace(s)) that this pod should be + co-located (affinity) or not co-located (anti-affinity) with, + where co-located is defined as running on a node whose value of + the label with key matches that of any node on which + a pod of the set of pods is running + properties: + labelSelector: + description: |- + A label query over a set of resources, in this case pods. + If it's null, this PodAffinityTerm matches with no Pods. + properties: + matchExpressions: + description: matchExpressions is a list + of label selector requirements. The requirements + are ANDed. + items: + description: |- + A label selector requirement is a selector that contains values, a key, and an operator that + relates the key and values. + properties: + key: + description: key is the label key + that the selector applies to. + type: string + operator: + description: |- + operator represents a key's relationship to a set of values. + Valid operators are In, NotIn, Exists and DoesNotExist. + type: string + values: + description: |- + values is an array of string values. If the operator is In or NotIn, + the values array must be non-empty. If the operator is Exists or DoesNotExist, + the values array must be empty. This array is replaced during a strategic + merge patch. + items: + type: string + type: array + x-kubernetes-list-type: atomic + required: + - key + - operator + type: object + type: array + x-kubernetes-list-type: atomic + matchLabels: + additionalProperties: + type: string + description: |- + matchLabels is a map of {key,value} pairs. A single {key,value} in the matchLabels + map is equivalent to an element of matchExpressions, whose key field is "key", the + operator is "In", and the values array contains only "value". The requirements are ANDed. + type: object + type: object + x-kubernetes-map-type: atomic + matchLabelKeys: + description: |- + MatchLabelKeys is a set of pod label keys to select which pods will + be taken into consideration. The keys are used to lookup values from the + incoming pod labels, those key-value labels are merged with `labelSelector` as `key in (value)` + to select the group of existing pods which pods will be taken into consideration + for the incoming pod's pod (anti) affinity. Keys that don't exist in the incoming + pod labels will be ignored. The default value is empty. + The same key is forbidden to exist in both matchLabelKeys and labelSelector. + Also, matchLabelKeys cannot be set when labelSelector isn't set. + items: + type: string + type: array + x-kubernetes-list-type: atomic + mismatchLabelKeys: + description: |- + MismatchLabelKeys is a set of pod label keys to select which pods will + be taken into consideration. The keys are used to lookup values from the + incoming pod labels, those key-value labels are merged with `labelSelector` as `key notin (value)` + to select the group of existing pods which pods will be taken into consideration + for the incoming pod's pod (anti) affinity. Keys that don't exist in the incoming + pod labels will be ignored. The default value is empty. + The same key is forbidden to exist in both mismatchLabelKeys and labelSelector. + Also, mismatchLabelKeys cannot be set when labelSelector isn't set. + items: + type: string + type: array + x-kubernetes-list-type: atomic + namespaceSelector: + description: |- + A label query over the set of namespaces that the term applies to. + The term is applied to the union of the namespaces selected by this field + and the ones listed in the namespaces field. + null selector and null or empty namespaces list means "this pod's namespace". + An empty selector ({}) matches all namespaces. + properties: + matchExpressions: + description: matchExpressions is a list + of label selector requirements. The requirements + are ANDed. + items: + description: |- + A label selector requirement is a selector that contains values, a key, and an operator that + relates the key and values. + properties: + key: + description: key is the label key + that the selector applies to. + type: string + operator: + description: |- + operator represents a key's relationship to a set of values. + Valid operators are In, NotIn, Exists and DoesNotExist. + type: string + values: + description: |- + values is an array of string values. If the operator is In or NotIn, + the values array must be non-empty. If the operator is Exists or DoesNotExist, + the values array must be empty. This array is replaced during a strategic + merge patch. + items: + type: string + type: array + x-kubernetes-list-type: atomic + required: + - key + - operator + type: object + type: array + x-kubernetes-list-type: atomic + matchLabels: + additionalProperties: + type: string + description: |- + matchLabels is a map of {key,value} pairs. A single {key,value} in the matchLabels + map is equivalent to an element of matchExpressions, whose key field is "key", the + operator is "In", and the values array contains only "value". The requirements are ANDed. + type: object + type: object + x-kubernetes-map-type: atomic + namespaces: + description: |- + namespaces specifies a static list of namespace names that the term applies to. + The term is applied to the union of the namespaces listed in this field + and the ones selected by namespaceSelector. + null or empty namespaces list and null namespaceSelector means "this pod's namespace". + items: + type: string + type: array + x-kubernetes-list-type: atomic + topologyKey: + description: |- + This pod should be co-located (affinity) or not co-located (anti-affinity) with the pods matching + the labelSelector in the specified namespaces, where co-located is defined as running on a node + whose value of the label with key topologyKey matches that of any node on which any of the + selected pods is running. + Empty topologyKey is not allowed. + type: string + required: + - topologyKey + type: object + type: array + x-kubernetes-list-type: atomic + type: object + podAntiAffinity: + description: Describes pod anti-affinity scheduling rules + (e.g. avoid putting this pod in the same node, zone, + etc. as some other pod(s)). + properties: + preferredDuringSchedulingIgnoredDuringExecution: + description: |- + The scheduler will prefer to schedule pods to nodes that satisfy + the anti-affinity expressions specified by this field, but it may choose + a node that violates one or more of the expressions. The node that is + most preferred is the one with the greatest sum of weights, i.e. + for each node that meets all of the scheduling requirements (resource + request, requiredDuringScheduling anti-affinity expressions, etc.), + compute a sum by iterating through the elements of this field and subtracting + "weight" from the sum if the node has pods which matches the corresponding podAffinityTerm; the + node(s) with the highest sum are the most preferred. + items: + description: The weights of all of the matched WeightedPodAffinityTerm + fields are added per-node to find the most preferred + node(s) + properties: + podAffinityTerm: + description: Required. A pod affinity term, + associated with the corresponding weight. + properties: + labelSelector: + description: |- + A label query over a set of resources, in this case pods. + If it's null, this PodAffinityTerm matches with no Pods. + properties: + matchExpressions: + description: matchExpressions is a list + of label selector requirements. The + requirements are ANDed. + items: + description: |- + A label selector requirement is a selector that contains values, a key, and an operator that + relates the key and values. + properties: + key: + description: key is the label + key that the selector applies + to. + type: string + operator: + description: |- + operator represents a key's relationship to a set of values. + Valid operators are In, NotIn, Exists and DoesNotExist. + type: string + values: + description: |- + values is an array of string values. If the operator is In or NotIn, + the values array must be non-empty. If the operator is Exists or DoesNotExist, + the values array must be empty. This array is replaced during a strategic + merge patch. + items: + type: string + type: array + x-kubernetes-list-type: atomic + required: + - key + - operator + type: object + type: array + x-kubernetes-list-type: atomic + matchLabels: + additionalProperties: + type: string + description: |- + matchLabels is a map of {key,value} pairs. A single {key,value} in the matchLabels + map is equivalent to an element of matchExpressions, whose key field is "key", the + operator is "In", and the values array contains only "value". The requirements are ANDed. + type: object + type: object + x-kubernetes-map-type: atomic + matchLabelKeys: + description: |- + MatchLabelKeys is a set of pod label keys to select which pods will + be taken into consideration. The keys are used to lookup values from the + incoming pod labels, those key-value labels are merged with `labelSelector` as `key in (value)` + to select the group of existing pods which pods will be taken into consideration + for the incoming pod's pod (anti) affinity. Keys that don't exist in the incoming + pod labels will be ignored. The default value is empty. + The same key is forbidden to exist in both matchLabelKeys and labelSelector. + Also, matchLabelKeys cannot be set when labelSelector isn't set. + items: + type: string + type: array + x-kubernetes-list-type: atomic + mismatchLabelKeys: + description: |- + MismatchLabelKeys is a set of pod label keys to select which pods will + be taken into consideration. The keys are used to lookup values from the + incoming pod labels, those key-value labels are merged with `labelSelector` as `key notin (value)` + to select the group of existing pods which pods will be taken into consideration + for the incoming pod's pod (anti) affinity. Keys that don't exist in the incoming + pod labels will be ignored. The default value is empty. + The same key is forbidden to exist in both mismatchLabelKeys and labelSelector. + Also, mismatchLabelKeys cannot be set when labelSelector isn't set. + items: + type: string + type: array + x-kubernetes-list-type: atomic + namespaceSelector: + description: |- + A label query over the set of namespaces that the term applies to. + The term is applied to the union of the namespaces selected by this field + and the ones listed in the namespaces field. + null selector and null or empty namespaces list means "this pod's namespace". + An empty selector ({}) matches all namespaces. + properties: + matchExpressions: + description: matchExpressions is a list + of label selector requirements. The + requirements are ANDed. + items: + description: |- + A label selector requirement is a selector that contains values, a key, and an operator that + relates the key and values. + properties: + key: + description: key is the label + key that the selector applies + to. + type: string + operator: + description: |- + operator represents a key's relationship to a set of values. + Valid operators are In, NotIn, Exists and DoesNotExist. + type: string + values: + description: |- + values is an array of string values. If the operator is In or NotIn, + the values array must be non-empty. If the operator is Exists or DoesNotExist, + the values array must be empty. This array is replaced during a strategic + merge patch. + items: + type: string + type: array + x-kubernetes-list-type: atomic + required: + - key + - operator + type: object + type: array + x-kubernetes-list-type: atomic + matchLabels: + additionalProperties: + type: string + description: |- + matchLabels is a map of {key,value} pairs. A single {key,value} in the matchLabels + map is equivalent to an element of matchExpressions, whose key field is "key", the + operator is "In", and the values array contains only "value". The requirements are ANDed. + type: object + type: object + x-kubernetes-map-type: atomic + namespaces: + description: |- + namespaces specifies a static list of namespace names that the term applies to. + The term is applied to the union of the namespaces listed in this field + and the ones selected by namespaceSelector. + null or empty namespaces list and null namespaceSelector means "this pod's namespace". + items: + type: string + type: array + x-kubernetes-list-type: atomic + topologyKey: + description: |- + This pod should be co-located (affinity) or not co-located (anti-affinity) with the pods matching + the labelSelector in the specified namespaces, where co-located is defined as running on a node + whose value of the label with key topologyKey matches that of any node on which any of the + selected pods is running. + Empty topologyKey is not allowed. + type: string + required: + - topologyKey + type: object + weight: + description: |- + weight associated with matching the corresponding podAffinityTerm, + in the range 1-100. + format: int32 + type: integer + required: + - podAffinityTerm + - weight + type: object + type: array + x-kubernetes-list-type: atomic + requiredDuringSchedulingIgnoredDuringExecution: + description: |- + If the anti-affinity requirements specified by this field are not met at + scheduling time, the pod will not be scheduled onto the node. + If the anti-affinity requirements specified by this field cease to be met + at some point during pod execution (e.g. due to a pod label update), the + system may or may not try to eventually evict the pod from its node. + When there are multiple elements, the lists of nodes corresponding to each + podAffinityTerm are intersected, i.e. all terms must be satisfied. + items: + description: |- + Defines a set of pods (namely those matching the labelSelector + relative to the given namespace(s)) that this pod should be + co-located (affinity) or not co-located (anti-affinity) with, + where co-located is defined as running on a node whose value of + the label with key matches that of any node on which + a pod of the set of pods is running + properties: + labelSelector: + description: |- + A label query over a set of resources, in this case pods. + If it's null, this PodAffinityTerm matches with no Pods. + properties: + matchExpressions: + description: matchExpressions is a list + of label selector requirements. The requirements + are ANDed. + items: + description: |- + A label selector requirement is a selector that contains values, a key, and an operator that + relates the key and values. + properties: + key: + description: key is the label key + that the selector applies to. + type: string + operator: + description: |- + operator represents a key's relationship to a set of values. + Valid operators are In, NotIn, Exists and DoesNotExist. + type: string + values: + description: |- + values is an array of string values. If the operator is In or NotIn, + the values array must be non-empty. If the operator is Exists or DoesNotExist, + the values array must be empty. This array is replaced during a strategic + merge patch. + items: + type: string + type: array + x-kubernetes-list-type: atomic + required: + - key + - operator + type: object + type: array + x-kubernetes-list-type: atomic + matchLabels: + additionalProperties: + type: string + description: |- + matchLabels is a map of {key,value} pairs. A single {key,value} in the matchLabels + map is equivalent to an element of matchExpressions, whose key field is "key", the + operator is "In", and the values array contains only "value". The requirements are ANDed. + type: object + type: object + x-kubernetes-map-type: atomic + matchLabelKeys: + description: |- + MatchLabelKeys is a set of pod label keys to select which pods will + be taken into consideration. The keys are used to lookup values from the + incoming pod labels, those key-value labels are merged with `labelSelector` as `key in (value)` + to select the group of existing pods which pods will be taken into consideration + for the incoming pod's pod (anti) affinity. Keys that don't exist in the incoming + pod labels will be ignored. The default value is empty. + The same key is forbidden to exist in both matchLabelKeys and labelSelector. + Also, matchLabelKeys cannot be set when labelSelector isn't set. + items: + type: string + type: array + x-kubernetes-list-type: atomic + mismatchLabelKeys: + description: |- + MismatchLabelKeys is a set of pod label keys to select which pods will + be taken into consideration. The keys are used to lookup values from the + incoming pod labels, those key-value labels are merged with `labelSelector` as `key notin (value)` + to select the group of existing pods which pods will be taken into consideration + for the incoming pod's pod (anti) affinity. Keys that don't exist in the incoming + pod labels will be ignored. The default value is empty. + The same key is forbidden to exist in both mismatchLabelKeys and labelSelector. + Also, mismatchLabelKeys cannot be set when labelSelector isn't set. + items: + type: string + type: array + x-kubernetes-list-type: atomic + namespaceSelector: + description: |- + A label query over the set of namespaces that the term applies to. + The term is applied to the union of the namespaces selected by this field + and the ones listed in the namespaces field. + null selector and null or empty namespaces list means "this pod's namespace". + An empty selector ({}) matches all namespaces. + properties: + matchExpressions: + description: matchExpressions is a list + of label selector requirements. The requirements + are ANDed. + items: + description: |- + A label selector requirement is a selector that contains values, a key, and an operator that + relates the key and values. + properties: + key: + description: key is the label key + that the selector applies to. + type: string + operator: + description: |- + operator represents a key's relationship to a set of values. + Valid operators are In, NotIn, Exists and DoesNotExist. + type: string + values: + description: |- + values is an array of string values. If the operator is In or NotIn, + the values array must be non-empty. If the operator is Exists or DoesNotExist, + the values array must be empty. This array is replaced during a strategic + merge patch. + items: + type: string + type: array + x-kubernetes-list-type: atomic + required: + - key + - operator + type: object + type: array + x-kubernetes-list-type: atomic + matchLabels: + additionalProperties: + type: string + description: |- + matchLabels is a map of {key,value} pairs. A single {key,value} in the matchLabels + map is equivalent to an element of matchExpressions, whose key field is "key", the + operator is "In", and the values array contains only "value". The requirements are ANDed. + type: object + type: object + x-kubernetes-map-type: atomic + namespaces: + description: |- + namespaces specifies a static list of namespace names that the term applies to. + The term is applied to the union of the namespaces listed in this field + and the ones selected by namespaceSelector. + null or empty namespaces list and null namespaceSelector means "this pod's namespace". + items: + type: string + type: array + x-kubernetes-list-type: atomic + topologyKey: + description: |- + This pod should be co-located (affinity) or not co-located (anti-affinity) with the pods matching + the labelSelector in the specified namespaces, where co-located is defined as running on a node + whose value of the label with key topologyKey matches that of any node on which any of the + selected pods is running. + Empty topologyKey is not allowed. + type: string + required: + - topologyKey + type: object + type: array + x-kubernetes-list-type: atomic + type: object + type: object + nodeSelector: + additionalProperties: + type: string + description: |- + nodeSelector is the node selector applied to the relevant kind of pods + It specifies a map of key-value pairs: for the pod to be eligible to run on a node, + the node must have each of the indicated key-value pairs as labels + (it can have additional labels as well). + See https://kubernetes.io/docs/concepts/configuration/assign-pod-node/#nodeselector + type: object + tolerations: + description: |- + tolerations is a list of tolerations applied to the relevant kind of pods + See https://kubernetes.io/docs/concepts/configuration/taint-and-toleration/ for more info. + These are additional tolerations other than default ones. + items: + description: |- + The pod this Toleration is attached to tolerates any taint that matches + the triple using the matching operator . + properties: + effect: + description: |- + Effect indicates the taint effect to match. Empty means match all taint effects. + When specified, allowed values are NoSchedule, PreferNoSchedule and NoExecute. + type: string + key: + description: |- + Key is the taint key that the toleration applies to. Empty means match all taint keys. + If the key is empty, operator must be Exists; this combination means to match all values and all keys. + type: string + operator: + description: |- + Operator represents a key's relationship to the value. + Valid operators are Exists and Equal. Defaults to Equal. + Exists is equivalent to wildcard for value, so that a pod can + tolerate all taints of a particular category. + type: string + tolerationSeconds: + description: |- + TolerationSeconds represents the period of time the toleration (which must be + of effect NoExecute, otherwise this field is ignored) tolerates the taint. By default, + it is not set, which means tolerate the taint forever (do not evict). Zero and + negative values will be treated as 0 (evict immediately) by the system. + format: int64 + type: integer + value: + description: |- + Value is the taint value the toleration matches to. + If the operator is Exists, the value should be empty, otherwise just a regular string. + type: string + type: object + type: array + type: object + type: object + instancetypeConfig: + description: InstancetypeConfig holds the configuration of instance + type related functionality within KubeVirt. + properties: + referencePolicy: + description: |- + ReferencePolicy defines how an instance type or preference should be referenced by the VM after submission, supported values are: + reference (default) - Where a copy of the original object is stashed in a ControllerRevision and referenced by the VM. + expand - Where the instance type or preference are expanded into the VM if no revisionNames have been populated. + expandAll - Where the instance type or preference are expanded into the VM regardless of revisionNames previously being populated. + enum: + - reference + - expand + - expandAll + nullable: true + type: string + type: object + ksmConfiguration: + description: |- + KSMConfiguration holds the information regarding + the enabling the KSM in the nodes (if available). + properties: + nodeLabelSelector: + description: |- + NodeLabelSelector is a selector that filters in which nodes the KSM will be enabled. + Empty NodeLabelSelector will enable ksm for every node. + properties: + matchExpressions: + description: matchExpressions is a list of label selector + requirements. The requirements are ANDed. + items: + description: |- + A label selector requirement is a selector that contains values, a key, and an operator that + relates the key and values. + properties: + key: + description: key is the label key that the selector + applies to. + type: string + operator: + description: |- + operator represents a key's relationship to a set of values. + Valid operators are In, NotIn, Exists and DoesNotExist. + type: string + values: + description: |- + values is an array of string values. If the operator is In or NotIn, + the values array must be non-empty. If the operator is Exists or DoesNotExist, + the values array must be empty. This array is replaced during a strategic + merge patch. + items: + type: string + type: array + x-kubernetes-list-type: atomic + required: + - key + - operator + type: object + type: array + x-kubernetes-list-type: atomic + matchLabels: + additionalProperties: + type: string + description: |- + matchLabels is a map of {key,value} pairs. A single {key,value} in the matchLabels + map is equivalent to an element of matchExpressions, whose key field is "key", the + operator is "In", and the values array contains only "value". The requirements are ANDed. + type: object + type: object + x-kubernetes-map-type: atomic + type: object + kubeMacPoolConfiguration: + description: KubeMacPoolConfiguration holds kubemacpool MAC address + range configuration. + properties: + rangeEnd: + description: |- + RangeEnd defines the last MAC address in the kubemacpool range. + The MAC address format should be AA:BB:CC:DD:EE:FF. + pattern: ^([0-9a-fA-F]{2}:){5}[0-9a-fA-F]{2}$ + type: string + rangeStart: + description: |- + RangeStart defines the first MAC address in the kubemacpool range. + The MAC address format should be AA:BB:CC:DD:EE:FF. + pattern: ^([0-9a-fA-F]{2}:){5}[0-9a-fA-F]{2}$ + type: string + type: object + x-kubernetes-validations: + - message: both rangeStart and rangeEnd must be configured together, + or both omitted + rule: (has(self.rangeStart) && has(self.rangeEnd)) || (!has(self.rangeStart) + && !has(self.rangeEnd)) + kubeSecondaryDNSNameServerIP: + description: KubeSecondaryDNSNameServerIP defines name server IP used + by KubeSecondaryDNS + type: string + liveMigrationConfig: + default: + allowAutoConverge: false + allowPostCopy: false + completionTimeoutPerGiB: 150 + parallelMigrationsPerCluster: 5 + parallelOutboundMigrationsPerNode: 2 + progressTimeout: 150 + description: |- + Live migration limits and timeouts are applied so that migration processes do not + overwhelm the cluster. + properties: + allowAutoConverge: + default: false + description: |- + AllowAutoConverge allows the platform to compromise performance/availability of VMIs to + guarantee successful VMI live migrations. Defaults to false + type: boolean + allowPostCopy: + default: false + description: |- + When enabled, KubeVirt attempts to use post-copy live-migration in case it + reaches its completion timeout while attempting pre-copy live-migration. + Post-copy migrations allow even the busiest VMs to successfully live-migrate. + However, events like a network failure or a failure in any of the source or + destination nodes can cause the migrated VM to crash or reach inconsistency. + Enable this option when evicting nodes is more important than keeping VMs + alive. + Defaults to false. + type: boolean + bandwidthPerMigration: + description: Bandwidth limit of each migration, the value is quantity + of bytes per second (e.g. 2048Mi = 2048MiB/sec) + pattern: ^(\+|-)?(([0-9]+(\.[0-9]*)?)|(\.[0-9]+))(([KMGTPE]i)|[numkMGTPE]|([eE](\+|-)?(([0-9]+(\.[0-9]*)?)|(\.[0-9]+))))?$ + type: string + completionTimeoutPerGiB: + default: 150 + description: |- + If a migrating VM is big and busy, while the connection to the destination node + is slow, migration may never converge. The completion timeout is calculated + based on completionTimeoutPerGiB times the size of the guest (both RAM and + migrated disks, if any). For example, with completionTimeoutPerGiB set to 800, + a virtual machine instance with 6GiB memory will timeout if it has not + completed migration in 1h20m. Use a lower completionTimeoutPerGiB to induce + quicker failure, so that another destination or post-copy is attempted. Use a + higher completionTimeoutPerGiB to let workload with spikes in its memory dirty + rate to converge. + The format is a number. + format: int64 + type: integer + network: + description: The migrations will be performed over a dedicated + multus network to minimize disruption to tenant workloads due + to network saturation when VM live migrations are triggered. + type: string + parallelMigrationsPerCluster: + default: 5 + description: Number of migrations running in parallel in the cluster. + format: int32 + type: integer + parallelOutboundMigrationsPerNode: + default: 2 + description: Maximum number of outbound migrations per node. + format: int32 + type: integer + progressTimeout: + default: 150 + description: The migration will be canceled if memory copy fails + to make progress in this time, in seconds. + format: int64 + type: integer + type: object + liveUpdateConfiguration: + description: |- + LiveUpdateConfiguration holds the cluster configuration for live update of virtual machines - max cpu sockets, + max guest memory and max hotplug ratio. This setting can affect VM CPU and memory settings. + properties: + maxCpuSockets: + description: |- + MaxCpuSockets provides a MaxSockets value for VMs that do not provide their own. + For VMs with more sockets than maximum the MaxSockets will be set to equal number of sockets. + format: int32 + type: integer + maxGuest: + anyOf: + - type: integer + - type: string + description: |- + MaxGuest defines the maximum amount memory that can be allocated + to the guest using hotplug. + pattern: ^(\+|-)?(([0-9]+(\.[0-9]*)?)|(\.[0-9]+))(([KMGTPE]i)|[numkMGTPE]|([eE](\+|-)?(([0-9]+(\.[0-9]*)?)|(\.[0-9]+))))?$ + x-kubernetes-int-or-string: true + maxHotplugRatio: + description: |- + MaxHotplugRatio is the ratio used to define the max amount + of a hotplug resource that can be made available to a VM + when the specific Max* setting is not defined (MaxCpuSockets, MaxGuest) + Example: VM is configured with 512Mi of guest memory, if MaxGuest is not + defined and MaxHotplugRatio is 2 then MaxGuest = 1Gi + defaults to 4 + format: int32 + type: integer + type: object + logVerbosityConfig: + description: |- + LogVerbosityConfig configures the verbosity level of Kubevirt's different components. The higher + the value - the higher the log verbosity. + properties: + cdi: + description: CDI indicates the log verbosity level that controls + the amount of information logged for CDI components. + format: int32 + type: integer + kubevirt: + description: |- + Kubevirt is a struct that allows specifying the log verbosity level that controls the amount of information + logged for each Kubevirt component. + properties: + nodeVerbosity: + additionalProperties: + type: integer + description: NodeVerbosity represents a map of nodes with + a specific verbosity level + type: object + virtAPI: + type: integer + virtController: + type: integer + virtHandler: + type: integer + virtLauncher: + type: integer + virtOperator: + type: integer + virtSynchronizationController: + type: integer + type: object + type: object + mediatedDevicesConfiguration: + description: MediatedDevicesConfiguration holds information about + MDEV types to be defined on nodes, if available + properties: + mediatedDeviceTypes: + items: + type: string + type: array + x-kubernetes-list-type: atomic + nodeMediatedDeviceTypes: + items: + description: NodeMediatedDeviceTypesConfig holds information + about MDEV types to be defined in a specific node that matches + the NodeSelector field. + properties: + mediatedDeviceTypes: + items: + type: string + type: array + x-kubernetes-list-type: atomic + nodeSelector: + additionalProperties: + type: string + description: |- + NodeSelector is a selector which must be true for the vmi to fit on a node. + Selector which must match a node's labels for the vmi to be scheduled on that node. + More info: https://kubernetes.io/docs/concepts/configuration/assign-pod-node/ + type: object + required: + - nodeSelector + type: object + type: array + x-kubernetes-list-type: atomic + type: object + networkBinding: + additionalProperties: + properties: + computeResourceOverhead: + description: |- + ComputeResourceOverhead specifies the resource overhead that should be added to the compute container when using the binding. + version: v1alphav1 + properties: + limits: + additionalProperties: + anyOf: + - type: integer + - type: string + pattern: ^(\+|-)?(([0-9]+(\.[0-9]*)?)|(\.[0-9]+))(([KMGTPE]i)|[numkMGTPE]|([eE](\+|-)?(([0-9]+(\.[0-9]*)?)|(\.[0-9]+))))?$ + x-kubernetes-int-or-string: true + description: |- + Limits describes the maximum amount of compute resources allowed. + More info: https://kubernetes.io/docs/concepts/configuration/manage-resources-containers/ + type: object + requests: + additionalProperties: + anyOf: + - type: integer + - type: string + pattern: ^(\+|-)?(([0-9]+(\.[0-9]*)?)|(\.[0-9]+))(([KMGTPE]i)|[numkMGTPE]|([eE](\+|-)?(([0-9]+(\.[0-9]*)?)|(\.[0-9]+))))?$ + x-kubernetes-int-or-string: true + description: |- + Requests describes the minimum amount of compute resources required. + If Requests is omitted for a container, it defaults to Limits if that is explicitly specified, + otherwise to an implementation-defined value. Requests cannot exceed Limits. + More info: https://kubernetes.io/docs/concepts/configuration/manage-resources-containers/ + type: object + type: object + domainAttachmentType: + description: |- + DomainAttachmentType is a standard domain network attachment method kubevirt supports. + Supported values: "tap", "managedTap" (since v1.4). + The standard domain attachment can be used instead or in addition to the sidecarImage. + version: 1alphav1 + type: string + downwardAPI: + description: |- + DownwardAPI specifies what kind of data should be exposed to the binding plugin sidecar. + Supported values: "device-info" + version: v1alphav1 + type: string + migration: + description: |- + Migration means the VM using the plugin can be safely migrated + version: 1alphav1 + properties: + method: + description: |- + Method defines a pre-defined migration methodology + version: 1alphav1 + type: string + type: object + networkAttachmentDefinition: + description: |- + NetworkAttachmentDefinition references to a NetworkAttachmentDefinition CR object. + Format: , /. + If namespace is not specified, VMI namespace is assumed. + version: 1alphav1 + type: string + sidecarImage: + description: |- + SidecarImage references a container image that runs in the virt-launcher pod. + The sidecar handles (libvirt) domain configuration and optional services. + version: 1alphav1 + type: string + type: object + description: |- + NetworkBinding defines the network binding plugins. + Those bindings can be used when defining virtual machine interfaces. + type: object + obsoleteCPUs: + description: ObsoleteCPUs allows avoiding scheduling of VMs for obsolete + CPU models + properties: + cpuModels: + description: |- + CPUModels is a list of obsolete CPU models. When the node-labeller obtains the list of obsolete CPU models, it + eliminates those CPU models and creates labels for valid CPU models. + The default values for this field is nil, however, HCO uses opinionated values, and adding values to this list + will add them to the opinionated values. + items: + type: string + type: array + x-kubernetes-list-type: set + type: object + permittedHostDevices: + description: PermittedHostDevices holds information about devices + allowed for passthrough + properties: + mediatedDevices: + items: + description: MediatedHostDevice represents a host mediated device + allowed for passthrough + properties: + disabled: + description: |- + HCO enforces the existence of several MediatedHostDevice objects. Set disabled field to true instead of remove + these objects. + type: boolean + externalResourceProvider: + description: indicates that this resource is being provided + by an external device plugin + type: boolean + mdevNameSelector: + description: name of a mediated device type required to + identify a mediated device on a host + type: string + resourceName: + description: name by which a device is advertised and being + requested + type: string + required: + - mdevNameSelector + - resourceName + type: object + type: array + x-kubernetes-list-map-keys: + - mdevNameSelector + x-kubernetes-list-type: map + pciHostDevices: + items: + description: PciHostDevice represents a host PCI device allowed + for passthrough + properties: + disabled: + description: |- + HCO enforces the existence of several PciHostDevice objects. Set disabled field to true instead of remove + these objects. + type: boolean + externalResourceProvider: + description: indicates that this resource is being provided + by an external device plugin + type: boolean + pciDeviceSelector: + description: a combination of a vendor_id:product_id required + to identify a PCI device on a host. + type: string + resourceName: + description: name by which a device is advertised and being + requested + type: string + required: + - pciDeviceSelector + - resourceName + type: object + type: array + x-kubernetes-list-map-keys: + - pciDeviceSelector + x-kubernetes-list-type: map + usbHostDevices: + items: + description: USBHostDevice represents a host USB device allowed + for passthrough + properties: + disabled: + description: |- + HCO enforces the existence of several USBHostDevice objects. Set disabled field to true instead of remove + these objects. + type: boolean + externalResourceProvider: + description: |- + If true, KubeVirt will leave the allocation and monitoring to an + external device plugin + type: boolean + resourceName: + description: |- + Identifies the list of USB host devices. + e.g: kubevirt.io/storage, kubevirt.io/bootable-usb, etc + type: string + selectors: + items: + description: USBSelector represents a selector for a USB + device allowed for passthrough + properties: + product: + type: string + vendor: + type: string + required: + - product + - vendor + type: object + type: array + x-kubernetes-list-type: atomic + required: + - resourceName + type: object + type: array + x-kubernetes-list-map-keys: + - resourceName + x-kubernetes-list-type: map + type: object + resourceRequirements: + default: + vmiCPUAllocationRatio: 10 + description: ResourceRequirements describes the resource requirements + for the operand workloads. + properties: + autoCPULimitNamespaceLabelSelector: + description: |- + When set, AutoCPULimitNamespaceLabelSelector will set a CPU limit on virt-launcher for VMIs running inside + namespaces that match the label selector. + The CPU limit will equal the number of requested vCPUs. + This setting does not apply to VMIs with dedicated CPUs. + properties: + matchExpressions: + description: matchExpressions is a list of label selector + requirements. The requirements are ANDed. + items: + description: |- + A label selector requirement is a selector that contains values, a key, and an operator that + relates the key and values. + properties: + key: + description: key is the label key that the selector + applies to. + type: string + operator: + description: |- + operator represents a key's relationship to a set of values. + Valid operators are In, NotIn, Exists and DoesNotExist. + type: string + values: + description: |- + values is an array of string values. If the operator is In or NotIn, + the values array must be non-empty. If the operator is Exists or DoesNotExist, + the values array must be empty. This array is replaced during a strategic + merge patch. + items: + type: string + type: array + x-kubernetes-list-type: atomic + required: + - key + - operator + type: object + type: array + x-kubernetes-list-type: atomic + matchLabels: + additionalProperties: + type: string + description: |- + matchLabels is a map of {key,value} pairs. A single {key,value} in the matchLabels + map is equivalent to an element of matchExpressions, whose key field is "key", the + operator is "In", and the values array contains only "value". The requirements are ANDed. + type: object + type: object + x-kubernetes-map-type: atomic + storageWorkloads: + description: |- + StorageWorkloads defines the resources requirements for storage workloads. It will propagate to the CDI custom + resource + properties: + claims: + description: |- + Claims lists the names of resources, defined in spec.resourceClaims, + that are used by this container. + + This field depends on the + DynamicResourceAllocation feature gate. + + This field is immutable. It can only be set for containers. + items: + description: ResourceClaim references one entry in PodSpec.ResourceClaims. + properties: + name: + description: |- + Name must match the name of one entry in pod.spec.resourceClaims of + the Pod where this field is used. It makes that resource available + inside a container. + type: string + request: + description: |- + Request is the name chosen for a request in the referenced claim. + If empty, everything from the claim is made available, otherwise + only the result of this request. + type: string + required: + - name + type: object + type: array + x-kubernetes-list-map-keys: + - name + x-kubernetes-list-type: map + limits: + additionalProperties: + anyOf: + - type: integer + - type: string + pattern: ^(\+|-)?(([0-9]+(\.[0-9]*)?)|(\.[0-9]+))(([KMGTPE]i)|[numkMGTPE]|([eE](\+|-)?(([0-9]+(\.[0-9]*)?)|(\.[0-9]+))))?$ + x-kubernetes-int-or-string: true + description: |- + Limits describes the maximum amount of compute resources allowed. + More info: https://kubernetes.io/docs/concepts/configuration/manage-resources-containers/ + type: object + requests: + additionalProperties: + anyOf: + - type: integer + - type: string + pattern: ^(\+|-)?(([0-9]+(\.[0-9]*)?)|(\.[0-9]+))(([KMGTPE]i)|[numkMGTPE]|([eE](\+|-)?(([0-9]+(\.[0-9]*)?)|(\.[0-9]+))))?$ + x-kubernetes-int-or-string: true + description: |- + Requests describes the minimum amount of compute resources required. + If Requests is omitted for a container, it defaults to Limits if that is explicitly specified, + otherwise to an implementation-defined value. Requests cannot exceed Limits. + More info: https://kubernetes.io/docs/concepts/configuration/manage-resources-containers/ + type: object + type: object + vmiCPUAllocationRatio: + default: 10 + description: |- + VmiCPUAllocationRatio defines, for each requested virtual CPU, + how much physical CPU to request per VMI from the + hosting node. The value is in fraction of a CPU thread (or + core on non-hyperthreaded nodes). + VMI POD CPU request = number of vCPUs * 1/vmiCPUAllocationRatio + For example, a value of 1 means 1 physical CPU thread per VMI CPU thread. + A value of 100 would be 1% of a physical thread allocated for each + requested VMI thread. + This option has no effect on VMIs that request dedicated CPUs. + Defaults to 10 + minimum: 1 + type: integer + type: object + x-kubernetes-validations: + - message: vmiCPUAllocationRatio must be greater than 0 + rule: '!has(self.vmiCPUAllocationRatio) || self.vmiCPUAllocationRatio + > 0' + scratchSpaceStorageClass: + description: |- + Override the storage class used for scratch space during transfer operations. The scratch space storage class + is determined in the following order: + value of scratchSpaceStorageClass, if that doesn't exist, use the default storage class, if there is no default + storage class, use the storage class of the DataVolume, if no storage class specified, use no storage class for + scratch space + type: string + storageImport: + description: StorageImport contains configuration for importing containerized + data + properties: + insecureRegistries: + description: |- + InsecureRegistries is a list of image registries URLs that are not secured. Setting an insecure registry URL + in this list allows pulling images from this registry. + items: + type: string + type: array + x-kubernetes-list-type: set + type: object + tlsSecurityProfile: + description: |- + TLSSecurityProfile specifies the settings for TLS connections to be propagated to all kubevirt-hyperconverged components. + If unset, the hyperconverged cluster operator will consume the value set on the APIServer CR on OCP/OKD or Intermediate if on vanilla k8s. + Note that only Old, Intermediate and Custom profiles are currently supported, and the maximum available + MinTLSVersions is VersionTLS12. + properties: + custom: + description: |- + custom is a user-defined TLS security profile. Be extremely careful using a custom + profile as invalid configurations can be catastrophic. An example custom profile + looks like this: + + ciphers: + + - ECDHE-ECDSA-CHACHA20-POLY1305 + + - ECDHE-RSA-CHACHA20-POLY1305 + + - ECDHE-RSA-AES128-GCM-SHA256 + + - ECDHE-ECDSA-AES128-GCM-SHA256 + + minTLSVersion: VersionTLS11 + nullable: true + properties: + ciphers: + description: |- + ciphers is used to specify the cipher algorithms that are negotiated + during the TLS handshake. Operators may remove entries their operands + do not support. For example, to use DES-CBC3-SHA (yaml): + + ciphers: + - DES-CBC3-SHA + items: + type: string + type: array + x-kubernetes-list-type: atomic + minTLSVersion: + description: |- + minTLSVersion is used to specify the minimal version of the TLS protocol + that is negotiated during the TLS handshake. For example, to use TLS + versions 1.1, 1.2 and 1.3 (yaml): + + minTLSVersion: VersionTLS11 + + NOTE: currently the highest minTLSVersion allowed is VersionTLS12 + enum: + - VersionTLS10 + - VersionTLS11 + - VersionTLS12 + - VersionTLS13 + type: string + type: object + intermediate: + description: |- + intermediate is a TLS security profile based on: + + https://wiki.mozilla.org/Security/Server_Side_TLS#Intermediate_compatibility_.28recommended.29 + + and looks like this (yaml): + + ciphers: + + - TLS_AES_128_GCM_SHA256 + + - TLS_AES_256_GCM_SHA384 + + - TLS_CHACHA20_POLY1305_SHA256 + + - ECDHE-ECDSA-AES128-GCM-SHA256 + + - ECDHE-RSA-AES128-GCM-SHA256 + + - ECDHE-ECDSA-AES256-GCM-SHA384 + + - ECDHE-RSA-AES256-GCM-SHA384 + + - ECDHE-ECDSA-CHACHA20-POLY1305 + + - ECDHE-RSA-CHACHA20-POLY1305 + + - DHE-RSA-AES128-GCM-SHA256 + + - DHE-RSA-AES256-GCM-SHA384 + + minTLSVersion: VersionTLS12 + nullable: true + type: object + modern: + description: |- + modern is a TLS security profile based on: + + https://wiki.mozilla.org/Security/Server_Side_TLS#Modern_compatibility + + and looks like this (yaml): + + ciphers: + + - TLS_AES_128_GCM_SHA256 + + - TLS_AES_256_GCM_SHA384 + + - TLS_CHACHA20_POLY1305_SHA256 + + minTLSVersion: VersionTLS13 + nullable: true + type: object + old: + description: |- + old is a TLS security profile based on: + + https://wiki.mozilla.org/Security/Server_Side_TLS#Old_backward_compatibility + + and looks like this (yaml): + + ciphers: + + - TLS_AES_128_GCM_SHA256 + + - TLS_AES_256_GCM_SHA384 + + - TLS_CHACHA20_POLY1305_SHA256 + + - ECDHE-ECDSA-AES128-GCM-SHA256 + + - ECDHE-RSA-AES128-GCM-SHA256 + + - ECDHE-ECDSA-AES256-GCM-SHA384 + + - ECDHE-RSA-AES256-GCM-SHA384 + + - ECDHE-ECDSA-CHACHA20-POLY1305 + + - ECDHE-RSA-CHACHA20-POLY1305 + + - DHE-RSA-AES128-GCM-SHA256 + + - DHE-RSA-AES256-GCM-SHA384 + + - DHE-RSA-CHACHA20-POLY1305 + + - ECDHE-ECDSA-AES128-SHA256 + + - ECDHE-RSA-AES128-SHA256 + + - ECDHE-ECDSA-AES128-SHA + + - ECDHE-RSA-AES128-SHA + + - ECDHE-ECDSA-AES256-SHA384 + + - ECDHE-RSA-AES256-SHA384 + + - ECDHE-ECDSA-AES256-SHA + + - ECDHE-RSA-AES256-SHA + + - DHE-RSA-AES128-SHA256 + + - DHE-RSA-AES256-SHA256 + + - AES128-GCM-SHA256 + + - AES256-GCM-SHA384 + + - AES128-SHA256 + + - AES256-SHA256 + + - AES128-SHA + + - AES256-SHA + + - DES-CBC3-SHA + + minTLSVersion: VersionTLS10 + nullable: true + type: object + type: + description: |- + type is one of Old, Intermediate, Modern or Custom. Custom provides + the ability to specify individual TLS security profile parameters. + Old, Intermediate and Modern are TLS security profiles based on: + + https://wiki.mozilla.org/Security/Server_Side_TLS#Recommended_configurations + + The profiles are intent based, so they may change over time as new ciphers are developed and existing ciphers + are found to be insecure. Depending on precisely which ciphers are available to a process, the list may be + reduced. + + Note that the Modern profile is currently not supported because it is not + yet well adopted by common software libraries. + enum: + - Old + - Intermediate + - Modern + - Custom + type: string + type: object + tuningPolicy: + description: |- + TuningPolicy allows to configure the mode in which the RateLimits of kubevirt are set. + If TuningPolicy is not present the default kubevirt values are used. + It can be set to `annotation` for fine-tuning the kubevirt queryPerSeconds (qps) and burst values. + Qps and burst values are taken from the annotation hco.kubevirt.io/tuningPolicy + enum: + - annotation + - highBurst + type: string + uninstallStrategy: + default: BlockUninstallIfWorkloadsExist + description: |- + UninstallStrategy defines how to proceed on uninstall when workloads (VirtualMachines, DataVolumes) still exist. + BlockUninstallIfWorkloadsExist will prevent the CR from being removed when workloads still exist. + BlockUninstallIfWorkloadsExist is the safest choice to protect your workloads from accidental data loss, so it's strongly advised. + RemoveWorkloads will cause all the workloads to be cascading deleted on uninstallation. + WARNING: please notice that RemoveWorkloads will cause your workloads to be deleted as soon as this CR will be, even accidentally, deleted. + Please correctly consider the implications of this option before setting it. + BlockUninstallIfWorkloadsExist is the default behaviour. + enum: + - RemoveWorkloads + - BlockUninstallIfWorkloadsExist + type: string + virtualMachineOptions: + default: + disableFreePageReporting: false + disableSerialConsoleLog: false + description: VirtualMachineOptions holds the cluster level information + regarding the virtual machine. + properties: + disableFreePageReporting: + default: false + description: |- + DisableFreePageReporting disable the free page reporting of + memory balloon device https://libvirt.org/formatdomain.html#memory-balloon-device. + This will have effect only if AutoattachMemBalloon is not false and the vmi is not + requesting any high performance feature (dedicatedCPU/realtime/hugePages), in which free page reporting is always disabled. + type: boolean + disableSerialConsoleLog: + default: false + description: |- + DisableSerialConsoleLog disables logging the auto-attached default serial console. + If not set, serial console logs will be written to a file and then streamed from a container named `guest-console-log`. + The value can be individually overridden for each VM, not relevant if AutoattachSerialConsole is disabled for the VM. + type: boolean + type: object + vmStateStorageClass: + description: VMStateStorageClass is the name of the storage class + to use for the PVCs created to preserve VM state, like TPM. + type: string + workloadUpdateStrategy: + default: + batchEvictionInterval: 1m0s + batchEvictionSize: 10 + workloadUpdateMethods: + - LiveMigrate + description: WorkloadUpdateStrategy defines at the cluster level how + to handle automated workload updates + properties: + batchEvictionInterval: + default: 1m0s + description: |- + BatchEvictionInterval Represents the interval to wait before issuing the next + batch of shutdowns + type: string + batchEvictionSize: + default: 10 + description: |- + BatchEvictionSize Represents the number of VMIs that can be forced updated per + the BatchShutdownInterval interval + type: integer + workloadUpdateMethods: + default: + - LiveMigrate + description: |- + WorkloadUpdateMethods defines the methods that can be used to disrupt workloads + during automated workload updates. + When multiple methods are present, the least disruptive method takes + precedence over more disruptive methods. For example if both LiveMigrate and Evict + methods are listed, only VMs which are not live migratable will be restarted/shutdown. + An empty list defaults to no automated workload updating. + items: + type: string + type: array + x-kubernetes-list-type: atomic + required: + - workloadUpdateMethods + type: object + workloads: + description: |- + workloads HyperConvergedConfig influences the pod configuration (currently only placement) of components + which need to be running on a node where virtualization workloads should be able to run. + Changes to Workloads HyperConvergedConfig can be applied only without existing workload. + properties: + nodePlacement: + description: NodePlacement describes node scheduling configuration. + properties: + affinity: + description: |- + affinity enables pod affinity/anti-affinity placement expanding the types of constraints + that can be expressed with nodeSelector. + affinity is going to be applied to the relevant kind of pods in parallel with nodeSelector + See https://kubernetes.io/docs/concepts/scheduling-eviction/assign-pod-node/#affinity-and-anti-affinity + properties: + nodeAffinity: + description: Describes node affinity scheduling rules + for the pod. + properties: + preferredDuringSchedulingIgnoredDuringExecution: + description: |- + The scheduler will prefer to schedule pods to nodes that satisfy + the affinity expressions specified by this field, but it may choose + a node that violates one or more of the expressions. The node that is + most preferred is the one with the greatest sum of weights, i.e. + for each node that meets all of the scheduling requirements (resource + request, requiredDuringScheduling affinity expressions, etc.), + compute a sum by iterating through the elements of this field and adding + "weight" to the sum if the node matches the corresponding matchExpressions; the + node(s) with the highest sum are the most preferred. + items: + description: |- + An empty preferred scheduling term matches all objects with implicit weight 0 + (i.e. it's a no-op). A null preferred scheduling term matches no objects (i.e. is also a no-op). + properties: + preference: + description: A node selector term, associated + with the corresponding weight. + properties: + matchExpressions: + description: A list of node selector requirements + by node's labels. + items: + description: |- + A node selector requirement is a selector that contains values, a key, and an operator + that relates the key and values. + properties: + key: + description: The label key that the + selector applies to. + type: string + operator: + description: |- + Represents a key's relationship to a set of values. + Valid operators are In, NotIn, Exists, DoesNotExist. Gt, and Lt. + type: string + values: + description: |- + An array of string values. If the operator is In or NotIn, + the values array must be non-empty. If the operator is Exists or DoesNotExist, + the values array must be empty. If the operator is Gt or Lt, the values + array must have a single element, which will be interpreted as an integer. + This array is replaced during a strategic merge patch. + items: + type: string + type: array + x-kubernetes-list-type: atomic + required: + - key + - operator + type: object + type: array + x-kubernetes-list-type: atomic + matchFields: + description: A list of node selector requirements + by node's fields. + items: + description: |- + A node selector requirement is a selector that contains values, a key, and an operator + that relates the key and values. + properties: + key: + description: The label key that the + selector applies to. + type: string + operator: + description: |- + Represents a key's relationship to a set of values. + Valid operators are In, NotIn, Exists, DoesNotExist. Gt, and Lt. + type: string + values: + description: |- + An array of string values. If the operator is In or NotIn, + the values array must be non-empty. If the operator is Exists or DoesNotExist, + the values array must be empty. If the operator is Gt or Lt, the values + array must have a single element, which will be interpreted as an integer. + This array is replaced during a strategic merge patch. + items: + type: string + type: array + x-kubernetes-list-type: atomic + required: + - key + - operator + type: object + type: array + x-kubernetes-list-type: atomic + type: object + x-kubernetes-map-type: atomic + weight: + description: Weight associated with matching + the corresponding nodeSelectorTerm, in the + range 1-100. + format: int32 + type: integer + required: + - preference + - weight + type: object + type: array + x-kubernetes-list-type: atomic + requiredDuringSchedulingIgnoredDuringExecution: + description: |- + If the affinity requirements specified by this field are not met at + scheduling time, the pod will not be scheduled onto the node. + If the affinity requirements specified by this field cease to be met + at some point during pod execution (e.g. due to an update), the system + may or may not try to eventually evict the pod from its node. + properties: + nodeSelectorTerms: + description: Required. A list of node selector + terms. The terms are ORed. + items: + description: |- + A null or empty node selector term matches no objects. The requirements of + them are ANDed. + The TopologySelectorTerm type implements a subset of the NodeSelectorTerm. + properties: + matchExpressions: + description: A list of node selector requirements + by node's labels. + items: + description: |- + A node selector requirement is a selector that contains values, a key, and an operator + that relates the key and values. + properties: + key: + description: The label key that the + selector applies to. + type: string + operator: + description: |- + Represents a key's relationship to a set of values. + Valid operators are In, NotIn, Exists, DoesNotExist. Gt, and Lt. + type: string + values: + description: |- + An array of string values. If the operator is In or NotIn, + the values array must be non-empty. If the operator is Exists or DoesNotExist, + the values array must be empty. If the operator is Gt or Lt, the values + array must have a single element, which will be interpreted as an integer. + This array is replaced during a strategic merge patch. + items: + type: string + type: array + x-kubernetes-list-type: atomic + required: + - key + - operator + type: object + type: array + x-kubernetes-list-type: atomic + matchFields: + description: A list of node selector requirements + by node's fields. + items: + description: |- + A node selector requirement is a selector that contains values, a key, and an operator + that relates the key and values. + properties: + key: + description: The label key that the + selector applies to. + type: string + operator: + description: |- + Represents a key's relationship to a set of values. + Valid operators are In, NotIn, Exists, DoesNotExist. Gt, and Lt. + type: string + values: + description: |- + An array of string values. If the operator is In or NotIn, + the values array must be non-empty. If the operator is Exists or DoesNotExist, + the values array must be empty. If the operator is Gt or Lt, the values + array must have a single element, which will be interpreted as an integer. + This array is replaced during a strategic merge patch. + items: + type: string + type: array + x-kubernetes-list-type: atomic + required: + - key + - operator + type: object + type: array + x-kubernetes-list-type: atomic + type: object + x-kubernetes-map-type: atomic + type: array + x-kubernetes-list-type: atomic + required: + - nodeSelectorTerms + type: object + x-kubernetes-map-type: atomic + type: object + podAffinity: + description: Describes pod affinity scheduling rules (e.g. + co-locate this pod in the same node, zone, etc. as some + other pod(s)). + properties: + preferredDuringSchedulingIgnoredDuringExecution: + description: |- + The scheduler will prefer to schedule pods to nodes that satisfy + the affinity expressions specified by this field, but it may choose + a node that violates one or more of the expressions. The node that is + most preferred is the one with the greatest sum of weights, i.e. + for each node that meets all of the scheduling requirements (resource + request, requiredDuringScheduling affinity expressions, etc.), + compute a sum by iterating through the elements of this field and adding + "weight" to the sum if the node has pods which matches the corresponding podAffinityTerm; the + node(s) with the highest sum are the most preferred. + items: + description: The weights of all of the matched WeightedPodAffinityTerm + fields are added per-node to find the most preferred + node(s) + properties: + podAffinityTerm: + description: Required. A pod affinity term, + associated with the corresponding weight. + properties: + labelSelector: + description: |- + A label query over a set of resources, in this case pods. + If it's null, this PodAffinityTerm matches with no Pods. + properties: + matchExpressions: + description: matchExpressions is a list + of label selector requirements. The + requirements are ANDed. + items: + description: |- + A label selector requirement is a selector that contains values, a key, and an operator that + relates the key and values. + properties: + key: + description: key is the label + key that the selector applies + to. + type: string + operator: + description: |- + operator represents a key's relationship to a set of values. + Valid operators are In, NotIn, Exists and DoesNotExist. + type: string + values: + description: |- + values is an array of string values. If the operator is In or NotIn, + the values array must be non-empty. If the operator is Exists or DoesNotExist, + the values array must be empty. This array is replaced during a strategic + merge patch. + items: + type: string + type: array + x-kubernetes-list-type: atomic + required: + - key + - operator + type: object + type: array + x-kubernetes-list-type: atomic + matchLabels: + additionalProperties: + type: string + description: |- + matchLabels is a map of {key,value} pairs. A single {key,value} in the matchLabels + map is equivalent to an element of matchExpressions, whose key field is "key", the + operator is "In", and the values array contains only "value". The requirements are ANDed. + type: object + type: object + x-kubernetes-map-type: atomic + matchLabelKeys: + description: |- + MatchLabelKeys is a set of pod label keys to select which pods will + be taken into consideration. The keys are used to lookup values from the + incoming pod labels, those key-value labels are merged with `labelSelector` as `key in (value)` + to select the group of existing pods which pods will be taken into consideration + for the incoming pod's pod (anti) affinity. Keys that don't exist in the incoming + pod labels will be ignored. The default value is empty. + The same key is forbidden to exist in both matchLabelKeys and labelSelector. + Also, matchLabelKeys cannot be set when labelSelector isn't set. + items: + type: string + type: array + x-kubernetes-list-type: atomic + mismatchLabelKeys: + description: |- + MismatchLabelKeys is a set of pod label keys to select which pods will + be taken into consideration. The keys are used to lookup values from the + incoming pod labels, those key-value labels are merged with `labelSelector` as `key notin (value)` + to select the group of existing pods which pods will be taken into consideration + for the incoming pod's pod (anti) affinity. Keys that don't exist in the incoming + pod labels will be ignored. The default value is empty. + The same key is forbidden to exist in both mismatchLabelKeys and labelSelector. + Also, mismatchLabelKeys cannot be set when labelSelector isn't set. + items: + type: string + type: array + x-kubernetes-list-type: atomic + namespaceSelector: + description: |- + A label query over the set of namespaces that the term applies to. + The term is applied to the union of the namespaces selected by this field + and the ones listed in the namespaces field. + null selector and null or empty namespaces list means "this pod's namespace". + An empty selector ({}) matches all namespaces. + properties: + matchExpressions: + description: matchExpressions is a list + of label selector requirements. The + requirements are ANDed. + items: + description: |- + A label selector requirement is a selector that contains values, a key, and an operator that + relates the key and values. + properties: + key: + description: key is the label + key that the selector applies + to. + type: string + operator: + description: |- + operator represents a key's relationship to a set of values. + Valid operators are In, NotIn, Exists and DoesNotExist. + type: string + values: + description: |- + values is an array of string values. If the operator is In or NotIn, + the values array must be non-empty. If the operator is Exists or DoesNotExist, + the values array must be empty. This array is replaced during a strategic + merge patch. + items: + type: string + type: array + x-kubernetes-list-type: atomic + required: + - key + - operator + type: object + type: array + x-kubernetes-list-type: atomic + matchLabels: + additionalProperties: + type: string + description: |- + matchLabels is a map of {key,value} pairs. A single {key,value} in the matchLabels + map is equivalent to an element of matchExpressions, whose key field is "key", the + operator is "In", and the values array contains only "value". The requirements are ANDed. + type: object + type: object + x-kubernetes-map-type: atomic + namespaces: + description: |- + namespaces specifies a static list of namespace names that the term applies to. + The term is applied to the union of the namespaces listed in this field + and the ones selected by namespaceSelector. + null or empty namespaces list and null namespaceSelector means "this pod's namespace". + items: + type: string + type: array + x-kubernetes-list-type: atomic + topologyKey: + description: |- + This pod should be co-located (affinity) or not co-located (anti-affinity) with the pods matching + the labelSelector in the specified namespaces, where co-located is defined as running on a node + whose value of the label with key topologyKey matches that of any node on which any of the + selected pods is running. + Empty topologyKey is not allowed. + type: string + required: + - topologyKey + type: object + weight: + description: |- + weight associated with matching the corresponding podAffinityTerm, + in the range 1-100. + format: int32 + type: integer + required: + - podAffinityTerm + - weight + type: object + type: array + x-kubernetes-list-type: atomic + requiredDuringSchedulingIgnoredDuringExecution: + description: |- + If the affinity requirements specified by this field are not met at + scheduling time, the pod will not be scheduled onto the node. + If the affinity requirements specified by this field cease to be met + at some point during pod execution (e.g. due to a pod label update), the + system may or may not try to eventually evict the pod from its node. + When there are multiple elements, the lists of nodes corresponding to each + podAffinityTerm are intersected, i.e. all terms must be satisfied. + items: + description: |- + Defines a set of pods (namely those matching the labelSelector + relative to the given namespace(s)) that this pod should be + co-located (affinity) or not co-located (anti-affinity) with, + where co-located is defined as running on a node whose value of + the label with key matches that of any node on which + a pod of the set of pods is running + properties: + labelSelector: + description: |- + A label query over a set of resources, in this case pods. + If it's null, this PodAffinityTerm matches with no Pods. + properties: + matchExpressions: + description: matchExpressions is a list + of label selector requirements. The requirements + are ANDed. + items: + description: |- + A label selector requirement is a selector that contains values, a key, and an operator that + relates the key and values. + properties: + key: + description: key is the label key + that the selector applies to. + type: string + operator: + description: |- + operator represents a key's relationship to a set of values. + Valid operators are In, NotIn, Exists and DoesNotExist. + type: string + values: + description: |- + values is an array of string values. If the operator is In or NotIn, + the values array must be non-empty. If the operator is Exists or DoesNotExist, + the values array must be empty. This array is replaced during a strategic + merge patch. + items: + type: string + type: array + x-kubernetes-list-type: atomic + required: + - key + - operator + type: object + type: array + x-kubernetes-list-type: atomic + matchLabels: + additionalProperties: + type: string + description: |- + matchLabels is a map of {key,value} pairs. A single {key,value} in the matchLabels + map is equivalent to an element of matchExpressions, whose key field is "key", the + operator is "In", and the values array contains only "value". The requirements are ANDed. + type: object + type: object + x-kubernetes-map-type: atomic + matchLabelKeys: + description: |- + MatchLabelKeys is a set of pod label keys to select which pods will + be taken into consideration. The keys are used to lookup values from the + incoming pod labels, those key-value labels are merged with `labelSelector` as `key in (value)` + to select the group of existing pods which pods will be taken into consideration + for the incoming pod's pod (anti) affinity. Keys that don't exist in the incoming + pod labels will be ignored. The default value is empty. + The same key is forbidden to exist in both matchLabelKeys and labelSelector. + Also, matchLabelKeys cannot be set when labelSelector isn't set. + items: + type: string + type: array + x-kubernetes-list-type: atomic + mismatchLabelKeys: + description: |- + MismatchLabelKeys is a set of pod label keys to select which pods will + be taken into consideration. The keys are used to lookup values from the + incoming pod labels, those key-value labels are merged with `labelSelector` as `key notin (value)` + to select the group of existing pods which pods will be taken into consideration + for the incoming pod's pod (anti) affinity. Keys that don't exist in the incoming + pod labels will be ignored. The default value is empty. + The same key is forbidden to exist in both mismatchLabelKeys and labelSelector. + Also, mismatchLabelKeys cannot be set when labelSelector isn't set. + items: + type: string + type: array + x-kubernetes-list-type: atomic + namespaceSelector: + description: |- + A label query over the set of namespaces that the term applies to. + The term is applied to the union of the namespaces selected by this field + and the ones listed in the namespaces field. + null selector and null or empty namespaces list means "this pod's namespace". + An empty selector ({}) matches all namespaces. + properties: + matchExpressions: + description: matchExpressions is a list + of label selector requirements. The requirements + are ANDed. + items: + description: |- + A label selector requirement is a selector that contains values, a key, and an operator that + relates the key and values. + properties: + key: + description: key is the label key + that the selector applies to. + type: string + operator: + description: |- + operator represents a key's relationship to a set of values. + Valid operators are In, NotIn, Exists and DoesNotExist. + type: string + values: + description: |- + values is an array of string values. If the operator is In or NotIn, + the values array must be non-empty. If the operator is Exists or DoesNotExist, + the values array must be empty. This array is replaced during a strategic + merge patch. + items: + type: string + type: array + x-kubernetes-list-type: atomic + required: + - key + - operator + type: object + type: array + x-kubernetes-list-type: atomic + matchLabels: + additionalProperties: + type: string + description: |- + matchLabels is a map of {key,value} pairs. A single {key,value} in the matchLabels + map is equivalent to an element of matchExpressions, whose key field is "key", the + operator is "In", and the values array contains only "value". The requirements are ANDed. + type: object + type: object + x-kubernetes-map-type: atomic + namespaces: + description: |- + namespaces specifies a static list of namespace names that the term applies to. + The term is applied to the union of the namespaces listed in this field + and the ones selected by namespaceSelector. + null or empty namespaces list and null namespaceSelector means "this pod's namespace". + items: + type: string + type: array + x-kubernetes-list-type: atomic + topologyKey: + description: |- + This pod should be co-located (affinity) or not co-located (anti-affinity) with the pods matching + the labelSelector in the specified namespaces, where co-located is defined as running on a node + whose value of the label with key topologyKey matches that of any node on which any of the + selected pods is running. + Empty topologyKey is not allowed. + type: string + required: + - topologyKey + type: object + type: array + x-kubernetes-list-type: atomic + type: object + podAntiAffinity: + description: Describes pod anti-affinity scheduling rules + (e.g. avoid putting this pod in the same node, zone, + etc. as some other pod(s)). + properties: + preferredDuringSchedulingIgnoredDuringExecution: + description: |- + The scheduler will prefer to schedule pods to nodes that satisfy + the anti-affinity expressions specified by this field, but it may choose + a node that violates one or more of the expressions. The node that is + most preferred is the one with the greatest sum of weights, i.e. + for each node that meets all of the scheduling requirements (resource + request, requiredDuringScheduling anti-affinity expressions, etc.), + compute a sum by iterating through the elements of this field and subtracting + "weight" from the sum if the node has pods which matches the corresponding podAffinityTerm; the + node(s) with the highest sum are the most preferred. + items: + description: The weights of all of the matched WeightedPodAffinityTerm + fields are added per-node to find the most preferred + node(s) + properties: + podAffinityTerm: + description: Required. A pod affinity term, + associated with the corresponding weight. + properties: + labelSelector: + description: |- + A label query over a set of resources, in this case pods. + If it's null, this PodAffinityTerm matches with no Pods. + properties: + matchExpressions: + description: matchExpressions is a list + of label selector requirements. The + requirements are ANDed. + items: + description: |- + A label selector requirement is a selector that contains values, a key, and an operator that + relates the key and values. + properties: + key: + description: key is the label + key that the selector applies + to. + type: string + operator: + description: |- + operator represents a key's relationship to a set of values. + Valid operators are In, NotIn, Exists and DoesNotExist. + type: string + values: + description: |- + values is an array of string values. If the operator is In or NotIn, + the values array must be non-empty. If the operator is Exists or DoesNotExist, + the values array must be empty. This array is replaced during a strategic + merge patch. + items: + type: string + type: array + x-kubernetes-list-type: atomic + required: + - key + - operator + type: object + type: array + x-kubernetes-list-type: atomic + matchLabels: + additionalProperties: + type: string + description: |- + matchLabels is a map of {key,value} pairs. A single {key,value} in the matchLabels + map is equivalent to an element of matchExpressions, whose key field is "key", the + operator is "In", and the values array contains only "value". The requirements are ANDed. + type: object + type: object + x-kubernetes-map-type: atomic + matchLabelKeys: + description: |- + MatchLabelKeys is a set of pod label keys to select which pods will + be taken into consideration. The keys are used to lookup values from the + incoming pod labels, those key-value labels are merged with `labelSelector` as `key in (value)` + to select the group of existing pods which pods will be taken into consideration + for the incoming pod's pod (anti) affinity. Keys that don't exist in the incoming + pod labels will be ignored. The default value is empty. + The same key is forbidden to exist in both matchLabelKeys and labelSelector. + Also, matchLabelKeys cannot be set when labelSelector isn't set. + items: + type: string + type: array + x-kubernetes-list-type: atomic + mismatchLabelKeys: + description: |- + MismatchLabelKeys is a set of pod label keys to select which pods will + be taken into consideration. The keys are used to lookup values from the + incoming pod labels, those key-value labels are merged with `labelSelector` as `key notin (value)` + to select the group of existing pods which pods will be taken into consideration + for the incoming pod's pod (anti) affinity. Keys that don't exist in the incoming + pod labels will be ignored. The default value is empty. + The same key is forbidden to exist in both mismatchLabelKeys and labelSelector. + Also, mismatchLabelKeys cannot be set when labelSelector isn't set. + items: + type: string + type: array + x-kubernetes-list-type: atomic + namespaceSelector: + description: |- + A label query over the set of namespaces that the term applies to. + The term is applied to the union of the namespaces selected by this field + and the ones listed in the namespaces field. + null selector and null or empty namespaces list means "this pod's namespace". + An empty selector ({}) matches all namespaces. + properties: + matchExpressions: + description: matchExpressions is a list + of label selector requirements. The + requirements are ANDed. + items: + description: |- + A label selector requirement is a selector that contains values, a key, and an operator that + relates the key and values. + properties: + key: + description: key is the label + key that the selector applies + to. + type: string + operator: + description: |- + operator represents a key's relationship to a set of values. + Valid operators are In, NotIn, Exists and DoesNotExist. + type: string + values: + description: |- + values is an array of string values. If the operator is In or NotIn, + the values array must be non-empty. If the operator is Exists or DoesNotExist, + the values array must be empty. This array is replaced during a strategic + merge patch. + items: + type: string + type: array + x-kubernetes-list-type: atomic + required: + - key + - operator + type: object + type: array + x-kubernetes-list-type: atomic + matchLabels: + additionalProperties: + type: string + description: |- + matchLabels is a map of {key,value} pairs. A single {key,value} in the matchLabels + map is equivalent to an element of matchExpressions, whose key field is "key", the + operator is "In", and the values array contains only "value". The requirements are ANDed. + type: object + type: object + x-kubernetes-map-type: atomic + namespaces: + description: |- + namespaces specifies a static list of namespace names that the term applies to. + The term is applied to the union of the namespaces listed in this field + and the ones selected by namespaceSelector. + null or empty namespaces list and null namespaceSelector means "this pod's namespace". + items: + type: string + type: array + x-kubernetes-list-type: atomic + topologyKey: + description: |- + This pod should be co-located (affinity) or not co-located (anti-affinity) with the pods matching + the labelSelector in the specified namespaces, where co-located is defined as running on a node + whose value of the label with key topologyKey matches that of any node on which any of the + selected pods is running. + Empty topologyKey is not allowed. + type: string + required: + - topologyKey + type: object + weight: + description: |- + weight associated with matching the corresponding podAffinityTerm, + in the range 1-100. + format: int32 + type: integer + required: + - podAffinityTerm + - weight + type: object + type: array + x-kubernetes-list-type: atomic + requiredDuringSchedulingIgnoredDuringExecution: + description: |- + If the anti-affinity requirements specified by this field are not met at + scheduling time, the pod will not be scheduled onto the node. + If the anti-affinity requirements specified by this field cease to be met + at some point during pod execution (e.g. due to a pod label update), the + system may or may not try to eventually evict the pod from its node. + When there are multiple elements, the lists of nodes corresponding to each + podAffinityTerm are intersected, i.e. all terms must be satisfied. + items: + description: |- + Defines a set of pods (namely those matching the labelSelector + relative to the given namespace(s)) that this pod should be + co-located (affinity) or not co-located (anti-affinity) with, + where co-located is defined as running on a node whose value of + the label with key matches that of any node on which + a pod of the set of pods is running + properties: + labelSelector: + description: |- + A label query over a set of resources, in this case pods. + If it's null, this PodAffinityTerm matches with no Pods. + properties: + matchExpressions: + description: matchExpressions is a list + of label selector requirements. The requirements + are ANDed. + items: + description: |- + A label selector requirement is a selector that contains values, a key, and an operator that + relates the key and values. + properties: + key: + description: key is the label key + that the selector applies to. + type: string + operator: + description: |- + operator represents a key's relationship to a set of values. + Valid operators are In, NotIn, Exists and DoesNotExist. + type: string + values: + description: |- + values is an array of string values. If the operator is In or NotIn, + the values array must be non-empty. If the operator is Exists or DoesNotExist, + the values array must be empty. This array is replaced during a strategic + merge patch. + items: + type: string + type: array + x-kubernetes-list-type: atomic + required: + - key + - operator + type: object + type: array + x-kubernetes-list-type: atomic + matchLabels: + additionalProperties: + type: string + description: |- + matchLabels is a map of {key,value} pairs. A single {key,value} in the matchLabels + map is equivalent to an element of matchExpressions, whose key field is "key", the + operator is "In", and the values array contains only "value". The requirements are ANDed. + type: object + type: object + x-kubernetes-map-type: atomic + matchLabelKeys: + description: |- + MatchLabelKeys is a set of pod label keys to select which pods will + be taken into consideration. The keys are used to lookup values from the + incoming pod labels, those key-value labels are merged with `labelSelector` as `key in (value)` + to select the group of existing pods which pods will be taken into consideration + for the incoming pod's pod (anti) affinity. Keys that don't exist in the incoming + pod labels will be ignored. The default value is empty. + The same key is forbidden to exist in both matchLabelKeys and labelSelector. + Also, matchLabelKeys cannot be set when labelSelector isn't set. + items: + type: string + type: array + x-kubernetes-list-type: atomic + mismatchLabelKeys: + description: |- + MismatchLabelKeys is a set of pod label keys to select which pods will + be taken into consideration. The keys are used to lookup values from the + incoming pod labels, those key-value labels are merged with `labelSelector` as `key notin (value)` + to select the group of existing pods which pods will be taken into consideration + for the incoming pod's pod (anti) affinity. Keys that don't exist in the incoming + pod labels will be ignored. The default value is empty. + The same key is forbidden to exist in both mismatchLabelKeys and labelSelector. + Also, mismatchLabelKeys cannot be set when labelSelector isn't set. + items: + type: string + type: array + x-kubernetes-list-type: atomic + namespaceSelector: + description: |- + A label query over the set of namespaces that the term applies to. + The term is applied to the union of the namespaces selected by this field + and the ones listed in the namespaces field. + null selector and null or empty namespaces list means "this pod's namespace". + An empty selector ({}) matches all namespaces. + properties: + matchExpressions: + description: matchExpressions is a list + of label selector requirements. The requirements + are ANDed. + items: + description: |- + A label selector requirement is a selector that contains values, a key, and an operator that + relates the key and values. + properties: + key: + description: key is the label key + that the selector applies to. + type: string + operator: + description: |- + operator represents a key's relationship to a set of values. + Valid operators are In, NotIn, Exists and DoesNotExist. + type: string + values: + description: |- + values is an array of string values. If the operator is In or NotIn, + the values array must be non-empty. If the operator is Exists or DoesNotExist, + the values array must be empty. This array is replaced during a strategic + merge patch. + items: + type: string + type: array + x-kubernetes-list-type: atomic + required: + - key + - operator + type: object + type: array + x-kubernetes-list-type: atomic + matchLabels: + additionalProperties: + type: string + description: |- + matchLabels is a map of {key,value} pairs. A single {key,value} in the matchLabels + map is equivalent to an element of matchExpressions, whose key field is "key", the + operator is "In", and the values array contains only "value". The requirements are ANDed. + type: object + type: object + x-kubernetes-map-type: atomic + namespaces: + description: |- + namespaces specifies a static list of namespace names that the term applies to. + The term is applied to the union of the namespaces listed in this field + and the ones selected by namespaceSelector. + null or empty namespaces list and null namespaceSelector means "this pod's namespace". + items: + type: string + type: array + x-kubernetes-list-type: atomic + topologyKey: + description: |- + This pod should be co-located (affinity) or not co-located (anti-affinity) with the pods matching + the labelSelector in the specified namespaces, where co-located is defined as running on a node + whose value of the label with key topologyKey matches that of any node on which any of the + selected pods is running. + Empty topologyKey is not allowed. + type: string + required: + - topologyKey + type: object + type: array + x-kubernetes-list-type: atomic + type: object + type: object + nodeSelector: + additionalProperties: + type: string + description: |- + nodeSelector is the node selector applied to the relevant kind of pods + It specifies a map of key-value pairs: for the pod to be eligible to run on a node, + the node must have each of the indicated key-value pairs as labels + (it can have additional labels as well). + See https://kubernetes.io/docs/concepts/configuration/assign-pod-node/#nodeselector + type: object + tolerations: + description: |- + tolerations is a list of tolerations applied to the relevant kind of pods + See https://kubernetes.io/docs/concepts/configuration/taint-and-toleration/ for more info. + These are additional tolerations other than default ones. + items: + description: |- + The pod this Toleration is attached to tolerates any taint that matches + the triple using the matching operator . + properties: + effect: + description: |- + Effect indicates the taint effect to match. Empty means match all taint effects. + When specified, allowed values are NoSchedule, PreferNoSchedule and NoExecute. + type: string + key: + description: |- + Key is the taint key that the toleration applies to. Empty means match all taint keys. + If the key is empty, operator must be Exists; this combination means to match all values and all keys. + type: string + operator: + description: |- + Operator represents a key's relationship to the value. + Valid operators are Exists and Equal. Defaults to Equal. + Exists is equivalent to wildcard for value, so that a pod can + tolerate all taints of a particular category. + type: string + tolerationSeconds: + description: |- + TolerationSeconds represents the period of time the toleration (which must be + of effect NoExecute, otherwise this field is ignored) tolerates the taint. By default, + it is not set, which means tolerate the taint forever (do not evict). Zero and + negative values will be treated as 0 (evict immediately) by the system. + format: int64 + type: integer + value: + description: |- + Value is the taint value the toleration matches to. + If the operator is Exists, the value should be empty, otherwise just a regular string. + type: string + type: object + type: array + type: object + type: object + type: object + status: + description: HyperConvergedStatus defines the observed state of HyperConverged + properties: + conditions: + description: Conditions describes the state of the HyperConverged + resource. + items: + description: Condition contains details for one aspect of the current + state of this API Resource. + properties: + lastTransitionTime: + description: |- + lastTransitionTime is the last time the condition transitioned from one status to another. + This should be when the underlying condition changed. If that is not known, then using the time when the API field changed is acceptable. + format: date-time + type: string + message: + description: |- + message is a human readable message indicating details about the transition. + This may be an empty string. + maxLength: 32768 + type: string + observedGeneration: + description: |- + observedGeneration represents the .metadata.generation that the condition was set based upon. + For instance, if .metadata.generation is currently 12, but the .status.conditions[x].observedGeneration is 9, the condition is out of date + with respect to the current state of the instance. + format: int64 + minimum: 0 + type: integer + reason: + description: |- + reason contains a programmatic identifier indicating the reason for the condition's last transition. + Producers of specific condition types may define expected values and meanings for this field, + and whether the values are considered a guaranteed API. + The value should be a CamelCase string. + This field may not be empty. + maxLength: 1024 + minLength: 1 + pattern: ^[A-Za-z]([A-Za-z0-9_,:]*[A-Za-z0-9_])?$ + type: string + status: + description: status of the condition, one of True, False, Unknown. + enum: + - "True" + - "False" + - Unknown + type: string + type: + description: type of condition in CamelCase or in foo.example.com/CamelCase. + maxLength: 316 + pattern: ^([a-z0-9]([-a-z0-9]*[a-z0-9])?(\.[a-z0-9]([-a-z0-9]*[a-z0-9])?)*/)?(([A-Za-z0-9][-A-Za-z0-9_.]*)?[A-Za-z0-9])$ + type: string + required: + - lastTransitionTime + - message + - reason + - status + - type + type: object + type: array + x-kubernetes-list-type: atomic + dataImportCronTemplates: + description: |- + DataImportCronTemplates is a list of the actual DataImportCronTemplates as HCO update in the SSP CR. The list + contains both the common and the custom templates, including any modification done by HCO. + items: + description: DataImportCronTemplateStatus is a copy of a dataImportCronTemplate + as defined in the spec, or in the HCO image. + properties: + metadata: + properties: + annotations: + additionalProperties: + type: string + type: object + finalizers: + items: + type: string + type: array + labels: + additionalProperties: + type: string + type: object + name: + type: string + namespace: + type: string + type: object + spec: + description: DataImportCronSpec defines specification for DataImportCron + properties: + garbageCollect: + description: |- + GarbageCollect specifies whether old PVCs should be cleaned up after a new PVC is imported. + Options are currently "Outdated" and "Never", defaults to "Outdated". + type: string + importsToKeep: + description: Number of import PVCs to keep when garbage + collecting. Default is 3. + format: int32 + type: integer + managedDataSource: + description: |- + ManagedDataSource specifies the name of the corresponding DataSource this cron will manage. + DataSource has to be in the same namespace. + type: string + retentionPolicy: + description: RetentionPolicy specifies whether the created + DataVolumes and DataSources are retained when their DataImportCron + is deleted. Default is RatainAll. + type: string + schedule: + description: Schedule specifies in cron format when and + how often to look for new imports + type: string + serviceAccountName: + description: ServiceAccountName is the name of the ServiceAccount + for creating DataVolumes. + minLength: 1 + type: string + template: + description: Template specifies template for the DVs to + be created + properties: + apiVersion: + description: |- + APIVersion defines the versioned schema of this representation of an object. + Servers should convert recognized schemas to the latest internal value, and + may reject unrecognized values. + More info: https://git.k8s.io/community/contributors/devel/sig-architecture/api-conventions.md#resources + type: string + kind: + description: |- + Kind is a string value representing the REST resource this object represents. + Servers may infer this from the endpoint the client submits requests to. + Cannot be updated. + In CamelCase. + More info: https://git.k8s.io/community/contributors/devel/sig-architecture/api-conventions.md#types-kinds + type: string + metadata: + properties: + annotations: + additionalProperties: + type: string + type: object + finalizers: + items: + type: string + type: array + labels: + additionalProperties: + type: string + type: object + name: + type: string + namespace: + type: string + type: object + spec: + description: DataVolumeSpec defines the DataVolume type + specification + properties: + checkpoints: + description: Checkpoints is a list of DataVolumeCheckpoints, + representing stages in a multistage import. + items: + description: DataVolumeCheckpoint defines a stage + in a warm migration. + properties: + current: + description: Current is the identifier of + the snapshot created for this checkpoint. + type: string + previous: + description: Previous is the identifier of + the snapshot from the previous checkpoint. + type: string + required: + - current + - previous + type: object + type: array + contentType: + description: 'DataVolumeContentType options: "kubevirt", + "archive"' + enum: + - kubevirt + - archive + type: string + finalCheckpoint: + description: FinalCheckpoint indicates whether the + current DataVolumeCheckpoint is the final checkpoint. + type: boolean + preallocation: + description: Preallocation controls whether storage + for DataVolumes should be allocated in advance. + type: boolean + priorityClassName: + description: PriorityClassName for Importer, Cloner + and Uploader pod + type: string + pvc: + description: PVC is the PVC specification + properties: + accessModes: + description: |- + accessModes contains the desired access modes the volume should have. + More info: https://kubernetes.io/docs/concepts/storage/persistent-volumes#access-modes-1 + items: + type: string + type: array + x-kubernetes-list-type: atomic + dataSource: + description: |- + dataSource field can be used to specify either: + * An existing VolumeSnapshot object (snapshot.storage.k8s.io/VolumeSnapshot) + * An existing PVC (PersistentVolumeClaim) + If the provisioner or an external controller can support the specified data source, + it will create a new volume based on the contents of the specified data source. + When the AnyVolumeDataSource feature gate is enabled, dataSource contents will be copied to dataSourceRef, + and dataSourceRef contents will be copied to dataSource when dataSourceRef.namespace is not specified. + If the namespace is specified, then dataSourceRef will not be copied to dataSource. + properties: + apiGroup: + description: |- + APIGroup is the group for the resource being referenced. + If APIGroup is not specified, the specified Kind must be in the core API group. + For any other third-party types, APIGroup is required. + type: string + kind: + description: Kind is the type of resource + being referenced + type: string + name: + description: Name is the name of resource + being referenced + type: string + required: + - kind + - name + type: object + x-kubernetes-map-type: atomic + dataSourceRef: + description: |- + dataSourceRef specifies the object from which to populate the volume with data, if a non-empty + volume is desired. This may be any object from a non-empty API group (non + core object) or a PersistentVolumeClaim object. + When this field is specified, volume binding will only succeed if the type of + the specified object matches some installed volume populator or dynamic + provisioner. + This field will replace the functionality of the dataSource field and as such + if both fields are non-empty, they must have the same value. For backwards + compatibility, when namespace isn't specified in dataSourceRef, + both fields (dataSource and dataSourceRef) will be set to the same + value automatically if one of them is empty and the other is non-empty. + When namespace is specified in dataSourceRef, + dataSource isn't set to the same value and must be empty. + There are three important differences between dataSource and dataSourceRef: + * While dataSource only allows two specific types of objects, dataSourceRef + allows any non-core object, as well as PersistentVolumeClaim objects. + * While dataSource ignores disallowed values (dropping them), dataSourceRef + preserves all values, and generates an error if a disallowed value is + specified. + * While dataSource only allows local objects, dataSourceRef allows objects + in any namespaces. + (Beta) Using this field requires the AnyVolumeDataSource feature gate to be enabled. + (Alpha) Using the namespace field of dataSourceRef requires the CrossNamespaceVolumeDataSource feature gate to be enabled. + properties: + apiGroup: + description: |- + APIGroup is the group for the resource being referenced. + If APIGroup is not specified, the specified Kind must be in the core API group. + For any other third-party types, APIGroup is required. + type: string + kind: + description: Kind is the type of resource + being referenced + type: string + name: + description: Name is the name of resource + being referenced + type: string + namespace: + description: |- + Namespace is the namespace of resource being referenced + Note that when a namespace is specified, a gateway.networking.k8s.io/ReferenceGrant object is required in the referent namespace to allow that namespace's owner to accept the reference. See the ReferenceGrant documentation for details. + (Alpha) This field requires the CrossNamespaceVolumeDataSource feature gate to be enabled. + type: string + required: + - kind + - name + type: object + resources: + description: |- + resources represents the minimum resources the volume should have. + If RecoverVolumeExpansionFailure feature is enabled users are allowed to specify resource requirements + that are lower than previous value but must still be higher than capacity recorded in the + status field of the claim. + More info: https://kubernetes.io/docs/concepts/storage/persistent-volumes#resources + properties: + limits: + additionalProperties: + anyOf: + - type: integer + - type: string + pattern: ^(\+|-)?(([0-9]+(\.[0-9]*)?)|(\.[0-9]+))(([KMGTPE]i)|[numkMGTPE]|([eE](\+|-)?(([0-9]+(\.[0-9]*)?)|(\.[0-9]+))))?$ + x-kubernetes-int-or-string: true + description: |- + Limits describes the maximum amount of compute resources allowed. + More info: https://kubernetes.io/docs/concepts/configuration/manage-resources-containers/ + type: object + requests: + additionalProperties: + anyOf: + - type: integer + - type: string + pattern: ^(\+|-)?(([0-9]+(\.[0-9]*)?)|(\.[0-9]+))(([KMGTPE]i)|[numkMGTPE]|([eE](\+|-)?(([0-9]+(\.[0-9]*)?)|(\.[0-9]+))))?$ + x-kubernetes-int-or-string: true + description: |- + Requests describes the minimum amount of compute resources required. + If Requests is omitted for a container, it defaults to Limits if that is explicitly specified, + otherwise to an implementation-defined value. Requests cannot exceed Limits. + More info: https://kubernetes.io/docs/concepts/configuration/manage-resources-containers/ + type: object + type: object + selector: + description: selector is a label query over + volumes to consider for binding. + properties: + matchExpressions: + description: matchExpressions is a list + of label selector requirements. The requirements + are ANDed. + items: + description: |- + A label selector requirement is a selector that contains values, a key, and an operator that + relates the key and values. + properties: + key: + description: key is the label key + that the selector applies to. + type: string + operator: + description: |- + operator represents a key's relationship to a set of values. + Valid operators are In, NotIn, Exists and DoesNotExist. + type: string + values: + description: |- + values is an array of string values. If the operator is In or NotIn, + the values array must be non-empty. If the operator is Exists or DoesNotExist, + the values array must be empty. This array is replaced during a strategic + merge patch. + items: + type: string + type: array + x-kubernetes-list-type: atomic + required: + - key + - operator + type: object + type: array + x-kubernetes-list-type: atomic + matchLabels: + additionalProperties: + type: string + description: |- + matchLabels is a map of {key,value} pairs. A single {key,value} in the matchLabels + map is equivalent to an element of matchExpressions, whose key field is "key", the + operator is "In", and the values array contains only "value". The requirements are ANDed. + type: object + type: object + x-kubernetes-map-type: atomic + storageClassName: + description: |- + storageClassName is the name of the StorageClass required by the claim. + More info: https://kubernetes.io/docs/concepts/storage/persistent-volumes#class-1 + type: string + volumeAttributesClassName: + description: |- + volumeAttributesClassName may be used to set the VolumeAttributesClass used by this claim. + If specified, the CSI driver will create or update the volume with the attributes defined + in the corresponding VolumeAttributesClass. This has a different purpose than storageClassName, + it can be changed after the claim is created. An empty string or nil value indicates that no + VolumeAttributesClass will be applied to the claim. If the claim enters an Infeasible error state, + this field can be reset to its previous value (including nil) to cancel the modification. + If the resource referred to by volumeAttributesClass does not exist, this PersistentVolumeClaim will be + set to a Pending state, as reflected by the modifyVolumeStatus field, until such as a resource + exists. + More info: https://kubernetes.io/docs/concepts/storage/volume-attributes-classes/ + type: string + volumeMode: + description: |- + volumeMode defines what type of volume is required by the claim. + Value of Filesystem is implied when not included in claim spec. + type: string + volumeName: + description: volumeName is the binding reference + to the PersistentVolume backing this claim. + type: string + type: object + source: + description: Source is the src of the data for the + requested DataVolume + properties: + blank: + description: DataVolumeBlankImage provides the + parameters to create a new raw blank image + for the PVC + type: object + gcs: + description: DataVolumeSourceGCS provides the + parameters to create a Data Volume from an + GCS source + properties: + secretRef: + description: SecretRef provides the secret + reference needed to access the GCS source + type: string + url: + description: URL is the url of the GCS source + type: string + required: + - url + type: object + http: + description: DataVolumeSourceHTTP can be either + an http or https endpoint, with an optional + basic auth user name and password, and an + optional configmap containing additional CAs + properties: + certConfigMap: + description: CertConfigMap is a configmap + reference, containing a Certificate Authority(CA) + public key, and a base64 encoded pem certificate + type: string + extraHeaders: + description: ExtraHeaders is a list of strings + containing extra headers to include with + HTTP transfer requests + items: + type: string + type: array + secretExtraHeaders: + description: SecretExtraHeaders is a list + of Secret references, each containing + an extra HTTP header that may include + sensitive information + items: + type: string + type: array + secretRef: + description: SecretRef A Secret reference, + the secret should contain accessKeyId + (user name) base64 encoded, and secretKey + (password) also base64 encoded + type: string + url: + description: URL is the URL of the http(s) + endpoint + type: string + required: + - url + type: object + imageio: + description: DataVolumeSourceImageIO provides + the parameters to create a Data Volume from + an imageio source + properties: + certConfigMap: + description: CertConfigMap provides a reference + to the CA cert + type: string + diskId: + description: DiskID provides id of a disk + to be imported + type: string + insecureSkipVerify: + description: InsecureSkipVerify is a flag + to skip certificate verification + type: boolean + secretRef: + description: SecretRef provides the secret + reference needed to access the ovirt-engine + type: string + url: + description: URL is the URL of the ovirt-engine + type: string + required: + - diskId + - url + type: object + pvc: + description: DataVolumeSourcePVC provides the + parameters to create a Data Volume from an + existing PVC + properties: + name: + description: The name of the source PVC + type: string + namespace: + description: The namespace of the source + PVC + type: string + required: + - name + - namespace + type: object + registry: + description: DataVolumeSourceRegistry provides + the parameters to create a Data Volume from + an registry source + properties: + certConfigMap: + description: CertConfigMap provides a reference + to the Registry certs + type: string + imageStream: + description: ImageStream is the name of + image stream for import + type: string + platform: + description: Platform describes the minimum + runtime requirements of the image + properties: + architecture: + description: Architecture specifies + the image target CPU architecture + type: string + type: object + pullMethod: + description: PullMethod can be either "pod" + (default import), or "node" (node docker + cache based import) + type: string + secretRef: + description: SecretRef provides the secret + reference needed to access the Registry + source + type: string + url: + description: 'URL is the url of the registry + source (starting with the scheme: docker, + oci-archive)' + type: string + type: object + s3: + description: DataVolumeSourceS3 provides the + parameters to create a Data Volume from an + S3 source + properties: + certConfigMap: + description: CertConfigMap is a configmap + reference, containing a Certificate Authority(CA) + public key, and a base64 encoded pem certificate + type: string + secretRef: + description: SecretRef provides the secret + reference needed to access the S3 source + type: string + url: + description: URL is the url of the S3 source + type: string + required: + - url + type: object + snapshot: + description: DataVolumeSourceSnapshot provides + the parameters to create a Data Volume from + an existing VolumeSnapshot + properties: + name: + description: The name of the source VolumeSnapshot + type: string + namespace: + description: The namespace of the source + VolumeSnapshot + type: string + required: + - name + - namespace + type: object + upload: + description: DataVolumeSourceUpload provides + the parameters to create a Data Volume by + uploading the source + type: object + vddk: + description: DataVolumeSourceVDDK provides the + parameters to create a Data Volume from a + Vmware source + properties: + backingFile: + description: BackingFile is the path to + the virtual hard disk to migrate from + vCenter/ESXi + type: string + extraArgs: + description: ExtraArgs is a reference to + a ConfigMap containing extra arguments + to pass directly to the VDDK library + type: string + initImageURL: + description: InitImageURL is an optional + URL to an image containing an extracted + VDDK library, overrides v2v-vmware config + map + type: string + secretRef: + description: SecretRef provides a reference + to a secret containing the username and + password needed to access the vCenter + or ESXi host + type: string + thumbprint: + description: Thumbprint is the certificate + thumbprint of the vCenter or ESXi host + type: string + url: + description: URL is the URL of the vCenter + or ESXi host with the VM to migrate + type: string + uuid: + description: UUID is the UUID of the virtual + machine that the backing file is attached + to in vCenter/ESXi + type: string + type: object + type: object + sourceRef: + description: SourceRef is an indirect reference + to the source of data for the requested DataVolume + properties: + kind: + description: The kind of the source reference, + currently only "DataSource" is supported + type: string + name: + description: The name of the source reference + type: string + namespace: + description: The namespace of the source reference, + defaults to the DataVolume namespace + type: string + required: + - kind + - name + type: object + storage: + description: Storage is the requested storage specification + properties: + accessModes: + description: |- + AccessModes contains the desired access modes the volume should have. + More info: https://kubernetes.io/docs/concepts/storage/persistent-volumes#access-modes-1 + items: + type: string + type: array + dataSource: + description: |- + This field can be used to specify either: * An existing VolumeSnapshot object (snapshot.storage.k8s.io/VolumeSnapshot) * An existing PVC (PersistentVolumeClaim) * An existing custom resource that implements data population (Alpha) In order to use custom resource types that implement data population, the AnyVolumeDataSource feature gate must be enabled. If the provisioner or an external controller can support the specified data source, it will create a new volume based on the contents of the specified data source. + If the AnyVolumeDataSource feature gate is enabled, this field will always have the same contents as the DataSourceRef field. + properties: + apiGroup: + description: |- + APIGroup is the group for the resource being referenced. + If APIGroup is not specified, the specified Kind must be in the core API group. + For any other third-party types, APIGroup is required. + type: string + kind: + description: Kind is the type of resource + being referenced + type: string + name: + description: Name is the name of resource + being referenced + type: string + required: + - kind + - name + type: object + x-kubernetes-map-type: atomic + dataSourceRef: + description: |- + Specifies the object from which to populate the volume with data, if a non-empty volume is desired. This may be any local object from a non-empty API group (non core object) or a PersistentVolumeClaim object. When this field is specified, volume binding will only succeed if the type of the specified object matches some installed volume populator or dynamic provisioner. + This field will replace the functionality of the DataSource field and as such if both fields are non-empty, they must have the same value. For backwards compatibility, both fields (DataSource and DataSourceRef) will be set to the same value automatically if one of them is empty and the other is non-empty. + There are two important differences between DataSource and DataSourceRef: + * While DataSource only allows two specific types of objects, DataSourceRef allows any non-core object, as well as PersistentVolumeClaim objects. + * While DataSource ignores disallowed values (dropping them), DataSourceRef preserves all values, and generates an error if a disallowed value is specified. + (Beta) Using this field requires the AnyVolumeDataSource feature gate to be enabled. + properties: + apiGroup: + description: |- + APIGroup is the group for the resource being referenced. + If APIGroup is not specified, the specified Kind must be in the core API group. + For any other third-party types, APIGroup is required. + type: string + kind: + description: Kind is the type of resource + being referenced + type: string + name: + description: Name is the name of resource + being referenced + type: string + namespace: + description: |- + Namespace is the namespace of resource being referenced + Note that when a namespace is specified, a gateway.networking.k8s.io/ReferenceGrant object is required in the referent namespace to allow that namespace's owner to accept the reference. See the ReferenceGrant documentation for details. + (Alpha) This field requires the CrossNamespaceVolumeDataSource feature gate to be enabled. + type: string + required: + - kind + - name + type: object + resources: + description: |- + Resources represents the minimum resources the volume should have. + More info: https://kubernetes.io/docs/concepts/storage/persistent-volumes#resources + properties: + limits: + additionalProperties: + anyOf: + - type: integer + - type: string + pattern: ^(\+|-)?(([0-9]+(\.[0-9]*)?)|(\.[0-9]+))(([KMGTPE]i)|[numkMGTPE]|([eE](\+|-)?(([0-9]+(\.[0-9]*)?)|(\.[0-9]+))))?$ + x-kubernetes-int-or-string: true + description: |- + Limits describes the maximum amount of compute resources allowed. + More info: https://kubernetes.io/docs/concepts/configuration/manage-resources-containers/ + type: object + requests: + additionalProperties: + anyOf: + - type: integer + - type: string + pattern: ^(\+|-)?(([0-9]+(\.[0-9]*)?)|(\.[0-9]+))(([KMGTPE]i)|[numkMGTPE]|([eE](\+|-)?(([0-9]+(\.[0-9]*)?)|(\.[0-9]+))))?$ + x-kubernetes-int-or-string: true + description: |- + Requests describes the minimum amount of compute resources required. + If Requests is omitted for a container, it defaults to Limits if that is explicitly specified, + otherwise to an implementation-defined value. Requests cannot exceed Limits. + More info: https://kubernetes.io/docs/concepts/configuration/manage-resources-containers/ + type: object + type: object + selector: + description: A label query over volumes to consider + for binding. + properties: + matchExpressions: + description: matchExpressions is a list + of label selector requirements. The requirements + are ANDed. + items: + description: |- + A label selector requirement is a selector that contains values, a key, and an operator that + relates the key and values. + properties: + key: + description: key is the label key + that the selector applies to. + type: string + operator: + description: |- + operator represents a key's relationship to a set of values. + Valid operators are In, NotIn, Exists and DoesNotExist. + type: string + values: + description: |- + values is an array of string values. If the operator is In or NotIn, + the values array must be non-empty. If the operator is Exists or DoesNotExist, + the values array must be empty. This array is replaced during a strategic + merge patch. + items: + type: string + type: array + x-kubernetes-list-type: atomic + required: + - key + - operator + type: object + type: array + x-kubernetes-list-type: atomic + matchLabels: + additionalProperties: + type: string + description: |- + matchLabels is a map of {key,value} pairs. A single {key,value} in the matchLabels + map is equivalent to an element of matchExpressions, whose key field is "key", the + operator is "In", and the values array contains only "value". The requirements are ANDed. + type: object + type: object + x-kubernetes-map-type: atomic + storageClassName: + description: |- + Name of the StorageClass required by the claim. + More info: https://kubernetes.io/docs/concepts/storage/persistent-volumes#class-1 + type: string + volumeMode: + description: |- + volumeMode defines what type of volume is required by the claim. + Value of Filesystem is implied when not included in claim spec. + type: string + volumeName: + description: VolumeName is the binding reference + to the PersistentVolume backing this claim. + type: string + type: object + type: object + status: + description: DataVolumeStatus contains the current status + of the DataVolume + properties: + claimName: + description: ClaimName is the name of the underlying + PVC used by the DataVolume. + type: string + conditions: + items: + description: DataVolumeCondition represents the + state of a data volume condition. + properties: + lastHeartbeatTime: + format: date-time + type: string + lastTransitionTime: + format: date-time + type: string + message: + type: string + reason: + type: string + status: + type: string + type: + description: DataVolumeConditionType is the + string representation of known condition + types + type: string + required: + - status + - type + type: object + type: array + phase: + description: Phase is the current phase of the data + volume + type: string + progress: + description: DataVolumeProgress is the current progress + of the DataVolume transfer operation. Value between + 0 and 100 inclusive, N/A if not available + type: string + restartCount: + description: RestartCount is the number of times + the pod populating the DataVolume has restarted + format: int32 + type: integer + type: object + required: + - spec + type: object + required: + - managedDataSource + - schedule + - template + type: object + status: + description: DataImportCronStatus is the status field of the + DIC template + properties: + commonTemplate: + description: CommonTemplate indicates whether this is a + common template (true), or a custom one (false) + type: boolean + conditions: + description: Conditions is a list of conditions that describe + the state of the DataImportCronTemplate. + items: + description: Condition contains details for one aspect + of the current state of this API Resource. + properties: + lastTransitionTime: + description: |- + lastTransitionTime is the last time the condition transitioned from one status to another. + This should be when the underlying condition changed. If that is not known, then using the time when the API field changed is acceptable. + format: date-time + type: string + message: + description: |- + message is a human readable message indicating details about the transition. + This may be an empty string. + maxLength: 32768 + type: string + observedGeneration: + description: |- + observedGeneration represents the .metadata.generation that the condition was set based upon. + For instance, if .metadata.generation is currently 12, but the .status.conditions[x].observedGeneration is 9, the condition is out of date + with respect to the current state of the instance. + format: int64 + minimum: 0 + type: integer + reason: + description: |- + reason contains a programmatic identifier indicating the reason for the condition's last transition. + Producers of specific condition types may define expected values and meanings for this field, + and whether the values are considered a guaranteed API. + The value should be a CamelCase string. + This field may not be empty. + maxLength: 1024 + minLength: 1 + pattern: ^[A-Za-z]([A-Za-z0-9_,:]*[A-Za-z0-9_])?$ + type: string + status: + description: status of the condition, one of True, + False, Unknown. + enum: + - "True" + - "False" + - Unknown + type: string + type: + description: type of condition in CamelCase or in + foo.example.com/CamelCase. + maxLength: 316 + pattern: ^([a-z0-9]([-a-z0-9]*[a-z0-9])?(\.[a-z0-9]([-a-z0-9]*[a-z0-9])?)*/)?(([A-Za-z0-9][-A-Za-z0-9_.]*)?[A-Za-z0-9])$ + type: string + required: + - lastTransitionTime + - message + - reason + - status + - type + type: object + type: array + modified: + description: Modified indicates if a common template was + customized. Always false for custom templates. + type: boolean + originalSupportedArchitectures: + description: |- + OriginalSupportedArchitectures is a comma-separated list of CPU architectures that the original + template supports. + type: string + type: object + type: object + type: array + dataImportSchedule: + description: |- + DataImportSchedule is the cron expression that is used in for the hard-coded data import cron templates. HCO + generates the value of this field once and stored in the status field, so will survive restart. + type: string + infrastructureHighlyAvailable: + description: |- + InfrastructureHighlyAvailable describes whether the cluster has only one worker node + (false) or more (true). + type: boolean + nodeInfo: + description: NodeInfo holds information about the cluster nodes + properties: + controlPlaneArchitectures: + description: ControlPlaneArchitectures is a distinct list of the + CPU architecture of the control-plane nodes. + items: + type: string + type: array + workloadsArchitectures: + description: WorkloadsArchitectures is a distinct list of the + CPU architectures of the workloads nodes in the cluster. + items: + type: string + type: array + type: object + observedGeneration: + description: |- + ObservedGeneration reflects the HyperConverged resource generation. If the ObservedGeneration is less than the + resource generation in metadata, the status is out of date + format: int64 + type: integer + relatedObjects: + description: |- + RelatedObjects is a list of objects created and maintained by this + operator. Object references will be added to this list after they have + been created AND found in the cluster. + items: + description: ObjectReference contains enough information to let + you inspect or modify the referred object. + properties: + apiVersion: + description: API version of the referent. + type: string + fieldPath: + description: |- + If referring to a piece of an object instead of an entire object, this string + should contain a valid JSON/Go field access statement, such as desiredState.manifest.containers[2]. + For example, if the object reference is to a container within a pod, this would take on a value like: + "spec.containers{name}" (where "name" refers to the name of the container that triggered + the event) or if no container name is specified "spec.containers[2]" (container with + index 2 in this pod). This syntax is chosen only to have some well-defined way of + referencing a part of an object. + type: string + kind: + description: |- + Kind of the referent. + More info: https://git.k8s.io/community/contributors/devel/sig-architecture/api-conventions.md#types-kinds + type: string + name: + description: |- + Name of the referent. + More info: https://kubernetes.io/docs/concepts/overview/working-with-objects/names/#names + type: string + namespace: + description: |- + Namespace of the referent. + More info: https://kubernetes.io/docs/concepts/overview/working-with-objects/namespaces/ + type: string + resourceVersion: + description: |- + Specific resourceVersion to which this reference is made, if any. + More info: https://git.k8s.io/community/contributors/devel/sig-architecture/api-conventions.md#concurrency-control-and-consistency + type: string + uid: + description: |- + UID of the referent. + More info: https://kubernetes.io/docs/concepts/overview/working-with-objects/names/#uids + type: string + type: object + x-kubernetes-map-type: atomic + type: array + x-kubernetes-list-type: atomic + systemHealthStatus: + description: SystemHealthStatus reflects the health of HCO and its + secondary resources, based on the aggregated conditions. + type: string + versions: + description: |- + Versions is a list of HCO component versions, as name/version pairs. The version with a name of "operator" + is the HCO version itself, as described here: + https://github.com/openshift/cluster-version-operator/blob/master/docs/dev/clusteroperator.md#version + items: + properties: + name: + type: string + version: + type: string + type: object + type: array + x-kubernetes-list-type: atomic + type: object + type: object + served: true + storage: false + subresources: + status: {} - additionalPrinterColumns: - jsonPath: .metadata.creationTimestamp name: Age diff --git a/deploy/index-image/community-kubevirt-hyperconverged/1.18.0/manifests/kubevirt-hyperconverged-operator.v1.18.0.clusterserviceversion.yaml b/deploy/index-image/community-kubevirt-hyperconverged/1.18.0/manifests/kubevirt-hyperconverged-operator.v1.18.0.clusterserviceversion.yaml index c792d0af56..7c8c10bbc7 100644 --- a/deploy/index-image/community-kubevirt-hyperconverged/1.18.0/manifests/kubevirt-hyperconverged-operator.v1.18.0.clusterserviceversion.yaml +++ b/deploy/index-image/community-kubevirt-hyperconverged/1.18.0/manifests/kubevirt-hyperconverged-operator.v1.18.0.clusterserviceversion.yaml @@ -407,6 +407,8 @@ spec: verbs: - get - list + - update + - patch - watch - delete - apiGroups: @@ -5542,6 +5544,30 @@ spec: deploymentName: hco-webhook failurePolicy: Fail generateName: validate-hco.kubevirt.io + matchPolicy: Exact + rules: + - apiGroups: + - hco.kubevirt.io + apiVersions: + - v1 + operations: + - CREATE + - DELETE + - UPDATE + resources: + - hyperconvergeds + sideEffects: None + timeoutSeconds: 10 + type: ValidatingAdmissionWebhook + webhookPath: /validate-hco-kubevirt-io-v1-hyperconverged + - admissionReviewVersions: + - v1beta1 + - v1 + containerPort: 4343 + deploymentName: hco-webhook + failurePolicy: Fail + generateName: validate-hco-v1beta1.kubevirt.io + matchPolicy: Exact rules: - apiGroups: - hco.kubevirt.io @@ -5587,6 +5613,29 @@ spec: deploymentName: hco-webhook failurePolicy: Fail generateName: mutate-hyperconverged-hco.kubevirt.io + matchPolicy: Exact + rules: + - apiGroups: + - hco.kubevirt.io + apiVersions: + - v1 + operations: + - CREATE + - UPDATE + resources: + - hyperconvergeds + sideEffects: NoneOnDryRun + timeoutSeconds: 10 + type: MutatingAdmissionWebhook + webhookPath: /mutate-hco-kubevirt-io-v1-hyperconverged + - admissionReviewVersions: + - v1beta1 + - v1 + containerPort: 4343 + deploymentName: hco-webhook + failurePolicy: Fail + generateName: mutate-hyperconverged-hco-v1beta1.kubevirt.io + matchPolicy: Exact rules: - apiGroups: - hco.kubevirt.io diff --git a/deploy/olm-catalog/community-kubevirt-hyperconverged/1.18.0/manifests/hco00.crd.yaml b/deploy/olm-catalog/community-kubevirt-hyperconverged/1.18.0/manifests/hco00.crd.yaml index d7b0d4cb77..a1cebffd93 100644 --- a/deploy/olm-catalog/community-kubevirt-hyperconverged/1.18.0/manifests/hco00.crd.yaml +++ b/deploy/olm-catalog/community-kubevirt-hyperconverged/1.18.0/manifests/hco00.crd.yaml @@ -17,6 +17,5186 @@ spec: singular: hyperconverged scope: Namespaced versions: + - additionalPrinterColumns: + - jsonPath: .metadata.creationTimestamp + name: Age + type: date + name: v1 + schema: + openAPIV3Schema: + description: HyperConverged is the Schema for the hyperconvergeds API + properties: + apiVersion: + description: |- + APIVersion defines the versioned schema of this representation of an object. + Servers should convert recognized schemas to the latest internal value, and + may reject unrecognized values. + More info: https://git.k8s.io/community/contributors/devel/sig-architecture/api-conventions.md#resources + type: string + kind: + description: |- + Kind is a string value representing the REST resource this object represents. + Servers may infer this from the endpoint the client submits requests to. + Cannot be updated. + In CamelCase. + More info: https://git.k8s.io/community/contributors/devel/sig-architecture/api-conventions.md#types-kinds + type: string + metadata: + properties: + name: + pattern: kubevirt-hyperconverged + type: string + type: object + spec: + default: + certConfig: + ca: + duration: 48h0m0s + renewBefore: 24h0m0s + server: + duration: 24h0m0s + renewBefore: 12h0m0s + deployVmConsoleProxy: false + enableApplicationAwareQuota: false + enableCommonBootImageImport: true + liveMigrationConfig: + allowAutoConverge: false + allowPostCopy: false + completionTimeoutPerGiB: 150 + parallelMigrationsPerCluster: 5 + parallelOutboundMigrationsPerNode: 2 + progressTimeout: 150 + resourceRequirements: + vmiCPUAllocationRatio: 10 + uninstallStrategy: BlockUninstallIfWorkloadsExist + virtualMachineOptions: + disableFreePageReporting: false + disableSerialConsoleLog: false + description: HyperConvergedSpec defines the desired state of HyperConverged + properties: + CommonInstancetypesDeployment: + description: CommonInstancetypesDeployment holds the configuration + of common-instancetypes deployment within KubeVirt. + properties: + enabled: + description: Enabled controls the deployment of common-instancetypes + resources, defaults to True. + nullable: true + type: boolean + type: object + applicationAwareConfig: + description: ApplicationAwareConfig set the AAQ configurations + properties: + allowApplicationAwareClusterResourceQuota: + default: false + description: AllowApplicationAwareClusterResourceQuota if set + to true, allows creation and management of ClusterAppsResourceQuota + type: boolean + namespaceSelector: + description: NamespaceSelector determines in which namespaces + scheduling gate will be added to pods.. + properties: + matchExpressions: + description: matchExpressions is a list of label selector + requirements. The requirements are ANDed. + items: + description: |- + A label selector requirement is a selector that contains values, a key, and an operator that + relates the key and values. + properties: + key: + description: key is the label key that the selector + applies to. + type: string + operator: + description: |- + operator represents a key's relationship to a set of values. + Valid operators are In, NotIn, Exists and DoesNotExist. + type: string + values: + description: |- + values is an array of string values. If the operator is In or NotIn, + the values array must be non-empty. If the operator is Exists or DoesNotExist, + the values array must be empty. This array is replaced during a strategic + merge patch. + items: + type: string + type: array + x-kubernetes-list-type: atomic + required: + - key + - operator + type: object + type: array + x-kubernetes-list-type: atomic + matchLabels: + additionalProperties: + type: string + description: |- + matchLabels is a map of {key,value} pairs. A single {key,value} in the matchLabels + map is equivalent to an element of matchExpressions, whose key field is "key", the + operator is "In", and the values array contains only "value". The requirements are ANDed. + type: object + type: object + x-kubernetes-map-type: atomic + vmiCalcConfigName: + default: DedicatedVirtualResources + description: |- + VmiCalcConfigName determine how resource allocation will be done with ApplicationsResourceQuota. + allowed values are: VmiPodUsage, VirtualResources, DedicatedVirtualResources or IgnoreVmiCalculator + enum: + - VmiPodUsage + - VirtualResources + - DedicatedVirtualResources + - IgnoreVmiCalculator + type: string + type: object + certConfig: + default: + ca: + duration: 48h0m0s + renewBefore: 24h0m0s + server: + duration: 24h0m0s + renewBefore: 12h0m0s + description: certConfig holds the rotation policy for internal, self-signed + certificates + properties: + ca: + default: + duration: 48h0m0s + renewBefore: 24h0m0s + description: |- + CA configuration - + CA certs are kept in the CA bundle as long as they are valid + properties: + duration: + default: 48h0m0s + description: |- + The requested 'duration' (i.e. lifetime) of the Certificate. + This should comply with golang's ParseDuration format (https://golang.org/pkg/time/#ParseDuration) + type: string + renewBefore: + default: 24h0m0s + description: |- + The amount of time before the currently issued certificate's `notAfter` + time that we will begin to attempt to renew the certificate. + This should comply with golang's ParseDuration format (https://golang.org/pkg/time/#ParseDuration) + type: string + type: object + server: + default: + duration: 24h0m0s + renewBefore: 12h0m0s + description: |- + Server configuration - + Certs are rotated and discarded + properties: + duration: + default: 24h0m0s + description: |- + The requested 'duration' (i.e. lifetime) of the Certificate. + This should comply with golang's ParseDuration format (https://golang.org/pkg/time/#ParseDuration) + type: string + renewBefore: + default: 12h0m0s + description: |- + The amount of time before the currently issued certificate's `notAfter` + time that we will begin to attempt to renew the certificate. + This should comply with golang's ParseDuration format (https://golang.org/pkg/time/#ParseDuration) + type: string + type: object + type: object + commonBootImageNamespace: + description: |- + CommonBootImageNamespace override the default namespace of the common boot images, in order to hide them. + + If not set, HCO won't set any namespace, letting SSP to use the default. If set, use the namespace to create the + DataImportCronTemplates and the common image streams, with this namespace. This field is not set by default. + type: string + commonTemplatesNamespace: + description: |- + CommonTemplatesNamespace defines namespace in which common templates will + be deployed. It overrides the default openshift namespace. + type: string + dataImportCronTemplates: + description: DataImportCronTemplates holds list of data import cron + templates (golden images) + items: + description: |- + DataImportCronTemplate defines the template type for DataImportCrons. + It requires metadata.name to be specified while leaving namespace as optional. + properties: + metadata: + properties: + annotations: + additionalProperties: + type: string + type: object + finalizers: + items: + type: string + type: array + labels: + additionalProperties: + type: string + type: object + name: + type: string + namespace: + type: string + type: object + spec: + description: DataImportCronSpec defines specification for DataImportCron + properties: + garbageCollect: + description: |- + GarbageCollect specifies whether old PVCs should be cleaned up after a new PVC is imported. + Options are currently "Outdated" and "Never", defaults to "Outdated". + type: string + importsToKeep: + description: Number of import PVCs to keep when garbage + collecting. Default is 3. + format: int32 + type: integer + managedDataSource: + description: |- + ManagedDataSource specifies the name of the corresponding DataSource this cron will manage. + DataSource has to be in the same namespace. + type: string + retentionPolicy: + description: RetentionPolicy specifies whether the created + DataVolumes and DataSources are retained when their DataImportCron + is deleted. Default is RatainAll. + type: string + schedule: + description: Schedule specifies in cron format when and + how often to look for new imports + type: string + serviceAccountName: + description: ServiceAccountName is the name of the ServiceAccount + for creating DataVolumes. + minLength: 1 + type: string + template: + description: Template specifies template for the DVs to + be created + properties: + apiVersion: + description: |- + APIVersion defines the versioned schema of this representation of an object. + Servers should convert recognized schemas to the latest internal value, and + may reject unrecognized values. + More info: https://git.k8s.io/community/contributors/devel/sig-architecture/api-conventions.md#resources + type: string + kind: + description: |- + Kind is a string value representing the REST resource this object represents. + Servers may infer this from the endpoint the client submits requests to. + Cannot be updated. + In CamelCase. + More info: https://git.k8s.io/community/contributors/devel/sig-architecture/api-conventions.md#types-kinds + type: string + metadata: + properties: + annotations: + additionalProperties: + type: string + type: object + finalizers: + items: + type: string + type: array + labels: + additionalProperties: + type: string + type: object + name: + type: string + namespace: + type: string + type: object + spec: + description: DataVolumeSpec defines the DataVolume type + specification + properties: + checkpoints: + description: Checkpoints is a list of DataVolumeCheckpoints, + representing stages in a multistage import. + items: + description: DataVolumeCheckpoint defines a stage + in a warm migration. + properties: + current: + description: Current is the identifier of + the snapshot created for this checkpoint. + type: string + previous: + description: Previous is the identifier of + the snapshot from the previous checkpoint. + type: string + required: + - current + - previous + type: object + type: array + contentType: + description: 'DataVolumeContentType options: "kubevirt", + "archive"' + enum: + - kubevirt + - archive + type: string + finalCheckpoint: + description: FinalCheckpoint indicates whether the + current DataVolumeCheckpoint is the final checkpoint. + type: boolean + preallocation: + description: Preallocation controls whether storage + for DataVolumes should be allocated in advance. + type: boolean + priorityClassName: + description: PriorityClassName for Importer, Cloner + and Uploader pod + type: string + pvc: + description: PVC is the PVC specification + properties: + accessModes: + description: |- + accessModes contains the desired access modes the volume should have. + More info: https://kubernetes.io/docs/concepts/storage/persistent-volumes#access-modes-1 + items: + type: string + type: array + x-kubernetes-list-type: atomic + dataSource: + description: |- + dataSource field can be used to specify either: + * An existing VolumeSnapshot object (snapshot.storage.k8s.io/VolumeSnapshot) + * An existing PVC (PersistentVolumeClaim) + If the provisioner or an external controller can support the specified data source, + it will create a new volume based on the contents of the specified data source. + When the AnyVolumeDataSource feature gate is enabled, dataSource contents will be copied to dataSourceRef, + and dataSourceRef contents will be copied to dataSource when dataSourceRef.namespace is not specified. + If the namespace is specified, then dataSourceRef will not be copied to dataSource. + properties: + apiGroup: + description: |- + APIGroup is the group for the resource being referenced. + If APIGroup is not specified, the specified Kind must be in the core API group. + For any other third-party types, APIGroup is required. + type: string + kind: + description: Kind is the type of resource + being referenced + type: string + name: + description: Name is the name of resource + being referenced + type: string + required: + - kind + - name + type: object + x-kubernetes-map-type: atomic + dataSourceRef: + description: |- + dataSourceRef specifies the object from which to populate the volume with data, if a non-empty + volume is desired. This may be any object from a non-empty API group (non + core object) or a PersistentVolumeClaim object. + When this field is specified, volume binding will only succeed if the type of + the specified object matches some installed volume populator or dynamic + provisioner. + This field will replace the functionality of the dataSource field and as such + if both fields are non-empty, they must have the same value. For backwards + compatibility, when namespace isn't specified in dataSourceRef, + both fields (dataSource and dataSourceRef) will be set to the same + value automatically if one of them is empty and the other is non-empty. + When namespace is specified in dataSourceRef, + dataSource isn't set to the same value and must be empty. + There are three important differences between dataSource and dataSourceRef: + * While dataSource only allows two specific types of objects, dataSourceRef + allows any non-core object, as well as PersistentVolumeClaim objects. + * While dataSource ignores disallowed values (dropping them), dataSourceRef + preserves all values, and generates an error if a disallowed value is + specified. + * While dataSource only allows local objects, dataSourceRef allows objects + in any namespaces. + (Beta) Using this field requires the AnyVolumeDataSource feature gate to be enabled. + (Alpha) Using the namespace field of dataSourceRef requires the CrossNamespaceVolumeDataSource feature gate to be enabled. + properties: + apiGroup: + description: |- + APIGroup is the group for the resource being referenced. + If APIGroup is not specified, the specified Kind must be in the core API group. + For any other third-party types, APIGroup is required. + type: string + kind: + description: Kind is the type of resource + being referenced + type: string + name: + description: Name is the name of resource + being referenced + type: string + namespace: + description: |- + Namespace is the namespace of resource being referenced + Note that when a namespace is specified, a gateway.networking.k8s.io/ReferenceGrant object is required in the referent namespace to allow that namespace's owner to accept the reference. See the ReferenceGrant documentation for details. + (Alpha) This field requires the CrossNamespaceVolumeDataSource feature gate to be enabled. + type: string + required: + - kind + - name + type: object + resources: + description: |- + resources represents the minimum resources the volume should have. + If RecoverVolumeExpansionFailure feature is enabled users are allowed to specify resource requirements + that are lower than previous value but must still be higher than capacity recorded in the + status field of the claim. + More info: https://kubernetes.io/docs/concepts/storage/persistent-volumes#resources + properties: + limits: + additionalProperties: + anyOf: + - type: integer + - type: string + pattern: ^(\+|-)?(([0-9]+(\.[0-9]*)?)|(\.[0-9]+))(([KMGTPE]i)|[numkMGTPE]|([eE](\+|-)?(([0-9]+(\.[0-9]*)?)|(\.[0-9]+))))?$ + x-kubernetes-int-or-string: true + description: |- + Limits describes the maximum amount of compute resources allowed. + More info: https://kubernetes.io/docs/concepts/configuration/manage-resources-containers/ + type: object + requests: + additionalProperties: + anyOf: + - type: integer + - type: string + pattern: ^(\+|-)?(([0-9]+(\.[0-9]*)?)|(\.[0-9]+))(([KMGTPE]i)|[numkMGTPE]|([eE](\+|-)?(([0-9]+(\.[0-9]*)?)|(\.[0-9]+))))?$ + x-kubernetes-int-or-string: true + description: |- + Requests describes the minimum amount of compute resources required. + If Requests is omitted for a container, it defaults to Limits if that is explicitly specified, + otherwise to an implementation-defined value. Requests cannot exceed Limits. + More info: https://kubernetes.io/docs/concepts/configuration/manage-resources-containers/ + type: object + type: object + selector: + description: selector is a label query over + volumes to consider for binding. + properties: + matchExpressions: + description: matchExpressions is a list + of label selector requirements. The requirements + are ANDed. + items: + description: |- + A label selector requirement is a selector that contains values, a key, and an operator that + relates the key and values. + properties: + key: + description: key is the label key + that the selector applies to. + type: string + operator: + description: |- + operator represents a key's relationship to a set of values. + Valid operators are In, NotIn, Exists and DoesNotExist. + type: string + values: + description: |- + values is an array of string values. If the operator is In or NotIn, + the values array must be non-empty. If the operator is Exists or DoesNotExist, + the values array must be empty. This array is replaced during a strategic + merge patch. + items: + type: string + type: array + x-kubernetes-list-type: atomic + required: + - key + - operator + type: object + type: array + x-kubernetes-list-type: atomic + matchLabels: + additionalProperties: + type: string + description: |- + matchLabels is a map of {key,value} pairs. A single {key,value} in the matchLabels + map is equivalent to an element of matchExpressions, whose key field is "key", the + operator is "In", and the values array contains only "value". The requirements are ANDed. + type: object + type: object + x-kubernetes-map-type: atomic + storageClassName: + description: |- + storageClassName is the name of the StorageClass required by the claim. + More info: https://kubernetes.io/docs/concepts/storage/persistent-volumes#class-1 + type: string + volumeAttributesClassName: + description: |- + volumeAttributesClassName may be used to set the VolumeAttributesClass used by this claim. + If specified, the CSI driver will create or update the volume with the attributes defined + in the corresponding VolumeAttributesClass. This has a different purpose than storageClassName, + it can be changed after the claim is created. An empty string or nil value indicates that no + VolumeAttributesClass will be applied to the claim. If the claim enters an Infeasible error state, + this field can be reset to its previous value (including nil) to cancel the modification. + If the resource referred to by volumeAttributesClass does not exist, this PersistentVolumeClaim will be + set to a Pending state, as reflected by the modifyVolumeStatus field, until such as a resource + exists. + More info: https://kubernetes.io/docs/concepts/storage/volume-attributes-classes/ + type: string + volumeMode: + description: |- + volumeMode defines what type of volume is required by the claim. + Value of Filesystem is implied when not included in claim spec. + type: string + volumeName: + description: volumeName is the binding reference + to the PersistentVolume backing this claim. + type: string + type: object + source: + description: Source is the src of the data for the + requested DataVolume + properties: + blank: + description: DataVolumeBlankImage provides the + parameters to create a new raw blank image + for the PVC + type: object + gcs: + description: DataVolumeSourceGCS provides the + parameters to create a Data Volume from an + GCS source + properties: + secretRef: + description: SecretRef provides the secret + reference needed to access the GCS source + type: string + url: + description: URL is the url of the GCS source + type: string + required: + - url + type: object + http: + description: DataVolumeSourceHTTP can be either + an http or https endpoint, with an optional + basic auth user name and password, and an + optional configmap containing additional CAs + properties: + certConfigMap: + description: CertConfigMap is a configmap + reference, containing a Certificate Authority(CA) + public key, and a base64 encoded pem certificate + type: string + extraHeaders: + description: ExtraHeaders is a list of strings + containing extra headers to include with + HTTP transfer requests + items: + type: string + type: array + secretExtraHeaders: + description: SecretExtraHeaders is a list + of Secret references, each containing + an extra HTTP header that may include + sensitive information + items: + type: string + type: array + secretRef: + description: SecretRef A Secret reference, + the secret should contain accessKeyId + (user name) base64 encoded, and secretKey + (password) also base64 encoded + type: string + url: + description: URL is the URL of the http(s) + endpoint + type: string + required: + - url + type: object + imageio: + description: DataVolumeSourceImageIO provides + the parameters to create a Data Volume from + an imageio source + properties: + certConfigMap: + description: CertConfigMap provides a reference + to the CA cert + type: string + diskId: + description: DiskID provides id of a disk + to be imported + type: string + insecureSkipVerify: + description: InsecureSkipVerify is a flag + to skip certificate verification + type: boolean + secretRef: + description: SecretRef provides the secret + reference needed to access the ovirt-engine + type: string + url: + description: URL is the URL of the ovirt-engine + type: string + required: + - diskId + - url + type: object + pvc: + description: DataVolumeSourcePVC provides the + parameters to create a Data Volume from an + existing PVC + properties: + name: + description: The name of the source PVC + type: string + namespace: + description: The namespace of the source + PVC + type: string + required: + - name + - namespace + type: object + registry: + description: DataVolumeSourceRegistry provides + the parameters to create a Data Volume from + an registry source + properties: + certConfigMap: + description: CertConfigMap provides a reference + to the Registry certs + type: string + imageStream: + description: ImageStream is the name of + image stream for import + type: string + platform: + description: Platform describes the minimum + runtime requirements of the image + properties: + architecture: + description: Architecture specifies + the image target CPU architecture + type: string + type: object + pullMethod: + description: PullMethod can be either "pod" + (default import), or "node" (node docker + cache based import) + type: string + secretRef: + description: SecretRef provides the secret + reference needed to access the Registry + source + type: string + url: + description: 'URL is the url of the registry + source (starting with the scheme: docker, + oci-archive)' + type: string + type: object + s3: + description: DataVolumeSourceS3 provides the + parameters to create a Data Volume from an + S3 source + properties: + certConfigMap: + description: CertConfigMap is a configmap + reference, containing a Certificate Authority(CA) + public key, and a base64 encoded pem certificate + type: string + secretRef: + description: SecretRef provides the secret + reference needed to access the S3 source + type: string + url: + description: URL is the url of the S3 source + type: string + required: + - url + type: object + snapshot: + description: DataVolumeSourceSnapshot provides + the parameters to create a Data Volume from + an existing VolumeSnapshot + properties: + name: + description: The name of the source VolumeSnapshot + type: string + namespace: + description: The namespace of the source + VolumeSnapshot + type: string + required: + - name + - namespace + type: object + upload: + description: DataVolumeSourceUpload provides + the parameters to create a Data Volume by + uploading the source + type: object + vddk: + description: DataVolumeSourceVDDK provides the + parameters to create a Data Volume from a + Vmware source + properties: + backingFile: + description: BackingFile is the path to + the virtual hard disk to migrate from + vCenter/ESXi + type: string + extraArgs: + description: ExtraArgs is a reference to + a ConfigMap containing extra arguments + to pass directly to the VDDK library + type: string + initImageURL: + description: InitImageURL is an optional + URL to an image containing an extracted + VDDK library, overrides v2v-vmware config + map + type: string + secretRef: + description: SecretRef provides a reference + to a secret containing the username and + password needed to access the vCenter + or ESXi host + type: string + thumbprint: + description: Thumbprint is the certificate + thumbprint of the vCenter or ESXi host + type: string + url: + description: URL is the URL of the vCenter + or ESXi host with the VM to migrate + type: string + uuid: + description: UUID is the UUID of the virtual + machine that the backing file is attached + to in vCenter/ESXi + type: string + type: object + type: object + sourceRef: + description: SourceRef is an indirect reference + to the source of data for the requested DataVolume + properties: + kind: + description: The kind of the source reference, + currently only "DataSource" is supported + type: string + name: + description: The name of the source reference + type: string + namespace: + description: The namespace of the source reference, + defaults to the DataVolume namespace + type: string + required: + - kind + - name + type: object + storage: + description: Storage is the requested storage specification + properties: + accessModes: + description: |- + AccessModes contains the desired access modes the volume should have. + More info: https://kubernetes.io/docs/concepts/storage/persistent-volumes#access-modes-1 + items: + type: string + type: array + dataSource: + description: |- + This field can be used to specify either: * An existing VolumeSnapshot object (snapshot.storage.k8s.io/VolumeSnapshot) * An existing PVC (PersistentVolumeClaim) * An existing custom resource that implements data population (Alpha) In order to use custom resource types that implement data population, the AnyVolumeDataSource feature gate must be enabled. If the provisioner or an external controller can support the specified data source, it will create a new volume based on the contents of the specified data source. + If the AnyVolumeDataSource feature gate is enabled, this field will always have the same contents as the DataSourceRef field. + properties: + apiGroup: + description: |- + APIGroup is the group for the resource being referenced. + If APIGroup is not specified, the specified Kind must be in the core API group. + For any other third-party types, APIGroup is required. + type: string + kind: + description: Kind is the type of resource + being referenced + type: string + name: + description: Name is the name of resource + being referenced + type: string + required: + - kind + - name + type: object + x-kubernetes-map-type: atomic + dataSourceRef: + description: |- + Specifies the object from which to populate the volume with data, if a non-empty volume is desired. This may be any local object from a non-empty API group (non core object) or a PersistentVolumeClaim object. When this field is specified, volume binding will only succeed if the type of the specified object matches some installed volume populator or dynamic provisioner. + This field will replace the functionality of the DataSource field and as such if both fields are non-empty, they must have the same value. For backwards compatibility, both fields (DataSource and DataSourceRef) will be set to the same value automatically if one of them is empty and the other is non-empty. + There are two important differences between DataSource and DataSourceRef: + * While DataSource only allows two specific types of objects, DataSourceRef allows any non-core object, as well as PersistentVolumeClaim objects. + * While DataSource ignores disallowed values (dropping them), DataSourceRef preserves all values, and generates an error if a disallowed value is specified. + (Beta) Using this field requires the AnyVolumeDataSource feature gate to be enabled. + properties: + apiGroup: + description: |- + APIGroup is the group for the resource being referenced. + If APIGroup is not specified, the specified Kind must be in the core API group. + For any other third-party types, APIGroup is required. + type: string + kind: + description: Kind is the type of resource + being referenced + type: string + name: + description: Name is the name of resource + being referenced + type: string + namespace: + description: |- + Namespace is the namespace of resource being referenced + Note that when a namespace is specified, a gateway.networking.k8s.io/ReferenceGrant object is required in the referent namespace to allow that namespace's owner to accept the reference. See the ReferenceGrant documentation for details. + (Alpha) This field requires the CrossNamespaceVolumeDataSource feature gate to be enabled. + type: string + required: + - kind + - name + type: object + resources: + description: |- + Resources represents the minimum resources the volume should have. + More info: https://kubernetes.io/docs/concepts/storage/persistent-volumes#resources + properties: + limits: + additionalProperties: + anyOf: + - type: integer + - type: string + pattern: ^(\+|-)?(([0-9]+(\.[0-9]*)?)|(\.[0-9]+))(([KMGTPE]i)|[numkMGTPE]|([eE](\+|-)?(([0-9]+(\.[0-9]*)?)|(\.[0-9]+))))?$ + x-kubernetes-int-or-string: true + description: |- + Limits describes the maximum amount of compute resources allowed. + More info: https://kubernetes.io/docs/concepts/configuration/manage-resources-containers/ + type: object + requests: + additionalProperties: + anyOf: + - type: integer + - type: string + pattern: ^(\+|-)?(([0-9]+(\.[0-9]*)?)|(\.[0-9]+))(([KMGTPE]i)|[numkMGTPE]|([eE](\+|-)?(([0-9]+(\.[0-9]*)?)|(\.[0-9]+))))?$ + x-kubernetes-int-or-string: true + description: |- + Requests describes the minimum amount of compute resources required. + If Requests is omitted for a container, it defaults to Limits if that is explicitly specified, + otherwise to an implementation-defined value. Requests cannot exceed Limits. + More info: https://kubernetes.io/docs/concepts/configuration/manage-resources-containers/ + type: object + type: object + selector: + description: A label query over volumes to consider + for binding. + properties: + matchExpressions: + description: matchExpressions is a list + of label selector requirements. The requirements + are ANDed. + items: + description: |- + A label selector requirement is a selector that contains values, a key, and an operator that + relates the key and values. + properties: + key: + description: key is the label key + that the selector applies to. + type: string + operator: + description: |- + operator represents a key's relationship to a set of values. + Valid operators are In, NotIn, Exists and DoesNotExist. + type: string + values: + description: |- + values is an array of string values. If the operator is In or NotIn, + the values array must be non-empty. If the operator is Exists or DoesNotExist, + the values array must be empty. This array is replaced during a strategic + merge patch. + items: + type: string + type: array + x-kubernetes-list-type: atomic + required: + - key + - operator + type: object + type: array + x-kubernetes-list-type: atomic + matchLabels: + additionalProperties: + type: string + description: |- + matchLabels is a map of {key,value} pairs. A single {key,value} in the matchLabels + map is equivalent to an element of matchExpressions, whose key field is "key", the + operator is "In", and the values array contains only "value". The requirements are ANDed. + type: object + type: object + x-kubernetes-map-type: atomic + storageClassName: + description: |- + Name of the StorageClass required by the claim. + More info: https://kubernetes.io/docs/concepts/storage/persistent-volumes#class-1 + type: string + volumeMode: + description: |- + volumeMode defines what type of volume is required by the claim. + Value of Filesystem is implied when not included in claim spec. + type: string + volumeName: + description: VolumeName is the binding reference + to the PersistentVolume backing this claim. + type: string + type: object + type: object + status: + description: DataVolumeStatus contains the current status + of the DataVolume + properties: + claimName: + description: ClaimName is the name of the underlying + PVC used by the DataVolume. + type: string + conditions: + items: + description: DataVolumeCondition represents the + state of a data volume condition. + properties: + lastHeartbeatTime: + format: date-time + type: string + lastTransitionTime: + format: date-time + type: string + message: + type: string + reason: + type: string + status: + type: string + type: + description: DataVolumeConditionType is the + string representation of known condition + types + type: string + required: + - status + - type + type: object + type: array + phase: + description: Phase is the current phase of the data + volume + type: string + progress: + description: DataVolumeProgress is the current progress + of the DataVolume transfer operation. Value between + 0 and 100 inclusive, N/A if not available + type: string + restartCount: + description: RestartCount is the number of times + the pod populating the DataVolume has restarted + format: int32 + type: integer + type: object + required: + - spec + type: object + required: + - managedDataSource + - schedule + - template + type: object + type: object + type: array + x-kubernetes-list-type: atomic + defaultCPUModel: + description: |- + DefaultCPUModel defines a cluster default for CPU model: default CPU model is set when VMI doesn't have any CPU model. + When VMI has CPU model set, then VMI's CPU model is preferred. + When default CPU model is not set and VMI's CPU model is not set too, host-model will be set. + Default CPU model can be changed when kubevirt is running. + type: string + defaultRuntimeClass: + description: |- + DefaultRuntimeClass defines a cluster default for the RuntimeClass to be used for VMIs pods if not set there. + Default RuntimeClass can be changed when kubevirt is running, existing VMIs are not impacted till + the next restart/live-migration when they are eventually going to consume the new default RuntimeClass. + type: string + deployVmConsoleProxy: + default: false + description: deploy VM console proxy resources in SSP operator + type: boolean + enableApplicationAwareQuota: + default: false + description: EnableApplicationAwareQuota if true, enables the Application + Aware Quota feature + type: boolean + enableCommonBootImageImport: + default: true + description: |- + Opt-in to automatic delivery/updates of the common data import cron templates. + There are two sources for the data import cron templates: hard coded list of common templates, and custom (user + defined) templates that can be added to the dataImportCronTemplates field. This field only controls the common + templates. It is possible to use custom templates by adding them to the dataImportCronTemplates field. + type: boolean + evictionStrategy: + description: |- + EvictionStrategy defines at the cluster level if the VirtualMachineInstance should be + migrated instead of shut-off in case of a node drain. If the VirtualMachineInstance specific + field is set it overrides the cluster level one. + Allowed values: + - `None` no eviction strategy at cluster level. + - `LiveMigrate` migrate the VM on eviction; a not live migratable VM with no specific strategy will block the drain of the node util manually evicted. + - `LiveMigrateIfPossible` migrate the VM on eviction if live migration is possible, otherwise directly evict. + - `External` block the drain, track eviction and notify an external controller. + Defaults to LiveMigrate with multiple worker nodes, None on single worker clusters. + enum: + - None + - LiveMigrate + - LiveMigrateIfPossible + - External + type: string + featureGates: + description: |- + FeatureGates is a set of optional feature gates to enable or disable new + features that are not generally available yet. + Add a new FeatureGate Object to this set, to enable a feature that is + disabled by default, or to disable a feature that is enabled by default. + + A feature gate may be in the following phases: + * Alpha: the feature is in dev-preview. It is disabled by default, but can + be enabled. + * Beta: the feature gate is in tech-preview. It is enabled by default, but + can be disabled. + * GA: the feature is graduated and is always enabled. There is no way to + disable it. + * Deprecated: the feature is no longer supported. There is no way to enable + it + + Feature-Gate list: + * alignCPUs: + Enable KubeVirt to request up to two additional dedicated CPUs in order to + complete the total CPU count to an even parity when using emulator thread + isolation. + Note: this feature is in Developer Preview. + Phase: Alpha + + * decentralizedLiveMigration: + enables the decentralized live migration (cross-cluster migration) feature. + This feature allows live migration of VirtualMachineInstances between + different clusters. + Note: This feature is in Developer Preview. + Phase: Alpha + + * declarativeHotplugVolumes: + enables the use of the declarative volume hotplug feature in KubeVirt. + When enabled, the "DeclarativeHotplugVolumes" feature gate is enabled in + the KubeVirt CR, instead of the "HotplugVolumes" feature gate. + When disabled, the "HotplugVolumes" feature gate is enabled (default + behavior). + Phase: Alpha + + * deployKubeSecondaryDNS: + Deploy KubeSecondaryDNS by CNAO + Phase: Alpha + + * disableMDevConfiguration: + Disable mediated devices handling on KubeVirt + Phase: Alpha + + * downwardMetrics: + Allow to expose a limited set of host metrics to guests. + Phase: Alpha + + * enableMultiArchBootImageImport: + allows the HCO to run on heterogeneous clusters with different CPU + architectures. + Enabling this feature gate will allow the HCO to create Golden Images for + different CPU architectures. + Phase: Alpha + + * objectGraph: + enables the ObjectGraph VM and VMI subresource in KubeVirt. + This subresource returns a structured list of k8s objects that are related + to the specified VM or VMI, enabling better dependency tracking. + Phase: Alpha + + * persistentReservation: + Enable persistent reservation of a LUN through the SCSI Persistent Reserve + commands on Kubevirt. + In order to issue privileged SCSI ioctls, the VM requires activation of the + persistent reservation flag. + Once this feature gate is enabled, then the additional container with the + qemu-pr-helper is deployed inside the virt-handler pod. + Enabling (or removing) the feature gate causes the redeployment of the + virt-handler pod. + Phase: Alpha + + * videoConfig: + allows users to configure video device types for their virtual machines. + This can be useful for workloads that require specific video capabilities + or architectures. + Phase: Beta + + * autoResourceLimits: + Phase: Deprecated + + * deployKubevirtIpamController: + Phase: Deprecated + + * deployTektonTaskResources: + Phase: Deprecated + + * deployVmConsoleProxy: + Phase: Deprecated + + * enableApplicationAwareQuota: + This feature gate is ignored. Use spec.enableApplicationAwareQuota field instead + Phase: Deprecated + + * enableCommonBootImageImport: + This feature gate is ignored. Use spec.enableCommonBootImageImport field instead + Phase: Deprecated + + * enableManagedTenantQuota: + Phase: Deprecated + + * nonRoot: + Phase: Deprecated + + * primaryUserDefinedNetworkBinding: + Phase: Deprecated + + * withHostPassthroughCPU: + Phase: Deprecated + items: + description: FeatureGate is an optional feature gate to enable or + disable a new feature that is not generally available yet. + properties: + name: + description: Name is the feature gate name + type: string + state: + description: State determines if the feature gate is enabled + ("Enabled"), or disabled ("False"). The default value is "Disabled". + enum: + - Enabled + - Disabled + type: string + required: + - name + type: object + type: array + filesystemOverhead: + description: |- + FilesystemOverhead describes the space reserved for overhead when using Filesystem volumes. + A value is between 0 and 1, if not defined it is 0.055 (5.5 percent overhead) + properties: + global: + description: Global is how much space of a Filesystem volume should + be reserved for overhead. This value is used unless overridden + by a more specific value (per storageClass) + pattern: ^(0(?:\.\d{1,3})?|1)$ + type: string + storageClass: + additionalProperties: + description: |- + Percent is a string that can only be a value between [0,1) + (Note: we actually rely on reconcile to reject invalid values) + pattern: ^(0(?:\.\d{1,3})?|1)$ + type: string + description: StorageClass specifies how much space of a Filesystem + volume should be reserved for safety. The keys are the storageClass + and the values are the overhead. This value overrides the global + value + type: object + type: object + higherWorkloadDensity: + default: + memoryOvercommitPercentage: 100 + description: HigherWorkloadDensity holds configuration aimed to increase + virtual machine density + properties: + memoryOvercommitPercentage: + default: 100 + description: |- + MemoryOvercommitPercentage is the percentage of memory we want to give VMIs compared to the amount + given to its parent pod (virt-launcher). For example, a value of 102 means the VMI will + "see" 2% more memory than its parent pod. Values under 100 are effectively "undercommits". + Overcommits can lead to memory exhaustion, which in turn can lead to crashes. Use carefully. + minimum: 10 + type: integer + type: object + infra: + description: |- + infra HyperConvergedConfig influences the pod configuration (currently only placement) + for all the infra components needed on the virtualization enabled cluster + but not necessarily directly on each node running VMs/VMIs. + properties: + nodePlacement: + description: NodePlacement describes node scheduling configuration. + properties: + affinity: + description: |- + affinity enables pod affinity/anti-affinity placement expanding the types of constraints + that can be expressed with nodeSelector. + affinity is going to be applied to the relevant kind of pods in parallel with nodeSelector + See https://kubernetes.io/docs/concepts/scheduling-eviction/assign-pod-node/#affinity-and-anti-affinity + properties: + nodeAffinity: + description: Describes node affinity scheduling rules + for the pod. + properties: + preferredDuringSchedulingIgnoredDuringExecution: + description: |- + The scheduler will prefer to schedule pods to nodes that satisfy + the affinity expressions specified by this field, but it may choose + a node that violates one or more of the expressions. The node that is + most preferred is the one with the greatest sum of weights, i.e. + for each node that meets all of the scheduling requirements (resource + request, requiredDuringScheduling affinity expressions, etc.), + compute a sum by iterating through the elements of this field and adding + "weight" to the sum if the node matches the corresponding matchExpressions; the + node(s) with the highest sum are the most preferred. + items: + description: |- + An empty preferred scheduling term matches all objects with implicit weight 0 + (i.e. it's a no-op). A null preferred scheduling term matches no objects (i.e. is also a no-op). + properties: + preference: + description: A node selector term, associated + with the corresponding weight. + properties: + matchExpressions: + description: A list of node selector requirements + by node's labels. + items: + description: |- + A node selector requirement is a selector that contains values, a key, and an operator + that relates the key and values. + properties: + key: + description: The label key that the + selector applies to. + type: string + operator: + description: |- + Represents a key's relationship to a set of values. + Valid operators are In, NotIn, Exists, DoesNotExist. Gt, and Lt. + type: string + values: + description: |- + An array of string values. If the operator is In or NotIn, + the values array must be non-empty. If the operator is Exists or DoesNotExist, + the values array must be empty. If the operator is Gt or Lt, the values + array must have a single element, which will be interpreted as an integer. + This array is replaced during a strategic merge patch. + items: + type: string + type: array + x-kubernetes-list-type: atomic + required: + - key + - operator + type: object + type: array + x-kubernetes-list-type: atomic + matchFields: + description: A list of node selector requirements + by node's fields. + items: + description: |- + A node selector requirement is a selector that contains values, a key, and an operator + that relates the key and values. + properties: + key: + description: The label key that the + selector applies to. + type: string + operator: + description: |- + Represents a key's relationship to a set of values. + Valid operators are In, NotIn, Exists, DoesNotExist. Gt, and Lt. + type: string + values: + description: |- + An array of string values. If the operator is In or NotIn, + the values array must be non-empty. If the operator is Exists or DoesNotExist, + the values array must be empty. If the operator is Gt or Lt, the values + array must have a single element, which will be interpreted as an integer. + This array is replaced during a strategic merge patch. + items: + type: string + type: array + x-kubernetes-list-type: atomic + required: + - key + - operator + type: object + type: array + x-kubernetes-list-type: atomic + type: object + x-kubernetes-map-type: atomic + weight: + description: Weight associated with matching + the corresponding nodeSelectorTerm, in the + range 1-100. + format: int32 + type: integer + required: + - preference + - weight + type: object + type: array + x-kubernetes-list-type: atomic + requiredDuringSchedulingIgnoredDuringExecution: + description: |- + If the affinity requirements specified by this field are not met at + scheduling time, the pod will not be scheduled onto the node. + If the affinity requirements specified by this field cease to be met + at some point during pod execution (e.g. due to an update), the system + may or may not try to eventually evict the pod from its node. + properties: + nodeSelectorTerms: + description: Required. A list of node selector + terms. The terms are ORed. + items: + description: |- + A null or empty node selector term matches no objects. The requirements of + them are ANDed. + The TopologySelectorTerm type implements a subset of the NodeSelectorTerm. + properties: + matchExpressions: + description: A list of node selector requirements + by node's labels. + items: + description: |- + A node selector requirement is a selector that contains values, a key, and an operator + that relates the key and values. + properties: + key: + description: The label key that the + selector applies to. + type: string + operator: + description: |- + Represents a key's relationship to a set of values. + Valid operators are In, NotIn, Exists, DoesNotExist. Gt, and Lt. + type: string + values: + description: |- + An array of string values. If the operator is In or NotIn, + the values array must be non-empty. If the operator is Exists or DoesNotExist, + the values array must be empty. If the operator is Gt or Lt, the values + array must have a single element, which will be interpreted as an integer. + This array is replaced during a strategic merge patch. + items: + type: string + type: array + x-kubernetes-list-type: atomic + required: + - key + - operator + type: object + type: array + x-kubernetes-list-type: atomic + matchFields: + description: A list of node selector requirements + by node's fields. + items: + description: |- + A node selector requirement is a selector that contains values, a key, and an operator + that relates the key and values. + properties: + key: + description: The label key that the + selector applies to. + type: string + operator: + description: |- + Represents a key's relationship to a set of values. + Valid operators are In, NotIn, Exists, DoesNotExist. Gt, and Lt. + type: string + values: + description: |- + An array of string values. If the operator is In or NotIn, + the values array must be non-empty. If the operator is Exists or DoesNotExist, + the values array must be empty. If the operator is Gt or Lt, the values + array must have a single element, which will be interpreted as an integer. + This array is replaced during a strategic merge patch. + items: + type: string + type: array + x-kubernetes-list-type: atomic + required: + - key + - operator + type: object + type: array + x-kubernetes-list-type: atomic + type: object + x-kubernetes-map-type: atomic + type: array + x-kubernetes-list-type: atomic + required: + - nodeSelectorTerms + type: object + x-kubernetes-map-type: atomic + type: object + podAffinity: + description: Describes pod affinity scheduling rules (e.g. + co-locate this pod in the same node, zone, etc. as some + other pod(s)). + properties: + preferredDuringSchedulingIgnoredDuringExecution: + description: |- + The scheduler will prefer to schedule pods to nodes that satisfy + the affinity expressions specified by this field, but it may choose + a node that violates one or more of the expressions. The node that is + most preferred is the one with the greatest sum of weights, i.e. + for each node that meets all of the scheduling requirements (resource + request, requiredDuringScheduling affinity expressions, etc.), + compute a sum by iterating through the elements of this field and adding + "weight" to the sum if the node has pods which matches the corresponding podAffinityTerm; the + node(s) with the highest sum are the most preferred. + items: + description: The weights of all of the matched WeightedPodAffinityTerm + fields are added per-node to find the most preferred + node(s) + properties: + podAffinityTerm: + description: Required. A pod affinity term, + associated with the corresponding weight. + properties: + labelSelector: + description: |- + A label query over a set of resources, in this case pods. + If it's null, this PodAffinityTerm matches with no Pods. + properties: + matchExpressions: + description: matchExpressions is a list + of label selector requirements. The + requirements are ANDed. + items: + description: |- + A label selector requirement is a selector that contains values, a key, and an operator that + relates the key and values. + properties: + key: + description: key is the label + key that the selector applies + to. + type: string + operator: + description: |- + operator represents a key's relationship to a set of values. + Valid operators are In, NotIn, Exists and DoesNotExist. + type: string + values: + description: |- + values is an array of string values. If the operator is In or NotIn, + the values array must be non-empty. If the operator is Exists or DoesNotExist, + the values array must be empty. This array is replaced during a strategic + merge patch. + items: + type: string + type: array + x-kubernetes-list-type: atomic + required: + - key + - operator + type: object + type: array + x-kubernetes-list-type: atomic + matchLabels: + additionalProperties: + type: string + description: |- + matchLabels is a map of {key,value} pairs. A single {key,value} in the matchLabels + map is equivalent to an element of matchExpressions, whose key field is "key", the + operator is "In", and the values array contains only "value". The requirements are ANDed. + type: object + type: object + x-kubernetes-map-type: atomic + matchLabelKeys: + description: |- + MatchLabelKeys is a set of pod label keys to select which pods will + be taken into consideration. The keys are used to lookup values from the + incoming pod labels, those key-value labels are merged with `labelSelector` as `key in (value)` + to select the group of existing pods which pods will be taken into consideration + for the incoming pod's pod (anti) affinity. Keys that don't exist in the incoming + pod labels will be ignored. The default value is empty. + The same key is forbidden to exist in both matchLabelKeys and labelSelector. + Also, matchLabelKeys cannot be set when labelSelector isn't set. + items: + type: string + type: array + x-kubernetes-list-type: atomic + mismatchLabelKeys: + description: |- + MismatchLabelKeys is a set of pod label keys to select which pods will + be taken into consideration. The keys are used to lookup values from the + incoming pod labels, those key-value labels are merged with `labelSelector` as `key notin (value)` + to select the group of existing pods which pods will be taken into consideration + for the incoming pod's pod (anti) affinity. Keys that don't exist in the incoming + pod labels will be ignored. The default value is empty. + The same key is forbidden to exist in both mismatchLabelKeys and labelSelector. + Also, mismatchLabelKeys cannot be set when labelSelector isn't set. + items: + type: string + type: array + x-kubernetes-list-type: atomic + namespaceSelector: + description: |- + A label query over the set of namespaces that the term applies to. + The term is applied to the union of the namespaces selected by this field + and the ones listed in the namespaces field. + null selector and null or empty namespaces list means "this pod's namespace". + An empty selector ({}) matches all namespaces. + properties: + matchExpressions: + description: matchExpressions is a list + of label selector requirements. The + requirements are ANDed. + items: + description: |- + A label selector requirement is a selector that contains values, a key, and an operator that + relates the key and values. + properties: + key: + description: key is the label + key that the selector applies + to. + type: string + operator: + description: |- + operator represents a key's relationship to a set of values. + Valid operators are In, NotIn, Exists and DoesNotExist. + type: string + values: + description: |- + values is an array of string values. If the operator is In or NotIn, + the values array must be non-empty. If the operator is Exists or DoesNotExist, + the values array must be empty. This array is replaced during a strategic + merge patch. + items: + type: string + type: array + x-kubernetes-list-type: atomic + required: + - key + - operator + type: object + type: array + x-kubernetes-list-type: atomic + matchLabels: + additionalProperties: + type: string + description: |- + matchLabels is a map of {key,value} pairs. A single {key,value} in the matchLabels + map is equivalent to an element of matchExpressions, whose key field is "key", the + operator is "In", and the values array contains only "value". The requirements are ANDed. + type: object + type: object + x-kubernetes-map-type: atomic + namespaces: + description: |- + namespaces specifies a static list of namespace names that the term applies to. + The term is applied to the union of the namespaces listed in this field + and the ones selected by namespaceSelector. + null or empty namespaces list and null namespaceSelector means "this pod's namespace". + items: + type: string + type: array + x-kubernetes-list-type: atomic + topologyKey: + description: |- + This pod should be co-located (affinity) or not co-located (anti-affinity) with the pods matching + the labelSelector in the specified namespaces, where co-located is defined as running on a node + whose value of the label with key topologyKey matches that of any node on which any of the + selected pods is running. + Empty topologyKey is not allowed. + type: string + required: + - topologyKey + type: object + weight: + description: |- + weight associated with matching the corresponding podAffinityTerm, + in the range 1-100. + format: int32 + type: integer + required: + - podAffinityTerm + - weight + type: object + type: array + x-kubernetes-list-type: atomic + requiredDuringSchedulingIgnoredDuringExecution: + description: |- + If the affinity requirements specified by this field are not met at + scheduling time, the pod will not be scheduled onto the node. + If the affinity requirements specified by this field cease to be met + at some point during pod execution (e.g. due to a pod label update), the + system may or may not try to eventually evict the pod from its node. + When there are multiple elements, the lists of nodes corresponding to each + podAffinityTerm are intersected, i.e. all terms must be satisfied. + items: + description: |- + Defines a set of pods (namely those matching the labelSelector + relative to the given namespace(s)) that this pod should be + co-located (affinity) or not co-located (anti-affinity) with, + where co-located is defined as running on a node whose value of + the label with key matches that of any node on which + a pod of the set of pods is running + properties: + labelSelector: + description: |- + A label query over a set of resources, in this case pods. + If it's null, this PodAffinityTerm matches with no Pods. + properties: + matchExpressions: + description: matchExpressions is a list + of label selector requirements. The requirements + are ANDed. + items: + description: |- + A label selector requirement is a selector that contains values, a key, and an operator that + relates the key and values. + properties: + key: + description: key is the label key + that the selector applies to. + type: string + operator: + description: |- + operator represents a key's relationship to a set of values. + Valid operators are In, NotIn, Exists and DoesNotExist. + type: string + values: + description: |- + values is an array of string values. If the operator is In or NotIn, + the values array must be non-empty. If the operator is Exists or DoesNotExist, + the values array must be empty. This array is replaced during a strategic + merge patch. + items: + type: string + type: array + x-kubernetes-list-type: atomic + required: + - key + - operator + type: object + type: array + x-kubernetes-list-type: atomic + matchLabels: + additionalProperties: + type: string + description: |- + matchLabels is a map of {key,value} pairs. A single {key,value} in the matchLabels + map is equivalent to an element of matchExpressions, whose key field is "key", the + operator is "In", and the values array contains only "value". The requirements are ANDed. + type: object + type: object + x-kubernetes-map-type: atomic + matchLabelKeys: + description: |- + MatchLabelKeys is a set of pod label keys to select which pods will + be taken into consideration. The keys are used to lookup values from the + incoming pod labels, those key-value labels are merged with `labelSelector` as `key in (value)` + to select the group of existing pods which pods will be taken into consideration + for the incoming pod's pod (anti) affinity. Keys that don't exist in the incoming + pod labels will be ignored. The default value is empty. + The same key is forbidden to exist in both matchLabelKeys and labelSelector. + Also, matchLabelKeys cannot be set when labelSelector isn't set. + items: + type: string + type: array + x-kubernetes-list-type: atomic + mismatchLabelKeys: + description: |- + MismatchLabelKeys is a set of pod label keys to select which pods will + be taken into consideration. The keys are used to lookup values from the + incoming pod labels, those key-value labels are merged with `labelSelector` as `key notin (value)` + to select the group of existing pods which pods will be taken into consideration + for the incoming pod's pod (anti) affinity. Keys that don't exist in the incoming + pod labels will be ignored. The default value is empty. + The same key is forbidden to exist in both mismatchLabelKeys and labelSelector. + Also, mismatchLabelKeys cannot be set when labelSelector isn't set. + items: + type: string + type: array + x-kubernetes-list-type: atomic + namespaceSelector: + description: |- + A label query over the set of namespaces that the term applies to. + The term is applied to the union of the namespaces selected by this field + and the ones listed in the namespaces field. + null selector and null or empty namespaces list means "this pod's namespace". + An empty selector ({}) matches all namespaces. + properties: + matchExpressions: + description: matchExpressions is a list + of label selector requirements. The requirements + are ANDed. + items: + description: |- + A label selector requirement is a selector that contains values, a key, and an operator that + relates the key and values. + properties: + key: + description: key is the label key + that the selector applies to. + type: string + operator: + description: |- + operator represents a key's relationship to a set of values. + Valid operators are In, NotIn, Exists and DoesNotExist. + type: string + values: + description: |- + values is an array of string values. If the operator is In or NotIn, + the values array must be non-empty. If the operator is Exists or DoesNotExist, + the values array must be empty. This array is replaced during a strategic + merge patch. + items: + type: string + type: array + x-kubernetes-list-type: atomic + required: + - key + - operator + type: object + type: array + x-kubernetes-list-type: atomic + matchLabels: + additionalProperties: + type: string + description: |- + matchLabels is a map of {key,value} pairs. A single {key,value} in the matchLabels + map is equivalent to an element of matchExpressions, whose key field is "key", the + operator is "In", and the values array contains only "value". The requirements are ANDed. + type: object + type: object + x-kubernetes-map-type: atomic + namespaces: + description: |- + namespaces specifies a static list of namespace names that the term applies to. + The term is applied to the union of the namespaces listed in this field + and the ones selected by namespaceSelector. + null or empty namespaces list and null namespaceSelector means "this pod's namespace". + items: + type: string + type: array + x-kubernetes-list-type: atomic + topologyKey: + description: |- + This pod should be co-located (affinity) or not co-located (anti-affinity) with the pods matching + the labelSelector in the specified namespaces, where co-located is defined as running on a node + whose value of the label with key topologyKey matches that of any node on which any of the + selected pods is running. + Empty topologyKey is not allowed. + type: string + required: + - topologyKey + type: object + type: array + x-kubernetes-list-type: atomic + type: object + podAntiAffinity: + description: Describes pod anti-affinity scheduling rules + (e.g. avoid putting this pod in the same node, zone, + etc. as some other pod(s)). + properties: + preferredDuringSchedulingIgnoredDuringExecution: + description: |- + The scheduler will prefer to schedule pods to nodes that satisfy + the anti-affinity expressions specified by this field, but it may choose + a node that violates one or more of the expressions. The node that is + most preferred is the one with the greatest sum of weights, i.e. + for each node that meets all of the scheduling requirements (resource + request, requiredDuringScheduling anti-affinity expressions, etc.), + compute a sum by iterating through the elements of this field and subtracting + "weight" from the sum if the node has pods which matches the corresponding podAffinityTerm; the + node(s) with the highest sum are the most preferred. + items: + description: The weights of all of the matched WeightedPodAffinityTerm + fields are added per-node to find the most preferred + node(s) + properties: + podAffinityTerm: + description: Required. A pod affinity term, + associated with the corresponding weight. + properties: + labelSelector: + description: |- + A label query over a set of resources, in this case pods. + If it's null, this PodAffinityTerm matches with no Pods. + properties: + matchExpressions: + description: matchExpressions is a list + of label selector requirements. The + requirements are ANDed. + items: + description: |- + A label selector requirement is a selector that contains values, a key, and an operator that + relates the key and values. + properties: + key: + description: key is the label + key that the selector applies + to. + type: string + operator: + description: |- + operator represents a key's relationship to a set of values. + Valid operators are In, NotIn, Exists and DoesNotExist. + type: string + values: + description: |- + values is an array of string values. If the operator is In or NotIn, + the values array must be non-empty. If the operator is Exists or DoesNotExist, + the values array must be empty. This array is replaced during a strategic + merge patch. + items: + type: string + type: array + x-kubernetes-list-type: atomic + required: + - key + - operator + type: object + type: array + x-kubernetes-list-type: atomic + matchLabels: + additionalProperties: + type: string + description: |- + matchLabels is a map of {key,value} pairs. A single {key,value} in the matchLabels + map is equivalent to an element of matchExpressions, whose key field is "key", the + operator is "In", and the values array contains only "value". The requirements are ANDed. + type: object + type: object + x-kubernetes-map-type: atomic + matchLabelKeys: + description: |- + MatchLabelKeys is a set of pod label keys to select which pods will + be taken into consideration. The keys are used to lookup values from the + incoming pod labels, those key-value labels are merged with `labelSelector` as `key in (value)` + to select the group of existing pods which pods will be taken into consideration + for the incoming pod's pod (anti) affinity. Keys that don't exist in the incoming + pod labels will be ignored. The default value is empty. + The same key is forbidden to exist in both matchLabelKeys and labelSelector. + Also, matchLabelKeys cannot be set when labelSelector isn't set. + items: + type: string + type: array + x-kubernetes-list-type: atomic + mismatchLabelKeys: + description: |- + MismatchLabelKeys is a set of pod label keys to select which pods will + be taken into consideration. The keys are used to lookup values from the + incoming pod labels, those key-value labels are merged with `labelSelector` as `key notin (value)` + to select the group of existing pods which pods will be taken into consideration + for the incoming pod's pod (anti) affinity. Keys that don't exist in the incoming + pod labels will be ignored. The default value is empty. + The same key is forbidden to exist in both mismatchLabelKeys and labelSelector. + Also, mismatchLabelKeys cannot be set when labelSelector isn't set. + items: + type: string + type: array + x-kubernetes-list-type: atomic + namespaceSelector: + description: |- + A label query over the set of namespaces that the term applies to. + The term is applied to the union of the namespaces selected by this field + and the ones listed in the namespaces field. + null selector and null or empty namespaces list means "this pod's namespace". + An empty selector ({}) matches all namespaces. + properties: + matchExpressions: + description: matchExpressions is a list + of label selector requirements. The + requirements are ANDed. + items: + description: |- + A label selector requirement is a selector that contains values, a key, and an operator that + relates the key and values. + properties: + key: + description: key is the label + key that the selector applies + to. + type: string + operator: + description: |- + operator represents a key's relationship to a set of values. + Valid operators are In, NotIn, Exists and DoesNotExist. + type: string + values: + description: |- + values is an array of string values. If the operator is In or NotIn, + the values array must be non-empty. If the operator is Exists or DoesNotExist, + the values array must be empty. This array is replaced during a strategic + merge patch. + items: + type: string + type: array + x-kubernetes-list-type: atomic + required: + - key + - operator + type: object + type: array + x-kubernetes-list-type: atomic + matchLabels: + additionalProperties: + type: string + description: |- + matchLabels is a map of {key,value} pairs. A single {key,value} in the matchLabels + map is equivalent to an element of matchExpressions, whose key field is "key", the + operator is "In", and the values array contains only "value". The requirements are ANDed. + type: object + type: object + x-kubernetes-map-type: atomic + namespaces: + description: |- + namespaces specifies a static list of namespace names that the term applies to. + The term is applied to the union of the namespaces listed in this field + and the ones selected by namespaceSelector. + null or empty namespaces list and null namespaceSelector means "this pod's namespace". + items: + type: string + type: array + x-kubernetes-list-type: atomic + topologyKey: + description: |- + This pod should be co-located (affinity) or not co-located (anti-affinity) with the pods matching + the labelSelector in the specified namespaces, where co-located is defined as running on a node + whose value of the label with key topologyKey matches that of any node on which any of the + selected pods is running. + Empty topologyKey is not allowed. + type: string + required: + - topologyKey + type: object + weight: + description: |- + weight associated with matching the corresponding podAffinityTerm, + in the range 1-100. + format: int32 + type: integer + required: + - podAffinityTerm + - weight + type: object + type: array + x-kubernetes-list-type: atomic + requiredDuringSchedulingIgnoredDuringExecution: + description: |- + If the anti-affinity requirements specified by this field are not met at + scheduling time, the pod will not be scheduled onto the node. + If the anti-affinity requirements specified by this field cease to be met + at some point during pod execution (e.g. due to a pod label update), the + system may or may not try to eventually evict the pod from its node. + When there are multiple elements, the lists of nodes corresponding to each + podAffinityTerm are intersected, i.e. all terms must be satisfied. + items: + description: |- + Defines a set of pods (namely those matching the labelSelector + relative to the given namespace(s)) that this pod should be + co-located (affinity) or not co-located (anti-affinity) with, + where co-located is defined as running on a node whose value of + the label with key matches that of any node on which + a pod of the set of pods is running + properties: + labelSelector: + description: |- + A label query over a set of resources, in this case pods. + If it's null, this PodAffinityTerm matches with no Pods. + properties: + matchExpressions: + description: matchExpressions is a list + of label selector requirements. The requirements + are ANDed. + items: + description: |- + A label selector requirement is a selector that contains values, a key, and an operator that + relates the key and values. + properties: + key: + description: key is the label key + that the selector applies to. + type: string + operator: + description: |- + operator represents a key's relationship to a set of values. + Valid operators are In, NotIn, Exists and DoesNotExist. + type: string + values: + description: |- + values is an array of string values. If the operator is In or NotIn, + the values array must be non-empty. If the operator is Exists or DoesNotExist, + the values array must be empty. This array is replaced during a strategic + merge patch. + items: + type: string + type: array + x-kubernetes-list-type: atomic + required: + - key + - operator + type: object + type: array + x-kubernetes-list-type: atomic + matchLabels: + additionalProperties: + type: string + description: |- + matchLabels is a map of {key,value} pairs. A single {key,value} in the matchLabels + map is equivalent to an element of matchExpressions, whose key field is "key", the + operator is "In", and the values array contains only "value". The requirements are ANDed. + type: object + type: object + x-kubernetes-map-type: atomic + matchLabelKeys: + description: |- + MatchLabelKeys is a set of pod label keys to select which pods will + be taken into consideration. The keys are used to lookup values from the + incoming pod labels, those key-value labels are merged with `labelSelector` as `key in (value)` + to select the group of existing pods which pods will be taken into consideration + for the incoming pod's pod (anti) affinity. Keys that don't exist in the incoming + pod labels will be ignored. The default value is empty. + The same key is forbidden to exist in both matchLabelKeys and labelSelector. + Also, matchLabelKeys cannot be set when labelSelector isn't set. + items: + type: string + type: array + x-kubernetes-list-type: atomic + mismatchLabelKeys: + description: |- + MismatchLabelKeys is a set of pod label keys to select which pods will + be taken into consideration. The keys are used to lookup values from the + incoming pod labels, those key-value labels are merged with `labelSelector` as `key notin (value)` + to select the group of existing pods which pods will be taken into consideration + for the incoming pod's pod (anti) affinity. Keys that don't exist in the incoming + pod labels will be ignored. The default value is empty. + The same key is forbidden to exist in both mismatchLabelKeys and labelSelector. + Also, mismatchLabelKeys cannot be set when labelSelector isn't set. + items: + type: string + type: array + x-kubernetes-list-type: atomic + namespaceSelector: + description: |- + A label query over the set of namespaces that the term applies to. + The term is applied to the union of the namespaces selected by this field + and the ones listed in the namespaces field. + null selector and null or empty namespaces list means "this pod's namespace". + An empty selector ({}) matches all namespaces. + properties: + matchExpressions: + description: matchExpressions is a list + of label selector requirements. The requirements + are ANDed. + items: + description: |- + A label selector requirement is a selector that contains values, a key, and an operator that + relates the key and values. + properties: + key: + description: key is the label key + that the selector applies to. + type: string + operator: + description: |- + operator represents a key's relationship to a set of values. + Valid operators are In, NotIn, Exists and DoesNotExist. + type: string + values: + description: |- + values is an array of string values. If the operator is In or NotIn, + the values array must be non-empty. If the operator is Exists or DoesNotExist, + the values array must be empty. This array is replaced during a strategic + merge patch. + items: + type: string + type: array + x-kubernetes-list-type: atomic + required: + - key + - operator + type: object + type: array + x-kubernetes-list-type: atomic + matchLabels: + additionalProperties: + type: string + description: |- + matchLabels is a map of {key,value} pairs. A single {key,value} in the matchLabels + map is equivalent to an element of matchExpressions, whose key field is "key", the + operator is "In", and the values array contains only "value". The requirements are ANDed. + type: object + type: object + x-kubernetes-map-type: atomic + namespaces: + description: |- + namespaces specifies a static list of namespace names that the term applies to. + The term is applied to the union of the namespaces listed in this field + and the ones selected by namespaceSelector. + null or empty namespaces list and null namespaceSelector means "this pod's namespace". + items: + type: string + type: array + x-kubernetes-list-type: atomic + topologyKey: + description: |- + This pod should be co-located (affinity) or not co-located (anti-affinity) with the pods matching + the labelSelector in the specified namespaces, where co-located is defined as running on a node + whose value of the label with key topologyKey matches that of any node on which any of the + selected pods is running. + Empty topologyKey is not allowed. + type: string + required: + - topologyKey + type: object + type: array + x-kubernetes-list-type: atomic + type: object + type: object + nodeSelector: + additionalProperties: + type: string + description: |- + nodeSelector is the node selector applied to the relevant kind of pods + It specifies a map of key-value pairs: for the pod to be eligible to run on a node, + the node must have each of the indicated key-value pairs as labels + (it can have additional labels as well). + See https://kubernetes.io/docs/concepts/configuration/assign-pod-node/#nodeselector + type: object + tolerations: + description: |- + tolerations is a list of tolerations applied to the relevant kind of pods + See https://kubernetes.io/docs/concepts/configuration/taint-and-toleration/ for more info. + These are additional tolerations other than default ones. + items: + description: |- + The pod this Toleration is attached to tolerates any taint that matches + the triple using the matching operator . + properties: + effect: + description: |- + Effect indicates the taint effect to match. Empty means match all taint effects. + When specified, allowed values are NoSchedule, PreferNoSchedule and NoExecute. + type: string + key: + description: |- + Key is the taint key that the toleration applies to. Empty means match all taint keys. + If the key is empty, operator must be Exists; this combination means to match all values and all keys. + type: string + operator: + description: |- + Operator represents a key's relationship to the value. + Valid operators are Exists and Equal. Defaults to Equal. + Exists is equivalent to wildcard for value, so that a pod can + tolerate all taints of a particular category. + type: string + tolerationSeconds: + description: |- + TolerationSeconds represents the period of time the toleration (which must be + of effect NoExecute, otherwise this field is ignored) tolerates the taint. By default, + it is not set, which means tolerate the taint forever (do not evict). Zero and + negative values will be treated as 0 (evict immediately) by the system. + format: int64 + type: integer + value: + description: |- + Value is the taint value the toleration matches to. + If the operator is Exists, the value should be empty, otherwise just a regular string. + type: string + type: object + type: array + type: object + type: object + instancetypeConfig: + description: InstancetypeConfig holds the configuration of instance + type related functionality within KubeVirt. + properties: + referencePolicy: + description: |- + ReferencePolicy defines how an instance type or preference should be referenced by the VM after submission, supported values are: + reference (default) - Where a copy of the original object is stashed in a ControllerRevision and referenced by the VM. + expand - Where the instance type or preference are expanded into the VM if no revisionNames have been populated. + expandAll - Where the instance type or preference are expanded into the VM regardless of revisionNames previously being populated. + enum: + - reference + - expand + - expandAll + nullable: true + type: string + type: object + ksmConfiguration: + description: |- + KSMConfiguration holds the information regarding + the enabling the KSM in the nodes (if available). + properties: + nodeLabelSelector: + description: |- + NodeLabelSelector is a selector that filters in which nodes the KSM will be enabled. + Empty NodeLabelSelector will enable ksm for every node. + properties: + matchExpressions: + description: matchExpressions is a list of label selector + requirements. The requirements are ANDed. + items: + description: |- + A label selector requirement is a selector that contains values, a key, and an operator that + relates the key and values. + properties: + key: + description: key is the label key that the selector + applies to. + type: string + operator: + description: |- + operator represents a key's relationship to a set of values. + Valid operators are In, NotIn, Exists and DoesNotExist. + type: string + values: + description: |- + values is an array of string values. If the operator is In or NotIn, + the values array must be non-empty. If the operator is Exists or DoesNotExist, + the values array must be empty. This array is replaced during a strategic + merge patch. + items: + type: string + type: array + x-kubernetes-list-type: atomic + required: + - key + - operator + type: object + type: array + x-kubernetes-list-type: atomic + matchLabels: + additionalProperties: + type: string + description: |- + matchLabels is a map of {key,value} pairs. A single {key,value} in the matchLabels + map is equivalent to an element of matchExpressions, whose key field is "key", the + operator is "In", and the values array contains only "value". The requirements are ANDed. + type: object + type: object + x-kubernetes-map-type: atomic + type: object + kubeMacPoolConfiguration: + description: KubeMacPoolConfiguration holds kubemacpool MAC address + range configuration. + properties: + rangeEnd: + description: |- + RangeEnd defines the last MAC address in the kubemacpool range. + The MAC address format should be AA:BB:CC:DD:EE:FF. + pattern: ^([0-9a-fA-F]{2}:){5}[0-9a-fA-F]{2}$ + type: string + rangeStart: + description: |- + RangeStart defines the first MAC address in the kubemacpool range. + The MAC address format should be AA:BB:CC:DD:EE:FF. + pattern: ^([0-9a-fA-F]{2}:){5}[0-9a-fA-F]{2}$ + type: string + type: object + x-kubernetes-validations: + - message: both rangeStart and rangeEnd must be configured together, + or both omitted + rule: (has(self.rangeStart) && has(self.rangeEnd)) || (!has(self.rangeStart) + && !has(self.rangeEnd)) + kubeSecondaryDNSNameServerIP: + description: KubeSecondaryDNSNameServerIP defines name server IP used + by KubeSecondaryDNS + type: string + liveMigrationConfig: + default: + allowAutoConverge: false + allowPostCopy: false + completionTimeoutPerGiB: 150 + parallelMigrationsPerCluster: 5 + parallelOutboundMigrationsPerNode: 2 + progressTimeout: 150 + description: |- + Live migration limits and timeouts are applied so that migration processes do not + overwhelm the cluster. + properties: + allowAutoConverge: + default: false + description: |- + AllowAutoConverge allows the platform to compromise performance/availability of VMIs to + guarantee successful VMI live migrations. Defaults to false + type: boolean + allowPostCopy: + default: false + description: |- + When enabled, KubeVirt attempts to use post-copy live-migration in case it + reaches its completion timeout while attempting pre-copy live-migration. + Post-copy migrations allow even the busiest VMs to successfully live-migrate. + However, events like a network failure or a failure in any of the source or + destination nodes can cause the migrated VM to crash or reach inconsistency. + Enable this option when evicting nodes is more important than keeping VMs + alive. + Defaults to false. + type: boolean + bandwidthPerMigration: + description: Bandwidth limit of each migration, the value is quantity + of bytes per second (e.g. 2048Mi = 2048MiB/sec) + pattern: ^(\+|-)?(([0-9]+(\.[0-9]*)?)|(\.[0-9]+))(([KMGTPE]i)|[numkMGTPE]|([eE](\+|-)?(([0-9]+(\.[0-9]*)?)|(\.[0-9]+))))?$ + type: string + completionTimeoutPerGiB: + default: 150 + description: |- + If a migrating VM is big and busy, while the connection to the destination node + is slow, migration may never converge. The completion timeout is calculated + based on completionTimeoutPerGiB times the size of the guest (both RAM and + migrated disks, if any). For example, with completionTimeoutPerGiB set to 800, + a virtual machine instance with 6GiB memory will timeout if it has not + completed migration in 1h20m. Use a lower completionTimeoutPerGiB to induce + quicker failure, so that another destination or post-copy is attempted. Use a + higher completionTimeoutPerGiB to let workload with spikes in its memory dirty + rate to converge. + The format is a number. + format: int64 + type: integer + network: + description: The migrations will be performed over a dedicated + multus network to minimize disruption to tenant workloads due + to network saturation when VM live migrations are triggered. + type: string + parallelMigrationsPerCluster: + default: 5 + description: Number of migrations running in parallel in the cluster. + format: int32 + type: integer + parallelOutboundMigrationsPerNode: + default: 2 + description: Maximum number of outbound migrations per node. + format: int32 + type: integer + progressTimeout: + default: 150 + description: The migration will be canceled if memory copy fails + to make progress in this time, in seconds. + format: int64 + type: integer + type: object + liveUpdateConfiguration: + description: |- + LiveUpdateConfiguration holds the cluster configuration for live update of virtual machines - max cpu sockets, + max guest memory and max hotplug ratio. This setting can affect VM CPU and memory settings. + properties: + maxCpuSockets: + description: |- + MaxCpuSockets provides a MaxSockets value for VMs that do not provide their own. + For VMs with more sockets than maximum the MaxSockets will be set to equal number of sockets. + format: int32 + type: integer + maxGuest: + anyOf: + - type: integer + - type: string + description: |- + MaxGuest defines the maximum amount memory that can be allocated + to the guest using hotplug. + pattern: ^(\+|-)?(([0-9]+(\.[0-9]*)?)|(\.[0-9]+))(([KMGTPE]i)|[numkMGTPE]|([eE](\+|-)?(([0-9]+(\.[0-9]*)?)|(\.[0-9]+))))?$ + x-kubernetes-int-or-string: true + maxHotplugRatio: + description: |- + MaxHotplugRatio is the ratio used to define the max amount + of a hotplug resource that can be made available to a VM + when the specific Max* setting is not defined (MaxCpuSockets, MaxGuest) + Example: VM is configured with 512Mi of guest memory, if MaxGuest is not + defined and MaxHotplugRatio is 2 then MaxGuest = 1Gi + defaults to 4 + format: int32 + type: integer + type: object + logVerbosityConfig: + description: |- + LogVerbosityConfig configures the verbosity level of Kubevirt's different components. The higher + the value - the higher the log verbosity. + properties: + cdi: + description: CDI indicates the log verbosity level that controls + the amount of information logged for CDI components. + format: int32 + type: integer + kubevirt: + description: |- + Kubevirt is a struct that allows specifying the log verbosity level that controls the amount of information + logged for each Kubevirt component. + properties: + nodeVerbosity: + additionalProperties: + type: integer + description: NodeVerbosity represents a map of nodes with + a specific verbosity level + type: object + virtAPI: + type: integer + virtController: + type: integer + virtHandler: + type: integer + virtLauncher: + type: integer + virtOperator: + type: integer + virtSynchronizationController: + type: integer + type: object + type: object + mediatedDevicesConfiguration: + description: MediatedDevicesConfiguration holds information about + MDEV types to be defined on nodes, if available + properties: + mediatedDeviceTypes: + items: + type: string + type: array + x-kubernetes-list-type: atomic + nodeMediatedDeviceTypes: + items: + description: NodeMediatedDeviceTypesConfig holds information + about MDEV types to be defined in a specific node that matches + the NodeSelector field. + properties: + mediatedDeviceTypes: + items: + type: string + type: array + x-kubernetes-list-type: atomic + nodeSelector: + additionalProperties: + type: string + description: |- + NodeSelector is a selector which must be true for the vmi to fit on a node. + Selector which must match a node's labels for the vmi to be scheduled on that node. + More info: https://kubernetes.io/docs/concepts/configuration/assign-pod-node/ + type: object + required: + - nodeSelector + type: object + type: array + x-kubernetes-list-type: atomic + type: object + networkBinding: + additionalProperties: + properties: + computeResourceOverhead: + description: |- + ComputeResourceOverhead specifies the resource overhead that should be added to the compute container when using the binding. + version: v1alphav1 + properties: + limits: + additionalProperties: + anyOf: + - type: integer + - type: string + pattern: ^(\+|-)?(([0-9]+(\.[0-9]*)?)|(\.[0-9]+))(([KMGTPE]i)|[numkMGTPE]|([eE](\+|-)?(([0-9]+(\.[0-9]*)?)|(\.[0-9]+))))?$ + x-kubernetes-int-or-string: true + description: |- + Limits describes the maximum amount of compute resources allowed. + More info: https://kubernetes.io/docs/concepts/configuration/manage-resources-containers/ + type: object + requests: + additionalProperties: + anyOf: + - type: integer + - type: string + pattern: ^(\+|-)?(([0-9]+(\.[0-9]*)?)|(\.[0-9]+))(([KMGTPE]i)|[numkMGTPE]|([eE](\+|-)?(([0-9]+(\.[0-9]*)?)|(\.[0-9]+))))?$ + x-kubernetes-int-or-string: true + description: |- + Requests describes the minimum amount of compute resources required. + If Requests is omitted for a container, it defaults to Limits if that is explicitly specified, + otherwise to an implementation-defined value. Requests cannot exceed Limits. + More info: https://kubernetes.io/docs/concepts/configuration/manage-resources-containers/ + type: object + type: object + domainAttachmentType: + description: |- + DomainAttachmentType is a standard domain network attachment method kubevirt supports. + Supported values: "tap", "managedTap" (since v1.4). + The standard domain attachment can be used instead or in addition to the sidecarImage. + version: 1alphav1 + type: string + downwardAPI: + description: |- + DownwardAPI specifies what kind of data should be exposed to the binding plugin sidecar. + Supported values: "device-info" + version: v1alphav1 + type: string + migration: + description: |- + Migration means the VM using the plugin can be safely migrated + version: 1alphav1 + properties: + method: + description: |- + Method defines a pre-defined migration methodology + version: 1alphav1 + type: string + type: object + networkAttachmentDefinition: + description: |- + NetworkAttachmentDefinition references to a NetworkAttachmentDefinition CR object. + Format: , /. + If namespace is not specified, VMI namespace is assumed. + version: 1alphav1 + type: string + sidecarImage: + description: |- + SidecarImage references a container image that runs in the virt-launcher pod. + The sidecar handles (libvirt) domain configuration and optional services. + version: 1alphav1 + type: string + type: object + description: |- + NetworkBinding defines the network binding plugins. + Those bindings can be used when defining virtual machine interfaces. + type: object + obsoleteCPUs: + description: ObsoleteCPUs allows avoiding scheduling of VMs for obsolete + CPU models + properties: + cpuModels: + description: |- + CPUModels is a list of obsolete CPU models. When the node-labeller obtains the list of obsolete CPU models, it + eliminates those CPU models and creates labels for valid CPU models. + The default values for this field is nil, however, HCO uses opinionated values, and adding values to this list + will add them to the opinionated values. + items: + type: string + type: array + x-kubernetes-list-type: set + type: object + permittedHostDevices: + description: PermittedHostDevices holds information about devices + allowed for passthrough + properties: + mediatedDevices: + items: + description: MediatedHostDevice represents a host mediated device + allowed for passthrough + properties: + disabled: + description: |- + HCO enforces the existence of several MediatedHostDevice objects. Set disabled field to true instead of remove + these objects. + type: boolean + externalResourceProvider: + description: indicates that this resource is being provided + by an external device plugin + type: boolean + mdevNameSelector: + description: name of a mediated device type required to + identify a mediated device on a host + type: string + resourceName: + description: name by which a device is advertised and being + requested + type: string + required: + - mdevNameSelector + - resourceName + type: object + type: array + x-kubernetes-list-map-keys: + - mdevNameSelector + x-kubernetes-list-type: map + pciHostDevices: + items: + description: PciHostDevice represents a host PCI device allowed + for passthrough + properties: + disabled: + description: |- + HCO enforces the existence of several PciHostDevice objects. Set disabled field to true instead of remove + these objects. + type: boolean + externalResourceProvider: + description: indicates that this resource is being provided + by an external device plugin + type: boolean + pciDeviceSelector: + description: a combination of a vendor_id:product_id required + to identify a PCI device on a host. + type: string + resourceName: + description: name by which a device is advertised and being + requested + type: string + required: + - pciDeviceSelector + - resourceName + type: object + type: array + x-kubernetes-list-map-keys: + - pciDeviceSelector + x-kubernetes-list-type: map + usbHostDevices: + items: + description: USBHostDevice represents a host USB device allowed + for passthrough + properties: + disabled: + description: |- + HCO enforces the existence of several USBHostDevice objects. Set disabled field to true instead of remove + these objects. + type: boolean + externalResourceProvider: + description: |- + If true, KubeVirt will leave the allocation and monitoring to an + external device plugin + type: boolean + resourceName: + description: |- + Identifies the list of USB host devices. + e.g: kubevirt.io/storage, kubevirt.io/bootable-usb, etc + type: string + selectors: + items: + description: USBSelector represents a selector for a USB + device allowed for passthrough + properties: + product: + type: string + vendor: + type: string + required: + - product + - vendor + type: object + type: array + x-kubernetes-list-type: atomic + required: + - resourceName + type: object + type: array + x-kubernetes-list-map-keys: + - resourceName + x-kubernetes-list-type: map + type: object + resourceRequirements: + default: + vmiCPUAllocationRatio: 10 + description: ResourceRequirements describes the resource requirements + for the operand workloads. + properties: + autoCPULimitNamespaceLabelSelector: + description: |- + When set, AutoCPULimitNamespaceLabelSelector will set a CPU limit on virt-launcher for VMIs running inside + namespaces that match the label selector. + The CPU limit will equal the number of requested vCPUs. + This setting does not apply to VMIs with dedicated CPUs. + properties: + matchExpressions: + description: matchExpressions is a list of label selector + requirements. The requirements are ANDed. + items: + description: |- + A label selector requirement is a selector that contains values, a key, and an operator that + relates the key and values. + properties: + key: + description: key is the label key that the selector + applies to. + type: string + operator: + description: |- + operator represents a key's relationship to a set of values. + Valid operators are In, NotIn, Exists and DoesNotExist. + type: string + values: + description: |- + values is an array of string values. If the operator is In or NotIn, + the values array must be non-empty. If the operator is Exists or DoesNotExist, + the values array must be empty. This array is replaced during a strategic + merge patch. + items: + type: string + type: array + x-kubernetes-list-type: atomic + required: + - key + - operator + type: object + type: array + x-kubernetes-list-type: atomic + matchLabels: + additionalProperties: + type: string + description: |- + matchLabels is a map of {key,value} pairs. A single {key,value} in the matchLabels + map is equivalent to an element of matchExpressions, whose key field is "key", the + operator is "In", and the values array contains only "value". The requirements are ANDed. + type: object + type: object + x-kubernetes-map-type: atomic + storageWorkloads: + description: |- + StorageWorkloads defines the resources requirements for storage workloads. It will propagate to the CDI custom + resource + properties: + claims: + description: |- + Claims lists the names of resources, defined in spec.resourceClaims, + that are used by this container. + + This field depends on the + DynamicResourceAllocation feature gate. + + This field is immutable. It can only be set for containers. + items: + description: ResourceClaim references one entry in PodSpec.ResourceClaims. + properties: + name: + description: |- + Name must match the name of one entry in pod.spec.resourceClaims of + the Pod where this field is used. It makes that resource available + inside a container. + type: string + request: + description: |- + Request is the name chosen for a request in the referenced claim. + If empty, everything from the claim is made available, otherwise + only the result of this request. + type: string + required: + - name + type: object + type: array + x-kubernetes-list-map-keys: + - name + x-kubernetes-list-type: map + limits: + additionalProperties: + anyOf: + - type: integer + - type: string + pattern: ^(\+|-)?(([0-9]+(\.[0-9]*)?)|(\.[0-9]+))(([KMGTPE]i)|[numkMGTPE]|([eE](\+|-)?(([0-9]+(\.[0-9]*)?)|(\.[0-9]+))))?$ + x-kubernetes-int-or-string: true + description: |- + Limits describes the maximum amount of compute resources allowed. + More info: https://kubernetes.io/docs/concepts/configuration/manage-resources-containers/ + type: object + requests: + additionalProperties: + anyOf: + - type: integer + - type: string + pattern: ^(\+|-)?(([0-9]+(\.[0-9]*)?)|(\.[0-9]+))(([KMGTPE]i)|[numkMGTPE]|([eE](\+|-)?(([0-9]+(\.[0-9]*)?)|(\.[0-9]+))))?$ + x-kubernetes-int-or-string: true + description: |- + Requests describes the minimum amount of compute resources required. + If Requests is omitted for a container, it defaults to Limits if that is explicitly specified, + otherwise to an implementation-defined value. Requests cannot exceed Limits. + More info: https://kubernetes.io/docs/concepts/configuration/manage-resources-containers/ + type: object + type: object + vmiCPUAllocationRatio: + default: 10 + description: |- + VmiCPUAllocationRatio defines, for each requested virtual CPU, + how much physical CPU to request per VMI from the + hosting node. The value is in fraction of a CPU thread (or + core on non-hyperthreaded nodes). + VMI POD CPU request = number of vCPUs * 1/vmiCPUAllocationRatio + For example, a value of 1 means 1 physical CPU thread per VMI CPU thread. + A value of 100 would be 1% of a physical thread allocated for each + requested VMI thread. + This option has no effect on VMIs that request dedicated CPUs. + Defaults to 10 + minimum: 1 + type: integer + type: object + x-kubernetes-validations: + - message: vmiCPUAllocationRatio must be greater than 0 + rule: '!has(self.vmiCPUAllocationRatio) || self.vmiCPUAllocationRatio + > 0' + scratchSpaceStorageClass: + description: |- + Override the storage class used for scratch space during transfer operations. The scratch space storage class + is determined in the following order: + value of scratchSpaceStorageClass, if that doesn't exist, use the default storage class, if there is no default + storage class, use the storage class of the DataVolume, if no storage class specified, use no storage class for + scratch space + type: string + storageImport: + description: StorageImport contains configuration for importing containerized + data + properties: + insecureRegistries: + description: |- + InsecureRegistries is a list of image registries URLs that are not secured. Setting an insecure registry URL + in this list allows pulling images from this registry. + items: + type: string + type: array + x-kubernetes-list-type: set + type: object + tlsSecurityProfile: + description: |- + TLSSecurityProfile specifies the settings for TLS connections to be propagated to all kubevirt-hyperconverged components. + If unset, the hyperconverged cluster operator will consume the value set on the APIServer CR on OCP/OKD or Intermediate if on vanilla k8s. + Note that only Old, Intermediate and Custom profiles are currently supported, and the maximum available + MinTLSVersions is VersionTLS12. + properties: + custom: + description: |- + custom is a user-defined TLS security profile. Be extremely careful using a custom + profile as invalid configurations can be catastrophic. An example custom profile + looks like this: + + ciphers: + + - ECDHE-ECDSA-CHACHA20-POLY1305 + + - ECDHE-RSA-CHACHA20-POLY1305 + + - ECDHE-RSA-AES128-GCM-SHA256 + + - ECDHE-ECDSA-AES128-GCM-SHA256 + + minTLSVersion: VersionTLS11 + nullable: true + properties: + ciphers: + description: |- + ciphers is used to specify the cipher algorithms that are negotiated + during the TLS handshake. Operators may remove entries their operands + do not support. For example, to use DES-CBC3-SHA (yaml): + + ciphers: + - DES-CBC3-SHA + items: + type: string + type: array + x-kubernetes-list-type: atomic + minTLSVersion: + description: |- + minTLSVersion is used to specify the minimal version of the TLS protocol + that is negotiated during the TLS handshake. For example, to use TLS + versions 1.1, 1.2 and 1.3 (yaml): + + minTLSVersion: VersionTLS11 + + NOTE: currently the highest minTLSVersion allowed is VersionTLS12 + enum: + - VersionTLS10 + - VersionTLS11 + - VersionTLS12 + - VersionTLS13 + type: string + type: object + intermediate: + description: |- + intermediate is a TLS security profile based on: + + https://wiki.mozilla.org/Security/Server_Side_TLS#Intermediate_compatibility_.28recommended.29 + + and looks like this (yaml): + + ciphers: + + - TLS_AES_128_GCM_SHA256 + + - TLS_AES_256_GCM_SHA384 + + - TLS_CHACHA20_POLY1305_SHA256 + + - ECDHE-ECDSA-AES128-GCM-SHA256 + + - ECDHE-RSA-AES128-GCM-SHA256 + + - ECDHE-ECDSA-AES256-GCM-SHA384 + + - ECDHE-RSA-AES256-GCM-SHA384 + + - ECDHE-ECDSA-CHACHA20-POLY1305 + + - ECDHE-RSA-CHACHA20-POLY1305 + + - DHE-RSA-AES128-GCM-SHA256 + + - DHE-RSA-AES256-GCM-SHA384 + + minTLSVersion: VersionTLS12 + nullable: true + type: object + modern: + description: |- + modern is a TLS security profile based on: + + https://wiki.mozilla.org/Security/Server_Side_TLS#Modern_compatibility + + and looks like this (yaml): + + ciphers: + + - TLS_AES_128_GCM_SHA256 + + - TLS_AES_256_GCM_SHA384 + + - TLS_CHACHA20_POLY1305_SHA256 + + minTLSVersion: VersionTLS13 + nullable: true + type: object + old: + description: |- + old is a TLS security profile based on: + + https://wiki.mozilla.org/Security/Server_Side_TLS#Old_backward_compatibility + + and looks like this (yaml): + + ciphers: + + - TLS_AES_128_GCM_SHA256 + + - TLS_AES_256_GCM_SHA384 + + - TLS_CHACHA20_POLY1305_SHA256 + + - ECDHE-ECDSA-AES128-GCM-SHA256 + + - ECDHE-RSA-AES128-GCM-SHA256 + + - ECDHE-ECDSA-AES256-GCM-SHA384 + + - ECDHE-RSA-AES256-GCM-SHA384 + + - ECDHE-ECDSA-CHACHA20-POLY1305 + + - ECDHE-RSA-CHACHA20-POLY1305 + + - DHE-RSA-AES128-GCM-SHA256 + + - DHE-RSA-AES256-GCM-SHA384 + + - DHE-RSA-CHACHA20-POLY1305 + + - ECDHE-ECDSA-AES128-SHA256 + + - ECDHE-RSA-AES128-SHA256 + + - ECDHE-ECDSA-AES128-SHA + + - ECDHE-RSA-AES128-SHA + + - ECDHE-ECDSA-AES256-SHA384 + + - ECDHE-RSA-AES256-SHA384 + + - ECDHE-ECDSA-AES256-SHA + + - ECDHE-RSA-AES256-SHA + + - DHE-RSA-AES128-SHA256 + + - DHE-RSA-AES256-SHA256 + + - AES128-GCM-SHA256 + + - AES256-GCM-SHA384 + + - AES128-SHA256 + + - AES256-SHA256 + + - AES128-SHA + + - AES256-SHA + + - DES-CBC3-SHA + + minTLSVersion: VersionTLS10 + nullable: true + type: object + type: + description: |- + type is one of Old, Intermediate, Modern or Custom. Custom provides + the ability to specify individual TLS security profile parameters. + Old, Intermediate and Modern are TLS security profiles based on: + + https://wiki.mozilla.org/Security/Server_Side_TLS#Recommended_configurations + + The profiles are intent based, so they may change over time as new ciphers are developed and existing ciphers + are found to be insecure. Depending on precisely which ciphers are available to a process, the list may be + reduced. + + Note that the Modern profile is currently not supported because it is not + yet well adopted by common software libraries. + enum: + - Old + - Intermediate + - Modern + - Custom + type: string + type: object + tuningPolicy: + description: |- + TuningPolicy allows to configure the mode in which the RateLimits of kubevirt are set. + If TuningPolicy is not present the default kubevirt values are used. + It can be set to `annotation` for fine-tuning the kubevirt queryPerSeconds (qps) and burst values. + Qps and burst values are taken from the annotation hco.kubevirt.io/tuningPolicy + enum: + - annotation + - highBurst + type: string + uninstallStrategy: + default: BlockUninstallIfWorkloadsExist + description: |- + UninstallStrategy defines how to proceed on uninstall when workloads (VirtualMachines, DataVolumes) still exist. + BlockUninstallIfWorkloadsExist will prevent the CR from being removed when workloads still exist. + BlockUninstallIfWorkloadsExist is the safest choice to protect your workloads from accidental data loss, so it's strongly advised. + RemoveWorkloads will cause all the workloads to be cascading deleted on uninstallation. + WARNING: please notice that RemoveWorkloads will cause your workloads to be deleted as soon as this CR will be, even accidentally, deleted. + Please correctly consider the implications of this option before setting it. + BlockUninstallIfWorkloadsExist is the default behaviour. + enum: + - RemoveWorkloads + - BlockUninstallIfWorkloadsExist + type: string + virtualMachineOptions: + default: + disableFreePageReporting: false + disableSerialConsoleLog: false + description: VirtualMachineOptions holds the cluster level information + regarding the virtual machine. + properties: + disableFreePageReporting: + default: false + description: |- + DisableFreePageReporting disable the free page reporting of + memory balloon device https://libvirt.org/formatdomain.html#memory-balloon-device. + This will have effect only if AutoattachMemBalloon is not false and the vmi is not + requesting any high performance feature (dedicatedCPU/realtime/hugePages), in which free page reporting is always disabled. + type: boolean + disableSerialConsoleLog: + default: false + description: |- + DisableSerialConsoleLog disables logging the auto-attached default serial console. + If not set, serial console logs will be written to a file and then streamed from a container named `guest-console-log`. + The value can be individually overridden for each VM, not relevant if AutoattachSerialConsole is disabled for the VM. + type: boolean + type: object + vmStateStorageClass: + description: VMStateStorageClass is the name of the storage class + to use for the PVCs created to preserve VM state, like TPM. + type: string + workloadUpdateStrategy: + default: + batchEvictionInterval: 1m0s + batchEvictionSize: 10 + workloadUpdateMethods: + - LiveMigrate + description: WorkloadUpdateStrategy defines at the cluster level how + to handle automated workload updates + properties: + batchEvictionInterval: + default: 1m0s + description: |- + BatchEvictionInterval Represents the interval to wait before issuing the next + batch of shutdowns + type: string + batchEvictionSize: + default: 10 + description: |- + BatchEvictionSize Represents the number of VMIs that can be forced updated per + the BatchShutdownInterval interval + type: integer + workloadUpdateMethods: + default: + - LiveMigrate + description: |- + WorkloadUpdateMethods defines the methods that can be used to disrupt workloads + during automated workload updates. + When multiple methods are present, the least disruptive method takes + precedence over more disruptive methods. For example if both LiveMigrate and Evict + methods are listed, only VMs which are not live migratable will be restarted/shutdown. + An empty list defaults to no automated workload updating. + items: + type: string + type: array + x-kubernetes-list-type: atomic + required: + - workloadUpdateMethods + type: object + workloads: + description: |- + workloads HyperConvergedConfig influences the pod configuration (currently only placement) of components + which need to be running on a node where virtualization workloads should be able to run. + Changes to Workloads HyperConvergedConfig can be applied only without existing workload. + properties: + nodePlacement: + description: NodePlacement describes node scheduling configuration. + properties: + affinity: + description: |- + affinity enables pod affinity/anti-affinity placement expanding the types of constraints + that can be expressed with nodeSelector. + affinity is going to be applied to the relevant kind of pods in parallel with nodeSelector + See https://kubernetes.io/docs/concepts/scheduling-eviction/assign-pod-node/#affinity-and-anti-affinity + properties: + nodeAffinity: + description: Describes node affinity scheduling rules + for the pod. + properties: + preferredDuringSchedulingIgnoredDuringExecution: + description: |- + The scheduler will prefer to schedule pods to nodes that satisfy + the affinity expressions specified by this field, but it may choose + a node that violates one or more of the expressions. The node that is + most preferred is the one with the greatest sum of weights, i.e. + for each node that meets all of the scheduling requirements (resource + request, requiredDuringScheduling affinity expressions, etc.), + compute a sum by iterating through the elements of this field and adding + "weight" to the sum if the node matches the corresponding matchExpressions; the + node(s) with the highest sum are the most preferred. + items: + description: |- + An empty preferred scheduling term matches all objects with implicit weight 0 + (i.e. it's a no-op). A null preferred scheduling term matches no objects (i.e. is also a no-op). + properties: + preference: + description: A node selector term, associated + with the corresponding weight. + properties: + matchExpressions: + description: A list of node selector requirements + by node's labels. + items: + description: |- + A node selector requirement is a selector that contains values, a key, and an operator + that relates the key and values. + properties: + key: + description: The label key that the + selector applies to. + type: string + operator: + description: |- + Represents a key's relationship to a set of values. + Valid operators are In, NotIn, Exists, DoesNotExist. Gt, and Lt. + type: string + values: + description: |- + An array of string values. If the operator is In or NotIn, + the values array must be non-empty. If the operator is Exists or DoesNotExist, + the values array must be empty. If the operator is Gt or Lt, the values + array must have a single element, which will be interpreted as an integer. + This array is replaced during a strategic merge patch. + items: + type: string + type: array + x-kubernetes-list-type: atomic + required: + - key + - operator + type: object + type: array + x-kubernetes-list-type: atomic + matchFields: + description: A list of node selector requirements + by node's fields. + items: + description: |- + A node selector requirement is a selector that contains values, a key, and an operator + that relates the key and values. + properties: + key: + description: The label key that the + selector applies to. + type: string + operator: + description: |- + Represents a key's relationship to a set of values. + Valid operators are In, NotIn, Exists, DoesNotExist. Gt, and Lt. + type: string + values: + description: |- + An array of string values. If the operator is In or NotIn, + the values array must be non-empty. If the operator is Exists or DoesNotExist, + the values array must be empty. If the operator is Gt or Lt, the values + array must have a single element, which will be interpreted as an integer. + This array is replaced during a strategic merge patch. + items: + type: string + type: array + x-kubernetes-list-type: atomic + required: + - key + - operator + type: object + type: array + x-kubernetes-list-type: atomic + type: object + x-kubernetes-map-type: atomic + weight: + description: Weight associated with matching + the corresponding nodeSelectorTerm, in the + range 1-100. + format: int32 + type: integer + required: + - preference + - weight + type: object + type: array + x-kubernetes-list-type: atomic + requiredDuringSchedulingIgnoredDuringExecution: + description: |- + If the affinity requirements specified by this field are not met at + scheduling time, the pod will not be scheduled onto the node. + If the affinity requirements specified by this field cease to be met + at some point during pod execution (e.g. due to an update), the system + may or may not try to eventually evict the pod from its node. + properties: + nodeSelectorTerms: + description: Required. A list of node selector + terms. The terms are ORed. + items: + description: |- + A null or empty node selector term matches no objects. The requirements of + them are ANDed. + The TopologySelectorTerm type implements a subset of the NodeSelectorTerm. + properties: + matchExpressions: + description: A list of node selector requirements + by node's labels. + items: + description: |- + A node selector requirement is a selector that contains values, a key, and an operator + that relates the key and values. + properties: + key: + description: The label key that the + selector applies to. + type: string + operator: + description: |- + Represents a key's relationship to a set of values. + Valid operators are In, NotIn, Exists, DoesNotExist. Gt, and Lt. + type: string + values: + description: |- + An array of string values. If the operator is In or NotIn, + the values array must be non-empty. If the operator is Exists or DoesNotExist, + the values array must be empty. If the operator is Gt or Lt, the values + array must have a single element, which will be interpreted as an integer. + This array is replaced during a strategic merge patch. + items: + type: string + type: array + x-kubernetes-list-type: atomic + required: + - key + - operator + type: object + type: array + x-kubernetes-list-type: atomic + matchFields: + description: A list of node selector requirements + by node's fields. + items: + description: |- + A node selector requirement is a selector that contains values, a key, and an operator + that relates the key and values. + properties: + key: + description: The label key that the + selector applies to. + type: string + operator: + description: |- + Represents a key's relationship to a set of values. + Valid operators are In, NotIn, Exists, DoesNotExist. Gt, and Lt. + type: string + values: + description: |- + An array of string values. If the operator is In or NotIn, + the values array must be non-empty. If the operator is Exists or DoesNotExist, + the values array must be empty. If the operator is Gt or Lt, the values + array must have a single element, which will be interpreted as an integer. + This array is replaced during a strategic merge patch. + items: + type: string + type: array + x-kubernetes-list-type: atomic + required: + - key + - operator + type: object + type: array + x-kubernetes-list-type: atomic + type: object + x-kubernetes-map-type: atomic + type: array + x-kubernetes-list-type: atomic + required: + - nodeSelectorTerms + type: object + x-kubernetes-map-type: atomic + type: object + podAffinity: + description: Describes pod affinity scheduling rules (e.g. + co-locate this pod in the same node, zone, etc. as some + other pod(s)). + properties: + preferredDuringSchedulingIgnoredDuringExecution: + description: |- + The scheduler will prefer to schedule pods to nodes that satisfy + the affinity expressions specified by this field, but it may choose + a node that violates one or more of the expressions. The node that is + most preferred is the one with the greatest sum of weights, i.e. + for each node that meets all of the scheduling requirements (resource + request, requiredDuringScheduling affinity expressions, etc.), + compute a sum by iterating through the elements of this field and adding + "weight" to the sum if the node has pods which matches the corresponding podAffinityTerm; the + node(s) with the highest sum are the most preferred. + items: + description: The weights of all of the matched WeightedPodAffinityTerm + fields are added per-node to find the most preferred + node(s) + properties: + podAffinityTerm: + description: Required. A pod affinity term, + associated with the corresponding weight. + properties: + labelSelector: + description: |- + A label query over a set of resources, in this case pods. + If it's null, this PodAffinityTerm matches with no Pods. + properties: + matchExpressions: + description: matchExpressions is a list + of label selector requirements. The + requirements are ANDed. + items: + description: |- + A label selector requirement is a selector that contains values, a key, and an operator that + relates the key and values. + properties: + key: + description: key is the label + key that the selector applies + to. + type: string + operator: + description: |- + operator represents a key's relationship to a set of values. + Valid operators are In, NotIn, Exists and DoesNotExist. + type: string + values: + description: |- + values is an array of string values. If the operator is In or NotIn, + the values array must be non-empty. If the operator is Exists or DoesNotExist, + the values array must be empty. This array is replaced during a strategic + merge patch. + items: + type: string + type: array + x-kubernetes-list-type: atomic + required: + - key + - operator + type: object + type: array + x-kubernetes-list-type: atomic + matchLabels: + additionalProperties: + type: string + description: |- + matchLabels is a map of {key,value} pairs. A single {key,value} in the matchLabels + map is equivalent to an element of matchExpressions, whose key field is "key", the + operator is "In", and the values array contains only "value". The requirements are ANDed. + type: object + type: object + x-kubernetes-map-type: atomic + matchLabelKeys: + description: |- + MatchLabelKeys is a set of pod label keys to select which pods will + be taken into consideration. The keys are used to lookup values from the + incoming pod labels, those key-value labels are merged with `labelSelector` as `key in (value)` + to select the group of existing pods which pods will be taken into consideration + for the incoming pod's pod (anti) affinity. Keys that don't exist in the incoming + pod labels will be ignored. The default value is empty. + The same key is forbidden to exist in both matchLabelKeys and labelSelector. + Also, matchLabelKeys cannot be set when labelSelector isn't set. + items: + type: string + type: array + x-kubernetes-list-type: atomic + mismatchLabelKeys: + description: |- + MismatchLabelKeys is a set of pod label keys to select which pods will + be taken into consideration. The keys are used to lookup values from the + incoming pod labels, those key-value labels are merged with `labelSelector` as `key notin (value)` + to select the group of existing pods which pods will be taken into consideration + for the incoming pod's pod (anti) affinity. Keys that don't exist in the incoming + pod labels will be ignored. The default value is empty. + The same key is forbidden to exist in both mismatchLabelKeys and labelSelector. + Also, mismatchLabelKeys cannot be set when labelSelector isn't set. + items: + type: string + type: array + x-kubernetes-list-type: atomic + namespaceSelector: + description: |- + A label query over the set of namespaces that the term applies to. + The term is applied to the union of the namespaces selected by this field + and the ones listed in the namespaces field. + null selector and null or empty namespaces list means "this pod's namespace". + An empty selector ({}) matches all namespaces. + properties: + matchExpressions: + description: matchExpressions is a list + of label selector requirements. The + requirements are ANDed. + items: + description: |- + A label selector requirement is a selector that contains values, a key, and an operator that + relates the key and values. + properties: + key: + description: key is the label + key that the selector applies + to. + type: string + operator: + description: |- + operator represents a key's relationship to a set of values. + Valid operators are In, NotIn, Exists and DoesNotExist. + type: string + values: + description: |- + values is an array of string values. If the operator is In or NotIn, + the values array must be non-empty. If the operator is Exists or DoesNotExist, + the values array must be empty. This array is replaced during a strategic + merge patch. + items: + type: string + type: array + x-kubernetes-list-type: atomic + required: + - key + - operator + type: object + type: array + x-kubernetes-list-type: atomic + matchLabels: + additionalProperties: + type: string + description: |- + matchLabels is a map of {key,value} pairs. A single {key,value} in the matchLabels + map is equivalent to an element of matchExpressions, whose key field is "key", the + operator is "In", and the values array contains only "value". The requirements are ANDed. + type: object + type: object + x-kubernetes-map-type: atomic + namespaces: + description: |- + namespaces specifies a static list of namespace names that the term applies to. + The term is applied to the union of the namespaces listed in this field + and the ones selected by namespaceSelector. + null or empty namespaces list and null namespaceSelector means "this pod's namespace". + items: + type: string + type: array + x-kubernetes-list-type: atomic + topologyKey: + description: |- + This pod should be co-located (affinity) or not co-located (anti-affinity) with the pods matching + the labelSelector in the specified namespaces, where co-located is defined as running on a node + whose value of the label with key topologyKey matches that of any node on which any of the + selected pods is running. + Empty topologyKey is not allowed. + type: string + required: + - topologyKey + type: object + weight: + description: |- + weight associated with matching the corresponding podAffinityTerm, + in the range 1-100. + format: int32 + type: integer + required: + - podAffinityTerm + - weight + type: object + type: array + x-kubernetes-list-type: atomic + requiredDuringSchedulingIgnoredDuringExecution: + description: |- + If the affinity requirements specified by this field are not met at + scheduling time, the pod will not be scheduled onto the node. + If the affinity requirements specified by this field cease to be met + at some point during pod execution (e.g. due to a pod label update), the + system may or may not try to eventually evict the pod from its node. + When there are multiple elements, the lists of nodes corresponding to each + podAffinityTerm are intersected, i.e. all terms must be satisfied. + items: + description: |- + Defines a set of pods (namely those matching the labelSelector + relative to the given namespace(s)) that this pod should be + co-located (affinity) or not co-located (anti-affinity) with, + where co-located is defined as running on a node whose value of + the label with key matches that of any node on which + a pod of the set of pods is running + properties: + labelSelector: + description: |- + A label query over a set of resources, in this case pods. + If it's null, this PodAffinityTerm matches with no Pods. + properties: + matchExpressions: + description: matchExpressions is a list + of label selector requirements. The requirements + are ANDed. + items: + description: |- + A label selector requirement is a selector that contains values, a key, and an operator that + relates the key and values. + properties: + key: + description: key is the label key + that the selector applies to. + type: string + operator: + description: |- + operator represents a key's relationship to a set of values. + Valid operators are In, NotIn, Exists and DoesNotExist. + type: string + values: + description: |- + values is an array of string values. If the operator is In or NotIn, + the values array must be non-empty. If the operator is Exists or DoesNotExist, + the values array must be empty. This array is replaced during a strategic + merge patch. + items: + type: string + type: array + x-kubernetes-list-type: atomic + required: + - key + - operator + type: object + type: array + x-kubernetes-list-type: atomic + matchLabels: + additionalProperties: + type: string + description: |- + matchLabels is a map of {key,value} pairs. A single {key,value} in the matchLabels + map is equivalent to an element of matchExpressions, whose key field is "key", the + operator is "In", and the values array contains only "value". The requirements are ANDed. + type: object + type: object + x-kubernetes-map-type: atomic + matchLabelKeys: + description: |- + MatchLabelKeys is a set of pod label keys to select which pods will + be taken into consideration. The keys are used to lookup values from the + incoming pod labels, those key-value labels are merged with `labelSelector` as `key in (value)` + to select the group of existing pods which pods will be taken into consideration + for the incoming pod's pod (anti) affinity. Keys that don't exist in the incoming + pod labels will be ignored. The default value is empty. + The same key is forbidden to exist in both matchLabelKeys and labelSelector. + Also, matchLabelKeys cannot be set when labelSelector isn't set. + items: + type: string + type: array + x-kubernetes-list-type: atomic + mismatchLabelKeys: + description: |- + MismatchLabelKeys is a set of pod label keys to select which pods will + be taken into consideration. The keys are used to lookup values from the + incoming pod labels, those key-value labels are merged with `labelSelector` as `key notin (value)` + to select the group of existing pods which pods will be taken into consideration + for the incoming pod's pod (anti) affinity. Keys that don't exist in the incoming + pod labels will be ignored. The default value is empty. + The same key is forbidden to exist in both mismatchLabelKeys and labelSelector. + Also, mismatchLabelKeys cannot be set when labelSelector isn't set. + items: + type: string + type: array + x-kubernetes-list-type: atomic + namespaceSelector: + description: |- + A label query over the set of namespaces that the term applies to. + The term is applied to the union of the namespaces selected by this field + and the ones listed in the namespaces field. + null selector and null or empty namespaces list means "this pod's namespace". + An empty selector ({}) matches all namespaces. + properties: + matchExpressions: + description: matchExpressions is a list + of label selector requirements. The requirements + are ANDed. + items: + description: |- + A label selector requirement is a selector that contains values, a key, and an operator that + relates the key and values. + properties: + key: + description: key is the label key + that the selector applies to. + type: string + operator: + description: |- + operator represents a key's relationship to a set of values. + Valid operators are In, NotIn, Exists and DoesNotExist. + type: string + values: + description: |- + values is an array of string values. If the operator is In or NotIn, + the values array must be non-empty. If the operator is Exists or DoesNotExist, + the values array must be empty. This array is replaced during a strategic + merge patch. + items: + type: string + type: array + x-kubernetes-list-type: atomic + required: + - key + - operator + type: object + type: array + x-kubernetes-list-type: atomic + matchLabels: + additionalProperties: + type: string + description: |- + matchLabels is a map of {key,value} pairs. A single {key,value} in the matchLabels + map is equivalent to an element of matchExpressions, whose key field is "key", the + operator is "In", and the values array contains only "value". The requirements are ANDed. + type: object + type: object + x-kubernetes-map-type: atomic + namespaces: + description: |- + namespaces specifies a static list of namespace names that the term applies to. + The term is applied to the union of the namespaces listed in this field + and the ones selected by namespaceSelector. + null or empty namespaces list and null namespaceSelector means "this pod's namespace". + items: + type: string + type: array + x-kubernetes-list-type: atomic + topologyKey: + description: |- + This pod should be co-located (affinity) or not co-located (anti-affinity) with the pods matching + the labelSelector in the specified namespaces, where co-located is defined as running on a node + whose value of the label with key topologyKey matches that of any node on which any of the + selected pods is running. + Empty topologyKey is not allowed. + type: string + required: + - topologyKey + type: object + type: array + x-kubernetes-list-type: atomic + type: object + podAntiAffinity: + description: Describes pod anti-affinity scheduling rules + (e.g. avoid putting this pod in the same node, zone, + etc. as some other pod(s)). + properties: + preferredDuringSchedulingIgnoredDuringExecution: + description: |- + The scheduler will prefer to schedule pods to nodes that satisfy + the anti-affinity expressions specified by this field, but it may choose + a node that violates one or more of the expressions. The node that is + most preferred is the one with the greatest sum of weights, i.e. + for each node that meets all of the scheduling requirements (resource + request, requiredDuringScheduling anti-affinity expressions, etc.), + compute a sum by iterating through the elements of this field and subtracting + "weight" from the sum if the node has pods which matches the corresponding podAffinityTerm; the + node(s) with the highest sum are the most preferred. + items: + description: The weights of all of the matched WeightedPodAffinityTerm + fields are added per-node to find the most preferred + node(s) + properties: + podAffinityTerm: + description: Required. A pod affinity term, + associated with the corresponding weight. + properties: + labelSelector: + description: |- + A label query over a set of resources, in this case pods. + If it's null, this PodAffinityTerm matches with no Pods. + properties: + matchExpressions: + description: matchExpressions is a list + of label selector requirements. The + requirements are ANDed. + items: + description: |- + A label selector requirement is a selector that contains values, a key, and an operator that + relates the key and values. + properties: + key: + description: key is the label + key that the selector applies + to. + type: string + operator: + description: |- + operator represents a key's relationship to a set of values. + Valid operators are In, NotIn, Exists and DoesNotExist. + type: string + values: + description: |- + values is an array of string values. If the operator is In or NotIn, + the values array must be non-empty. If the operator is Exists or DoesNotExist, + the values array must be empty. This array is replaced during a strategic + merge patch. + items: + type: string + type: array + x-kubernetes-list-type: atomic + required: + - key + - operator + type: object + type: array + x-kubernetes-list-type: atomic + matchLabels: + additionalProperties: + type: string + description: |- + matchLabels is a map of {key,value} pairs. A single {key,value} in the matchLabels + map is equivalent to an element of matchExpressions, whose key field is "key", the + operator is "In", and the values array contains only "value". The requirements are ANDed. + type: object + type: object + x-kubernetes-map-type: atomic + matchLabelKeys: + description: |- + MatchLabelKeys is a set of pod label keys to select which pods will + be taken into consideration. The keys are used to lookup values from the + incoming pod labels, those key-value labels are merged with `labelSelector` as `key in (value)` + to select the group of existing pods which pods will be taken into consideration + for the incoming pod's pod (anti) affinity. Keys that don't exist in the incoming + pod labels will be ignored. The default value is empty. + The same key is forbidden to exist in both matchLabelKeys and labelSelector. + Also, matchLabelKeys cannot be set when labelSelector isn't set. + items: + type: string + type: array + x-kubernetes-list-type: atomic + mismatchLabelKeys: + description: |- + MismatchLabelKeys is a set of pod label keys to select which pods will + be taken into consideration. The keys are used to lookup values from the + incoming pod labels, those key-value labels are merged with `labelSelector` as `key notin (value)` + to select the group of existing pods which pods will be taken into consideration + for the incoming pod's pod (anti) affinity. Keys that don't exist in the incoming + pod labels will be ignored. The default value is empty. + The same key is forbidden to exist in both mismatchLabelKeys and labelSelector. + Also, mismatchLabelKeys cannot be set when labelSelector isn't set. + items: + type: string + type: array + x-kubernetes-list-type: atomic + namespaceSelector: + description: |- + A label query over the set of namespaces that the term applies to. + The term is applied to the union of the namespaces selected by this field + and the ones listed in the namespaces field. + null selector and null or empty namespaces list means "this pod's namespace". + An empty selector ({}) matches all namespaces. + properties: + matchExpressions: + description: matchExpressions is a list + of label selector requirements. The + requirements are ANDed. + items: + description: |- + A label selector requirement is a selector that contains values, a key, and an operator that + relates the key and values. + properties: + key: + description: key is the label + key that the selector applies + to. + type: string + operator: + description: |- + operator represents a key's relationship to a set of values. + Valid operators are In, NotIn, Exists and DoesNotExist. + type: string + values: + description: |- + values is an array of string values. If the operator is In or NotIn, + the values array must be non-empty. If the operator is Exists or DoesNotExist, + the values array must be empty. This array is replaced during a strategic + merge patch. + items: + type: string + type: array + x-kubernetes-list-type: atomic + required: + - key + - operator + type: object + type: array + x-kubernetes-list-type: atomic + matchLabels: + additionalProperties: + type: string + description: |- + matchLabels is a map of {key,value} pairs. A single {key,value} in the matchLabels + map is equivalent to an element of matchExpressions, whose key field is "key", the + operator is "In", and the values array contains only "value". The requirements are ANDed. + type: object + type: object + x-kubernetes-map-type: atomic + namespaces: + description: |- + namespaces specifies a static list of namespace names that the term applies to. + The term is applied to the union of the namespaces listed in this field + and the ones selected by namespaceSelector. + null or empty namespaces list and null namespaceSelector means "this pod's namespace". + items: + type: string + type: array + x-kubernetes-list-type: atomic + topologyKey: + description: |- + This pod should be co-located (affinity) or not co-located (anti-affinity) with the pods matching + the labelSelector in the specified namespaces, where co-located is defined as running on a node + whose value of the label with key topologyKey matches that of any node on which any of the + selected pods is running. + Empty topologyKey is not allowed. + type: string + required: + - topologyKey + type: object + weight: + description: |- + weight associated with matching the corresponding podAffinityTerm, + in the range 1-100. + format: int32 + type: integer + required: + - podAffinityTerm + - weight + type: object + type: array + x-kubernetes-list-type: atomic + requiredDuringSchedulingIgnoredDuringExecution: + description: |- + If the anti-affinity requirements specified by this field are not met at + scheduling time, the pod will not be scheduled onto the node. + If the anti-affinity requirements specified by this field cease to be met + at some point during pod execution (e.g. due to a pod label update), the + system may or may not try to eventually evict the pod from its node. + When there are multiple elements, the lists of nodes corresponding to each + podAffinityTerm are intersected, i.e. all terms must be satisfied. + items: + description: |- + Defines a set of pods (namely those matching the labelSelector + relative to the given namespace(s)) that this pod should be + co-located (affinity) or not co-located (anti-affinity) with, + where co-located is defined as running on a node whose value of + the label with key matches that of any node on which + a pod of the set of pods is running + properties: + labelSelector: + description: |- + A label query over a set of resources, in this case pods. + If it's null, this PodAffinityTerm matches with no Pods. + properties: + matchExpressions: + description: matchExpressions is a list + of label selector requirements. The requirements + are ANDed. + items: + description: |- + A label selector requirement is a selector that contains values, a key, and an operator that + relates the key and values. + properties: + key: + description: key is the label key + that the selector applies to. + type: string + operator: + description: |- + operator represents a key's relationship to a set of values. + Valid operators are In, NotIn, Exists and DoesNotExist. + type: string + values: + description: |- + values is an array of string values. If the operator is In or NotIn, + the values array must be non-empty. If the operator is Exists or DoesNotExist, + the values array must be empty. This array is replaced during a strategic + merge patch. + items: + type: string + type: array + x-kubernetes-list-type: atomic + required: + - key + - operator + type: object + type: array + x-kubernetes-list-type: atomic + matchLabels: + additionalProperties: + type: string + description: |- + matchLabels is a map of {key,value} pairs. A single {key,value} in the matchLabels + map is equivalent to an element of matchExpressions, whose key field is "key", the + operator is "In", and the values array contains only "value". The requirements are ANDed. + type: object + type: object + x-kubernetes-map-type: atomic + matchLabelKeys: + description: |- + MatchLabelKeys is a set of pod label keys to select which pods will + be taken into consideration. The keys are used to lookup values from the + incoming pod labels, those key-value labels are merged with `labelSelector` as `key in (value)` + to select the group of existing pods which pods will be taken into consideration + for the incoming pod's pod (anti) affinity. Keys that don't exist in the incoming + pod labels will be ignored. The default value is empty. + The same key is forbidden to exist in both matchLabelKeys and labelSelector. + Also, matchLabelKeys cannot be set when labelSelector isn't set. + items: + type: string + type: array + x-kubernetes-list-type: atomic + mismatchLabelKeys: + description: |- + MismatchLabelKeys is a set of pod label keys to select which pods will + be taken into consideration. The keys are used to lookup values from the + incoming pod labels, those key-value labels are merged with `labelSelector` as `key notin (value)` + to select the group of existing pods which pods will be taken into consideration + for the incoming pod's pod (anti) affinity. Keys that don't exist in the incoming + pod labels will be ignored. The default value is empty. + The same key is forbidden to exist in both mismatchLabelKeys and labelSelector. + Also, mismatchLabelKeys cannot be set when labelSelector isn't set. + items: + type: string + type: array + x-kubernetes-list-type: atomic + namespaceSelector: + description: |- + A label query over the set of namespaces that the term applies to. + The term is applied to the union of the namespaces selected by this field + and the ones listed in the namespaces field. + null selector and null or empty namespaces list means "this pod's namespace". + An empty selector ({}) matches all namespaces. + properties: + matchExpressions: + description: matchExpressions is a list + of label selector requirements. The requirements + are ANDed. + items: + description: |- + A label selector requirement is a selector that contains values, a key, and an operator that + relates the key and values. + properties: + key: + description: key is the label key + that the selector applies to. + type: string + operator: + description: |- + operator represents a key's relationship to a set of values. + Valid operators are In, NotIn, Exists and DoesNotExist. + type: string + values: + description: |- + values is an array of string values. If the operator is In or NotIn, + the values array must be non-empty. If the operator is Exists or DoesNotExist, + the values array must be empty. This array is replaced during a strategic + merge patch. + items: + type: string + type: array + x-kubernetes-list-type: atomic + required: + - key + - operator + type: object + type: array + x-kubernetes-list-type: atomic + matchLabels: + additionalProperties: + type: string + description: |- + matchLabels is a map of {key,value} pairs. A single {key,value} in the matchLabels + map is equivalent to an element of matchExpressions, whose key field is "key", the + operator is "In", and the values array contains only "value". The requirements are ANDed. + type: object + type: object + x-kubernetes-map-type: atomic + namespaces: + description: |- + namespaces specifies a static list of namespace names that the term applies to. + The term is applied to the union of the namespaces listed in this field + and the ones selected by namespaceSelector. + null or empty namespaces list and null namespaceSelector means "this pod's namespace". + items: + type: string + type: array + x-kubernetes-list-type: atomic + topologyKey: + description: |- + This pod should be co-located (affinity) or not co-located (anti-affinity) with the pods matching + the labelSelector in the specified namespaces, where co-located is defined as running on a node + whose value of the label with key topologyKey matches that of any node on which any of the + selected pods is running. + Empty topologyKey is not allowed. + type: string + required: + - topologyKey + type: object + type: array + x-kubernetes-list-type: atomic + type: object + type: object + nodeSelector: + additionalProperties: + type: string + description: |- + nodeSelector is the node selector applied to the relevant kind of pods + It specifies a map of key-value pairs: for the pod to be eligible to run on a node, + the node must have each of the indicated key-value pairs as labels + (it can have additional labels as well). + See https://kubernetes.io/docs/concepts/configuration/assign-pod-node/#nodeselector + type: object + tolerations: + description: |- + tolerations is a list of tolerations applied to the relevant kind of pods + See https://kubernetes.io/docs/concepts/configuration/taint-and-toleration/ for more info. + These are additional tolerations other than default ones. + items: + description: |- + The pod this Toleration is attached to tolerates any taint that matches + the triple using the matching operator . + properties: + effect: + description: |- + Effect indicates the taint effect to match. Empty means match all taint effects. + When specified, allowed values are NoSchedule, PreferNoSchedule and NoExecute. + type: string + key: + description: |- + Key is the taint key that the toleration applies to. Empty means match all taint keys. + If the key is empty, operator must be Exists; this combination means to match all values and all keys. + type: string + operator: + description: |- + Operator represents a key's relationship to the value. + Valid operators are Exists and Equal. Defaults to Equal. + Exists is equivalent to wildcard for value, so that a pod can + tolerate all taints of a particular category. + type: string + tolerationSeconds: + description: |- + TolerationSeconds represents the period of time the toleration (which must be + of effect NoExecute, otherwise this field is ignored) tolerates the taint. By default, + it is not set, which means tolerate the taint forever (do not evict). Zero and + negative values will be treated as 0 (evict immediately) by the system. + format: int64 + type: integer + value: + description: |- + Value is the taint value the toleration matches to. + If the operator is Exists, the value should be empty, otherwise just a regular string. + type: string + type: object + type: array + type: object + type: object + type: object + status: + description: HyperConvergedStatus defines the observed state of HyperConverged + properties: + conditions: + description: Conditions describes the state of the HyperConverged + resource. + items: + description: Condition contains details for one aspect of the current + state of this API Resource. + properties: + lastTransitionTime: + description: |- + lastTransitionTime is the last time the condition transitioned from one status to another. + This should be when the underlying condition changed. If that is not known, then using the time when the API field changed is acceptable. + format: date-time + type: string + message: + description: |- + message is a human readable message indicating details about the transition. + This may be an empty string. + maxLength: 32768 + type: string + observedGeneration: + description: |- + observedGeneration represents the .metadata.generation that the condition was set based upon. + For instance, if .metadata.generation is currently 12, but the .status.conditions[x].observedGeneration is 9, the condition is out of date + with respect to the current state of the instance. + format: int64 + minimum: 0 + type: integer + reason: + description: |- + reason contains a programmatic identifier indicating the reason for the condition's last transition. + Producers of specific condition types may define expected values and meanings for this field, + and whether the values are considered a guaranteed API. + The value should be a CamelCase string. + This field may not be empty. + maxLength: 1024 + minLength: 1 + pattern: ^[A-Za-z]([A-Za-z0-9_,:]*[A-Za-z0-9_])?$ + type: string + status: + description: status of the condition, one of True, False, Unknown. + enum: + - "True" + - "False" + - Unknown + type: string + type: + description: type of condition in CamelCase or in foo.example.com/CamelCase. + maxLength: 316 + pattern: ^([a-z0-9]([-a-z0-9]*[a-z0-9])?(\.[a-z0-9]([-a-z0-9]*[a-z0-9])?)*/)?(([A-Za-z0-9][-A-Za-z0-9_.]*)?[A-Za-z0-9])$ + type: string + required: + - lastTransitionTime + - message + - reason + - status + - type + type: object + type: array + x-kubernetes-list-type: atomic + dataImportCronTemplates: + description: |- + DataImportCronTemplates is a list of the actual DataImportCronTemplates as HCO update in the SSP CR. The list + contains both the common and the custom templates, including any modification done by HCO. + items: + description: DataImportCronTemplateStatus is a copy of a dataImportCronTemplate + as defined in the spec, or in the HCO image. + properties: + metadata: + properties: + annotations: + additionalProperties: + type: string + type: object + finalizers: + items: + type: string + type: array + labels: + additionalProperties: + type: string + type: object + name: + type: string + namespace: + type: string + type: object + spec: + description: DataImportCronSpec defines specification for DataImportCron + properties: + garbageCollect: + description: |- + GarbageCollect specifies whether old PVCs should be cleaned up after a new PVC is imported. + Options are currently "Outdated" and "Never", defaults to "Outdated". + type: string + importsToKeep: + description: Number of import PVCs to keep when garbage + collecting. Default is 3. + format: int32 + type: integer + managedDataSource: + description: |- + ManagedDataSource specifies the name of the corresponding DataSource this cron will manage. + DataSource has to be in the same namespace. + type: string + retentionPolicy: + description: RetentionPolicy specifies whether the created + DataVolumes and DataSources are retained when their DataImportCron + is deleted. Default is RatainAll. + type: string + schedule: + description: Schedule specifies in cron format when and + how often to look for new imports + type: string + serviceAccountName: + description: ServiceAccountName is the name of the ServiceAccount + for creating DataVolumes. + minLength: 1 + type: string + template: + description: Template specifies template for the DVs to + be created + properties: + apiVersion: + description: |- + APIVersion defines the versioned schema of this representation of an object. + Servers should convert recognized schemas to the latest internal value, and + may reject unrecognized values. + More info: https://git.k8s.io/community/contributors/devel/sig-architecture/api-conventions.md#resources + type: string + kind: + description: |- + Kind is a string value representing the REST resource this object represents. + Servers may infer this from the endpoint the client submits requests to. + Cannot be updated. + In CamelCase. + More info: https://git.k8s.io/community/contributors/devel/sig-architecture/api-conventions.md#types-kinds + type: string + metadata: + properties: + annotations: + additionalProperties: + type: string + type: object + finalizers: + items: + type: string + type: array + labels: + additionalProperties: + type: string + type: object + name: + type: string + namespace: + type: string + type: object + spec: + description: DataVolumeSpec defines the DataVolume type + specification + properties: + checkpoints: + description: Checkpoints is a list of DataVolumeCheckpoints, + representing stages in a multistage import. + items: + description: DataVolumeCheckpoint defines a stage + in a warm migration. + properties: + current: + description: Current is the identifier of + the snapshot created for this checkpoint. + type: string + previous: + description: Previous is the identifier of + the snapshot from the previous checkpoint. + type: string + required: + - current + - previous + type: object + type: array + contentType: + description: 'DataVolumeContentType options: "kubevirt", + "archive"' + enum: + - kubevirt + - archive + type: string + finalCheckpoint: + description: FinalCheckpoint indicates whether the + current DataVolumeCheckpoint is the final checkpoint. + type: boolean + preallocation: + description: Preallocation controls whether storage + for DataVolumes should be allocated in advance. + type: boolean + priorityClassName: + description: PriorityClassName for Importer, Cloner + and Uploader pod + type: string + pvc: + description: PVC is the PVC specification + properties: + accessModes: + description: |- + accessModes contains the desired access modes the volume should have. + More info: https://kubernetes.io/docs/concepts/storage/persistent-volumes#access-modes-1 + items: + type: string + type: array + x-kubernetes-list-type: atomic + dataSource: + description: |- + dataSource field can be used to specify either: + * An existing VolumeSnapshot object (snapshot.storage.k8s.io/VolumeSnapshot) + * An existing PVC (PersistentVolumeClaim) + If the provisioner or an external controller can support the specified data source, + it will create a new volume based on the contents of the specified data source. + When the AnyVolumeDataSource feature gate is enabled, dataSource contents will be copied to dataSourceRef, + and dataSourceRef contents will be copied to dataSource when dataSourceRef.namespace is not specified. + If the namespace is specified, then dataSourceRef will not be copied to dataSource. + properties: + apiGroup: + description: |- + APIGroup is the group for the resource being referenced. + If APIGroup is not specified, the specified Kind must be in the core API group. + For any other third-party types, APIGroup is required. + type: string + kind: + description: Kind is the type of resource + being referenced + type: string + name: + description: Name is the name of resource + being referenced + type: string + required: + - kind + - name + type: object + x-kubernetes-map-type: atomic + dataSourceRef: + description: |- + dataSourceRef specifies the object from which to populate the volume with data, if a non-empty + volume is desired. This may be any object from a non-empty API group (non + core object) or a PersistentVolumeClaim object. + When this field is specified, volume binding will only succeed if the type of + the specified object matches some installed volume populator or dynamic + provisioner. + This field will replace the functionality of the dataSource field and as such + if both fields are non-empty, they must have the same value. For backwards + compatibility, when namespace isn't specified in dataSourceRef, + both fields (dataSource and dataSourceRef) will be set to the same + value automatically if one of them is empty and the other is non-empty. + When namespace is specified in dataSourceRef, + dataSource isn't set to the same value and must be empty. + There are three important differences between dataSource and dataSourceRef: + * While dataSource only allows two specific types of objects, dataSourceRef + allows any non-core object, as well as PersistentVolumeClaim objects. + * While dataSource ignores disallowed values (dropping them), dataSourceRef + preserves all values, and generates an error if a disallowed value is + specified. + * While dataSource only allows local objects, dataSourceRef allows objects + in any namespaces. + (Beta) Using this field requires the AnyVolumeDataSource feature gate to be enabled. + (Alpha) Using the namespace field of dataSourceRef requires the CrossNamespaceVolumeDataSource feature gate to be enabled. + properties: + apiGroup: + description: |- + APIGroup is the group for the resource being referenced. + If APIGroup is not specified, the specified Kind must be in the core API group. + For any other third-party types, APIGroup is required. + type: string + kind: + description: Kind is the type of resource + being referenced + type: string + name: + description: Name is the name of resource + being referenced + type: string + namespace: + description: |- + Namespace is the namespace of resource being referenced + Note that when a namespace is specified, a gateway.networking.k8s.io/ReferenceGrant object is required in the referent namespace to allow that namespace's owner to accept the reference. See the ReferenceGrant documentation for details. + (Alpha) This field requires the CrossNamespaceVolumeDataSource feature gate to be enabled. + type: string + required: + - kind + - name + type: object + resources: + description: |- + resources represents the minimum resources the volume should have. + If RecoverVolumeExpansionFailure feature is enabled users are allowed to specify resource requirements + that are lower than previous value but must still be higher than capacity recorded in the + status field of the claim. + More info: https://kubernetes.io/docs/concepts/storage/persistent-volumes#resources + properties: + limits: + additionalProperties: + anyOf: + - type: integer + - type: string + pattern: ^(\+|-)?(([0-9]+(\.[0-9]*)?)|(\.[0-9]+))(([KMGTPE]i)|[numkMGTPE]|([eE](\+|-)?(([0-9]+(\.[0-9]*)?)|(\.[0-9]+))))?$ + x-kubernetes-int-or-string: true + description: |- + Limits describes the maximum amount of compute resources allowed. + More info: https://kubernetes.io/docs/concepts/configuration/manage-resources-containers/ + type: object + requests: + additionalProperties: + anyOf: + - type: integer + - type: string + pattern: ^(\+|-)?(([0-9]+(\.[0-9]*)?)|(\.[0-9]+))(([KMGTPE]i)|[numkMGTPE]|([eE](\+|-)?(([0-9]+(\.[0-9]*)?)|(\.[0-9]+))))?$ + x-kubernetes-int-or-string: true + description: |- + Requests describes the minimum amount of compute resources required. + If Requests is omitted for a container, it defaults to Limits if that is explicitly specified, + otherwise to an implementation-defined value. Requests cannot exceed Limits. + More info: https://kubernetes.io/docs/concepts/configuration/manage-resources-containers/ + type: object + type: object + selector: + description: selector is a label query over + volumes to consider for binding. + properties: + matchExpressions: + description: matchExpressions is a list + of label selector requirements. The requirements + are ANDed. + items: + description: |- + A label selector requirement is a selector that contains values, a key, and an operator that + relates the key and values. + properties: + key: + description: key is the label key + that the selector applies to. + type: string + operator: + description: |- + operator represents a key's relationship to a set of values. + Valid operators are In, NotIn, Exists and DoesNotExist. + type: string + values: + description: |- + values is an array of string values. If the operator is In or NotIn, + the values array must be non-empty. If the operator is Exists or DoesNotExist, + the values array must be empty. This array is replaced during a strategic + merge patch. + items: + type: string + type: array + x-kubernetes-list-type: atomic + required: + - key + - operator + type: object + type: array + x-kubernetes-list-type: atomic + matchLabels: + additionalProperties: + type: string + description: |- + matchLabels is a map of {key,value} pairs. A single {key,value} in the matchLabels + map is equivalent to an element of matchExpressions, whose key field is "key", the + operator is "In", and the values array contains only "value". The requirements are ANDed. + type: object + type: object + x-kubernetes-map-type: atomic + storageClassName: + description: |- + storageClassName is the name of the StorageClass required by the claim. + More info: https://kubernetes.io/docs/concepts/storage/persistent-volumes#class-1 + type: string + volumeAttributesClassName: + description: |- + volumeAttributesClassName may be used to set the VolumeAttributesClass used by this claim. + If specified, the CSI driver will create or update the volume with the attributes defined + in the corresponding VolumeAttributesClass. This has a different purpose than storageClassName, + it can be changed after the claim is created. An empty string or nil value indicates that no + VolumeAttributesClass will be applied to the claim. If the claim enters an Infeasible error state, + this field can be reset to its previous value (including nil) to cancel the modification. + If the resource referred to by volumeAttributesClass does not exist, this PersistentVolumeClaim will be + set to a Pending state, as reflected by the modifyVolumeStatus field, until such as a resource + exists. + More info: https://kubernetes.io/docs/concepts/storage/volume-attributes-classes/ + type: string + volumeMode: + description: |- + volumeMode defines what type of volume is required by the claim. + Value of Filesystem is implied when not included in claim spec. + type: string + volumeName: + description: volumeName is the binding reference + to the PersistentVolume backing this claim. + type: string + type: object + source: + description: Source is the src of the data for the + requested DataVolume + properties: + blank: + description: DataVolumeBlankImage provides the + parameters to create a new raw blank image + for the PVC + type: object + gcs: + description: DataVolumeSourceGCS provides the + parameters to create a Data Volume from an + GCS source + properties: + secretRef: + description: SecretRef provides the secret + reference needed to access the GCS source + type: string + url: + description: URL is the url of the GCS source + type: string + required: + - url + type: object + http: + description: DataVolumeSourceHTTP can be either + an http or https endpoint, with an optional + basic auth user name and password, and an + optional configmap containing additional CAs + properties: + certConfigMap: + description: CertConfigMap is a configmap + reference, containing a Certificate Authority(CA) + public key, and a base64 encoded pem certificate + type: string + extraHeaders: + description: ExtraHeaders is a list of strings + containing extra headers to include with + HTTP transfer requests + items: + type: string + type: array + secretExtraHeaders: + description: SecretExtraHeaders is a list + of Secret references, each containing + an extra HTTP header that may include + sensitive information + items: + type: string + type: array + secretRef: + description: SecretRef A Secret reference, + the secret should contain accessKeyId + (user name) base64 encoded, and secretKey + (password) also base64 encoded + type: string + url: + description: URL is the URL of the http(s) + endpoint + type: string + required: + - url + type: object + imageio: + description: DataVolumeSourceImageIO provides + the parameters to create a Data Volume from + an imageio source + properties: + certConfigMap: + description: CertConfigMap provides a reference + to the CA cert + type: string + diskId: + description: DiskID provides id of a disk + to be imported + type: string + insecureSkipVerify: + description: InsecureSkipVerify is a flag + to skip certificate verification + type: boolean + secretRef: + description: SecretRef provides the secret + reference needed to access the ovirt-engine + type: string + url: + description: URL is the URL of the ovirt-engine + type: string + required: + - diskId + - url + type: object + pvc: + description: DataVolumeSourcePVC provides the + parameters to create a Data Volume from an + existing PVC + properties: + name: + description: The name of the source PVC + type: string + namespace: + description: The namespace of the source + PVC + type: string + required: + - name + - namespace + type: object + registry: + description: DataVolumeSourceRegistry provides + the parameters to create a Data Volume from + an registry source + properties: + certConfigMap: + description: CertConfigMap provides a reference + to the Registry certs + type: string + imageStream: + description: ImageStream is the name of + image stream for import + type: string + platform: + description: Platform describes the minimum + runtime requirements of the image + properties: + architecture: + description: Architecture specifies + the image target CPU architecture + type: string + type: object + pullMethod: + description: PullMethod can be either "pod" + (default import), or "node" (node docker + cache based import) + type: string + secretRef: + description: SecretRef provides the secret + reference needed to access the Registry + source + type: string + url: + description: 'URL is the url of the registry + source (starting with the scheme: docker, + oci-archive)' + type: string + type: object + s3: + description: DataVolumeSourceS3 provides the + parameters to create a Data Volume from an + S3 source + properties: + certConfigMap: + description: CertConfigMap is a configmap + reference, containing a Certificate Authority(CA) + public key, and a base64 encoded pem certificate + type: string + secretRef: + description: SecretRef provides the secret + reference needed to access the S3 source + type: string + url: + description: URL is the url of the S3 source + type: string + required: + - url + type: object + snapshot: + description: DataVolumeSourceSnapshot provides + the parameters to create a Data Volume from + an existing VolumeSnapshot + properties: + name: + description: The name of the source VolumeSnapshot + type: string + namespace: + description: The namespace of the source + VolumeSnapshot + type: string + required: + - name + - namespace + type: object + upload: + description: DataVolumeSourceUpload provides + the parameters to create a Data Volume by + uploading the source + type: object + vddk: + description: DataVolumeSourceVDDK provides the + parameters to create a Data Volume from a + Vmware source + properties: + backingFile: + description: BackingFile is the path to + the virtual hard disk to migrate from + vCenter/ESXi + type: string + extraArgs: + description: ExtraArgs is a reference to + a ConfigMap containing extra arguments + to pass directly to the VDDK library + type: string + initImageURL: + description: InitImageURL is an optional + URL to an image containing an extracted + VDDK library, overrides v2v-vmware config + map + type: string + secretRef: + description: SecretRef provides a reference + to a secret containing the username and + password needed to access the vCenter + or ESXi host + type: string + thumbprint: + description: Thumbprint is the certificate + thumbprint of the vCenter or ESXi host + type: string + url: + description: URL is the URL of the vCenter + or ESXi host with the VM to migrate + type: string + uuid: + description: UUID is the UUID of the virtual + machine that the backing file is attached + to in vCenter/ESXi + type: string + type: object + type: object + sourceRef: + description: SourceRef is an indirect reference + to the source of data for the requested DataVolume + properties: + kind: + description: The kind of the source reference, + currently only "DataSource" is supported + type: string + name: + description: The name of the source reference + type: string + namespace: + description: The namespace of the source reference, + defaults to the DataVolume namespace + type: string + required: + - kind + - name + type: object + storage: + description: Storage is the requested storage specification + properties: + accessModes: + description: |- + AccessModes contains the desired access modes the volume should have. + More info: https://kubernetes.io/docs/concepts/storage/persistent-volumes#access-modes-1 + items: + type: string + type: array + dataSource: + description: |- + This field can be used to specify either: * An existing VolumeSnapshot object (snapshot.storage.k8s.io/VolumeSnapshot) * An existing PVC (PersistentVolumeClaim) * An existing custom resource that implements data population (Alpha) In order to use custom resource types that implement data population, the AnyVolumeDataSource feature gate must be enabled. If the provisioner or an external controller can support the specified data source, it will create a new volume based on the contents of the specified data source. + If the AnyVolumeDataSource feature gate is enabled, this field will always have the same contents as the DataSourceRef field. + properties: + apiGroup: + description: |- + APIGroup is the group for the resource being referenced. + If APIGroup is not specified, the specified Kind must be in the core API group. + For any other third-party types, APIGroup is required. + type: string + kind: + description: Kind is the type of resource + being referenced + type: string + name: + description: Name is the name of resource + being referenced + type: string + required: + - kind + - name + type: object + x-kubernetes-map-type: atomic + dataSourceRef: + description: |- + Specifies the object from which to populate the volume with data, if a non-empty volume is desired. This may be any local object from a non-empty API group (non core object) or a PersistentVolumeClaim object. When this field is specified, volume binding will only succeed if the type of the specified object matches some installed volume populator or dynamic provisioner. + This field will replace the functionality of the DataSource field and as such if both fields are non-empty, they must have the same value. For backwards compatibility, both fields (DataSource and DataSourceRef) will be set to the same value automatically if one of them is empty and the other is non-empty. + There are two important differences between DataSource and DataSourceRef: + * While DataSource only allows two specific types of objects, DataSourceRef allows any non-core object, as well as PersistentVolumeClaim objects. + * While DataSource ignores disallowed values (dropping them), DataSourceRef preserves all values, and generates an error if a disallowed value is specified. + (Beta) Using this field requires the AnyVolumeDataSource feature gate to be enabled. + properties: + apiGroup: + description: |- + APIGroup is the group for the resource being referenced. + If APIGroup is not specified, the specified Kind must be in the core API group. + For any other third-party types, APIGroup is required. + type: string + kind: + description: Kind is the type of resource + being referenced + type: string + name: + description: Name is the name of resource + being referenced + type: string + namespace: + description: |- + Namespace is the namespace of resource being referenced + Note that when a namespace is specified, a gateway.networking.k8s.io/ReferenceGrant object is required in the referent namespace to allow that namespace's owner to accept the reference. See the ReferenceGrant documentation for details. + (Alpha) This field requires the CrossNamespaceVolumeDataSource feature gate to be enabled. + type: string + required: + - kind + - name + type: object + resources: + description: |- + Resources represents the minimum resources the volume should have. + More info: https://kubernetes.io/docs/concepts/storage/persistent-volumes#resources + properties: + limits: + additionalProperties: + anyOf: + - type: integer + - type: string + pattern: ^(\+|-)?(([0-9]+(\.[0-9]*)?)|(\.[0-9]+))(([KMGTPE]i)|[numkMGTPE]|([eE](\+|-)?(([0-9]+(\.[0-9]*)?)|(\.[0-9]+))))?$ + x-kubernetes-int-or-string: true + description: |- + Limits describes the maximum amount of compute resources allowed. + More info: https://kubernetes.io/docs/concepts/configuration/manage-resources-containers/ + type: object + requests: + additionalProperties: + anyOf: + - type: integer + - type: string + pattern: ^(\+|-)?(([0-9]+(\.[0-9]*)?)|(\.[0-9]+))(([KMGTPE]i)|[numkMGTPE]|([eE](\+|-)?(([0-9]+(\.[0-9]*)?)|(\.[0-9]+))))?$ + x-kubernetes-int-or-string: true + description: |- + Requests describes the minimum amount of compute resources required. + If Requests is omitted for a container, it defaults to Limits if that is explicitly specified, + otherwise to an implementation-defined value. Requests cannot exceed Limits. + More info: https://kubernetes.io/docs/concepts/configuration/manage-resources-containers/ + type: object + type: object + selector: + description: A label query over volumes to consider + for binding. + properties: + matchExpressions: + description: matchExpressions is a list + of label selector requirements. The requirements + are ANDed. + items: + description: |- + A label selector requirement is a selector that contains values, a key, and an operator that + relates the key and values. + properties: + key: + description: key is the label key + that the selector applies to. + type: string + operator: + description: |- + operator represents a key's relationship to a set of values. + Valid operators are In, NotIn, Exists and DoesNotExist. + type: string + values: + description: |- + values is an array of string values. If the operator is In or NotIn, + the values array must be non-empty. If the operator is Exists or DoesNotExist, + the values array must be empty. This array is replaced during a strategic + merge patch. + items: + type: string + type: array + x-kubernetes-list-type: atomic + required: + - key + - operator + type: object + type: array + x-kubernetes-list-type: atomic + matchLabels: + additionalProperties: + type: string + description: |- + matchLabels is a map of {key,value} pairs. A single {key,value} in the matchLabels + map is equivalent to an element of matchExpressions, whose key field is "key", the + operator is "In", and the values array contains only "value". The requirements are ANDed. + type: object + type: object + x-kubernetes-map-type: atomic + storageClassName: + description: |- + Name of the StorageClass required by the claim. + More info: https://kubernetes.io/docs/concepts/storage/persistent-volumes#class-1 + type: string + volumeMode: + description: |- + volumeMode defines what type of volume is required by the claim. + Value of Filesystem is implied when not included in claim spec. + type: string + volumeName: + description: VolumeName is the binding reference + to the PersistentVolume backing this claim. + type: string + type: object + type: object + status: + description: DataVolumeStatus contains the current status + of the DataVolume + properties: + claimName: + description: ClaimName is the name of the underlying + PVC used by the DataVolume. + type: string + conditions: + items: + description: DataVolumeCondition represents the + state of a data volume condition. + properties: + lastHeartbeatTime: + format: date-time + type: string + lastTransitionTime: + format: date-time + type: string + message: + type: string + reason: + type: string + status: + type: string + type: + description: DataVolumeConditionType is the + string representation of known condition + types + type: string + required: + - status + - type + type: object + type: array + phase: + description: Phase is the current phase of the data + volume + type: string + progress: + description: DataVolumeProgress is the current progress + of the DataVolume transfer operation. Value between + 0 and 100 inclusive, N/A if not available + type: string + restartCount: + description: RestartCount is the number of times + the pod populating the DataVolume has restarted + format: int32 + type: integer + type: object + required: + - spec + type: object + required: + - managedDataSource + - schedule + - template + type: object + status: + description: DataImportCronStatus is the status field of the + DIC template + properties: + commonTemplate: + description: CommonTemplate indicates whether this is a + common template (true), or a custom one (false) + type: boolean + conditions: + description: Conditions is a list of conditions that describe + the state of the DataImportCronTemplate. + items: + description: Condition contains details for one aspect + of the current state of this API Resource. + properties: + lastTransitionTime: + description: |- + lastTransitionTime is the last time the condition transitioned from one status to another. + This should be when the underlying condition changed. If that is not known, then using the time when the API field changed is acceptable. + format: date-time + type: string + message: + description: |- + message is a human readable message indicating details about the transition. + This may be an empty string. + maxLength: 32768 + type: string + observedGeneration: + description: |- + observedGeneration represents the .metadata.generation that the condition was set based upon. + For instance, if .metadata.generation is currently 12, but the .status.conditions[x].observedGeneration is 9, the condition is out of date + with respect to the current state of the instance. + format: int64 + minimum: 0 + type: integer + reason: + description: |- + reason contains a programmatic identifier indicating the reason for the condition's last transition. + Producers of specific condition types may define expected values and meanings for this field, + and whether the values are considered a guaranteed API. + The value should be a CamelCase string. + This field may not be empty. + maxLength: 1024 + minLength: 1 + pattern: ^[A-Za-z]([A-Za-z0-9_,:]*[A-Za-z0-9_])?$ + type: string + status: + description: status of the condition, one of True, + False, Unknown. + enum: + - "True" + - "False" + - Unknown + type: string + type: + description: type of condition in CamelCase or in + foo.example.com/CamelCase. + maxLength: 316 + pattern: ^([a-z0-9]([-a-z0-9]*[a-z0-9])?(\.[a-z0-9]([-a-z0-9]*[a-z0-9])?)*/)?(([A-Za-z0-9][-A-Za-z0-9_.]*)?[A-Za-z0-9])$ + type: string + required: + - lastTransitionTime + - message + - reason + - status + - type + type: object + type: array + modified: + description: Modified indicates if a common template was + customized. Always false for custom templates. + type: boolean + originalSupportedArchitectures: + description: |- + OriginalSupportedArchitectures is a comma-separated list of CPU architectures that the original + template supports. + type: string + type: object + type: object + type: array + dataImportSchedule: + description: |- + DataImportSchedule is the cron expression that is used in for the hard-coded data import cron templates. HCO + generates the value of this field once and stored in the status field, so will survive restart. + type: string + infrastructureHighlyAvailable: + description: |- + InfrastructureHighlyAvailable describes whether the cluster has only one worker node + (false) or more (true). + type: boolean + nodeInfo: + description: NodeInfo holds information about the cluster nodes + properties: + controlPlaneArchitectures: + description: ControlPlaneArchitectures is a distinct list of the + CPU architecture of the control-plane nodes. + items: + type: string + type: array + workloadsArchitectures: + description: WorkloadsArchitectures is a distinct list of the + CPU architectures of the workloads nodes in the cluster. + items: + type: string + type: array + type: object + observedGeneration: + description: |- + ObservedGeneration reflects the HyperConverged resource generation. If the ObservedGeneration is less than the + resource generation in metadata, the status is out of date + format: int64 + type: integer + relatedObjects: + description: |- + RelatedObjects is a list of objects created and maintained by this + operator. Object references will be added to this list after they have + been created AND found in the cluster. + items: + description: ObjectReference contains enough information to let + you inspect or modify the referred object. + properties: + apiVersion: + description: API version of the referent. + type: string + fieldPath: + description: |- + If referring to a piece of an object instead of an entire object, this string + should contain a valid JSON/Go field access statement, such as desiredState.manifest.containers[2]. + For example, if the object reference is to a container within a pod, this would take on a value like: + "spec.containers{name}" (where "name" refers to the name of the container that triggered + the event) or if no container name is specified "spec.containers[2]" (container with + index 2 in this pod). This syntax is chosen only to have some well-defined way of + referencing a part of an object. + type: string + kind: + description: |- + Kind of the referent. + More info: https://git.k8s.io/community/contributors/devel/sig-architecture/api-conventions.md#types-kinds + type: string + name: + description: |- + Name of the referent. + More info: https://kubernetes.io/docs/concepts/overview/working-with-objects/names/#names + type: string + namespace: + description: |- + Namespace of the referent. + More info: https://kubernetes.io/docs/concepts/overview/working-with-objects/namespaces/ + type: string + resourceVersion: + description: |- + Specific resourceVersion to which this reference is made, if any. + More info: https://git.k8s.io/community/contributors/devel/sig-architecture/api-conventions.md#concurrency-control-and-consistency + type: string + uid: + description: |- + UID of the referent. + More info: https://kubernetes.io/docs/concepts/overview/working-with-objects/names/#uids + type: string + type: object + x-kubernetes-map-type: atomic + type: array + x-kubernetes-list-type: atomic + systemHealthStatus: + description: SystemHealthStatus reflects the health of HCO and its + secondary resources, based on the aggregated conditions. + type: string + versions: + description: |- + Versions is a list of HCO component versions, as name/version pairs. The version with a name of "operator" + is the HCO version itself, as described here: + https://github.com/openshift/cluster-version-operator/blob/master/docs/dev/clusteroperator.md#version + items: + properties: + name: + type: string + version: + type: string + type: object + type: array + x-kubernetes-list-type: atomic + type: object + type: object + served: true + storage: false + subresources: + status: {} - additionalPrinterColumns: - jsonPath: .metadata.creationTimestamp name: Age diff --git a/deploy/olm-catalog/community-kubevirt-hyperconverged/1.18.0/manifests/kubevirt-hyperconverged-operator.v1.18.0.clusterserviceversion.yaml b/deploy/olm-catalog/community-kubevirt-hyperconverged/1.18.0/manifests/kubevirt-hyperconverged-operator.v1.18.0.clusterserviceversion.yaml index 58cc478fc8..5633b20c08 100644 --- a/deploy/olm-catalog/community-kubevirt-hyperconverged/1.18.0/manifests/kubevirt-hyperconverged-operator.v1.18.0.clusterserviceversion.yaml +++ b/deploy/olm-catalog/community-kubevirt-hyperconverged/1.18.0/manifests/kubevirt-hyperconverged-operator.v1.18.0.clusterserviceversion.yaml @@ -9,7 +9,7 @@ metadata: certified: "false" console.openshift.io/disable-operand-delete: "true" containerImage: quay.io/kubevirt/hyperconverged-cluster-operator:1.18.0-unstable - createdAt: "2026-02-02 13:05:11" + createdAt: "2026-02-04 07:33:22" description: A unified operator deploying and controlling KubeVirt and its supporting operators with opinionated defaults features.operators.openshift.io/cnf: "false" @@ -407,6 +407,8 @@ spec: verbs: - get - list + - update + - patch - watch - delete - apiGroups: @@ -5542,6 +5544,30 @@ spec: deploymentName: hco-webhook failurePolicy: Fail generateName: validate-hco.kubevirt.io + matchPolicy: Exact + rules: + - apiGroups: + - hco.kubevirt.io + apiVersions: + - v1 + operations: + - CREATE + - DELETE + - UPDATE + resources: + - hyperconvergeds + sideEffects: None + timeoutSeconds: 10 + type: ValidatingAdmissionWebhook + webhookPath: /validate-hco-kubevirt-io-v1-hyperconverged + - admissionReviewVersions: + - v1beta1 + - v1 + containerPort: 4343 + deploymentName: hco-webhook + failurePolicy: Fail + generateName: validate-hco-v1beta1.kubevirt.io + matchPolicy: Exact rules: - apiGroups: - hco.kubevirt.io @@ -5587,6 +5613,29 @@ spec: deploymentName: hco-webhook failurePolicy: Fail generateName: mutate-hyperconverged-hco.kubevirt.io + matchPolicy: Exact + rules: + - apiGroups: + - hco.kubevirt.io + apiVersions: + - v1 + operations: + - CREATE + - UPDATE + resources: + - hyperconvergeds + sideEffects: NoneOnDryRun + timeoutSeconds: 10 + type: MutatingAdmissionWebhook + webhookPath: /mutate-hco-kubevirt-io-v1-hyperconverged + - admissionReviewVersions: + - v1beta1 + - v1 + containerPort: 4343 + deploymentName: hco-webhook + failurePolicy: Fail + generateName: mutate-hyperconverged-hco-v1beta1.kubevirt.io + matchPolicy: Exact rules: - apiGroups: - hco.kubevirt.io diff --git a/deploy/webhooks.yaml b/deploy/webhooks.yaml index 1727e8c457..ddce32c686 100644 --- a/deploy/webhooks.yaml +++ b/deploy/webhooks.yaml @@ -48,17 +48,44 @@ webhooks: service: name: hyperconverged-cluster-webhook-service namespace: kubevirt-hyperconverged - path: /validate-hco-kubevirt-io-v1beta1-hyperconverged + path: /validate-hco-kubevirt-io-v1-hyperconverged port: 4343 failurePolicy: Fail - matchPolicy: Equivalent + matchPolicy: Exact name: validate-hco.kubevirt.io objectSelector: {} rules: - apiGroups: - hco.kubevirt.io apiVersions: - - v1alpha1 + - v1 + operations: + - CREATE + - DELETE + - UPDATE + resources: + - hyperconvergeds + scope: '*' + sideEffects: None + timeoutSeconds: 30 +- admissionReviewVersions: + - v1beta1 + - v1 + clientConfig: + # caBundle: WILL BE INJECTED BY CERT-MANAGER BECAUSE OF THE ANNOTATION + service: + name: hyperconverged-cluster-webhook-service + namespace: kubevirt-hyperconverged + path: /validate-hco-kubevirt-io-v1beta1-hyperconverged + port: 4343 + failurePolicy: Fail + matchPolicy: Exact + name: validate-hco-v1beta1.kubevirt.io + objectSelector: {} + rules: + - apiGroups: + - hco.kubevirt.io + apiVersions: - v1beta1 operations: - CREATE @@ -104,15 +131,40 @@ webhooks: service: name: hyperconverged-cluster-webhook-service namespace: kubevirt-hyperconverged - path: /mutate-hco-kubevirt-io-v1beta1-hyperconverged + path: /mutate-hco-kubevirt-io-v1-hyperconverged port: 4343 failurePolicy: Fail + matchPolicy: Exact name: mutate-hyperconverged-hco.kubevirt.io rules: - apiGroups: - hco.kubevirt.io apiVersions: - - v1alpha1 + - v1 + operations: + - CREATE + - UPDATE + resources: + - hyperconvergeds + sideEffects: NoneOnDryRun + timeoutSeconds: 10 +- admissionReviewVersions: + - v1beta1 + - v1 + clientConfig: + # caBundle: WILL BE INJECTED BY CERT-MANAGER BECAUSE OF THE ANNOTATION + service: + name: hyperconverged-cluster-webhook-service + namespace: kubevirt-hyperconverged + path: /mutate-hco-kubevirt-io-v1beta1-hyperconverged + port: 4343 + failurePolicy: Fail + matchPolicy: Exact + name: mutate-hyperconverged-hco-v1beta1.kubevirt.io + rules: + - apiGroups: + - hco.kubevirt.io + apiVersions: - v1beta1 operations: - CREATE diff --git a/hack/deploy.sh b/hack/deploy.sh index b10be3c1f8..275f5ad373 100755 --- a/hack/deploy.sh +++ b/hack/deploy.sh @@ -120,7 +120,7 @@ hack/deploy-cert-manager.sh "${CMD}" apply $LABEL_SELECTOR_ARG -f _out/cluster_role.yaml "${CMD}" apply $LABEL_SELECTOR_ARG -f _out/service_account.yaml "${CMD}" apply $LABEL_SELECTOR_ARG -f _out/cluster_role_binding.yaml -"${CMD}" apply $LABEL_SELECTOR_ARG -f _out/crds/ +"${CMD}" apply $LABEL_SELECTOR_ARG --server-side -f _out/crds/ sleep 20 if [[ "$(${CMD} get crd ${HCO_CRD_NAME} -o=jsonpath='{.status.conditions[?(@.type=="NonStructuralSchema")].status}')" == "True" ]]; diff --git a/hack/generate.sh b/hack/generate.sh index 77cbc58719..3759d279ce 100755 --- a/hack/generate.sh +++ b/hack/generate.sh @@ -7,32 +7,52 @@ PROJECT_ROOT="$(readlink -e "$(dirname "${BASH_SOURCE[0]}")"/../)" PACKAGE=github.com/kubevirt/hyperconverged-cluster-operator API_FOLDER=api -API_VERSION=v1beta1 +API_VERSIONS=(v1 v1beta1) go install \ k8s.io/code-generator/cmd/deepcopy-gen@${K8S_VER} \ - k8s.io/code-generator/cmd/defaulter-gen@${K8S_VER} + k8s.io/code-generator/cmd/defaulter-gen@${K8S_VER} \ + k8s.io/code-generator/cmd/conversion-gen@${K8S_VER} go install \ k8s.io/kube-openapi/cmd/openapi-gen@${KUBEOPENAPI_VER} deepcopy-gen \ - --output-file zz_generated.deepcopy.go \ - --go-header-file "${PROJECT_ROOT}/hack/boilerplate.go.txt" \ - "${PACKAGE}/${API_FOLDER}/${API_VERSION}" - -defaulter-gen \ - --output-file zz_generated.defaults.go \ - --go-header-file "${PROJECT_ROOT}/hack/boilerplate.go.txt" \ - "${PACKAGE}/${API_FOLDER}/${API_VERSION}" + --output-file zz_generated.deepcopy.go \ + --go-header-file "${PROJECT_ROOT}/hack/boilerplate.go.txt" \ + "${PACKAGE}/${API_FOLDER}/v1/featuregates" openapi-gen \ - --output-file zz_generated.openapi.go \ - --go-header-file "${PROJECT_ROOT}/hack/boilerplate.go.txt" \ - --output-dir api/v1beta1/ \ - --output-pkg github.com/kubevirt/hyperconverged-cluster-operator/api/v1beta1 \ - "${PACKAGE}/${API_FOLDER}/${API_VERSION}" - -go fmt api/v1beta1/zz_generated.deepcopy.go -go fmt api/v1beta1/zz_generated.defaults.go -go fmt api/v1beta1/zz_generated.openapi.go + --output-file zz_generated.openapi.go \ + --go-header-file "${PROJECT_ROOT}/hack/boilerplate.go.txt" \ + --output-dir ${API_FOLDER}/v1/featuregates/ \ + --output-pkg github.com/kubevirt/hyperconverged-cluster-operator/api/v1/featuregates \ + "${PACKAGE}/${API_FOLDER}/v1/featuregates" + +for API_VERSION in ${API_VERSIONS[@]}; do + deepcopy-gen \ + --output-file zz_generated.deepcopy.go \ + --go-header-file "${PROJECT_ROOT}/hack/boilerplate.go.txt" \ + "${PACKAGE}/${API_FOLDER}/${API_VERSION}" + + defaulter-gen \ + --output-file zz_generated.defaults.go \ + --go-header-file "${PROJECT_ROOT}/hack/boilerplate.go.txt" \ + "${PACKAGE}/${API_FOLDER}/${API_VERSION}" + + openapi-gen \ + --output-file zz_generated.openapi.go \ + --go-header-file "${PROJECT_ROOT}/hack/boilerplate.go.txt" \ + --output-dir ${API_FOLDER}/${API_VERSION}/ \ + --output-pkg github.com/kubevirt/hyperconverged-cluster-operator/api/${API_VERSION} \ + "${PACKAGE}/${API_FOLDER}/${API_VERSION}" + + go fmt ${API_FOLDER}/${API_VERSION}/zz_generated.deepcopy.go + go fmt ${API_FOLDER}/${API_VERSION}/zz_generated.defaults.go + go fmt ${API_FOLDER}/${API_VERSION}/zz_generated.openapi.go +done + +# generate auto conversion file +conversion-gen --output-file=zz_generated.conversion.go \ + --go-header-file=./hack/boilerplate.go.txt \ + ./api/v1beta1 diff --git a/pkg/components/components.go b/pkg/components/components.go index 02211a6e7d..0c58abf03d 100644 --- a/pkg/components/components.go +++ b/pkg/components/components.go @@ -580,7 +580,7 @@ func GetClusterPermissions() []rbacv1.PolicyRule { { APIGroups: stringListToSlice("apiextensions.k8s.io"), Resources: stringListToSlice("customresourcedefinitions"), - Verbs: stringListToSlice("get", "list", "watch", "delete"), + Verbs: stringListToSlice("get", "list", "update", "patch", "watch", "delete"), }, { APIGroups: stringListToSlice("apiextensions.k8s.io"), @@ -756,7 +756,7 @@ func GetOperatorCR() *hcov1beta1.HyperConverged { _ = hcov1beta1.RegisterDefaults(defaultScheme) defaultHco := &hcov1beta1.HyperConverged{ TypeMeta: metav1.TypeMeta{ - APIVersion: util.APIVersion, + APIVersion: hcov1beta1.APIVersion, Kind: util.HyperConvergedKind, }, ObjectMeta: metav1.ObjectMeta{ @@ -817,7 +817,7 @@ type CSVBaseParams struct { func GetCSVBase(params *CSVBaseParams) *csvv1alpha1.ClusterServiceVersion { almExamples, _ := json.Marshal( map[string]interface{}{ - "apiVersion": util.APIVersion, + "apiVersion": hcov1beta1.APIVersion, "kind": util.HyperConvergedKind, "metadata": map[string]interface{}{ "name": packageName, @@ -836,83 +836,11 @@ func GetCSVBase(params *CSVBaseParams) *csvv1alpha1.ClusterServiceVersion { // ValidatingWebhookConfiguration object first (eventually bypassing the OLM if needed). // so failurePolicy = admissionregistrationv1.Fail - validatingWebhook := csvv1alpha1.WebhookDescription{ - GenerateName: util.HcoValidatingWebhook, - Type: csvv1alpha1.ValidatingAdmissionWebhook, - DeploymentName: hcoWhDeploymentName, - ContainerPort: util.WebhookPort, - AdmissionReviewVersions: stringListToSlice("v1beta1", "v1"), - SideEffects: ptr.To(admissionregistrationv1.SideEffectClassNone), - FailurePolicy: ptr.To(admissionregistrationv1.Fail), - TimeoutSeconds: ptr.To[int32](10), - Rules: []admissionregistrationv1.RuleWithOperations{ - { - Operations: []admissionregistrationv1.OperationType{ - admissionregistrationv1.Create, - admissionregistrationv1.Delete, - admissionregistrationv1.Update, - }, - Rule: admissionregistrationv1.Rule{ - APIGroups: stringListToSlice(util.APIVersionGroup), - APIVersions: stringListToSlice(util.APIVersionBeta), - Resources: stringListToSlice("hyperconvergeds"), - }, - }, - }, - WebhookPath: ptr.To(util.HCOWebhookPath), - } - - mutatingNamespaceWebhook := csvv1alpha1.WebhookDescription{ - GenerateName: util.HcoMutatingWebhookNS, - Type: csvv1alpha1.MutatingAdmissionWebhook, - DeploymentName: hcoWhDeploymentName, - ContainerPort: util.WebhookPort, - AdmissionReviewVersions: stringListToSlice("v1beta1", "v1"), - SideEffects: ptr.To(admissionregistrationv1.SideEffectClassNoneOnDryRun), - FailurePolicy: ptr.To(admissionregistrationv1.Fail), - TimeoutSeconds: ptr.To[int32](10), - ObjectSelector: &metav1.LabelSelector{ - MatchLabels: map[string]string{util.KubernetesMetadataName: params.Namespace}, - }, - Rules: []admissionregistrationv1.RuleWithOperations{ - { - Operations: []admissionregistrationv1.OperationType{ - admissionregistrationv1.Delete, - }, - Rule: admissionregistrationv1.Rule{ - APIGroups: []string{""}, - APIVersions: stringListToSlice("v1"), - Resources: stringListToSlice("namespaces"), - }, - }, - }, - WebhookPath: ptr.To(util.HCONSWebhookPath), - } - - mutatingHyperConvergedWebhook := csvv1alpha1.WebhookDescription{ - GenerateName: util.HcoMutatingWebhookHyperConverged, - Type: csvv1alpha1.MutatingAdmissionWebhook, - DeploymentName: hcoWhDeploymentName, - ContainerPort: util.WebhookPort, - AdmissionReviewVersions: stringListToSlice("v1beta1", "v1"), - SideEffects: ptr.To(admissionregistrationv1.SideEffectClassNoneOnDryRun), - FailurePolicy: ptr.To(admissionregistrationv1.Fail), - TimeoutSeconds: ptr.To[int32](10), - Rules: []admissionregistrationv1.RuleWithOperations{ - { - Operations: []admissionregistrationv1.OperationType{ - admissionregistrationv1.Create, - admissionregistrationv1.Update, - }, - Rule: admissionregistrationv1.Rule{ - APIGroups: stringListToSlice(util.APIVersionGroup), - APIVersions: stringListToSlice(util.APIVersionBeta), - Resources: stringListToSlice("hyperconvergeds"), - }, - }, - }, - WebhookPath: ptr.To(util.HCOMutatingWebhookPath), - } + validatingWebhook := createHCValidatingWebhook(util.HcoValidatingWebhook, util.APIVersionV1, util.HCOWebhookPath) + v1Beta1ValidatingWebhook := createHCValidatingWebhook(util.HcoV1Beta1ValidatingWebhook, util.APIVersionBeta, util.HCOWebhookV1Beta1Path) + mutatingNamespaceWebhook := createMutatingNSWebhook(params) + mutatingHyperConvergedWebhook := createMutatingHCWebhook(util.HcoMutatingWebhookHyperConverged, util.APIVersionV1, util.HCOMutatingWebhookPath) + v1Beta1MutatingHyperConvergedWebhook := createMutatingHCWebhook(util.HcoV1Beta1MutatingWebhookHyperConverged, util.APIVersionBeta, util.HCOV1Beta1MutatingWebhookPath) return &csvv1alpha1.ClusterServiceVersion{ TypeMeta: metav1.TypeMeta{ @@ -1015,8 +943,10 @@ func GetCSVBase(params *CSVBaseParams) *csvv1alpha1.ClusterServiceVersion { InstallStrategy: csvv1alpha1.NamedInstallStrategy{}, WebhookDefinitions: []csvv1alpha1.WebhookDescription{ validatingWebhook, + v1Beta1ValidatingWebhook, mutatingNamespaceWebhook, mutatingHyperConvergedWebhook, + v1Beta1MutatingHyperConvergedWebhook, }, CustomResourceDefinitions: csvv1alpha1.CustomResourceDefinitions{ Owned: []csvv1alpha1.CRDDescription{ @@ -1095,6 +1025,92 @@ func GetCSVBase(params *CSVBaseParams) *csvv1alpha1.ClusterServiceVersion { } } +func createMutatingHCWebhook(name, apiVersion, path string) csvv1alpha1.WebhookDescription { + return csvv1alpha1.WebhookDescription{ + GenerateName: name, + Type: csvv1alpha1.MutatingAdmissionWebhook, + DeploymentName: hcoWhDeploymentName, + ContainerPort: util.WebhookPort, + AdmissionReviewVersions: stringListToSlice("v1beta1", "v1"), + SideEffects: ptr.To(admissionregistrationv1.SideEffectClassNoneOnDryRun), + FailurePolicy: ptr.To(admissionregistrationv1.Fail), + MatchPolicy: ptr.To(admissionregistrationv1.Exact), + TimeoutSeconds: ptr.To[int32](10), + Rules: []admissionregistrationv1.RuleWithOperations{ + { + Operations: []admissionregistrationv1.OperationType{ + admissionregistrationv1.Create, + admissionregistrationv1.Update, + }, + Rule: admissionregistrationv1.Rule{ + APIGroups: stringListToSlice(util.APIVersionGroup), + APIVersions: stringListToSlice(apiVersion), + Resources: stringListToSlice("hyperconvergeds"), + }, + }, + }, + WebhookPath: &path, + } +} + +func createMutatingNSWebhook(params *CSVBaseParams) csvv1alpha1.WebhookDescription { + return csvv1alpha1.WebhookDescription{ + GenerateName: util.HcoMutatingWebhookNS, + Type: csvv1alpha1.MutatingAdmissionWebhook, + DeploymentName: hcoWhDeploymentName, + ContainerPort: util.WebhookPort, + AdmissionReviewVersions: stringListToSlice("v1beta1", "v1"), + SideEffects: ptr.To(admissionregistrationv1.SideEffectClassNoneOnDryRun), + FailurePolicy: ptr.To(admissionregistrationv1.Fail), + TimeoutSeconds: ptr.To[int32](10), + ObjectSelector: &metav1.LabelSelector{ + MatchLabels: map[string]string{util.KubernetesMetadataName: params.Namespace}, + }, + Rules: []admissionregistrationv1.RuleWithOperations{ + { + Operations: []admissionregistrationv1.OperationType{ + admissionregistrationv1.Delete, + }, + Rule: admissionregistrationv1.Rule{ + APIGroups: []string{""}, + APIVersions: stringListToSlice("v1"), + Resources: stringListToSlice("namespaces"), + }, + }, + }, + WebhookPath: ptr.To(util.HCONSWebhookPath), + } +} + +func createHCValidatingWebhook(name, apiVersion, path string) csvv1alpha1.WebhookDescription { + return csvv1alpha1.WebhookDescription{ + GenerateName: name, + Type: csvv1alpha1.ValidatingAdmissionWebhook, + DeploymentName: hcoWhDeploymentName, + ContainerPort: util.WebhookPort, + AdmissionReviewVersions: stringListToSlice("v1beta1", "v1"), + SideEffects: ptr.To(admissionregistrationv1.SideEffectClassNone), + FailurePolicy: ptr.To(admissionregistrationv1.Fail), + MatchPolicy: ptr.To(admissionregistrationv1.Exact), + TimeoutSeconds: ptr.To[int32](10), + Rules: []admissionregistrationv1.RuleWithOperations{ + { + Operations: []admissionregistrationv1.OperationType{ + admissionregistrationv1.Create, + admissionregistrationv1.Delete, + admissionregistrationv1.Update, + }, + Rule: admissionregistrationv1.Rule{ + APIGroups: stringListToSlice(util.APIVersionGroup), + APIVersions: stringListToSlice(apiVersion), + Resources: stringListToSlice("hyperconvergeds"), + }, + }, + }, + WebhookPath: ptr.To(path), + } +} + func InjectVolumesForWebHookCerts(deploy *appsv1.Deployment) { // check if there is already a volume for api certificates for _, vol := range deploy.Spec.Template.Spec.Volumes { diff --git a/pkg/util/consts.go b/pkg/util/consts.go index 2d66b2e75d..9a24a0293f 100644 --- a/pkg/util/consts.go +++ b/pkg/util/consts.go @@ -1,6 +1,9 @@ package util -import "github.com/kubevirt/hyperconverged-cluster-operator/api/v1beta1" +import ( + hcov1 "github.com/kubevirt/hyperconverged-cluster-operator/api/v1" + hcov1beta1 "github.com/kubevirt/hyperconverged-cluster-operator/api/v1beta1" +) // pod names const ( @@ -11,50 +14,80 @@ const ( // HCO common constants const ( - OperatorNamespaceEnv = "OPERATOR_NAMESPACE" - OperatorWebhookModeEnv = "WEBHOOK_MODE" - ContainerAppName = "APP" - ContainerOperatorApp = "OPERATOR" - ContainerWebhookApp = "WEBHOOK" - HcoKvIoVersionName = "HCO_KV_IO_VERSION" - KubevirtVersionEnvV = "KUBEVIRT_VERSION" - KvVirtLauncherOSVersionEnvV = "VIRT_LAUNCHER_OS_VERSION" - CdiVersionEnvV = "CDI_VERSION" - CnaoVersionEnvV = "NETWORK_ADDONS_VERSION" - SspVersionEnvV = "SSP_VERSION" - HppoVersionEnvV = "HPPO_VERSION" - AaqVersionEnvV = "AAQ_VERSION" - MigrationOperatorVersionEnvV = "MIGRATION_OPERATOR_VERSION" - KVUIPluginImageEnvV = "KV_CONSOLE_PLUGIN_IMAGE" - KVUIProxyImageEnvV = "KV_CONSOLE_PROXY_IMAGE" - PasstImageEnvV = "PASST_SIDECAR_IMAGE" - PasstCNIImageEnvV = "PASST_CNI_IMAGE" - WaspAgentImageEnvV = "WASP_AGENT_IMAGE" - DeployNetworkPoliciesEnvV = "DEPLOY_NETWORK_POLICIES" - HcoValidatingWebhook = "validate-hco.kubevirt.io" - HcoMutatingWebhookNS = "mutate-ns-hco.kubevirt.io" + OperatorNamespaceEnv = "OPERATOR_NAMESPACE" + OperatorWebhookModeEnv = "WEBHOOK_MODE" + ContainerAppName = "APP" + ContainerOperatorApp = "OPERATOR" + ContainerWebhookApp = "WEBHOOK" + HcoKvIoVersionName = "HCO_KV_IO_VERSION" + KubevirtVersionEnvV = "KUBEVIRT_VERSION" + KvVirtLauncherOSVersionEnvV = "VIRT_LAUNCHER_OS_VERSION" + CdiVersionEnvV = "CDI_VERSION" + CnaoVersionEnvV = "NETWORK_ADDONS_VERSION" + SspVersionEnvV = "SSP_VERSION" + HppoVersionEnvV = "HPPO_VERSION" + AaqVersionEnvV = "AAQ_VERSION" + MigrationOperatorVersionEnvV = "MIGRATION_OPERATOR_VERSION" + KVUIPluginImageEnvV = "KV_CONSOLE_PLUGIN_IMAGE" + KVUIProxyImageEnvV = "KV_CONSOLE_PROXY_IMAGE" + PasstImageEnvV = "PASST_SIDECAR_IMAGE" + PasstCNIImageEnvV = "PASST_CNI_IMAGE" + WaspAgentImageEnvV = "WASP_AGENT_IMAGE" + DeployNetworkPoliciesEnvV = "DEPLOY_NETWORK_POLICIES" +) + +const ( + HcoValidatingWebhook = "validate-hco.kubevirt.io" + HcoV1Beta1ValidatingWebhook = "validate-hco-v1beta1.kubevirt.io" + HcoMutatingWebhookNS = "mutate-ns-hco.kubevirt.io" + HcoMutatingWebhookHyperConverged = "mutate-hyperconverged-hco.kubevirt.io" + HcoV1Beta1MutatingWebhookHyperConverged = "mutate-hyperconverged-hco-v1beta1.kubevirt.io" + + HCOWebhookPath = "/validate-hco-kubevirt-io-v1-hyperconverged" + HCOWebhookV1Beta1Path = "/validate-hco-kubevirt-io-v1beta1-hyperconverged" + HCOMutatingWebhookPath = "/mutate-hco-kubevirt-io-v1-hyperconverged" + HCOV1Beta1MutatingWebhookPath = "/mutate-hco-kubevirt-io-v1beta1-hyperconverged" + HCONSWebhookPath = "/mutate-ns-hco-kubevirt-io" + HCOConversionWebhookPath = "/convert" + + WebhookPort = 4343 + WebhookPortName = "webhook" + + WebhookCertName = "apiserver.crt" + WebhookKeyName = "apiserver.key" + DefaultWebhookCertDir = "/apiserver.local.config/certificates" +) + +const ( + HyperConvergedCRDName = "hyperconvergeds.hco.kubevirt.io" PrometheusRuleCRDName = "prometheusrules.monitoring.coreos.com" ServiceMonitorCRDName = "servicemonitors.monitoring.coreos.com" DeschedulerCRDName = "kubedeschedulers.operator.openshift.io" PersesDashboardsCRDName = "persesdashboards.perses.dev" PersesDatasourcesCRDName = "persesdatasources.perses.dev" NetworkAttachmentDefinitionCRDName = "network-attachment-definitions.k8s.cni.cncf.io" - HcoMutatingWebhookHyperConverged = "mutate-hyperconverged-hco.kubevirt.io" - AppLabel = "app" - UndefinedNamespace = "" - OpenshiftNamespace = "openshift" - APIVersionBeta = v1beta1.APIVersionBeta - CurrentAPIVersion = v1beta1.CurrentAPIVersion - APIVersionGroup = v1beta1.APIVersionGroup - APIVersion = v1beta1.APIVersion - HyperConvergedKind = "HyperConverged" +) + +const ( + AppLabel = "app" + UndefinedNamespace = "" + OpenshiftNamespace = "openshift" + AppLabelPrefix = "app.kubernetes.io" + AppLabelVersion = AppLabelPrefix + "/version" + AppLabelManagedBy = AppLabelPrefix + "/managed-by" + AppLabelPartOf = AppLabelPrefix + "/part-of" + AppLabelComponent = AppLabelPrefix + "/component" +) + +const ( + APIVersionBeta = hcov1beta1.APIVersionBeta + APIVersionV1 = hcov1.APIVersionV1 + CurrentAPIVersion = hcov1beta1.CurrentAPIVersion + APIVersionGroup = hcov1.APIVersionGroup + APIVersion = hcov1.APIVersion + HyperConvergedKind = "HyperConverged" // Recommended labels by Kubernetes. See // https://kubernetes.io/docs/concepts/overview/working-with-objects/common-labels/ - AppLabelPrefix = "app.kubernetes.io" - AppLabelVersion = AppLabelPrefix + "/version" - AppLabelManagedBy = AppLabelPrefix + "/managed-by" - AppLabelPartOf = AppLabelPrefix + "/part-of" - AppLabelComponent = AppLabelPrefix + "/component" // Operator name for managed-by label OperatorName = "hco-operator" // Value for "part-of" label @@ -66,23 +99,17 @@ const ( PrometheusNSLabel = "openshift.io/cluster-monitoring" // HyperConvergedName is the name of the HyperConverged resource that will be reconciled - HyperConvergedName = "kubevirt-hyperconverged" - MetricsHost = "0.0.0.0" - MetricsPort int32 = 8443 - MetricsPortName = "metrics" - HealthProbeHost = "0.0.0.0" - HealthProbePort int32 = 6060 - ReadinessEndpointName = "/readyz" - LivenessEndpointName = "/livez" - HCOWebhookPath = "/validate-hco-kubevirt-io-v1beta1-hyperconverged" - HCOMutatingWebhookPath = "/mutate-hco-kubevirt-io-v1beta1-hyperconverged" - HCONSWebhookPath = "/mutate-ns-hco-kubevirt-io" - WebhookPort = 4343 - WebhookPortName = "webhook" + HyperConvergedName = "kubevirt-hyperconverged" +) - WebhookCertName = "apiserver.crt" - WebhookKeyName = "apiserver.key" - DefaultWebhookCertDir = "/apiserver.local.config/certificates" +const ( + MetricsHost = "0.0.0.0" + MetricsPort int32 = 8443 + MetricsPortName = "metrics" + HealthProbeHost = "0.0.0.0" + HealthProbePort int32 = 6060 + ReadinessEndpointName = "/readyz" + LivenessEndpointName = "/livez" CliDownloadsServerPort int32 = 8080 UIPluginServerPort int32 = 9443 diff --git a/pkg/webhooks/mutator/hyperConvergedMutator.go b/pkg/webhooks/mutator/hyperConvergedMutator.go index d145e76036..3a95d15617 100644 --- a/pkg/webhooks/mutator/hyperConvergedMutator.go +++ b/pkg/webhooks/mutator/hyperConvergedMutator.go @@ -13,14 +13,14 @@ import ( kubevirtcorev1 "kubevirt.io/api/core/v1" - hcov1beta1 "github.com/kubevirt/hyperconverged-cluster-operator/api/v1beta1" + hcov1 "github.com/kubevirt/hyperconverged-cluster-operator/api/v1" goldenimages "github.com/kubevirt/hyperconverged-cluster-operator/controllers/handlers/golden-images" ) var ( hcMutatorLogger = logf.Log.WithName("hyperConverged mutator") - _ admission.Handler = &NsMutator{} + _ admission.Handler = &HyperConvergedMutator{} ) // HyperConvergedMutator mutates HyperConverged requests @@ -53,7 +53,7 @@ const ( ) func (hcm *HyperConvergedMutator) mutateHyperConverged(req admission.Request) admission.Response { - hc := &hcov1beta1.HyperConverged{} + hc := &hcov1.HyperConverged{} err := hcm.decoder.Decode(req, hc) if err != nil { hcMutatorLogger.Error(err, "failed to read the HyperConverged custom resource") @@ -77,7 +77,7 @@ func (hcm *HyperConvergedMutator) mutateHyperConverged(req admission.Request) ad return admission.Allowed("") } -func getMutatePatches(hc *hcov1beta1.HyperConverged) []jsonpatch.JsonPatchOperation { +func getMutatePatches(hc *hcov1.HyperConverged) []jsonpatch.JsonPatchOperation { var patches []jsonpatch.JsonPatchOperation for index, dict := range hc.Spec.DataImportCronTemplates { if dict.Annotations == nil { @@ -97,29 +97,10 @@ func getMutatePatches(hc *hcov1beta1.HyperConverged) []jsonpatch.JsonPatchOperat patches = mutateEvictionStrategy(hc, patches) - if hc.Spec.MediatedDevicesConfiguration != nil { - if len(hc.Spec.MediatedDevicesConfiguration.MediatedDevicesTypes) > 0 && len(hc.Spec.MediatedDevicesConfiguration.MediatedDeviceTypes) == 0 { //nolint SA1019 - patches = append(patches, jsonpatch.JsonPatchOperation{ - Operation: "add", - Path: "/spec/mediatedDevicesConfiguration/mediatedDeviceTypes", - Value: hc.Spec.MediatedDevicesConfiguration.MediatedDevicesTypes, //nolint SA1019 - }) - } - for i, hcoNodeMdevTypeConf := range hc.Spec.MediatedDevicesConfiguration.NodeMediatedDeviceTypes { - if len(hcoNodeMdevTypeConf.MediatedDevicesTypes) > 0 && len(hcoNodeMdevTypeConf.MediatedDeviceTypes) == 0 { //nolint SA1019 - patches = append(patches, jsonpatch.JsonPatchOperation{ - Operation: "add", - Path: fmt.Sprintf("/spec/mediatedDevicesConfiguration/nodeMediatedDeviceTypes/%d/mediatedDeviceTypes", i), - Value: hcoNodeMdevTypeConf.MediatedDevicesTypes, //nolint SA1019 - }) - } - } - } - return patches } -func mutateEvictionStrategy(hc *hcov1beta1.HyperConverged, patches []jsonpatch.JsonPatchOperation) []jsonpatch.JsonPatchOperation { +func mutateEvictionStrategy(hc *hcov1.HyperConverged, patches []jsonpatch.JsonPatchOperation) []jsonpatch.JsonPatchOperation { if hc.Status.InfrastructureHighlyAvailable == nil || hc.Spec.EvictionStrategy != nil { // New HyperConverged CR return patches } diff --git a/pkg/webhooks/mutator/hyperConvergedMutator_test.go b/pkg/webhooks/mutator/hyperConvergedMutator_test.go index 9ce5f195f2..8912d689e3 100644 --- a/pkg/webhooks/mutator/hyperConvergedMutator_test.go +++ b/pkg/webhooks/mutator/hyperConvergedMutator_test.go @@ -17,7 +17,7 @@ import ( kubevirtcorev1 "kubevirt.io/api/core/v1" - "github.com/kubevirt/hyperconverged-cluster-operator/api/v1beta1" + hcov1 "github.com/kubevirt/hyperconverged-cluster-operator/api/v1" "github.com/kubevirt/hyperconverged-cluster-operator/controllers/commontestutils" goldenimages "github.com/kubevirt/hyperconverged-cluster-operator/controllers/handlers/golden-images" "github.com/kubevirt/hyperconverged-cluster-operator/pkg/util" @@ -25,21 +25,21 @@ import ( var _ = Describe("test HyperConverged mutator", func() { var ( - cr *v1beta1.HyperConverged + cr *hcov1.HyperConverged cli client.Client mutator *HyperConvergedMutator ) mutatorScheme = scheme.Scheme - Expect(v1beta1.AddToScheme(mutatorScheme)).To(Succeed()) + Expect(hcov1.AddToScheme(mutatorScheme)).To(Succeed()) BeforeEach(func() { Expect(os.Setenv("OPERATOR_NAMESPACE", HcoValidNamespace)).To(Succeed()) - cr = &v1beta1.HyperConverged{ + cr = &hcov1.HyperConverged{ ObjectMeta: metav1.ObjectMeta{ Name: util.HyperConvergedName, Namespace: HcoValidNamespace, }, - Spec: v1beta1.HyperConvergedSpec{ + Spec: hcov1.HyperConvergedSpec{ EvictionStrategy: ptr.To(kubevirtcorev1.EvictionStrategyLiveMigrate), }, } @@ -59,7 +59,7 @@ var _ = Describe("test HyperConverged mutator", func() { ) DescribeTable("check dict annotation on create", func(annotations map[string]string, expectedPatches *jsonpatch.JsonPatchOperation) { - cr.Spec.DataImportCronTemplates = []v1beta1.DataImportCronTemplate{ + cr.Spec.DataImportCronTemplates = []hcov1.DataImportCronTemplate{ { ObjectMeta: metav1.ObjectMeta{ Name: "dictName", @@ -97,7 +97,7 @@ var _ = Describe("test HyperConverged mutator", func() { ) It("should handle multiple DICTs", func() { - cr.Spec.DataImportCronTemplates = []v1beta1.DataImportCronTemplate{ + cr.Spec.DataImportCronTemplates = []hcov1.DataImportCronTemplate{ { ObjectMeta: metav1.ObjectMeta{ Name: "no-annotation", @@ -144,94 +144,6 @@ var _ = Describe("test HyperConverged mutator", func() { })) }) - It("should handle multiple DICTs and mediatedDevicesTypes -> mediatedDeviceTypes at the same time", func() { - cr.Spec.DataImportCronTemplates = []v1beta1.DataImportCronTemplate{ - { - ObjectMeta: metav1.ObjectMeta{ - Name: "no-annotation", - }, - }, - { - ObjectMeta: metav1.ObjectMeta{ - Name: "different-annotation", - Annotations: map[string]string{"something/else": "value"}, - }, - }, - { - ObjectMeta: metav1.ObjectMeta{ - Name: "annotation-true", - Annotations: map[string]string{goldenimages.CDIImmediateBindAnnotation: "true"}, - }, - }, - { - ObjectMeta: metav1.ObjectMeta{ - Name: "annotation-true", - Annotations: map[string]string{goldenimages.CDIImmediateBindAnnotation: "false"}, - }, - }, - } - - cr.Spec.MediatedDevicesConfiguration = &v1beta1.MediatedDevicesConfiguration{ - MediatedDevicesTypes: []string{"nvidia-222", "nvidia-230"}, //nolint SA1019 - NodeMediatedDeviceTypes: []v1beta1.NodeMediatedDeviceTypesConfig{ - { - NodeSelector: map[string]string{ - "testLabel1": "true", - }, - MediatedDeviceTypes: []string{ - "nvidia-223", - }, - }, - { - NodeSelector: map[string]string{ - "testLabel2": "true", - }, - MediatedDevicesTypes: []string{ - "nvidia-229", - }, - }, - { - NodeSelector: map[string]string{ - "testLabel3": "true", - }, - MediatedDeviceTypes: []string{ - "nvidia-232", - }, - }, - }, - } - - req := admission.Request{AdmissionRequest: newCreateRequest(cr, testCodec)} - - res := mutator.Handle(context.TODO(), req) - Expect(res.Allowed).To(BeTrue()) - - Expect(res.Patches).To(HaveLen(5)) - Expect(res.Patches).To(Equal([]jsonpatch.JsonPatchOperation{ - { - Operation: "add", - Path: fmt.Sprintf(annotationPathTemplate, 0), - Value: map[string]string{goldenimages.CDIImmediateBindAnnotation: "true"}, - }, - { - Operation: "add", - Path: fmt.Sprintf(dictAnnotationPathTemplate, 1), - Value: "true", - }, - { - Operation: "add", - Path: "/spec/mediatedDevicesConfiguration/mediatedDeviceTypes", - Value: []string{"nvidia-222", "nvidia-230"}, - }, - { - Operation: "add", - Path: "/spec/mediatedDevicesConfiguration/nodeMediatedDeviceTypes/1/mediatedDeviceTypes", - Value: []string{"nvidia-229"}, - }, - ksmPatch, - })) - }) - Context("Check defaults for cluster level EvictionStrategy", func() { DescribeTable("check EvictionStrategy default", func(SNO bool, strategy *kubevirtcorev1.EvictionStrategy, patches []jsonpatch.JsonPatchOperation) { @@ -298,130 +210,6 @@ var _ = Describe("test HyperConverged mutator", func() { ) }) - DescribeTable("Check mediatedDevicesTypes -> mediatedDeviceTypes transition", func(initialMDConfiguration *v1beta1.MediatedDevicesConfiguration, patches []jsonpatch.JsonPatchOperation) { - cr.Spec.MediatedDevicesConfiguration = initialMDConfiguration - - req := admission.Request{AdmissionRequest: newCreateRequest(cr, testCodec)} - - res := mutator.Handle(context.TODO(), req) - Expect(res.Allowed).To(BeTrue()) - - patches = append(patches, ksmPatch) - Expect(res.Patches).To(Equal(patches)) - }, - Entry("should do nothing if nothing is there", - nil, - nil, - ), - Entry("should do nothing if already using mediatedDeviceTypes", - &v1beta1.MediatedDevicesConfiguration{ - MediatedDeviceTypes: []string{"nvidia-222", "nvidia-230"}, - NodeMediatedDeviceTypes: []v1beta1.NodeMediatedDeviceTypesConfig{ - { - NodeSelector: map[string]string{ - "testLabel1": "true", - }, - MediatedDeviceTypes: []string{ - "nvidia-223", - }, - }, - { - NodeSelector: map[string]string{ - "testLabel2": "true", - }, - MediatedDeviceTypes: []string{ - "nvidia-229", - }, - }, - }, - }, - nil, - ), - Entry("should set the mediatedDeviceTypes if using only deprecated ones", - &v1beta1.MediatedDevicesConfiguration{ - MediatedDevicesTypes: []string{"nvidia-222", "nvidia-230"}, - NodeMediatedDeviceTypes: []v1beta1.NodeMediatedDeviceTypesConfig{ - { - NodeSelector: map[string]string{ - "testLabel1": "true", - }, - MediatedDevicesTypes: []string{ - "nvidia-223", - }, - }, - { - NodeSelector: map[string]string{ - "testLabel2": "true", - }, - MediatedDevicesTypes: []string{ - "nvidia-229", - }, - }, - }, - }, - []jsonpatch.JsonPatchOperation{ - jsonpatch.JsonPatchOperation{ - Operation: "add", - Path: "/spec/mediatedDevicesConfiguration/mediatedDeviceTypes", - Value: []string{"nvidia-222", "nvidia-230"}, - }, - jsonpatch.JsonPatchOperation{ - Operation: "add", - Path: "/spec/mediatedDevicesConfiguration/nodeMediatedDeviceTypes/0/mediatedDeviceTypes", - Value: []string{"nvidia-223"}, - }, - jsonpatch.JsonPatchOperation{ - Operation: "add", - Path: "/spec/mediatedDevicesConfiguration/nodeMediatedDeviceTypes/1/mediatedDeviceTypes", - Value: []string{"nvidia-229"}, - }, - }, - ), - Entry("should set the mediatedDeviceTypes only when needed if using a mix of the two", - &v1beta1.MediatedDevicesConfiguration{ - MediatedDevicesTypes: []string{"nvidia-222", "nvidia-230"}, - NodeMediatedDeviceTypes: []v1beta1.NodeMediatedDeviceTypesConfig{ - { - NodeSelector: map[string]string{ - "testLabel1": "true", - }, - MediatedDeviceTypes: []string{ - "nvidia-223", - }, - }, - { - NodeSelector: map[string]string{ - "testLabel2": "true", - }, - MediatedDevicesTypes: []string{ - "nvidia-229", - }, - }, - { - NodeSelector: map[string]string{ - "testLabel3": "true", - }, - MediatedDeviceTypes: []string{ - "nvidia-232", - }, - }, - }, - }, - []jsonpatch.JsonPatchOperation{ - { - Operation: "add", - Path: "/spec/mediatedDevicesConfiguration/mediatedDeviceTypes", - Value: []string{"nvidia-222", "nvidia-230"}, - }, - { - Operation: "add", - Path: "/spec/mediatedDevicesConfiguration/nodeMediatedDeviceTypes/1/mediatedDeviceTypes", - Value: []string{"nvidia-229"}, - }, - }, - ), - ) - It("should enable KSM by default", func() { req := admission.Request{AdmissionRequest: newCreateRequest(cr, testCodec)} @@ -446,7 +234,7 @@ var _ = Describe("test HyperConverged mutator", func() { Context("Check mutating webhook for update operation", func() { DescribeTable("check dict annotation on update", func(annotations map[string]string, expectedPatches *jsonpatch.JsonPatchOperation) { origCR := cr.DeepCopy() - cr.Spec.DataImportCronTemplates = []v1beta1.DataImportCronTemplate{ + cr.Spec.DataImportCronTemplates = []hcov1.DataImportCronTemplate{ { ObjectMeta: metav1.ObjectMeta{ Name: "dictName", @@ -484,7 +272,7 @@ var _ = Describe("test HyperConverged mutator", func() { It("should handle multiple DICTs on update", func() { origCR := cr.DeepCopy() - cr.Spec.DataImportCronTemplates = []v1beta1.DataImportCronTemplate{ + cr.Spec.DataImportCronTemplates = []hcov1.DataImportCronTemplate{ { ObjectMeta: metav1.ObjectMeta{ Name: "no-annotation", @@ -528,92 +316,6 @@ var _ = Describe("test HyperConverged mutator", func() { })) }) - It("should handle multiple DICTs and mediatedDevicesTypes -> mediatedDeviceTypes at the same time", func() { - origCR := cr.DeepCopy() - cr.Spec.DataImportCronTemplates = []v1beta1.DataImportCronTemplate{ - { - ObjectMeta: metav1.ObjectMeta{ - Name: "no-annotation", - }, - }, - { - ObjectMeta: metav1.ObjectMeta{ - Name: "different-annotation", - Annotations: map[string]string{"something/else": "value"}, - }, - }, - { - ObjectMeta: metav1.ObjectMeta{ - Name: "annotation-true", - Annotations: map[string]string{goldenimages.CDIImmediateBindAnnotation: "true"}, - }, - }, - { - ObjectMeta: metav1.ObjectMeta{ - Name: "annotation-true", - Annotations: map[string]string{goldenimages.CDIImmediateBindAnnotation: "false"}, - }, - }, - } - - cr.Spec.MediatedDevicesConfiguration = &v1beta1.MediatedDevicesConfiguration{ - MediatedDevicesTypes: []string{"nvidia-222", "nvidia-230"}, //nolint SA1019 - NodeMediatedDeviceTypes: []v1beta1.NodeMediatedDeviceTypesConfig{ - { - NodeSelector: map[string]string{ - "testLabel1": "true", - }, - MediatedDeviceTypes: []string{ - "nvidia-223", - }, - }, - { - NodeSelector: map[string]string{ - "testLabel2": "true", - }, - MediatedDevicesTypes: []string{ - "nvidia-229", - }, - }, - { - NodeSelector: map[string]string{ - "testLabel3": "true", - }, - MediatedDeviceTypes: []string{ - "nvidia-232", - }, - }, - }, - } - - req := admission.Request{AdmissionRequest: newUpdateRequest(origCR, cr, testCodec)} - - res := mutator.Handle(context.TODO(), req) - Expect(res.Allowed).To(BeTrue()) - - Expect(res.Patches).To(HaveLen(4)) - Expect(res.Patches[0]).To(Equal(jsonpatch.JsonPatchOperation{ - Operation: "add", - Path: fmt.Sprintf(annotationPathTemplate, 0), - Value: map[string]string{goldenimages.CDIImmediateBindAnnotation: "true"}, - })) - Expect(res.Patches[1]).To(Equal(jsonpatch.JsonPatchOperation{ - Operation: "add", - Path: fmt.Sprintf(dictAnnotationPathTemplate, 1), - Value: "true", - })) - Expect(res.Patches[2]).To(Equal(jsonpatch.JsonPatchOperation{ - Operation: "add", - Path: "/spec/mediatedDevicesConfiguration/mediatedDeviceTypes", - Value: []string{"nvidia-222", "nvidia-230"}, - })) - Expect(res.Patches[3]).To(Equal(jsonpatch.JsonPatchOperation{ - Operation: "add", - Path: "/spec/mediatedDevicesConfiguration/nodeMediatedDeviceTypes/1/mediatedDeviceTypes", - Value: []string{"nvidia-229"}, - })) - }) - Context("Check defaults for cluster level EvictionStrategy", func() { DescribeTable("check EvictionStrategy default", func(SNO bool, strategy *kubevirtcorev1.EvictionStrategy, patches []jsonpatch.JsonPatchOperation) { @@ -679,131 +381,6 @@ var _ = Describe("test HyperConverged mutator", func() { ), ) }) - - DescribeTable("Check mediatedDevicesTypes -> mediatedDeviceTypes transition", func(initialMDConfiguration *v1beta1.MediatedDevicesConfiguration, patches []jsonpatch.JsonPatchOperation) { - origCR := cr.DeepCopy() - cr.Spec.MediatedDevicesConfiguration = initialMDConfiguration - - req := admission.Request{AdmissionRequest: newUpdateRequest(origCR, cr, testCodec)} - - res := mutator.Handle(context.TODO(), req) - Expect(res.Allowed).To(BeTrue()) - - Expect(res.Patches).To(Equal(patches)) - }, - Entry("should do nothing if nothing is there", - nil, - nil, - ), - Entry("should do nothing if already using mediatedDeviceTypes", - &v1beta1.MediatedDevicesConfiguration{ - MediatedDeviceTypes: []string{"nvidia-222", "nvidia-230"}, - NodeMediatedDeviceTypes: []v1beta1.NodeMediatedDeviceTypesConfig{ - { - NodeSelector: map[string]string{ - "testLabel1": "true", - }, - MediatedDeviceTypes: []string{ - "nvidia-223", - }, - }, - { - NodeSelector: map[string]string{ - "testLabel2": "true", - }, - MediatedDeviceTypes: []string{ - "nvidia-229", - }, - }, - }, - }, - nil, - ), - Entry("should set the mediatedDeviceTypes if using only deprecated ones", - &v1beta1.MediatedDevicesConfiguration{ - MediatedDevicesTypes: []string{"nvidia-222", "nvidia-230"}, - NodeMediatedDeviceTypes: []v1beta1.NodeMediatedDeviceTypesConfig{ - { - NodeSelector: map[string]string{ - "testLabel1": "true", - }, - MediatedDevicesTypes: []string{ - "nvidia-223", - }, - }, - { - NodeSelector: map[string]string{ - "testLabel2": "true", - }, - MediatedDevicesTypes: []string{ - "nvidia-229", - }, - }, - }, - }, - []jsonpatch.JsonPatchOperation{ - jsonpatch.JsonPatchOperation{ - Operation: "add", - Path: "/spec/mediatedDevicesConfiguration/mediatedDeviceTypes", - Value: []string{"nvidia-222", "nvidia-230"}, - }, - jsonpatch.JsonPatchOperation{ - Operation: "add", - Path: "/spec/mediatedDevicesConfiguration/nodeMediatedDeviceTypes/0/mediatedDeviceTypes", - Value: []string{"nvidia-223"}, - }, - jsonpatch.JsonPatchOperation{ - Operation: "add", - Path: "/spec/mediatedDevicesConfiguration/nodeMediatedDeviceTypes/1/mediatedDeviceTypes", - Value: []string{"nvidia-229"}, - }, - }, - ), - Entry("should set the mediatedDeviceTypes only when needed if using a mix of the two", - &v1beta1.MediatedDevicesConfiguration{ - MediatedDevicesTypes: []string{"nvidia-222", "nvidia-230"}, - NodeMediatedDeviceTypes: []v1beta1.NodeMediatedDeviceTypesConfig{ - { - NodeSelector: map[string]string{ - "testLabel1": "true", - }, - MediatedDeviceTypes: []string{ - "nvidia-223", - }, - }, - { - NodeSelector: map[string]string{ - "testLabel2": "true", - }, - MediatedDevicesTypes: []string{ - "nvidia-229", - }, - }, - { - NodeSelector: map[string]string{ - "testLabel3": "true", - }, - MediatedDeviceTypes: []string{ - "nvidia-232", - }, - }, - }, - }, - []jsonpatch.JsonPatchOperation{ - jsonpatch.JsonPatchOperation{ - Operation: "add", - Path: "/spec/mediatedDevicesConfiguration/mediatedDeviceTypes", - Value: []string{"nvidia-222", "nvidia-230"}, - }, - jsonpatch.JsonPatchOperation{ - Operation: "add", - Path: "/spec/mediatedDevicesConfiguration/nodeMediatedDeviceTypes/1/mediatedDeviceTypes", - Value: []string{"nvidia-229"}, - }, - }, - ), - ) - }) }) diff --git a/pkg/webhooks/mutator/hyperConvergedV1Beta1Mutator.go b/pkg/webhooks/mutator/hyperConvergedV1Beta1Mutator.go new file mode 100644 index 0000000000..2712bdd5b1 --- /dev/null +++ b/pkg/webhooks/mutator/hyperConvergedV1Beta1Mutator.go @@ -0,0 +1,134 @@ +package mutator + +import ( + "context" + "fmt" + "net/http" + + "gomodules.xyz/jsonpatch/v2" + admissionv1 "k8s.io/api/admission/v1" + "sigs.k8s.io/controller-runtime/pkg/client" + logf "sigs.k8s.io/controller-runtime/pkg/log" + "sigs.k8s.io/controller-runtime/pkg/webhook/admission" + + kubevirtcorev1 "kubevirt.io/api/core/v1" + + hcov1beta1 "github.com/kubevirt/hyperconverged-cluster-operator/api/v1beta1" + goldenimages "github.com/kubevirt/hyperconverged-cluster-operator/controllers/handlers/golden-images" +) + +var ( + hcV1Beta1MutatorLogger = logf.Log.WithName("hyperConverged v1beta1 mutator") + + _ admission.Handler = &HyperConvergedV1Beta1Mutator{} +) + +// HyperConvergedV1Beta1Mutator mutates HyperConverged v1beta1 requests +type HyperConvergedV1Beta1Mutator struct { + decoder admission.Decoder + cli client.Client +} + +func NewHyperConvergedV1Beta1Mutator(cli client.Client, decoder admission.Decoder) *HyperConvergedV1Beta1Mutator { + return &HyperConvergedV1Beta1Mutator{ + cli: cli, + decoder: decoder, + } +} + +func (hcm *HyperConvergedV1Beta1Mutator) Handle(_ context.Context, req admission.Request) admission.Response { + hcV1Beta1MutatorLogger.Info("reaching HyperConvergedMutator.Handle") + + if req.Operation == admissionv1.Update || req.Operation == admissionv1.Create { + return hcm.mutateHyperConverged(req) + } + + // ignoring other operations + return admission.Allowed(ignoreOperationMessage) +} + +func (hcm *HyperConvergedV1Beta1Mutator) mutateHyperConverged(req admission.Request) admission.Response { + hc := &hcov1beta1.HyperConverged{} + err := hcm.decoder.Decode(req, hc) + if err != nil { + hcV1Beta1MutatorLogger.Error(err, "failed to read the HyperConverged custom resource") + return admission.Errored(http.StatusBadRequest, fmt.Errorf("failed to parse the HyperConverged")) + } + + patches := getV1Beta1MutatePatches(hc) + + if req.Operation == admissionv1.Create && hc.Spec.KSMConfiguration == nil { + patches = append(patches, jsonpatch.JsonPatchOperation{ + Operation: "add", + Path: "/spec/ksmConfiguration", + Value: kubevirtcorev1.KSMConfiguration{}, + }) + } + + if len(patches) > 0 { + return admission.Patched("mutated", patches...) + } + + return admission.Allowed("") +} + +func getV1Beta1MutatePatches(hc *hcov1beta1.HyperConverged) []jsonpatch.JsonPatchOperation { + var patches []jsonpatch.JsonPatchOperation + for index, dict := range hc.Spec.DataImportCronTemplates { + if dict.Annotations == nil { + patches = append(patches, jsonpatch.JsonPatchOperation{ + Operation: "add", + Path: fmt.Sprintf(annotationPathTemplate, index), + Value: map[string]string{goldenimages.CDIImmediateBindAnnotation: "true"}, + }) + } else if _, annotationFound := dict.Annotations[goldenimages.CDIImmediateBindAnnotation]; !annotationFound { + patches = append(patches, jsonpatch.JsonPatchOperation{ + Operation: "add", + Path: fmt.Sprintf(dictAnnotationPathTemplate, index), + Value: "true", + }) + } + } + + patches = mutateV1Beta1EvictionStrategy(hc, patches) + + if hc.Spec.MediatedDevicesConfiguration != nil { + if len(hc.Spec.MediatedDevicesConfiguration.MediatedDevicesTypes) > 0 && len(hc.Spec.MediatedDevicesConfiguration.MediatedDeviceTypes) == 0 { //nolint SA1019 + patches = append(patches, jsonpatch.JsonPatchOperation{ + Operation: "add", + Path: "/spec/mediatedDevicesConfiguration/mediatedDeviceTypes", + Value: hc.Spec.MediatedDevicesConfiguration.MediatedDevicesTypes, //nolint SA1019 + }) + } + for i, hcoNodeMdevTypeConf := range hc.Spec.MediatedDevicesConfiguration.NodeMediatedDeviceTypes { + if len(hcoNodeMdevTypeConf.MediatedDevicesTypes) > 0 && len(hcoNodeMdevTypeConf.MediatedDeviceTypes) == 0 { //nolint SA1019 + patches = append(patches, jsonpatch.JsonPatchOperation{ + Operation: "add", + Path: fmt.Sprintf("/spec/mediatedDevicesConfiguration/nodeMediatedDeviceTypes/%d/mediatedDeviceTypes", i), + Value: hcoNodeMdevTypeConf.MediatedDevicesTypes, //nolint SA1019 + }) + } + } + } + + return patches +} + +func mutateV1Beta1EvictionStrategy(hc *hcov1beta1.HyperConverged, patches []jsonpatch.JsonPatchOperation) []jsonpatch.JsonPatchOperation { + if hc.Status.InfrastructureHighlyAvailable == nil || hc.Spec.EvictionStrategy != nil { // New HyperConverged CR + return patches + } + + var value = kubevirtcorev1.EvictionStrategyNone + if *hc.Status.InfrastructureHighlyAvailable { + value = kubevirtcorev1.EvictionStrategyLiveMigrate + } + + patches = append(patches, jsonpatch.JsonPatchOperation{ + Operation: "replace", + Path: "/spec/evictionStrategy", + Value: value, + }) + + return patches +} diff --git a/pkg/webhooks/mutator/hyperConvergedV1Beta1Mutator_test.go b/pkg/webhooks/mutator/hyperConvergedV1Beta1Mutator_test.go new file mode 100644 index 0000000000..db1ef14146 --- /dev/null +++ b/pkg/webhooks/mutator/hyperConvergedV1Beta1Mutator_test.go @@ -0,0 +1,815 @@ +package mutator + +import ( + "context" + "fmt" + "os" + + . "github.com/onsi/ginkgo/v2" + . "github.com/onsi/gomega" + "gomodules.xyz/jsonpatch/v2" + metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" + "k8s.io/apimachinery/pkg/runtime" + "k8s.io/client-go/kubernetes/scheme" + "k8s.io/utils/ptr" + "sigs.k8s.io/controller-runtime/pkg/client" + "sigs.k8s.io/controller-runtime/pkg/webhook/admission" + + kubevirtcorev1 "kubevirt.io/api/core/v1" + + hcov1beta1 "github.com/kubevirt/hyperconverged-cluster-operator/api/v1beta1" + "github.com/kubevirt/hyperconverged-cluster-operator/controllers/commontestutils" + goldenimages "github.com/kubevirt/hyperconverged-cluster-operator/controllers/handlers/golden-images" + "github.com/kubevirt/hyperconverged-cluster-operator/pkg/util" +) + +var _ = Describe("test HyperConverged mutator", func() { + var ( + cr *hcov1beta1.HyperConverged + cli client.Client + mutator *HyperConvergedV1Beta1Mutator + ) + + mutatorScheme = scheme.Scheme + Expect(hcov1beta1.AddToScheme(mutatorScheme)).To(Succeed()) + BeforeEach(func() { + Expect(os.Setenv("OPERATOR_NAMESPACE", HcoValidNamespace)).To(Succeed()) + cr = &hcov1beta1.HyperConverged{ + ObjectMeta: metav1.ObjectMeta{ + Name: util.HyperConvergedName, + Namespace: HcoValidNamespace, + }, + Spec: hcov1beta1.HyperConvergedSpec{ + EvictionStrategy: ptr.To(kubevirtcorev1.EvictionStrategyLiveMigrate), + }, + } + + cli = commontestutils.InitClient(nil) + mutator = initV1Beta1HCMutator(mutatorScheme, cli) + }) + + Context("Check mutating webhook for create operation", func() { + + var ( + ksmPatch = jsonpatch.JsonPatchOperation{ + Operation: "add", + Path: "/spec/ksmConfiguration", + Value: kubevirtcorev1.KSMConfiguration{}, + } + ) + + DescribeTable("check dict annotation on create", func(annotations map[string]string, expectedPatches *jsonpatch.JsonPatchOperation) { + cr.Spec.DataImportCronTemplates = []hcov1beta1.DataImportCronTemplate{ + { + ObjectMeta: metav1.ObjectMeta{ + Name: "dictName", + Annotations: annotations, + }, + }, + } + + req := admission.Request{AdmissionRequest: newCreateRequest(cr, testCodec)} + + res := mutator.Handle(context.TODO(), req) + Expect(res.Allowed).To(BeTrue()) + + if expectedPatches == nil { + Expect(res.Patches).To(HaveLen(1)) + } else { + Expect(res.Patches).To(HaveLen(2)) + Expect(res.Patches).To(ContainElement(*expectedPatches)) + } + + Expect(res.Patches).To(ContainElement(ksmPatch)) + }, + Entry("no annotations", nil, &jsonpatch.JsonPatchOperation{ + Operation: "add", + Path: fmt.Sprintf(annotationPathTemplate, 0), + Value: map[string]string{goldenimages.CDIImmediateBindAnnotation: "true"}, + }), + Entry("different annotations", map[string]string{"something/else": "value"}, &jsonpatch.JsonPatchOperation{ + Operation: "add", + Path: fmt.Sprintf(dictAnnotationPathTemplate, 0), + Value: "true", + }), + Entry("annotation=true", map[string]string{goldenimages.CDIImmediateBindAnnotation: "true"}, nil), + Entry("annotation=false", map[string]string{goldenimages.CDIImmediateBindAnnotation: "false"}, nil), + ) + + It("should handle multiple DICTs", func() { + cr.Spec.DataImportCronTemplates = []hcov1beta1.DataImportCronTemplate{ + { + ObjectMeta: metav1.ObjectMeta{ + Name: "no-annotation", + }, + }, + { + ObjectMeta: metav1.ObjectMeta{ + Name: "different-annotation", + Annotations: map[string]string{"something/else": "value"}, + }, + }, + { + ObjectMeta: metav1.ObjectMeta{ + Name: "annotation-true", + Annotations: map[string]string{goldenimages.CDIImmediateBindAnnotation: "true"}, + }, + }, + { + ObjectMeta: metav1.ObjectMeta{ + Name: "annotation-true", + Annotations: map[string]string{goldenimages.CDIImmediateBindAnnotation: "false"}, + }, + }, + } + + req := admission.Request{AdmissionRequest: newCreateRequest(cr, testCodec)} + + res := mutator.Handle(context.TODO(), req) + Expect(res.Allowed).To(BeTrue()) + + Expect(res.Patches).To(HaveLen(3)) + Expect(res.Patches).To(Equal([]jsonpatch.JsonPatchOperation{ + { + Operation: "add", + Path: fmt.Sprintf(annotationPathTemplate, 0), + Value: map[string]string{goldenimages.CDIImmediateBindAnnotation: "true"}, + }, + { + Operation: "add", + Path: fmt.Sprintf(dictAnnotationPathTemplate, 1), + Value: "true", + }, + ksmPatch, + })) + }) + + It("should handle multiple DICTs and mediatedDevicesTypes -> mediatedDeviceTypes at the same time", func() { + cr.Spec.DataImportCronTemplates = []hcov1beta1.DataImportCronTemplate{ + { + ObjectMeta: metav1.ObjectMeta{ + Name: "no-annotation", + }, + }, + { + ObjectMeta: metav1.ObjectMeta{ + Name: "different-annotation", + Annotations: map[string]string{"something/else": "value"}, + }, + }, + { + ObjectMeta: metav1.ObjectMeta{ + Name: "annotation-true", + Annotations: map[string]string{goldenimages.CDIImmediateBindAnnotation: "true"}, + }, + }, + { + ObjectMeta: metav1.ObjectMeta{ + Name: "annotation-true", + Annotations: map[string]string{goldenimages.CDIImmediateBindAnnotation: "false"}, + }, + }, + } + + cr.Spec.MediatedDevicesConfiguration = &hcov1beta1.MediatedDevicesConfiguration{ + MediatedDevicesTypes: []string{"nvidia-222", "nvidia-230"}, //nolint SA1019 + NodeMediatedDeviceTypes: []hcov1beta1.NodeMediatedDeviceTypesConfig{ + { + NodeSelector: map[string]string{ + "testLabel1": "true", + }, + MediatedDeviceTypes: []string{ + "nvidia-223", + }, + }, + { + NodeSelector: map[string]string{ + "testLabel2": "true", + }, + MediatedDevicesTypes: []string{ + "nvidia-229", + }, + }, + { + NodeSelector: map[string]string{ + "testLabel3": "true", + }, + MediatedDeviceTypes: []string{ + "nvidia-232", + }, + }, + }, + } + + req := admission.Request{AdmissionRequest: newCreateRequest(cr, testCodec)} + + res := mutator.Handle(context.TODO(), req) + Expect(res.Allowed).To(BeTrue()) + + Expect(res.Patches).To(HaveLen(5)) + Expect(res.Patches).To(Equal([]jsonpatch.JsonPatchOperation{ + { + Operation: "add", + Path: fmt.Sprintf(annotationPathTemplate, 0), + Value: map[string]string{goldenimages.CDIImmediateBindAnnotation: "true"}, + }, + { + Operation: "add", + Path: fmt.Sprintf(dictAnnotationPathTemplate, 1), + Value: "true", + }, + { + Operation: "add", + Path: "/spec/mediatedDevicesConfiguration/mediatedDeviceTypes", + Value: []string{"nvidia-222", "nvidia-230"}, + }, + { + Operation: "add", + Path: "/spec/mediatedDevicesConfiguration/nodeMediatedDeviceTypes/1/mediatedDeviceTypes", + Value: []string{"nvidia-229"}, + }, + ksmPatch, + })) + }) + + Context("Check defaults for cluster level EvictionStrategy", func() { + + DescribeTable("check EvictionStrategy default", func(SNO bool, strategy *kubevirtcorev1.EvictionStrategy, patches []jsonpatch.JsonPatchOperation) { + cr.Status.InfrastructureHighlyAvailable = ptr.To(!SNO) + + cr.Spec.EvictionStrategy = strategy + + req := admission.Request{AdmissionRequest: newCreateRequest(cr, testCodec)} + + res := mutator.Handle(context.TODO(), req) + Expect(res.Allowed).To(BeTrue()) + + patches = append(patches, ksmPatch) + Expect(res.Patches).To(Equal(patches)) + }, + Entry("should set EvictionStrategyNone if not set and on SNO", + true, + nil, + []jsonpatch.JsonPatchOperation{{ + Operation: "replace", + Path: "/spec/evictionStrategy", + Value: kubevirtcorev1.EvictionStrategyNone, + }}, + ), + Entry("should not override EvictionStrategy if set and on SNO - 1", + true, + ptr.To(kubevirtcorev1.EvictionStrategyNone), + nil, + ), + Entry("should not override EvictionStrategy if set and on SNO - 2", + true, + ptr.To(kubevirtcorev1.EvictionStrategyLiveMigrate), + nil, + ), + Entry("should not override EvictionStrategy if set and on SNO - 3", + true, + ptr.To(kubevirtcorev1.EvictionStrategyExternal), + nil, + ), + Entry("should set EvictionStrategyLiveMigrate if not set and not on SNO", + false, + nil, + []jsonpatch.JsonPatchOperation{jsonpatch.JsonPatchOperation{ + Operation: "replace", + Path: "/spec/evictionStrategy", + Value: kubevirtcorev1.EvictionStrategyLiveMigrate, + }}, + ), + Entry("should not override EvictionStrategy if set and not on SNO - 1", + false, + ptr.To(kubevirtcorev1.EvictionStrategyNone), + nil, + ), + Entry("should not override EvictionStrategy if set and not on SNO - 2", + false, + ptr.To(kubevirtcorev1.EvictionStrategyLiveMigrate), + nil, + ), + Entry("should not override EvictionStrategy if set and not on SNO - 3", + false, + ptr.To(kubevirtcorev1.EvictionStrategyExternal), + nil, + ), + ) + }) + + DescribeTable("Check mediatedDevicesTypes -> mediatedDeviceTypes transition", func(initialMDConfiguration *hcov1beta1.MediatedDevicesConfiguration, patches []jsonpatch.JsonPatchOperation) { + cr.Spec.MediatedDevicesConfiguration = initialMDConfiguration + + req := admission.Request{AdmissionRequest: newCreateRequest(cr, testCodec)} + + res := mutator.Handle(context.TODO(), req) + Expect(res.Allowed).To(BeTrue()) + + patches = append(patches, ksmPatch) + Expect(res.Patches).To(Equal(patches)) + }, + Entry("should do nothing if nothing is there", + nil, + nil, + ), + Entry("should do nothing if already using mediatedDeviceTypes", + &hcov1beta1.MediatedDevicesConfiguration{ + MediatedDeviceTypes: []string{"nvidia-222", "nvidia-230"}, + NodeMediatedDeviceTypes: []hcov1beta1.NodeMediatedDeviceTypesConfig{ + { + NodeSelector: map[string]string{ + "testLabel1": "true", + }, + MediatedDeviceTypes: []string{ + "nvidia-223", + }, + }, + { + NodeSelector: map[string]string{ + "testLabel2": "true", + }, + MediatedDeviceTypes: []string{ + "nvidia-229", + }, + }, + }, + }, + nil, + ), + Entry("should set the mediatedDeviceTypes if using only deprecated ones", + &hcov1beta1.MediatedDevicesConfiguration{ + MediatedDevicesTypes: []string{"nvidia-222", "nvidia-230"}, + NodeMediatedDeviceTypes: []hcov1beta1.NodeMediatedDeviceTypesConfig{ + { + NodeSelector: map[string]string{ + "testLabel1": "true", + }, + MediatedDevicesTypes: []string{ + "nvidia-223", + }, + }, + { + NodeSelector: map[string]string{ + "testLabel2": "true", + }, + MediatedDevicesTypes: []string{ + "nvidia-229", + }, + }, + }, + }, + []jsonpatch.JsonPatchOperation{ + jsonpatch.JsonPatchOperation{ + Operation: "add", + Path: "/spec/mediatedDevicesConfiguration/mediatedDeviceTypes", + Value: []string{"nvidia-222", "nvidia-230"}, + }, + jsonpatch.JsonPatchOperation{ + Operation: "add", + Path: "/spec/mediatedDevicesConfiguration/nodeMediatedDeviceTypes/0/mediatedDeviceTypes", + Value: []string{"nvidia-223"}, + }, + jsonpatch.JsonPatchOperation{ + Operation: "add", + Path: "/spec/mediatedDevicesConfiguration/nodeMediatedDeviceTypes/1/mediatedDeviceTypes", + Value: []string{"nvidia-229"}, + }, + }, + ), + Entry("should set the mediatedDeviceTypes only when needed if using a mix of the two", + &hcov1beta1.MediatedDevicesConfiguration{ + MediatedDevicesTypes: []string{"nvidia-222", "nvidia-230"}, + NodeMediatedDeviceTypes: []hcov1beta1.NodeMediatedDeviceTypesConfig{ + { + NodeSelector: map[string]string{ + "testLabel1": "true", + }, + MediatedDeviceTypes: []string{ + "nvidia-223", + }, + }, + { + NodeSelector: map[string]string{ + "testLabel2": "true", + }, + MediatedDevicesTypes: []string{ + "nvidia-229", + }, + }, + { + NodeSelector: map[string]string{ + "testLabel3": "true", + }, + MediatedDeviceTypes: []string{ + "nvidia-232", + }, + }, + }, + }, + []jsonpatch.JsonPatchOperation{ + { + Operation: "add", + Path: "/spec/mediatedDevicesConfiguration/mediatedDeviceTypes", + Value: []string{"nvidia-222", "nvidia-230"}, + }, + { + Operation: "add", + Path: "/spec/mediatedDevicesConfiguration/nodeMediatedDeviceTypes/1/mediatedDeviceTypes", + Value: []string{"nvidia-229"}, + }, + }, + ), + ) + + It("should enable KSM by default", func() { + req := admission.Request{AdmissionRequest: newCreateRequest(cr, testCodec)} + + res := mutator.Handle(context.TODO(), req) + Expect(res.Allowed).To(BeTrue()) + + Expect(res.Patches).To(Equal([]jsonpatch.JsonPatchOperation{ksmPatch})) + }) + + It("should not enable KSM, if already set", func() { + cr.Spec.KSMConfiguration = &kubevirtcorev1.KSMConfiguration{} + req := admission.Request{AdmissionRequest: newCreateRequest(cr, testCodec)} + + res := mutator.Handle(context.TODO(), req) + Expect(res.Allowed).To(BeTrue()) + + Expect(res.Patches).To(BeEmpty()) + }) + + }) + + Context("Check mutating webhook for update operation", func() { + DescribeTable("check dict annotation on update", func(annotations map[string]string, expectedPatches *jsonpatch.JsonPatchOperation) { + origCR := cr.DeepCopy() + cr.Spec.DataImportCronTemplates = []hcov1beta1.DataImportCronTemplate{ + { + ObjectMeta: metav1.ObjectMeta{ + Name: "dictName", + Annotations: annotations, + }, + }, + } + + req := admission.Request{AdmissionRequest: newUpdateRequest(origCR, cr, testCodec)} + + res := mutator.Handle(context.TODO(), req) + Expect(res.Allowed).To(BeTrue()) + + if expectedPatches == nil { + Expect(res.Patches).To(BeEmpty()) + } else { + Expect(res.Patches).To(HaveLen(1)) + Expect(res.Patches[0]).To(Equal(*expectedPatches)) + } + }, + Entry("no annotations", nil, &jsonpatch.JsonPatchOperation{ + Operation: "add", + Path: fmt.Sprintf(annotationPathTemplate, 0), + Value: map[string]string{goldenimages.CDIImmediateBindAnnotation: "true"}, + }), + Entry("different annotations", map[string]string{"something/else": "value"}, &jsonpatch.JsonPatchOperation{ + Operation: "add", + Path: fmt.Sprintf(dictAnnotationPathTemplate, 0), + Value: "true", + }), + Entry("annotation=true", map[string]string{goldenimages.CDIImmediateBindAnnotation: "true"}, nil), + Entry("annotation=false", map[string]string{goldenimages.CDIImmediateBindAnnotation: "false"}, nil), + ) + + It("should handle multiple DICTs on update", func() { + origCR := cr.DeepCopy() + + cr.Spec.DataImportCronTemplates = []hcov1beta1.DataImportCronTemplate{ + { + ObjectMeta: metav1.ObjectMeta{ + Name: "no-annotation", + }, + }, + { + ObjectMeta: metav1.ObjectMeta{ + Name: "different-annotation", + Annotations: map[string]string{"something/else": "value"}, + }, + }, + { + ObjectMeta: metav1.ObjectMeta{ + Name: "annotation-true", + Annotations: map[string]string{goldenimages.CDIImmediateBindAnnotation: "true"}, + }, + }, + { + ObjectMeta: metav1.ObjectMeta{ + Name: "annotation-true", + Annotations: map[string]string{goldenimages.CDIImmediateBindAnnotation: "false"}, + }, + }, + } + + req := admission.Request{AdmissionRequest: newUpdateRequest(origCR, cr, testCodec)} + + res := mutator.Handle(context.TODO(), req) + Expect(res.Allowed).To(BeTrue()) + + Expect(res.Patches).To(HaveLen(2)) + Expect(res.Patches[0]).To(Equal(jsonpatch.JsonPatchOperation{ + Operation: "add", + Path: fmt.Sprintf(annotationPathTemplate, 0), + Value: map[string]string{goldenimages.CDIImmediateBindAnnotation: "true"}, + })) + Expect(res.Patches[1]).To(Equal(jsonpatch.JsonPatchOperation{ + Operation: "add", + Path: fmt.Sprintf(dictAnnotationPathTemplate, 1), + Value: "true", + })) + }) + + It("should handle multiple DICTs and mediatedDevicesTypes -> mediatedDeviceTypes at the same time", func() { + origCR := cr.DeepCopy() + cr.Spec.DataImportCronTemplates = []hcov1beta1.DataImportCronTemplate{ + { + ObjectMeta: metav1.ObjectMeta{ + Name: "no-annotation", + }, + }, + { + ObjectMeta: metav1.ObjectMeta{ + Name: "different-annotation", + Annotations: map[string]string{"something/else": "value"}, + }, + }, + { + ObjectMeta: metav1.ObjectMeta{ + Name: "annotation-true", + Annotations: map[string]string{goldenimages.CDIImmediateBindAnnotation: "true"}, + }, + }, + { + ObjectMeta: metav1.ObjectMeta{ + Name: "annotation-true", + Annotations: map[string]string{goldenimages.CDIImmediateBindAnnotation: "false"}, + }, + }, + } + + cr.Spec.MediatedDevicesConfiguration = &hcov1beta1.MediatedDevicesConfiguration{ + MediatedDevicesTypes: []string{"nvidia-222", "nvidia-230"}, //nolint SA1019 + NodeMediatedDeviceTypes: []hcov1beta1.NodeMediatedDeviceTypesConfig{ + { + NodeSelector: map[string]string{ + "testLabel1": "true", + }, + MediatedDeviceTypes: []string{ + "nvidia-223", + }, + }, + { + NodeSelector: map[string]string{ + "testLabel2": "true", + }, + MediatedDevicesTypes: []string{ + "nvidia-229", + }, + }, + { + NodeSelector: map[string]string{ + "testLabel3": "true", + }, + MediatedDeviceTypes: []string{ + "nvidia-232", + }, + }, + }, + } + + req := admission.Request{AdmissionRequest: newUpdateRequest(origCR, cr, testCodec)} + + res := mutator.Handle(context.TODO(), req) + Expect(res.Allowed).To(BeTrue()) + + Expect(res.Patches).To(HaveLen(4)) + Expect(res.Patches[0]).To(Equal(jsonpatch.JsonPatchOperation{ + Operation: "add", + Path: fmt.Sprintf(annotationPathTemplate, 0), + Value: map[string]string{goldenimages.CDIImmediateBindAnnotation: "true"}, + })) + Expect(res.Patches[1]).To(Equal(jsonpatch.JsonPatchOperation{ + Operation: "add", + Path: fmt.Sprintf(dictAnnotationPathTemplate, 1), + Value: "true", + })) + Expect(res.Patches[2]).To(Equal(jsonpatch.JsonPatchOperation{ + Operation: "add", + Path: "/spec/mediatedDevicesConfiguration/mediatedDeviceTypes", + Value: []string{"nvidia-222", "nvidia-230"}, + })) + Expect(res.Patches[3]).To(Equal(jsonpatch.JsonPatchOperation{ + Operation: "add", + Path: "/spec/mediatedDevicesConfiguration/nodeMediatedDeviceTypes/1/mediatedDeviceTypes", + Value: []string{"nvidia-229"}, + })) + }) + + Context("Check defaults for cluster level EvictionStrategy", func() { + + DescribeTable("check EvictionStrategy default", func(SNO bool, strategy *kubevirtcorev1.EvictionStrategy, patches []jsonpatch.JsonPatchOperation) { + origCR := cr.DeepCopy() + cr.Status.InfrastructureHighlyAvailable = ptr.To(!SNO) + + cr.Spec.EvictionStrategy = strategy + + req := admission.Request{AdmissionRequest: newUpdateRequest(origCR, cr, testCodec)} + + res := mutator.Handle(context.TODO(), req) + Expect(res.Allowed).To(BeTrue()) + + Expect(res.Patches).To(Equal(patches)) + }, + Entry("should set EvictionStrategyNone if not set and on SNO", + true, + nil, + []jsonpatch.JsonPatchOperation{jsonpatch.JsonPatchOperation{ + Operation: "replace", + Path: "/spec/evictionStrategy", + Value: kubevirtcorev1.EvictionStrategyNone, + }}, + ), + Entry("should not override EvictionStrategy if set and on SNO - 1", + true, + ptr.To(kubevirtcorev1.EvictionStrategyNone), + nil, + ), + Entry("should not override EvictionStrategy if set and on SNO - 2", + true, + ptr.To(kubevirtcorev1.EvictionStrategyLiveMigrate), + nil, + ), + Entry("should not override EvictionStrategy if set and on SNO - 3", + true, + ptr.To(kubevirtcorev1.EvictionStrategyExternal), + nil, + ), + Entry("should set EvictionStrategyLiveMigrate if not set and not on SNO", + false, + nil, + []jsonpatch.JsonPatchOperation{jsonpatch.JsonPatchOperation{ + Operation: "replace", + Path: "/spec/evictionStrategy", + Value: kubevirtcorev1.EvictionStrategyLiveMigrate, + }}, + ), + Entry("should not override EvictionStrategy if set and not on SNO - 1", + false, + ptr.To(kubevirtcorev1.EvictionStrategyNone), + nil, + ), + Entry("should not override EvictionStrategy if set and not on SNO - 2", + false, + ptr.To(kubevirtcorev1.EvictionStrategyLiveMigrate), + nil, + ), + Entry("should not override EvictionStrategy if set and not on SNO - 3", + false, + ptr.To(kubevirtcorev1.EvictionStrategyExternal), + nil, + ), + ) + }) + + DescribeTable("Check mediatedDevicesTypes -> mediatedDeviceTypes transition", func(initialMDConfiguration *hcov1beta1.MediatedDevicesConfiguration, patches []jsonpatch.JsonPatchOperation) { + origCR := cr.DeepCopy() + cr.Spec.MediatedDevicesConfiguration = initialMDConfiguration + + req := admission.Request{AdmissionRequest: newUpdateRequest(origCR, cr, testCodec)} + + res := mutator.Handle(context.TODO(), req) + Expect(res.Allowed).To(BeTrue()) + + Expect(res.Patches).To(Equal(patches)) + }, + Entry("should do nothing if nothing is there", + nil, + nil, + ), + Entry("should do nothing if already using mediatedDeviceTypes", + &hcov1beta1.MediatedDevicesConfiguration{ + MediatedDeviceTypes: []string{"nvidia-222", "nvidia-230"}, + NodeMediatedDeviceTypes: []hcov1beta1.NodeMediatedDeviceTypesConfig{ + { + NodeSelector: map[string]string{ + "testLabel1": "true", + }, + MediatedDeviceTypes: []string{ + "nvidia-223", + }, + }, + { + NodeSelector: map[string]string{ + "testLabel2": "true", + }, + MediatedDeviceTypes: []string{ + "nvidia-229", + }, + }, + }, + }, + nil, + ), + Entry("should set the mediatedDeviceTypes if using only deprecated ones", + &hcov1beta1.MediatedDevicesConfiguration{ + MediatedDevicesTypes: []string{"nvidia-222", "nvidia-230"}, + NodeMediatedDeviceTypes: []hcov1beta1.NodeMediatedDeviceTypesConfig{ + { + NodeSelector: map[string]string{ + "testLabel1": "true", + }, + MediatedDevicesTypes: []string{ + "nvidia-223", + }, + }, + { + NodeSelector: map[string]string{ + "testLabel2": "true", + }, + MediatedDevicesTypes: []string{ + "nvidia-229", + }, + }, + }, + }, + []jsonpatch.JsonPatchOperation{ + jsonpatch.JsonPatchOperation{ + Operation: "add", + Path: "/spec/mediatedDevicesConfiguration/mediatedDeviceTypes", + Value: []string{"nvidia-222", "nvidia-230"}, + }, + jsonpatch.JsonPatchOperation{ + Operation: "add", + Path: "/spec/mediatedDevicesConfiguration/nodeMediatedDeviceTypes/0/mediatedDeviceTypes", + Value: []string{"nvidia-223"}, + }, + jsonpatch.JsonPatchOperation{ + Operation: "add", + Path: "/spec/mediatedDevicesConfiguration/nodeMediatedDeviceTypes/1/mediatedDeviceTypes", + Value: []string{"nvidia-229"}, + }, + }, + ), + Entry("should set the mediatedDeviceTypes only when needed if using a mix of the two", + &hcov1beta1.MediatedDevicesConfiguration{ + MediatedDevicesTypes: []string{"nvidia-222", "nvidia-230"}, + NodeMediatedDeviceTypes: []hcov1beta1.NodeMediatedDeviceTypesConfig{ + { + NodeSelector: map[string]string{ + "testLabel1": "true", + }, + MediatedDeviceTypes: []string{ + "nvidia-223", + }, + }, + { + NodeSelector: map[string]string{ + "testLabel2": "true", + }, + MediatedDevicesTypes: []string{ + "nvidia-229", + }, + }, + { + NodeSelector: map[string]string{ + "testLabel3": "true", + }, + MediatedDeviceTypes: []string{ + "nvidia-232", + }, + }, + }, + }, + []jsonpatch.JsonPatchOperation{ + jsonpatch.JsonPatchOperation{ + Operation: "add", + Path: "/spec/mediatedDevicesConfiguration/mediatedDeviceTypes", + Value: []string{"nvidia-222", "nvidia-230"}, + }, + jsonpatch.JsonPatchOperation{ + Operation: "add", + Path: "/spec/mediatedDevicesConfiguration/nodeMediatedDeviceTypes/1/mediatedDeviceTypes", + Value: []string{"nvidia-229"}, + }, + }, + ), + ) + + }) +}) + +func initV1Beta1HCMutator(s *runtime.Scheme, testClient client.Client) *HyperConvergedV1Beta1Mutator { + decoder := admission.NewDecoder(s) + mutator := NewHyperConvergedV1Beta1Mutator(testClient, decoder) + + return mutator +} diff --git a/pkg/webhooks/mutator/mutator_suite_test.go b/pkg/webhooks/mutator/mutator_suite_test.go index a95814b22e..9c0c2d6168 100644 --- a/pkg/webhooks/mutator/mutator_suite_test.go +++ b/pkg/webhooks/mutator/mutator_suite_test.go @@ -15,6 +15,7 @@ import ( cdiv1beta1 "kubevirt.io/containerized-data-importer-api/pkg/apis/core/v1beta1" sspv1beta3 "kubevirt.io/ssp-operator/api/v1beta3" + hcov1 "github.com/kubevirt/hyperconverged-cluster-operator/api/v1" hcov1beta1 "github.com/kubevirt/hyperconverged-cluster-operator/api/v1beta1" ) @@ -29,6 +30,7 @@ func TestMutatorWebhook(t *testing.T) { BeforeSuite(func() { for _, f := range []func(*runtime.Scheme) error{ + hcov1.AddToScheme, hcov1beta1.AddToScheme, cdiv1beta1.AddToScheme, kubevirtcorev1.AddToScheme, @@ -40,7 +42,7 @@ func TestMutatorWebhook(t *testing.T) { } codecFactory = serializer.NewCodecFactory(mutatorScheme) - testCodec = codecFactory.LegacyCodec(corev1.SchemeGroupVersion, hcov1beta1.SchemeGroupVersion) + testCodec = codecFactory.LegacyCodec(corev1.SchemeGroupVersion, hcov1.SchemeGroupVersion, hcov1beta1.SchemeGroupVersion) }) RunSpecs(t, "Mutator Webhooks Suite") diff --git a/pkg/webhooks/mutator/namespace_mutator_test.go b/pkg/webhooks/mutator/namespace_mutator_test.go index 9c7fe2aeb0..fd66888848 100644 --- a/pkg/webhooks/mutator/namespace_mutator_test.go +++ b/pkg/webhooks/mutator/namespace_mutator_test.go @@ -14,7 +14,7 @@ import ( "sigs.k8s.io/controller-runtime/pkg/client" "sigs.k8s.io/controller-runtime/pkg/webhook/admission" - "github.com/kubevirt/hyperconverged-cluster-operator/api/v1beta1" + hcov1 "github.com/kubevirt/hyperconverged-cluster-operator/api/v1" "github.com/kubevirt/hyperconverged-cluster-operator/controllers/commontestutils" "github.com/kubevirt/hyperconverged-cluster-operator/pkg/util" ) @@ -34,12 +34,12 @@ var _ = Describe("webhooks mutator", func() { Expect(os.Setenv("OPERATOR_NAMESPACE", HcoValidNamespace)).To(Succeed()) }) - cr := &v1beta1.HyperConverged{ + cr := &hcov1.HyperConverged{ ObjectMeta: metav1.ObjectMeta{ Name: util.HyperConvergedName, Namespace: HcoValidNamespace, }, - Spec: v1beta1.HyperConvergedSpec{}, + Spec: hcov1.HyperConvergedSpec{}, } var ns runtime.Object = &corev1.Namespace{ diff --git a/pkg/webhooks/mutator/utils.go b/pkg/webhooks/mutator/utils.go index b77788529a..e2bc33131c 100644 --- a/pkg/webhooks/mutator/utils.go +++ b/pkg/webhooks/mutator/utils.go @@ -7,12 +7,12 @@ import ( metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" "sigs.k8s.io/controller-runtime/pkg/client" - "github.com/kubevirt/hyperconverged-cluster-operator/api/v1beta1" + hcov1 "github.com/kubevirt/hyperconverged-cluster-operator/api/v1" hcoutil "github.com/kubevirt/hyperconverged-cluster-operator/pkg/util" ) -func getHcoObject(ctx context.Context, cli client.Client, namespace string) (*v1beta1.HyperConverged, error) { - hco := &v1beta1.HyperConverged{ +func getHcoObject(ctx context.Context, cli client.Client, namespace string) (*hcov1.HyperConverged, error) { + hco := &hcov1.HyperConverged{ ObjectMeta: metav1.ObjectMeta{ Name: hcoutil.HyperConvergedName, Namespace: namespace, diff --git a/pkg/webhooks/setup.go b/pkg/webhooks/setup.go index 673a933a12..b29de4dad4 100644 --- a/pkg/webhooks/setup.go +++ b/pkg/webhooks/setup.go @@ -6,14 +6,14 @@ import ( openshiftconfigv1 "github.com/openshift/api/config/v1" "sigs.k8s.io/controller-runtime/pkg/webhook/admission" - "github.com/kubevirt/hyperconverged-cluster-operator/pkg/webhooks/mutator" - "github.com/kubevirt/hyperconverged-cluster-operator/pkg/webhooks/validator" - ctrl "sigs.k8s.io/controller-runtime" logf "sigs.k8s.io/controller-runtime/pkg/log" "sigs.k8s.io/controller-runtime/pkg/webhook" + hcov1beta1 "github.com/kubevirt/hyperconverged-cluster-operator/api/v1beta1" hcoutil "github.com/kubevirt/hyperconverged-cluster-operator/pkg/util" + "github.com/kubevirt/hyperconverged-cluster-operator/pkg/webhooks/mutator" + "github.com/kubevirt/hyperconverged-cluster-operator/pkg/webhooks/validator" ) const ( @@ -30,14 +30,23 @@ func SetupWebhookWithManager(mgr ctrl.Manager, isOpenshift bool, hcoTLSSecurityP decoder := admission.NewDecoder(mgr.GetScheme()) whHandler := validator.NewWebhookHandler(logger, mgr.GetClient(), decoder, operatorNsEnv, isOpenshift, hcoTLSSecurityProfile) + whV1Beta1Handler := validator.NewV1Beta1WebhookHandler(logger, mgr.GetClient(), decoder, operatorNsEnv, isOpenshift, hcoTLSSecurityProfile) nsMutator := mutator.NewNsMutator(mgr.GetClient(), decoder, operatorNsEnv) hyperConvergedMutator := mutator.NewHyperConvergedMutator(mgr.GetClient(), decoder) + hyperConvergedV1Beta1Mutator := mutator.NewHyperConvergedV1Beta1Mutator(mgr.GetClient(), decoder) + + // add the conversion webhook + if err := ctrl.NewWebhookManagedBy(mgr).For(&hcov1beta1.HyperConverged{}).Complete(); err != nil { + return err + } srv := mgr.GetWebhookServer() srv.Register(hcoutil.HCONSWebhookPath, &webhook.Admission{Handler: nsMutator}) srv.Register(hcoutil.HCOMutatingWebhookPath, &webhook.Admission{Handler: hyperConvergedMutator}) + srv.Register(hcoutil.HCOV1Beta1MutatingWebhookPath, &webhook.Admission{Handler: hyperConvergedV1Beta1Mutator}) srv.Register(hcoutil.HCOWebhookPath, &webhook.Admission{Handler: whHandler}) + srv.Register(hcoutil.HCOWebhookV1Beta1Path, &webhook.Admission{Handler: whV1Beta1Handler}) return nil } diff --git a/pkg/webhooks/setup_test.go b/pkg/webhooks/setup_test.go index 8147c33cba..109c14ac04 100644 --- a/pkg/webhooks/setup_test.go +++ b/pkg/webhooks/setup_test.go @@ -1,6 +1,7 @@ package webhooks import ( + "net/http" "os" "path" "strings" @@ -72,6 +73,32 @@ var _ = Describe("Hyperconverged API: Webhook", func() { }) }) + + Context("test conversion", func() { + var ( + cl client.Client + mgr manager.Manager + ) + + BeforeEach(func() { + cl = commontestutils.InitClient([]client.Object{}) + var err error + opt := manager.Options{ + Scheme: cl.Scheme(), + Logger: GinkgoLogr, + WebhookServer: webhook.NewServer(webhook.Options{ + Port: 8443, + WebhookMux: &http.ServeMux{}, + }), + } + mgr, err = commontestutils.NewManagerMock(&rest.Config{}, opt, cl, logger) + Expect(err).ToNot(HaveOccurred()) + }) + + It("should add conversion webhook", func() { + Expect(SetupWebhookWithManager(mgr, false, nil)).To(Succeed()) + }) + }) }) func getTestFilesLocation() string { diff --git a/pkg/webhooks/validator/validator.go b/pkg/webhooks/validator/validator.go index 72b3bfb381..b583ca174b 100644 --- a/pkg/webhooks/validator/validator.go +++ b/pkg/webhooks/validator/validator.go @@ -18,7 +18,6 @@ import ( apierrors "k8s.io/apimachinery/pkg/api/errors" metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" "k8s.io/component-helpers/scheduling/corev1/nodeaffinity" - "k8s.io/utils/strings/slices" "sigs.k8s.io/controller-runtime/pkg/client" "sigs.k8s.io/controller-runtime/pkg/webhook/admission" @@ -27,7 +26,8 @@ import ( cdiv1beta1 "kubevirt.io/containerized-data-importer-api/pkg/apis/core/v1beta1" sspv1beta3 "kubevirt.io/ssp-operator/api/v1beta3" - "github.com/kubevirt/hyperconverged-cluster-operator/api/v1beta1" + hcov1 "github.com/kubevirt/hyperconverged-cluster-operator/api/v1" + hcov1beta1 "github.com/kubevirt/hyperconverged-cluster-operator/api/v1beta1" "github.com/kubevirt/hyperconverged-cluster-operator/controllers/handlers" "github.com/kubevirt/hyperconverged-cluster-operator/pkg/nodeinfo" hcoutil "github.com/kubevirt/hyperconverged-cluster-operator/pkg/util" @@ -63,7 +63,12 @@ type WebhookHandler struct { decoder admission.Decoder } -var hcoTLSConfigCache *openshiftconfigv1.TLSSecurityProfile +const decodeErrorMsg = "failed to decode the request" + +var ( + hcoTLSConfigCache *openshiftconfigv1.TLSSecurityProfile + errDecode = errors.New(decodeErrorMsg) +) func NewWebhookHandler(logger logr.Logger, cli client.Client, decoder admission.Decoder, namespace string, isOpenshift bool, hcoTLSSecurityProfile *openshiftconfigv1.TLSSecurityProfile) *WebhookHandler { hcoTLSConfigCache = hcoTLSSecurityProfile @@ -79,26 +84,50 @@ func NewWebhookHandler(logger logr.Logger, cli client.Client, decoder admission. func (wh *WebhookHandler) Handle(ctx context.Context, req admission.Request) admission.Response { ctx = admission.NewContextWithRequest(ctx, req) + logger := logr.FromContextOrDiscard(ctx) // Get the object in the request - obj := &v1beta1.HyperConverged{} + obj := &hcov1beta1.HyperConverged{} dryRun := req.DryRun != nil && *req.DryRun var err error switch req.Operation { case admissionv1.Create: - if err := wh.decoder.Decode(req, obj); err != nil { + v1obj := &hcov1.HyperConverged{} + if err = wh.decoder.Decode(req, v1obj); err != nil { + logger.Error(err, decodeErrorMsg) + return admission.Errored(http.StatusBadRequest, errDecode) + } + + if err = obj.ConvertFrom(v1obj); err != nil { + logger.Error(err, decodeErrorMsg) return admission.Errored(http.StatusBadRequest, err) } err = wh.ValidateCreate(ctx, dryRun, obj) case admissionv1.Update: - oldObj := &v1beta1.HyperConverged{} - if err := wh.decoder.DecodeRaw(req.Object, obj); err != nil { + v1obj := &hcov1.HyperConverged{} + if err = wh.decoder.DecodeRaw(req.Object, v1obj); err != nil { + logger.Error(err, decodeErrorMsg) + return admission.Errored(http.StatusBadRequest, errDecode) + } + + if err = obj.ConvertFrom(v1obj); err != nil { + logger.Error(err, decodeErrorMsg) return admission.Errored(http.StatusBadRequest, err) } - if err := wh.decoder.DecodeRaw(req.OldObject, oldObj); err != nil { + + oldObj := &hcov1beta1.HyperConverged{} + v1OldObj := &hcov1.HyperConverged{} + + if err = wh.decoder.DecodeRaw(req.OldObject, v1OldObj); err != nil { + logger.Error(err, decodeErrorMsg) + return admission.Errored(http.StatusBadRequest, errDecode) + } + + if err = oldObj.ConvertFrom(v1OldObj); err != nil { + logger.Error(err, decodeErrorMsg) return admission.Errored(http.StatusBadRequest, err) } @@ -106,7 +135,16 @@ func (wh *WebhookHandler) Handle(ctx context.Context, req admission.Request) adm case admissionv1.Delete: // In reference to PR: https://github.com/kubernetes/kubernetes/pull/76346 // OldObject contains the object being deleted - if err := wh.decoder.DecodeRaw(req.OldObject, obj); err != nil { + + v1obj := &hcov1.HyperConverged{} + + if err = wh.decoder.DecodeRaw(req.OldObject, v1obj); err != nil { + logger.Error(err, decodeErrorMsg) + return admission.Errored(http.StatusBadRequest, errDecode) + } + + if err = obj.ConvertFrom(v1obj); err != nil { + logger.Error(err, decodeErrorMsg) return admission.Errored(http.StatusBadRequest, err) } @@ -116,25 +154,27 @@ func (wh *WebhookHandler) Handle(ctx context.Context, req admission.Request) adm } // Check the error message first. - if err != nil { - var apiStatus apierrors.APIStatus - if errors.As(err, &apiStatus) { - return validationResponseFromStatus(false, apiStatus.Status()) - } + return getAdmissionResponse(err) +} - var vw *ValidationWarning - if errors.As(err, &vw) { - return admission.Allowed("").WithWarnings(vw.Warnings()...) - } +func getAdmissionResponse(err error) admission.Response { + if err == nil { + return admission.Allowed("") + } + var apiStatus apierrors.APIStatus + if errors.As(err, &apiStatus) { + return validationResponseFromStatus(false, apiStatus.Status()) + } - return admission.Denied(err.Error()) + var vw *ValidationWarning + if errors.As(err, &vw) { + return admission.Allowed("").WithWarnings(vw.Warnings()...) } - // Return allowed if everything succeeded. - return admission.Allowed("") + return admission.Denied(err.Error()) } -func (wh *WebhookHandler) ValidateCreate(_ context.Context, dryrun bool, hc *v1beta1.HyperConverged) error { +func (wh *WebhookHandler) ValidateCreate(_ context.Context, dryrun bool, hc *hcov1beta1.HyperConverged) error { wh.logger.Info("Validating create", "name", hc.Name, "namespace:", hc.Namespace) if err := wh.validateCertConfig(hc); err != nil { @@ -149,14 +189,6 @@ func (wh *WebhookHandler) ValidateCreate(_ context.Context, dryrun bool, hc *v1b return err } - if err := wh.validateMediatedDeviceTypes(hc); err != nil { - return err - } - - if err := wh.validateFeatureGatesOnCreate(hc); err != nil { - return err - } - if err := wh.validateTuningPolicy(hc); err != nil { return err } @@ -188,7 +220,7 @@ func (wh *WebhookHandler) ValidateCreate(_ context.Context, dryrun bool, hc *v1b return nil } -func (wh *WebhookHandler) getOperands(requested *v1beta1.HyperConverged) (*kubevirtcorev1.KubeVirt, *cdiv1beta1.CDI, *networkaddonsv1.NetworkAddonsConfig, error) { +func (wh *WebhookHandler) getOperands(requested *hcov1beta1.HyperConverged) (*kubevirtcorev1.KubeVirt, *cdiv1beta1.CDI, *networkaddonsv1.NetworkAddonsConfig, error) { if err := wh.validateCertConfig(requested); err != nil { return nil, nil, nil, err } @@ -213,7 +245,7 @@ func (wh *WebhookHandler) getOperands(requested *v1beta1.HyperConverged) (*kubev // ValidateUpdate is the ValidateUpdate webhook implementation. It calls all the resources in parallel, to dry-run the // upgrade. -func (wh *WebhookHandler) ValidateUpdate(ctx context.Context, dryrun bool, requested *v1beta1.HyperConverged, exists *v1beta1.HyperConverged) error { +func (wh *WebhookHandler) ValidateUpdate(ctx context.Context, dryrun bool, requested *hcov1beta1.HyperConverged, exists *hcov1beta1.HyperConverged) error { wh.logger.Info("Validating update", "name", requested.Name) if err := wh.validateDataImportCronTemplates(requested); err != nil { @@ -224,14 +256,6 @@ func (wh *WebhookHandler) ValidateUpdate(ctx context.Context, dryrun bool, reque return err } - if err := wh.validateMediatedDeviceTypes(requested); err != nil { - return err - } - - if err := wh.validateFeatureGatesOnUpdate(requested, exists); err != nil { - return err - } - if err := wh.validateTuningPolicy(requested); err != nil { return err } @@ -305,7 +329,7 @@ func (wh *WebhookHandler) ValidateUpdate(ctx context.Context, dryrun bool, reque return nil } -func (wh *WebhookHandler) updateOperatorCr(ctx context.Context, hc *v1beta1.HyperConverged, exists client.Object, opts *client.UpdateOptions) error { +func (wh *WebhookHandler) updateOperatorCr(ctx context.Context, hc *hcov1beta1.HyperConverged, exists client.Object, opts *client.UpdateOptions) error { err := hcoutil.GetRuntimeObject(ctx, wh.cli, exists) if err != nil { wh.logger.Error(err, "failed to get object from kubernetes", "kind", exists.GetObjectKind()) @@ -351,7 +375,7 @@ func (wh *WebhookHandler) updateOperatorCr(ctx context.Context, hc *v1beta1.Hype return nil } -func (wh *WebhookHandler) ValidateDelete(ctx context.Context, dryrun bool, hc *v1beta1.HyperConverged) error { +func (wh *WebhookHandler) ValidateDelete(ctx context.Context, dryrun bool, hc *hcov1beta1.HyperConverged) error { wh.logger.Info("Validating delete", "name", hc.Name, "namespace", hc.Namespace) kv := handlers.NewKubeVirtWithNameOnly(hc) @@ -373,7 +397,7 @@ func (wh *WebhookHandler) ValidateDelete(ctx context.Context, dryrun bool, hc *v return nil } -func (wh *WebhookHandler) validateCertConfig(hc *v1beta1.HyperConverged) error { +func (wh *WebhookHandler) validateCertConfig(hc *hcov1beta1.HyperConverged) error { minimalDuration := metav1.Duration{Duration: 10 * time.Minute} ccValues := make(map[string]time.Duration) @@ -403,7 +427,7 @@ func (wh *WebhookHandler) validateCertConfig(hc *v1beta1.HyperConverged) error { return nil } -func (wh *WebhookHandler) validateDataImportCronTemplates(hc *v1beta1.HyperConverged) error { +func (wh *WebhookHandler) validateDataImportCronTemplates(hc *hcov1beta1.HyperConverged) error { for _, dict := range hc.Spec.DataImportCronTemplates { val, ok := dict.Annotations[hcoutil.DataImportCronEnabledAnnotation] @@ -422,7 +446,7 @@ func (wh *WebhookHandler) validateDataImportCronTemplates(hc *v1beta1.HyperConve return nil } -func (wh *WebhookHandler) validateTLSSecurityProfiles(hc *v1beta1.HyperConverged) error { +func (wh *WebhookHandler) validateTLSSecurityProfiles(hc *hcov1beta1.HyperConverged) error { tlsSP := hc.Spec.TLSSecurityProfile if tlsSP == nil || tlsSP.Custom == nil { @@ -442,82 +466,14 @@ func (wh *WebhookHandler) validateTLSSecurityProfiles(hc *v1beta1.HyperConverged return nil } -func (wh *WebhookHandler) validateMediatedDeviceTypes(hc *v1beta1.HyperConverged) error { - mdc := hc.Spec.MediatedDevicesConfiguration - if mdc != nil { - if len(mdc.MediatedDevicesTypes) > 0 && len(mdc.MediatedDeviceTypes) > 0 && !slices.Equal(mdc.MediatedDevicesTypes, mdc.MediatedDeviceTypes) { //nolint SA1019 - return fmt.Errorf("mediatedDevicesTypes is deprecated, please use mediatedDeviceTypes instead") - } - for _, nmdc := range mdc.NodeMediatedDeviceTypes { - if len(nmdc.MediatedDevicesTypes) > 0 && len(nmdc.MediatedDeviceTypes) > 0 && !slices.Equal(nmdc.MediatedDevicesTypes, nmdc.MediatedDeviceTypes) { //nolint SA1019 - return fmt.Errorf("mediatedDevicesTypes is deprecated, please use mediatedDeviceTypes instead") - } - } - } - return nil -} - -func (wh *WebhookHandler) validateTuningPolicy(hc *v1beta1.HyperConverged) error { - if hc.Spec.TuningPolicy == v1beta1.HyperConvergedHighBurstProfile { //nolint SA1019 +func (wh *WebhookHandler) validateTuningPolicy(hc *hcov1beta1.HyperConverged) error { + if hc.Spec.TuningPolicy == hcov1beta1.HyperConvergedHighBurstProfile { //nolint SA1019 return newValidationWarning([]string{"spec.tuningPolicy: the highBurst profile is deprecated as of v1.16.0 and will be removed in a future release"}) } return nil } -const ( - fgMovedWarning = "spec.featureGates.%[1]s is deprecated and ignored. It will removed in a future version; use spec.%[1]s instead" - fgDeprecationWarning = "spec.featureGates.%s is deprecated and ignored. It will be removed in a future version;" -) - -func (wh *WebhookHandler) validateFeatureGatesOnCreate(hc *v1beta1.HyperConverged) error { - warnings := wh.validateDeprecatedFeatureGates(hc) - warnings = validateOldFGOnCreate(warnings, hc) - - if len(warnings) > 0 { - return newValidationWarning(warnings) - } - - return nil -} - -func (wh *WebhookHandler) validateFeatureGatesOnUpdate(requested, exists *v1beta1.HyperConverged) error { - warnings := wh.validateDeprecatedFeatureGates(requested) - warnings = validateOldFGOnUpdate(warnings, requested, exists) - - if len(warnings) > 0 { - return newValidationWarning(warnings) - } - - return nil -} - -func (wh *WebhookHandler) validateDeprecatedFeatureGates(hc *v1beta1.HyperConverged) []string { - var warnings []string - - //nolint:staticcheck - if hc.Spec.FeatureGates.WithHostPassthroughCPU != nil { - warnings = append(warnings, fmt.Sprintf(fgDeprecationWarning, "withHostPassthroughCPU")) - } - - //nolint:staticcheck - if hc.Spec.FeatureGates.DeployTektonTaskResources != nil { - warnings = append(warnings, fmt.Sprintf(fgDeprecationWarning, "deployTektonTaskResources")) - } - - //nolint:staticcheck - if hc.Spec.FeatureGates.NonRoot != nil { - warnings = append(warnings, fmt.Sprintf(fgDeprecationWarning, "nonRoot")) - } - - //nolint:staticcheck - if hc.Spec.FeatureGates.EnableManagedTenantQuota != nil { - warnings = append(warnings, fmt.Sprintf(fgDeprecationWarning, "enableManagedTenantQuota")) - } - - return warnings -} - -func (wh *WebhookHandler) validateAffinity(hc *v1beta1.HyperConverged) error { +func (wh *WebhookHandler) validateAffinity(hc *hcov1beta1.HyperConverged) error { if hc.Spec.Workloads.NodePlacement != nil { if err := validateAffinity(hc.Spec.Workloads.NodePlacement.Affinity); err != nil { return fmt.Errorf("invalid workloads node placement affinity: %v", err.Error()) @@ -543,48 +499,6 @@ func validateAffinity(affinity *corev1.Affinity) error { return err } -func validateOldFGOnCreate(warnings []string, hc *v1beta1.HyperConverged) []string { - //nolint:staticcheck - if hc.Spec.FeatureGates.EnableApplicationAwareQuota != nil { - warnings = append(warnings, fmt.Sprintf(fgMovedWarning, "enableApplicationAwareQuota")) - } - - //nolint:staticcheck - if hc.Spec.FeatureGates.EnableCommonBootImageImport != nil { - warnings = append(warnings, fmt.Sprintf(fgMovedWarning, "enableCommonBootImageImport")) - } - - //nolint:staticcheck - if hc.Spec.FeatureGates.DeployVMConsoleProxy != nil { - warnings = append(warnings, fmt.Sprintf(fgMovedWarning, "deployVmConsoleProxy")) - } - - return warnings -} - -func validateOldFGOnUpdate(warnings []string, hc, prevHC *v1beta1.HyperConverged) []string { - //nolint:staticcheck - if oldFGChanged(hc.Spec.FeatureGates.EnableApplicationAwareQuota, prevHC.Spec.FeatureGates.EnableApplicationAwareQuota) { - warnings = append(warnings, fmt.Sprintf(fgMovedWarning, "enableApplicationAwareQuota")) - } - - //nolint:staticcheck - if oldFGChanged(hc.Spec.FeatureGates.EnableCommonBootImageImport, prevHC.Spec.FeatureGates.EnableCommonBootImageImport) { - warnings = append(warnings, fmt.Sprintf(fgMovedWarning, "enableCommonBootImageImport")) - } - - //nolint:staticcheck - if oldFGChanged(hc.Spec.FeatureGates.DeployVMConsoleProxy, prevHC.Spec.FeatureGates.DeployVMConsoleProxy) { - warnings = append(warnings, fmt.Sprintf(fgMovedWarning, "deployVmConsoleProxy")) - } - - return warnings -} - -func oldFGChanged(newFG, prevFG *bool) bool { - return newFG != nil && (prevFG == nil || *newFG != *prevFG) -} - func hasRequiredHTTP2Ciphers(ciphers []string) bool { var requiredHTTP2Ciphers = []string{ "ECDHE-RSA-AES128-GCM-SHA256", diff --git a/pkg/webhooks/validator/validator_suite_test.go b/pkg/webhooks/validator/validator_suite_test.go new file mode 100644 index 0000000000..893e9b7a12 --- /dev/null +++ b/pkg/webhooks/validator/validator_suite_test.go @@ -0,0 +1,13 @@ +package validator + +import ( + "testing" + + . "github.com/onsi/ginkgo/v2" + . "github.com/onsi/gomega" +) + +func TestValidatorWebhook(t *testing.T) { + RegisterFailHandler(Fail) + RunSpecs(t, "Validator Webhooks Suite") +} diff --git a/pkg/webhooks/validator/validator_test.go b/pkg/webhooks/validator/validator_test.go index eb7e99ddcd..0d548dacb0 100644 --- a/pkg/webhooks/validator/validator_test.go +++ b/pkg/webhooks/validator/validator_test.go @@ -4,9 +4,9 @@ import ( "context" "errors" "os" - "testing" "time" + "github.com/go-logr/logr" . "github.com/onsi/ginkgo/v2" . "github.com/onsi/gomega" "github.com/onsi/gomega/types" @@ -30,7 +30,8 @@ import ( sdkapi "kubevirt.io/controller-lifecycle-operator-sdk/api" sspv1beta3 "kubevirt.io/ssp-operator/api/v1beta3" - "github.com/kubevirt/hyperconverged-cluster-operator/api/v1beta1" + hcov1 "github.com/kubevirt/hyperconverged-cluster-operator/api/v1" + hcov1beta1 "github.com/kubevirt/hyperconverged-cluster-operator/api/v1beta1" "github.com/kubevirt/hyperconverged-cluster-operator/controllers/common" "github.com/kubevirt/hyperconverged-cluster-operator/controllers/commontestutils" "github.com/kubevirt/hyperconverged-cluster-operator/controllers/handlers" @@ -46,11 +47,6 @@ var ( logger = zap.New(zap.WriteTo(GinkgoWriter), zap.UseDevMode(true)).WithName("hyperconverged-resource") ) -func TestValidatorWebhook(t *testing.T) { - RegisterFailHandler(Fail) - RunSpecs(t, "Validator Webhooks Suite") -} - const ( validKvAnnotation = `[ { @@ -106,10 +102,10 @@ const ( invalidSspAnnotation = `[{"op": "wrongOp", "path": "/spec/templateValidator/replicas", "value": 5}]` ) -var _ = Describe("webhooks validator", func() { +var _ = Describe("v1 webhooks validator", func() { s := scheme.Scheme for _, f := range []func(*runtime.Scheme) error{ - v1beta1.AddToScheme, + hcov1.AddToScheme, cdiv1beta1.AddToScheme, kubevirtcorev1.AddToScheme, networkaddonsv1.AddToScheme, @@ -119,1695 +115,1455 @@ var _ = Describe("webhooks validator", func() { } codecFactory := serializer.NewCodecFactory(s) - v1beta1Codec := codecFactory.LegacyCodec(v1beta1.SchemeGroupVersion) + v1Codec := codecFactory.LegacyCodec(hcov1.SchemeGroupVersion) cli := fake.NewClientBuilder().WithScheme(s).Build() decoder := admission.NewDecoder(s) wh := NewWebhookHandler(logger, cli, decoder, HcoValidNamespace, true, nil) + var dryRun bool + BeforeEach(func() { + Expect(os.Setenv("OPERATOR_NAMESPACE", HcoValidNamespace)).To(Succeed()) + dryRun = false + }) + Context("Check create validation webhook", func() { - var cr *v1beta1.HyperConverged - var dryRun bool - var ctx context.Context - BeforeEach(func() { - Expect(os.Setenv("OPERATOR_NAMESPACE", HcoValidNamespace)).To(Succeed()) - cr = commontestutils.NewHco() - dryRun = false - ctx = context.TODO() - }) + Context("check create request", func() { + var v1cr *hcov1.HyperConverged - It("should correctly handle a valid creation request", func() { - req := newRequest(admissionv1.Create, cr, v1beta1Codec, false) + BeforeEach(func() { + v1cr = commontestutils.NewV1HCO() + }) - res := wh.Handle(ctx, req) - Expect(res.Allowed).To(BeTrue()) - Expect(res.Result.Code).To(Equal(int32(200))) - }) + It("should correctly handle a valid creation request", func(ctx context.Context) { + ctx = logr.NewContext(ctx, GinkgoLogr) + req := newRequest(admissionv1.Create, v1cr, v1Codec, false) - It("should correctly handle a valid dryrun creation request", func() { - req := newRequest(admissionv1.Create, cr, v1beta1Codec, true) + res := wh.Handle(ctx, req) + Expect(res.Allowed).To(BeTrue()) + Expect(res.Result.Code).To(Equal(int32(200))) + }) - res := wh.Handle(ctx, req) - Expect(res.Allowed).To(BeTrue()) - Expect(res.Result.Code).To(Equal(int32(200))) - }) + It("should correctly handle a valid dryrun creation request", func(ctx context.Context) { + req := newRequest(admissionv1.Create, v1cr, v1Codec, true) - It("should reject malformed creation requests", func() { - req := newRequest(admissionv1.Create, cr, v1beta1Codec, false) - req.OldObject = req.Object - req.Object = runtime.RawExtension{} + res := wh.Handle(ctx, req) + Expect(res.Allowed).To(BeTrue()) + Expect(res.Result.Code).To(Equal(int32(200))) + }) - res := wh.Handle(ctx, req) - Expect(res.Allowed).To(BeFalse()) - Expect(res.Result.Code).To(Equal(int32(400))) - Expect(res.Result.Message).To(Equal("there is no content to decode")) + It("should reject malformed creation requests", func(ctx context.Context) { + ctx = logr.NewContext(ctx, GinkgoLogr) + req := newRequest(admissionv1.Create, v1cr, v1Codec, false) + req.OldObject = req.Object + req.Object = runtime.RawExtension{} - req = newRequest(admissionv1.Create, cr, v1beta1Codec, false) - req.Operation = "MALFORMED" + res := wh.Handle(ctx, req) + Expect(res.Allowed).To(BeFalse()) + Expect(res.Result.Code).To(Equal(int32(400))) + Expect(res.Result.Message).To(Equal(decodeErrorMsg)) - res = wh.Handle(ctx, req) - Expect(res.Allowed).To(BeFalse()) - Expect(res.Result.Code).To(Equal(int32(400))) - Expect(res.Result.Message).To(Equal("unknown operation request \"MALFORMED\"")) - }) + req = newRequest(admissionv1.Create, v1cr, v1Codec, false) + req.Operation = "MALFORMED" - It("should accept creation of a resource with a valid namespace", func() { - Expect(wh.ValidateCreate(ctx, dryRun, cr)).To(Succeed()) + res = wh.Handle(ctx, req) + Expect(res.Allowed).To(BeFalse()) + Expect(res.Result.Code).To(Equal(int32(400))) + Expect(res.Result.Message).To(Equal("unknown operation request \"MALFORMED\"")) + }) }) - DescribeTable("Validate annotations", func(annotations map[string]string, assertion types.GomegaMatcher) { - cr.Annotations = annotations - Expect(wh.ValidateCreate(ctx, dryRun, cr)).To(assertion) - }, - Entry("should accept creation of a resource with a valid kv annotation", - map[string]string{common.JSONPatchKVAnnotationName: validKvAnnotation}, - Succeed(), - ), - Entry("should reject creation of a resource with an invalid kv annotation", - map[string]string{common.JSONPatchKVAnnotationName: invalidKvAnnotation}, - Not(Succeed()), - ), - Entry("should accept creation of a resource with a valid cdi annotation", - map[string]string{common.JSONPatchCDIAnnotationName: validCdiAnnotation}, - Succeed(), - ), - Entry("should reject creation of a resource with an invalid cdi annotation", - map[string]string{common.JSONPatchCDIAnnotationName: invalidCdiAnnotation}, - Not(Succeed()), - ), - Entry("should accept creation of a resource with a valid cna annotation", - map[string]string{common.JSONPatchCNAOAnnotationName: validCnaAnnotation}, - Succeed(), - ), - Entry("should reject creation of a resource with an invalid cna annotation", - map[string]string{common.JSONPatchCNAOAnnotationName: invalidCnaAnnotation}, - Not(Succeed()), - ), - Entry("should accept creation of a resource with a valid ssp annotation", - map[string]string{common.JSONPatchSSPAnnotationName: validSspAnnotation}, - Succeed(), - ), - Entry("should reject creation of a resource with an invalid ssp annotation", - map[string]string{common.JSONPatchSSPAnnotationName: invalidSspAnnotation}, - Not(Succeed()), - ), - ) - - Context("test permitted host devices validation", func() { - It("should allow unique PCI Host Device", func() { - cr.Spec.PermittedHostDevices = &v1beta1.PermittedHostDevices{ - PciHostDevices: []v1beta1.PciHostDevice{ - { - PCIDeviceSelector: "111", - ResourceName: "name", - }, - { - PCIDeviceSelector: "222", - ResourceName: "name", - }, - { - PCIDeviceSelector: "333", - ResourceName: "name", - }, - }, - } + Context("check ValidateCreate", func() { + var cr *hcov1beta1.HyperConverged + BeforeEach(func() { + cr = commontestutils.NewHco() + }) + + It("should accept creation of a resource with a valid namespace", func(ctx context.Context) { Expect(wh.ValidateCreate(ctx, dryRun, cr)).To(Succeed()) }) - It("should allow unique Mediate Host Device", func() { - cr.Spec.PermittedHostDevices = &v1beta1.PermittedHostDevices{ - MediatedDevices: []v1beta1.MediatedHostDevice{ - { - MDEVNameSelector: "111", - ResourceName: "name", - }, - { - MDEVNameSelector: "222", - ResourceName: "name", + DescribeTable("Validate annotations", func(ctx context.Context, annotations map[string]string, assertion types.GomegaMatcher) { + cr.Annotations = annotations + Expect(wh.ValidateCreate(ctx, dryRun, cr)).To(assertion) + }, + Entry("should accept creation of a resource with a valid kv annotation", + map[string]string{common.JSONPatchKVAnnotationName: validKvAnnotation}, + Succeed(), + ), + Entry("should reject creation of a resource with an invalid kv annotation", + map[string]string{common.JSONPatchKVAnnotationName: invalidKvAnnotation}, + Not(Succeed()), + ), + Entry("should accept creation of a resource with a valid cdi annotation", + map[string]string{common.JSONPatchCDIAnnotationName: validCdiAnnotation}, + Succeed(), + ), + Entry("should reject creation of a resource with an invalid cdi annotation", + map[string]string{common.JSONPatchCDIAnnotationName: invalidCdiAnnotation}, + Not(Succeed()), + ), + Entry("should accept creation of a resource with a valid cna annotation", + map[string]string{common.JSONPatchCNAOAnnotationName: validCnaAnnotation}, + Succeed(), + ), + Entry("should reject creation of a resource with an invalid cna annotation", + map[string]string{common.JSONPatchCNAOAnnotationName: invalidCnaAnnotation}, + Not(Succeed()), + ), + Entry("should accept creation of a resource with a valid ssp annotation", + map[string]string{common.JSONPatchSSPAnnotationName: validSspAnnotation}, + Succeed(), + ), + Entry("should reject creation of a resource with an invalid ssp annotation", + map[string]string{common.JSONPatchSSPAnnotationName: invalidSspAnnotation}, + Not(Succeed()), + ), + ) + + Context("test permitted host devices validation", func() { + It("should allow unique PCI Host Device", func(ctx context.Context) { + cr.Spec.PermittedHostDevices = &hcov1beta1.PermittedHostDevices{ + PciHostDevices: []hcov1beta1.PciHostDevice{ + { + PCIDeviceSelector: "111", + ResourceName: "name", + }, + { + PCIDeviceSelector: "222", + ResourceName: "name", + }, + { + PCIDeviceSelector: "333", + ResourceName: "name", + }, }, - { - MDEVNameSelector: "333", - ResourceName: "name", + } + Expect(wh.ValidateCreate(ctx, dryRun, cr)).To(Succeed()) + }) + + It("should allow unique Mediate Host Device", func(ctx context.Context) { + cr.Spec.PermittedHostDevices = &hcov1beta1.PermittedHostDevices{ + MediatedDevices: []hcov1beta1.MediatedHostDevice{ + { + MDEVNameSelector: "111", + ResourceName: "name", + }, + { + MDEVNameSelector: "222", + ResourceName: "name", + }, + { + MDEVNameSelector: "333", + ResourceName: "name", + }, }, - }, - } - Expect(wh.ValidateCreate(ctx, dryRun, cr)).To(Succeed()) + } + Expect(wh.ValidateCreate(ctx, dryRun, cr)).To(Succeed()) + }) }) - }) - Context("Test DataImportCronTemplates", func() { - var image1, image2, image3, image4 v1beta1.DataImportCronTemplate + Context("Test DataImportCronTemplates", func() { + var image1, image2, image3, image4 hcov1beta1.DataImportCronTemplate - var dryRun bool - var ctx context.Context + BeforeEach(func() { + dryRun = false - BeforeEach(func() { - dryRun = false - ctx = context.TODO() - - image1 = v1beta1.DataImportCronTemplate{ - ObjectMeta: metav1.ObjectMeta{Name: "image1"}, - Spec: &cdiv1beta1.DataImportCronSpec{ - Schedule: "1 */12 * * *", - Template: cdiv1beta1.DataVolume{ - Spec: cdiv1beta1.DataVolumeSpec{ - Source: &cdiv1beta1.DataVolumeSource{ - Registry: &cdiv1beta1.DataVolumeSourceRegistry{URL: ptr.To("docker://someregistry/image1")}, + image1 = hcov1beta1.DataImportCronTemplate{ + ObjectMeta: metav1.ObjectMeta{Name: "image1"}, + Spec: &cdiv1beta1.DataImportCronSpec{ + Schedule: "1 */12 * * *", + Template: cdiv1beta1.DataVolume{ + Spec: cdiv1beta1.DataVolumeSpec{ + Source: &cdiv1beta1.DataVolumeSource{ + Registry: &cdiv1beta1.DataVolumeSourceRegistry{URL: ptr.To("docker://someregistry/image1")}, + }, }, }, + ManagedDataSource: "image1", }, - ManagedDataSource: "image1", - }, - } + } - image2 = v1beta1.DataImportCronTemplate{ - ObjectMeta: metav1.ObjectMeta{Name: "image2"}, - Spec: &cdiv1beta1.DataImportCronSpec{ - Schedule: "2 */12 * * *", - Template: cdiv1beta1.DataVolume{ - Spec: cdiv1beta1.DataVolumeSpec{ - Source: &cdiv1beta1.DataVolumeSource{ - Registry: &cdiv1beta1.DataVolumeSourceRegistry{URL: ptr.To("docker://someregistry/image2")}, + image2 = hcov1beta1.DataImportCronTemplate{ + ObjectMeta: metav1.ObjectMeta{Name: "image2"}, + Spec: &cdiv1beta1.DataImportCronSpec{ + Schedule: "2 */12 * * *", + Template: cdiv1beta1.DataVolume{ + Spec: cdiv1beta1.DataVolumeSpec{ + Source: &cdiv1beta1.DataVolumeSource{ + Registry: &cdiv1beta1.DataVolumeSourceRegistry{URL: ptr.To("docker://someregistry/image2")}, + }, }, }, + ManagedDataSource: "image2", }, - ManagedDataSource: "image2", - }, - } + } - image3 = v1beta1.DataImportCronTemplate{ - ObjectMeta: metav1.ObjectMeta{Name: "image3"}, - Spec: &cdiv1beta1.DataImportCronSpec{ - Schedule: "3 */12 * * *", - Template: cdiv1beta1.DataVolume{ - Spec: cdiv1beta1.DataVolumeSpec{ - Source: &cdiv1beta1.DataVolumeSource{ - Registry: &cdiv1beta1.DataVolumeSourceRegistry{URL: ptr.To("docker://someregistry/image3")}, + image3 = hcov1beta1.DataImportCronTemplate{ + ObjectMeta: metav1.ObjectMeta{Name: "image3"}, + Spec: &cdiv1beta1.DataImportCronSpec{ + Schedule: "3 */12 * * *", + Template: cdiv1beta1.DataVolume{ + Spec: cdiv1beta1.DataVolumeSpec{ + Source: &cdiv1beta1.DataVolumeSource{ + Registry: &cdiv1beta1.DataVolumeSourceRegistry{URL: ptr.To("docker://someregistry/image3")}, + }, }, }, + ManagedDataSource: "image3", }, - ManagedDataSource: "image3", - }, - } + } - image4 = v1beta1.DataImportCronTemplate{ - ObjectMeta: metav1.ObjectMeta{Name: "image4"}, - Spec: &cdiv1beta1.DataImportCronSpec{ - Schedule: "4 */12 * * *", - Template: cdiv1beta1.DataVolume{ - Spec: cdiv1beta1.DataVolumeSpec{ - Source: &cdiv1beta1.DataVolumeSource{ - Registry: &cdiv1beta1.DataVolumeSourceRegistry{URL: ptr.To("docker://someregistry/image4")}, + image4 = hcov1beta1.DataImportCronTemplate{ + ObjectMeta: metav1.ObjectMeta{Name: "image4"}, + Spec: &cdiv1beta1.DataImportCronSpec{ + Schedule: "4 */12 * * *", + Template: cdiv1beta1.DataVolume{ + Spec: cdiv1beta1.DataVolumeSpec{ + Source: &cdiv1beta1.DataVolumeSource{ + Registry: &cdiv1beta1.DataVolumeSourceRegistry{URL: ptr.To("docker://someregistry/image4")}, + }, }, }, + ManagedDataSource: "image4", }, - ManagedDataSource: "image4", - }, - } - - cr.Spec.DataImportCronTemplates = []v1beta1.DataImportCronTemplate{image1, image2, image3, image4} - }) - - It("should allow setting the annotation to true", func() { - cr.Spec.DataImportCronTemplates[0].Annotations = map[string]string{util.DataImportCronEnabledAnnotation: "true"} - cr.Spec.DataImportCronTemplates[1].Annotations = map[string]string{util.DataImportCronEnabledAnnotation: "TRUE"} - cr.Spec.DataImportCronTemplates[2].Annotations = map[string]string{util.DataImportCronEnabledAnnotation: "TrUe"} - cr.Spec.DataImportCronTemplates[3].Annotations = map[string]string{util.DataImportCronEnabledAnnotation: "tRuE"} - - Expect(wh.ValidateCreate(ctx, dryRun, cr)).To(Succeed()) - }) - - It("should allow setting the annotation to false", func() { - cr.Spec.DataImportCronTemplates[0].Annotations = map[string]string{util.DataImportCronEnabledAnnotation: "false"} - cr.Spec.DataImportCronTemplates[1].Annotations = map[string]string{util.DataImportCronEnabledAnnotation: "FALSE"} - cr.Spec.DataImportCronTemplates[2].Annotations = map[string]string{util.DataImportCronEnabledAnnotation: "FaLsE"} - cr.Spec.DataImportCronTemplates[3].Annotations = map[string]string{util.DataImportCronEnabledAnnotation: "fAlSe"} + } - Expect(wh.ValidateCreate(ctx, dryRun, cr)).To(Succeed()) - }) + cr.Spec.DataImportCronTemplates = []hcov1beta1.DataImportCronTemplate{image1, image2, image3, image4} + }) - It("should allow setting no annotation", func() { - Expect(wh.ValidateCreate(ctx, dryRun, cr)).To(Succeed()) - }) + It("should allow setting the annotation to true", func(ctx context.Context) { + cr.Spec.DataImportCronTemplates[0].Annotations = map[string]string{util.DataImportCronEnabledAnnotation: "true"} + cr.Spec.DataImportCronTemplates[1].Annotations = map[string]string{util.DataImportCronEnabledAnnotation: "TRUE"} + cr.Spec.DataImportCronTemplates[2].Annotations = map[string]string{util.DataImportCronEnabledAnnotation: "TrUe"} + cr.Spec.DataImportCronTemplates[3].Annotations = map[string]string{util.DataImportCronEnabledAnnotation: "tRuE"} - It("should not allow empty annotation", func() { - cr.Spec.DataImportCronTemplates[0].Annotations = map[string]string{util.DataImportCronEnabledAnnotation: ""} - cr.Spec.DataImportCronTemplates[1].Annotations = map[string]string{util.DataImportCronEnabledAnnotation: ""} + Expect(wh.ValidateCreate(ctx, dryRun, cr)).To(Succeed()) + }) - Expect(wh.ValidateCreate(ctx, dryRun, cr)).ToNot(Succeed()) - }) + It("should allow setting the annotation to false", func(ctx context.Context) { + cr.Spec.DataImportCronTemplates[0].Annotations = map[string]string{util.DataImportCronEnabledAnnotation: "false"} + cr.Spec.DataImportCronTemplates[1].Annotations = map[string]string{util.DataImportCronEnabledAnnotation: "FALSE"} + cr.Spec.DataImportCronTemplates[2].Annotations = map[string]string{util.DataImportCronEnabledAnnotation: "FaLsE"} + cr.Spec.DataImportCronTemplates[3].Annotations = map[string]string{util.DataImportCronEnabledAnnotation: "fAlSe"} - It("should not allow unknown annotation values", func() { - cr.Spec.DataImportCronTemplates[0].Annotations = map[string]string{util.DataImportCronEnabledAnnotation: "wrong"} - cr.Spec.DataImportCronTemplates[1].Annotations = map[string]string{util.DataImportCronEnabledAnnotation: "mistake"} + Expect(wh.ValidateCreate(ctx, dryRun, cr)).To(Succeed()) + }) - Expect(wh.ValidateCreate(ctx, dryRun, cr)).ToNot(Succeed()) - }) + It("should allow setting no annotation", func(ctx context.Context) { + Expect(wh.ValidateCreate(ctx, dryRun, cr)).To(Succeed()) + }) - Context("Empty DICT spec", func() { - It("don't allow if the annotation does not exist", func() { - // empty annotation map - cr.Spec.DataImportCronTemplates[0].Annotations = map[string]string{} - cr.Spec.DataImportCronTemplates[0].Spec = nil - // no annotation map - cr.Spec.DataImportCronTemplates[1].Spec = nil + It("should not allow empty annotation", func(ctx context.Context) { + cr.Spec.DataImportCronTemplates[0].Annotations = map[string]string{util.DataImportCronEnabledAnnotation: ""} + cr.Spec.DataImportCronTemplates[1].Annotations = map[string]string{util.DataImportCronEnabledAnnotation: ""} Expect(wh.ValidateCreate(ctx, dryRun, cr)).ToNot(Succeed()) }) - It("don't allow if the annotation is true", func() { - cr.Spec.DataImportCronTemplates[0].Annotations = map[string]string{util.DataImportCronEnabledAnnotation: "True"} - cr.Spec.DataImportCronTemplates[0].Spec = nil - cr.Spec.DataImportCronTemplates[1].Annotations = map[string]string{util.DataImportCronEnabledAnnotation: "true"} - cr.Spec.DataImportCronTemplates[1].Spec = nil + It("should not allow unknown annotation values", func(ctx context.Context) { + cr.Spec.DataImportCronTemplates[0].Annotations = map[string]string{util.DataImportCronEnabledAnnotation: "wrong"} + cr.Spec.DataImportCronTemplates[1].Annotations = map[string]string{util.DataImportCronEnabledAnnotation: "mistake"} Expect(wh.ValidateCreate(ctx, dryRun, cr)).ToNot(Succeed()) }) - It("allow if the annotation is false", func() { - cr.Spec.DataImportCronTemplates[0].Annotations = map[string]string{util.DataImportCronEnabledAnnotation: "False"} - cr.Spec.DataImportCronTemplates[0].Spec = nil - cr.Spec.DataImportCronTemplates[1].Annotations = map[string]string{util.DataImportCronEnabledAnnotation: "false"} - cr.Spec.DataImportCronTemplates[1].Spec = nil - - Expect(wh.ValidateCreate(ctx, dryRun, cr)).To(Succeed()) + Context("Empty DICT spec", func() { + It("don't allow if the annotation does not exist", func(ctx context.Context) { + // empty annotation map + cr.Spec.DataImportCronTemplates[0].Annotations = map[string]string{} + cr.Spec.DataImportCronTemplates[0].Spec = nil + // no annotation map + cr.Spec.DataImportCronTemplates[1].Spec = nil + + Expect(wh.ValidateCreate(ctx, dryRun, cr)).ToNot(Succeed()) + }) + + It("don't allow if the annotation is true", func(ctx context.Context) { + cr.Spec.DataImportCronTemplates[0].Annotations = map[string]string{util.DataImportCronEnabledAnnotation: "True"} + cr.Spec.DataImportCronTemplates[0].Spec = nil + cr.Spec.DataImportCronTemplates[1].Annotations = map[string]string{util.DataImportCronEnabledAnnotation: "true"} + cr.Spec.DataImportCronTemplates[1].Spec = nil + + Expect(wh.ValidateCreate(ctx, dryRun, cr)).ToNot(Succeed()) + }) + + It("allow if the annotation is false", func(ctx context.Context) { + cr.Spec.DataImportCronTemplates[0].Annotations = map[string]string{util.DataImportCronEnabledAnnotation: "False"} + cr.Spec.DataImportCronTemplates[0].Spec = nil + cr.Spec.DataImportCronTemplates[1].Annotations = map[string]string{util.DataImportCronEnabledAnnotation: "false"} + cr.Spec.DataImportCronTemplates[1].Spec = nil + + Expect(wh.ValidateCreate(ctx, dryRun, cr)).To(Succeed()) + }) }) }) - }) - - Context("validate tlsSecurityProfiles", func() { - var dryRun bool - var ctx context.Context - BeforeEach(func() { - dryRun = false - ctx = context.TODO() - }) + Context("validate tlsSecurityProfiles", func() { - updateTLSSecurityProfile := func(minTLSVersion openshiftconfigv1.TLSProtocolVersion, ciphers []string) error { - cr.Spec.TLSSecurityProfile = &openshiftconfigv1.TLSSecurityProfile{ - Custom: &openshiftconfigv1.CustomTLSProfile{ - TLSProfileSpec: openshiftconfigv1.TLSProfileSpec{ - MinTLSVersion: minTLSVersion, - Ciphers: ciphers, + updateTLSSecurityProfile := func(ctx context.Context, minTLSVersion openshiftconfigv1.TLSProtocolVersion, ciphers []string) error { + cr.Spec.TLSSecurityProfile = &openshiftconfigv1.TLSSecurityProfile{ + Custom: &openshiftconfigv1.CustomTLSProfile{ + TLSProfileSpec: openshiftconfigv1.TLSProfileSpec{ + MinTLSVersion: minTLSVersion, + Ciphers: ciphers, + }, }, - }, + } + + return wh.ValidateCreate(ctx, dryRun, cr) } - return wh.ValidateCreate(ctx, dryRun, cr) - } + DescribeTable("should succeed if has any of the HTTP/2-required ciphers", + func(ctx context.Context, cipher string) { + Expect( + updateTLSSecurityProfile(ctx, openshiftconfigv1.VersionTLS12, []string{"DHE-RSA-AES256-GCM-SHA384", cipher, "DHE-RSA-CHACHA20-POLY1305"}), + ).To(Succeed()) + }, + Entry("ECDHE-RSA-AES128-GCM-SHA256", "ECDHE-RSA-AES128-GCM-SHA256"), + Entry("ECDHE-ECDSA-AES128-GCM-SHA256", "ECDHE-ECDSA-AES128-GCM-SHA256"), + ) + + It("should fail if does not have any of the HTTP/2-required ciphers", func(ctx context.Context) { + err := updateTLSSecurityProfile(ctx, openshiftconfigv1.VersionTLS12, []string{"DHE-RSA-AES256-GCM-SHA384", "DHE-RSA-CHACHA20-POLY1305"}) + Expect(err).To(HaveOccurred()) + Expect(err.Error()).To(ContainSubstring("http2: TLSConfig.CipherSuites is missing an HTTP/2-required AES_128_GCM_SHA256 cipher (need at least one of ECDHE-RSA-AES128-GCM-SHA256 or ECDHE-ECDSA-AES128-GCM-SHA256)")) + }) - DescribeTable("should succeed if has any of the HTTP/2-required ciphers", - func(cipher string) { + It("should succeed if does not have any of the HTTP/2-required ciphers but TLS version >= 1.3", func(ctx context.Context) { Expect( - updateTLSSecurityProfile(openshiftconfigv1.VersionTLS12, []string{"DHE-RSA-AES256-GCM-SHA384", cipher, "DHE-RSA-CHACHA20-POLY1305"}), + updateTLSSecurityProfile(ctx, openshiftconfigv1.VersionTLS13, []string{}), ).To(Succeed()) - }, - Entry("ECDHE-RSA-AES128-GCM-SHA256", "ECDHE-RSA-AES128-GCM-SHA256"), - Entry("ECDHE-ECDSA-AES128-GCM-SHA256", "ECDHE-ECDSA-AES128-GCM-SHA256"), - ) - - It("should fail if does not have any of the HTTP/2-required ciphers", func() { - err := updateTLSSecurityProfile(openshiftconfigv1.VersionTLS12, []string{"DHE-RSA-AES256-GCM-SHA384", "DHE-RSA-CHACHA20-POLY1305"}) - Expect(err).To(HaveOccurred()) - Expect(err.Error()).To(ContainSubstring("http2: TLSConfig.CipherSuites is missing an HTTP/2-required AES_128_GCM_SHA256 cipher (need at least one of ECDHE-RSA-AES128-GCM-SHA256 or ECDHE-ECDSA-AES128-GCM-SHA256)")) - }) - - It("should succeed if does not have any of the HTTP/2-required ciphers but TLS version >= 1.3", func() { - Expect( - updateTLSSecurityProfile(openshiftconfigv1.VersionTLS13, []string{}), - ).To(Succeed()) - }) + }) - It("should fail if does have custom ciphers with TLS version >= 1.3", func() { - err := updateTLSSecurityProfile(openshiftconfigv1.VersionTLS13, []string{"TLS_AES_128_GCM_SHA256", "TLS_CHACHA20_POLY1305_SHA256"}) - Expect(err).To(HaveOccurred()) - Expect(err.Error()).To(ContainSubstring("custom ciphers cannot be selected when minTLSVersion is VersionTLS13")) - }) + It("should fail if does have custom ciphers with TLS version >= 1.3", func(ctx context.Context) { + err := updateTLSSecurityProfile(ctx, openshiftconfigv1.VersionTLS13, []string{"TLS_AES_128_GCM_SHA256", "TLS_CHACHA20_POLY1305_SHA256"}) + Expect(err).To(HaveOccurred()) + Expect(err.Error()).To(ContainSubstring("custom ciphers cannot be selected when minTLSVersion is VersionTLS13")) + }) - It("should fail when minTLSVersion is invalid", func() { - err := updateTLSSecurityProfile("invalidProtocolVersion", []string{"TLS_AES_128_GCM_SHA256", "TLS_CHACHA20_POLY1305_SHA256"}) - Expect(err).To(HaveOccurred()) - Expect(err.Error()).To(ContainSubstring("invalid value for spec.tlsSecurityProfile.custom.minTLSVersion")) + It("should fail when minTLSVersion is invalid", func(ctx context.Context) { + err := updateTLSSecurityProfile(ctx, "invalidProtocolVersion", []string{"TLS_AES_128_GCM_SHA256", "TLS_CHACHA20_POLY1305_SHA256"}) + Expect(err).To(HaveOccurred()) + Expect(err.Error()).To(ContainSubstring("invalid value for spec.tlsSecurityProfile.custom.minTLSVersion")) + }) }) - }) - - Context("validate deprecated FGs", func() { - DescribeTable("should return warning for deprecated feature gate", func(fgs v1beta1.HyperConvergedFeatureGates, fgNames ...string) { - cr.Spec.FeatureGates = fgs - err := wh.ValidateCreate(ctx, dryRun, cr) - Expect(err).To(HaveOccurred()) - expected := &ValidationWarning{} - Expect(errors.As(err, &expected)).To(BeTrue()) - - Expect(expected.warnings).To(HaveLen(len(fgNames))) - for _, fgName := range fgNames { - Expect(expected.warnings).To(ContainElements(ContainSubstring(fgName))) - } - }, - Entry("should trigger a warning if the withHostPassthroughCPU=false FG exists in the CR", - v1beta1.HyperConvergedFeatureGates{WithHostPassthroughCPU: ptr.To(false)}, "withHostPassthroughCPU"), - Entry("should trigger a warning if the withHostPassthroughCPU=true FG exists in the CR", - v1beta1.HyperConvergedFeatureGates{WithHostPassthroughCPU: ptr.To(true)}, "withHostPassthroughCPU"), - - Entry("should trigger a warning if the deployTektonTaskResources=false FG exists in the CR", - v1beta1.HyperConvergedFeatureGates{DeployTektonTaskResources: ptr.To(false)}, "deployTektonTaskResources"), - Entry("should trigger a warning if the deployTektonTaskResources=true FG exists in the CR", - v1beta1.HyperConvergedFeatureGates{DeployTektonTaskResources: ptr.To(true)}, "deployTektonTaskResources"), - - Entry("should trigger a warning if the enableManagedTenantQuota=false FG exists in the CR", - v1beta1.HyperConvergedFeatureGates{EnableManagedTenantQuota: ptr.To(false)}, "enableManagedTenantQuota"), - Entry("should trigger a warning if the enableManagedTenantQuota=true FG exists in the CR", - v1beta1.HyperConvergedFeatureGates{EnableManagedTenantQuota: ptr.To(true)}, "enableManagedTenantQuota"), - - Entry("should trigger a warning if the nonRoot=false FG exists in the CR", - v1beta1.HyperConvergedFeatureGates{NonRoot: ptr.To(false)}, "nonRoot"), - Entry("should trigger a warning if the nonRoot=true FG exists in the CR", - v1beta1.HyperConvergedFeatureGates{NonRoot: ptr.To(true)}, "nonRoot"), - - Entry("should trigger multiple warnings if several deprecated FG exist in the CR", - v1beta1.HyperConvergedFeatureGates{ - NonRoot: ptr.To(true), - EnableManagedTenantQuota: ptr.To(true), - }, "enableManagedTenantQuota", "nonRoot"), - - Entry("should trigger multiple warnings if several deprecated FG exist in the CR, with some valid FGs", - v1beta1.HyperConvergedFeatureGates{ - DownwardMetrics: ptr.To(true), - NonRoot: ptr.To(false), - EnableCommonBootImageImport: ptr.To(true), - EnableApplicationAwareQuota: ptr.To(false), - EnableManagedTenantQuota: ptr.To(false), - DeployVMConsoleProxy: ptr.To(false), - DeployKubeSecondaryDNS: ptr.To(false), - }, "enableManagedTenantQuota", "nonRoot", "enableApplicationAwareQuota", "enableCommonBootImageImport", "deployVmConsoleProxy"), - ) - }) - Context("validate affinity", func() { - It("should allow empty affinity", func() { - cr.Spec.Infra.NodePlacement = &sdkapi.NodePlacement{ - Affinity: nil, - } - cr.Spec.Workloads.NodePlacement = &sdkapi.NodePlacement{ - Affinity: nil, - } + Context("validate affinity", func() { + It("should allow empty affinity", func(ctx context.Context) { + cr.Spec.Infra.NodePlacement = &sdkapi.NodePlacement{ + Affinity: nil, + } + cr.Spec.Workloads.NodePlacement = &sdkapi.NodePlacement{ + Affinity: nil, + } - Expect(wh.ValidateCreate(ctx, dryRun, cr)).To(Succeed()) - }) + Expect(wh.ValidateCreate(ctx, dryRun, cr)).To(Succeed()) + }) - It("should allow empty affinity", func() { - cr.Spec.Infra.NodePlacement = &sdkapi.NodePlacement{ - Affinity: &corev1.Affinity{}, - } - cr.Spec.Workloads.NodePlacement = &sdkapi.NodePlacement{ - Affinity: &corev1.Affinity{}, - } + It("should allow empty affinity", func(ctx context.Context) { + cr.Spec.Infra.NodePlacement = &sdkapi.NodePlacement{ + Affinity: &corev1.Affinity{}, + } + cr.Spec.Workloads.NodePlacement = &sdkapi.NodePlacement{ + Affinity: &corev1.Affinity{}, + } - Expect(wh.ValidateCreate(ctx, dryRun, cr)).To(Succeed()) - }) + Expect(wh.ValidateCreate(ctx, dryRun, cr)).To(Succeed()) + }) - It("should allow valid affinity", func() { - cr.Spec.Infra.NodePlacement = &sdkapi.NodePlacement{ - Affinity: &corev1.Affinity{ - NodeAffinity: &corev1.NodeAffinity{ - RequiredDuringSchedulingIgnoredDuringExecution: &corev1.NodeSelector{ - NodeSelectorTerms: []corev1.NodeSelectorTerm{ - { - MatchExpressions: []corev1.NodeSelectorRequirement{ - { - Key: "kubernetes.io/os", - Operator: corev1.NodeSelectorOpIn, - Values: []string{"linux"}, + It("should allow valid affinity", func(ctx context.Context) { + cr.Spec.Infra.NodePlacement = &sdkapi.NodePlacement{ + Affinity: &corev1.Affinity{ + NodeAffinity: &corev1.NodeAffinity{ + RequiredDuringSchedulingIgnoredDuringExecution: &corev1.NodeSelector{ + NodeSelectorTerms: []corev1.NodeSelectorTerm{ + { + MatchExpressions: []corev1.NodeSelectorRequirement{ + { + Key: "kubernetes.io/os", + Operator: corev1.NodeSelectorOpIn, + Values: []string{"linux"}, + }, }, }, }, }, }, }, - }, - } + } - cr.Spec.Workloads.NodePlacement = &sdkapi.NodePlacement{ - Affinity: &corev1.Affinity{ - NodeAffinity: &corev1.NodeAffinity{ - RequiredDuringSchedulingIgnoredDuringExecution: &corev1.NodeSelector{ - NodeSelectorTerms: []corev1.NodeSelectorTerm{ - { - MatchExpressions: []corev1.NodeSelectorRequirement{ - { - Key: "kubernetes.io/os", - Operator: corev1.NodeSelectorOpIn, - Values: []string{"linux"}, + cr.Spec.Workloads.NodePlacement = &sdkapi.NodePlacement{ + Affinity: &corev1.Affinity{ + NodeAffinity: &corev1.NodeAffinity{ + RequiredDuringSchedulingIgnoredDuringExecution: &corev1.NodeSelector{ + NodeSelectorTerms: []corev1.NodeSelectorTerm{ + { + MatchExpressions: []corev1.NodeSelectorRequirement{ + { + Key: "kubernetes.io/os", + Operator: corev1.NodeSelectorOpIn, + Values: []string{"linux"}, + }, }, }, }, }, }, }, - }, - } + } - Expect(wh.ValidateCreate(ctx, dryRun, cr)).To(Succeed()) - }) + Expect(wh.ValidateCreate(ctx, dryRun, cr)).To(Succeed()) + }) - It("should reject invalid workloads affinity: unknown operator", func() { - cr.Spec.Infra.NodePlacement = &sdkapi.NodePlacement{ - Affinity: &corev1.Affinity{ - NodeAffinity: &corev1.NodeAffinity{ - RequiredDuringSchedulingIgnoredDuringExecution: &corev1.NodeSelector{ - NodeSelectorTerms: []corev1.NodeSelectorTerm{ - { - MatchExpressions: []corev1.NodeSelectorRequirement{ - { - Key: "kubernetes.io/os", - Operator: corev1.NodeSelectorOpIn, - Values: []string{"linux"}, + It("should reject invalid workloads affinity: unknown operator", func(ctx context.Context) { + cr.Spec.Infra.NodePlacement = &sdkapi.NodePlacement{ + Affinity: &corev1.Affinity{ + NodeAffinity: &corev1.NodeAffinity{ + RequiredDuringSchedulingIgnoredDuringExecution: &corev1.NodeSelector{ + NodeSelectorTerms: []corev1.NodeSelectorTerm{ + { + MatchExpressions: []corev1.NodeSelectorRequirement{ + { + Key: "kubernetes.io/os", + Operator: corev1.NodeSelectorOpIn, + Values: []string{"linux"}, + }, }, }, }, }, }, }, - }, - } + } - cr.Spec.Workloads.NodePlacement = &sdkapi.NodePlacement{ - Affinity: &corev1.Affinity{ - NodeAffinity: &corev1.NodeAffinity{ - RequiredDuringSchedulingIgnoredDuringExecution: &corev1.NodeSelector{ - NodeSelectorTerms: []corev1.NodeSelectorTerm{ - { - MatchExpressions: []corev1.NodeSelectorRequirement{ - { - Key: "kubernetes.io/os", - Operator: "WrongOperator", - Values: []string{"linux"}, + cr.Spec.Workloads.NodePlacement = &sdkapi.NodePlacement{ + Affinity: &corev1.Affinity{ + NodeAffinity: &corev1.NodeAffinity{ + RequiredDuringSchedulingIgnoredDuringExecution: &corev1.NodeSelector{ + NodeSelectorTerms: []corev1.NodeSelectorTerm{ + { + MatchExpressions: []corev1.NodeSelectorRequirement{ + { + Key: "kubernetes.io/os", + Operator: "WrongOperator", + Values: []string{"linux"}, + }, }, }, }, }, }, }, - }, - } + } - Expect(wh.ValidateCreate(ctx, dryRun, cr)).To(MatchError( - And( - ContainSubstring("invalid workloads node placement affinity:"), - ContainSubstring(`Unsupported value: "WrongOperator"`), - ), - )) - }) + Expect(wh.ValidateCreate(ctx, dryRun, cr)).To(MatchError( + And( + ContainSubstring("invalid workloads node placement affinity:"), + ContainSubstring(`Unsupported value: "WrongOperator"`), + ), + )) + }) - It("should reject invalid workloads affinity: more than one value in matchFields", func() { - cr.Spec.Infra.NodePlacement = &sdkapi.NodePlacement{ - Affinity: &corev1.Affinity{ - NodeAffinity: &corev1.NodeAffinity{ - RequiredDuringSchedulingIgnoredDuringExecution: &corev1.NodeSelector{ - NodeSelectorTerms: []corev1.NodeSelectorTerm{ - { - MatchExpressions: []corev1.NodeSelectorRequirement{ - { - Key: "kubernetes.io/os", - Operator: corev1.NodeSelectorOpIn, - Values: []string{"linux"}, + It("should reject invalid workloads affinity: more than one value in matchFields", func(ctx context.Context) { + cr.Spec.Infra.NodePlacement = &sdkapi.NodePlacement{ + Affinity: &corev1.Affinity{ + NodeAffinity: &corev1.NodeAffinity{ + RequiredDuringSchedulingIgnoredDuringExecution: &corev1.NodeSelector{ + NodeSelectorTerms: []corev1.NodeSelectorTerm{ + { + MatchExpressions: []corev1.NodeSelectorRequirement{ + { + Key: "kubernetes.io/os", + Operator: corev1.NodeSelectorOpIn, + Values: []string{"linux"}, + }, }, }, }, }, }, }, - }, - } + } - cr.Spec.Workloads.NodePlacement = &sdkapi.NodePlacement{ - Affinity: &corev1.Affinity{ - NodeAffinity: &corev1.NodeAffinity{ - RequiredDuringSchedulingIgnoredDuringExecution: &corev1.NodeSelector{ - NodeSelectorTerms: []corev1.NodeSelectorTerm{ - { - MatchFields: []corev1.NodeSelectorRequirement{ - { - Key: "kubernetes.io/os", - Operator: corev1.NodeSelectorOpIn, - Values: []string{"linux", "windows"}, + cr.Spec.Workloads.NodePlacement = &sdkapi.NodePlacement{ + Affinity: &corev1.Affinity{ + NodeAffinity: &corev1.NodeAffinity{ + RequiredDuringSchedulingIgnoredDuringExecution: &corev1.NodeSelector{ + NodeSelectorTerms: []corev1.NodeSelectorTerm{ + { + MatchFields: []corev1.NodeSelectorRequirement{ + { + Key: "kubernetes.io/os", + Operator: corev1.NodeSelectorOpIn, + Values: []string{"linux", "windows"}, + }, }, }, }, }, }, }, - }, - } + } - Expect(wh.ValidateCreate(ctx, dryRun, cr)).To(MatchError( - And( - ContainSubstring("invalid workloads node placement affinity:"), - ContainSubstring("must have one element"), - ), - )) - }) + Expect(wh.ValidateCreate(ctx, dryRun, cr)).To(MatchError( + And( + ContainSubstring("invalid workloads node placement affinity:"), + ContainSubstring("must have one element"), + ), + )) + }) - It("should reject invalid infra affinity: unknown operator", func() { - cr.Spec.Infra.NodePlacement = &sdkapi.NodePlacement{ - Affinity: &corev1.Affinity{ - NodeAffinity: &corev1.NodeAffinity{ - RequiredDuringSchedulingIgnoredDuringExecution: &corev1.NodeSelector{ - NodeSelectorTerms: []corev1.NodeSelectorTerm{ - { - MatchExpressions: []corev1.NodeSelectorRequirement{ - { - Key: "kubernetes.io/os", - Operator: "WrongOperator", - Values: []string{"linux"}, + It("should reject invalid infra affinity: unknown operator", func(ctx context.Context) { + cr.Spec.Infra.NodePlacement = &sdkapi.NodePlacement{ + Affinity: &corev1.Affinity{ + NodeAffinity: &corev1.NodeAffinity{ + RequiredDuringSchedulingIgnoredDuringExecution: &corev1.NodeSelector{ + NodeSelectorTerms: []corev1.NodeSelectorTerm{ + { + MatchExpressions: []corev1.NodeSelectorRequirement{ + { + Key: "kubernetes.io/os", + Operator: "WrongOperator", + Values: []string{"linux"}, + }, }, }, }, }, }, }, - }, - } + } - cr.Spec.Workloads.NodePlacement = &sdkapi.NodePlacement{ - Affinity: &corev1.Affinity{ - NodeAffinity: &corev1.NodeAffinity{ - RequiredDuringSchedulingIgnoredDuringExecution: &corev1.NodeSelector{ - NodeSelectorTerms: []corev1.NodeSelectorTerm{ - { - MatchExpressions: []corev1.NodeSelectorRequirement{ - { - Key: "kubernetes.io/os", - Operator: corev1.NodeSelectorOpIn, - Values: []string{"linux"}, + cr.Spec.Workloads.NodePlacement = &sdkapi.NodePlacement{ + Affinity: &corev1.Affinity{ + NodeAffinity: &corev1.NodeAffinity{ + RequiredDuringSchedulingIgnoredDuringExecution: &corev1.NodeSelector{ + NodeSelectorTerms: []corev1.NodeSelectorTerm{ + { + MatchExpressions: []corev1.NodeSelectorRequirement{ + { + Key: "kubernetes.io/os", + Operator: corev1.NodeSelectorOpIn, + Values: []string{"linux"}, + }, }, }, }, }, }, }, - }, - } + } - Expect(wh.ValidateCreate(ctx, dryRun, cr)).To(MatchError( - And( - ContainSubstring("invalid infra node placement affinity:"), - ContainSubstring(`Unsupported value: "WrongOperator"`), - ), - )) - }) + Expect(wh.ValidateCreate(ctx, dryRun, cr)).To(MatchError( + And( + ContainSubstring("invalid infra node placement affinity:"), + ContainSubstring(`Unsupported value: "WrongOperator"`), + ), + )) + }) - It("should reject invalid infra affinity: more than one value in fieldSelector", func() { - cr.Spec.Infra.NodePlacement = &sdkapi.NodePlacement{ - Affinity: &corev1.Affinity{ - NodeAffinity: &corev1.NodeAffinity{ - RequiredDuringSchedulingIgnoredDuringExecution: &corev1.NodeSelector{ - NodeSelectorTerms: []corev1.NodeSelectorTerm{ - { - MatchFields: []corev1.NodeSelectorRequirement{ - { - Key: "kubernetes.io/os", - Operator: corev1.NodeSelectorOpIn, - Values: []string{"linux", "windows"}, + It("should reject invalid infra affinity: more than one value in fieldSelector", func(ctx context.Context) { + cr.Spec.Infra.NodePlacement = &sdkapi.NodePlacement{ + Affinity: &corev1.Affinity{ + NodeAffinity: &corev1.NodeAffinity{ + RequiredDuringSchedulingIgnoredDuringExecution: &corev1.NodeSelector{ + NodeSelectorTerms: []corev1.NodeSelectorTerm{ + { + MatchFields: []corev1.NodeSelectorRequirement{ + { + Key: "kubernetes.io/os", + Operator: corev1.NodeSelectorOpIn, + Values: []string{"linux", "windows"}, + }, }, }, }, }, }, }, - }, - } + } - cr.Spec.Workloads.NodePlacement = &sdkapi.NodePlacement{ - Affinity: &corev1.Affinity{ - NodeAffinity: &corev1.NodeAffinity{ - RequiredDuringSchedulingIgnoredDuringExecution: &corev1.NodeSelector{ - NodeSelectorTerms: []corev1.NodeSelectorTerm{ - { - MatchExpressions: []corev1.NodeSelectorRequirement{ - { - Key: "kubernetes.io/os", - Operator: corev1.NodeSelectorOpIn, - Values: []string{"linux"}, + cr.Spec.Workloads.NodePlacement = &sdkapi.NodePlacement{ + Affinity: &corev1.Affinity{ + NodeAffinity: &corev1.NodeAffinity{ + RequiredDuringSchedulingIgnoredDuringExecution: &corev1.NodeSelector{ + NodeSelectorTerms: []corev1.NodeSelectorTerm{ + { + MatchExpressions: []corev1.NodeSelectorRequirement{ + { + Key: "kubernetes.io/os", + Operator: corev1.NodeSelectorOpIn, + Values: []string{"linux"}, + }, }, }, }, }, }, }, - }, - } + } - Expect(wh.ValidateCreate(ctx, dryRun, cr)).To(MatchError( - And( - ContainSubstring("invalid infra node placement affinity:"), - ContainSubstring("must have one element"), - ), - )) + Expect(wh.ValidateCreate(ctx, dryRun, cr)).To(MatchError( + And( + ContainSubstring("invalid infra node placement affinity:"), + ContainSubstring("must have one element"), + ), + )) + }) }) - }) - Context("validate tuning policy", func() { - It("should return warning for deprecated highBurst tuning policy", func() { - cr.Spec.TuningPolicy = v1beta1.HyperConvergedHighBurstProfile //nolint SA1019 - err := wh.ValidateCreate(ctx, dryRun, cr) - Expect(err).To(HaveOccurred()) - expected := &ValidationWarning{} - Expect(errors.As(err, &expected)).To(BeTrue()) - Expect(expected.warnings).To(HaveLen(1)) - Expect(expected.warnings[0]).To(ContainSubstring("highBurst profile is deprecated")) - Expect(expected.warnings[0]).To(ContainSubstring("v1.16.0")) - }) + Context("validate tuning policy", func() { + It("should return warning for deprecated highBurst tuning policy", func(ctx context.Context) { + cr.Spec.TuningPolicy = hcov1beta1.HyperConvergedHighBurstProfile //nolint SA1019 + err := wh.ValidateCreate(ctx, dryRun, cr) + Expect(err).To(HaveOccurred()) + expected := &ValidationWarning{} + Expect(errors.As(err, &expected)).To(BeTrue()) + Expect(expected.warnings).To(HaveLen(1)) + Expect(expected.warnings[0]).To(ContainSubstring("highBurst profile is deprecated")) + Expect(expected.warnings[0]).To(ContainSubstring("v1.16.0")) + }) - It("should not return warning when tuning policy is not set", func() { - cr.Spec.TuningPolicy = "" - Expect(wh.ValidateCreate(ctx, dryRun, cr)).To(Succeed()) + It("should not return warning when tuning policy is not set", func(ctx context.Context) { + cr.Spec.TuningPolicy = "" + Expect(wh.ValidateCreate(ctx, dryRun, cr)).To(Succeed()) + }) }) }) }) Context("validate update validation webhook", func() { - var hco *v1beta1.HyperConverged - var dryRun bool - var ctx context.Context + Context("check update request", func() { + var hco *hcov1.HyperConverged - BeforeEach(func() { - hco = commontestutils.NewHco() - hco.Spec.Infra = v1beta1.HyperConvergedConfig{ - NodePlacement: newHyperConvergedConfig(), - } - hco.Spec.Workloads = v1beta1.HyperConvergedConfig{ - NodePlacement: newHyperConvergedConfig(), - } - dryRun = false - ctx = context.TODO() - }) + BeforeEach(func() { + hco = commontestutils.NewV1HCO() + }) - It("should correctly handle a valid update request", func() { - req := newRequest(admissionv1.Update, hco, v1beta1Codec, false) + It("should correctly handle a valid update request", func(ctx context.Context) { + ctx = logr.NewContext(ctx, GinkgoLogr) + req := newRequest(admissionv1.Update, hco, v1Codec, false) - res := wh.Handle(ctx, req) - Expect(res.Allowed).To(BeTrue()) - Expect(res.Result.Code).To(Equal(int32(200))) - }) + res := wh.Handle(ctx, req) + Expect(res.Allowed).To(BeTrue()) + Expect(res.Result.Code).To(Equal(int32(200))) + }) - It("should correctly handle a valid dryrun update request", func() { - req := newRequest(admissionv1.Update, hco, v1beta1Codec, true) + It("should correctly handle a valid dryrun update request", func(ctx context.Context) { + ctx = logr.NewContext(ctx, GinkgoLogr) + req := newRequest(admissionv1.Update, hco, v1Codec, true) - res := wh.Handle(ctx, req) - Expect(res.Allowed).To(BeTrue()) - Expect(res.Result.Code).To(Equal(int32(200))) - }) + res := wh.Handle(ctx, req) + Expect(res.Allowed).To(BeTrue()) + Expect(res.Result.Code).To(Equal(int32(200))) + }) - It("should reject malformed update requests", func() { - req := newRequest(admissionv1.Update, hco, v1beta1Codec, false) - req.Object = runtime.RawExtension{} + It("should reject update requests with no object", func(ctx context.Context) { + ctx = logr.NewContext(ctx, GinkgoLogr) + req := newRequest(admissionv1.Update, hco, v1Codec, false) + req.Object = runtime.RawExtension{} - res := wh.Handle(ctx, req) - Expect(res.Allowed).To(BeFalse()) - Expect(res.Result.Code).To(Equal(int32(400))) - Expect(res.Result.Message).To(Equal("there is no content to decode")) + res := wh.Handle(ctx, req) + Expect(res.Allowed).To(BeFalse()) + Expect(res.Result.Code).To(Equal(int32(400))) + Expect(res.Result.Message).To(Equal(decodeErrorMsg)) + }) - req = newRequest(admissionv1.Update, hco, v1beta1Codec, false) - req.OldObject = runtime.RawExtension{} + It("should reject update requests with no oldObject", func(ctx context.Context) { + ctx = logr.NewContext(ctx, GinkgoLogr) + req := newRequest(admissionv1.Update, hco, v1Codec, false) + req.OldObject = runtime.RawExtension{} - res = wh.Handle(ctx, req) - Expect(res.Allowed).To(BeFalse()) - Expect(res.Result.Code).To(Equal(int32(400))) - Expect(res.Result.Message).To(Equal("there is no content to decode")) + res := wh.Handle(ctx, req) + Expect(res.Allowed).To(BeFalse()) + Expect(res.Result.Code).To(Equal(int32(400))) + Expect(res.Result.Message).To(Equal(decodeErrorMsg)) + }) }) - It("should return error if KV CR is missing", func() { - ctx := context.TODO() - cli := getFakeClient(hco) - - kv := handlers.NewKubeVirtWithNameOnly(hco) - Expect(cli.Delete(ctx, kv)).To(Succeed()) + Context("check ValidateUpdate", func() { + var hco *hcov1beta1.HyperConverged - wh := NewWebhookHandler(logger, cli, decoder, HcoValidNamespace, true, nil) - - newHco := &v1beta1.HyperConverged{} - hco.DeepCopyInto(newHco) - // just do some change to force update - newHco.Spec.Infra.NodePlacement.NodeSelector["key3"] = "value3" - - err := wh.ValidateUpdate(ctx, dryRun, newHco, hco) - Expect(err).To(MatchError(apierrors.IsNotFound, "not found error")) - Expect(err).To(MatchError(ContainSubstring("kubevirts.kubevirt.io"))) - }) - - It("should return error if dry-run update of KV CR returns error", func() { - cli := getFakeClient(hco) - cli.InitiateUpdateErrors(getUpdateError(kvUpdateFailure)) + BeforeEach(func() { + hco = commontestutils.NewHco() + hco.Spec.Infra = hcov1beta1.HyperConvergedConfig{ + NodePlacement: newHyperConvergedConfig(), + } + hco.Spec.Workloads = hcov1beta1.HyperConvergedConfig{ + NodePlacement: newHyperConvergedConfig(), + } + }) - wh := NewWebhookHandler(logger, cli, decoder, HcoValidNamespace, true, nil) + It("should return error if KV CR is missing", func(ctx context.Context) { + cli := getFakeClient(hco) - newHco := &v1beta1.HyperConverged{} - hco.DeepCopyInto(newHco) - // change something in workloads to trigger dry-run update - newHco.Spec.Workloads.NodePlacement.NodeSelector["a change"] = "Something else" + kv := handlers.NewKubeVirtWithNameOnly(hco) + Expect(cli.Delete(ctx, kv)).To(Succeed()) - err := wh.ValidateUpdate(ctx, dryRun, newHco, hco) - Expect(err).To(MatchError(ErrFakeKvError)) - }) + wh := NewWebhookHandler(logger, cli, decoder, HcoValidNamespace, true, nil) - It("should return error if CDI CR is missing", func() { - ctx := context.TODO() - cli := getFakeClient(hco) - cdi, err := handlers.NewCDI(hco) - Expect(err).ToNot(HaveOccurred()) - Expect(cli.Delete(ctx, cdi)).To(Succeed()) + newHco := &hcov1beta1.HyperConverged{} + hco.DeepCopyInto(newHco) + // just do some change to force update + newHco.Spec.Infra.NodePlacement.NodeSelector["key3"] = "value3" - wh := NewWebhookHandler(logger, cli, decoder, HcoValidNamespace, true, nil) + err := wh.ValidateUpdate(ctx, dryRun, newHco, hco) + Expect(err).To(MatchError(apierrors.IsNotFound, "not found error")) + Expect(err).To(MatchError(ContainSubstring("kubevirts.kubevirt.io"))) + }) - newHco := &v1beta1.HyperConverged{} - hco.DeepCopyInto(newHco) - // just do some change to force update - newHco.Spec.Infra.NodePlacement.NodeSelector["key3"] = "value3" + It("should return error if dry-run update of KV CR returns error", func(ctx context.Context) { + cli := getFakeClient(hco) + cli.InitiateUpdateErrors(getUpdateError(kvUpdateFailure)) - err = wh.ValidateUpdate(ctx, dryRun, newHco, hco) - Expect(err).To(MatchError(apierrors.IsNotFound, "not found error")) - Expect(err).To(MatchError(ContainSubstring("cdis.cdi.kubevirt.io"))) - }) + wh := NewWebhookHandler(logger, cli, decoder, HcoValidNamespace, true, nil) - It("should return error if dry-run update of CDI CR returns error", func() { - cli := getFakeClient(hco) - cli.InitiateUpdateErrors(getUpdateError(cdiUpdateFailure)) - wh := NewWebhookHandler(logger, cli, decoder, HcoValidNamespace, true, nil) + newHco := &hcov1beta1.HyperConverged{} + hco.DeepCopyInto(newHco) + // change something in workloads to trigger dry-run update + newHco.Spec.Workloads.NodePlacement.NodeSelector["a change"] = "Something else" - newHco := &v1beta1.HyperConverged{} - hco.DeepCopyInto(newHco) - // change something in workloads to trigger dry-run update - newHco.Spec.Workloads.NodePlacement.NodeSelector["a change"] = "Something else" + err := wh.ValidateUpdate(ctx, dryRun, newHco, hco) + Expect(err).To(MatchError(ErrFakeKvError)) + }) - err := wh.ValidateUpdate(ctx, dryRun, newHco, hco) - Expect(err).To(MatchError(ErrFakeCdiError)) - }) + It("should return error if CDI CR is missing", func(ctx context.Context) { + cli := getFakeClient(hco) + cdi, err := handlers.NewCDI(hco) + Expect(err).ToNot(HaveOccurred()) + Expect(cli.Delete(ctx, cdi)).To(Succeed()) - It("should not return error if dry-run update of ALL CR passes", func() { - cli := getFakeClient(hco) - cli.InitiateUpdateErrors(getUpdateError(noFailure)) + wh := NewWebhookHandler(logger, cli, decoder, HcoValidNamespace, true, nil) - wh := NewWebhookHandler(logger, cli, decoder, HcoValidNamespace, true, nil) + newHco := &hcov1beta1.HyperConverged{} + hco.DeepCopyInto(newHco) + // just do some change to force update + newHco.Spec.Infra.NodePlacement.NodeSelector["key3"] = "value3" - newHco := &v1beta1.HyperConverged{} - hco.DeepCopyInto(newHco) - // change something in workloads to trigger dry-run update - newHco.Spec.Workloads.NodePlacement.NodeSelector["a change"] = "Something else" + err = wh.ValidateUpdate(ctx, dryRun, newHco, hco) + Expect(err).To(MatchError(apierrors.IsNotFound, "not found error")) + Expect(err).To(MatchError(ContainSubstring("cdis.cdi.kubevirt.io"))) + }) - Expect(wh.ValidateUpdate(ctx, dryRun, newHco, hco)).To(Succeed()) - }) + It("should return error if dry-run update of CDI CR returns error", func(ctx context.Context) { + cli := getFakeClient(hco) + cli.InitiateUpdateErrors(getUpdateError(cdiUpdateFailure)) + wh := NewWebhookHandler(logger, cli, decoder, HcoValidNamespace, true, nil) - It("should return error if NetworkAddons CR is missing", func() { - ctx := context.TODO() - cli := getFakeClient(hco) - cna, err := handlers.NewNetworkAddons(hco) - Expect(err).ToNot(HaveOccurred()) - Expect(cli.Delete(ctx, cna)).To(Succeed()) - wh := NewWebhookHandler(logger, cli, decoder, HcoValidNamespace, true, nil) - - newHco := &v1beta1.HyperConverged{} - hco.DeepCopyInto(newHco) - // just do some change to force update - newHco.Spec.Infra.NodePlacement.NodeSelector["key3"] = "value3" - - err = wh.ValidateUpdate(ctx, dryRun, newHco, hco) - Expect(err).To(MatchError(apierrors.IsNotFound, "not found error")) - Expect(err).To(MatchError(ContainSubstring("networkaddonsconfigs.networkaddonsoperator.network.kubevirt.io"))) - }) + newHco := &hcov1beta1.HyperConverged{} + hco.DeepCopyInto(newHco) + // change something in workloads to trigger dry-run update + newHco.Spec.Workloads.NodePlacement.NodeSelector["a change"] = "Something else" - It("should return error if dry-run update of NetworkAddons CR returns error", func() { - cli := getFakeClient(hco) - cli.InitiateUpdateErrors(getUpdateError(networkUpdateFailure)) + err := wh.ValidateUpdate(ctx, dryRun, newHco, hco) + Expect(err).To(MatchError(ErrFakeCdiError)) + }) - wh := NewWebhookHandler(logger, cli, decoder, HcoValidNamespace, true, nil) + It("should not return error if dry-run update of ALL CR passes", func(ctx context.Context) { + cli := getFakeClient(hco) + cli.InitiateUpdateErrors(getUpdateError(noFailure)) - newHco := &v1beta1.HyperConverged{} - hco.DeepCopyInto(newHco) - // change something in workloads to trigger dry-run update - newHco.Spec.Workloads.NodePlacement.NodeSelector["a change"] = "Something else" + wh := NewWebhookHandler(logger, cli, decoder, HcoValidNamespace, true, nil) - err := wh.ValidateUpdate(ctx, dryRun, newHco, hco) - Expect(err).To(MatchError(ErrFakeNetworkError)) - }) + newHco := &hcov1beta1.HyperConverged{} + hco.DeepCopyInto(newHco) + // change something in workloads to trigger dry-run update + newHco.Spec.Workloads.NodePlacement.NodeSelector["a change"] = "Something else" - It("should return error if SSP CR is missing", func() { - ctx := context.TODO() - cli := getFakeClient(hco) + Expect(wh.ValidateUpdate(ctx, dryRun, newHco, hco)).To(Succeed()) + }) - Expect(cli.Delete(ctx, handlers.NewSSPWithNameOnly(hco))).To(Succeed()) - wh := NewWebhookHandler(logger, cli, decoder, HcoValidNamespace, true, nil) + It("should return error if NetworkAddons CR is missing", func(ctx context.Context) { + cli := getFakeClient(hco) + cna, err := handlers.NewNetworkAddons(hco) + Expect(err).ToNot(HaveOccurred()) + Expect(cli.Delete(ctx, cna)).To(Succeed()) + wh := NewWebhookHandler(logger, cli, decoder, HcoValidNamespace, true, nil) - newHco := &v1beta1.HyperConverged{} - hco.DeepCopyInto(newHco) - // just do some change to force update - newHco.Spec.Infra.NodePlacement.NodeSelector["key3"] = "value3" + newHco := &hcov1beta1.HyperConverged{} + hco.DeepCopyInto(newHco) + // just do some change to force update + newHco.Spec.Infra.NodePlacement.NodeSelector["key3"] = "value3" - err := wh.ValidateUpdate(ctx, dryRun, newHco, hco) - Expect(err).To(MatchError(apierrors.IsNotFound, "not found error")) - Expect(err).To(MatchError(ContainSubstring("ssps.ssp.kubevirt.io"))) - }) + err = wh.ValidateUpdate(ctx, dryRun, newHco, hco) + Expect(err).To(MatchError(apierrors.IsNotFound, "not found error")) + Expect(err).To(MatchError(ContainSubstring("networkaddonsconfigs.networkaddonsoperator.network.kubevirt.io"))) + }) - It("should return error if dry-run update of SSP CR returns error", func() { - cli := getFakeClient(hco) - cli.InitiateUpdateErrors(getUpdateError(sspUpdateFailure)) - wh := NewWebhookHandler(logger, cli, decoder, HcoValidNamespace, true, nil) + It("should return error if dry-run update of NetworkAddons CR returns error", func(ctx context.Context) { + cli := getFakeClient(hco) + cli.InitiateUpdateErrors(getUpdateError(networkUpdateFailure)) - newHco := &v1beta1.HyperConverged{} - hco.DeepCopyInto(newHco) - // change something in workloads to trigger dry-run update - newHco.Spec.Workloads.NodePlacement.NodeSelector["a change"] = "Something else" + wh := NewWebhookHandler(logger, cli, decoder, HcoValidNamespace, true, nil) - err := wh.ValidateUpdate(ctx, dryRun, newHco, hco) - Expect(err).To(MatchError(ErrFakeSspError)) + newHco := &hcov1beta1.HyperConverged{} + hco.DeepCopyInto(newHco) + // change something in workloads to trigger dry-run update + newHco.Spec.Workloads.NodePlacement.NodeSelector["a change"] = "Something else" - }) + err := wh.ValidateUpdate(ctx, dryRun, newHco, hco) + Expect(err).To(MatchError(ErrFakeNetworkError)) + }) - It("should return error if dry-run update is timeout", func() { - cli := getFakeClient(hco) - cli.InitiateUpdateErrors(initiateTimeout) + It("should return error if SSP CR is missing", func(ctx context.Context) { + cli := getFakeClient(hco) - wh := NewWebhookHandler(logger, cli, decoder, HcoValidNamespace, true, nil) + Expect(cli.Delete(ctx, handlers.NewSSPWithNameOnly(hco))).To(Succeed()) + wh := NewWebhookHandler(logger, cli, decoder, HcoValidNamespace, true, nil) - newHco := &v1beta1.HyperConverged{} - hco.DeepCopyInto(newHco) - // change something in workloads to trigger dry-run update - newHco.Spec.Workloads.NodePlacement.NodeSelector["a change"] = "Something else" + newHco := &hcov1beta1.HyperConverged{} + hco.DeepCopyInto(newHco) + // just do some change to force update + newHco.Spec.Infra.NodePlacement.NodeSelector["key3"] = "value3" - err := wh.ValidateUpdate(ctx, dryRun, newHco, hco) - Expect(err).To(MatchError(context.DeadlineExceeded)) - }) + err := wh.ValidateUpdate(ctx, dryRun, newHco, hco) + Expect(err).To(MatchError(apierrors.IsNotFound, "not found error")) + Expect(err).To(MatchError(ContainSubstring("ssps.ssp.kubevirt.io"))) + }) - It("should not return error if nothing was changed", func() { - cli := getFakeClient(hco) - cli.InitiateUpdateErrors(initiateTimeout) + It("should return error if dry-run update of SSP CR returns error", func(ctx context.Context) { + cli := getFakeClient(hco) + cli.InitiateUpdateErrors(getUpdateError(sspUpdateFailure)) + wh := NewWebhookHandler(logger, cli, decoder, HcoValidNamespace, true, nil) - wh := NewWebhookHandler(logger, cli, decoder, HcoValidNamespace, true, nil) + newHco := &hcov1beta1.HyperConverged{} + hco.DeepCopyInto(newHco) + // change something in workloads to trigger dry-run update + newHco.Spec.Workloads.NodePlacement.NodeSelector["a change"] = "Something else" - newHco := &v1beta1.HyperConverged{} - hco.DeepCopyInto(newHco) + err := wh.ValidateUpdate(ctx, dryRun, newHco, hco) + Expect(err).To(MatchError(ErrFakeSspError)) - Expect(wh.ValidateUpdate(ctx, dryRun, newHco, hco)).To(Succeed()) - }) + }) - Context("test permitted host devices update validation", func() { - It("should allow unique PCI Host Device", func() { + It("should return error if dry-run update is timeout", func(ctx context.Context) { cli := getFakeClient(hco) + cli.InitiateUpdateErrors(initiateTimeout) + wh := NewWebhookHandler(logger, cli, decoder, HcoValidNamespace, true, nil) - newHco := &v1beta1.HyperConverged{} + newHco := &hcov1beta1.HyperConverged{} hco.DeepCopyInto(newHco) - newHco.Spec.PermittedHostDevices = &v1beta1.PermittedHostDevices{ - PciHostDevices: []v1beta1.PciHostDevice{ - { - PCIDeviceSelector: "111", - ResourceName: "name", - }, - { - PCIDeviceSelector: "222", - ResourceName: "name", - }, - { - PCIDeviceSelector: "333", - ResourceName: "name", - }, - }, - } - Expect(wh.ValidateUpdate(ctx, dryRun, newHco, hco)).To(Succeed()) + // change something in workloads to trigger dry-run update + newHco.Spec.Workloads.NodePlacement.NodeSelector["a change"] = "Something else" + + err := wh.ValidateUpdate(ctx, dryRun, newHco, hco) + Expect(err).To(MatchError(context.DeadlineExceeded)) }) - It("should allow unique Mediate Host Device", func() { + It("should not return error if nothing was changed", func(ctx context.Context) { cli := getFakeClient(hco) + cli.InitiateUpdateErrors(initiateTimeout) + wh := NewWebhookHandler(logger, cli, decoder, HcoValidNamespace, true, nil) - newHco := &v1beta1.HyperConverged{} + newHco := &hcov1beta1.HyperConverged{} hco.DeepCopyInto(newHco) - newHco.Spec.PermittedHostDevices = &v1beta1.PermittedHostDevices{ - MediatedDevices: []v1beta1.MediatedHostDevice{ - { - MDEVNameSelector: "111", - ResourceName: "name", - }, - { - MDEVNameSelector: "222", - ResourceName: "name", - }, - { - MDEVNameSelector: "333", - ResourceName: "name", - }, - }, - } + Expect(wh.ValidateUpdate(ctx, dryRun, newHco, hco)).To(Succeed()) }) - }) - Context("plain-k8s tests", func() { - It("should return error in plain-k8s if KV CR is missing", func() { - hco := &v1beta1.HyperConverged{} - ctx := context.TODO() - cli := getFakeClient(hco) - kv, err := handlers.NewKubeVirt(hco) - Expect(err).ToNot(HaveOccurred()) - Expect(cli.Delete(ctx, kv)).To(Succeed()) - wh := NewWebhookHandler(logger, cli, decoder, HcoValidNamespace, false, nil) - - newHco := commontestutils.NewHco() - newHco.Spec.Infra = v1beta1.HyperConvergedConfig{ - NodePlacement: newHyperConvergedConfig(), - } - newHco.Spec.Workloads = v1beta1.HyperConvergedConfig{ - NodePlacement: newHyperConvergedConfig(), - } + Context("test permitted host devices update validation", func() { + It("should allow unique PCI Host Device", func(ctx context.Context) { + cli := getFakeClient(hco) + wh := NewWebhookHandler(logger, cli, decoder, HcoValidNamespace, true, nil) - Expect( - wh.ValidateUpdate(ctx, dryRun, newHco, hco), - ).To(MatchError(apierrors.IsNotFound, "not found error")) - }) - }) + newHco := &hcov1beta1.HyperConverged{} + hco.DeepCopyInto(newHco) + newHco.Spec.PermittedHostDevices = &hcov1beta1.PermittedHostDevices{ + PciHostDevices: []hcov1beta1.PciHostDevice{ + { + PCIDeviceSelector: "111", + ResourceName: "name", + }, + { + PCIDeviceSelector: "222", + ResourceName: "name", + }, + { + PCIDeviceSelector: "333", + ResourceName: "name", + }, + }, + } + Expect(wh.ValidateUpdate(ctx, dryRun, newHco, hco)).To(Succeed()) + }) - Context("Check LiveMigrationConfiguration", func() { - var hco *v1beta1.HyperConverged + It("should allow unique Mediate Host Device", func(ctx context.Context) { + cli := getFakeClient(hco) + wh := NewWebhookHandler(logger, cli, decoder, HcoValidNamespace, true, nil) - BeforeEach(func() { - hco = commontestutils.NewHco() + newHco := &hcov1beta1.HyperConverged{} + hco.DeepCopyInto(newHco) + newHco.Spec.PermittedHostDevices = &hcov1beta1.PermittedHostDevices{ + MediatedDevices: []hcov1beta1.MediatedHostDevice{ + { + MDEVNameSelector: "111", + ResourceName: "name", + }, + { + MDEVNameSelector: "222", + ResourceName: "name", + }, + { + MDEVNameSelector: "333", + ResourceName: "name", + }, + }, + } + Expect(wh.ValidateUpdate(ctx, dryRun, newHco, hco)).To(Succeed()) + }) }) - It("should ignore if there is no change in live migration", func() { - cli := getFakeClient(hco) + Context("plain-k8s tests", func() { + It("should return error in plain-k8s if KV CR is missing", func(ctx context.Context) { + hco := &hcov1beta1.HyperConverged{} + cli := getFakeClient(hco) + kv, err := handlers.NewKubeVirt(hco) + Expect(err).ToNot(HaveOccurred()) + Expect(cli.Delete(ctx, kv)).To(Succeed()) + wh := NewWebhookHandler(logger, cli, decoder, HcoValidNamespace, false, nil) + + newHco := commontestutils.NewHco() + newHco.Spec.Infra = hcov1beta1.HyperConvergedConfig{ + NodePlacement: newHyperConvergedConfig(), + } + newHco.Spec.Workloads = hcov1beta1.HyperConvergedConfig{ + NodePlacement: newHyperConvergedConfig(), + } - // Deleting KV here, in order to make sure the that the webhook does not find differences, - // and so it exits with no error before finding that KV is not there. - // Later we'll check that there is no error from the webhook, and that will prove that - // the comparison works. - kv := handlers.NewKubeVirtWithNameOnly(hco) - Expect(cli.Delete(context.TODO(), kv)).To(Succeed()) + Expect( + wh.ValidateUpdate(ctx, dryRun, newHco, hco), + ).To(MatchError(apierrors.IsNotFound, "not found error")) + }) + }) - wh := NewWebhookHandler(logger, cli, decoder, HcoValidNamespace, true, nil) + Context("Check LiveMigrationConfiguration", func() { + It("should ignore if there is no change in live migration", func(ctx context.Context) { + cli := getFakeClient(hco) - newHco := &v1beta1.HyperConverged{} - hco.DeepCopyInto(newHco) + // Deleting KV here, in order to make sure the that the webhook does not find differences, + // and so it exits with no error before finding that KV is not there. + // Later we'll check that there is no error from the webhook, and that will prove that + // the comparison works. + kv := handlers.NewKubeVirtWithNameOnly(hco) + Expect(cli.Delete(context.TODO(), kv)).To(Succeed()) - Expect(wh.ValidateUpdate(ctx, dryRun, newHco, hco)).To(Succeed()) - }) + wh := NewWebhookHandler(logger, cli, decoder, HcoValidNamespace, true, nil) - It("should allow updating of live migration", func() { - cli := getFakeClient(hco) + newHco := &hcov1beta1.HyperConverged{} + hco.DeepCopyInto(newHco) - wh := NewWebhookHandler(logger, cli, decoder, HcoValidNamespace, true, nil) + Expect(wh.ValidateUpdate(ctx, dryRun, newHco, hco)).To(Succeed()) + }) - newHco := &v1beta1.HyperConverged{} - hco.DeepCopyInto(newHco) + It("should allow updating of live migration", func(ctx context.Context) { + cli := getFakeClient(hco) - // change something in the LiveMigrationConfig field - hco.Spec.LiveMigrationConfig.CompletionTimeoutPerGiB = ptr.To[int64](200) + wh := NewWebhookHandler(logger, cli, decoder, HcoValidNamespace, true, nil) - Expect(wh.ValidateUpdate(ctx, dryRun, newHco, hco)).To(Succeed()) - }) + newHco := &hcov1beta1.HyperConverged{} + hco.DeepCopyInto(newHco) - It("should fail if live migration is wrong", func() { - cli := getFakeClient(hco) + // change something in the LiveMigrationConfig field + hco.Spec.LiveMigrationConfig.CompletionTimeoutPerGiB = ptr.To[int64](200) - wh := NewWebhookHandler(logger, cli, decoder, HcoValidNamespace, true, nil) + Expect(wh.ValidateUpdate(ctx, dryRun, newHco, hco)).To(Succeed()) + }) - newHco := &v1beta1.HyperConverged{} - hco.DeepCopyInto(newHco) + It("should fail if live migration is wrong", func(ctx context.Context) { + cli := getFakeClient(hco) - // change something in the LiveMigrationConfig field - newHco.Spec.LiveMigrationConfig.BandwidthPerMigration = ptr.To("Wrong Value") + wh := NewWebhookHandler(logger, cli, decoder, HcoValidNamespace, true, nil) - Expect( - wh.ValidateUpdate(ctx, dryRun, newHco, hco), - ).To(MatchError(ContainSubstring("failed to parse the LiveMigrationConfig.bandwidthPerMigration field"))) - }) - }) + newHco := &hcov1beta1.HyperConverged{} + hco.DeepCopyInto(newHco) - Context("Check CertRotation", func() { - var hco *v1beta1.HyperConverged + // change something in the LiveMigrationConfig field + newHco.Spec.LiveMigrationConfig.BandwidthPerMigration = ptr.To("Wrong Value") - BeforeEach(func() { - hco = commontestutils.NewHco() + Expect( + wh.ValidateUpdate(ctx, dryRun, newHco, hco), + ).To(MatchError(ContainSubstring("failed to parse the LiveMigrationConfig.bandwidthPerMigration field"))) + }) }) - It("should ignore if there is no change in cert config", func() { - cli := getFakeClient(hco) + Context("Check CertRotation", func() { + It("should ignore if there is no change in cert config", func(ctx context.Context) { + cli := getFakeClient(hco) - // Deleting KV here, in order to make sure the that the webhook does not find differences, - // and so it exits with no error before finding that KV is not there. - // Later we'll check that there is no error from the webhook, and that will prove that - // the comparison works. - kv := handlers.NewKubeVirtWithNameOnly(hco) - Expect(cli.Delete(context.TODO(), kv)).To(Succeed()) + // Deleting KV here, in order to make sure the that the webhook does not find differences, + // and so it exits with no error before finding that KV is not there. + // Later we'll check that there is no error from the webhook, and that will prove that + // the comparison works. + kv := handlers.NewKubeVirtWithNameOnly(hco) + Expect(cli.Delete(ctx, kv)).To(Succeed()) - wh := NewWebhookHandler(logger, cli, decoder, HcoValidNamespace, true, nil) + wh := NewWebhookHandler(logger, cli, decoder, HcoValidNamespace, true, nil) - newHco := &v1beta1.HyperConverged{} - hco.DeepCopyInto(newHco) + newHco := &hcov1beta1.HyperConverged{} + hco.DeepCopyInto(newHco) - Expect(wh.ValidateUpdate(ctx, dryRun, newHco, hco)).To(Succeed()) - }) + Expect(wh.ValidateUpdate(ctx, dryRun, newHco, hco)).To(Succeed()) + }) - It("should allow updating of cert config", func() { - cli := getFakeClient(hco) + It("should allow updating of cert config", func(ctx context.Context) { + cli := getFakeClient(hco) - wh := NewWebhookHandler(logger, cli, decoder, HcoValidNamespace, true, nil) + wh := NewWebhookHandler(logger, cli, decoder, HcoValidNamespace, true, nil) - newHco := &v1beta1.HyperConverged{} - hco.DeepCopyInto(newHco) + newHco := &hcov1beta1.HyperConverged{} + hco.DeepCopyInto(newHco) - // change something in the CertConfig fields - newHco.Spec.CertConfig.CA.Duration.Duration = hco.Spec.CertConfig.CA.Duration.Duration * 2 - newHco.Spec.CertConfig.CA.RenewBefore.Duration = hco.Spec.CertConfig.CA.RenewBefore.Duration * 2 - newHco.Spec.CertConfig.Server.Duration.Duration = hco.Spec.CertConfig.Server.Duration.Duration * 2 - newHco.Spec.CertConfig.Server.RenewBefore.Duration = hco.Spec.CertConfig.Server.RenewBefore.Duration * 2 + // change something in the CertConfig fields + newHco.Spec.CertConfig.CA.Duration.Duration = hco.Spec.CertConfig.CA.Duration.Duration * 2 + newHco.Spec.CertConfig.CA.RenewBefore.Duration = hco.Spec.CertConfig.CA.RenewBefore.Duration * 2 + newHco.Spec.CertConfig.Server.Duration.Duration = hco.Spec.CertConfig.Server.Duration.Duration * 2 + newHco.Spec.CertConfig.Server.RenewBefore.Duration = hco.Spec.CertConfig.Server.RenewBefore.Duration * 2 - Expect(wh.ValidateUpdate(ctx, dryRun, newHco, hco)).To(Succeed()) - }) + Expect(wh.ValidateUpdate(ctx, dryRun, newHco, hco)).To(Succeed()) + }) - DescribeTable("should fail if cert config is wrong", - func(newHco v1beta1.HyperConverged, errorMsg string) { - cli := getFakeClient(hco) + DescribeTable("should fail if cert config is wrong", + func(ctx context.Context, newHco hcov1beta1.HyperConverged, errorMsg string) { + cli := getFakeClient(hco) - wh := NewWebhookHandler(logger, cli, decoder, HcoValidNamespace, true, nil) + wh := NewWebhookHandler(logger, cli, decoder, HcoValidNamespace, true, nil) - err := wh.ValidateUpdate(ctx, dryRun, &newHco, hco) - Expect(err).To(MatchError(ContainSubstring(errorMsg))) - }, - Entry("certConfig.ca.duration is too short", - v1beta1.HyperConverged{ - ObjectMeta: metav1.ObjectMeta{ - Name: util.HyperConvergedName, - Namespace: HcoValidNamespace, - }, - Spec: v1beta1.HyperConvergedSpec{ - CertConfig: v1beta1.HyperConvergedCertConfig{ - CA: v1beta1.CertRotateConfigCA{ - Duration: &metav1.Duration{Duration: 8 * time.Minute}, - RenewBefore: &metav1.Duration{Duration: 24 * time.Hour}, - }, - Server: v1beta1.CertRotateConfigServer{ - Duration: &metav1.Duration{Duration: 24 * time.Hour}, - RenewBefore: &metav1.Duration{Duration: 12 * time.Hour}, - }, - }, - }, + err := wh.ValidateUpdate(ctx, dryRun, &newHco, hco) + Expect(err).To(MatchError(ContainSubstring(errorMsg))) }, - "spec.certConfig.ca.duration: value is too small"), - Entry("certConfig.ca.renewBefore is too short", - v1beta1.HyperConverged{ - ObjectMeta: metav1.ObjectMeta{ - Name: util.HyperConvergedName, - Namespace: HcoValidNamespace, - }, - Spec: v1beta1.HyperConvergedSpec{ - CertConfig: v1beta1.HyperConvergedCertConfig{ - CA: v1beta1.CertRotateConfigCA{ - Duration: &metav1.Duration{Duration: 48 * time.Hour}, - RenewBefore: &metav1.Duration{Duration: 8 * time.Minute}, - }, - Server: v1beta1.CertRotateConfigServer{ - Duration: &metav1.Duration{Duration: 24 * time.Hour}, - RenewBefore: &metav1.Duration{Duration: 12 * time.Hour}, + Entry("certConfig.ca.duration is too short", + hcov1beta1.HyperConverged{ + ObjectMeta: metav1.ObjectMeta{ + Name: util.HyperConvergedName, + Namespace: HcoValidNamespace, + }, + Spec: hcov1beta1.HyperConvergedSpec{ + CertConfig: hcov1beta1.HyperConvergedCertConfig{ + CA: hcov1beta1.CertRotateConfigCA{ + Duration: &metav1.Duration{Duration: 8 * time.Minute}, + RenewBefore: &metav1.Duration{Duration: 24 * time.Hour}, + }, + Server: hcov1beta1.CertRotateConfigServer{ + Duration: &metav1.Duration{Duration: 24 * time.Hour}, + RenewBefore: &metav1.Duration{Duration: 12 * time.Hour}, + }, }, }, }, - }, - "spec.certConfig.ca.renewBefore: value is too small"), - Entry("certConfig.server.duration is too short", - v1beta1.HyperConverged{ - ObjectMeta: metav1.ObjectMeta{ - Name: util.HyperConvergedName, - Namespace: HcoValidNamespace, - }, - Spec: v1beta1.HyperConvergedSpec{ - CertConfig: v1beta1.HyperConvergedCertConfig{ - CA: v1beta1.CertRotateConfigCA{ - Duration: &metav1.Duration{Duration: 48 * time.Hour}, - RenewBefore: &metav1.Duration{Duration: 24 * time.Hour}, - }, - Server: v1beta1.CertRotateConfigServer{ - Duration: &metav1.Duration{Duration: 8 * time.Minute}, - RenewBefore: &metav1.Duration{Duration: 12 * time.Hour}, + "spec.certConfig.ca.duration: value is too small"), + Entry("certConfig.ca.renewBefore is too short", + hcov1beta1.HyperConverged{ + ObjectMeta: metav1.ObjectMeta{ + Name: util.HyperConvergedName, + Namespace: HcoValidNamespace, + }, + Spec: hcov1beta1.HyperConvergedSpec{ + CertConfig: hcov1beta1.HyperConvergedCertConfig{ + CA: hcov1beta1.CertRotateConfigCA{ + Duration: &metav1.Duration{Duration: 48 * time.Hour}, + RenewBefore: &metav1.Duration{Duration: 8 * time.Minute}, + }, + Server: hcov1beta1.CertRotateConfigServer{ + Duration: &metav1.Duration{Duration: 24 * time.Hour}, + RenewBefore: &metav1.Duration{Duration: 12 * time.Hour}, + }, }, }, }, - }, - "spec.certConfig.server.duration: value is too small"), - Entry("certConfig.server.renewBefore is too short", - v1beta1.HyperConverged{ - ObjectMeta: metav1.ObjectMeta{ - Name: util.HyperConvergedName, - Namespace: HcoValidNamespace, - }, - Spec: v1beta1.HyperConvergedSpec{ - CertConfig: v1beta1.HyperConvergedCertConfig{ - CA: v1beta1.CertRotateConfigCA{ - Duration: &metav1.Duration{Duration: 48 * time.Hour}, - RenewBefore: &metav1.Duration{Duration: 24 * time.Hour}, - }, - Server: v1beta1.CertRotateConfigServer{ - Duration: &metav1.Duration{Duration: 24 * time.Hour}, - RenewBefore: &metav1.Duration{Duration: 8 * time.Minute}, + "spec.certConfig.ca.renewBefore: value is too small"), + Entry("certConfig.server.duration is too short", + hcov1beta1.HyperConverged{ + ObjectMeta: metav1.ObjectMeta{ + Name: util.HyperConvergedName, + Namespace: HcoValidNamespace, + }, + Spec: hcov1beta1.HyperConvergedSpec{ + CertConfig: hcov1beta1.HyperConvergedCertConfig{ + CA: hcov1beta1.CertRotateConfigCA{ + Duration: &metav1.Duration{Duration: 48 * time.Hour}, + RenewBefore: &metav1.Duration{Duration: 24 * time.Hour}, + }, + Server: hcov1beta1.CertRotateConfigServer{ + Duration: &metav1.Duration{Duration: 8 * time.Minute}, + RenewBefore: &metav1.Duration{Duration: 12 * time.Hour}, + }, }, }, }, - }, - "spec.certConfig.server.renewBefore: value is too small"), - Entry("ca: duration is smaller than renewBefore", - v1beta1.HyperConverged{ - ObjectMeta: metav1.ObjectMeta{ - Name: util.HyperConvergedName, - Namespace: HcoValidNamespace, - }, - Spec: v1beta1.HyperConvergedSpec{ - CertConfig: v1beta1.HyperConvergedCertConfig{ - CA: v1beta1.CertRotateConfigCA{ - Duration: &metav1.Duration{Duration: 23 * time.Hour}, - RenewBefore: &metav1.Duration{Duration: 24 * time.Hour}, - }, - Server: v1beta1.CertRotateConfigServer{ - Duration: &metav1.Duration{Duration: 24 * time.Hour}, - RenewBefore: &metav1.Duration{Duration: 12 * time.Hour}, + "spec.certConfig.server.duration: value is too small"), + Entry("certConfig.server.renewBefore is too short", + hcov1beta1.HyperConverged{ + ObjectMeta: metav1.ObjectMeta{ + Name: util.HyperConvergedName, + Namespace: HcoValidNamespace, + }, + Spec: hcov1beta1.HyperConvergedSpec{ + CertConfig: hcov1beta1.HyperConvergedCertConfig{ + CA: hcov1beta1.CertRotateConfigCA{ + Duration: &metav1.Duration{Duration: 48 * time.Hour}, + RenewBefore: &metav1.Duration{Duration: 24 * time.Hour}, + }, + Server: hcov1beta1.CertRotateConfigServer{ + Duration: &metav1.Duration{Duration: 24 * time.Hour}, + RenewBefore: &metav1.Duration{Duration: 8 * time.Minute}, + }, }, }, }, - }, - "spec.certConfig.ca: duration is smaller than renewBefore"), - Entry("server: duration is smaller than renewBefore", - v1beta1.HyperConverged{ - ObjectMeta: metav1.ObjectMeta{ - Name: util.HyperConvergedName, - Namespace: HcoValidNamespace, - }, - Spec: v1beta1.HyperConvergedSpec{ - CertConfig: v1beta1.HyperConvergedCertConfig{ - CA: v1beta1.CertRotateConfigCA{ - Duration: &metav1.Duration{Duration: 48 * time.Hour}, - RenewBefore: &metav1.Duration{Duration: 24 * time.Hour}, - }, - Server: v1beta1.CertRotateConfigServer{ - Duration: &metav1.Duration{Duration: 11 * time.Hour}, - RenewBefore: &metav1.Duration{Duration: 12 * time.Hour}, + "spec.certConfig.server.renewBefore: value is too small"), + Entry("ca: duration is smaller than renewBefore", + hcov1beta1.HyperConverged{ + ObjectMeta: metav1.ObjectMeta{ + Name: util.HyperConvergedName, + Namespace: HcoValidNamespace, + }, + Spec: hcov1beta1.HyperConvergedSpec{ + CertConfig: hcov1beta1.HyperConvergedCertConfig{ + CA: hcov1beta1.CertRotateConfigCA{ + Duration: &metav1.Duration{Duration: 23 * time.Hour}, + RenewBefore: &metav1.Duration{Duration: 24 * time.Hour}, + }, + Server: hcov1beta1.CertRotateConfigServer{ + Duration: &metav1.Duration{Duration: 24 * time.Hour}, + RenewBefore: &metav1.Duration{Duration: 12 * time.Hour}, + }, }, }, }, - }, - "spec.certConfig.server: duration is smaller than renewBefore"), - Entry("ca.duration is smaller than server.duration", - v1beta1.HyperConverged{ - ObjectMeta: metav1.ObjectMeta{ - Name: util.HyperConvergedName, - Namespace: HcoValidNamespace, - }, - Spec: v1beta1.HyperConvergedSpec{ - CertConfig: v1beta1.HyperConvergedCertConfig{ - CA: v1beta1.CertRotateConfigCA{ - Duration: &metav1.Duration{Duration: 48 * time.Hour}, - RenewBefore: &metav1.Duration{Duration: 24 * time.Hour}, - }, - Server: v1beta1.CertRotateConfigServer{ - Duration: &metav1.Duration{Duration: 96 * time.Hour}, - RenewBefore: &metav1.Duration{Duration: 12 * time.Hour}, + "spec.certConfig.ca: duration is smaller than renewBefore"), + Entry("server: duration is smaller than renewBefore", + hcov1beta1.HyperConverged{ + ObjectMeta: metav1.ObjectMeta{ + Name: util.HyperConvergedName, + Namespace: HcoValidNamespace, + }, + Spec: hcov1beta1.HyperConvergedSpec{ + CertConfig: hcov1beta1.HyperConvergedCertConfig{ + CA: hcov1beta1.CertRotateConfigCA{ + Duration: &metav1.Duration{Duration: 48 * time.Hour}, + RenewBefore: &metav1.Duration{Duration: 24 * time.Hour}, + }, + Server: hcov1beta1.CertRotateConfigServer{ + Duration: &metav1.Duration{Duration: 11 * time.Hour}, + RenewBefore: &metav1.Duration{Duration: 12 * time.Hour}, + }, }, }, }, - }, - "spec.certConfig: ca.duration is smaller than server.duration"), - ) - - }) - - Context("validate tlsSecurityProfiles", func() { - var hco *v1beta1.HyperConverged + "spec.certConfig.server: duration is smaller than renewBefore"), + Entry("ca.duration is smaller than server.duration", + hcov1beta1.HyperConverged{ + ObjectMeta: metav1.ObjectMeta{ + Name: util.HyperConvergedName, + Namespace: HcoValidNamespace, + }, + Spec: hcov1beta1.HyperConvergedSpec{ + CertConfig: hcov1beta1.HyperConvergedCertConfig{ + CA: hcov1beta1.CertRotateConfigCA{ + Duration: &metav1.Duration{Duration: 48 * time.Hour}, + RenewBefore: &metav1.Duration{Duration: 24 * time.Hour}, + }, + Server: hcov1beta1.CertRotateConfigServer{ + Duration: &metav1.Duration{Duration: 96 * time.Hour}, + RenewBefore: &metav1.Duration{Duration: 12 * time.Hour}, + }, + }, + }, + }, + "spec.certConfig: ca.duration is smaller than server.duration"), + ) - BeforeEach(func() { - hco = commontestutils.NewHco() }) - updateTLSSecurityProfile := func(minTLSVersion openshiftconfigv1.TLSProtocolVersion, ciphers []string) error { - cli := getFakeClient(hco) + Context("validate tlsSecurityProfiles", func() { + updateTLSSecurityProfile := func(ctx context.Context, minTLSVersion openshiftconfigv1.TLSProtocolVersion, ciphers []string) error { + cli := getFakeClient(hco) - wh := NewWebhookHandler(logger, cli, decoder, HcoValidNamespace, true, nil) + wh := NewWebhookHandler(logger, cli, decoder, HcoValidNamespace, true, nil) - newHco := &v1beta1.HyperConverged{} - hco.DeepCopyInto(newHco) + newHco := &hcov1beta1.HyperConverged{} + hco.DeepCopyInto(newHco) - newHco.Spec.TLSSecurityProfile = &openshiftconfigv1.TLSSecurityProfile{ - Custom: &openshiftconfigv1.CustomTLSProfile{ - TLSProfileSpec: openshiftconfigv1.TLSProfileSpec{ - MinTLSVersion: minTLSVersion, - Ciphers: ciphers, + newHco.Spec.TLSSecurityProfile = &openshiftconfigv1.TLSSecurityProfile{ + Custom: &openshiftconfigv1.CustomTLSProfile{ + TLSProfileSpec: openshiftconfigv1.TLSProfileSpec{ + MinTLSVersion: minTLSVersion, + Ciphers: ciphers, + }, }, - }, + } + + return wh.ValidateUpdate(ctx, dryRun, newHco, hco) } - return wh.ValidateUpdate(ctx, dryRun, newHco, hco) - } + DescribeTable("should succeed if has any of the HTTP/2-required ciphers", + func(ctx context.Context, cipher string) { + Expect( + updateTLSSecurityProfile(ctx, openshiftconfigv1.VersionTLS12, []string{"DHE-RSA-AES256-GCM-SHA384", cipher, "DHE-RSA-CHACHA20-POLY1305"}), + ).To(Succeed()) + }, + Entry("ECDHE-RSA-AES128-GCM-SHA256", "ECDHE-RSA-AES128-GCM-SHA256"), + Entry("ECDHE-ECDSA-AES128-GCM-SHA256", "ECDHE-ECDSA-AES128-GCM-SHA256"), + ) + + It("should fail if does not have any of the HTTP/2-required ciphers", func(ctx context.Context) { + err := updateTLSSecurityProfile(ctx, openshiftconfigv1.VersionTLS12, []string{"DHE-RSA-AES256-GCM-SHA384", "DHE-RSA-CHACHA20-POLY1305"}) + Expect(err).To(HaveOccurred()) + Expect(err.Error()).To(ContainSubstring("http2: TLSConfig.CipherSuites is missing an HTTP/2-required AES_128_GCM_SHA256 cipher (need at least one of ECDHE-RSA-AES128-GCM-SHA256 or ECDHE-ECDSA-AES128-GCM-SHA256)")) + }) - DescribeTable("should succeed if has any of the HTTP/2-required ciphers", - func(cipher string) { + It("should succeed if does not have any of the HTTP/2-required ciphers but TLS version >= 1.3", func(ctx context.Context) { Expect( - updateTLSSecurityProfile(openshiftconfigv1.VersionTLS12, []string{"DHE-RSA-AES256-GCM-SHA384", cipher, "DHE-RSA-CHACHA20-POLY1305"}), + updateTLSSecurityProfile(ctx, openshiftconfigv1.VersionTLS13, []string{}), ).To(Succeed()) - }, - Entry("ECDHE-RSA-AES128-GCM-SHA256", "ECDHE-RSA-AES128-GCM-SHA256"), - Entry("ECDHE-ECDSA-AES128-GCM-SHA256", "ECDHE-ECDSA-AES128-GCM-SHA256"), - ) + }) - It("should fail if does not have any of the HTTP/2-required ciphers", func() { - err := updateTLSSecurityProfile(openshiftconfigv1.VersionTLS12, []string{"DHE-RSA-AES256-GCM-SHA384", "DHE-RSA-CHACHA20-POLY1305"}) - Expect(err).To(HaveOccurred()) - Expect(err.Error()).To(ContainSubstring("http2: TLSConfig.CipherSuites is missing an HTTP/2-required AES_128_GCM_SHA256 cipher (need at least one of ECDHE-RSA-AES128-GCM-SHA256 or ECDHE-ECDSA-AES128-GCM-SHA256)")) - }) + It("should fail if does have custom ciphers with TLS version >= 1.3", func(ctx context.Context) { + err := updateTLSSecurityProfile(ctx, openshiftconfigv1.VersionTLS13, []string{"TLS_AES_128_GCM_SHA256", "TLS_CHACHA20_POLY1305_SHA256"}) + Expect(err).To(HaveOccurred()) + Expect(err.Error()).To(ContainSubstring("custom ciphers cannot be selected when minTLSVersion is VersionTLS13")) + }) - It("should succeed if does not have any of the HTTP/2-required ciphers but TLS version >= 1.3", func() { - Expect( - updateTLSSecurityProfile(openshiftconfigv1.VersionTLS13, []string{}), - ).To(Succeed()) + It("should fail when minTLSVersion is invalid", func(ctx context.Context) { + err := updateTLSSecurityProfile(ctx, "invalidProtocolVersion", []string{"TLS_AES_128_GCM_SHA256", "TLS_CHACHA20_POLY1305_SHA256"}) + Expect(err).To(HaveOccurred()) + Expect(err.Error()).To(ContainSubstring("invalid value for spec.tlsSecurityProfile.custom.minTLSVersion")) + }) }) - It("should fail if does have custom ciphers with TLS version >= 1.3", func() { - err := updateTLSSecurityProfile(openshiftconfigv1.VersionTLS13, []string{"TLS_AES_128_GCM_SHA256", "TLS_CHACHA20_POLY1305_SHA256"}) - Expect(err).To(HaveOccurred()) - Expect(err.Error()).To(ContainSubstring("custom ciphers cannot be selected when minTLSVersion is VersionTLS13")) - }) + Context("validate tuning policy on update", func() { + It("should return warning for deprecated highBurst tuning policy", func(ctx context.Context) { + newHCO := hco.DeepCopy() + newHCO.Spec.TuningPolicy = hcov1beta1.HyperConvergedHighBurstProfile //nolint SA1019 + err := wh.ValidateUpdate(ctx, dryRun, newHCO, hco) + Expect(err).To(HaveOccurred()) + expected := &ValidationWarning{} + Expect(errors.As(err, &expected)).To(BeTrue()) + Expect(expected.warnings).To(HaveLen(1)) + Expect(expected.warnings[0]).To(ContainSubstring("highBurst profile is deprecated")) + Expect(expected.warnings[0]).To(ContainSubstring("v1.16.0")) + }) - It("should fail when minTLSVersion is invalid", func() { - err := updateTLSSecurityProfile("invalidProtocolVersion", []string{"TLS_AES_128_GCM_SHA256", "TLS_CHACHA20_POLY1305_SHA256"}) - Expect(err).To(HaveOccurred()) - Expect(err.Error()).To(ContainSubstring("invalid value for spec.tlsSecurityProfile.custom.minTLSVersion")) + It("should not return warning when tuning policy is not set", func(ctx context.Context) { + newHCO := hco.DeepCopy() + newHCO.Spec.TuningPolicy = "" + Expect(wh.ValidateUpdate(ctx, dryRun, newHCO, hco)).To(Succeed()) + }) }) - }) - - Context("validate deprecated FGs", func() { - DescribeTable("should return warning for deprecated feature gate", func(fgs v1beta1.HyperConvergedFeatureGates, fgNames ...string) { - newHCO := hco.DeepCopy() - newHCO.Spec.FeatureGates = fgs - - err := wh.ValidateUpdate(ctx, dryRun, newHCO, hco) - - Expect(err).To(HaveOccurred()) - expected := &ValidationWarning{} - Expect(errors.As(err, &expected)).To(BeTrue()) - - Expect(expected.warnings).To(HaveLen(len(fgNames))) - for _, fgName := range fgNames { - Expect(expected.warnings).To(ContainElements(ContainSubstring(fgName))) - } - }, - Entry("should trigger a warning if the withHostPassthroughCPU=false FG exists in the CR", - v1beta1.HyperConvergedFeatureGates{WithHostPassthroughCPU: ptr.To(false)}, "withHostPassthroughCPU"), - Entry("should trigger a warning if the withHostPassthroughCPU=true FG exists in the CR", - v1beta1.HyperConvergedFeatureGates{WithHostPassthroughCPU: ptr.To(true)}, "withHostPassthroughCPU"), - - Entry("should trigger a warning if the deployTektonTaskResources=false FG exists in the CR", - v1beta1.HyperConvergedFeatureGates{DeployTektonTaskResources: ptr.To(false)}, "deployTektonTaskResources"), - Entry("should trigger a warning if the deployTektonTaskResources=true FG exists in the CR", - v1beta1.HyperConvergedFeatureGates{DeployTektonTaskResources: ptr.To(true)}, "deployTektonTaskResources"), - - Entry("should trigger a warning if the enableManagedTenantQuota=false FG exists in the CR", - v1beta1.HyperConvergedFeatureGates{EnableManagedTenantQuota: ptr.To(false)}, "enableManagedTenantQuota"), - Entry("should trigger a warning if the enableManagedTenantQuota=true FG exists in the CR", - v1beta1.HyperConvergedFeatureGates{EnableManagedTenantQuota: ptr.To(true)}, "enableManagedTenantQuota"), - - Entry("should trigger a warning if the nonRoot=false FG exists in the CR", - v1beta1.HyperConvergedFeatureGates{NonRoot: ptr.To(false)}, "nonRoot"), - Entry("should trigger a warning if the nonRoot=true FG exists in the CR", - v1beta1.HyperConvergedFeatureGates{NonRoot: ptr.To(true)}, "nonRoot"), - - Entry("should trigger multiple warnings if several deprecated FG exist in the CR", - v1beta1.HyperConvergedFeatureGates{ - NonRoot: ptr.To(true), - EnableManagedTenantQuota: ptr.To(true), - }, "enableManagedTenantQuota", "nonRoot"), - - Entry("should trigger multiple warnings if several deprecated FG exist in the CR, with some valid FGs", - v1beta1.HyperConvergedFeatureGates{ - DownwardMetrics: ptr.To(true), - NonRoot: ptr.To(false), - EnableCommonBootImageImport: ptr.To(true), - EnableManagedTenantQuota: ptr.To(false), - }, "enableManagedTenantQuota", "nonRoot", "enableCommonBootImageImport"), - ) - }) - - Context("validate moved FG on update", func() { - //nolint:staticcheck - DescribeTable("should return warning for enableApplicationAwareQuota on update", func(newFG, oldFG *bool) { - newHCO := hco.DeepCopy() - hco.Spec.FeatureGates.EnableApplicationAwareQuota = newFG - newHCO.Spec.FeatureGates.EnableApplicationAwareQuota = oldFG - - err := wh.ValidateUpdate(ctx, dryRun, newHCO, hco) - - Expect(err).To(HaveOccurred()) - expected := &ValidationWarning{} - Expect(errors.As(err, &expected)).To(BeTrue()) - - Expect(expected.warnings).To(HaveLen(1)) - Expect(expected.warnings).To(ContainElements(ContainSubstring("enableApplicationAwareQuota"))) - }, - Entry("should trigger warning if enableApplicationAwareQuota appeared as true", nil, ptr.To(true)), - Entry("should trigger warning if enableApplicationAwareQuota appeared as false", nil, ptr.To(false)), - Entry("should trigger warning if enableApplicationAwareQuota has changed from true to false", ptr.To(true), ptr.To(false)), - Entry("should trigger warning if enableApplicationAwareQuota has changed from false to true", ptr.To(false), ptr.To(true)), - ) - - //nolint:staticcheck - DescribeTable("should not return warning for enableApplicationAwareQuota if not change", func(newFG, oldFG *bool) { - cli := getFakeClient(hco) - wh := NewWebhookHandler(logger, cli, decoder, HcoValidNamespace, true, nil) - newHCO := hco.DeepCopy() - hco.Spec.FeatureGates.EnableApplicationAwareQuota = newFG - newHCO.Spec.FeatureGates.EnableApplicationAwareQuota = oldFG - - Expect(wh.ValidateUpdate(ctx, dryRun, newHCO, hco)).To(Succeed()) - }, - Entry("should not trigger warning if enableApplicationAwareQuota (true) disappeared", ptr.To(true), nil), - Entry("should not trigger warning if enableApplicationAwareQuota (false) disappeared", ptr.To(false), nil), - Entry("should not trigger warning if enableApplicationAwareQuota (true) wasn't changed", ptr.To(true), ptr.To(true)), - Entry("should not trigger warning if enableApplicationAwareQuota (false) wasn't changed", ptr.To(false), ptr.To(false)), - ) - - //nolint:staticcheck - DescribeTable("should return warning for enableCommonBootImageImport on update", func(newFG, oldFG *bool) { - newHCO := hco.DeepCopy() - hco.Spec.FeatureGates.EnableCommonBootImageImport = newFG - newHCO.Spec.FeatureGates.EnableCommonBootImageImport = oldFG - err := wh.ValidateUpdate(ctx, dryRun, newHCO, hco) - - Expect(err).To(HaveOccurred()) - expected := &ValidationWarning{} - Expect(errors.As(err, &expected)).To(BeTrue()) - - Expect(expected.warnings).To(HaveLen(1)) - Expect(expected.warnings).To(ContainElements(ContainSubstring("enableCommonBootImageImport"))) - }, - Entry("should trigger warning if enableCommonBootImageImport appeared as true", nil, ptr.To(true)), - Entry("should trigger warning if enableCommonBootImageImport appeared as false", nil, ptr.To(false)), - Entry("should trigger warning if enableCommonBootImageImport has changed from true to false", ptr.To(true), ptr.To(false)), - Entry("should trigger warning if enableCommonBootImageImport has changed from false to true", ptr.To(false), ptr.To(true)), - ) - - //nolint:staticcheck - DescribeTable("should not return warning for enableCommonBootImageImport if not change", func(newFG, oldFG *bool) { - cli := getFakeClient(hco) - wh := NewWebhookHandler(logger, cli, decoder, HcoValidNamespace, true, nil) - newHCO := hco.DeepCopy() - hco.Spec.FeatureGates.EnableCommonBootImageImport = newFG - newHCO.Spec.FeatureGates.EnableCommonBootImageImport = oldFG - - Expect(wh.ValidateUpdate(ctx, dryRun, newHCO, hco)).To(Succeed()) - }, - Entry("should not trigger warning if enableCommonBootImageImport (true) disappeared", ptr.To(true), nil), - Entry("should not trigger warning if enableCommonBootImageImport (false) disappeared", ptr.To(false), nil), - Entry("should not trigger warning if enableCommonBootImageImport (true) wasn't changed", ptr.To(true), ptr.To(true)), - Entry("should not trigger warning if enableCommonBootImageImport (false) wasn't changed", ptr.To(false), ptr.To(false)), - ) - - //nolint:staticcheck - DescribeTable("should return warning for deployVmConsoleProxy on update", func(newFG, oldFG *bool) { - newHCO := hco.DeepCopy() - hco.Spec.FeatureGates.DeployVMConsoleProxy = newFG - newHCO.Spec.FeatureGates.DeployVMConsoleProxy = oldFG - - err := wh.ValidateUpdate(ctx, dryRun, newHCO, hco) - - Expect(err).To(HaveOccurred()) - expected := &ValidationWarning{} - Expect(errors.As(err, &expected)).To(BeTrue()) - - Expect(expected.warnings).To(HaveLen(1)) - Expect(expected.warnings).To(ContainElements(ContainSubstring("deployVmConsoleProxy"))) - }, - Entry("should trigger warning if deployVmConsoleProxy appeared as true", nil, ptr.To(true)), - Entry("should trigger warning if deployVmConsoleProxy appeared as false", nil, ptr.To(false)), - Entry("should trigger warning if deployVmConsoleProxy has changed from true to false", ptr.To(true), ptr.To(false)), - Entry("should trigger warning if deployVmConsoleProxy has changed from false to true", ptr.To(false), ptr.To(true)), - ) + Context("unsupported annotation", func() { + DescribeTable("should accept if annotation is valid", + func(ctx context.Context, annotationName, annotation string) { + cli := getFakeClient(hco) + wh := NewWebhookHandler(logger, cli, decoder, HcoValidNamespace, true, nil) - //nolint:staticcheck - DescribeTable("should not return warning for deployVmConsoleProxy if not change", func(newFG, oldFG *bool) { - cli := getFakeClient(hco) - wh := NewWebhookHandler(logger, cli, decoder, HcoValidNamespace, true, nil) - newHCO := hco.DeepCopy() - hco.Spec.FeatureGates.DeployVMConsoleProxy = newFG - newHCO.Spec.FeatureGates.DeployVMConsoleProxy = oldFG + newHco := &hcov1beta1.HyperConverged{} + hco.DeepCopyInto(newHco) + hco.Annotations = map[string]string{annotationName: annotation} - Expect(wh.ValidateUpdate(ctx, dryRun, newHCO, hco)).To(Succeed()) - }, - Entry("should not trigger warning if deployVmConsoleProxy (true) disappeared", ptr.To(true), nil), - Entry("should not trigger warning if deployVmConsoleProxy (false) disappeared", ptr.To(false), nil), - Entry("should not trigger warning if deployVmConsoleProxy (true) wasn't changed", ptr.To(true), ptr.To(true)), - Entry("should not trigger warning if deployVmConsoleProxy (false) wasn't changed", ptr.To(false), ptr.To(false)), - ) + Expect(wh.ValidateUpdate(ctx, dryRun, newHco, hco)).To(Succeed()) + }, + Entry("should accept if kv annotation is valid", common.JSONPatchKVAnnotationName, validKvAnnotation), + Entry("should accept if cdi annotation is valid", common.JSONPatchCDIAnnotationName, validCdiAnnotation), + Entry("should accept if cna annotation is valid", common.JSONPatchCNAOAnnotationName, validCnaAnnotation), + Entry("should accept if ssp annotation is valid", common.JSONPatchSSPAnnotationName, validSspAnnotation), + ) - //nolint:staticcheck - DescribeTable("should not return warning for deployKubeSecondaryDNS if not change", func(newFG, oldFG *bool) { - cli := getFakeClient(hco) - wh := NewWebhookHandler(logger, cli, decoder, HcoValidNamespace, true, nil) - newHCO := hco.DeepCopy() - hco.Spec.FeatureGates.DeployKubeSecondaryDNS = newFG - newHCO.Spec.FeatureGates.DeployKubeSecondaryDNS = oldFG + DescribeTable("should reject if annotation is invalid", + func(ctx context.Context, annotationName, annotation string) { + cli := getFakeClient(hco) + cli.InitiateUpdateErrors(initiateTimeout) - Expect(wh.ValidateUpdate(ctx, dryRun, newHCO, hco)).To(Succeed()) - }, - Entry("should not trigger warning if deployKubeSecondaryDNS (true) disappeared", ptr.To(true), nil), - Entry("should not trigger warning if deployKubeSecondaryDNS (false) disappeared", ptr.To(false), nil), - Entry("should not trigger warning if deployKubeSecondaryDNS (true) wasn't changed", ptr.To(true), ptr.To(true)), - Entry("should not trigger warning if deployKubeSecondaryDNS (false) wasn't changed", ptr.To(false), ptr.To(false)), - ) - }) + wh := NewWebhookHandler(logger, cli, decoder, HcoValidNamespace, true, nil) - Context("validate tuning policy on update", func() { - It("should return warning for deprecated highBurst tuning policy", func() { - newHCO := hco.DeepCopy() - newHCO.Spec.TuningPolicy = v1beta1.HyperConvergedHighBurstProfile //nolint SA1019 - err := wh.ValidateUpdate(ctx, dryRun, newHCO, hco) - Expect(err).To(HaveOccurred()) - expected := &ValidationWarning{} - Expect(errors.As(err, &expected)).To(BeTrue()) - Expect(expected.warnings).To(HaveLen(1)) - Expect(expected.warnings[0]).To(ContainSubstring("highBurst profile is deprecated")) - Expect(expected.warnings[0]).To(ContainSubstring("v1.16.0")) - }) + newHco := &hcov1beta1.HyperConverged{} + hco.DeepCopyInto(newHco) + newHco.Annotations = map[string]string{annotationName: annotation} - It("should not return warning when tuning policy is not set", func() { - newHCO := hco.DeepCopy() - newHCO.Spec.TuningPolicy = "" - Expect(wh.ValidateUpdate(ctx, dryRun, newHCO, hco)).To(Succeed()) + Expect(wh.ValidateUpdate(context.TODO(), false, newHco, hco)).To(MatchError(ContainSubstring("invalid jsonPatch in the %s", annotationName))) + }, + Entry("should reject if kv annotation is invalid", common.JSONPatchKVAnnotationName, invalidKvAnnotation), + Entry("should reject if cdi annotation is invalid", common.JSONPatchCDIAnnotationName, invalidCdiAnnotation), + Entry("should reject if cna annotation is invalid", common.JSONPatchCNAOAnnotationName, invalidCnaAnnotation), + Entry("should accept if ssp annotation is invalid", common.JSONPatchSSPAnnotationName, invalidSspAnnotation), + ) }) }) }) Context("validate delete validation webhook", func() { - var hco *v1beta1.HyperConverged - var dryRun bool - var ctx context.Context - - BeforeEach(func() { - hco = &v1beta1.HyperConverged{ - ObjectMeta: metav1.ObjectMeta{ - Name: util.HyperConvergedName, - Namespace: HcoValidNamespace, - }, - } - dryRun = false - ctx = context.TODO() - }) - - It("should correctly handle a valid delete request", func() { - req := newRequest(admissionv1.Delete, hco, v1beta1Codec, false) - - res := wh.Handle(ctx, req) - Expect(res.Allowed).To(BeTrue()) - Expect(res.Result.Code).To(Equal(int32(200))) - }) + Context("check delete request", func() { + var hco *hcov1.HyperConverged - It("should correctly handle a valid dryrun delete request", func() { - req := newRequest(admissionv1.Delete, hco, v1beta1Codec, true) - - res := wh.Handle(ctx, req) - Expect(res.Allowed).To(BeTrue()) - Expect(res.Result.Code).To(Equal(int32(200))) - }) - - It("should reject a malformed delete request", func() { - req := newRequest(admissionv1.Delete, hco, v1beta1Codec, false) - req.OldObject = req.Object - req.Object = runtime.RawExtension{} + BeforeEach(func() { + hco = &hcov1.HyperConverged{ + ObjectMeta: metav1.ObjectMeta{ + Name: util.HyperConvergedName, + Namespace: HcoValidNamespace, + }, + } + }) - res := wh.Handle(ctx, req) - Expect(res.Allowed).To(BeFalse()) - Expect(res.Result.Code).To(Equal(int32(400))) - Expect(res.Result.Message).To(Equal("there is no content to decode")) - }) + It("should correctly handle a valid delete request", func(ctx context.Context) { + req := newRequest(admissionv1.Delete, hco, v1Codec, false) + ctx = logr.NewContext(ctx, GinkgoLogr) - It("should validate deletion", func() { - cli := getFakeClient(hco) + res := wh.Handle(ctx, req) + Expect(res.Allowed).To(BeTrue()) + Expect(res.Result.Code).To(Equal(int32(200))) + }) - wh := NewWebhookHandler(logger, cli, decoder, HcoValidNamespace, true, nil) + It("should correctly handle a valid dryrun delete request", func(ctx context.Context) { + req := newRequest(admissionv1.Delete, hco, v1Codec, true) + ctx = logr.NewContext(ctx, GinkgoLogr) - Expect(wh.ValidateDelete(ctx, dryRun, hco)).To(Succeed()) + res := wh.Handle(ctx, req) + Expect(res.Allowed).To(BeTrue()) + Expect(res.Result.Code).To(Equal(int32(200))) + }) - By("Validate that KV still exists, as it a dry-run deletion") - kv := handlers.NewKubeVirtWithNameOnly(hco) - Expect(util.GetRuntimeObject(context.TODO(), cli, kv)).To(Succeed()) + It("should reject a malformed delete request", func(ctx context.Context) { + req := newRequest(admissionv1.Delete, hco, v1Codec, false) + req.OldObject = req.Object + req.Object = runtime.RawExtension{} + ctx = logr.NewContext(ctx, GinkgoLogr) - By("Validate that CDI still exists, as it a dry-run deletion") - cdi := handlers.NewCDIWithNameOnly(hco) - Expect(util.GetRuntimeObject(context.TODO(), cli, cdi)).To(Succeed()) + res := wh.Handle(ctx, req) + Expect(res.Allowed).To(BeFalse()) + Expect(res.Result.Code).To(Equal(int32(400))) + Expect(res.Result.Message).To(Equal(decodeErrorMsg)) + }) }) - It("should reject if KV deletion fails", func() { - cli := getFakeClient(hco) + Context("check ValidateDelete", func() { + var hco *hcov1beta1.HyperConverged - wh := NewWebhookHandler(logger, cli, decoder, HcoValidNamespace, true, nil) - - cli.InitiateDeleteErrors(func(obj client.Object) error { - if unstructed, ok := obj.(runtime.Unstructured); ok { - kind := unstructed.GetObjectKind() - if kind.GroupVersionKind().Kind == "KubeVirt" { - return ErrFakeKvError - } + BeforeEach(func() { + hco = &hcov1beta1.HyperConverged{ + ObjectMeta: metav1.ObjectMeta{ + Name: util.HyperConvergedName, + Namespace: HcoValidNamespace, + }, } - return nil }) - err := wh.ValidateDelete(ctx, dryRun, hco) - Expect(err).To(MatchError(ErrFakeKvError)) - }) + It("should validate deletion", func(ctx context.Context) { + cli := getFakeClient(hco) - It("should reject if CDI deletion fails", func() { - cli := getFakeClient(hco) + wh := NewWebhookHandler(logger, cli, decoder, HcoValidNamespace, true, nil) - wh := NewWebhookHandler(logger, cli, decoder, HcoValidNamespace, true, nil) + Expect(wh.ValidateDelete(ctx, dryRun, hco)).To(Succeed()) - cli.InitiateDeleteErrors(func(obj client.Object) error { - if unstructed, ok := obj.(runtime.Unstructured); ok { - kind := unstructed.GetObjectKind() - if kind.GroupVersionKind().Kind == "CDI" { - return ErrFakeCdiError - } - } - return nil + By("Validate that KV still exists, as it a dry-run deletion") + kv := handlers.NewKubeVirtWithNameOnly(hco) + Expect(util.GetRuntimeObject(context.TODO(), cli, kv)).To(Succeed()) + + By("Validate that CDI still exists, as it a dry-run deletion") + cdi := handlers.NewCDIWithNameOnly(hco) + Expect(util.GetRuntimeObject(context.TODO(), cli, cdi)).To(Succeed()) }) - err := wh.ValidateDelete(ctx, dryRun, hco) - Expect(err).To(MatchError(ErrFakeCdiError)) - }) + It("should reject if KV deletion fails", func(ctx context.Context) { + cli := getFakeClient(hco) - It("should ignore if KV does not exist", func() { - cli := getFakeClient(hco) - ctx := context.TODO() + wh := NewWebhookHandler(logger, cli, decoder, HcoValidNamespace, true, nil) - kv := handlers.NewKubeVirtWithNameOnly(hco) - Expect(cli.Delete(ctx, kv)).To(Succeed()) + cli.InitiateDeleteErrors(func(obj client.Object) error { + if unstructed, ok := obj.(runtime.Unstructured); ok { + kind := unstructed.GetObjectKind() + if kind.GroupVersionKind().Kind == "KubeVirt" { + return ErrFakeKvError + } + } + return nil + }) - wh := NewWebhookHandler(logger, cli, decoder, HcoValidNamespace, true, nil) + err := wh.ValidateDelete(ctx, dryRun, hco) + Expect(err).To(MatchError(ErrFakeKvError)) + }) - Expect(wh.ValidateDelete(ctx, dryRun, hco)).To(Succeed()) - }) + It("should reject if CDI deletion fails", func(ctx context.Context) { + cli := getFakeClient(hco) - It("should reject if getting KV failed for not-not-exists error", func() { - cli := getFakeClient(hco) + wh := NewWebhookHandler(logger, cli, decoder, HcoValidNamespace, true, nil) - wh := NewWebhookHandler(logger, cli, decoder, HcoValidNamespace, true, nil) + cli.InitiateDeleteErrors(func(obj client.Object) error { + if unstructed, ok := obj.(runtime.Unstructured); ok { + kind := unstructed.GetObjectKind() + if kind.GroupVersionKind().Kind == "CDI" { + return ErrFakeCdiError + } + } + return nil + }) - cli.InitiateGetErrors(func(key client.ObjectKey) error { - if key.Name == "kubevirt-kubevirt-hyperconverged" { - return ErrFakeKvError - } - return nil + err := wh.ValidateDelete(ctx, dryRun, hco) + Expect(err).To(MatchError(ErrFakeCdiError)) }) - err := wh.ValidateDelete(ctx, dryRun, hco) - Expect(err).To(MatchError(ErrFakeKvError)) - }) + It("should ignore if KV does not exist", func(ctx context.Context) { + cli := getFakeClient(hco) - It("should ignore if CDI does not exist", func() { - cli := getFakeClient(hco) - ctx := context.TODO() + kv := handlers.NewKubeVirtWithNameOnly(hco) + Expect(cli.Delete(ctx, kv)).To(Succeed()) - cdi := handlers.NewCDIWithNameOnly(hco) - Expect(cli.Delete(ctx, cdi)).To(Succeed()) + wh := NewWebhookHandler(logger, cli, decoder, HcoValidNamespace, true, nil) - wh := NewWebhookHandler(logger, cli, decoder, HcoValidNamespace, true, nil) + Expect(wh.ValidateDelete(ctx, dryRun, hco)).To(Succeed()) + }) - Expect(wh.ValidateDelete(ctx, dryRun, hco)).To(Succeed()) - }) + It("should reject if getting KV failed for not-not-exists error", func(ctx context.Context) { + cli := getFakeClient(hco) - It("should reject if getting CDI failed for not-not-exists error", func() { - cli := getFakeClient(hco) + wh := NewWebhookHandler(logger, cli, decoder, HcoValidNamespace, true, nil) - wh := NewWebhookHandler(logger, cli, decoder, HcoValidNamespace, true, nil) + cli.InitiateGetErrors(func(key client.ObjectKey) error { + if key.Name == "kubevirt-kubevirt-hyperconverged" { + return ErrFakeKvError + } + return nil + }) - cli.InitiateGetErrors(func(key client.ObjectKey) error { - if key.Name == "cdi-kubevirt-hyperconverged" { - return ErrFakeCdiError - } - return nil + err := wh.ValidateDelete(ctx, dryRun, hco) + Expect(err).To(MatchError(ErrFakeKvError)) }) - err := wh.ValidateDelete(ctx, dryRun, hco) - Expect(err).To(MatchError(ErrFakeCdiError)) - }) - }) + It("should ignore if CDI does not exist", func(ctx context.Context) { + cli := getFakeClient(hco) - Context("unsupported annotation", func() { - var hco *v1beta1.HyperConverged - BeforeEach(func() { - Expect(os.Setenv("OPERATOR_NAMESPACE", HcoValidNamespace)).To(Succeed()) - hco = commontestutils.NewHco() - }) + cdi := handlers.NewCDIWithNameOnly(hco) + Expect(cli.Delete(ctx, cdi)).To(Succeed()) - DescribeTable("should accept if annotation is valid", - func(annotationName, annotation string) { - cli := getFakeClient(hco) wh := NewWebhookHandler(logger, cli, decoder, HcoValidNamespace, true, nil) - dryRun := false - ctx := context.TODO() - - newHco := &v1beta1.HyperConverged{} - hco.DeepCopyInto(newHco) - hco.Annotations = map[string]string{annotationName: annotation} + Expect(wh.ValidateDelete(ctx, dryRun, hco)).To(Succeed()) + }) - Expect(wh.ValidateUpdate(ctx, dryRun, newHco, hco)).To(Succeed()) - }, - Entry("should accept if kv annotation is valid", common.JSONPatchKVAnnotationName, validKvAnnotation), - Entry("should accept if cdi annotation is valid", common.JSONPatchCDIAnnotationName, validCdiAnnotation), - Entry("should accept if cna annotation is valid", common.JSONPatchCNAOAnnotationName, validCnaAnnotation), - Entry("should accept if ssp annotation is valid", common.JSONPatchSSPAnnotationName, validSspAnnotation), - ) - - DescribeTable("should reject if annotation is invalid", - func(annotationName, annotation string) { + It("should reject if getting CDI failed for not-not-exists error", func(ctx context.Context) { cli := getFakeClient(hco) - cli.InitiateUpdateErrors(initiateTimeout) wh := NewWebhookHandler(logger, cli, decoder, HcoValidNamespace, true, nil) - newHco := &v1beta1.HyperConverged{} - hco.DeepCopyInto(newHco) - newHco.Annotations = map[string]string{annotationName: annotation} + cli.InitiateGetErrors(func(key client.ObjectKey) error { + if key.Name == "cdi-kubevirt-hyperconverged" { + return ErrFakeCdiError + } + return nil + }) - Expect(wh.ValidateUpdate(context.TODO(), false, newHco, hco)).To(MatchError(ContainSubstring("invalid jsonPatch in the %s", annotationName))) - }, - Entry("should reject if kv annotation is invalid", common.JSONPatchKVAnnotationName, invalidKvAnnotation), - Entry("should reject if cdi annotation is invalid", common.JSONPatchCDIAnnotationName, invalidCdiAnnotation), - Entry("should reject if cna annotation is invalid", common.JSONPatchCNAOAnnotationName, invalidCnaAnnotation), - Entry("should accept if ssp annotation is invalid", common.JSONPatchSSPAnnotationName, invalidSspAnnotation), - ) + err := wh.ValidateDelete(ctx, dryRun, hco) + Expect(err).To(MatchError(ErrFakeCdiError)) + }) + }) }) Context("hcoTLSConfigCache", func() { - var cr *v1beta1.HyperConverged - var ctx context.Context + var cr *hcov1beta1.HyperConverged intermediateTLSSecurityProfile := openshiftconfigv1.TLSSecurityProfile{ Type: openshiftconfigv1.TLSProfileIntermediateType, @@ -1824,34 +1580,32 @@ var _ = Describe("webhooks validator", func() { } BeforeEach(func() { - Expect(os.Setenv("OPERATOR_NAMESPACE", HcoValidNamespace)).To(Succeed()) - cr = commontestutils.NewHco() - ctx = context.TODO() hcoTLSConfigCache = &initialTLSSecurityProfile + cr = commontestutils.NewHco() }) Context("create", func() { - It("should update hcoTLSConfigCache creating a resource not in dry run mode", func() { + It("should update hcoTLSConfigCache creating a resource not in dry run mode", func(ctx context.Context) { Expect(hcoTLSConfigCache).To(Equal(&initialTLSSecurityProfile)) cr.Spec.TLSSecurityProfile = &modernTLSSecurityProfile Expect(wh.ValidateCreate(ctx, false, cr)).To(Succeed()) Expect(hcoTLSConfigCache).To(Equal(&modernTLSSecurityProfile)) }) - It("should not update hcoTLSConfigCache creating a resource in dry run mode", func() { + It("should not update hcoTLSConfigCache creating a resource in dry run mode", func(ctx context.Context) { Expect(hcoTLSConfigCache).To(Equal(&initialTLSSecurityProfile)) cr.Spec.TLSSecurityProfile = &modernTLSSecurityProfile Expect(wh.ValidateCreate(ctx, true, cr)).To(Succeed()) Expect(hcoTLSConfigCache).ToNot(Equal(&modernTLSSecurityProfile)) }) - It("should not update hcoTLSConfigCache if the create request is refused", func() { + It("should not update hcoTLSConfigCache if the create request is refused", func(ctx context.Context) { Expect(hcoTLSConfigCache).To(Equal(&initialTLSSecurityProfile)) cr.Spec.TLSSecurityProfile = &modernTLSSecurityProfile cr.Namespace = ResourceInvalidNamespace - cr.Spec.DataImportCronTemplates = []v1beta1.DataImportCronTemplate{ + cr.Spec.DataImportCronTemplates = []hcov1beta1.DataImportCronTemplate{ { ObjectMeta: metav1.ObjectMeta{ Annotations: map[string]string{ @@ -1868,13 +1622,13 @@ var _ = Describe("webhooks validator", func() { Context("update", func() { - It("should update hcoTLSConfigCache updating a resource not in dry run mode", func() { + It("should update hcoTLSConfigCache updating a resource not in dry run mode", func(ctx context.Context) { cli := getFakeClient(cr) cli.InitiateUpdateErrors(getUpdateError(noFailure)) wh := NewWebhookHandler(logger, cli, decoder, HcoValidNamespace, true, nil) - newCr := &v1beta1.HyperConverged{} + newCr := &hcov1beta1.HyperConverged{} cr.DeepCopyInto(newCr) newCr.Spec.TLSSecurityProfile = &oldTLSSecurityProfile @@ -1882,13 +1636,13 @@ var _ = Describe("webhooks validator", func() { Expect(hcoTLSConfigCache).To(Equal(&oldTLSSecurityProfile)) }) - It("should not update hcoTLSConfigCache updating a resource in dry run mode", func() { + It("should not update hcoTLSConfigCache updating a resource in dry run mode", func(ctx context.Context) { cli := getFakeClient(cr) cli.InitiateUpdateErrors(getUpdateError(noFailure)) wh := NewWebhookHandler(logger, cli, decoder, HcoValidNamespace, true, &initialTLSSecurityProfile) - newCr := &v1beta1.HyperConverged{} + newCr := &hcov1beta1.HyperConverged{} cr.DeepCopyInto(newCr) newCr.Spec.TLSSecurityProfile = &oldTLSSecurityProfile @@ -1896,13 +1650,13 @@ var _ = Describe("webhooks validator", func() { Expect(hcoTLSConfigCache).To(Equal(&initialTLSSecurityProfile)) }) - It("should not update hcoTLSConfigCache if the update request is refused", func() { + It("should not update hcoTLSConfigCache if the update request is refused", func(ctx context.Context) { cli := getFakeClient(cr) cli.InitiateUpdateErrors(getUpdateError(cdiUpdateFailure)) wh := NewWebhookHandler(logger, cli, decoder, HcoValidNamespace, true, &initialTLSSecurityProfile) - newCr := &v1beta1.HyperConverged{} + newCr := &hcov1beta1.HyperConverged{} cr.DeepCopyInto(newCr) newCr.Spec.TLSSecurityProfile = &oldTLSSecurityProfile @@ -1915,7 +1669,7 @@ var _ = Describe("webhooks validator", func() { Context("delete", func() { - It("should reset hcoTLSConfigCache deleting a resource not in dry run mode", func() { + It("should reset hcoTLSConfigCache deleting a resource not in dry run mode", func(ctx context.Context) { cli := getFakeClient(cr) wh := NewWebhookHandler(logger, cli, decoder, HcoValidNamespace, true, nil) @@ -1925,7 +1679,7 @@ var _ = Describe("webhooks validator", func() { Expect(hcoTLSConfigCache).To(BeNil()) }) - It("should not update hcoTLSConfigCache deleting a resource in dry run mode", func() { + It("should not update hcoTLSConfigCache deleting a resource in dry run mode", func(ctx context.Context) { cli := getFakeClient(cr) wh := NewWebhookHandler(logger, cli, decoder, HcoValidNamespace, true, nil) @@ -1935,7 +1689,7 @@ var _ = Describe("webhooks validator", func() { Expect(hcoTLSConfigCache).To(Equal(&modernTLSSecurityProfile)) }) - It("should not update hcoTLSConfigCache if the delete request is refused", func() { + It("should not update hcoTLSConfigCache if the delete request is refused", func(ctx context.Context) { cli := getFakeClient(cr) wh := NewWebhookHandler(logger, cli, decoder, HcoValidNamespace, true, nil) @@ -2107,180 +1861,6 @@ var _ = Describe("webhooks validator", func() { }) }) - - Context("MediatedDeviceTypes", func() { - var cr *v1beta1.HyperConverged - var newCr *v1beta1.HyperConverged - var ctx context.Context - - BeforeEach(func() { - Expect(os.Setenv("OPERATOR_NAMESPACE", HcoValidNamespace)).To(Succeed()) - cr = commontestutils.NewHco() - cr.Spec.MediatedDevicesConfiguration = nil - newCr = cr.DeepCopy() - ctx = context.TODO() - }) - - DescribeTable("Check mediatedDevicesTypes -> mediatedDeviceTypes transition", func(mDConfiguration *v1beta1.MediatedDevicesConfiguration, expected types.GomegaMatcher) { - // create - newCr.Spec.MediatedDevicesConfiguration = mDConfiguration - Expect(wh.ValidateCreate(ctx, false, newCr)).To(expected) - - // update - cli := getFakeClient(cr) - cli.InitiateUpdateErrors(getUpdateError(noFailure)) - whU := NewWebhookHandler(logger, cli, decoder, HcoValidNamespace, true, nil) - Expect(whU.ValidateUpdate(ctx, false, newCr, cr)).To(expected) - }, - Entry("should not fail with no configuration", - nil, - Succeed(), - ), - Entry("should not fail if using only mediatedDeviceTypes", - &v1beta1.MediatedDevicesConfiguration{ - MediatedDeviceTypes: []string{"nvidia-222", "nvidia-230"}, - NodeMediatedDeviceTypes: []v1beta1.NodeMediatedDeviceTypesConfig{ - { - NodeSelector: map[string]string{ - "testLabel1": "true", - }, - MediatedDeviceTypes: []string{ - "nvidia-223", - }, - }, - { - NodeSelector: map[string]string{ - "testLabel2": "true", - }, - MediatedDeviceTypes: []string{ - "nvidia-229", - }, - }, - }, - }, - Succeed(), - ), - Entry("should not fail if using only deprecated APIs", - &v1beta1.MediatedDevicesConfiguration{ - MediatedDevicesTypes: []string{"nvidia-222", "nvidia-230"}, - NodeMediatedDeviceTypes: []v1beta1.NodeMediatedDeviceTypesConfig{ - { - NodeSelector: map[string]string{ - "testLabel1": "true", - }, - MediatedDevicesTypes: []string{ - "nvidia-223", - }, - }, - { - NodeSelector: map[string]string{ - "testLabel2": "true", - }, - MediatedDevicesTypes: []string{ - "nvidia-229", - }, - }, - }, - }, - Succeed(), - ), - Entry("should not fail if correctly using both mediatedDeviceTypes and deprecated APIs", - &v1beta1.MediatedDevicesConfiguration{ - MediatedDevicesTypes: []string{"nvidia-222", "nvidia-230"}, - MediatedDeviceTypes: []string{"nvidia-222", "nvidia-230"}, - NodeMediatedDeviceTypes: []v1beta1.NodeMediatedDeviceTypesConfig{ - { - NodeSelector: map[string]string{ - "testLabel1": "true", - }, - MediatedDevicesTypes: []string{ - "nvidia-223", - }, - MediatedDeviceTypes: []string{ - "nvidia-223", - }, - }, - { - NodeSelector: map[string]string{ - "testLabel2": "true", - }, - MediatedDevicesTypes: []string{ - "nvidia-229", - }, - MediatedDeviceTypes: []string{ - "nvidia-229", - }, - }, - }, - }, - Succeed(), - ), - Entry("should fail if mixing mediatedDeviceTypes and deprecated APIs on spec.mediatedDevicesConfiguration.mediatedDeviceTypes", - &v1beta1.MediatedDevicesConfiguration{ - MediatedDevicesTypes: []string{"nvidia-222", "nvidia-230"}, - MediatedDeviceTypes: []string{"nvidia-222"}, - NodeMediatedDeviceTypes: []v1beta1.NodeMediatedDeviceTypesConfig{ - { - NodeSelector: map[string]string{ - "testLabel1": "true", - }, - MediatedDevicesTypes: []string{ - "nvidia-223", - }, - MediatedDeviceTypes: []string{ - "nvidia-223", - }, - }, - { - NodeSelector: map[string]string{ - "testLabel2": "true", - }, - MediatedDevicesTypes: []string{ - "nvidia-229", - }, - MediatedDeviceTypes: []string{ - "nvidia-229", - }, - }, - }, - }, - Not(Succeed()), - ), - Entry("should fail if mixing mediatedDeviceTypes and deprecated APIs on spec.mediatedDevicesConfiguration.nodeMediatedDeviceTypes[1].mediatedDeviceTypes", - &v1beta1.MediatedDevicesConfiguration{ - MediatedDevicesTypes: []string{"nvidia-222", "nvidia-230"}, - MediatedDeviceTypes: []string{"nvidia-222", "nvidia-230"}, - NodeMediatedDeviceTypes: []v1beta1.NodeMediatedDeviceTypesConfig{ - { - NodeSelector: map[string]string{ - "testLabel1": "true", - }, - MediatedDevicesTypes: []string{ - "nvidia-223", - }, - MediatedDeviceTypes: []string{ - "nvidia-223", - }, - }, - { - NodeSelector: map[string]string{ - "testLabel2": "true", - }, - MediatedDevicesTypes: []string{ - "nvidia-229", - }, - MediatedDeviceTypes: []string{ - "nvidia-229", "nvidia-230", - }, - }, - }, - }, - Not(Succeed()), - ), - ) - - }) - }) func newHyperConvergedConfig() *sdkapi.NodePlacement { @@ -2314,7 +1894,26 @@ func newHyperConvergedConfig() *sdkapi.NodePlacement { } } -func getFakeClient(hco *v1beta1.HyperConverged) *commontestutils.HcoTestClient { +func getFakeClient(hco *hcov1beta1.HyperConverged) *commontestutils.HcoTestClient { + kv, err := handlers.NewKubeVirt(hco) + Expect(err).ToNot(HaveOccurred()) + + cdi, err := handlers.NewCDI(hco) + Expect(err).ToNot(HaveOccurred()) + + cna, err := handlers.NewNetworkAddons(hco) + Expect(err).ToNot(HaveOccurred()) + + ssp, _, err := handlers.NewSSP(hco) + Expect(err).ToNot(HaveOccurred()) + + v1hc := &hcov1.HyperConverged{} + Expect(hco.ConvertTo(v1hc)).To(Succeed()) + + return commontestutils.InitClient([]client.Object{v1hc, kv, cdi, cna, ssp}) +} + +func getFakeV1Beta1Client(hco *hcov1beta1.HyperConverged) *commontestutils.HcoTestClient { kv, err := handlers.NewKubeVirt(hco) Expect(err).ToNot(HaveOccurred()) @@ -2390,14 +1989,14 @@ func initiateTimeout(_ client.Object) error { return nil } -func newRequest(operation admissionv1.Operation, cr *v1beta1.HyperConverged, encoder runtime.Encoder, dryrun bool) admission.Request { +func newRequest(operation admissionv1.Operation, cr *hcov1.HyperConverged, encoder runtime.Encoder, dryrun bool) admission.Request { req := admission.Request{ AdmissionRequest: admissionv1.AdmissionRequest{ DryRun: ptr.To(dryrun), Operation: operation, Resource: metav1.GroupVersionResource{ - Group: v1beta1.SchemeGroupVersion.Group, - Version: v1beta1.SchemeGroupVersion.Version, + Group: hcov1.SchemeGroupVersion.Group, + Version: hcov1.SchemeGroupVersion.Version, Resource: "testresource", }, UID: "test-uid", diff --git a/pkg/webhooks/validator/validator_v1beta1.go b/pkg/webhooks/validator/validator_v1beta1.go new file mode 100644 index 0000000000..92408a1079 --- /dev/null +++ b/pkg/webhooks/validator/validator_v1beta1.go @@ -0,0 +1,246 @@ +package validator + +import ( + "context" + "errors" + "fmt" + "net/http" + + "github.com/go-logr/logr" + openshiftconfigv1 "github.com/openshift/api/config/v1" + admissionv1 "k8s.io/api/admission/v1" + apierrors "k8s.io/apimachinery/pkg/api/errors" + "k8s.io/utils/strings/slices" + "sigs.k8s.io/controller-runtime/pkg/client" + "sigs.k8s.io/controller-runtime/pkg/webhook/admission" + + hcov1beta1 "github.com/kubevirt/hyperconverged-cluster-operator/api/v1beta1" +) + +type V1Beta1WebhookHandler struct { + logger logr.Logger + cli client.Client + namespace string + isOpenshift bool + decoder admission.Decoder + v1Handler *WebhookHandler +} + +func NewV1Beta1WebhookHandler(logger logr.Logger, cli client.Client, decoder admission.Decoder, namespace string, isOpenshift bool, hcoTLSSecurityProfile *openshiftconfigv1.TLSSecurityProfile) *V1Beta1WebhookHandler { + hcoTLSConfigCache = hcoTLSSecurityProfile + return &V1Beta1WebhookHandler{ + logger: logger, + cli: cli, + namespace: namespace, + isOpenshift: isOpenshift, + decoder: decoder, + v1Handler: NewWebhookHandler(logger, cli, decoder, namespace, isOpenshift, hcoTLSSecurityProfile), + } +} + +func (wh *V1Beta1WebhookHandler) Handle(ctx context.Context, req admission.Request) admission.Response { + + ctx = admission.NewContextWithRequest(ctx, req) + logger := logr.FromContextOrDiscard(ctx) + + // Get the object in the request + obj := &hcov1beta1.HyperConverged{} + + dryRun := req.DryRun != nil && *req.DryRun + + var err error + switch req.Operation { + case admissionv1.Create: + if err = wh.decoder.Decode(req, obj); err != nil { + logger.Error(err, decodeErrorMsg) + return admission.Errored(http.StatusBadRequest, errDecode) + } + + err = wh.ValidateCreate(ctx, dryRun, obj) + case admissionv1.Update: + oldObj := &hcov1beta1.HyperConverged{} + if err = wh.decoder.DecodeRaw(req.Object, obj); err != nil { + logger.Error(err, decodeErrorMsg) + return admission.Errored(http.StatusBadRequest, errDecode) + } + if err = wh.decoder.DecodeRaw(req.OldObject, oldObj); err != nil { + logger.Error(err, decodeErrorMsg) + return admission.Errored(http.StatusBadRequest, errDecode) + } + + err = wh.ValidateUpdate(ctx, dryRun, obj, oldObj) + case admissionv1.Delete: + // In reference to PR: https://github.com/kubernetes/kubernetes/pull/76346 + // OldObject contains the object being deleted + if err = wh.decoder.DecodeRaw(req.OldObject, obj); err != nil { + logger.Error(err, decodeErrorMsg) + return admission.Errored(http.StatusBadRequest, errDecode) + } + + err = wh.ValidateDelete(ctx, dryRun, obj) + default: + return admission.Errored(http.StatusBadRequest, fmt.Errorf("unknown operation request %q", req.Operation)) + } + + // Check the error message first. + if err != nil { + var apiStatus apierrors.APIStatus + if errors.As(err, &apiStatus) { + return validationResponseFromStatus(false, apiStatus.Status()) + } + + var vw *ValidationWarning + if errors.As(err, &vw) { + return admission.Allowed("").WithWarnings(vw.Warnings()...) + } + + return admission.Denied(err.Error()) + } + + // Return allowed if everything succeeded. + return admission.Allowed("") +} + +func (wh *V1Beta1WebhookHandler) ValidateCreate(ctx context.Context, dryrun bool, hc *hcov1beta1.HyperConverged) error { + wh.logger.Info("Validating create", "name", hc.Name, "namespace:", hc.Namespace) + + if err := wh.validateMediatedDeviceTypes(hc); err != nil { + return err + } + + if err := wh.validateFeatureGatesOnCreate(hc); err != nil { + return err + } + + return wh.v1Handler.ValidateCreate(ctx, dryrun, hc) +} + +// ValidateUpdate is the ValidateUpdate webhook implementation. It calls all the resources in parallel, to dry-run the +// upgrade. +func (wh *V1Beta1WebhookHandler) ValidateUpdate(ctx context.Context, dryrun bool, requested *hcov1beta1.HyperConverged, exists *hcov1beta1.HyperConverged) error { + wh.logger.Info("Validating update", "name", requested.Name) + + if err := wh.validateMediatedDeviceTypes(requested); err != nil { + return err + } + + if err := wh.validateFeatureGatesOnUpdate(requested, exists); err != nil { + return err + } + + return wh.v1Handler.ValidateUpdate(ctx, dryrun, requested, exists) +} + +func (wh *V1Beta1WebhookHandler) ValidateDelete(ctx context.Context, dryrun bool, hc *hcov1beta1.HyperConverged) error { + return wh.v1Handler.ValidateDelete(ctx, dryrun, hc) +} + +func (wh *V1Beta1WebhookHandler) validateMediatedDeviceTypes(hc *hcov1beta1.HyperConverged) error { + mdc := hc.Spec.MediatedDevicesConfiguration + if mdc != nil { + if len(mdc.MediatedDevicesTypes) > 0 && len(mdc.MediatedDeviceTypes) > 0 && !slices.Equal(mdc.MediatedDevicesTypes, mdc.MediatedDeviceTypes) { //nolint SA1019 + return fmt.Errorf("mediatedDevicesTypes is deprecated, please use mediatedDeviceTypes instead") + } + for _, nmdc := range mdc.NodeMediatedDeviceTypes { + if len(nmdc.MediatedDevicesTypes) > 0 && len(nmdc.MediatedDeviceTypes) > 0 && !slices.Equal(nmdc.MediatedDevicesTypes, nmdc.MediatedDeviceTypes) { //nolint SA1019 + return fmt.Errorf("mediatedDevicesTypes is deprecated, please use mediatedDeviceTypes instead") + } + } + } + return nil +} + +const ( + fgMovedWarning = "spec.featureGates.%[1]s is deprecated and ignored. It will removed in a future version; use spec.%[1]s instead" + fgDeprecationWarning = "spec.featureGates.%s is deprecated and ignored. It will be removed in a future version;" +) + +func (wh *V1Beta1WebhookHandler) validateFeatureGatesOnCreate(hc *hcov1beta1.HyperConverged) error { + warnings := wh.validateDeprecatedFeatureGates(hc) + warnings = wh.validateOldFGOnCreate(warnings, hc) + + if len(warnings) > 0 { + return newValidationWarning(warnings) + } + + return nil +} + +func (wh *V1Beta1WebhookHandler) validateFeatureGatesOnUpdate(requested, exists *hcov1beta1.HyperConverged) error { + warnings := wh.validateDeprecatedFeatureGates(requested) + warnings = wh.validateOldFGOnUpdate(warnings, requested, exists) + + if len(warnings) > 0 { + return newValidationWarning(warnings) + } + + return nil +} + +func (wh *V1Beta1WebhookHandler) validateDeprecatedFeatureGates(hc *hcov1beta1.HyperConverged) []string { + var warnings []string + + //nolint:staticcheck + if hc.Spec.FeatureGates.WithHostPassthroughCPU != nil { + warnings = append(warnings, fmt.Sprintf(fgDeprecationWarning, "withHostPassthroughCPU")) + } + + //nolint:staticcheck + if hc.Spec.FeatureGates.DeployTektonTaskResources != nil { + warnings = append(warnings, fmt.Sprintf(fgDeprecationWarning, "deployTektonTaskResources")) + } + + //nolint:staticcheck + if hc.Spec.FeatureGates.NonRoot != nil { + warnings = append(warnings, fmt.Sprintf(fgDeprecationWarning, "nonRoot")) + } + + //nolint:staticcheck + if hc.Spec.FeatureGates.EnableManagedTenantQuota != nil { + warnings = append(warnings, fmt.Sprintf(fgDeprecationWarning, "enableManagedTenantQuota")) + } + + return warnings +} + +func (*V1Beta1WebhookHandler) validateOldFGOnCreate(warnings []string, hc *hcov1beta1.HyperConverged) []string { + //nolint:staticcheck + if hc.Spec.FeatureGates.EnableApplicationAwareQuota != nil { + warnings = append(warnings, fmt.Sprintf(fgMovedWarning, "enableApplicationAwareQuota")) + } + + //nolint:staticcheck + if hc.Spec.FeatureGates.EnableCommonBootImageImport != nil { + warnings = append(warnings, fmt.Sprintf(fgMovedWarning, "enableCommonBootImageImport")) + } + + //nolint:staticcheck + if hc.Spec.FeatureGates.DeployVMConsoleProxy != nil { + warnings = append(warnings, fmt.Sprintf(fgMovedWarning, "deployVmConsoleProxy")) + } + + return warnings +} + +func (*V1Beta1WebhookHandler) validateOldFGOnUpdate(warnings []string, hc, prevHC *hcov1beta1.HyperConverged) []string { + //nolint:staticcheck + if oldFGChanged(hc.Spec.FeatureGates.EnableApplicationAwareQuota, prevHC.Spec.FeatureGates.EnableApplicationAwareQuota) { + warnings = append(warnings, fmt.Sprintf(fgMovedWarning, "enableApplicationAwareQuota")) + } + + //nolint:staticcheck + if oldFGChanged(hc.Spec.FeatureGates.EnableCommonBootImageImport, prevHC.Spec.FeatureGates.EnableCommonBootImageImport) { + warnings = append(warnings, fmt.Sprintf(fgMovedWarning, "enableCommonBootImageImport")) + } + + //nolint:staticcheck + if oldFGChanged(hc.Spec.FeatureGates.DeployVMConsoleProxy, prevHC.Spec.FeatureGates.DeployVMConsoleProxy) { + warnings = append(warnings, fmt.Sprintf(fgMovedWarning, "deployVmConsoleProxy")) + } + + return warnings +} + +func oldFGChanged(newFG, prevFG *bool) bool { + return newFG != nil && (prevFG == nil || *newFG != *prevFG) +} diff --git a/pkg/webhooks/validator/validator_v1beta1_test.go b/pkg/webhooks/validator/validator_v1beta1_test.go new file mode 100644 index 0000000000..c4f3637dc3 --- /dev/null +++ b/pkg/webhooks/validator/validator_v1beta1_test.go @@ -0,0 +1,670 @@ +package validator + +import ( + "context" + "errors" + "os" + + "github.com/go-logr/logr" + . "github.com/onsi/ginkgo/v2" + . "github.com/onsi/gomega" + "github.com/onsi/gomega/types" + admissionv1 "k8s.io/api/admission/v1" + metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" + "k8s.io/apimachinery/pkg/runtime" + "k8s.io/apimachinery/pkg/runtime/serializer" + "k8s.io/client-go/kubernetes/scheme" + "k8s.io/utils/ptr" + "sigs.k8s.io/controller-runtime/pkg/client/fake" + "sigs.k8s.io/controller-runtime/pkg/webhook/admission" + + networkaddonsv1 "github.com/kubevirt/cluster-network-addons-operator/pkg/apis/networkaddonsoperator/v1" + kubevirtcorev1 "kubevirt.io/api/core/v1" + cdiv1beta1 "kubevirt.io/containerized-data-importer-api/pkg/apis/core/v1beta1" + sspv1beta3 "kubevirt.io/ssp-operator/api/v1beta3" + + hcov1 "github.com/kubevirt/hyperconverged-cluster-operator/api/v1" + hcov1beta1 "github.com/kubevirt/hyperconverged-cluster-operator/api/v1beta1" + "github.com/kubevirt/hyperconverged-cluster-operator/controllers/commontestutils" + "github.com/kubevirt/hyperconverged-cluster-operator/controllers/handlers" + "github.com/kubevirt/hyperconverged-cluster-operator/pkg/util" +) + +var _ = Describe("v1beta1 webhooks validator", func() { + s := scheme.Scheme + for _, f := range []func(*runtime.Scheme) error{ + hcov1.AddToScheme, + hcov1beta1.AddToScheme, + cdiv1beta1.AddToScheme, + kubevirtcorev1.AddToScheme, + networkaddonsv1.AddToScheme, + sspv1beta3.AddToScheme, + } { + Expect(f(s)).To(Succeed()) + } + + codecFactory := serializer.NewCodecFactory(s) + v1Beta1Codec := codecFactory.LegacyCodec(hcov1beta1.SchemeGroupVersion) + + cli := fake.NewClientBuilder().WithScheme(s).Build() + decoder := admission.NewDecoder(s) + + wh := NewV1Beta1WebhookHandler(logger, cli, decoder, HcoValidNamespace, true, nil) + + var ( + dryRun bool + cr *hcov1beta1.HyperConverged + ) + + BeforeEach(func() { + Expect(os.Setenv("OPERATOR_NAMESPACE", HcoValidNamespace)).To(Succeed()) + dryRun = false + cr = commontestutils.NewHco() + }) + + Context("Check create validation webhook", func() { + Context("check update request", func() { + It("should correctly handle a valid creation request", func(ctx context.Context) { + ctx = logr.NewContext(ctx, GinkgoLogr) + req := newV1Beta1Request(admissionv1.Create, cr, v1Beta1Codec, false) + + res := wh.Handle(ctx, req) + Expect(res.Allowed).To(BeTrue()) + Expect(res.Result.Code).To(Equal(int32(200))) + }) + + It("should correctly handle a valid dryrun creation request", func(ctx context.Context) { + req := newV1Beta1Request(admissionv1.Create, cr, v1Beta1Codec, true) + ctx = logr.NewContext(ctx, GinkgoLogr) + + res := wh.Handle(ctx, req) + Expect(res.Allowed).To(BeTrue()) + Expect(res.Result.Code).To(Equal(int32(200))) + }) + + It("should reject malformed creation requests", func(ctx context.Context) { + req := newV1Beta1Request(admissionv1.Create, cr, v1Beta1Codec, false) + ctx = logr.NewContext(ctx, GinkgoLogr) + + req.OldObject = req.Object + req.Object = runtime.RawExtension{} + + res := wh.Handle(ctx, req) + Expect(res.Allowed).To(BeFalse()) + Expect(res.Result.Code).To(Equal(int32(400))) + Expect(res.Result.Message).To(Equal(decodeErrorMsg)) + + req = newV1Beta1Request(admissionv1.Create, cr, v1Beta1Codec, false) + req.Operation = "MALFORMED" + + res = wh.Handle(ctx, req) + Expect(res.Allowed).To(BeFalse()) + Expect(res.Result.Code).To(Equal(int32(400))) + Expect(res.Result.Message).To(Equal(`unknown operation request "MALFORMED"`)) + }) + }) + + // Only v1beta1 specific tests. All the rest are tested in v1 + Context("check ValidateCreate", func() { + It("should accept creation of a resource with a valid namespace", func(ctx context.Context) { + Expect(wh.ValidateCreate(ctx, dryRun, cr)).To(Succeed()) + }) + + }) + + Context("validate deprecated FGs", func() { + DescribeTable("should return warning for deprecated feature gate", func(ctx context.Context, fgs hcov1beta1.HyperConvergedFeatureGates, fgNames ...string) { + cr.Spec.FeatureGates = fgs + err := wh.ValidateCreate(ctx, dryRun, cr) + Expect(err).To(HaveOccurred()) + expected := &ValidationWarning{} + Expect(errors.As(err, &expected)).To(BeTrue()) + + Expect(expected.warnings).To(HaveLen(len(fgNames))) + for _, fgName := range fgNames { + Expect(expected.warnings).To(ContainElements(ContainSubstring(fgName))) + } + }, + Entry("should trigger a warning if the withHostPassthroughCPU=false FG exists in the CR", + hcov1beta1.HyperConvergedFeatureGates{WithHostPassthroughCPU: ptr.To(false)}, "withHostPassthroughCPU"), + Entry("should trigger a warning if the withHostPassthroughCPU=true FG exists in the CR", + hcov1beta1.HyperConvergedFeatureGates{WithHostPassthroughCPU: ptr.To(true)}, "withHostPassthroughCPU"), + + Entry("should trigger a warning if the deployTektonTaskResources=false FG exists in the CR", + hcov1beta1.HyperConvergedFeatureGates{DeployTektonTaskResources: ptr.To(false)}, "deployTektonTaskResources"), + Entry("should trigger a warning if the deployTektonTaskResources=true FG exists in the CR", + hcov1beta1.HyperConvergedFeatureGates{DeployTektonTaskResources: ptr.To(true)}, "deployTektonTaskResources"), + + Entry("should trigger a warning if the enableManagedTenantQuota=false FG exists in the CR", + hcov1beta1.HyperConvergedFeatureGates{EnableManagedTenantQuota: ptr.To(false)}, "enableManagedTenantQuota"), + Entry("should trigger a warning if the enableManagedTenantQuota=true FG exists in the CR", + hcov1beta1.HyperConvergedFeatureGates{EnableManagedTenantQuota: ptr.To(true)}, "enableManagedTenantQuota"), + + Entry("should trigger a warning if the nonRoot=false FG exists in the CR", + hcov1beta1.HyperConvergedFeatureGates{NonRoot: ptr.To(false)}, "nonRoot"), + Entry("should trigger a warning if the nonRoot=true FG exists in the CR", + hcov1beta1.HyperConvergedFeatureGates{NonRoot: ptr.To(true)}, "nonRoot"), + + Entry("should trigger multiple warnings if several deprecated FG exist in the CR", + hcov1beta1.HyperConvergedFeatureGates{ + NonRoot: ptr.To(true), + EnableManagedTenantQuota: ptr.To(true), + }, "enableManagedTenantQuota", "nonRoot"), + + Entry("should trigger multiple warnings if several deprecated FG exist in the CR, with some valid FGs", + hcov1beta1.HyperConvergedFeatureGates{ + DownwardMetrics: ptr.To(true), + NonRoot: ptr.To(false), + EnableCommonBootImageImport: ptr.To(true), + EnableApplicationAwareQuota: ptr.To(false), + EnableManagedTenantQuota: ptr.To(false), + DeployVMConsoleProxy: ptr.To(false), + DeployKubeSecondaryDNS: ptr.To(false), + }, "enableManagedTenantQuota", "nonRoot", "enableApplicationAwareQuota", "enableCommonBootImageImport", "deployVmConsoleProxy"), + ) + }) + }) + + Context("validate update validation webhook", func() { + BeforeEach(func() { + cr.Spec.Infra = hcov1beta1.HyperConvergedConfig{ + NodePlacement: newHyperConvergedConfig(), + } + cr.Spec.Workloads = hcov1beta1.HyperConvergedConfig{ + NodePlacement: newHyperConvergedConfig(), + } + }) + + Context("check update request", func() { + It("should correctly handle a valid update request", func(ctx context.Context) { + req := newV1Beta1Request(admissionv1.Update, cr, v1Beta1Codec, false) + ctx = logr.NewContext(ctx, GinkgoLogr) + + res := wh.Handle(ctx, req) + Expect(res.Allowed).To(BeTrue()) + Expect(res.Result.Code).To(Equal(int32(200))) + }) + + It("should correctly handle a valid dryrun update request", func(ctx context.Context) { + req := newV1Beta1Request(admissionv1.Update, cr, v1Beta1Codec, true) + ctx = logr.NewContext(ctx, GinkgoLogr) + + res := wh.Handle(ctx, req) + Expect(res.Allowed).To(BeTrue()) + Expect(res.Result.Code).To(Equal(int32(200))) + }) + + It("should reject update requests with no object", func(ctx context.Context) { + req := newV1Beta1Request(admissionv1.Update, cr, v1Beta1Codec, false) + req.Object = runtime.RawExtension{} + ctx = logr.NewContext(ctx, GinkgoLogr) + + res := wh.Handle(ctx, req) + Expect(res.Allowed).To(BeFalse()) + Expect(res.Result.Code).To(Equal(int32(400))) + Expect(res.Result.Message).To(Equal(decodeErrorMsg)) + }) + + It("should reject update requests with no oldObject", func(ctx context.Context) { + req := newV1Beta1Request(admissionv1.Update, cr, v1Beta1Codec, false) + req.OldObject = runtime.RawExtension{} + ctx = logr.NewContext(ctx, GinkgoLogr) + + res := wh.Handle(ctx, req) + Expect(res.Allowed).To(BeFalse()) + Expect(res.Result.Code).To(Equal(int32(400))) + Expect(res.Result.Message).To(Equal(decodeErrorMsg)) + }) + }) + + // Only v1beta1 specific tests. All the rest are tested in v1 + Context("check ValidateUpdate", func() { + Context("validate deprecated FGs", func() { + DescribeTable("should return warning for deprecated feature gate", func(ctx context.Context, fgs hcov1beta1.HyperConvergedFeatureGates, fgNames ...string) { + newHCO := cr.DeepCopy() + newHCO.Spec.FeatureGates = fgs + + err := wh.ValidateUpdate(ctx, dryRun, newHCO, cr) + + Expect(err).To(HaveOccurred()) + expected := &ValidationWarning{} + Expect(errors.As(err, &expected)).To(BeTrue()) + + Expect(expected.warnings).To(HaveLen(len(fgNames))) + for _, fgName := range fgNames { + Expect(expected.warnings).To(ContainElements(ContainSubstring(fgName))) + } + }, + Entry("should trigger a warning if the withHostPassthroughCPU=false FG exists in the CR", + hcov1beta1.HyperConvergedFeatureGates{WithHostPassthroughCPU: ptr.To(false)}, "withHostPassthroughCPU"), + Entry("should trigger a warning if the withHostPassthroughCPU=true FG exists in the CR", + hcov1beta1.HyperConvergedFeatureGates{WithHostPassthroughCPU: ptr.To(true)}, "withHostPassthroughCPU"), + + Entry("should trigger a warning if the deployTektonTaskResources=false FG exists in the CR", + hcov1beta1.HyperConvergedFeatureGates{DeployTektonTaskResources: ptr.To(false)}, "deployTektonTaskResources"), + Entry("should trigger a warning if the deployTektonTaskResources=true FG exists in the CR", + hcov1beta1.HyperConvergedFeatureGates{DeployTektonTaskResources: ptr.To(true)}, "deployTektonTaskResources"), + + Entry("should trigger a warning if the enableManagedTenantQuota=false FG exists in the CR", + hcov1beta1.HyperConvergedFeatureGates{EnableManagedTenantQuota: ptr.To(false)}, "enableManagedTenantQuota"), + Entry("should trigger a warning if the enableManagedTenantQuota=true FG exists in the CR", + hcov1beta1.HyperConvergedFeatureGates{EnableManagedTenantQuota: ptr.To(true)}, "enableManagedTenantQuota"), + + Entry("should trigger a warning if the nonRoot=false FG exists in the CR", + hcov1beta1.HyperConvergedFeatureGates{NonRoot: ptr.To(false)}, "nonRoot"), + Entry("should trigger a warning if the nonRoot=true FG exists in the CR", + hcov1beta1.HyperConvergedFeatureGates{NonRoot: ptr.To(true)}, "nonRoot"), + + Entry("should trigger multiple warnings if several deprecated FG exist in the CR", + hcov1beta1.HyperConvergedFeatureGates{ + NonRoot: ptr.To(true), + EnableManagedTenantQuota: ptr.To(true), + }, "enableManagedTenantQuota", "nonRoot"), + + Entry("should trigger multiple warnings if several deprecated FG exist in the CR, with some valid FGs", + hcov1beta1.HyperConvergedFeatureGates{ + DownwardMetrics: ptr.To(true), + NonRoot: ptr.To(false), + EnableCommonBootImageImport: ptr.To(true), + EnableManagedTenantQuota: ptr.To(false), + }, "enableManagedTenantQuota", "nonRoot", "enableCommonBootImageImport"), + ) + }) + + Context("validate moved FG on update", func() { + //nolint:staticcheck + DescribeTable("should return warning for enableApplicationAwareQuota on update", func(ctx context.Context, newFG, oldFG *bool) { + newHCO := cr.DeepCopy() + cr.Spec.FeatureGates.EnableApplicationAwareQuota = newFG + newHCO.Spec.FeatureGates.EnableApplicationAwareQuota = oldFG + + err := wh.ValidateUpdate(ctx, dryRun, newHCO, cr) + + Expect(err).To(HaveOccurred()) + expected := &ValidationWarning{} + Expect(errors.As(err, &expected)).To(BeTrue()) + + Expect(expected.warnings).To(HaveLen(1)) + Expect(expected.warnings).To(ContainElements(ContainSubstring("enableApplicationAwareQuota"))) + }, + Entry("should trigger warning if enableApplicationAwareQuota appeared as true", nil, ptr.To(true)), + Entry("should trigger warning if enableApplicationAwareQuota appeared as false", nil, ptr.To(false)), + Entry("should trigger warning if enableApplicationAwareQuota has changed from true to false", ptr.To(true), ptr.To(false)), + Entry("should trigger warning if enableApplicationAwareQuota has changed from false to true", ptr.To(false), ptr.To(true)), + ) + + //nolint:staticcheck + DescribeTable("should not return warning for enableApplicationAwareQuota if not change", func(ctx context.Context, newFG, oldFG *bool) { + cli := getFakeV1Beta1Client(cr) + wh := NewV1Beta1WebhookHandler(logger, cli, decoder, HcoValidNamespace, true, nil) + newHCO := cr.DeepCopy() + cr.Spec.FeatureGates.EnableApplicationAwareQuota = newFG + newHCO.Spec.FeatureGates.EnableApplicationAwareQuota = oldFG + + Expect(wh.ValidateUpdate(ctx, dryRun, newHCO, cr)).To(Succeed()) + }, + Entry("should not trigger warning if enableApplicationAwareQuota (true) disappeared", ptr.To(true), nil), + Entry("should not trigger warning if enableApplicationAwareQuota (false) disappeared", ptr.To(false), nil), + Entry("should not trigger warning if enableApplicationAwareQuota (true) wasn't changed", ptr.To(true), ptr.To(true)), + Entry("should not trigger warning if enableApplicationAwareQuota (false) wasn't changed", ptr.To(false), ptr.To(false)), + ) + + //nolint:staticcheck + DescribeTable("should return warning for enableCommonBootImageImport on update", func(ctx context.Context, newFG, oldFG *bool) { + newHCO := cr.DeepCopy() + cr.Spec.FeatureGates.EnableCommonBootImageImport = newFG + newHCO.Spec.FeatureGates.EnableCommonBootImageImport = oldFG + + err := wh.ValidateUpdate(ctx, dryRun, newHCO, cr) + + Expect(err).To(HaveOccurred()) + expected := &ValidationWarning{} + Expect(errors.As(err, &expected)).To(BeTrue()) + + Expect(expected.warnings).To(HaveLen(1)) + Expect(expected.warnings).To(ContainElements(ContainSubstring("enableCommonBootImageImport"))) + }, + Entry("should trigger warning if enableCommonBootImageImport appeared as true", nil, ptr.To(true)), + Entry("should trigger warning if enableCommonBootImageImport appeared as false", nil, ptr.To(false)), + Entry("should trigger warning if enableCommonBootImageImport has changed from true to false", ptr.To(true), ptr.To(false)), + Entry("should trigger warning if enableCommonBootImageImport has changed from false to true", ptr.To(false), ptr.To(true)), + ) + + //nolint:staticcheck + DescribeTable("should not return warning for enableCommonBootImageImport if not change", func(ctx context.Context, newFG, oldFG *bool) { + cli := getFakeV1Beta1Client(cr) + wh := NewV1Beta1WebhookHandler(logger, cli, decoder, HcoValidNamespace, true, nil) + newHCO := cr.DeepCopy() + cr.Spec.FeatureGates.EnableCommonBootImageImport = newFG + newHCO.Spec.FeatureGates.EnableCommonBootImageImport = oldFG + + Expect(wh.ValidateUpdate(ctx, dryRun, newHCO, cr)).To(Succeed()) + }, + Entry("should not trigger warning if enableCommonBootImageImport (true) disappeared", ptr.To(true), nil), + Entry("should not trigger warning if enableCommonBootImageImport (false) disappeared", ptr.To(false), nil), + Entry("should not trigger warning if enableCommonBootImageImport (true) wasn't changed", ptr.To(true), ptr.To(true)), + Entry("should not trigger warning if enableCommonBootImageImport (false) wasn't changed", ptr.To(false), ptr.To(false)), + ) + + //nolint:staticcheck + DescribeTable("should return warning for deployVmConsoleProxy on update", func(ctx context.Context, newFG, oldFG *bool) { + newHCO := cr.DeepCopy() + cr.Spec.FeatureGates.DeployVMConsoleProxy = newFG + newHCO.Spec.FeatureGates.DeployVMConsoleProxy = oldFG + + err := wh.ValidateUpdate(ctx, dryRun, newHCO, cr) + + Expect(err).To(HaveOccurred()) + expected := &ValidationWarning{} + Expect(errors.As(err, &expected)).To(BeTrue()) + + Expect(expected.warnings).To(HaveLen(1)) + Expect(expected.warnings).To(ContainElements(ContainSubstring("deployVmConsoleProxy"))) + }, + Entry("should trigger warning if deployVmConsoleProxy appeared as true", nil, ptr.To(true)), + Entry("should trigger warning if deployVmConsoleProxy appeared as false", nil, ptr.To(false)), + Entry("should trigger warning if deployVmConsoleProxy has changed from true to false", ptr.To(true), ptr.To(false)), + Entry("should trigger warning if deployVmConsoleProxy has changed from false to true", ptr.To(false), ptr.To(true)), + ) + + //nolint:staticcheck + DescribeTable("should not return warning for deployVmConsoleProxy if not change", func(ctx context.Context, newFG, oldFG *bool) { + cli := getFakeV1Beta1Client(cr) + wh := NewV1Beta1WebhookHandler(logger, cli, decoder, HcoValidNamespace, true, nil) + newHCO := cr.DeepCopy() + cr.Spec.FeatureGates.DeployVMConsoleProxy = newFG + newHCO.Spec.FeatureGates.DeployVMConsoleProxy = oldFG + + Expect(wh.ValidateUpdate(ctx, dryRun, newHCO, cr)).To(Succeed()) + }, + Entry("should not trigger warning if deployVmConsoleProxy (true) disappeared", ptr.To(true), nil), + Entry("should not trigger warning if deployVmConsoleProxy (false) disappeared", ptr.To(false), nil), + Entry("should not trigger warning if deployVmConsoleProxy (true) wasn't changed", ptr.To(true), ptr.To(true)), + Entry("should not trigger warning if deployVmConsoleProxy (false) wasn't changed", ptr.To(false), ptr.To(false)), + ) + + //nolint:staticcheck + DescribeTable("should not return warning for deployKubeSecondaryDNS if not change", func(ctx context.Context, newFG, oldFG *bool) { + cli := getFakeV1Beta1Client(cr) + wh := NewV1Beta1WebhookHandler(logger, cli, decoder, HcoValidNamespace, true, nil) + newHCO := cr.DeepCopy() + cr.Spec.FeatureGates.DeployKubeSecondaryDNS = newFG + newHCO.Spec.FeatureGates.DeployKubeSecondaryDNS = oldFG + + Expect(wh.ValidateUpdate(ctx, dryRun, newHCO, cr)).To(Succeed()) + }, + Entry("should not trigger warning if deployKubeSecondaryDNS (true) disappeared", ptr.To(true), nil), + Entry("should not trigger warning if deployKubeSecondaryDNS (false) disappeared", ptr.To(false), nil), + Entry("should not trigger warning if deployKubeSecondaryDNS (true) wasn't changed", ptr.To(true), ptr.To(true)), + Entry("should not trigger warning if deployKubeSecondaryDNS (false) wasn't changed", ptr.To(false), ptr.To(false)), + ) + }) + }) + }) + + Context("validate delete validation webhook", func() { + Context("check delete request", func() { + It("should correctly handle a valid delete request", func(ctx context.Context) { + req := newV1Beta1Request(admissionv1.Delete, cr, v1Beta1Codec, false) + ctx = logr.NewContext(ctx, GinkgoLogr) + + res := wh.Handle(ctx, req) + Expect(res.Allowed).To(BeTrue()) + Expect(res.Result.Code).To(Equal(int32(200))) + }) + + It("should correctly handle a valid dryrun delete request", func(ctx context.Context) { + req := newV1Beta1Request(admissionv1.Delete, cr, v1Beta1Codec, true) + ctx = logr.NewContext(ctx, GinkgoLogr) + + res := wh.Handle(ctx, req) + Expect(res.Allowed).To(BeTrue()) + Expect(res.Result.Code).To(Equal(int32(200))) + }) + + It("should reject a malformed delete request", func(ctx context.Context) { + req := newV1Beta1Request(admissionv1.Delete, cr, v1Beta1Codec, false) + req.OldObject = req.Object + req.Object = runtime.RawExtension{} + ctx = logr.NewContext(ctx, GinkgoLogr) + + res := wh.Handle(ctx, req) + Expect(res.Allowed).To(BeFalse()) + Expect(res.Result.Code).To(Equal(int32(400))) + Expect(res.Result.Message).To(Equal(decodeErrorMsg)) + }) + }) + + Context("check ValidateDelete", func() { + It("should validate deletion", func(ctx context.Context) { + cli := getFakeV1Beta1Client(cr) + + wh := NewV1Beta1WebhookHandler(logger, cli, decoder, HcoValidNamespace, true, nil) + + Expect(wh.ValidateDelete(ctx, dryRun, cr)).To(Succeed()) + + By("Validate that KV still exists, as it a dry-run deletion") + kv := handlers.NewKubeVirtWithNameOnly(cr) + Expect(util.GetRuntimeObject(ctx, cli, kv)).To(Succeed()) + + By("Validate that CDI still exists, as it a dry-run deletion") + cdi := handlers.NewCDIWithNameOnly(cr) + Expect(util.GetRuntimeObject(ctx, cli, cdi)).To(Succeed()) + }) + }) + }) + + Context("MediatedDeviceTypes", func() { + var cr *hcov1beta1.HyperConverged + var newCr *hcov1beta1.HyperConverged + + BeforeEach(func() { + Expect(os.Setenv("OPERATOR_NAMESPACE", HcoValidNamespace)).To(Succeed()) + cr = commontestutils.NewHco() + cr.Spec.MediatedDevicesConfiguration = nil + newCr = cr.DeepCopy() + }) + + DescribeTable("Check mediatedDevicesTypes -> mediatedDeviceTypes transition", func(ctx context.Context, mDConfiguration *hcov1beta1.MediatedDevicesConfiguration, expected types.GomegaMatcher) { + // create + newCr.Spec.MediatedDevicesConfiguration = mDConfiguration + Expect(wh.ValidateCreate(ctx, false, newCr)).To(expected) + + // update + cli := getFakeV1Beta1Client(cr) + cli.InitiateUpdateErrors(getUpdateError(noFailure)) + whU := NewV1Beta1WebhookHandler(logger, cli, decoder, HcoValidNamespace, true, nil) + Expect(whU.ValidateUpdate(ctx, false, newCr, cr)).To(expected) + }, + Entry("should not fail with no configuration", + nil, + Succeed(), + ), + Entry("should not fail if using only mediatedDeviceTypes", + &hcov1beta1.MediatedDevicesConfiguration{ + MediatedDeviceTypes: []string{"nvidia-222", "nvidia-230"}, + NodeMediatedDeviceTypes: []hcov1beta1.NodeMediatedDeviceTypesConfig{ + { + NodeSelector: map[string]string{ + "testLabel1": "true", + }, + MediatedDeviceTypes: []string{ + "nvidia-223", + }, + }, + { + NodeSelector: map[string]string{ + "testLabel2": "true", + }, + MediatedDeviceTypes: []string{ + "nvidia-229", + }, + }, + }, + }, + Succeed(), + ), + Entry("should not fail if using only deprecated APIs", + &hcov1beta1.MediatedDevicesConfiguration{ + MediatedDevicesTypes: []string{"nvidia-222", "nvidia-230"}, + NodeMediatedDeviceTypes: []hcov1beta1.NodeMediatedDeviceTypesConfig{ + { + NodeSelector: map[string]string{ + "testLabel1": "true", + }, + MediatedDevicesTypes: []string{ + "nvidia-223", + }, + }, + { + NodeSelector: map[string]string{ + "testLabel2": "true", + }, + MediatedDevicesTypes: []string{ + "nvidia-229", + }, + }, + }, + }, + Succeed(), + ), + Entry("should not fail if correctly using both mediatedDeviceTypes and deprecated APIs", + &hcov1beta1.MediatedDevicesConfiguration{ + MediatedDevicesTypes: []string{"nvidia-222", "nvidia-230"}, + MediatedDeviceTypes: []string{"nvidia-222", "nvidia-230"}, + NodeMediatedDeviceTypes: []hcov1beta1.NodeMediatedDeviceTypesConfig{ + { + NodeSelector: map[string]string{ + "testLabel1": "true", + }, + MediatedDevicesTypes: []string{ + "nvidia-223", + }, + MediatedDeviceTypes: []string{ + "nvidia-223", + }, + }, + { + NodeSelector: map[string]string{ + "testLabel2": "true", + }, + MediatedDevicesTypes: []string{ + "nvidia-229", + }, + MediatedDeviceTypes: []string{ + "nvidia-229", + }, + }, + }, + }, + Succeed(), + ), + Entry("should fail if mixing mediatedDeviceTypes and deprecated APIs on spec.mediatedDevicesConfiguration.mediatedDeviceTypes", + &hcov1beta1.MediatedDevicesConfiguration{ + MediatedDevicesTypes: []string{"nvidia-222", "nvidia-230"}, + MediatedDeviceTypes: []string{"nvidia-222"}, + NodeMediatedDeviceTypes: []hcov1beta1.NodeMediatedDeviceTypesConfig{ + { + NodeSelector: map[string]string{ + "testLabel1": "true", + }, + MediatedDevicesTypes: []string{ + "nvidia-223", + }, + MediatedDeviceTypes: []string{ + "nvidia-223", + }, + }, + { + NodeSelector: map[string]string{ + "testLabel2": "true", + }, + MediatedDevicesTypes: []string{ + "nvidia-229", + }, + MediatedDeviceTypes: []string{ + "nvidia-229", + }, + }, + }, + }, + Not(Succeed()), + ), + Entry("should fail if mixing mediatedDeviceTypes and deprecated APIs on spec.mediatedDevicesConfiguration.nodeMediatedDeviceTypes[1].mediatedDeviceTypes", + &hcov1beta1.MediatedDevicesConfiguration{ + MediatedDevicesTypes: []string{"nvidia-222", "nvidia-230"}, + MediatedDeviceTypes: []string{"nvidia-222", "nvidia-230"}, + NodeMediatedDeviceTypes: []hcov1beta1.NodeMediatedDeviceTypesConfig{ + { + NodeSelector: map[string]string{ + "testLabel1": "true", + }, + MediatedDevicesTypes: []string{ + "nvidia-223", + }, + MediatedDeviceTypes: []string{ + "nvidia-223", + }, + }, + { + NodeSelector: map[string]string{ + "testLabel2": "true", + }, + MediatedDevicesTypes: []string{ + "nvidia-229", + }, + MediatedDeviceTypes: []string{ + "nvidia-229", "nvidia-230", + }, + }, + }, + }, + Not(Succeed()), + ), + ) + + }) + +}) + +func newV1Beta1Request(operation admissionv1.Operation, cr *hcov1beta1.HyperConverged, encoder runtime.Encoder, dryrun bool) admission.Request { + req := admission.Request{ + AdmissionRequest: admissionv1.AdmissionRequest{ + DryRun: ptr.To(dryrun), + Operation: operation, + Resource: metav1.GroupVersionResource{ + Group: hcov1beta1.SchemeGroupVersion.Group, + Version: hcov1beta1.SchemeGroupVersion.Version, + Resource: "testresource", + }, + UID: "test-uid", + }, + } + + switch operation { + case admissionv1.Create: + req.Object = runtime.RawExtension{ + Raw: []byte(runtime.EncodeOrDie(encoder, cr)), + Object: cr, + } + case admissionv1.Update: + req.Object = runtime.RawExtension{ + Raw: []byte(runtime.EncodeOrDie(encoder, cr)), + Object: cr, + } + req.OldObject = runtime.RawExtension{ + Raw: []byte(runtime.EncodeOrDie(encoder, cr)), + Object: cr, + } + case admissionv1.Delete: + req.OldObject = runtime.RawExtension{ + Raw: []byte(runtime.EncodeOrDie(encoder, cr)), + Object: cr, + } + default: + req.Object = runtime.RawExtension{} + req.OldObject = runtime.RawExtension{} + } + + return req +} diff --git a/tests/func-tests/client.go b/tests/func-tests/client.go index 9fe18212b2..e3d40c6b23 100644 --- a/tests/func-tests/client.go +++ b/tests/func-tests/client.go @@ -24,7 +24,7 @@ import ( cdiv1beta1 "kubevirt.io/containerized-data-importer-api/pkg/apis/core/v1beta1" sspv1beta3 "kubevirt.io/ssp-operator/api/v1beta3" - hcov1beta1 "github.com/kubevirt/hyperconverged-cluster-operator/api/v1beta1" + hcoapi "github.com/kubevirt/hyperconverged-cluster-operator/api" ) var ( @@ -74,7 +74,7 @@ func setScheme(cli client.Client) { funcs := []func(scheme2 *runtime.Scheme) error{ corev1.AddToScheme, appsv1.AddToScheme, - hcov1beta1.AddToScheme, + hcoapi.AddToScheme, kvv1.AddToScheme, aaqv1alpha1.AddToScheme, consolev1.AddToScheme, diff --git a/tests/func-tests/mediateddevices_mediateddevice_test.go b/tests/func-tests/mediateddevices_mediateddevice_test.go index 634e0c0b7a..aa761d36fe 100644 --- a/tests/func-tests/mediateddevices_mediateddevice_test.go +++ b/tests/func-tests/mediateddevices_mediateddevice_test.go @@ -302,7 +302,7 @@ var _ = Describe("MediatedDevicesTypes -> MediatedDeviceTypes", Label("MediatedD DescribeTable("should correctly handle validate MediatedDevicesTypes -> MediatedDeviceTypes transition", func(ctx context.Context, mediatedDevicesConfiguration *v1beta1.MediatedDevicesConfiguration) { apiServerError := apiservererrors.ToStatusErr( - util.HcoValidatingWebhook, + util.HcoV1Beta1ValidatingWebhook, &metav1.Status{ Message: "mediatedDevicesTypes is deprecated, please use mediatedDeviceTypes instead", Reason: metav1.StatusReasonForbidden, diff --git a/tests/func-tests/v1api_test.go b/tests/func-tests/v1api_test.go new file mode 100644 index 0000000000..d6855c3dda --- /dev/null +++ b/tests/func-tests/v1api_test.go @@ -0,0 +1,149 @@ +package tests_test + +import ( + "context" + "fmt" + "reflect" + "strings" + "time" + + . "github.com/onsi/ginkgo/v2" + . "github.com/onsi/gomega" + "sigs.k8s.io/controller-runtime/pkg/client" + + hcov1 "github.com/kubevirt/hyperconverged-cluster-operator/api/v1" + "github.com/kubevirt/hyperconverged-cluster-operator/api/v1/featuregates" + hcov1v1beta1 "github.com/kubevirt/hyperconverged-cluster-operator/api/v1beta1" + hcoutil "github.com/kubevirt/hyperconverged-cluster-operator/pkg/util" + tests "github.com/kubevirt/hyperconverged-cluster-operator/tests/func-tests" +) + +var _ = Describe("v1 api test", func() { + tests.FlagParse() + + var hcKey = client.ObjectKey{Namespace: tests.InstallNamespace, Name: hcoutil.HyperConvergedName} + + It("should read v1.HyperConverged", Label("v1"), func(ctx context.Context) { + cl := tests.GetControllerRuntimeClient() + + By("read HyperConverged in v1beta1 format") + hcv1beta1 := tests.GetHCO(ctx, cl) + + By("read HyperConverged in v1 format") + hcv1 := &hcov1.HyperConverged{} + Expect(cl.Get(ctx, hcKey, hcv1)).To(Succeed()) + + v1beta1FGStatus := getCurrentV1Beta1FGStatus(hcv1beta1.Spec.FeatureGates) + + By("check that v1 feature gates got the same logical value as v1beta1's") + for fgName, fgValue := range v1beta1FGStatus { + matcher := BeFalseBecause("the %q feature gate is disabled in v1beta1, but enabled in v1", fgName) + if fgValue { + matcher = BeTrueBecause("the %q feature gate is enabled in v1beta1, but disabled in v1", fgName) + } + Expect(hcv1.Spec.FeatureGates.IsEnabled(fgName)).To(matcher) + } + }) + + It("should allow set fields in HyperConverged v1", func(ctx context.Context) { + cl := tests.GetControllerRuntimeClient() + + By("Make sure feature gates are with default values") + restoreFGsToDefault(ctx, cl) + + By("read HyperConverged in v1 format, then update two FGs") + Eventually(func(g Gomega, ctx context.Context) { + hcv1 := &hcov1.HyperConverged{} + g.Expect(cl.Get(ctx, hcKey, hcv1)).To(Succeed()) + + hcv1.Spec.FeatureGates.Disable("videoConfig") + hcv1.Spec.FeatureGates.Enable("downwardMetrics") + + g.Expect(cl.Update(ctx, hcv1)).To(Succeed()) + }).WithTimeout(60 * time.Second). + WithPolling(time.Second). + WithContext(ctx). + Should(Succeed()) + + By("read HyperConverged in v1beta1 format after the v1 update") + hcv1beta1 := &hcov1v1beta1.HyperConverged{} + Expect(cl.Get(ctx, hcKey, hcv1beta1)).To(Succeed()) + Expect(hcv1beta1.Spec.FeatureGates.DownwardMetrics).To(HaveValue(BeTrueBecause("downwardMetrics was enabled using v1 API. it is expected to be 'true' in v1beta1, but it's not'"))) + Expect(hcv1beta1.Spec.FeatureGates.VideoConfig).To(HaveValue(BeFalseBecause("videoConfig was disabled using v1 API. it is expected to be 'false' in v1beta1, but it's not'"))) + + DeferCleanup(func(ctx context.Context) { + By("restore the FGs") + restoreFGsToDefault(ctx, cl) + }) + }) +}) + +func getCurrentV1Beta1FGStatus(fgs hcov1v1beta1.HyperConvergedFeatureGates) map[string]bool { + fgMap := make(map[string]bool) + + fgVal := reflect.ValueOf(fgs) + fgType := reflect.TypeOf(fgs) + + if fgVal.Kind() == reflect.Ptr { + fgVal = fgVal.Elem() + fgType = fgType.Elem() + } + + for i := range fgType.NumField() { + field := fgType.Field(i) // Type info (name, tags, etc.) + value := fgVal.Field(i) // Actual value + + fgName := strings.Split(field.Tag.Get("json"), ",")[0] + if fgName == "" { + continue + } + + var fgValue bool + if value.Kind() == reflect.Ptr { + if value.IsNil() { + continue + } + + fgValue = value.Elem().Bool() + } else { + fgValue = value.Bool() + } + + fgMap[fgName] = fgValue + } + + return fgMap +} + +func restoreFGsToDefault(ctx context.Context, cl client.Client) { + GinkgoHelper() + + hcv1beta1 := &hcov1v1beta1.HyperConverged{} + patch := []byte(fmt.Sprintf(removePathPatchTmplt, "/spec/featureGates")) + + Eventually(func(g Gomega, ctx context.Context) { + g.Expect(tests.PatchHCO(ctx, cl, patch)).To(Succeed()) + }).WithTimeout(2 * time.Second). + WithPolling(500 * time.Millisecond). + WithContext(ctx). + Should(Succeed()) + + Eventually(func(g Gomega, ctx context.Context) { + hcv1beta1 = tests.GetHCO(ctx, cl) + v1beta1FGStatus := getCurrentV1Beta1FGStatus(hcv1beta1.Spec.FeatureGates) + defaultFGs := featuregates.HyperConvergedFeatureGates{} + + for fgName, fgValue := range v1beta1FGStatus { + fgDefault := defaultFGs.IsEnabled(fgName) + matcher := BeFalseBecause("the %q feature gate should be disabled by default, but is enabled in v1beta1", fgName) + if fgDefault { + matcher = BeTrueBecause("the %q feature gate should be enabled by default, but is disabled in v1beta1", fgName) + } + + g.Expect(fgValue).To(matcher) + } + }).WithTimeout(10 * time.Second). + WithPolling(500 * time.Millisecond). + WithContext(ctx). + Should(Succeed()) +} diff --git a/tools/csv-merger/generated-crd.yaml b/tools/csv-merger/generated-crd.yaml index d7b0d4cb77..a1cebffd93 100644 --- a/tools/csv-merger/generated-crd.yaml +++ b/tools/csv-merger/generated-crd.yaml @@ -17,6 +17,5186 @@ spec: singular: hyperconverged scope: Namespaced versions: + - additionalPrinterColumns: + - jsonPath: .metadata.creationTimestamp + name: Age + type: date + name: v1 + schema: + openAPIV3Schema: + description: HyperConverged is the Schema for the hyperconvergeds API + properties: + apiVersion: + description: |- + APIVersion defines the versioned schema of this representation of an object. + Servers should convert recognized schemas to the latest internal value, and + may reject unrecognized values. + More info: https://git.k8s.io/community/contributors/devel/sig-architecture/api-conventions.md#resources + type: string + kind: + description: |- + Kind is a string value representing the REST resource this object represents. + Servers may infer this from the endpoint the client submits requests to. + Cannot be updated. + In CamelCase. + More info: https://git.k8s.io/community/contributors/devel/sig-architecture/api-conventions.md#types-kinds + type: string + metadata: + properties: + name: + pattern: kubevirt-hyperconverged + type: string + type: object + spec: + default: + certConfig: + ca: + duration: 48h0m0s + renewBefore: 24h0m0s + server: + duration: 24h0m0s + renewBefore: 12h0m0s + deployVmConsoleProxy: false + enableApplicationAwareQuota: false + enableCommonBootImageImport: true + liveMigrationConfig: + allowAutoConverge: false + allowPostCopy: false + completionTimeoutPerGiB: 150 + parallelMigrationsPerCluster: 5 + parallelOutboundMigrationsPerNode: 2 + progressTimeout: 150 + resourceRequirements: + vmiCPUAllocationRatio: 10 + uninstallStrategy: BlockUninstallIfWorkloadsExist + virtualMachineOptions: + disableFreePageReporting: false + disableSerialConsoleLog: false + description: HyperConvergedSpec defines the desired state of HyperConverged + properties: + CommonInstancetypesDeployment: + description: CommonInstancetypesDeployment holds the configuration + of common-instancetypes deployment within KubeVirt. + properties: + enabled: + description: Enabled controls the deployment of common-instancetypes + resources, defaults to True. + nullable: true + type: boolean + type: object + applicationAwareConfig: + description: ApplicationAwareConfig set the AAQ configurations + properties: + allowApplicationAwareClusterResourceQuota: + default: false + description: AllowApplicationAwareClusterResourceQuota if set + to true, allows creation and management of ClusterAppsResourceQuota + type: boolean + namespaceSelector: + description: NamespaceSelector determines in which namespaces + scheduling gate will be added to pods.. + properties: + matchExpressions: + description: matchExpressions is a list of label selector + requirements. The requirements are ANDed. + items: + description: |- + A label selector requirement is a selector that contains values, a key, and an operator that + relates the key and values. + properties: + key: + description: key is the label key that the selector + applies to. + type: string + operator: + description: |- + operator represents a key's relationship to a set of values. + Valid operators are In, NotIn, Exists and DoesNotExist. + type: string + values: + description: |- + values is an array of string values. If the operator is In or NotIn, + the values array must be non-empty. If the operator is Exists or DoesNotExist, + the values array must be empty. This array is replaced during a strategic + merge patch. + items: + type: string + type: array + x-kubernetes-list-type: atomic + required: + - key + - operator + type: object + type: array + x-kubernetes-list-type: atomic + matchLabels: + additionalProperties: + type: string + description: |- + matchLabels is a map of {key,value} pairs. A single {key,value} in the matchLabels + map is equivalent to an element of matchExpressions, whose key field is "key", the + operator is "In", and the values array contains only "value". The requirements are ANDed. + type: object + type: object + x-kubernetes-map-type: atomic + vmiCalcConfigName: + default: DedicatedVirtualResources + description: |- + VmiCalcConfigName determine how resource allocation will be done with ApplicationsResourceQuota. + allowed values are: VmiPodUsage, VirtualResources, DedicatedVirtualResources or IgnoreVmiCalculator + enum: + - VmiPodUsage + - VirtualResources + - DedicatedVirtualResources + - IgnoreVmiCalculator + type: string + type: object + certConfig: + default: + ca: + duration: 48h0m0s + renewBefore: 24h0m0s + server: + duration: 24h0m0s + renewBefore: 12h0m0s + description: certConfig holds the rotation policy for internal, self-signed + certificates + properties: + ca: + default: + duration: 48h0m0s + renewBefore: 24h0m0s + description: |- + CA configuration - + CA certs are kept in the CA bundle as long as they are valid + properties: + duration: + default: 48h0m0s + description: |- + The requested 'duration' (i.e. lifetime) of the Certificate. + This should comply with golang's ParseDuration format (https://golang.org/pkg/time/#ParseDuration) + type: string + renewBefore: + default: 24h0m0s + description: |- + The amount of time before the currently issued certificate's `notAfter` + time that we will begin to attempt to renew the certificate. + This should comply with golang's ParseDuration format (https://golang.org/pkg/time/#ParseDuration) + type: string + type: object + server: + default: + duration: 24h0m0s + renewBefore: 12h0m0s + description: |- + Server configuration - + Certs are rotated and discarded + properties: + duration: + default: 24h0m0s + description: |- + The requested 'duration' (i.e. lifetime) of the Certificate. + This should comply with golang's ParseDuration format (https://golang.org/pkg/time/#ParseDuration) + type: string + renewBefore: + default: 12h0m0s + description: |- + The amount of time before the currently issued certificate's `notAfter` + time that we will begin to attempt to renew the certificate. + This should comply with golang's ParseDuration format (https://golang.org/pkg/time/#ParseDuration) + type: string + type: object + type: object + commonBootImageNamespace: + description: |- + CommonBootImageNamespace override the default namespace of the common boot images, in order to hide them. + + If not set, HCO won't set any namespace, letting SSP to use the default. If set, use the namespace to create the + DataImportCronTemplates and the common image streams, with this namespace. This field is not set by default. + type: string + commonTemplatesNamespace: + description: |- + CommonTemplatesNamespace defines namespace in which common templates will + be deployed. It overrides the default openshift namespace. + type: string + dataImportCronTemplates: + description: DataImportCronTemplates holds list of data import cron + templates (golden images) + items: + description: |- + DataImportCronTemplate defines the template type for DataImportCrons. + It requires metadata.name to be specified while leaving namespace as optional. + properties: + metadata: + properties: + annotations: + additionalProperties: + type: string + type: object + finalizers: + items: + type: string + type: array + labels: + additionalProperties: + type: string + type: object + name: + type: string + namespace: + type: string + type: object + spec: + description: DataImportCronSpec defines specification for DataImportCron + properties: + garbageCollect: + description: |- + GarbageCollect specifies whether old PVCs should be cleaned up after a new PVC is imported. + Options are currently "Outdated" and "Never", defaults to "Outdated". + type: string + importsToKeep: + description: Number of import PVCs to keep when garbage + collecting. Default is 3. + format: int32 + type: integer + managedDataSource: + description: |- + ManagedDataSource specifies the name of the corresponding DataSource this cron will manage. + DataSource has to be in the same namespace. + type: string + retentionPolicy: + description: RetentionPolicy specifies whether the created + DataVolumes and DataSources are retained when their DataImportCron + is deleted. Default is RatainAll. + type: string + schedule: + description: Schedule specifies in cron format when and + how often to look for new imports + type: string + serviceAccountName: + description: ServiceAccountName is the name of the ServiceAccount + for creating DataVolumes. + minLength: 1 + type: string + template: + description: Template specifies template for the DVs to + be created + properties: + apiVersion: + description: |- + APIVersion defines the versioned schema of this representation of an object. + Servers should convert recognized schemas to the latest internal value, and + may reject unrecognized values. + More info: https://git.k8s.io/community/contributors/devel/sig-architecture/api-conventions.md#resources + type: string + kind: + description: |- + Kind is a string value representing the REST resource this object represents. + Servers may infer this from the endpoint the client submits requests to. + Cannot be updated. + In CamelCase. + More info: https://git.k8s.io/community/contributors/devel/sig-architecture/api-conventions.md#types-kinds + type: string + metadata: + properties: + annotations: + additionalProperties: + type: string + type: object + finalizers: + items: + type: string + type: array + labels: + additionalProperties: + type: string + type: object + name: + type: string + namespace: + type: string + type: object + spec: + description: DataVolumeSpec defines the DataVolume type + specification + properties: + checkpoints: + description: Checkpoints is a list of DataVolumeCheckpoints, + representing stages in a multistage import. + items: + description: DataVolumeCheckpoint defines a stage + in a warm migration. + properties: + current: + description: Current is the identifier of + the snapshot created for this checkpoint. + type: string + previous: + description: Previous is the identifier of + the snapshot from the previous checkpoint. + type: string + required: + - current + - previous + type: object + type: array + contentType: + description: 'DataVolumeContentType options: "kubevirt", + "archive"' + enum: + - kubevirt + - archive + type: string + finalCheckpoint: + description: FinalCheckpoint indicates whether the + current DataVolumeCheckpoint is the final checkpoint. + type: boolean + preallocation: + description: Preallocation controls whether storage + for DataVolumes should be allocated in advance. + type: boolean + priorityClassName: + description: PriorityClassName for Importer, Cloner + and Uploader pod + type: string + pvc: + description: PVC is the PVC specification + properties: + accessModes: + description: |- + accessModes contains the desired access modes the volume should have. + More info: https://kubernetes.io/docs/concepts/storage/persistent-volumes#access-modes-1 + items: + type: string + type: array + x-kubernetes-list-type: atomic + dataSource: + description: |- + dataSource field can be used to specify either: + * An existing VolumeSnapshot object (snapshot.storage.k8s.io/VolumeSnapshot) + * An existing PVC (PersistentVolumeClaim) + If the provisioner or an external controller can support the specified data source, + it will create a new volume based on the contents of the specified data source. + When the AnyVolumeDataSource feature gate is enabled, dataSource contents will be copied to dataSourceRef, + and dataSourceRef contents will be copied to dataSource when dataSourceRef.namespace is not specified. + If the namespace is specified, then dataSourceRef will not be copied to dataSource. + properties: + apiGroup: + description: |- + APIGroup is the group for the resource being referenced. + If APIGroup is not specified, the specified Kind must be in the core API group. + For any other third-party types, APIGroup is required. + type: string + kind: + description: Kind is the type of resource + being referenced + type: string + name: + description: Name is the name of resource + being referenced + type: string + required: + - kind + - name + type: object + x-kubernetes-map-type: atomic + dataSourceRef: + description: |- + dataSourceRef specifies the object from which to populate the volume with data, if a non-empty + volume is desired. This may be any object from a non-empty API group (non + core object) or a PersistentVolumeClaim object. + When this field is specified, volume binding will only succeed if the type of + the specified object matches some installed volume populator or dynamic + provisioner. + This field will replace the functionality of the dataSource field and as such + if both fields are non-empty, they must have the same value. For backwards + compatibility, when namespace isn't specified in dataSourceRef, + both fields (dataSource and dataSourceRef) will be set to the same + value automatically if one of them is empty and the other is non-empty. + When namespace is specified in dataSourceRef, + dataSource isn't set to the same value and must be empty. + There are three important differences between dataSource and dataSourceRef: + * While dataSource only allows two specific types of objects, dataSourceRef + allows any non-core object, as well as PersistentVolumeClaim objects. + * While dataSource ignores disallowed values (dropping them), dataSourceRef + preserves all values, and generates an error if a disallowed value is + specified. + * While dataSource only allows local objects, dataSourceRef allows objects + in any namespaces. + (Beta) Using this field requires the AnyVolumeDataSource feature gate to be enabled. + (Alpha) Using the namespace field of dataSourceRef requires the CrossNamespaceVolumeDataSource feature gate to be enabled. + properties: + apiGroup: + description: |- + APIGroup is the group for the resource being referenced. + If APIGroup is not specified, the specified Kind must be in the core API group. + For any other third-party types, APIGroup is required. + type: string + kind: + description: Kind is the type of resource + being referenced + type: string + name: + description: Name is the name of resource + being referenced + type: string + namespace: + description: |- + Namespace is the namespace of resource being referenced + Note that when a namespace is specified, a gateway.networking.k8s.io/ReferenceGrant object is required in the referent namespace to allow that namespace's owner to accept the reference. See the ReferenceGrant documentation for details. + (Alpha) This field requires the CrossNamespaceVolumeDataSource feature gate to be enabled. + type: string + required: + - kind + - name + type: object + resources: + description: |- + resources represents the minimum resources the volume should have. + If RecoverVolumeExpansionFailure feature is enabled users are allowed to specify resource requirements + that are lower than previous value but must still be higher than capacity recorded in the + status field of the claim. + More info: https://kubernetes.io/docs/concepts/storage/persistent-volumes#resources + properties: + limits: + additionalProperties: + anyOf: + - type: integer + - type: string + pattern: ^(\+|-)?(([0-9]+(\.[0-9]*)?)|(\.[0-9]+))(([KMGTPE]i)|[numkMGTPE]|([eE](\+|-)?(([0-9]+(\.[0-9]*)?)|(\.[0-9]+))))?$ + x-kubernetes-int-or-string: true + description: |- + Limits describes the maximum amount of compute resources allowed. + More info: https://kubernetes.io/docs/concepts/configuration/manage-resources-containers/ + type: object + requests: + additionalProperties: + anyOf: + - type: integer + - type: string + pattern: ^(\+|-)?(([0-9]+(\.[0-9]*)?)|(\.[0-9]+))(([KMGTPE]i)|[numkMGTPE]|([eE](\+|-)?(([0-9]+(\.[0-9]*)?)|(\.[0-9]+))))?$ + x-kubernetes-int-or-string: true + description: |- + Requests describes the minimum amount of compute resources required. + If Requests is omitted for a container, it defaults to Limits if that is explicitly specified, + otherwise to an implementation-defined value. Requests cannot exceed Limits. + More info: https://kubernetes.io/docs/concepts/configuration/manage-resources-containers/ + type: object + type: object + selector: + description: selector is a label query over + volumes to consider for binding. + properties: + matchExpressions: + description: matchExpressions is a list + of label selector requirements. The requirements + are ANDed. + items: + description: |- + A label selector requirement is a selector that contains values, a key, and an operator that + relates the key and values. + properties: + key: + description: key is the label key + that the selector applies to. + type: string + operator: + description: |- + operator represents a key's relationship to a set of values. + Valid operators are In, NotIn, Exists and DoesNotExist. + type: string + values: + description: |- + values is an array of string values. If the operator is In or NotIn, + the values array must be non-empty. If the operator is Exists or DoesNotExist, + the values array must be empty. This array is replaced during a strategic + merge patch. + items: + type: string + type: array + x-kubernetes-list-type: atomic + required: + - key + - operator + type: object + type: array + x-kubernetes-list-type: atomic + matchLabels: + additionalProperties: + type: string + description: |- + matchLabels is a map of {key,value} pairs. A single {key,value} in the matchLabels + map is equivalent to an element of matchExpressions, whose key field is "key", the + operator is "In", and the values array contains only "value". The requirements are ANDed. + type: object + type: object + x-kubernetes-map-type: atomic + storageClassName: + description: |- + storageClassName is the name of the StorageClass required by the claim. + More info: https://kubernetes.io/docs/concepts/storage/persistent-volumes#class-1 + type: string + volumeAttributesClassName: + description: |- + volumeAttributesClassName may be used to set the VolumeAttributesClass used by this claim. + If specified, the CSI driver will create or update the volume with the attributes defined + in the corresponding VolumeAttributesClass. This has a different purpose than storageClassName, + it can be changed after the claim is created. An empty string or nil value indicates that no + VolumeAttributesClass will be applied to the claim. If the claim enters an Infeasible error state, + this field can be reset to its previous value (including nil) to cancel the modification. + If the resource referred to by volumeAttributesClass does not exist, this PersistentVolumeClaim will be + set to a Pending state, as reflected by the modifyVolumeStatus field, until such as a resource + exists. + More info: https://kubernetes.io/docs/concepts/storage/volume-attributes-classes/ + type: string + volumeMode: + description: |- + volumeMode defines what type of volume is required by the claim. + Value of Filesystem is implied when not included in claim spec. + type: string + volumeName: + description: volumeName is the binding reference + to the PersistentVolume backing this claim. + type: string + type: object + source: + description: Source is the src of the data for the + requested DataVolume + properties: + blank: + description: DataVolumeBlankImage provides the + parameters to create a new raw blank image + for the PVC + type: object + gcs: + description: DataVolumeSourceGCS provides the + parameters to create a Data Volume from an + GCS source + properties: + secretRef: + description: SecretRef provides the secret + reference needed to access the GCS source + type: string + url: + description: URL is the url of the GCS source + type: string + required: + - url + type: object + http: + description: DataVolumeSourceHTTP can be either + an http or https endpoint, with an optional + basic auth user name and password, and an + optional configmap containing additional CAs + properties: + certConfigMap: + description: CertConfigMap is a configmap + reference, containing a Certificate Authority(CA) + public key, and a base64 encoded pem certificate + type: string + extraHeaders: + description: ExtraHeaders is a list of strings + containing extra headers to include with + HTTP transfer requests + items: + type: string + type: array + secretExtraHeaders: + description: SecretExtraHeaders is a list + of Secret references, each containing + an extra HTTP header that may include + sensitive information + items: + type: string + type: array + secretRef: + description: SecretRef A Secret reference, + the secret should contain accessKeyId + (user name) base64 encoded, and secretKey + (password) also base64 encoded + type: string + url: + description: URL is the URL of the http(s) + endpoint + type: string + required: + - url + type: object + imageio: + description: DataVolumeSourceImageIO provides + the parameters to create a Data Volume from + an imageio source + properties: + certConfigMap: + description: CertConfigMap provides a reference + to the CA cert + type: string + diskId: + description: DiskID provides id of a disk + to be imported + type: string + insecureSkipVerify: + description: InsecureSkipVerify is a flag + to skip certificate verification + type: boolean + secretRef: + description: SecretRef provides the secret + reference needed to access the ovirt-engine + type: string + url: + description: URL is the URL of the ovirt-engine + type: string + required: + - diskId + - url + type: object + pvc: + description: DataVolumeSourcePVC provides the + parameters to create a Data Volume from an + existing PVC + properties: + name: + description: The name of the source PVC + type: string + namespace: + description: The namespace of the source + PVC + type: string + required: + - name + - namespace + type: object + registry: + description: DataVolumeSourceRegistry provides + the parameters to create a Data Volume from + an registry source + properties: + certConfigMap: + description: CertConfigMap provides a reference + to the Registry certs + type: string + imageStream: + description: ImageStream is the name of + image stream for import + type: string + platform: + description: Platform describes the minimum + runtime requirements of the image + properties: + architecture: + description: Architecture specifies + the image target CPU architecture + type: string + type: object + pullMethod: + description: PullMethod can be either "pod" + (default import), or "node" (node docker + cache based import) + type: string + secretRef: + description: SecretRef provides the secret + reference needed to access the Registry + source + type: string + url: + description: 'URL is the url of the registry + source (starting with the scheme: docker, + oci-archive)' + type: string + type: object + s3: + description: DataVolumeSourceS3 provides the + parameters to create a Data Volume from an + S3 source + properties: + certConfigMap: + description: CertConfigMap is a configmap + reference, containing a Certificate Authority(CA) + public key, and a base64 encoded pem certificate + type: string + secretRef: + description: SecretRef provides the secret + reference needed to access the S3 source + type: string + url: + description: URL is the url of the S3 source + type: string + required: + - url + type: object + snapshot: + description: DataVolumeSourceSnapshot provides + the parameters to create a Data Volume from + an existing VolumeSnapshot + properties: + name: + description: The name of the source VolumeSnapshot + type: string + namespace: + description: The namespace of the source + VolumeSnapshot + type: string + required: + - name + - namespace + type: object + upload: + description: DataVolumeSourceUpload provides + the parameters to create a Data Volume by + uploading the source + type: object + vddk: + description: DataVolumeSourceVDDK provides the + parameters to create a Data Volume from a + Vmware source + properties: + backingFile: + description: BackingFile is the path to + the virtual hard disk to migrate from + vCenter/ESXi + type: string + extraArgs: + description: ExtraArgs is a reference to + a ConfigMap containing extra arguments + to pass directly to the VDDK library + type: string + initImageURL: + description: InitImageURL is an optional + URL to an image containing an extracted + VDDK library, overrides v2v-vmware config + map + type: string + secretRef: + description: SecretRef provides a reference + to a secret containing the username and + password needed to access the vCenter + or ESXi host + type: string + thumbprint: + description: Thumbprint is the certificate + thumbprint of the vCenter or ESXi host + type: string + url: + description: URL is the URL of the vCenter + or ESXi host with the VM to migrate + type: string + uuid: + description: UUID is the UUID of the virtual + machine that the backing file is attached + to in vCenter/ESXi + type: string + type: object + type: object + sourceRef: + description: SourceRef is an indirect reference + to the source of data for the requested DataVolume + properties: + kind: + description: The kind of the source reference, + currently only "DataSource" is supported + type: string + name: + description: The name of the source reference + type: string + namespace: + description: The namespace of the source reference, + defaults to the DataVolume namespace + type: string + required: + - kind + - name + type: object + storage: + description: Storage is the requested storage specification + properties: + accessModes: + description: |- + AccessModes contains the desired access modes the volume should have. + More info: https://kubernetes.io/docs/concepts/storage/persistent-volumes#access-modes-1 + items: + type: string + type: array + dataSource: + description: |- + This field can be used to specify either: * An existing VolumeSnapshot object (snapshot.storage.k8s.io/VolumeSnapshot) * An existing PVC (PersistentVolumeClaim) * An existing custom resource that implements data population (Alpha) In order to use custom resource types that implement data population, the AnyVolumeDataSource feature gate must be enabled. If the provisioner or an external controller can support the specified data source, it will create a new volume based on the contents of the specified data source. + If the AnyVolumeDataSource feature gate is enabled, this field will always have the same contents as the DataSourceRef field. + properties: + apiGroup: + description: |- + APIGroup is the group for the resource being referenced. + If APIGroup is not specified, the specified Kind must be in the core API group. + For any other third-party types, APIGroup is required. + type: string + kind: + description: Kind is the type of resource + being referenced + type: string + name: + description: Name is the name of resource + being referenced + type: string + required: + - kind + - name + type: object + x-kubernetes-map-type: atomic + dataSourceRef: + description: |- + Specifies the object from which to populate the volume with data, if a non-empty volume is desired. This may be any local object from a non-empty API group (non core object) or a PersistentVolumeClaim object. When this field is specified, volume binding will only succeed if the type of the specified object matches some installed volume populator or dynamic provisioner. + This field will replace the functionality of the DataSource field and as such if both fields are non-empty, they must have the same value. For backwards compatibility, both fields (DataSource and DataSourceRef) will be set to the same value automatically if one of them is empty and the other is non-empty. + There are two important differences between DataSource and DataSourceRef: + * While DataSource only allows two specific types of objects, DataSourceRef allows any non-core object, as well as PersistentVolumeClaim objects. + * While DataSource ignores disallowed values (dropping them), DataSourceRef preserves all values, and generates an error if a disallowed value is specified. + (Beta) Using this field requires the AnyVolumeDataSource feature gate to be enabled. + properties: + apiGroup: + description: |- + APIGroup is the group for the resource being referenced. + If APIGroup is not specified, the specified Kind must be in the core API group. + For any other third-party types, APIGroup is required. + type: string + kind: + description: Kind is the type of resource + being referenced + type: string + name: + description: Name is the name of resource + being referenced + type: string + namespace: + description: |- + Namespace is the namespace of resource being referenced + Note that when a namespace is specified, a gateway.networking.k8s.io/ReferenceGrant object is required in the referent namespace to allow that namespace's owner to accept the reference. See the ReferenceGrant documentation for details. + (Alpha) This field requires the CrossNamespaceVolumeDataSource feature gate to be enabled. + type: string + required: + - kind + - name + type: object + resources: + description: |- + Resources represents the minimum resources the volume should have. + More info: https://kubernetes.io/docs/concepts/storage/persistent-volumes#resources + properties: + limits: + additionalProperties: + anyOf: + - type: integer + - type: string + pattern: ^(\+|-)?(([0-9]+(\.[0-9]*)?)|(\.[0-9]+))(([KMGTPE]i)|[numkMGTPE]|([eE](\+|-)?(([0-9]+(\.[0-9]*)?)|(\.[0-9]+))))?$ + x-kubernetes-int-or-string: true + description: |- + Limits describes the maximum amount of compute resources allowed. + More info: https://kubernetes.io/docs/concepts/configuration/manage-resources-containers/ + type: object + requests: + additionalProperties: + anyOf: + - type: integer + - type: string + pattern: ^(\+|-)?(([0-9]+(\.[0-9]*)?)|(\.[0-9]+))(([KMGTPE]i)|[numkMGTPE]|([eE](\+|-)?(([0-9]+(\.[0-9]*)?)|(\.[0-9]+))))?$ + x-kubernetes-int-or-string: true + description: |- + Requests describes the minimum amount of compute resources required. + If Requests is omitted for a container, it defaults to Limits if that is explicitly specified, + otherwise to an implementation-defined value. Requests cannot exceed Limits. + More info: https://kubernetes.io/docs/concepts/configuration/manage-resources-containers/ + type: object + type: object + selector: + description: A label query over volumes to consider + for binding. + properties: + matchExpressions: + description: matchExpressions is a list + of label selector requirements. The requirements + are ANDed. + items: + description: |- + A label selector requirement is a selector that contains values, a key, and an operator that + relates the key and values. + properties: + key: + description: key is the label key + that the selector applies to. + type: string + operator: + description: |- + operator represents a key's relationship to a set of values. + Valid operators are In, NotIn, Exists and DoesNotExist. + type: string + values: + description: |- + values is an array of string values. If the operator is In or NotIn, + the values array must be non-empty. If the operator is Exists or DoesNotExist, + the values array must be empty. This array is replaced during a strategic + merge patch. + items: + type: string + type: array + x-kubernetes-list-type: atomic + required: + - key + - operator + type: object + type: array + x-kubernetes-list-type: atomic + matchLabels: + additionalProperties: + type: string + description: |- + matchLabels is a map of {key,value} pairs. A single {key,value} in the matchLabels + map is equivalent to an element of matchExpressions, whose key field is "key", the + operator is "In", and the values array contains only "value". The requirements are ANDed. + type: object + type: object + x-kubernetes-map-type: atomic + storageClassName: + description: |- + Name of the StorageClass required by the claim. + More info: https://kubernetes.io/docs/concepts/storage/persistent-volumes#class-1 + type: string + volumeMode: + description: |- + volumeMode defines what type of volume is required by the claim. + Value of Filesystem is implied when not included in claim spec. + type: string + volumeName: + description: VolumeName is the binding reference + to the PersistentVolume backing this claim. + type: string + type: object + type: object + status: + description: DataVolumeStatus contains the current status + of the DataVolume + properties: + claimName: + description: ClaimName is the name of the underlying + PVC used by the DataVolume. + type: string + conditions: + items: + description: DataVolumeCondition represents the + state of a data volume condition. + properties: + lastHeartbeatTime: + format: date-time + type: string + lastTransitionTime: + format: date-time + type: string + message: + type: string + reason: + type: string + status: + type: string + type: + description: DataVolumeConditionType is the + string representation of known condition + types + type: string + required: + - status + - type + type: object + type: array + phase: + description: Phase is the current phase of the data + volume + type: string + progress: + description: DataVolumeProgress is the current progress + of the DataVolume transfer operation. Value between + 0 and 100 inclusive, N/A if not available + type: string + restartCount: + description: RestartCount is the number of times + the pod populating the DataVolume has restarted + format: int32 + type: integer + type: object + required: + - spec + type: object + required: + - managedDataSource + - schedule + - template + type: object + type: object + type: array + x-kubernetes-list-type: atomic + defaultCPUModel: + description: |- + DefaultCPUModel defines a cluster default for CPU model: default CPU model is set when VMI doesn't have any CPU model. + When VMI has CPU model set, then VMI's CPU model is preferred. + When default CPU model is not set and VMI's CPU model is not set too, host-model will be set. + Default CPU model can be changed when kubevirt is running. + type: string + defaultRuntimeClass: + description: |- + DefaultRuntimeClass defines a cluster default for the RuntimeClass to be used for VMIs pods if not set there. + Default RuntimeClass can be changed when kubevirt is running, existing VMIs are not impacted till + the next restart/live-migration when they are eventually going to consume the new default RuntimeClass. + type: string + deployVmConsoleProxy: + default: false + description: deploy VM console proxy resources in SSP operator + type: boolean + enableApplicationAwareQuota: + default: false + description: EnableApplicationAwareQuota if true, enables the Application + Aware Quota feature + type: boolean + enableCommonBootImageImport: + default: true + description: |- + Opt-in to automatic delivery/updates of the common data import cron templates. + There are two sources for the data import cron templates: hard coded list of common templates, and custom (user + defined) templates that can be added to the dataImportCronTemplates field. This field only controls the common + templates. It is possible to use custom templates by adding them to the dataImportCronTemplates field. + type: boolean + evictionStrategy: + description: |- + EvictionStrategy defines at the cluster level if the VirtualMachineInstance should be + migrated instead of shut-off in case of a node drain. If the VirtualMachineInstance specific + field is set it overrides the cluster level one. + Allowed values: + - `None` no eviction strategy at cluster level. + - `LiveMigrate` migrate the VM on eviction; a not live migratable VM with no specific strategy will block the drain of the node util manually evicted. + - `LiveMigrateIfPossible` migrate the VM on eviction if live migration is possible, otherwise directly evict. + - `External` block the drain, track eviction and notify an external controller. + Defaults to LiveMigrate with multiple worker nodes, None on single worker clusters. + enum: + - None + - LiveMigrate + - LiveMigrateIfPossible + - External + type: string + featureGates: + description: |- + FeatureGates is a set of optional feature gates to enable or disable new + features that are not generally available yet. + Add a new FeatureGate Object to this set, to enable a feature that is + disabled by default, or to disable a feature that is enabled by default. + + A feature gate may be in the following phases: + * Alpha: the feature is in dev-preview. It is disabled by default, but can + be enabled. + * Beta: the feature gate is in tech-preview. It is enabled by default, but + can be disabled. + * GA: the feature is graduated and is always enabled. There is no way to + disable it. + * Deprecated: the feature is no longer supported. There is no way to enable + it + + Feature-Gate list: + * alignCPUs: + Enable KubeVirt to request up to two additional dedicated CPUs in order to + complete the total CPU count to an even parity when using emulator thread + isolation. + Note: this feature is in Developer Preview. + Phase: Alpha + + * decentralizedLiveMigration: + enables the decentralized live migration (cross-cluster migration) feature. + This feature allows live migration of VirtualMachineInstances between + different clusters. + Note: This feature is in Developer Preview. + Phase: Alpha + + * declarativeHotplugVolumes: + enables the use of the declarative volume hotplug feature in KubeVirt. + When enabled, the "DeclarativeHotplugVolumes" feature gate is enabled in + the KubeVirt CR, instead of the "HotplugVolumes" feature gate. + When disabled, the "HotplugVolumes" feature gate is enabled (default + behavior). + Phase: Alpha + + * deployKubeSecondaryDNS: + Deploy KubeSecondaryDNS by CNAO + Phase: Alpha + + * disableMDevConfiguration: + Disable mediated devices handling on KubeVirt + Phase: Alpha + + * downwardMetrics: + Allow to expose a limited set of host metrics to guests. + Phase: Alpha + + * enableMultiArchBootImageImport: + allows the HCO to run on heterogeneous clusters with different CPU + architectures. + Enabling this feature gate will allow the HCO to create Golden Images for + different CPU architectures. + Phase: Alpha + + * objectGraph: + enables the ObjectGraph VM and VMI subresource in KubeVirt. + This subresource returns a structured list of k8s objects that are related + to the specified VM or VMI, enabling better dependency tracking. + Phase: Alpha + + * persistentReservation: + Enable persistent reservation of a LUN through the SCSI Persistent Reserve + commands on Kubevirt. + In order to issue privileged SCSI ioctls, the VM requires activation of the + persistent reservation flag. + Once this feature gate is enabled, then the additional container with the + qemu-pr-helper is deployed inside the virt-handler pod. + Enabling (or removing) the feature gate causes the redeployment of the + virt-handler pod. + Phase: Alpha + + * videoConfig: + allows users to configure video device types for their virtual machines. + This can be useful for workloads that require specific video capabilities + or architectures. + Phase: Beta + + * autoResourceLimits: + Phase: Deprecated + + * deployKubevirtIpamController: + Phase: Deprecated + + * deployTektonTaskResources: + Phase: Deprecated + + * deployVmConsoleProxy: + Phase: Deprecated + + * enableApplicationAwareQuota: + This feature gate is ignored. Use spec.enableApplicationAwareQuota field instead + Phase: Deprecated + + * enableCommonBootImageImport: + This feature gate is ignored. Use spec.enableCommonBootImageImport field instead + Phase: Deprecated + + * enableManagedTenantQuota: + Phase: Deprecated + + * nonRoot: + Phase: Deprecated + + * primaryUserDefinedNetworkBinding: + Phase: Deprecated + + * withHostPassthroughCPU: + Phase: Deprecated + items: + description: FeatureGate is an optional feature gate to enable or + disable a new feature that is not generally available yet. + properties: + name: + description: Name is the feature gate name + type: string + state: + description: State determines if the feature gate is enabled + ("Enabled"), or disabled ("False"). The default value is "Disabled". + enum: + - Enabled + - Disabled + type: string + required: + - name + type: object + type: array + filesystemOverhead: + description: |- + FilesystemOverhead describes the space reserved for overhead when using Filesystem volumes. + A value is between 0 and 1, if not defined it is 0.055 (5.5 percent overhead) + properties: + global: + description: Global is how much space of a Filesystem volume should + be reserved for overhead. This value is used unless overridden + by a more specific value (per storageClass) + pattern: ^(0(?:\.\d{1,3})?|1)$ + type: string + storageClass: + additionalProperties: + description: |- + Percent is a string that can only be a value between [0,1) + (Note: we actually rely on reconcile to reject invalid values) + pattern: ^(0(?:\.\d{1,3})?|1)$ + type: string + description: StorageClass specifies how much space of a Filesystem + volume should be reserved for safety. The keys are the storageClass + and the values are the overhead. This value overrides the global + value + type: object + type: object + higherWorkloadDensity: + default: + memoryOvercommitPercentage: 100 + description: HigherWorkloadDensity holds configuration aimed to increase + virtual machine density + properties: + memoryOvercommitPercentage: + default: 100 + description: |- + MemoryOvercommitPercentage is the percentage of memory we want to give VMIs compared to the amount + given to its parent pod (virt-launcher). For example, a value of 102 means the VMI will + "see" 2% more memory than its parent pod. Values under 100 are effectively "undercommits". + Overcommits can lead to memory exhaustion, which in turn can lead to crashes. Use carefully. + minimum: 10 + type: integer + type: object + infra: + description: |- + infra HyperConvergedConfig influences the pod configuration (currently only placement) + for all the infra components needed on the virtualization enabled cluster + but not necessarily directly on each node running VMs/VMIs. + properties: + nodePlacement: + description: NodePlacement describes node scheduling configuration. + properties: + affinity: + description: |- + affinity enables pod affinity/anti-affinity placement expanding the types of constraints + that can be expressed with nodeSelector. + affinity is going to be applied to the relevant kind of pods in parallel with nodeSelector + See https://kubernetes.io/docs/concepts/scheduling-eviction/assign-pod-node/#affinity-and-anti-affinity + properties: + nodeAffinity: + description: Describes node affinity scheduling rules + for the pod. + properties: + preferredDuringSchedulingIgnoredDuringExecution: + description: |- + The scheduler will prefer to schedule pods to nodes that satisfy + the affinity expressions specified by this field, but it may choose + a node that violates one or more of the expressions. The node that is + most preferred is the one with the greatest sum of weights, i.e. + for each node that meets all of the scheduling requirements (resource + request, requiredDuringScheduling affinity expressions, etc.), + compute a sum by iterating through the elements of this field and adding + "weight" to the sum if the node matches the corresponding matchExpressions; the + node(s) with the highest sum are the most preferred. + items: + description: |- + An empty preferred scheduling term matches all objects with implicit weight 0 + (i.e. it's a no-op). A null preferred scheduling term matches no objects (i.e. is also a no-op). + properties: + preference: + description: A node selector term, associated + with the corresponding weight. + properties: + matchExpressions: + description: A list of node selector requirements + by node's labels. + items: + description: |- + A node selector requirement is a selector that contains values, a key, and an operator + that relates the key and values. + properties: + key: + description: The label key that the + selector applies to. + type: string + operator: + description: |- + Represents a key's relationship to a set of values. + Valid operators are In, NotIn, Exists, DoesNotExist. Gt, and Lt. + type: string + values: + description: |- + An array of string values. If the operator is In or NotIn, + the values array must be non-empty. If the operator is Exists or DoesNotExist, + the values array must be empty. If the operator is Gt or Lt, the values + array must have a single element, which will be interpreted as an integer. + This array is replaced during a strategic merge patch. + items: + type: string + type: array + x-kubernetes-list-type: atomic + required: + - key + - operator + type: object + type: array + x-kubernetes-list-type: atomic + matchFields: + description: A list of node selector requirements + by node's fields. + items: + description: |- + A node selector requirement is a selector that contains values, a key, and an operator + that relates the key and values. + properties: + key: + description: The label key that the + selector applies to. + type: string + operator: + description: |- + Represents a key's relationship to a set of values. + Valid operators are In, NotIn, Exists, DoesNotExist. Gt, and Lt. + type: string + values: + description: |- + An array of string values. If the operator is In or NotIn, + the values array must be non-empty. If the operator is Exists or DoesNotExist, + the values array must be empty. If the operator is Gt or Lt, the values + array must have a single element, which will be interpreted as an integer. + This array is replaced during a strategic merge patch. + items: + type: string + type: array + x-kubernetes-list-type: atomic + required: + - key + - operator + type: object + type: array + x-kubernetes-list-type: atomic + type: object + x-kubernetes-map-type: atomic + weight: + description: Weight associated with matching + the corresponding nodeSelectorTerm, in the + range 1-100. + format: int32 + type: integer + required: + - preference + - weight + type: object + type: array + x-kubernetes-list-type: atomic + requiredDuringSchedulingIgnoredDuringExecution: + description: |- + If the affinity requirements specified by this field are not met at + scheduling time, the pod will not be scheduled onto the node. + If the affinity requirements specified by this field cease to be met + at some point during pod execution (e.g. due to an update), the system + may or may not try to eventually evict the pod from its node. + properties: + nodeSelectorTerms: + description: Required. A list of node selector + terms. The terms are ORed. + items: + description: |- + A null or empty node selector term matches no objects. The requirements of + them are ANDed. + The TopologySelectorTerm type implements a subset of the NodeSelectorTerm. + properties: + matchExpressions: + description: A list of node selector requirements + by node's labels. + items: + description: |- + A node selector requirement is a selector that contains values, a key, and an operator + that relates the key and values. + properties: + key: + description: The label key that the + selector applies to. + type: string + operator: + description: |- + Represents a key's relationship to a set of values. + Valid operators are In, NotIn, Exists, DoesNotExist. Gt, and Lt. + type: string + values: + description: |- + An array of string values. If the operator is In or NotIn, + the values array must be non-empty. If the operator is Exists or DoesNotExist, + the values array must be empty. If the operator is Gt or Lt, the values + array must have a single element, which will be interpreted as an integer. + This array is replaced during a strategic merge patch. + items: + type: string + type: array + x-kubernetes-list-type: atomic + required: + - key + - operator + type: object + type: array + x-kubernetes-list-type: atomic + matchFields: + description: A list of node selector requirements + by node's fields. + items: + description: |- + A node selector requirement is a selector that contains values, a key, and an operator + that relates the key and values. + properties: + key: + description: The label key that the + selector applies to. + type: string + operator: + description: |- + Represents a key's relationship to a set of values. + Valid operators are In, NotIn, Exists, DoesNotExist. Gt, and Lt. + type: string + values: + description: |- + An array of string values. If the operator is In or NotIn, + the values array must be non-empty. If the operator is Exists or DoesNotExist, + the values array must be empty. If the operator is Gt or Lt, the values + array must have a single element, which will be interpreted as an integer. + This array is replaced during a strategic merge patch. + items: + type: string + type: array + x-kubernetes-list-type: atomic + required: + - key + - operator + type: object + type: array + x-kubernetes-list-type: atomic + type: object + x-kubernetes-map-type: atomic + type: array + x-kubernetes-list-type: atomic + required: + - nodeSelectorTerms + type: object + x-kubernetes-map-type: atomic + type: object + podAffinity: + description: Describes pod affinity scheduling rules (e.g. + co-locate this pod in the same node, zone, etc. as some + other pod(s)). + properties: + preferredDuringSchedulingIgnoredDuringExecution: + description: |- + The scheduler will prefer to schedule pods to nodes that satisfy + the affinity expressions specified by this field, but it may choose + a node that violates one or more of the expressions. The node that is + most preferred is the one with the greatest sum of weights, i.e. + for each node that meets all of the scheduling requirements (resource + request, requiredDuringScheduling affinity expressions, etc.), + compute a sum by iterating through the elements of this field and adding + "weight" to the sum if the node has pods which matches the corresponding podAffinityTerm; the + node(s) with the highest sum are the most preferred. + items: + description: The weights of all of the matched WeightedPodAffinityTerm + fields are added per-node to find the most preferred + node(s) + properties: + podAffinityTerm: + description: Required. A pod affinity term, + associated with the corresponding weight. + properties: + labelSelector: + description: |- + A label query over a set of resources, in this case pods. + If it's null, this PodAffinityTerm matches with no Pods. + properties: + matchExpressions: + description: matchExpressions is a list + of label selector requirements. The + requirements are ANDed. + items: + description: |- + A label selector requirement is a selector that contains values, a key, and an operator that + relates the key and values. + properties: + key: + description: key is the label + key that the selector applies + to. + type: string + operator: + description: |- + operator represents a key's relationship to a set of values. + Valid operators are In, NotIn, Exists and DoesNotExist. + type: string + values: + description: |- + values is an array of string values. If the operator is In or NotIn, + the values array must be non-empty. If the operator is Exists or DoesNotExist, + the values array must be empty. This array is replaced during a strategic + merge patch. + items: + type: string + type: array + x-kubernetes-list-type: atomic + required: + - key + - operator + type: object + type: array + x-kubernetes-list-type: atomic + matchLabels: + additionalProperties: + type: string + description: |- + matchLabels is a map of {key,value} pairs. A single {key,value} in the matchLabels + map is equivalent to an element of matchExpressions, whose key field is "key", the + operator is "In", and the values array contains only "value". The requirements are ANDed. + type: object + type: object + x-kubernetes-map-type: atomic + matchLabelKeys: + description: |- + MatchLabelKeys is a set of pod label keys to select which pods will + be taken into consideration. The keys are used to lookup values from the + incoming pod labels, those key-value labels are merged with `labelSelector` as `key in (value)` + to select the group of existing pods which pods will be taken into consideration + for the incoming pod's pod (anti) affinity. Keys that don't exist in the incoming + pod labels will be ignored. The default value is empty. + The same key is forbidden to exist in both matchLabelKeys and labelSelector. + Also, matchLabelKeys cannot be set when labelSelector isn't set. + items: + type: string + type: array + x-kubernetes-list-type: atomic + mismatchLabelKeys: + description: |- + MismatchLabelKeys is a set of pod label keys to select which pods will + be taken into consideration. The keys are used to lookup values from the + incoming pod labels, those key-value labels are merged with `labelSelector` as `key notin (value)` + to select the group of existing pods which pods will be taken into consideration + for the incoming pod's pod (anti) affinity. Keys that don't exist in the incoming + pod labels will be ignored. The default value is empty. + The same key is forbidden to exist in both mismatchLabelKeys and labelSelector. + Also, mismatchLabelKeys cannot be set when labelSelector isn't set. + items: + type: string + type: array + x-kubernetes-list-type: atomic + namespaceSelector: + description: |- + A label query over the set of namespaces that the term applies to. + The term is applied to the union of the namespaces selected by this field + and the ones listed in the namespaces field. + null selector and null or empty namespaces list means "this pod's namespace". + An empty selector ({}) matches all namespaces. + properties: + matchExpressions: + description: matchExpressions is a list + of label selector requirements. The + requirements are ANDed. + items: + description: |- + A label selector requirement is a selector that contains values, a key, and an operator that + relates the key and values. + properties: + key: + description: key is the label + key that the selector applies + to. + type: string + operator: + description: |- + operator represents a key's relationship to a set of values. + Valid operators are In, NotIn, Exists and DoesNotExist. + type: string + values: + description: |- + values is an array of string values. If the operator is In or NotIn, + the values array must be non-empty. If the operator is Exists or DoesNotExist, + the values array must be empty. This array is replaced during a strategic + merge patch. + items: + type: string + type: array + x-kubernetes-list-type: atomic + required: + - key + - operator + type: object + type: array + x-kubernetes-list-type: atomic + matchLabels: + additionalProperties: + type: string + description: |- + matchLabels is a map of {key,value} pairs. A single {key,value} in the matchLabels + map is equivalent to an element of matchExpressions, whose key field is "key", the + operator is "In", and the values array contains only "value". The requirements are ANDed. + type: object + type: object + x-kubernetes-map-type: atomic + namespaces: + description: |- + namespaces specifies a static list of namespace names that the term applies to. + The term is applied to the union of the namespaces listed in this field + and the ones selected by namespaceSelector. + null or empty namespaces list and null namespaceSelector means "this pod's namespace". + items: + type: string + type: array + x-kubernetes-list-type: atomic + topologyKey: + description: |- + This pod should be co-located (affinity) or not co-located (anti-affinity) with the pods matching + the labelSelector in the specified namespaces, where co-located is defined as running on a node + whose value of the label with key topologyKey matches that of any node on which any of the + selected pods is running. + Empty topologyKey is not allowed. + type: string + required: + - topologyKey + type: object + weight: + description: |- + weight associated with matching the corresponding podAffinityTerm, + in the range 1-100. + format: int32 + type: integer + required: + - podAffinityTerm + - weight + type: object + type: array + x-kubernetes-list-type: atomic + requiredDuringSchedulingIgnoredDuringExecution: + description: |- + If the affinity requirements specified by this field are not met at + scheduling time, the pod will not be scheduled onto the node. + If the affinity requirements specified by this field cease to be met + at some point during pod execution (e.g. due to a pod label update), the + system may or may not try to eventually evict the pod from its node. + When there are multiple elements, the lists of nodes corresponding to each + podAffinityTerm are intersected, i.e. all terms must be satisfied. + items: + description: |- + Defines a set of pods (namely those matching the labelSelector + relative to the given namespace(s)) that this pod should be + co-located (affinity) or not co-located (anti-affinity) with, + where co-located is defined as running on a node whose value of + the label with key matches that of any node on which + a pod of the set of pods is running + properties: + labelSelector: + description: |- + A label query over a set of resources, in this case pods. + If it's null, this PodAffinityTerm matches with no Pods. + properties: + matchExpressions: + description: matchExpressions is a list + of label selector requirements. The requirements + are ANDed. + items: + description: |- + A label selector requirement is a selector that contains values, a key, and an operator that + relates the key and values. + properties: + key: + description: key is the label key + that the selector applies to. + type: string + operator: + description: |- + operator represents a key's relationship to a set of values. + Valid operators are In, NotIn, Exists and DoesNotExist. + type: string + values: + description: |- + values is an array of string values. If the operator is In or NotIn, + the values array must be non-empty. If the operator is Exists or DoesNotExist, + the values array must be empty. This array is replaced during a strategic + merge patch. + items: + type: string + type: array + x-kubernetes-list-type: atomic + required: + - key + - operator + type: object + type: array + x-kubernetes-list-type: atomic + matchLabels: + additionalProperties: + type: string + description: |- + matchLabels is a map of {key,value} pairs. A single {key,value} in the matchLabels + map is equivalent to an element of matchExpressions, whose key field is "key", the + operator is "In", and the values array contains only "value". The requirements are ANDed. + type: object + type: object + x-kubernetes-map-type: atomic + matchLabelKeys: + description: |- + MatchLabelKeys is a set of pod label keys to select which pods will + be taken into consideration. The keys are used to lookup values from the + incoming pod labels, those key-value labels are merged with `labelSelector` as `key in (value)` + to select the group of existing pods which pods will be taken into consideration + for the incoming pod's pod (anti) affinity. Keys that don't exist in the incoming + pod labels will be ignored. The default value is empty. + The same key is forbidden to exist in both matchLabelKeys and labelSelector. + Also, matchLabelKeys cannot be set when labelSelector isn't set. + items: + type: string + type: array + x-kubernetes-list-type: atomic + mismatchLabelKeys: + description: |- + MismatchLabelKeys is a set of pod label keys to select which pods will + be taken into consideration. The keys are used to lookup values from the + incoming pod labels, those key-value labels are merged with `labelSelector` as `key notin (value)` + to select the group of existing pods which pods will be taken into consideration + for the incoming pod's pod (anti) affinity. Keys that don't exist in the incoming + pod labels will be ignored. The default value is empty. + The same key is forbidden to exist in both mismatchLabelKeys and labelSelector. + Also, mismatchLabelKeys cannot be set when labelSelector isn't set. + items: + type: string + type: array + x-kubernetes-list-type: atomic + namespaceSelector: + description: |- + A label query over the set of namespaces that the term applies to. + The term is applied to the union of the namespaces selected by this field + and the ones listed in the namespaces field. + null selector and null or empty namespaces list means "this pod's namespace". + An empty selector ({}) matches all namespaces. + properties: + matchExpressions: + description: matchExpressions is a list + of label selector requirements. The requirements + are ANDed. + items: + description: |- + A label selector requirement is a selector that contains values, a key, and an operator that + relates the key and values. + properties: + key: + description: key is the label key + that the selector applies to. + type: string + operator: + description: |- + operator represents a key's relationship to a set of values. + Valid operators are In, NotIn, Exists and DoesNotExist. + type: string + values: + description: |- + values is an array of string values. If the operator is In or NotIn, + the values array must be non-empty. If the operator is Exists or DoesNotExist, + the values array must be empty. This array is replaced during a strategic + merge patch. + items: + type: string + type: array + x-kubernetes-list-type: atomic + required: + - key + - operator + type: object + type: array + x-kubernetes-list-type: atomic + matchLabels: + additionalProperties: + type: string + description: |- + matchLabels is a map of {key,value} pairs. A single {key,value} in the matchLabels + map is equivalent to an element of matchExpressions, whose key field is "key", the + operator is "In", and the values array contains only "value". The requirements are ANDed. + type: object + type: object + x-kubernetes-map-type: atomic + namespaces: + description: |- + namespaces specifies a static list of namespace names that the term applies to. + The term is applied to the union of the namespaces listed in this field + and the ones selected by namespaceSelector. + null or empty namespaces list and null namespaceSelector means "this pod's namespace". + items: + type: string + type: array + x-kubernetes-list-type: atomic + topologyKey: + description: |- + This pod should be co-located (affinity) or not co-located (anti-affinity) with the pods matching + the labelSelector in the specified namespaces, where co-located is defined as running on a node + whose value of the label with key topologyKey matches that of any node on which any of the + selected pods is running. + Empty topologyKey is not allowed. + type: string + required: + - topologyKey + type: object + type: array + x-kubernetes-list-type: atomic + type: object + podAntiAffinity: + description: Describes pod anti-affinity scheduling rules + (e.g. avoid putting this pod in the same node, zone, + etc. as some other pod(s)). + properties: + preferredDuringSchedulingIgnoredDuringExecution: + description: |- + The scheduler will prefer to schedule pods to nodes that satisfy + the anti-affinity expressions specified by this field, but it may choose + a node that violates one or more of the expressions. The node that is + most preferred is the one with the greatest sum of weights, i.e. + for each node that meets all of the scheduling requirements (resource + request, requiredDuringScheduling anti-affinity expressions, etc.), + compute a sum by iterating through the elements of this field and subtracting + "weight" from the sum if the node has pods which matches the corresponding podAffinityTerm; the + node(s) with the highest sum are the most preferred. + items: + description: The weights of all of the matched WeightedPodAffinityTerm + fields are added per-node to find the most preferred + node(s) + properties: + podAffinityTerm: + description: Required. A pod affinity term, + associated with the corresponding weight. + properties: + labelSelector: + description: |- + A label query over a set of resources, in this case pods. + If it's null, this PodAffinityTerm matches with no Pods. + properties: + matchExpressions: + description: matchExpressions is a list + of label selector requirements. The + requirements are ANDed. + items: + description: |- + A label selector requirement is a selector that contains values, a key, and an operator that + relates the key and values. + properties: + key: + description: key is the label + key that the selector applies + to. + type: string + operator: + description: |- + operator represents a key's relationship to a set of values. + Valid operators are In, NotIn, Exists and DoesNotExist. + type: string + values: + description: |- + values is an array of string values. If the operator is In or NotIn, + the values array must be non-empty. If the operator is Exists or DoesNotExist, + the values array must be empty. This array is replaced during a strategic + merge patch. + items: + type: string + type: array + x-kubernetes-list-type: atomic + required: + - key + - operator + type: object + type: array + x-kubernetes-list-type: atomic + matchLabels: + additionalProperties: + type: string + description: |- + matchLabels is a map of {key,value} pairs. A single {key,value} in the matchLabels + map is equivalent to an element of matchExpressions, whose key field is "key", the + operator is "In", and the values array contains only "value". The requirements are ANDed. + type: object + type: object + x-kubernetes-map-type: atomic + matchLabelKeys: + description: |- + MatchLabelKeys is a set of pod label keys to select which pods will + be taken into consideration. The keys are used to lookup values from the + incoming pod labels, those key-value labels are merged with `labelSelector` as `key in (value)` + to select the group of existing pods which pods will be taken into consideration + for the incoming pod's pod (anti) affinity. Keys that don't exist in the incoming + pod labels will be ignored. The default value is empty. + The same key is forbidden to exist in both matchLabelKeys and labelSelector. + Also, matchLabelKeys cannot be set when labelSelector isn't set. + items: + type: string + type: array + x-kubernetes-list-type: atomic + mismatchLabelKeys: + description: |- + MismatchLabelKeys is a set of pod label keys to select which pods will + be taken into consideration. The keys are used to lookup values from the + incoming pod labels, those key-value labels are merged with `labelSelector` as `key notin (value)` + to select the group of existing pods which pods will be taken into consideration + for the incoming pod's pod (anti) affinity. Keys that don't exist in the incoming + pod labels will be ignored. The default value is empty. + The same key is forbidden to exist in both mismatchLabelKeys and labelSelector. + Also, mismatchLabelKeys cannot be set when labelSelector isn't set. + items: + type: string + type: array + x-kubernetes-list-type: atomic + namespaceSelector: + description: |- + A label query over the set of namespaces that the term applies to. + The term is applied to the union of the namespaces selected by this field + and the ones listed in the namespaces field. + null selector and null or empty namespaces list means "this pod's namespace". + An empty selector ({}) matches all namespaces. + properties: + matchExpressions: + description: matchExpressions is a list + of label selector requirements. The + requirements are ANDed. + items: + description: |- + A label selector requirement is a selector that contains values, a key, and an operator that + relates the key and values. + properties: + key: + description: key is the label + key that the selector applies + to. + type: string + operator: + description: |- + operator represents a key's relationship to a set of values. + Valid operators are In, NotIn, Exists and DoesNotExist. + type: string + values: + description: |- + values is an array of string values. If the operator is In or NotIn, + the values array must be non-empty. If the operator is Exists or DoesNotExist, + the values array must be empty. This array is replaced during a strategic + merge patch. + items: + type: string + type: array + x-kubernetes-list-type: atomic + required: + - key + - operator + type: object + type: array + x-kubernetes-list-type: atomic + matchLabels: + additionalProperties: + type: string + description: |- + matchLabels is a map of {key,value} pairs. A single {key,value} in the matchLabels + map is equivalent to an element of matchExpressions, whose key field is "key", the + operator is "In", and the values array contains only "value". The requirements are ANDed. + type: object + type: object + x-kubernetes-map-type: atomic + namespaces: + description: |- + namespaces specifies a static list of namespace names that the term applies to. + The term is applied to the union of the namespaces listed in this field + and the ones selected by namespaceSelector. + null or empty namespaces list and null namespaceSelector means "this pod's namespace". + items: + type: string + type: array + x-kubernetes-list-type: atomic + topologyKey: + description: |- + This pod should be co-located (affinity) or not co-located (anti-affinity) with the pods matching + the labelSelector in the specified namespaces, where co-located is defined as running on a node + whose value of the label with key topologyKey matches that of any node on which any of the + selected pods is running. + Empty topologyKey is not allowed. + type: string + required: + - topologyKey + type: object + weight: + description: |- + weight associated with matching the corresponding podAffinityTerm, + in the range 1-100. + format: int32 + type: integer + required: + - podAffinityTerm + - weight + type: object + type: array + x-kubernetes-list-type: atomic + requiredDuringSchedulingIgnoredDuringExecution: + description: |- + If the anti-affinity requirements specified by this field are not met at + scheduling time, the pod will not be scheduled onto the node. + If the anti-affinity requirements specified by this field cease to be met + at some point during pod execution (e.g. due to a pod label update), the + system may or may not try to eventually evict the pod from its node. + When there are multiple elements, the lists of nodes corresponding to each + podAffinityTerm are intersected, i.e. all terms must be satisfied. + items: + description: |- + Defines a set of pods (namely those matching the labelSelector + relative to the given namespace(s)) that this pod should be + co-located (affinity) or not co-located (anti-affinity) with, + where co-located is defined as running on a node whose value of + the label with key matches that of any node on which + a pod of the set of pods is running + properties: + labelSelector: + description: |- + A label query over a set of resources, in this case pods. + If it's null, this PodAffinityTerm matches with no Pods. + properties: + matchExpressions: + description: matchExpressions is a list + of label selector requirements. The requirements + are ANDed. + items: + description: |- + A label selector requirement is a selector that contains values, a key, and an operator that + relates the key and values. + properties: + key: + description: key is the label key + that the selector applies to. + type: string + operator: + description: |- + operator represents a key's relationship to a set of values. + Valid operators are In, NotIn, Exists and DoesNotExist. + type: string + values: + description: |- + values is an array of string values. If the operator is In or NotIn, + the values array must be non-empty. If the operator is Exists or DoesNotExist, + the values array must be empty. This array is replaced during a strategic + merge patch. + items: + type: string + type: array + x-kubernetes-list-type: atomic + required: + - key + - operator + type: object + type: array + x-kubernetes-list-type: atomic + matchLabels: + additionalProperties: + type: string + description: |- + matchLabels is a map of {key,value} pairs. A single {key,value} in the matchLabels + map is equivalent to an element of matchExpressions, whose key field is "key", the + operator is "In", and the values array contains only "value". The requirements are ANDed. + type: object + type: object + x-kubernetes-map-type: atomic + matchLabelKeys: + description: |- + MatchLabelKeys is a set of pod label keys to select which pods will + be taken into consideration. The keys are used to lookup values from the + incoming pod labels, those key-value labels are merged with `labelSelector` as `key in (value)` + to select the group of existing pods which pods will be taken into consideration + for the incoming pod's pod (anti) affinity. Keys that don't exist in the incoming + pod labels will be ignored. The default value is empty. + The same key is forbidden to exist in both matchLabelKeys and labelSelector. + Also, matchLabelKeys cannot be set when labelSelector isn't set. + items: + type: string + type: array + x-kubernetes-list-type: atomic + mismatchLabelKeys: + description: |- + MismatchLabelKeys is a set of pod label keys to select which pods will + be taken into consideration. The keys are used to lookup values from the + incoming pod labels, those key-value labels are merged with `labelSelector` as `key notin (value)` + to select the group of existing pods which pods will be taken into consideration + for the incoming pod's pod (anti) affinity. Keys that don't exist in the incoming + pod labels will be ignored. The default value is empty. + The same key is forbidden to exist in both mismatchLabelKeys and labelSelector. + Also, mismatchLabelKeys cannot be set when labelSelector isn't set. + items: + type: string + type: array + x-kubernetes-list-type: atomic + namespaceSelector: + description: |- + A label query over the set of namespaces that the term applies to. + The term is applied to the union of the namespaces selected by this field + and the ones listed in the namespaces field. + null selector and null or empty namespaces list means "this pod's namespace". + An empty selector ({}) matches all namespaces. + properties: + matchExpressions: + description: matchExpressions is a list + of label selector requirements. The requirements + are ANDed. + items: + description: |- + A label selector requirement is a selector that contains values, a key, and an operator that + relates the key and values. + properties: + key: + description: key is the label key + that the selector applies to. + type: string + operator: + description: |- + operator represents a key's relationship to a set of values. + Valid operators are In, NotIn, Exists and DoesNotExist. + type: string + values: + description: |- + values is an array of string values. If the operator is In or NotIn, + the values array must be non-empty. If the operator is Exists or DoesNotExist, + the values array must be empty. This array is replaced during a strategic + merge patch. + items: + type: string + type: array + x-kubernetes-list-type: atomic + required: + - key + - operator + type: object + type: array + x-kubernetes-list-type: atomic + matchLabels: + additionalProperties: + type: string + description: |- + matchLabels is a map of {key,value} pairs. A single {key,value} in the matchLabels + map is equivalent to an element of matchExpressions, whose key field is "key", the + operator is "In", and the values array contains only "value". The requirements are ANDed. + type: object + type: object + x-kubernetes-map-type: atomic + namespaces: + description: |- + namespaces specifies a static list of namespace names that the term applies to. + The term is applied to the union of the namespaces listed in this field + and the ones selected by namespaceSelector. + null or empty namespaces list and null namespaceSelector means "this pod's namespace". + items: + type: string + type: array + x-kubernetes-list-type: atomic + topologyKey: + description: |- + This pod should be co-located (affinity) or not co-located (anti-affinity) with the pods matching + the labelSelector in the specified namespaces, where co-located is defined as running on a node + whose value of the label with key topologyKey matches that of any node on which any of the + selected pods is running. + Empty topologyKey is not allowed. + type: string + required: + - topologyKey + type: object + type: array + x-kubernetes-list-type: atomic + type: object + type: object + nodeSelector: + additionalProperties: + type: string + description: |- + nodeSelector is the node selector applied to the relevant kind of pods + It specifies a map of key-value pairs: for the pod to be eligible to run on a node, + the node must have each of the indicated key-value pairs as labels + (it can have additional labels as well). + See https://kubernetes.io/docs/concepts/configuration/assign-pod-node/#nodeselector + type: object + tolerations: + description: |- + tolerations is a list of tolerations applied to the relevant kind of pods + See https://kubernetes.io/docs/concepts/configuration/taint-and-toleration/ for more info. + These are additional tolerations other than default ones. + items: + description: |- + The pod this Toleration is attached to tolerates any taint that matches + the triple using the matching operator . + properties: + effect: + description: |- + Effect indicates the taint effect to match. Empty means match all taint effects. + When specified, allowed values are NoSchedule, PreferNoSchedule and NoExecute. + type: string + key: + description: |- + Key is the taint key that the toleration applies to. Empty means match all taint keys. + If the key is empty, operator must be Exists; this combination means to match all values and all keys. + type: string + operator: + description: |- + Operator represents a key's relationship to the value. + Valid operators are Exists and Equal. Defaults to Equal. + Exists is equivalent to wildcard for value, so that a pod can + tolerate all taints of a particular category. + type: string + tolerationSeconds: + description: |- + TolerationSeconds represents the period of time the toleration (which must be + of effect NoExecute, otherwise this field is ignored) tolerates the taint. By default, + it is not set, which means tolerate the taint forever (do not evict). Zero and + negative values will be treated as 0 (evict immediately) by the system. + format: int64 + type: integer + value: + description: |- + Value is the taint value the toleration matches to. + If the operator is Exists, the value should be empty, otherwise just a regular string. + type: string + type: object + type: array + type: object + type: object + instancetypeConfig: + description: InstancetypeConfig holds the configuration of instance + type related functionality within KubeVirt. + properties: + referencePolicy: + description: |- + ReferencePolicy defines how an instance type or preference should be referenced by the VM after submission, supported values are: + reference (default) - Where a copy of the original object is stashed in a ControllerRevision and referenced by the VM. + expand - Where the instance type or preference are expanded into the VM if no revisionNames have been populated. + expandAll - Where the instance type or preference are expanded into the VM regardless of revisionNames previously being populated. + enum: + - reference + - expand + - expandAll + nullable: true + type: string + type: object + ksmConfiguration: + description: |- + KSMConfiguration holds the information regarding + the enabling the KSM in the nodes (if available). + properties: + nodeLabelSelector: + description: |- + NodeLabelSelector is a selector that filters in which nodes the KSM will be enabled. + Empty NodeLabelSelector will enable ksm for every node. + properties: + matchExpressions: + description: matchExpressions is a list of label selector + requirements. The requirements are ANDed. + items: + description: |- + A label selector requirement is a selector that contains values, a key, and an operator that + relates the key and values. + properties: + key: + description: key is the label key that the selector + applies to. + type: string + operator: + description: |- + operator represents a key's relationship to a set of values. + Valid operators are In, NotIn, Exists and DoesNotExist. + type: string + values: + description: |- + values is an array of string values. If the operator is In or NotIn, + the values array must be non-empty. If the operator is Exists or DoesNotExist, + the values array must be empty. This array is replaced during a strategic + merge patch. + items: + type: string + type: array + x-kubernetes-list-type: atomic + required: + - key + - operator + type: object + type: array + x-kubernetes-list-type: atomic + matchLabels: + additionalProperties: + type: string + description: |- + matchLabels is a map of {key,value} pairs. A single {key,value} in the matchLabels + map is equivalent to an element of matchExpressions, whose key field is "key", the + operator is "In", and the values array contains only "value". The requirements are ANDed. + type: object + type: object + x-kubernetes-map-type: atomic + type: object + kubeMacPoolConfiguration: + description: KubeMacPoolConfiguration holds kubemacpool MAC address + range configuration. + properties: + rangeEnd: + description: |- + RangeEnd defines the last MAC address in the kubemacpool range. + The MAC address format should be AA:BB:CC:DD:EE:FF. + pattern: ^([0-9a-fA-F]{2}:){5}[0-9a-fA-F]{2}$ + type: string + rangeStart: + description: |- + RangeStart defines the first MAC address in the kubemacpool range. + The MAC address format should be AA:BB:CC:DD:EE:FF. + pattern: ^([0-9a-fA-F]{2}:){5}[0-9a-fA-F]{2}$ + type: string + type: object + x-kubernetes-validations: + - message: both rangeStart and rangeEnd must be configured together, + or both omitted + rule: (has(self.rangeStart) && has(self.rangeEnd)) || (!has(self.rangeStart) + && !has(self.rangeEnd)) + kubeSecondaryDNSNameServerIP: + description: KubeSecondaryDNSNameServerIP defines name server IP used + by KubeSecondaryDNS + type: string + liveMigrationConfig: + default: + allowAutoConverge: false + allowPostCopy: false + completionTimeoutPerGiB: 150 + parallelMigrationsPerCluster: 5 + parallelOutboundMigrationsPerNode: 2 + progressTimeout: 150 + description: |- + Live migration limits and timeouts are applied so that migration processes do not + overwhelm the cluster. + properties: + allowAutoConverge: + default: false + description: |- + AllowAutoConverge allows the platform to compromise performance/availability of VMIs to + guarantee successful VMI live migrations. Defaults to false + type: boolean + allowPostCopy: + default: false + description: |- + When enabled, KubeVirt attempts to use post-copy live-migration in case it + reaches its completion timeout while attempting pre-copy live-migration. + Post-copy migrations allow even the busiest VMs to successfully live-migrate. + However, events like a network failure or a failure in any of the source or + destination nodes can cause the migrated VM to crash or reach inconsistency. + Enable this option when evicting nodes is more important than keeping VMs + alive. + Defaults to false. + type: boolean + bandwidthPerMigration: + description: Bandwidth limit of each migration, the value is quantity + of bytes per second (e.g. 2048Mi = 2048MiB/sec) + pattern: ^(\+|-)?(([0-9]+(\.[0-9]*)?)|(\.[0-9]+))(([KMGTPE]i)|[numkMGTPE]|([eE](\+|-)?(([0-9]+(\.[0-9]*)?)|(\.[0-9]+))))?$ + type: string + completionTimeoutPerGiB: + default: 150 + description: |- + If a migrating VM is big and busy, while the connection to the destination node + is slow, migration may never converge. The completion timeout is calculated + based on completionTimeoutPerGiB times the size of the guest (both RAM and + migrated disks, if any). For example, with completionTimeoutPerGiB set to 800, + a virtual machine instance with 6GiB memory will timeout if it has not + completed migration in 1h20m. Use a lower completionTimeoutPerGiB to induce + quicker failure, so that another destination or post-copy is attempted. Use a + higher completionTimeoutPerGiB to let workload with spikes in its memory dirty + rate to converge. + The format is a number. + format: int64 + type: integer + network: + description: The migrations will be performed over a dedicated + multus network to minimize disruption to tenant workloads due + to network saturation when VM live migrations are triggered. + type: string + parallelMigrationsPerCluster: + default: 5 + description: Number of migrations running in parallel in the cluster. + format: int32 + type: integer + parallelOutboundMigrationsPerNode: + default: 2 + description: Maximum number of outbound migrations per node. + format: int32 + type: integer + progressTimeout: + default: 150 + description: The migration will be canceled if memory copy fails + to make progress in this time, in seconds. + format: int64 + type: integer + type: object + liveUpdateConfiguration: + description: |- + LiveUpdateConfiguration holds the cluster configuration for live update of virtual machines - max cpu sockets, + max guest memory and max hotplug ratio. This setting can affect VM CPU and memory settings. + properties: + maxCpuSockets: + description: |- + MaxCpuSockets provides a MaxSockets value for VMs that do not provide their own. + For VMs with more sockets than maximum the MaxSockets will be set to equal number of sockets. + format: int32 + type: integer + maxGuest: + anyOf: + - type: integer + - type: string + description: |- + MaxGuest defines the maximum amount memory that can be allocated + to the guest using hotplug. + pattern: ^(\+|-)?(([0-9]+(\.[0-9]*)?)|(\.[0-9]+))(([KMGTPE]i)|[numkMGTPE]|([eE](\+|-)?(([0-9]+(\.[0-9]*)?)|(\.[0-9]+))))?$ + x-kubernetes-int-or-string: true + maxHotplugRatio: + description: |- + MaxHotplugRatio is the ratio used to define the max amount + of a hotplug resource that can be made available to a VM + when the specific Max* setting is not defined (MaxCpuSockets, MaxGuest) + Example: VM is configured with 512Mi of guest memory, if MaxGuest is not + defined and MaxHotplugRatio is 2 then MaxGuest = 1Gi + defaults to 4 + format: int32 + type: integer + type: object + logVerbosityConfig: + description: |- + LogVerbosityConfig configures the verbosity level of Kubevirt's different components. The higher + the value - the higher the log verbosity. + properties: + cdi: + description: CDI indicates the log verbosity level that controls + the amount of information logged for CDI components. + format: int32 + type: integer + kubevirt: + description: |- + Kubevirt is a struct that allows specifying the log verbosity level that controls the amount of information + logged for each Kubevirt component. + properties: + nodeVerbosity: + additionalProperties: + type: integer + description: NodeVerbosity represents a map of nodes with + a specific verbosity level + type: object + virtAPI: + type: integer + virtController: + type: integer + virtHandler: + type: integer + virtLauncher: + type: integer + virtOperator: + type: integer + virtSynchronizationController: + type: integer + type: object + type: object + mediatedDevicesConfiguration: + description: MediatedDevicesConfiguration holds information about + MDEV types to be defined on nodes, if available + properties: + mediatedDeviceTypes: + items: + type: string + type: array + x-kubernetes-list-type: atomic + nodeMediatedDeviceTypes: + items: + description: NodeMediatedDeviceTypesConfig holds information + about MDEV types to be defined in a specific node that matches + the NodeSelector field. + properties: + mediatedDeviceTypes: + items: + type: string + type: array + x-kubernetes-list-type: atomic + nodeSelector: + additionalProperties: + type: string + description: |- + NodeSelector is a selector which must be true for the vmi to fit on a node. + Selector which must match a node's labels for the vmi to be scheduled on that node. + More info: https://kubernetes.io/docs/concepts/configuration/assign-pod-node/ + type: object + required: + - nodeSelector + type: object + type: array + x-kubernetes-list-type: atomic + type: object + networkBinding: + additionalProperties: + properties: + computeResourceOverhead: + description: |- + ComputeResourceOverhead specifies the resource overhead that should be added to the compute container when using the binding. + version: v1alphav1 + properties: + limits: + additionalProperties: + anyOf: + - type: integer + - type: string + pattern: ^(\+|-)?(([0-9]+(\.[0-9]*)?)|(\.[0-9]+))(([KMGTPE]i)|[numkMGTPE]|([eE](\+|-)?(([0-9]+(\.[0-9]*)?)|(\.[0-9]+))))?$ + x-kubernetes-int-or-string: true + description: |- + Limits describes the maximum amount of compute resources allowed. + More info: https://kubernetes.io/docs/concepts/configuration/manage-resources-containers/ + type: object + requests: + additionalProperties: + anyOf: + - type: integer + - type: string + pattern: ^(\+|-)?(([0-9]+(\.[0-9]*)?)|(\.[0-9]+))(([KMGTPE]i)|[numkMGTPE]|([eE](\+|-)?(([0-9]+(\.[0-9]*)?)|(\.[0-9]+))))?$ + x-kubernetes-int-or-string: true + description: |- + Requests describes the minimum amount of compute resources required. + If Requests is omitted for a container, it defaults to Limits if that is explicitly specified, + otherwise to an implementation-defined value. Requests cannot exceed Limits. + More info: https://kubernetes.io/docs/concepts/configuration/manage-resources-containers/ + type: object + type: object + domainAttachmentType: + description: |- + DomainAttachmentType is a standard domain network attachment method kubevirt supports. + Supported values: "tap", "managedTap" (since v1.4). + The standard domain attachment can be used instead or in addition to the sidecarImage. + version: 1alphav1 + type: string + downwardAPI: + description: |- + DownwardAPI specifies what kind of data should be exposed to the binding plugin sidecar. + Supported values: "device-info" + version: v1alphav1 + type: string + migration: + description: |- + Migration means the VM using the plugin can be safely migrated + version: 1alphav1 + properties: + method: + description: |- + Method defines a pre-defined migration methodology + version: 1alphav1 + type: string + type: object + networkAttachmentDefinition: + description: |- + NetworkAttachmentDefinition references to a NetworkAttachmentDefinition CR object. + Format: , /. + If namespace is not specified, VMI namespace is assumed. + version: 1alphav1 + type: string + sidecarImage: + description: |- + SidecarImage references a container image that runs in the virt-launcher pod. + The sidecar handles (libvirt) domain configuration and optional services. + version: 1alphav1 + type: string + type: object + description: |- + NetworkBinding defines the network binding plugins. + Those bindings can be used when defining virtual machine interfaces. + type: object + obsoleteCPUs: + description: ObsoleteCPUs allows avoiding scheduling of VMs for obsolete + CPU models + properties: + cpuModels: + description: |- + CPUModels is a list of obsolete CPU models. When the node-labeller obtains the list of obsolete CPU models, it + eliminates those CPU models and creates labels for valid CPU models. + The default values for this field is nil, however, HCO uses opinionated values, and adding values to this list + will add them to the opinionated values. + items: + type: string + type: array + x-kubernetes-list-type: set + type: object + permittedHostDevices: + description: PermittedHostDevices holds information about devices + allowed for passthrough + properties: + mediatedDevices: + items: + description: MediatedHostDevice represents a host mediated device + allowed for passthrough + properties: + disabled: + description: |- + HCO enforces the existence of several MediatedHostDevice objects. Set disabled field to true instead of remove + these objects. + type: boolean + externalResourceProvider: + description: indicates that this resource is being provided + by an external device plugin + type: boolean + mdevNameSelector: + description: name of a mediated device type required to + identify a mediated device on a host + type: string + resourceName: + description: name by which a device is advertised and being + requested + type: string + required: + - mdevNameSelector + - resourceName + type: object + type: array + x-kubernetes-list-map-keys: + - mdevNameSelector + x-kubernetes-list-type: map + pciHostDevices: + items: + description: PciHostDevice represents a host PCI device allowed + for passthrough + properties: + disabled: + description: |- + HCO enforces the existence of several PciHostDevice objects. Set disabled field to true instead of remove + these objects. + type: boolean + externalResourceProvider: + description: indicates that this resource is being provided + by an external device plugin + type: boolean + pciDeviceSelector: + description: a combination of a vendor_id:product_id required + to identify a PCI device on a host. + type: string + resourceName: + description: name by which a device is advertised and being + requested + type: string + required: + - pciDeviceSelector + - resourceName + type: object + type: array + x-kubernetes-list-map-keys: + - pciDeviceSelector + x-kubernetes-list-type: map + usbHostDevices: + items: + description: USBHostDevice represents a host USB device allowed + for passthrough + properties: + disabled: + description: |- + HCO enforces the existence of several USBHostDevice objects. Set disabled field to true instead of remove + these objects. + type: boolean + externalResourceProvider: + description: |- + If true, KubeVirt will leave the allocation and monitoring to an + external device plugin + type: boolean + resourceName: + description: |- + Identifies the list of USB host devices. + e.g: kubevirt.io/storage, kubevirt.io/bootable-usb, etc + type: string + selectors: + items: + description: USBSelector represents a selector for a USB + device allowed for passthrough + properties: + product: + type: string + vendor: + type: string + required: + - product + - vendor + type: object + type: array + x-kubernetes-list-type: atomic + required: + - resourceName + type: object + type: array + x-kubernetes-list-map-keys: + - resourceName + x-kubernetes-list-type: map + type: object + resourceRequirements: + default: + vmiCPUAllocationRatio: 10 + description: ResourceRequirements describes the resource requirements + for the operand workloads. + properties: + autoCPULimitNamespaceLabelSelector: + description: |- + When set, AutoCPULimitNamespaceLabelSelector will set a CPU limit on virt-launcher for VMIs running inside + namespaces that match the label selector. + The CPU limit will equal the number of requested vCPUs. + This setting does not apply to VMIs with dedicated CPUs. + properties: + matchExpressions: + description: matchExpressions is a list of label selector + requirements. The requirements are ANDed. + items: + description: |- + A label selector requirement is a selector that contains values, a key, and an operator that + relates the key and values. + properties: + key: + description: key is the label key that the selector + applies to. + type: string + operator: + description: |- + operator represents a key's relationship to a set of values. + Valid operators are In, NotIn, Exists and DoesNotExist. + type: string + values: + description: |- + values is an array of string values. If the operator is In or NotIn, + the values array must be non-empty. If the operator is Exists or DoesNotExist, + the values array must be empty. This array is replaced during a strategic + merge patch. + items: + type: string + type: array + x-kubernetes-list-type: atomic + required: + - key + - operator + type: object + type: array + x-kubernetes-list-type: atomic + matchLabels: + additionalProperties: + type: string + description: |- + matchLabels is a map of {key,value} pairs. A single {key,value} in the matchLabels + map is equivalent to an element of matchExpressions, whose key field is "key", the + operator is "In", and the values array contains only "value". The requirements are ANDed. + type: object + type: object + x-kubernetes-map-type: atomic + storageWorkloads: + description: |- + StorageWorkloads defines the resources requirements for storage workloads. It will propagate to the CDI custom + resource + properties: + claims: + description: |- + Claims lists the names of resources, defined in spec.resourceClaims, + that are used by this container. + + This field depends on the + DynamicResourceAllocation feature gate. + + This field is immutable. It can only be set for containers. + items: + description: ResourceClaim references one entry in PodSpec.ResourceClaims. + properties: + name: + description: |- + Name must match the name of one entry in pod.spec.resourceClaims of + the Pod where this field is used. It makes that resource available + inside a container. + type: string + request: + description: |- + Request is the name chosen for a request in the referenced claim. + If empty, everything from the claim is made available, otherwise + only the result of this request. + type: string + required: + - name + type: object + type: array + x-kubernetes-list-map-keys: + - name + x-kubernetes-list-type: map + limits: + additionalProperties: + anyOf: + - type: integer + - type: string + pattern: ^(\+|-)?(([0-9]+(\.[0-9]*)?)|(\.[0-9]+))(([KMGTPE]i)|[numkMGTPE]|([eE](\+|-)?(([0-9]+(\.[0-9]*)?)|(\.[0-9]+))))?$ + x-kubernetes-int-or-string: true + description: |- + Limits describes the maximum amount of compute resources allowed. + More info: https://kubernetes.io/docs/concepts/configuration/manage-resources-containers/ + type: object + requests: + additionalProperties: + anyOf: + - type: integer + - type: string + pattern: ^(\+|-)?(([0-9]+(\.[0-9]*)?)|(\.[0-9]+))(([KMGTPE]i)|[numkMGTPE]|([eE](\+|-)?(([0-9]+(\.[0-9]*)?)|(\.[0-9]+))))?$ + x-kubernetes-int-or-string: true + description: |- + Requests describes the minimum amount of compute resources required. + If Requests is omitted for a container, it defaults to Limits if that is explicitly specified, + otherwise to an implementation-defined value. Requests cannot exceed Limits. + More info: https://kubernetes.io/docs/concepts/configuration/manage-resources-containers/ + type: object + type: object + vmiCPUAllocationRatio: + default: 10 + description: |- + VmiCPUAllocationRatio defines, for each requested virtual CPU, + how much physical CPU to request per VMI from the + hosting node. The value is in fraction of a CPU thread (or + core on non-hyperthreaded nodes). + VMI POD CPU request = number of vCPUs * 1/vmiCPUAllocationRatio + For example, a value of 1 means 1 physical CPU thread per VMI CPU thread. + A value of 100 would be 1% of a physical thread allocated for each + requested VMI thread. + This option has no effect on VMIs that request dedicated CPUs. + Defaults to 10 + minimum: 1 + type: integer + type: object + x-kubernetes-validations: + - message: vmiCPUAllocationRatio must be greater than 0 + rule: '!has(self.vmiCPUAllocationRatio) || self.vmiCPUAllocationRatio + > 0' + scratchSpaceStorageClass: + description: |- + Override the storage class used for scratch space during transfer operations. The scratch space storage class + is determined in the following order: + value of scratchSpaceStorageClass, if that doesn't exist, use the default storage class, if there is no default + storage class, use the storage class of the DataVolume, if no storage class specified, use no storage class for + scratch space + type: string + storageImport: + description: StorageImport contains configuration for importing containerized + data + properties: + insecureRegistries: + description: |- + InsecureRegistries is a list of image registries URLs that are not secured. Setting an insecure registry URL + in this list allows pulling images from this registry. + items: + type: string + type: array + x-kubernetes-list-type: set + type: object + tlsSecurityProfile: + description: |- + TLSSecurityProfile specifies the settings for TLS connections to be propagated to all kubevirt-hyperconverged components. + If unset, the hyperconverged cluster operator will consume the value set on the APIServer CR on OCP/OKD or Intermediate if on vanilla k8s. + Note that only Old, Intermediate and Custom profiles are currently supported, and the maximum available + MinTLSVersions is VersionTLS12. + properties: + custom: + description: |- + custom is a user-defined TLS security profile. Be extremely careful using a custom + profile as invalid configurations can be catastrophic. An example custom profile + looks like this: + + ciphers: + + - ECDHE-ECDSA-CHACHA20-POLY1305 + + - ECDHE-RSA-CHACHA20-POLY1305 + + - ECDHE-RSA-AES128-GCM-SHA256 + + - ECDHE-ECDSA-AES128-GCM-SHA256 + + minTLSVersion: VersionTLS11 + nullable: true + properties: + ciphers: + description: |- + ciphers is used to specify the cipher algorithms that are negotiated + during the TLS handshake. Operators may remove entries their operands + do not support. For example, to use DES-CBC3-SHA (yaml): + + ciphers: + - DES-CBC3-SHA + items: + type: string + type: array + x-kubernetes-list-type: atomic + minTLSVersion: + description: |- + minTLSVersion is used to specify the minimal version of the TLS protocol + that is negotiated during the TLS handshake. For example, to use TLS + versions 1.1, 1.2 and 1.3 (yaml): + + minTLSVersion: VersionTLS11 + + NOTE: currently the highest minTLSVersion allowed is VersionTLS12 + enum: + - VersionTLS10 + - VersionTLS11 + - VersionTLS12 + - VersionTLS13 + type: string + type: object + intermediate: + description: |- + intermediate is a TLS security profile based on: + + https://wiki.mozilla.org/Security/Server_Side_TLS#Intermediate_compatibility_.28recommended.29 + + and looks like this (yaml): + + ciphers: + + - TLS_AES_128_GCM_SHA256 + + - TLS_AES_256_GCM_SHA384 + + - TLS_CHACHA20_POLY1305_SHA256 + + - ECDHE-ECDSA-AES128-GCM-SHA256 + + - ECDHE-RSA-AES128-GCM-SHA256 + + - ECDHE-ECDSA-AES256-GCM-SHA384 + + - ECDHE-RSA-AES256-GCM-SHA384 + + - ECDHE-ECDSA-CHACHA20-POLY1305 + + - ECDHE-RSA-CHACHA20-POLY1305 + + - DHE-RSA-AES128-GCM-SHA256 + + - DHE-RSA-AES256-GCM-SHA384 + + minTLSVersion: VersionTLS12 + nullable: true + type: object + modern: + description: |- + modern is a TLS security profile based on: + + https://wiki.mozilla.org/Security/Server_Side_TLS#Modern_compatibility + + and looks like this (yaml): + + ciphers: + + - TLS_AES_128_GCM_SHA256 + + - TLS_AES_256_GCM_SHA384 + + - TLS_CHACHA20_POLY1305_SHA256 + + minTLSVersion: VersionTLS13 + nullable: true + type: object + old: + description: |- + old is a TLS security profile based on: + + https://wiki.mozilla.org/Security/Server_Side_TLS#Old_backward_compatibility + + and looks like this (yaml): + + ciphers: + + - TLS_AES_128_GCM_SHA256 + + - TLS_AES_256_GCM_SHA384 + + - TLS_CHACHA20_POLY1305_SHA256 + + - ECDHE-ECDSA-AES128-GCM-SHA256 + + - ECDHE-RSA-AES128-GCM-SHA256 + + - ECDHE-ECDSA-AES256-GCM-SHA384 + + - ECDHE-RSA-AES256-GCM-SHA384 + + - ECDHE-ECDSA-CHACHA20-POLY1305 + + - ECDHE-RSA-CHACHA20-POLY1305 + + - DHE-RSA-AES128-GCM-SHA256 + + - DHE-RSA-AES256-GCM-SHA384 + + - DHE-RSA-CHACHA20-POLY1305 + + - ECDHE-ECDSA-AES128-SHA256 + + - ECDHE-RSA-AES128-SHA256 + + - ECDHE-ECDSA-AES128-SHA + + - ECDHE-RSA-AES128-SHA + + - ECDHE-ECDSA-AES256-SHA384 + + - ECDHE-RSA-AES256-SHA384 + + - ECDHE-ECDSA-AES256-SHA + + - ECDHE-RSA-AES256-SHA + + - DHE-RSA-AES128-SHA256 + + - DHE-RSA-AES256-SHA256 + + - AES128-GCM-SHA256 + + - AES256-GCM-SHA384 + + - AES128-SHA256 + + - AES256-SHA256 + + - AES128-SHA + + - AES256-SHA + + - DES-CBC3-SHA + + minTLSVersion: VersionTLS10 + nullable: true + type: object + type: + description: |- + type is one of Old, Intermediate, Modern or Custom. Custom provides + the ability to specify individual TLS security profile parameters. + Old, Intermediate and Modern are TLS security profiles based on: + + https://wiki.mozilla.org/Security/Server_Side_TLS#Recommended_configurations + + The profiles are intent based, so they may change over time as new ciphers are developed and existing ciphers + are found to be insecure. Depending on precisely which ciphers are available to a process, the list may be + reduced. + + Note that the Modern profile is currently not supported because it is not + yet well adopted by common software libraries. + enum: + - Old + - Intermediate + - Modern + - Custom + type: string + type: object + tuningPolicy: + description: |- + TuningPolicy allows to configure the mode in which the RateLimits of kubevirt are set. + If TuningPolicy is not present the default kubevirt values are used. + It can be set to `annotation` for fine-tuning the kubevirt queryPerSeconds (qps) and burst values. + Qps and burst values are taken from the annotation hco.kubevirt.io/tuningPolicy + enum: + - annotation + - highBurst + type: string + uninstallStrategy: + default: BlockUninstallIfWorkloadsExist + description: |- + UninstallStrategy defines how to proceed on uninstall when workloads (VirtualMachines, DataVolumes) still exist. + BlockUninstallIfWorkloadsExist will prevent the CR from being removed when workloads still exist. + BlockUninstallIfWorkloadsExist is the safest choice to protect your workloads from accidental data loss, so it's strongly advised. + RemoveWorkloads will cause all the workloads to be cascading deleted on uninstallation. + WARNING: please notice that RemoveWorkloads will cause your workloads to be deleted as soon as this CR will be, even accidentally, deleted. + Please correctly consider the implications of this option before setting it. + BlockUninstallIfWorkloadsExist is the default behaviour. + enum: + - RemoveWorkloads + - BlockUninstallIfWorkloadsExist + type: string + virtualMachineOptions: + default: + disableFreePageReporting: false + disableSerialConsoleLog: false + description: VirtualMachineOptions holds the cluster level information + regarding the virtual machine. + properties: + disableFreePageReporting: + default: false + description: |- + DisableFreePageReporting disable the free page reporting of + memory balloon device https://libvirt.org/formatdomain.html#memory-balloon-device. + This will have effect only if AutoattachMemBalloon is not false and the vmi is not + requesting any high performance feature (dedicatedCPU/realtime/hugePages), in which free page reporting is always disabled. + type: boolean + disableSerialConsoleLog: + default: false + description: |- + DisableSerialConsoleLog disables logging the auto-attached default serial console. + If not set, serial console logs will be written to a file and then streamed from a container named `guest-console-log`. + The value can be individually overridden for each VM, not relevant if AutoattachSerialConsole is disabled for the VM. + type: boolean + type: object + vmStateStorageClass: + description: VMStateStorageClass is the name of the storage class + to use for the PVCs created to preserve VM state, like TPM. + type: string + workloadUpdateStrategy: + default: + batchEvictionInterval: 1m0s + batchEvictionSize: 10 + workloadUpdateMethods: + - LiveMigrate + description: WorkloadUpdateStrategy defines at the cluster level how + to handle automated workload updates + properties: + batchEvictionInterval: + default: 1m0s + description: |- + BatchEvictionInterval Represents the interval to wait before issuing the next + batch of shutdowns + type: string + batchEvictionSize: + default: 10 + description: |- + BatchEvictionSize Represents the number of VMIs that can be forced updated per + the BatchShutdownInterval interval + type: integer + workloadUpdateMethods: + default: + - LiveMigrate + description: |- + WorkloadUpdateMethods defines the methods that can be used to disrupt workloads + during automated workload updates. + When multiple methods are present, the least disruptive method takes + precedence over more disruptive methods. For example if both LiveMigrate and Evict + methods are listed, only VMs which are not live migratable will be restarted/shutdown. + An empty list defaults to no automated workload updating. + items: + type: string + type: array + x-kubernetes-list-type: atomic + required: + - workloadUpdateMethods + type: object + workloads: + description: |- + workloads HyperConvergedConfig influences the pod configuration (currently only placement) of components + which need to be running on a node where virtualization workloads should be able to run. + Changes to Workloads HyperConvergedConfig can be applied only without existing workload. + properties: + nodePlacement: + description: NodePlacement describes node scheduling configuration. + properties: + affinity: + description: |- + affinity enables pod affinity/anti-affinity placement expanding the types of constraints + that can be expressed with nodeSelector. + affinity is going to be applied to the relevant kind of pods in parallel with nodeSelector + See https://kubernetes.io/docs/concepts/scheduling-eviction/assign-pod-node/#affinity-and-anti-affinity + properties: + nodeAffinity: + description: Describes node affinity scheduling rules + for the pod. + properties: + preferredDuringSchedulingIgnoredDuringExecution: + description: |- + The scheduler will prefer to schedule pods to nodes that satisfy + the affinity expressions specified by this field, but it may choose + a node that violates one or more of the expressions. The node that is + most preferred is the one with the greatest sum of weights, i.e. + for each node that meets all of the scheduling requirements (resource + request, requiredDuringScheduling affinity expressions, etc.), + compute a sum by iterating through the elements of this field and adding + "weight" to the sum if the node matches the corresponding matchExpressions; the + node(s) with the highest sum are the most preferred. + items: + description: |- + An empty preferred scheduling term matches all objects with implicit weight 0 + (i.e. it's a no-op). A null preferred scheduling term matches no objects (i.e. is also a no-op). + properties: + preference: + description: A node selector term, associated + with the corresponding weight. + properties: + matchExpressions: + description: A list of node selector requirements + by node's labels. + items: + description: |- + A node selector requirement is a selector that contains values, a key, and an operator + that relates the key and values. + properties: + key: + description: The label key that the + selector applies to. + type: string + operator: + description: |- + Represents a key's relationship to a set of values. + Valid operators are In, NotIn, Exists, DoesNotExist. Gt, and Lt. + type: string + values: + description: |- + An array of string values. If the operator is In or NotIn, + the values array must be non-empty. If the operator is Exists or DoesNotExist, + the values array must be empty. If the operator is Gt or Lt, the values + array must have a single element, which will be interpreted as an integer. + This array is replaced during a strategic merge patch. + items: + type: string + type: array + x-kubernetes-list-type: atomic + required: + - key + - operator + type: object + type: array + x-kubernetes-list-type: atomic + matchFields: + description: A list of node selector requirements + by node's fields. + items: + description: |- + A node selector requirement is a selector that contains values, a key, and an operator + that relates the key and values. + properties: + key: + description: The label key that the + selector applies to. + type: string + operator: + description: |- + Represents a key's relationship to a set of values. + Valid operators are In, NotIn, Exists, DoesNotExist. Gt, and Lt. + type: string + values: + description: |- + An array of string values. If the operator is In or NotIn, + the values array must be non-empty. If the operator is Exists or DoesNotExist, + the values array must be empty. If the operator is Gt or Lt, the values + array must have a single element, which will be interpreted as an integer. + This array is replaced during a strategic merge patch. + items: + type: string + type: array + x-kubernetes-list-type: atomic + required: + - key + - operator + type: object + type: array + x-kubernetes-list-type: atomic + type: object + x-kubernetes-map-type: atomic + weight: + description: Weight associated with matching + the corresponding nodeSelectorTerm, in the + range 1-100. + format: int32 + type: integer + required: + - preference + - weight + type: object + type: array + x-kubernetes-list-type: atomic + requiredDuringSchedulingIgnoredDuringExecution: + description: |- + If the affinity requirements specified by this field are not met at + scheduling time, the pod will not be scheduled onto the node. + If the affinity requirements specified by this field cease to be met + at some point during pod execution (e.g. due to an update), the system + may or may not try to eventually evict the pod from its node. + properties: + nodeSelectorTerms: + description: Required. A list of node selector + terms. The terms are ORed. + items: + description: |- + A null or empty node selector term matches no objects. The requirements of + them are ANDed. + The TopologySelectorTerm type implements a subset of the NodeSelectorTerm. + properties: + matchExpressions: + description: A list of node selector requirements + by node's labels. + items: + description: |- + A node selector requirement is a selector that contains values, a key, and an operator + that relates the key and values. + properties: + key: + description: The label key that the + selector applies to. + type: string + operator: + description: |- + Represents a key's relationship to a set of values. + Valid operators are In, NotIn, Exists, DoesNotExist. Gt, and Lt. + type: string + values: + description: |- + An array of string values. If the operator is In or NotIn, + the values array must be non-empty. If the operator is Exists or DoesNotExist, + the values array must be empty. If the operator is Gt or Lt, the values + array must have a single element, which will be interpreted as an integer. + This array is replaced during a strategic merge patch. + items: + type: string + type: array + x-kubernetes-list-type: atomic + required: + - key + - operator + type: object + type: array + x-kubernetes-list-type: atomic + matchFields: + description: A list of node selector requirements + by node's fields. + items: + description: |- + A node selector requirement is a selector that contains values, a key, and an operator + that relates the key and values. + properties: + key: + description: The label key that the + selector applies to. + type: string + operator: + description: |- + Represents a key's relationship to a set of values. + Valid operators are In, NotIn, Exists, DoesNotExist. Gt, and Lt. + type: string + values: + description: |- + An array of string values. If the operator is In or NotIn, + the values array must be non-empty. If the operator is Exists or DoesNotExist, + the values array must be empty. If the operator is Gt or Lt, the values + array must have a single element, which will be interpreted as an integer. + This array is replaced during a strategic merge patch. + items: + type: string + type: array + x-kubernetes-list-type: atomic + required: + - key + - operator + type: object + type: array + x-kubernetes-list-type: atomic + type: object + x-kubernetes-map-type: atomic + type: array + x-kubernetes-list-type: atomic + required: + - nodeSelectorTerms + type: object + x-kubernetes-map-type: atomic + type: object + podAffinity: + description: Describes pod affinity scheduling rules (e.g. + co-locate this pod in the same node, zone, etc. as some + other pod(s)). + properties: + preferredDuringSchedulingIgnoredDuringExecution: + description: |- + The scheduler will prefer to schedule pods to nodes that satisfy + the affinity expressions specified by this field, but it may choose + a node that violates one or more of the expressions. The node that is + most preferred is the one with the greatest sum of weights, i.e. + for each node that meets all of the scheduling requirements (resource + request, requiredDuringScheduling affinity expressions, etc.), + compute a sum by iterating through the elements of this field and adding + "weight" to the sum if the node has pods which matches the corresponding podAffinityTerm; the + node(s) with the highest sum are the most preferred. + items: + description: The weights of all of the matched WeightedPodAffinityTerm + fields are added per-node to find the most preferred + node(s) + properties: + podAffinityTerm: + description: Required. A pod affinity term, + associated with the corresponding weight. + properties: + labelSelector: + description: |- + A label query over a set of resources, in this case pods. + If it's null, this PodAffinityTerm matches with no Pods. + properties: + matchExpressions: + description: matchExpressions is a list + of label selector requirements. The + requirements are ANDed. + items: + description: |- + A label selector requirement is a selector that contains values, a key, and an operator that + relates the key and values. + properties: + key: + description: key is the label + key that the selector applies + to. + type: string + operator: + description: |- + operator represents a key's relationship to a set of values. + Valid operators are In, NotIn, Exists and DoesNotExist. + type: string + values: + description: |- + values is an array of string values. If the operator is In or NotIn, + the values array must be non-empty. If the operator is Exists or DoesNotExist, + the values array must be empty. This array is replaced during a strategic + merge patch. + items: + type: string + type: array + x-kubernetes-list-type: atomic + required: + - key + - operator + type: object + type: array + x-kubernetes-list-type: atomic + matchLabels: + additionalProperties: + type: string + description: |- + matchLabels is a map of {key,value} pairs. A single {key,value} in the matchLabels + map is equivalent to an element of matchExpressions, whose key field is "key", the + operator is "In", and the values array contains only "value". The requirements are ANDed. + type: object + type: object + x-kubernetes-map-type: atomic + matchLabelKeys: + description: |- + MatchLabelKeys is a set of pod label keys to select which pods will + be taken into consideration. The keys are used to lookup values from the + incoming pod labels, those key-value labels are merged with `labelSelector` as `key in (value)` + to select the group of existing pods which pods will be taken into consideration + for the incoming pod's pod (anti) affinity. Keys that don't exist in the incoming + pod labels will be ignored. The default value is empty. + The same key is forbidden to exist in both matchLabelKeys and labelSelector. + Also, matchLabelKeys cannot be set when labelSelector isn't set. + items: + type: string + type: array + x-kubernetes-list-type: atomic + mismatchLabelKeys: + description: |- + MismatchLabelKeys is a set of pod label keys to select which pods will + be taken into consideration. The keys are used to lookup values from the + incoming pod labels, those key-value labels are merged with `labelSelector` as `key notin (value)` + to select the group of existing pods which pods will be taken into consideration + for the incoming pod's pod (anti) affinity. Keys that don't exist in the incoming + pod labels will be ignored. The default value is empty. + The same key is forbidden to exist in both mismatchLabelKeys and labelSelector. + Also, mismatchLabelKeys cannot be set when labelSelector isn't set. + items: + type: string + type: array + x-kubernetes-list-type: atomic + namespaceSelector: + description: |- + A label query over the set of namespaces that the term applies to. + The term is applied to the union of the namespaces selected by this field + and the ones listed in the namespaces field. + null selector and null or empty namespaces list means "this pod's namespace". + An empty selector ({}) matches all namespaces. + properties: + matchExpressions: + description: matchExpressions is a list + of label selector requirements. The + requirements are ANDed. + items: + description: |- + A label selector requirement is a selector that contains values, a key, and an operator that + relates the key and values. + properties: + key: + description: key is the label + key that the selector applies + to. + type: string + operator: + description: |- + operator represents a key's relationship to a set of values. + Valid operators are In, NotIn, Exists and DoesNotExist. + type: string + values: + description: |- + values is an array of string values. If the operator is In or NotIn, + the values array must be non-empty. If the operator is Exists or DoesNotExist, + the values array must be empty. This array is replaced during a strategic + merge patch. + items: + type: string + type: array + x-kubernetes-list-type: atomic + required: + - key + - operator + type: object + type: array + x-kubernetes-list-type: atomic + matchLabels: + additionalProperties: + type: string + description: |- + matchLabels is a map of {key,value} pairs. A single {key,value} in the matchLabels + map is equivalent to an element of matchExpressions, whose key field is "key", the + operator is "In", and the values array contains only "value". The requirements are ANDed. + type: object + type: object + x-kubernetes-map-type: atomic + namespaces: + description: |- + namespaces specifies a static list of namespace names that the term applies to. + The term is applied to the union of the namespaces listed in this field + and the ones selected by namespaceSelector. + null or empty namespaces list and null namespaceSelector means "this pod's namespace". + items: + type: string + type: array + x-kubernetes-list-type: atomic + topologyKey: + description: |- + This pod should be co-located (affinity) or not co-located (anti-affinity) with the pods matching + the labelSelector in the specified namespaces, where co-located is defined as running on a node + whose value of the label with key topologyKey matches that of any node on which any of the + selected pods is running. + Empty topologyKey is not allowed. + type: string + required: + - topologyKey + type: object + weight: + description: |- + weight associated with matching the corresponding podAffinityTerm, + in the range 1-100. + format: int32 + type: integer + required: + - podAffinityTerm + - weight + type: object + type: array + x-kubernetes-list-type: atomic + requiredDuringSchedulingIgnoredDuringExecution: + description: |- + If the affinity requirements specified by this field are not met at + scheduling time, the pod will not be scheduled onto the node. + If the affinity requirements specified by this field cease to be met + at some point during pod execution (e.g. due to a pod label update), the + system may or may not try to eventually evict the pod from its node. + When there are multiple elements, the lists of nodes corresponding to each + podAffinityTerm are intersected, i.e. all terms must be satisfied. + items: + description: |- + Defines a set of pods (namely those matching the labelSelector + relative to the given namespace(s)) that this pod should be + co-located (affinity) or not co-located (anti-affinity) with, + where co-located is defined as running on a node whose value of + the label with key matches that of any node on which + a pod of the set of pods is running + properties: + labelSelector: + description: |- + A label query over a set of resources, in this case pods. + If it's null, this PodAffinityTerm matches with no Pods. + properties: + matchExpressions: + description: matchExpressions is a list + of label selector requirements. The requirements + are ANDed. + items: + description: |- + A label selector requirement is a selector that contains values, a key, and an operator that + relates the key and values. + properties: + key: + description: key is the label key + that the selector applies to. + type: string + operator: + description: |- + operator represents a key's relationship to a set of values. + Valid operators are In, NotIn, Exists and DoesNotExist. + type: string + values: + description: |- + values is an array of string values. If the operator is In or NotIn, + the values array must be non-empty. If the operator is Exists or DoesNotExist, + the values array must be empty. This array is replaced during a strategic + merge patch. + items: + type: string + type: array + x-kubernetes-list-type: atomic + required: + - key + - operator + type: object + type: array + x-kubernetes-list-type: atomic + matchLabels: + additionalProperties: + type: string + description: |- + matchLabels is a map of {key,value} pairs. A single {key,value} in the matchLabels + map is equivalent to an element of matchExpressions, whose key field is "key", the + operator is "In", and the values array contains only "value". The requirements are ANDed. + type: object + type: object + x-kubernetes-map-type: atomic + matchLabelKeys: + description: |- + MatchLabelKeys is a set of pod label keys to select which pods will + be taken into consideration. The keys are used to lookup values from the + incoming pod labels, those key-value labels are merged with `labelSelector` as `key in (value)` + to select the group of existing pods which pods will be taken into consideration + for the incoming pod's pod (anti) affinity. Keys that don't exist in the incoming + pod labels will be ignored. The default value is empty. + The same key is forbidden to exist in both matchLabelKeys and labelSelector. + Also, matchLabelKeys cannot be set when labelSelector isn't set. + items: + type: string + type: array + x-kubernetes-list-type: atomic + mismatchLabelKeys: + description: |- + MismatchLabelKeys is a set of pod label keys to select which pods will + be taken into consideration. The keys are used to lookup values from the + incoming pod labels, those key-value labels are merged with `labelSelector` as `key notin (value)` + to select the group of existing pods which pods will be taken into consideration + for the incoming pod's pod (anti) affinity. Keys that don't exist in the incoming + pod labels will be ignored. The default value is empty. + The same key is forbidden to exist in both mismatchLabelKeys and labelSelector. + Also, mismatchLabelKeys cannot be set when labelSelector isn't set. + items: + type: string + type: array + x-kubernetes-list-type: atomic + namespaceSelector: + description: |- + A label query over the set of namespaces that the term applies to. + The term is applied to the union of the namespaces selected by this field + and the ones listed in the namespaces field. + null selector and null or empty namespaces list means "this pod's namespace". + An empty selector ({}) matches all namespaces. + properties: + matchExpressions: + description: matchExpressions is a list + of label selector requirements. The requirements + are ANDed. + items: + description: |- + A label selector requirement is a selector that contains values, a key, and an operator that + relates the key and values. + properties: + key: + description: key is the label key + that the selector applies to. + type: string + operator: + description: |- + operator represents a key's relationship to a set of values. + Valid operators are In, NotIn, Exists and DoesNotExist. + type: string + values: + description: |- + values is an array of string values. If the operator is In or NotIn, + the values array must be non-empty. If the operator is Exists or DoesNotExist, + the values array must be empty. This array is replaced during a strategic + merge patch. + items: + type: string + type: array + x-kubernetes-list-type: atomic + required: + - key + - operator + type: object + type: array + x-kubernetes-list-type: atomic + matchLabels: + additionalProperties: + type: string + description: |- + matchLabels is a map of {key,value} pairs. A single {key,value} in the matchLabels + map is equivalent to an element of matchExpressions, whose key field is "key", the + operator is "In", and the values array contains only "value". The requirements are ANDed. + type: object + type: object + x-kubernetes-map-type: atomic + namespaces: + description: |- + namespaces specifies a static list of namespace names that the term applies to. + The term is applied to the union of the namespaces listed in this field + and the ones selected by namespaceSelector. + null or empty namespaces list and null namespaceSelector means "this pod's namespace". + items: + type: string + type: array + x-kubernetes-list-type: atomic + topologyKey: + description: |- + This pod should be co-located (affinity) or not co-located (anti-affinity) with the pods matching + the labelSelector in the specified namespaces, where co-located is defined as running on a node + whose value of the label with key topologyKey matches that of any node on which any of the + selected pods is running. + Empty topologyKey is not allowed. + type: string + required: + - topologyKey + type: object + type: array + x-kubernetes-list-type: atomic + type: object + podAntiAffinity: + description: Describes pod anti-affinity scheduling rules + (e.g. avoid putting this pod in the same node, zone, + etc. as some other pod(s)). + properties: + preferredDuringSchedulingIgnoredDuringExecution: + description: |- + The scheduler will prefer to schedule pods to nodes that satisfy + the anti-affinity expressions specified by this field, but it may choose + a node that violates one or more of the expressions. The node that is + most preferred is the one with the greatest sum of weights, i.e. + for each node that meets all of the scheduling requirements (resource + request, requiredDuringScheduling anti-affinity expressions, etc.), + compute a sum by iterating through the elements of this field and subtracting + "weight" from the sum if the node has pods which matches the corresponding podAffinityTerm; the + node(s) with the highest sum are the most preferred. + items: + description: The weights of all of the matched WeightedPodAffinityTerm + fields are added per-node to find the most preferred + node(s) + properties: + podAffinityTerm: + description: Required. A pod affinity term, + associated with the corresponding weight. + properties: + labelSelector: + description: |- + A label query over a set of resources, in this case pods. + If it's null, this PodAffinityTerm matches with no Pods. + properties: + matchExpressions: + description: matchExpressions is a list + of label selector requirements. The + requirements are ANDed. + items: + description: |- + A label selector requirement is a selector that contains values, a key, and an operator that + relates the key and values. + properties: + key: + description: key is the label + key that the selector applies + to. + type: string + operator: + description: |- + operator represents a key's relationship to a set of values. + Valid operators are In, NotIn, Exists and DoesNotExist. + type: string + values: + description: |- + values is an array of string values. If the operator is In or NotIn, + the values array must be non-empty. If the operator is Exists or DoesNotExist, + the values array must be empty. This array is replaced during a strategic + merge patch. + items: + type: string + type: array + x-kubernetes-list-type: atomic + required: + - key + - operator + type: object + type: array + x-kubernetes-list-type: atomic + matchLabels: + additionalProperties: + type: string + description: |- + matchLabels is a map of {key,value} pairs. A single {key,value} in the matchLabels + map is equivalent to an element of matchExpressions, whose key field is "key", the + operator is "In", and the values array contains only "value". The requirements are ANDed. + type: object + type: object + x-kubernetes-map-type: atomic + matchLabelKeys: + description: |- + MatchLabelKeys is a set of pod label keys to select which pods will + be taken into consideration. The keys are used to lookup values from the + incoming pod labels, those key-value labels are merged with `labelSelector` as `key in (value)` + to select the group of existing pods which pods will be taken into consideration + for the incoming pod's pod (anti) affinity. Keys that don't exist in the incoming + pod labels will be ignored. The default value is empty. + The same key is forbidden to exist in both matchLabelKeys and labelSelector. + Also, matchLabelKeys cannot be set when labelSelector isn't set. + items: + type: string + type: array + x-kubernetes-list-type: atomic + mismatchLabelKeys: + description: |- + MismatchLabelKeys is a set of pod label keys to select which pods will + be taken into consideration. The keys are used to lookup values from the + incoming pod labels, those key-value labels are merged with `labelSelector` as `key notin (value)` + to select the group of existing pods which pods will be taken into consideration + for the incoming pod's pod (anti) affinity. Keys that don't exist in the incoming + pod labels will be ignored. The default value is empty. + The same key is forbidden to exist in both mismatchLabelKeys and labelSelector. + Also, mismatchLabelKeys cannot be set when labelSelector isn't set. + items: + type: string + type: array + x-kubernetes-list-type: atomic + namespaceSelector: + description: |- + A label query over the set of namespaces that the term applies to. + The term is applied to the union of the namespaces selected by this field + and the ones listed in the namespaces field. + null selector and null or empty namespaces list means "this pod's namespace". + An empty selector ({}) matches all namespaces. + properties: + matchExpressions: + description: matchExpressions is a list + of label selector requirements. The + requirements are ANDed. + items: + description: |- + A label selector requirement is a selector that contains values, a key, and an operator that + relates the key and values. + properties: + key: + description: key is the label + key that the selector applies + to. + type: string + operator: + description: |- + operator represents a key's relationship to a set of values. + Valid operators are In, NotIn, Exists and DoesNotExist. + type: string + values: + description: |- + values is an array of string values. If the operator is In or NotIn, + the values array must be non-empty. If the operator is Exists or DoesNotExist, + the values array must be empty. This array is replaced during a strategic + merge patch. + items: + type: string + type: array + x-kubernetes-list-type: atomic + required: + - key + - operator + type: object + type: array + x-kubernetes-list-type: atomic + matchLabels: + additionalProperties: + type: string + description: |- + matchLabels is a map of {key,value} pairs. A single {key,value} in the matchLabels + map is equivalent to an element of matchExpressions, whose key field is "key", the + operator is "In", and the values array contains only "value". The requirements are ANDed. + type: object + type: object + x-kubernetes-map-type: atomic + namespaces: + description: |- + namespaces specifies a static list of namespace names that the term applies to. + The term is applied to the union of the namespaces listed in this field + and the ones selected by namespaceSelector. + null or empty namespaces list and null namespaceSelector means "this pod's namespace". + items: + type: string + type: array + x-kubernetes-list-type: atomic + topologyKey: + description: |- + This pod should be co-located (affinity) or not co-located (anti-affinity) with the pods matching + the labelSelector in the specified namespaces, where co-located is defined as running on a node + whose value of the label with key topologyKey matches that of any node on which any of the + selected pods is running. + Empty topologyKey is not allowed. + type: string + required: + - topologyKey + type: object + weight: + description: |- + weight associated with matching the corresponding podAffinityTerm, + in the range 1-100. + format: int32 + type: integer + required: + - podAffinityTerm + - weight + type: object + type: array + x-kubernetes-list-type: atomic + requiredDuringSchedulingIgnoredDuringExecution: + description: |- + If the anti-affinity requirements specified by this field are not met at + scheduling time, the pod will not be scheduled onto the node. + If the anti-affinity requirements specified by this field cease to be met + at some point during pod execution (e.g. due to a pod label update), the + system may or may not try to eventually evict the pod from its node. + When there are multiple elements, the lists of nodes corresponding to each + podAffinityTerm are intersected, i.e. all terms must be satisfied. + items: + description: |- + Defines a set of pods (namely those matching the labelSelector + relative to the given namespace(s)) that this pod should be + co-located (affinity) or not co-located (anti-affinity) with, + where co-located is defined as running on a node whose value of + the label with key matches that of any node on which + a pod of the set of pods is running + properties: + labelSelector: + description: |- + A label query over a set of resources, in this case pods. + If it's null, this PodAffinityTerm matches with no Pods. + properties: + matchExpressions: + description: matchExpressions is a list + of label selector requirements. The requirements + are ANDed. + items: + description: |- + A label selector requirement is a selector that contains values, a key, and an operator that + relates the key and values. + properties: + key: + description: key is the label key + that the selector applies to. + type: string + operator: + description: |- + operator represents a key's relationship to a set of values. + Valid operators are In, NotIn, Exists and DoesNotExist. + type: string + values: + description: |- + values is an array of string values. If the operator is In or NotIn, + the values array must be non-empty. If the operator is Exists or DoesNotExist, + the values array must be empty. This array is replaced during a strategic + merge patch. + items: + type: string + type: array + x-kubernetes-list-type: atomic + required: + - key + - operator + type: object + type: array + x-kubernetes-list-type: atomic + matchLabels: + additionalProperties: + type: string + description: |- + matchLabels is a map of {key,value} pairs. A single {key,value} in the matchLabels + map is equivalent to an element of matchExpressions, whose key field is "key", the + operator is "In", and the values array contains only "value". The requirements are ANDed. + type: object + type: object + x-kubernetes-map-type: atomic + matchLabelKeys: + description: |- + MatchLabelKeys is a set of pod label keys to select which pods will + be taken into consideration. The keys are used to lookup values from the + incoming pod labels, those key-value labels are merged with `labelSelector` as `key in (value)` + to select the group of existing pods which pods will be taken into consideration + for the incoming pod's pod (anti) affinity. Keys that don't exist in the incoming + pod labels will be ignored. The default value is empty. + The same key is forbidden to exist in both matchLabelKeys and labelSelector. + Also, matchLabelKeys cannot be set when labelSelector isn't set. + items: + type: string + type: array + x-kubernetes-list-type: atomic + mismatchLabelKeys: + description: |- + MismatchLabelKeys is a set of pod label keys to select which pods will + be taken into consideration. The keys are used to lookup values from the + incoming pod labels, those key-value labels are merged with `labelSelector` as `key notin (value)` + to select the group of existing pods which pods will be taken into consideration + for the incoming pod's pod (anti) affinity. Keys that don't exist in the incoming + pod labels will be ignored. The default value is empty. + The same key is forbidden to exist in both mismatchLabelKeys and labelSelector. + Also, mismatchLabelKeys cannot be set when labelSelector isn't set. + items: + type: string + type: array + x-kubernetes-list-type: atomic + namespaceSelector: + description: |- + A label query over the set of namespaces that the term applies to. + The term is applied to the union of the namespaces selected by this field + and the ones listed in the namespaces field. + null selector and null or empty namespaces list means "this pod's namespace". + An empty selector ({}) matches all namespaces. + properties: + matchExpressions: + description: matchExpressions is a list + of label selector requirements. The requirements + are ANDed. + items: + description: |- + A label selector requirement is a selector that contains values, a key, and an operator that + relates the key and values. + properties: + key: + description: key is the label key + that the selector applies to. + type: string + operator: + description: |- + operator represents a key's relationship to a set of values. + Valid operators are In, NotIn, Exists and DoesNotExist. + type: string + values: + description: |- + values is an array of string values. If the operator is In or NotIn, + the values array must be non-empty. If the operator is Exists or DoesNotExist, + the values array must be empty. This array is replaced during a strategic + merge patch. + items: + type: string + type: array + x-kubernetes-list-type: atomic + required: + - key + - operator + type: object + type: array + x-kubernetes-list-type: atomic + matchLabels: + additionalProperties: + type: string + description: |- + matchLabels is a map of {key,value} pairs. A single {key,value} in the matchLabels + map is equivalent to an element of matchExpressions, whose key field is "key", the + operator is "In", and the values array contains only "value". The requirements are ANDed. + type: object + type: object + x-kubernetes-map-type: atomic + namespaces: + description: |- + namespaces specifies a static list of namespace names that the term applies to. + The term is applied to the union of the namespaces listed in this field + and the ones selected by namespaceSelector. + null or empty namespaces list and null namespaceSelector means "this pod's namespace". + items: + type: string + type: array + x-kubernetes-list-type: atomic + topologyKey: + description: |- + This pod should be co-located (affinity) or not co-located (anti-affinity) with the pods matching + the labelSelector in the specified namespaces, where co-located is defined as running on a node + whose value of the label with key topologyKey matches that of any node on which any of the + selected pods is running. + Empty topologyKey is not allowed. + type: string + required: + - topologyKey + type: object + type: array + x-kubernetes-list-type: atomic + type: object + type: object + nodeSelector: + additionalProperties: + type: string + description: |- + nodeSelector is the node selector applied to the relevant kind of pods + It specifies a map of key-value pairs: for the pod to be eligible to run on a node, + the node must have each of the indicated key-value pairs as labels + (it can have additional labels as well). + See https://kubernetes.io/docs/concepts/configuration/assign-pod-node/#nodeselector + type: object + tolerations: + description: |- + tolerations is a list of tolerations applied to the relevant kind of pods + See https://kubernetes.io/docs/concepts/configuration/taint-and-toleration/ for more info. + These are additional tolerations other than default ones. + items: + description: |- + The pod this Toleration is attached to tolerates any taint that matches + the triple using the matching operator . + properties: + effect: + description: |- + Effect indicates the taint effect to match. Empty means match all taint effects. + When specified, allowed values are NoSchedule, PreferNoSchedule and NoExecute. + type: string + key: + description: |- + Key is the taint key that the toleration applies to. Empty means match all taint keys. + If the key is empty, operator must be Exists; this combination means to match all values and all keys. + type: string + operator: + description: |- + Operator represents a key's relationship to the value. + Valid operators are Exists and Equal. Defaults to Equal. + Exists is equivalent to wildcard for value, so that a pod can + tolerate all taints of a particular category. + type: string + tolerationSeconds: + description: |- + TolerationSeconds represents the period of time the toleration (which must be + of effect NoExecute, otherwise this field is ignored) tolerates the taint. By default, + it is not set, which means tolerate the taint forever (do not evict). Zero and + negative values will be treated as 0 (evict immediately) by the system. + format: int64 + type: integer + value: + description: |- + Value is the taint value the toleration matches to. + If the operator is Exists, the value should be empty, otherwise just a regular string. + type: string + type: object + type: array + type: object + type: object + type: object + status: + description: HyperConvergedStatus defines the observed state of HyperConverged + properties: + conditions: + description: Conditions describes the state of the HyperConverged + resource. + items: + description: Condition contains details for one aspect of the current + state of this API Resource. + properties: + lastTransitionTime: + description: |- + lastTransitionTime is the last time the condition transitioned from one status to another. + This should be when the underlying condition changed. If that is not known, then using the time when the API field changed is acceptable. + format: date-time + type: string + message: + description: |- + message is a human readable message indicating details about the transition. + This may be an empty string. + maxLength: 32768 + type: string + observedGeneration: + description: |- + observedGeneration represents the .metadata.generation that the condition was set based upon. + For instance, if .metadata.generation is currently 12, but the .status.conditions[x].observedGeneration is 9, the condition is out of date + with respect to the current state of the instance. + format: int64 + minimum: 0 + type: integer + reason: + description: |- + reason contains a programmatic identifier indicating the reason for the condition's last transition. + Producers of specific condition types may define expected values and meanings for this field, + and whether the values are considered a guaranteed API. + The value should be a CamelCase string. + This field may not be empty. + maxLength: 1024 + minLength: 1 + pattern: ^[A-Za-z]([A-Za-z0-9_,:]*[A-Za-z0-9_])?$ + type: string + status: + description: status of the condition, one of True, False, Unknown. + enum: + - "True" + - "False" + - Unknown + type: string + type: + description: type of condition in CamelCase or in foo.example.com/CamelCase. + maxLength: 316 + pattern: ^([a-z0-9]([-a-z0-9]*[a-z0-9])?(\.[a-z0-9]([-a-z0-9]*[a-z0-9])?)*/)?(([A-Za-z0-9][-A-Za-z0-9_.]*)?[A-Za-z0-9])$ + type: string + required: + - lastTransitionTime + - message + - reason + - status + - type + type: object + type: array + x-kubernetes-list-type: atomic + dataImportCronTemplates: + description: |- + DataImportCronTemplates is a list of the actual DataImportCronTemplates as HCO update in the SSP CR. The list + contains both the common and the custom templates, including any modification done by HCO. + items: + description: DataImportCronTemplateStatus is a copy of a dataImportCronTemplate + as defined in the spec, or in the HCO image. + properties: + metadata: + properties: + annotations: + additionalProperties: + type: string + type: object + finalizers: + items: + type: string + type: array + labels: + additionalProperties: + type: string + type: object + name: + type: string + namespace: + type: string + type: object + spec: + description: DataImportCronSpec defines specification for DataImportCron + properties: + garbageCollect: + description: |- + GarbageCollect specifies whether old PVCs should be cleaned up after a new PVC is imported. + Options are currently "Outdated" and "Never", defaults to "Outdated". + type: string + importsToKeep: + description: Number of import PVCs to keep when garbage + collecting. Default is 3. + format: int32 + type: integer + managedDataSource: + description: |- + ManagedDataSource specifies the name of the corresponding DataSource this cron will manage. + DataSource has to be in the same namespace. + type: string + retentionPolicy: + description: RetentionPolicy specifies whether the created + DataVolumes and DataSources are retained when their DataImportCron + is deleted. Default is RatainAll. + type: string + schedule: + description: Schedule specifies in cron format when and + how often to look for new imports + type: string + serviceAccountName: + description: ServiceAccountName is the name of the ServiceAccount + for creating DataVolumes. + minLength: 1 + type: string + template: + description: Template specifies template for the DVs to + be created + properties: + apiVersion: + description: |- + APIVersion defines the versioned schema of this representation of an object. + Servers should convert recognized schemas to the latest internal value, and + may reject unrecognized values. + More info: https://git.k8s.io/community/contributors/devel/sig-architecture/api-conventions.md#resources + type: string + kind: + description: |- + Kind is a string value representing the REST resource this object represents. + Servers may infer this from the endpoint the client submits requests to. + Cannot be updated. + In CamelCase. + More info: https://git.k8s.io/community/contributors/devel/sig-architecture/api-conventions.md#types-kinds + type: string + metadata: + properties: + annotations: + additionalProperties: + type: string + type: object + finalizers: + items: + type: string + type: array + labels: + additionalProperties: + type: string + type: object + name: + type: string + namespace: + type: string + type: object + spec: + description: DataVolumeSpec defines the DataVolume type + specification + properties: + checkpoints: + description: Checkpoints is a list of DataVolumeCheckpoints, + representing stages in a multistage import. + items: + description: DataVolumeCheckpoint defines a stage + in a warm migration. + properties: + current: + description: Current is the identifier of + the snapshot created for this checkpoint. + type: string + previous: + description: Previous is the identifier of + the snapshot from the previous checkpoint. + type: string + required: + - current + - previous + type: object + type: array + contentType: + description: 'DataVolumeContentType options: "kubevirt", + "archive"' + enum: + - kubevirt + - archive + type: string + finalCheckpoint: + description: FinalCheckpoint indicates whether the + current DataVolumeCheckpoint is the final checkpoint. + type: boolean + preallocation: + description: Preallocation controls whether storage + for DataVolumes should be allocated in advance. + type: boolean + priorityClassName: + description: PriorityClassName for Importer, Cloner + and Uploader pod + type: string + pvc: + description: PVC is the PVC specification + properties: + accessModes: + description: |- + accessModes contains the desired access modes the volume should have. + More info: https://kubernetes.io/docs/concepts/storage/persistent-volumes#access-modes-1 + items: + type: string + type: array + x-kubernetes-list-type: atomic + dataSource: + description: |- + dataSource field can be used to specify either: + * An existing VolumeSnapshot object (snapshot.storage.k8s.io/VolumeSnapshot) + * An existing PVC (PersistentVolumeClaim) + If the provisioner or an external controller can support the specified data source, + it will create a new volume based on the contents of the specified data source. + When the AnyVolumeDataSource feature gate is enabled, dataSource contents will be copied to dataSourceRef, + and dataSourceRef contents will be copied to dataSource when dataSourceRef.namespace is not specified. + If the namespace is specified, then dataSourceRef will not be copied to dataSource. + properties: + apiGroup: + description: |- + APIGroup is the group for the resource being referenced. + If APIGroup is not specified, the specified Kind must be in the core API group. + For any other third-party types, APIGroup is required. + type: string + kind: + description: Kind is the type of resource + being referenced + type: string + name: + description: Name is the name of resource + being referenced + type: string + required: + - kind + - name + type: object + x-kubernetes-map-type: atomic + dataSourceRef: + description: |- + dataSourceRef specifies the object from which to populate the volume with data, if a non-empty + volume is desired. This may be any object from a non-empty API group (non + core object) or a PersistentVolumeClaim object. + When this field is specified, volume binding will only succeed if the type of + the specified object matches some installed volume populator or dynamic + provisioner. + This field will replace the functionality of the dataSource field and as such + if both fields are non-empty, they must have the same value. For backwards + compatibility, when namespace isn't specified in dataSourceRef, + both fields (dataSource and dataSourceRef) will be set to the same + value automatically if one of them is empty and the other is non-empty. + When namespace is specified in dataSourceRef, + dataSource isn't set to the same value and must be empty. + There are three important differences between dataSource and dataSourceRef: + * While dataSource only allows two specific types of objects, dataSourceRef + allows any non-core object, as well as PersistentVolumeClaim objects. + * While dataSource ignores disallowed values (dropping them), dataSourceRef + preserves all values, and generates an error if a disallowed value is + specified. + * While dataSource only allows local objects, dataSourceRef allows objects + in any namespaces. + (Beta) Using this field requires the AnyVolumeDataSource feature gate to be enabled. + (Alpha) Using the namespace field of dataSourceRef requires the CrossNamespaceVolumeDataSource feature gate to be enabled. + properties: + apiGroup: + description: |- + APIGroup is the group for the resource being referenced. + If APIGroup is not specified, the specified Kind must be in the core API group. + For any other third-party types, APIGroup is required. + type: string + kind: + description: Kind is the type of resource + being referenced + type: string + name: + description: Name is the name of resource + being referenced + type: string + namespace: + description: |- + Namespace is the namespace of resource being referenced + Note that when a namespace is specified, a gateway.networking.k8s.io/ReferenceGrant object is required in the referent namespace to allow that namespace's owner to accept the reference. See the ReferenceGrant documentation for details. + (Alpha) This field requires the CrossNamespaceVolumeDataSource feature gate to be enabled. + type: string + required: + - kind + - name + type: object + resources: + description: |- + resources represents the minimum resources the volume should have. + If RecoverVolumeExpansionFailure feature is enabled users are allowed to specify resource requirements + that are lower than previous value but must still be higher than capacity recorded in the + status field of the claim. + More info: https://kubernetes.io/docs/concepts/storage/persistent-volumes#resources + properties: + limits: + additionalProperties: + anyOf: + - type: integer + - type: string + pattern: ^(\+|-)?(([0-9]+(\.[0-9]*)?)|(\.[0-9]+))(([KMGTPE]i)|[numkMGTPE]|([eE](\+|-)?(([0-9]+(\.[0-9]*)?)|(\.[0-9]+))))?$ + x-kubernetes-int-or-string: true + description: |- + Limits describes the maximum amount of compute resources allowed. + More info: https://kubernetes.io/docs/concepts/configuration/manage-resources-containers/ + type: object + requests: + additionalProperties: + anyOf: + - type: integer + - type: string + pattern: ^(\+|-)?(([0-9]+(\.[0-9]*)?)|(\.[0-9]+))(([KMGTPE]i)|[numkMGTPE]|([eE](\+|-)?(([0-9]+(\.[0-9]*)?)|(\.[0-9]+))))?$ + x-kubernetes-int-or-string: true + description: |- + Requests describes the minimum amount of compute resources required. + If Requests is omitted for a container, it defaults to Limits if that is explicitly specified, + otherwise to an implementation-defined value. Requests cannot exceed Limits. + More info: https://kubernetes.io/docs/concepts/configuration/manage-resources-containers/ + type: object + type: object + selector: + description: selector is a label query over + volumes to consider for binding. + properties: + matchExpressions: + description: matchExpressions is a list + of label selector requirements. The requirements + are ANDed. + items: + description: |- + A label selector requirement is a selector that contains values, a key, and an operator that + relates the key and values. + properties: + key: + description: key is the label key + that the selector applies to. + type: string + operator: + description: |- + operator represents a key's relationship to a set of values. + Valid operators are In, NotIn, Exists and DoesNotExist. + type: string + values: + description: |- + values is an array of string values. If the operator is In or NotIn, + the values array must be non-empty. If the operator is Exists or DoesNotExist, + the values array must be empty. This array is replaced during a strategic + merge patch. + items: + type: string + type: array + x-kubernetes-list-type: atomic + required: + - key + - operator + type: object + type: array + x-kubernetes-list-type: atomic + matchLabels: + additionalProperties: + type: string + description: |- + matchLabels is a map of {key,value} pairs. A single {key,value} in the matchLabels + map is equivalent to an element of matchExpressions, whose key field is "key", the + operator is "In", and the values array contains only "value". The requirements are ANDed. + type: object + type: object + x-kubernetes-map-type: atomic + storageClassName: + description: |- + storageClassName is the name of the StorageClass required by the claim. + More info: https://kubernetes.io/docs/concepts/storage/persistent-volumes#class-1 + type: string + volumeAttributesClassName: + description: |- + volumeAttributesClassName may be used to set the VolumeAttributesClass used by this claim. + If specified, the CSI driver will create or update the volume with the attributes defined + in the corresponding VolumeAttributesClass. This has a different purpose than storageClassName, + it can be changed after the claim is created. An empty string or nil value indicates that no + VolumeAttributesClass will be applied to the claim. If the claim enters an Infeasible error state, + this field can be reset to its previous value (including nil) to cancel the modification. + If the resource referred to by volumeAttributesClass does not exist, this PersistentVolumeClaim will be + set to a Pending state, as reflected by the modifyVolumeStatus field, until such as a resource + exists. + More info: https://kubernetes.io/docs/concepts/storage/volume-attributes-classes/ + type: string + volumeMode: + description: |- + volumeMode defines what type of volume is required by the claim. + Value of Filesystem is implied when not included in claim spec. + type: string + volumeName: + description: volumeName is the binding reference + to the PersistentVolume backing this claim. + type: string + type: object + source: + description: Source is the src of the data for the + requested DataVolume + properties: + blank: + description: DataVolumeBlankImage provides the + parameters to create a new raw blank image + for the PVC + type: object + gcs: + description: DataVolumeSourceGCS provides the + parameters to create a Data Volume from an + GCS source + properties: + secretRef: + description: SecretRef provides the secret + reference needed to access the GCS source + type: string + url: + description: URL is the url of the GCS source + type: string + required: + - url + type: object + http: + description: DataVolumeSourceHTTP can be either + an http or https endpoint, with an optional + basic auth user name and password, and an + optional configmap containing additional CAs + properties: + certConfigMap: + description: CertConfigMap is a configmap + reference, containing a Certificate Authority(CA) + public key, and a base64 encoded pem certificate + type: string + extraHeaders: + description: ExtraHeaders is a list of strings + containing extra headers to include with + HTTP transfer requests + items: + type: string + type: array + secretExtraHeaders: + description: SecretExtraHeaders is a list + of Secret references, each containing + an extra HTTP header that may include + sensitive information + items: + type: string + type: array + secretRef: + description: SecretRef A Secret reference, + the secret should contain accessKeyId + (user name) base64 encoded, and secretKey + (password) also base64 encoded + type: string + url: + description: URL is the URL of the http(s) + endpoint + type: string + required: + - url + type: object + imageio: + description: DataVolumeSourceImageIO provides + the parameters to create a Data Volume from + an imageio source + properties: + certConfigMap: + description: CertConfigMap provides a reference + to the CA cert + type: string + diskId: + description: DiskID provides id of a disk + to be imported + type: string + insecureSkipVerify: + description: InsecureSkipVerify is a flag + to skip certificate verification + type: boolean + secretRef: + description: SecretRef provides the secret + reference needed to access the ovirt-engine + type: string + url: + description: URL is the URL of the ovirt-engine + type: string + required: + - diskId + - url + type: object + pvc: + description: DataVolumeSourcePVC provides the + parameters to create a Data Volume from an + existing PVC + properties: + name: + description: The name of the source PVC + type: string + namespace: + description: The namespace of the source + PVC + type: string + required: + - name + - namespace + type: object + registry: + description: DataVolumeSourceRegistry provides + the parameters to create a Data Volume from + an registry source + properties: + certConfigMap: + description: CertConfigMap provides a reference + to the Registry certs + type: string + imageStream: + description: ImageStream is the name of + image stream for import + type: string + platform: + description: Platform describes the minimum + runtime requirements of the image + properties: + architecture: + description: Architecture specifies + the image target CPU architecture + type: string + type: object + pullMethod: + description: PullMethod can be either "pod" + (default import), or "node" (node docker + cache based import) + type: string + secretRef: + description: SecretRef provides the secret + reference needed to access the Registry + source + type: string + url: + description: 'URL is the url of the registry + source (starting with the scheme: docker, + oci-archive)' + type: string + type: object + s3: + description: DataVolumeSourceS3 provides the + parameters to create a Data Volume from an + S3 source + properties: + certConfigMap: + description: CertConfigMap is a configmap + reference, containing a Certificate Authority(CA) + public key, and a base64 encoded pem certificate + type: string + secretRef: + description: SecretRef provides the secret + reference needed to access the S3 source + type: string + url: + description: URL is the url of the S3 source + type: string + required: + - url + type: object + snapshot: + description: DataVolumeSourceSnapshot provides + the parameters to create a Data Volume from + an existing VolumeSnapshot + properties: + name: + description: The name of the source VolumeSnapshot + type: string + namespace: + description: The namespace of the source + VolumeSnapshot + type: string + required: + - name + - namespace + type: object + upload: + description: DataVolumeSourceUpload provides + the parameters to create a Data Volume by + uploading the source + type: object + vddk: + description: DataVolumeSourceVDDK provides the + parameters to create a Data Volume from a + Vmware source + properties: + backingFile: + description: BackingFile is the path to + the virtual hard disk to migrate from + vCenter/ESXi + type: string + extraArgs: + description: ExtraArgs is a reference to + a ConfigMap containing extra arguments + to pass directly to the VDDK library + type: string + initImageURL: + description: InitImageURL is an optional + URL to an image containing an extracted + VDDK library, overrides v2v-vmware config + map + type: string + secretRef: + description: SecretRef provides a reference + to a secret containing the username and + password needed to access the vCenter + or ESXi host + type: string + thumbprint: + description: Thumbprint is the certificate + thumbprint of the vCenter or ESXi host + type: string + url: + description: URL is the URL of the vCenter + or ESXi host with the VM to migrate + type: string + uuid: + description: UUID is the UUID of the virtual + machine that the backing file is attached + to in vCenter/ESXi + type: string + type: object + type: object + sourceRef: + description: SourceRef is an indirect reference + to the source of data for the requested DataVolume + properties: + kind: + description: The kind of the source reference, + currently only "DataSource" is supported + type: string + name: + description: The name of the source reference + type: string + namespace: + description: The namespace of the source reference, + defaults to the DataVolume namespace + type: string + required: + - kind + - name + type: object + storage: + description: Storage is the requested storage specification + properties: + accessModes: + description: |- + AccessModes contains the desired access modes the volume should have. + More info: https://kubernetes.io/docs/concepts/storage/persistent-volumes#access-modes-1 + items: + type: string + type: array + dataSource: + description: |- + This field can be used to specify either: * An existing VolumeSnapshot object (snapshot.storage.k8s.io/VolumeSnapshot) * An existing PVC (PersistentVolumeClaim) * An existing custom resource that implements data population (Alpha) In order to use custom resource types that implement data population, the AnyVolumeDataSource feature gate must be enabled. If the provisioner or an external controller can support the specified data source, it will create a new volume based on the contents of the specified data source. + If the AnyVolumeDataSource feature gate is enabled, this field will always have the same contents as the DataSourceRef field. + properties: + apiGroup: + description: |- + APIGroup is the group for the resource being referenced. + If APIGroup is not specified, the specified Kind must be in the core API group. + For any other third-party types, APIGroup is required. + type: string + kind: + description: Kind is the type of resource + being referenced + type: string + name: + description: Name is the name of resource + being referenced + type: string + required: + - kind + - name + type: object + x-kubernetes-map-type: atomic + dataSourceRef: + description: |- + Specifies the object from which to populate the volume with data, if a non-empty volume is desired. This may be any local object from a non-empty API group (non core object) or a PersistentVolumeClaim object. When this field is specified, volume binding will only succeed if the type of the specified object matches some installed volume populator or dynamic provisioner. + This field will replace the functionality of the DataSource field and as such if both fields are non-empty, they must have the same value. For backwards compatibility, both fields (DataSource and DataSourceRef) will be set to the same value automatically if one of them is empty and the other is non-empty. + There are two important differences between DataSource and DataSourceRef: + * While DataSource only allows two specific types of objects, DataSourceRef allows any non-core object, as well as PersistentVolumeClaim objects. + * While DataSource ignores disallowed values (dropping them), DataSourceRef preserves all values, and generates an error if a disallowed value is specified. + (Beta) Using this field requires the AnyVolumeDataSource feature gate to be enabled. + properties: + apiGroup: + description: |- + APIGroup is the group for the resource being referenced. + If APIGroup is not specified, the specified Kind must be in the core API group. + For any other third-party types, APIGroup is required. + type: string + kind: + description: Kind is the type of resource + being referenced + type: string + name: + description: Name is the name of resource + being referenced + type: string + namespace: + description: |- + Namespace is the namespace of resource being referenced + Note that when a namespace is specified, a gateway.networking.k8s.io/ReferenceGrant object is required in the referent namespace to allow that namespace's owner to accept the reference. See the ReferenceGrant documentation for details. + (Alpha) This field requires the CrossNamespaceVolumeDataSource feature gate to be enabled. + type: string + required: + - kind + - name + type: object + resources: + description: |- + Resources represents the minimum resources the volume should have. + More info: https://kubernetes.io/docs/concepts/storage/persistent-volumes#resources + properties: + limits: + additionalProperties: + anyOf: + - type: integer + - type: string + pattern: ^(\+|-)?(([0-9]+(\.[0-9]*)?)|(\.[0-9]+))(([KMGTPE]i)|[numkMGTPE]|([eE](\+|-)?(([0-9]+(\.[0-9]*)?)|(\.[0-9]+))))?$ + x-kubernetes-int-or-string: true + description: |- + Limits describes the maximum amount of compute resources allowed. + More info: https://kubernetes.io/docs/concepts/configuration/manage-resources-containers/ + type: object + requests: + additionalProperties: + anyOf: + - type: integer + - type: string + pattern: ^(\+|-)?(([0-9]+(\.[0-9]*)?)|(\.[0-9]+))(([KMGTPE]i)|[numkMGTPE]|([eE](\+|-)?(([0-9]+(\.[0-9]*)?)|(\.[0-9]+))))?$ + x-kubernetes-int-or-string: true + description: |- + Requests describes the minimum amount of compute resources required. + If Requests is omitted for a container, it defaults to Limits if that is explicitly specified, + otherwise to an implementation-defined value. Requests cannot exceed Limits. + More info: https://kubernetes.io/docs/concepts/configuration/manage-resources-containers/ + type: object + type: object + selector: + description: A label query over volumes to consider + for binding. + properties: + matchExpressions: + description: matchExpressions is a list + of label selector requirements. The requirements + are ANDed. + items: + description: |- + A label selector requirement is a selector that contains values, a key, and an operator that + relates the key and values. + properties: + key: + description: key is the label key + that the selector applies to. + type: string + operator: + description: |- + operator represents a key's relationship to a set of values. + Valid operators are In, NotIn, Exists and DoesNotExist. + type: string + values: + description: |- + values is an array of string values. If the operator is In or NotIn, + the values array must be non-empty. If the operator is Exists or DoesNotExist, + the values array must be empty. This array is replaced during a strategic + merge patch. + items: + type: string + type: array + x-kubernetes-list-type: atomic + required: + - key + - operator + type: object + type: array + x-kubernetes-list-type: atomic + matchLabels: + additionalProperties: + type: string + description: |- + matchLabels is a map of {key,value} pairs. A single {key,value} in the matchLabels + map is equivalent to an element of matchExpressions, whose key field is "key", the + operator is "In", and the values array contains only "value". The requirements are ANDed. + type: object + type: object + x-kubernetes-map-type: atomic + storageClassName: + description: |- + Name of the StorageClass required by the claim. + More info: https://kubernetes.io/docs/concepts/storage/persistent-volumes#class-1 + type: string + volumeMode: + description: |- + volumeMode defines what type of volume is required by the claim. + Value of Filesystem is implied when not included in claim spec. + type: string + volumeName: + description: VolumeName is the binding reference + to the PersistentVolume backing this claim. + type: string + type: object + type: object + status: + description: DataVolumeStatus contains the current status + of the DataVolume + properties: + claimName: + description: ClaimName is the name of the underlying + PVC used by the DataVolume. + type: string + conditions: + items: + description: DataVolumeCondition represents the + state of a data volume condition. + properties: + lastHeartbeatTime: + format: date-time + type: string + lastTransitionTime: + format: date-time + type: string + message: + type: string + reason: + type: string + status: + type: string + type: + description: DataVolumeConditionType is the + string representation of known condition + types + type: string + required: + - status + - type + type: object + type: array + phase: + description: Phase is the current phase of the data + volume + type: string + progress: + description: DataVolumeProgress is the current progress + of the DataVolume transfer operation. Value between + 0 and 100 inclusive, N/A if not available + type: string + restartCount: + description: RestartCount is the number of times + the pod populating the DataVolume has restarted + format: int32 + type: integer + type: object + required: + - spec + type: object + required: + - managedDataSource + - schedule + - template + type: object + status: + description: DataImportCronStatus is the status field of the + DIC template + properties: + commonTemplate: + description: CommonTemplate indicates whether this is a + common template (true), or a custom one (false) + type: boolean + conditions: + description: Conditions is a list of conditions that describe + the state of the DataImportCronTemplate. + items: + description: Condition contains details for one aspect + of the current state of this API Resource. + properties: + lastTransitionTime: + description: |- + lastTransitionTime is the last time the condition transitioned from one status to another. + This should be when the underlying condition changed. If that is not known, then using the time when the API field changed is acceptable. + format: date-time + type: string + message: + description: |- + message is a human readable message indicating details about the transition. + This may be an empty string. + maxLength: 32768 + type: string + observedGeneration: + description: |- + observedGeneration represents the .metadata.generation that the condition was set based upon. + For instance, if .metadata.generation is currently 12, but the .status.conditions[x].observedGeneration is 9, the condition is out of date + with respect to the current state of the instance. + format: int64 + minimum: 0 + type: integer + reason: + description: |- + reason contains a programmatic identifier indicating the reason for the condition's last transition. + Producers of specific condition types may define expected values and meanings for this field, + and whether the values are considered a guaranteed API. + The value should be a CamelCase string. + This field may not be empty. + maxLength: 1024 + minLength: 1 + pattern: ^[A-Za-z]([A-Za-z0-9_,:]*[A-Za-z0-9_])?$ + type: string + status: + description: status of the condition, one of True, + False, Unknown. + enum: + - "True" + - "False" + - Unknown + type: string + type: + description: type of condition in CamelCase or in + foo.example.com/CamelCase. + maxLength: 316 + pattern: ^([a-z0-9]([-a-z0-9]*[a-z0-9])?(\.[a-z0-9]([-a-z0-9]*[a-z0-9])?)*/)?(([A-Za-z0-9][-A-Za-z0-9_.]*)?[A-Za-z0-9])$ + type: string + required: + - lastTransitionTime + - message + - reason + - status + - type + type: object + type: array + modified: + description: Modified indicates if a common template was + customized. Always false for custom templates. + type: boolean + originalSupportedArchitectures: + description: |- + OriginalSupportedArchitectures is a comma-separated list of CPU architectures that the original + template supports. + type: string + type: object + type: object + type: array + dataImportSchedule: + description: |- + DataImportSchedule is the cron expression that is used in for the hard-coded data import cron templates. HCO + generates the value of this field once and stored in the status field, so will survive restart. + type: string + infrastructureHighlyAvailable: + description: |- + InfrastructureHighlyAvailable describes whether the cluster has only one worker node + (false) or more (true). + type: boolean + nodeInfo: + description: NodeInfo holds information about the cluster nodes + properties: + controlPlaneArchitectures: + description: ControlPlaneArchitectures is a distinct list of the + CPU architecture of the control-plane nodes. + items: + type: string + type: array + workloadsArchitectures: + description: WorkloadsArchitectures is a distinct list of the + CPU architectures of the workloads nodes in the cluster. + items: + type: string + type: array + type: object + observedGeneration: + description: |- + ObservedGeneration reflects the HyperConverged resource generation. If the ObservedGeneration is less than the + resource generation in metadata, the status is out of date + format: int64 + type: integer + relatedObjects: + description: |- + RelatedObjects is a list of objects created and maintained by this + operator. Object references will be added to this list after they have + been created AND found in the cluster. + items: + description: ObjectReference contains enough information to let + you inspect or modify the referred object. + properties: + apiVersion: + description: API version of the referent. + type: string + fieldPath: + description: |- + If referring to a piece of an object instead of an entire object, this string + should contain a valid JSON/Go field access statement, such as desiredState.manifest.containers[2]. + For example, if the object reference is to a container within a pod, this would take on a value like: + "spec.containers{name}" (where "name" refers to the name of the container that triggered + the event) or if no container name is specified "spec.containers[2]" (container with + index 2 in this pod). This syntax is chosen only to have some well-defined way of + referencing a part of an object. + type: string + kind: + description: |- + Kind of the referent. + More info: https://git.k8s.io/community/contributors/devel/sig-architecture/api-conventions.md#types-kinds + type: string + name: + description: |- + Name of the referent. + More info: https://kubernetes.io/docs/concepts/overview/working-with-objects/names/#names + type: string + namespace: + description: |- + Namespace of the referent. + More info: https://kubernetes.io/docs/concepts/overview/working-with-objects/namespaces/ + type: string + resourceVersion: + description: |- + Specific resourceVersion to which this reference is made, if any. + More info: https://git.k8s.io/community/contributors/devel/sig-architecture/api-conventions.md#concurrency-control-and-consistency + type: string + uid: + description: |- + UID of the referent. + More info: https://kubernetes.io/docs/concepts/overview/working-with-objects/names/#uids + type: string + type: object + x-kubernetes-map-type: atomic + type: array + x-kubernetes-list-type: atomic + systemHealthStatus: + description: SystemHealthStatus reflects the health of HCO and its + secondary resources, based on the aggregated conditions. + type: string + versions: + description: |- + Versions is a list of HCO component versions, as name/version pairs. The version with a name of "operator" + is the HCO version itself, as described here: + https://github.com/openshift/cluster-version-operator/blob/master/docs/dev/clusteroperator.md#version + items: + properties: + name: + type: string + version: + type: string + type: object + type: array + x-kubernetes-list-type: atomic + type: object + type: object + served: true + storage: false + subresources: + status: {} - additionalPrinterColumns: - jsonPath: .metadata.creationTimestamp name: Age diff --git a/tools/feature-gate-doc/featuregates_list.gotmplt b/tools/feature-gate-doc/featuregates_list.gotmplt new file mode 100644 index 0000000000..b0a16ad0d8 --- /dev/null +++ b/tools/feature-gate-doc/featuregates_list.gotmplt @@ -0,0 +1,26 @@ +// FeatureGates is a set of optional feature gates to enable or disable new +// features that are not generally available yet. +// Add a new FeatureGate Object to this set, to enable a feature that is +// disabled by default, or to disable a feature that is enabled by default. +// +// A feature gate may be in the following phases: +// * Alpha: the feature is in dev-preview. It is disabled by default, but can +// be enabled. +// * Beta: the feature gate is in tech-preview. It is enabled by default, but +// can be disabled. +// * GA: the feature is graduated and is always enabled. There is no way to +// disable it. +// * Deprecated: the feature is no longer supported. There is no way to enable +// it +// +// Feature-Gate list: +{{- range .}} +// * {{.Name}}: +{{- range .Description }} +// {{ . }} +{{- end }} +// Phase: {{.Phase}} +// +{{- end }} +// +optional +// +k8s:conversion-gen=false diff --git a/tools/feature-gate-doc/main.go b/tools/feature-gate-doc/main.go new file mode 100644 index 0000000000..c38d6babc8 --- /dev/null +++ b/tools/feature-gate-doc/main.go @@ -0,0 +1,361 @@ +package main + +import ( + "bufio" + "bytes" + _ "embed" + "errors" + "fmt" + "go/ast" + "go/format" + "go/parser" + "go/token" + "os" + "slices" + "strings" + "text/template" +) + +//go:embed featuregates_list.gotmplt +var templateContent []byte + +const ( + Alpha = "Alpha" + Beta = "Beta" + GA = "GA" + Deprecated = "Deprecated" + + featureGatesDetailsFile = "api/v1/featuregates/feature_gates_details.go" + apiSrcFileName = "api/v1/hyperconverged_types.go" + + maxLineLength = 75 +) + +var featureGatesTemplate = template.Must(template.New("featuregates").Parse(string(templateContent))) + +type featureGate struct { + Name string + Description []string + Phase string +} + +func main() { + featureGates, err := parseFGs() + if err != nil { + panic(err) + } + + newCommentBlockText := &bytes.Buffer{} + err = featureGatesTemplate.Execute(newCommentBlockText, featureGates) + if err != nil { + panic(err) + } + + scanner := bufio.NewScanner(newCommentBlockText) + err = applyNewComments(scanner) + if err != nil { + panic(err) + } +} + +func parseFGs() ([]featureGate, error) { + fset := token.NewFileSet() + + file, err := parser.ParseFile(fset, featureGatesDetailsFile, nil, 0) + if err != nil { + return nil, err + } + + fgsDecl, err := findFeatureGatesDetailsDecl(file) + if err != nil { + return nil, err + } + + featureGates, err := parseFeatureGateEntries(fgsDecl) + if err != nil { + return nil, err + } + + sortFeatureGates(featureGates) + + return featureGates, nil +} + +func findFeatureGatesDetailsDecl(file *ast.File) (*ast.CompositeLit, error) { + for _, d := range file.Decls { + decl, ok := d.(*ast.GenDecl) + if !ok { + continue + } + + for _, spec := range decl.Specs { + v, ok := spec.(*ast.ValueSpec) + if !ok || len(v.Names) != 1 || v.Names[0].Name != "featureGatesDetails" { + continue + } + + if len(v.Values) != 1 { + return nil, fmt.Errorf("featureGatesDetails should have 1 value but has %d", len(v.Values)) + } + + content, ok := v.Values[0].(*ast.CompositeLit) + if !ok { + return nil, errors.New("expected a composite literal") + } + + return content, nil + } + } + + return nil, errors.New("couldn't find featureGatesDetails declaration") +} + +func parseFeatureGateEntries(fgsDecl *ast.CompositeLit) ([]featureGate, error) { + var featureGates []featureGate + + for _, elt := range fgsDecl.Elts { + fg, err := parseFeatureGateEntry(elt) + if err != nil { + return nil, err + } + featureGates = append(featureGates, fg) + } + + return featureGates, nil +} + +func parseFeatureGateEntry(elt ast.Expr) (featureGate, error) { + kv, ok := elt.(*ast.KeyValueExpr) + if !ok { + return featureGate{}, errors.New("expected a key value expression") + } + + fgName := strings.Trim(kv.Key.(*ast.BasicLit).Value, `"`) + fgDetails, ok := kv.Value.(*ast.CompositeLit) + if !ok { + return featureGate{}, fmt.Errorf("expected composite literal for feature gate %s", fgName) + } + + phase, description := parseFeatureGateDetails(fgDetails) + + return featureGate{ + Name: fgName, + Description: description, + Phase: phase, + }, nil +} + +func parseFeatureGateDetails(fgDetails *ast.CompositeLit) (phase string, description []string) { + for _, detail := range fgDetails.Elts { + detailKV := detail.(*ast.KeyValueExpr) + fieldName := detailKV.Key.(*ast.Ident).Name + + switch fieldName { + case "phase": + phase = parsePhase(detailKV.Value.(*ast.Ident).Name) + case "description": + description = parseDescription(detailKV.Value) + } + } + return phase, description +} + +func parsePhase(phaseIdent string) string { + switch phaseIdent { + case "PhaseAlpha": + return Alpha + case "PhaseBeta": + return Beta + case "PhaseGA": + return GA + case "PhaseDeprecated": + return Deprecated + default: + return "" + } +} + +func parseDescription(value ast.Expr) []string { + switch val := value.(type) { + case *ast.BasicLit: + line := strings.Trim(val.Value, `"`) + line = strings.Trim(line, "`") + return []string{line} + case *ast.BinaryExpr: + return multilinesDescription(val, nil) + default: + return nil + } +} + +func sortFeatureGates(featureGates []featureGate) { + slices.SortFunc(featureGates, func(a, b featureGate) int { + if phaseCmp := cmpPhase(a.Phase, b.Phase); phaseCmp != 0 { + return phaseCmp + } + return strings.Compare(a.Name, b.Name) + }) +} + +func cmpPhase(a, b string) int { + if a == b { + return 0 + } + + return toComparablePhase(a) - toComparablePhase(b) +} + +func toComparablePhase(phase string) int { + switch phase { + case Alpha: + return 1 + case Beta: + return 2 + case GA: + return 3 + case Deprecated: + return 4 + } + + return 5 +} + +func applyNewComments(newComments *bufio.Scanner) error { + fset := token.NewFileSet() + + file, err := parser.ParseFile(fset, apiSrcFileName, nil, parser.ParseComments) + if err != nil { + return err + } + + field, err := findFeatureGatesNode(file) + if err != nil { + return err + } + + list, err := buildCommentList(newComments, field) + if err != nil { + return err + } + + updateCommentInAST(field, list, fset, file) + + return updateAPISrcFile(fset, file) +} + +func updateAPISrcFile(fset *token.FileSet, file *ast.File) error { + b := bytes.Buffer{} + err := format.Node(&b, fset, file) + if err != nil { + return err + } + + return os.WriteFile(apiSrcFileName, b.Bytes(), 0644) +} + +func updateCommentInAST(field *ast.Field, list []*ast.Comment, fset *token.FileSet, file *ast.File) { + field.Doc = &ast.CommentGroup{ + List: list, + } + + comments := ast.NewCommentMap(fset, file, file.Comments) + commentGroups := comments[field] + + if len(commentGroups) == 0 { + comments[field] = []*ast.CommentGroup{field.Doc} + } else { + // don't drop the auto-generated warning comment. Only set the actual doc comment. + commentGroups[len(commentGroups)-1] = field.Doc + } + + file.Comments = comments.Filter(file).Comments() +} + +func buildCommentList(newComments *bufio.Scanner, field *ast.Field) ([]*ast.Comment, error) { + var list []*ast.Comment + + for newComments.Scan() { + list = append(list, + &ast.Comment{ + Text: newComments.Text(), + Slash: field.Pos() - 1, + }, + ) + } + if err := newComments.Err(); err != nil { + return nil, err + } + + return list, nil +} + +func findFeatureGatesNode(file *ast.File) (*ast.Field, error) { + for _, decl := range file.Decls { + genDecl, ok := decl.(*ast.GenDecl) + if !ok { + continue + } + + for _, spec := range genDecl.Specs { + v, ok := spec.(*ast.TypeSpec) + if !ok || v.Name.Name != "HyperConvergedSpec" { + continue + } + + structType, ok := v.Type.(*ast.StructType) + if !ok { + return nil, fmt.Errorf("expected HyperConvergedSpec to be a struct type") + } + + if structType.Fields == nil { + return nil, fmt.Errorf("expected HyperConvergedSpec to not be empty struct") + } + + for _, field := range structType.Fields.List { + if len(field.Names) != 1 || field.Names[0].Name != "FeatureGates" { + continue + } + + return field, nil + } + } + } + + return nil, errors.New("couldn't find the FeatureGates field") +} + +func multilinesDescription(expr *ast.BinaryExpr, lines []string) []string { + switch val := expr.X.(type) { + case *ast.BasicLit: + line := val.Value + line = strings.Trim(line, `"`) + line = strings.Trim(line, "`") + lines = addLine(line, lines) + + case *ast.BinaryExpr: + lines = multilinesDescription(val, lines) + } + + line := expr.Y.(*ast.BasicLit).Value + line = strings.Trim(line, `"`) + line = strings.Trim(line, "`") + lines = addLine(line, lines) + + return lines +} + +func addLine(line string, lines []string) []string { + for len(line) > maxLineLength { + for i := maxLineLength; i > 0; i-- { + if line[i] == ' ' { + lines = append(lines, line[:i+1]) + line = line[i+1:] + break + } + } + } + + lines = append(lines, line) + + return lines +} diff --git a/tools/manifest-templator/generated-crd.yaml b/tools/manifest-templator/generated-crd.yaml index d7b0d4cb77..a1cebffd93 100644 --- a/tools/manifest-templator/generated-crd.yaml +++ b/tools/manifest-templator/generated-crd.yaml @@ -17,6 +17,5186 @@ spec: singular: hyperconverged scope: Namespaced versions: + - additionalPrinterColumns: + - jsonPath: .metadata.creationTimestamp + name: Age + type: date + name: v1 + schema: + openAPIV3Schema: + description: HyperConverged is the Schema for the hyperconvergeds API + properties: + apiVersion: + description: |- + APIVersion defines the versioned schema of this representation of an object. + Servers should convert recognized schemas to the latest internal value, and + may reject unrecognized values. + More info: https://git.k8s.io/community/contributors/devel/sig-architecture/api-conventions.md#resources + type: string + kind: + description: |- + Kind is a string value representing the REST resource this object represents. + Servers may infer this from the endpoint the client submits requests to. + Cannot be updated. + In CamelCase. + More info: https://git.k8s.io/community/contributors/devel/sig-architecture/api-conventions.md#types-kinds + type: string + metadata: + properties: + name: + pattern: kubevirt-hyperconverged + type: string + type: object + spec: + default: + certConfig: + ca: + duration: 48h0m0s + renewBefore: 24h0m0s + server: + duration: 24h0m0s + renewBefore: 12h0m0s + deployVmConsoleProxy: false + enableApplicationAwareQuota: false + enableCommonBootImageImport: true + liveMigrationConfig: + allowAutoConverge: false + allowPostCopy: false + completionTimeoutPerGiB: 150 + parallelMigrationsPerCluster: 5 + parallelOutboundMigrationsPerNode: 2 + progressTimeout: 150 + resourceRequirements: + vmiCPUAllocationRatio: 10 + uninstallStrategy: BlockUninstallIfWorkloadsExist + virtualMachineOptions: + disableFreePageReporting: false + disableSerialConsoleLog: false + description: HyperConvergedSpec defines the desired state of HyperConverged + properties: + CommonInstancetypesDeployment: + description: CommonInstancetypesDeployment holds the configuration + of common-instancetypes deployment within KubeVirt. + properties: + enabled: + description: Enabled controls the deployment of common-instancetypes + resources, defaults to True. + nullable: true + type: boolean + type: object + applicationAwareConfig: + description: ApplicationAwareConfig set the AAQ configurations + properties: + allowApplicationAwareClusterResourceQuota: + default: false + description: AllowApplicationAwareClusterResourceQuota if set + to true, allows creation and management of ClusterAppsResourceQuota + type: boolean + namespaceSelector: + description: NamespaceSelector determines in which namespaces + scheduling gate will be added to pods.. + properties: + matchExpressions: + description: matchExpressions is a list of label selector + requirements. The requirements are ANDed. + items: + description: |- + A label selector requirement is a selector that contains values, a key, and an operator that + relates the key and values. + properties: + key: + description: key is the label key that the selector + applies to. + type: string + operator: + description: |- + operator represents a key's relationship to a set of values. + Valid operators are In, NotIn, Exists and DoesNotExist. + type: string + values: + description: |- + values is an array of string values. If the operator is In or NotIn, + the values array must be non-empty. If the operator is Exists or DoesNotExist, + the values array must be empty. This array is replaced during a strategic + merge patch. + items: + type: string + type: array + x-kubernetes-list-type: atomic + required: + - key + - operator + type: object + type: array + x-kubernetes-list-type: atomic + matchLabels: + additionalProperties: + type: string + description: |- + matchLabels is a map of {key,value} pairs. A single {key,value} in the matchLabels + map is equivalent to an element of matchExpressions, whose key field is "key", the + operator is "In", and the values array contains only "value". The requirements are ANDed. + type: object + type: object + x-kubernetes-map-type: atomic + vmiCalcConfigName: + default: DedicatedVirtualResources + description: |- + VmiCalcConfigName determine how resource allocation will be done with ApplicationsResourceQuota. + allowed values are: VmiPodUsage, VirtualResources, DedicatedVirtualResources or IgnoreVmiCalculator + enum: + - VmiPodUsage + - VirtualResources + - DedicatedVirtualResources + - IgnoreVmiCalculator + type: string + type: object + certConfig: + default: + ca: + duration: 48h0m0s + renewBefore: 24h0m0s + server: + duration: 24h0m0s + renewBefore: 12h0m0s + description: certConfig holds the rotation policy for internal, self-signed + certificates + properties: + ca: + default: + duration: 48h0m0s + renewBefore: 24h0m0s + description: |- + CA configuration - + CA certs are kept in the CA bundle as long as they are valid + properties: + duration: + default: 48h0m0s + description: |- + The requested 'duration' (i.e. lifetime) of the Certificate. + This should comply with golang's ParseDuration format (https://golang.org/pkg/time/#ParseDuration) + type: string + renewBefore: + default: 24h0m0s + description: |- + The amount of time before the currently issued certificate's `notAfter` + time that we will begin to attempt to renew the certificate. + This should comply with golang's ParseDuration format (https://golang.org/pkg/time/#ParseDuration) + type: string + type: object + server: + default: + duration: 24h0m0s + renewBefore: 12h0m0s + description: |- + Server configuration - + Certs are rotated and discarded + properties: + duration: + default: 24h0m0s + description: |- + The requested 'duration' (i.e. lifetime) of the Certificate. + This should comply with golang's ParseDuration format (https://golang.org/pkg/time/#ParseDuration) + type: string + renewBefore: + default: 12h0m0s + description: |- + The amount of time before the currently issued certificate's `notAfter` + time that we will begin to attempt to renew the certificate. + This should comply with golang's ParseDuration format (https://golang.org/pkg/time/#ParseDuration) + type: string + type: object + type: object + commonBootImageNamespace: + description: |- + CommonBootImageNamespace override the default namespace of the common boot images, in order to hide them. + + If not set, HCO won't set any namespace, letting SSP to use the default. If set, use the namespace to create the + DataImportCronTemplates and the common image streams, with this namespace. This field is not set by default. + type: string + commonTemplatesNamespace: + description: |- + CommonTemplatesNamespace defines namespace in which common templates will + be deployed. It overrides the default openshift namespace. + type: string + dataImportCronTemplates: + description: DataImportCronTemplates holds list of data import cron + templates (golden images) + items: + description: |- + DataImportCronTemplate defines the template type for DataImportCrons. + It requires metadata.name to be specified while leaving namespace as optional. + properties: + metadata: + properties: + annotations: + additionalProperties: + type: string + type: object + finalizers: + items: + type: string + type: array + labels: + additionalProperties: + type: string + type: object + name: + type: string + namespace: + type: string + type: object + spec: + description: DataImportCronSpec defines specification for DataImportCron + properties: + garbageCollect: + description: |- + GarbageCollect specifies whether old PVCs should be cleaned up after a new PVC is imported. + Options are currently "Outdated" and "Never", defaults to "Outdated". + type: string + importsToKeep: + description: Number of import PVCs to keep when garbage + collecting. Default is 3. + format: int32 + type: integer + managedDataSource: + description: |- + ManagedDataSource specifies the name of the corresponding DataSource this cron will manage. + DataSource has to be in the same namespace. + type: string + retentionPolicy: + description: RetentionPolicy specifies whether the created + DataVolumes and DataSources are retained when their DataImportCron + is deleted. Default is RatainAll. + type: string + schedule: + description: Schedule specifies in cron format when and + how often to look for new imports + type: string + serviceAccountName: + description: ServiceAccountName is the name of the ServiceAccount + for creating DataVolumes. + minLength: 1 + type: string + template: + description: Template specifies template for the DVs to + be created + properties: + apiVersion: + description: |- + APIVersion defines the versioned schema of this representation of an object. + Servers should convert recognized schemas to the latest internal value, and + may reject unrecognized values. + More info: https://git.k8s.io/community/contributors/devel/sig-architecture/api-conventions.md#resources + type: string + kind: + description: |- + Kind is a string value representing the REST resource this object represents. + Servers may infer this from the endpoint the client submits requests to. + Cannot be updated. + In CamelCase. + More info: https://git.k8s.io/community/contributors/devel/sig-architecture/api-conventions.md#types-kinds + type: string + metadata: + properties: + annotations: + additionalProperties: + type: string + type: object + finalizers: + items: + type: string + type: array + labels: + additionalProperties: + type: string + type: object + name: + type: string + namespace: + type: string + type: object + spec: + description: DataVolumeSpec defines the DataVolume type + specification + properties: + checkpoints: + description: Checkpoints is a list of DataVolumeCheckpoints, + representing stages in a multistage import. + items: + description: DataVolumeCheckpoint defines a stage + in a warm migration. + properties: + current: + description: Current is the identifier of + the snapshot created for this checkpoint. + type: string + previous: + description: Previous is the identifier of + the snapshot from the previous checkpoint. + type: string + required: + - current + - previous + type: object + type: array + contentType: + description: 'DataVolumeContentType options: "kubevirt", + "archive"' + enum: + - kubevirt + - archive + type: string + finalCheckpoint: + description: FinalCheckpoint indicates whether the + current DataVolumeCheckpoint is the final checkpoint. + type: boolean + preallocation: + description: Preallocation controls whether storage + for DataVolumes should be allocated in advance. + type: boolean + priorityClassName: + description: PriorityClassName for Importer, Cloner + and Uploader pod + type: string + pvc: + description: PVC is the PVC specification + properties: + accessModes: + description: |- + accessModes contains the desired access modes the volume should have. + More info: https://kubernetes.io/docs/concepts/storage/persistent-volumes#access-modes-1 + items: + type: string + type: array + x-kubernetes-list-type: atomic + dataSource: + description: |- + dataSource field can be used to specify either: + * An existing VolumeSnapshot object (snapshot.storage.k8s.io/VolumeSnapshot) + * An existing PVC (PersistentVolumeClaim) + If the provisioner or an external controller can support the specified data source, + it will create a new volume based on the contents of the specified data source. + When the AnyVolumeDataSource feature gate is enabled, dataSource contents will be copied to dataSourceRef, + and dataSourceRef contents will be copied to dataSource when dataSourceRef.namespace is not specified. + If the namespace is specified, then dataSourceRef will not be copied to dataSource. + properties: + apiGroup: + description: |- + APIGroup is the group for the resource being referenced. + If APIGroup is not specified, the specified Kind must be in the core API group. + For any other third-party types, APIGroup is required. + type: string + kind: + description: Kind is the type of resource + being referenced + type: string + name: + description: Name is the name of resource + being referenced + type: string + required: + - kind + - name + type: object + x-kubernetes-map-type: atomic + dataSourceRef: + description: |- + dataSourceRef specifies the object from which to populate the volume with data, if a non-empty + volume is desired. This may be any object from a non-empty API group (non + core object) or a PersistentVolumeClaim object. + When this field is specified, volume binding will only succeed if the type of + the specified object matches some installed volume populator or dynamic + provisioner. + This field will replace the functionality of the dataSource field and as such + if both fields are non-empty, they must have the same value. For backwards + compatibility, when namespace isn't specified in dataSourceRef, + both fields (dataSource and dataSourceRef) will be set to the same + value automatically if one of them is empty and the other is non-empty. + When namespace is specified in dataSourceRef, + dataSource isn't set to the same value and must be empty. + There are three important differences between dataSource and dataSourceRef: + * While dataSource only allows two specific types of objects, dataSourceRef + allows any non-core object, as well as PersistentVolumeClaim objects. + * While dataSource ignores disallowed values (dropping them), dataSourceRef + preserves all values, and generates an error if a disallowed value is + specified. + * While dataSource only allows local objects, dataSourceRef allows objects + in any namespaces. + (Beta) Using this field requires the AnyVolumeDataSource feature gate to be enabled. + (Alpha) Using the namespace field of dataSourceRef requires the CrossNamespaceVolumeDataSource feature gate to be enabled. + properties: + apiGroup: + description: |- + APIGroup is the group for the resource being referenced. + If APIGroup is not specified, the specified Kind must be in the core API group. + For any other third-party types, APIGroup is required. + type: string + kind: + description: Kind is the type of resource + being referenced + type: string + name: + description: Name is the name of resource + being referenced + type: string + namespace: + description: |- + Namespace is the namespace of resource being referenced + Note that when a namespace is specified, a gateway.networking.k8s.io/ReferenceGrant object is required in the referent namespace to allow that namespace's owner to accept the reference. See the ReferenceGrant documentation for details. + (Alpha) This field requires the CrossNamespaceVolumeDataSource feature gate to be enabled. + type: string + required: + - kind + - name + type: object + resources: + description: |- + resources represents the minimum resources the volume should have. + If RecoverVolumeExpansionFailure feature is enabled users are allowed to specify resource requirements + that are lower than previous value but must still be higher than capacity recorded in the + status field of the claim. + More info: https://kubernetes.io/docs/concepts/storage/persistent-volumes#resources + properties: + limits: + additionalProperties: + anyOf: + - type: integer + - type: string + pattern: ^(\+|-)?(([0-9]+(\.[0-9]*)?)|(\.[0-9]+))(([KMGTPE]i)|[numkMGTPE]|([eE](\+|-)?(([0-9]+(\.[0-9]*)?)|(\.[0-9]+))))?$ + x-kubernetes-int-or-string: true + description: |- + Limits describes the maximum amount of compute resources allowed. + More info: https://kubernetes.io/docs/concepts/configuration/manage-resources-containers/ + type: object + requests: + additionalProperties: + anyOf: + - type: integer + - type: string + pattern: ^(\+|-)?(([0-9]+(\.[0-9]*)?)|(\.[0-9]+))(([KMGTPE]i)|[numkMGTPE]|([eE](\+|-)?(([0-9]+(\.[0-9]*)?)|(\.[0-9]+))))?$ + x-kubernetes-int-or-string: true + description: |- + Requests describes the minimum amount of compute resources required. + If Requests is omitted for a container, it defaults to Limits if that is explicitly specified, + otherwise to an implementation-defined value. Requests cannot exceed Limits. + More info: https://kubernetes.io/docs/concepts/configuration/manage-resources-containers/ + type: object + type: object + selector: + description: selector is a label query over + volumes to consider for binding. + properties: + matchExpressions: + description: matchExpressions is a list + of label selector requirements. The requirements + are ANDed. + items: + description: |- + A label selector requirement is a selector that contains values, a key, and an operator that + relates the key and values. + properties: + key: + description: key is the label key + that the selector applies to. + type: string + operator: + description: |- + operator represents a key's relationship to a set of values. + Valid operators are In, NotIn, Exists and DoesNotExist. + type: string + values: + description: |- + values is an array of string values. If the operator is In or NotIn, + the values array must be non-empty. If the operator is Exists or DoesNotExist, + the values array must be empty. This array is replaced during a strategic + merge patch. + items: + type: string + type: array + x-kubernetes-list-type: atomic + required: + - key + - operator + type: object + type: array + x-kubernetes-list-type: atomic + matchLabels: + additionalProperties: + type: string + description: |- + matchLabels is a map of {key,value} pairs. A single {key,value} in the matchLabels + map is equivalent to an element of matchExpressions, whose key field is "key", the + operator is "In", and the values array contains only "value". The requirements are ANDed. + type: object + type: object + x-kubernetes-map-type: atomic + storageClassName: + description: |- + storageClassName is the name of the StorageClass required by the claim. + More info: https://kubernetes.io/docs/concepts/storage/persistent-volumes#class-1 + type: string + volumeAttributesClassName: + description: |- + volumeAttributesClassName may be used to set the VolumeAttributesClass used by this claim. + If specified, the CSI driver will create or update the volume with the attributes defined + in the corresponding VolumeAttributesClass. This has a different purpose than storageClassName, + it can be changed after the claim is created. An empty string or nil value indicates that no + VolumeAttributesClass will be applied to the claim. If the claim enters an Infeasible error state, + this field can be reset to its previous value (including nil) to cancel the modification. + If the resource referred to by volumeAttributesClass does not exist, this PersistentVolumeClaim will be + set to a Pending state, as reflected by the modifyVolumeStatus field, until such as a resource + exists. + More info: https://kubernetes.io/docs/concepts/storage/volume-attributes-classes/ + type: string + volumeMode: + description: |- + volumeMode defines what type of volume is required by the claim. + Value of Filesystem is implied when not included in claim spec. + type: string + volumeName: + description: volumeName is the binding reference + to the PersistentVolume backing this claim. + type: string + type: object + source: + description: Source is the src of the data for the + requested DataVolume + properties: + blank: + description: DataVolumeBlankImage provides the + parameters to create a new raw blank image + for the PVC + type: object + gcs: + description: DataVolumeSourceGCS provides the + parameters to create a Data Volume from an + GCS source + properties: + secretRef: + description: SecretRef provides the secret + reference needed to access the GCS source + type: string + url: + description: URL is the url of the GCS source + type: string + required: + - url + type: object + http: + description: DataVolumeSourceHTTP can be either + an http or https endpoint, with an optional + basic auth user name and password, and an + optional configmap containing additional CAs + properties: + certConfigMap: + description: CertConfigMap is a configmap + reference, containing a Certificate Authority(CA) + public key, and a base64 encoded pem certificate + type: string + extraHeaders: + description: ExtraHeaders is a list of strings + containing extra headers to include with + HTTP transfer requests + items: + type: string + type: array + secretExtraHeaders: + description: SecretExtraHeaders is a list + of Secret references, each containing + an extra HTTP header that may include + sensitive information + items: + type: string + type: array + secretRef: + description: SecretRef A Secret reference, + the secret should contain accessKeyId + (user name) base64 encoded, and secretKey + (password) also base64 encoded + type: string + url: + description: URL is the URL of the http(s) + endpoint + type: string + required: + - url + type: object + imageio: + description: DataVolumeSourceImageIO provides + the parameters to create a Data Volume from + an imageio source + properties: + certConfigMap: + description: CertConfigMap provides a reference + to the CA cert + type: string + diskId: + description: DiskID provides id of a disk + to be imported + type: string + insecureSkipVerify: + description: InsecureSkipVerify is a flag + to skip certificate verification + type: boolean + secretRef: + description: SecretRef provides the secret + reference needed to access the ovirt-engine + type: string + url: + description: URL is the URL of the ovirt-engine + type: string + required: + - diskId + - url + type: object + pvc: + description: DataVolumeSourcePVC provides the + parameters to create a Data Volume from an + existing PVC + properties: + name: + description: The name of the source PVC + type: string + namespace: + description: The namespace of the source + PVC + type: string + required: + - name + - namespace + type: object + registry: + description: DataVolumeSourceRegistry provides + the parameters to create a Data Volume from + an registry source + properties: + certConfigMap: + description: CertConfigMap provides a reference + to the Registry certs + type: string + imageStream: + description: ImageStream is the name of + image stream for import + type: string + platform: + description: Platform describes the minimum + runtime requirements of the image + properties: + architecture: + description: Architecture specifies + the image target CPU architecture + type: string + type: object + pullMethod: + description: PullMethod can be either "pod" + (default import), or "node" (node docker + cache based import) + type: string + secretRef: + description: SecretRef provides the secret + reference needed to access the Registry + source + type: string + url: + description: 'URL is the url of the registry + source (starting with the scheme: docker, + oci-archive)' + type: string + type: object + s3: + description: DataVolumeSourceS3 provides the + parameters to create a Data Volume from an + S3 source + properties: + certConfigMap: + description: CertConfigMap is a configmap + reference, containing a Certificate Authority(CA) + public key, and a base64 encoded pem certificate + type: string + secretRef: + description: SecretRef provides the secret + reference needed to access the S3 source + type: string + url: + description: URL is the url of the S3 source + type: string + required: + - url + type: object + snapshot: + description: DataVolumeSourceSnapshot provides + the parameters to create a Data Volume from + an existing VolumeSnapshot + properties: + name: + description: The name of the source VolumeSnapshot + type: string + namespace: + description: The namespace of the source + VolumeSnapshot + type: string + required: + - name + - namespace + type: object + upload: + description: DataVolumeSourceUpload provides + the parameters to create a Data Volume by + uploading the source + type: object + vddk: + description: DataVolumeSourceVDDK provides the + parameters to create a Data Volume from a + Vmware source + properties: + backingFile: + description: BackingFile is the path to + the virtual hard disk to migrate from + vCenter/ESXi + type: string + extraArgs: + description: ExtraArgs is a reference to + a ConfigMap containing extra arguments + to pass directly to the VDDK library + type: string + initImageURL: + description: InitImageURL is an optional + URL to an image containing an extracted + VDDK library, overrides v2v-vmware config + map + type: string + secretRef: + description: SecretRef provides a reference + to a secret containing the username and + password needed to access the vCenter + or ESXi host + type: string + thumbprint: + description: Thumbprint is the certificate + thumbprint of the vCenter or ESXi host + type: string + url: + description: URL is the URL of the vCenter + or ESXi host with the VM to migrate + type: string + uuid: + description: UUID is the UUID of the virtual + machine that the backing file is attached + to in vCenter/ESXi + type: string + type: object + type: object + sourceRef: + description: SourceRef is an indirect reference + to the source of data for the requested DataVolume + properties: + kind: + description: The kind of the source reference, + currently only "DataSource" is supported + type: string + name: + description: The name of the source reference + type: string + namespace: + description: The namespace of the source reference, + defaults to the DataVolume namespace + type: string + required: + - kind + - name + type: object + storage: + description: Storage is the requested storage specification + properties: + accessModes: + description: |- + AccessModes contains the desired access modes the volume should have. + More info: https://kubernetes.io/docs/concepts/storage/persistent-volumes#access-modes-1 + items: + type: string + type: array + dataSource: + description: |- + This field can be used to specify either: * An existing VolumeSnapshot object (snapshot.storage.k8s.io/VolumeSnapshot) * An existing PVC (PersistentVolumeClaim) * An existing custom resource that implements data population (Alpha) In order to use custom resource types that implement data population, the AnyVolumeDataSource feature gate must be enabled. If the provisioner or an external controller can support the specified data source, it will create a new volume based on the contents of the specified data source. + If the AnyVolumeDataSource feature gate is enabled, this field will always have the same contents as the DataSourceRef field. + properties: + apiGroup: + description: |- + APIGroup is the group for the resource being referenced. + If APIGroup is not specified, the specified Kind must be in the core API group. + For any other third-party types, APIGroup is required. + type: string + kind: + description: Kind is the type of resource + being referenced + type: string + name: + description: Name is the name of resource + being referenced + type: string + required: + - kind + - name + type: object + x-kubernetes-map-type: atomic + dataSourceRef: + description: |- + Specifies the object from which to populate the volume with data, if a non-empty volume is desired. This may be any local object from a non-empty API group (non core object) or a PersistentVolumeClaim object. When this field is specified, volume binding will only succeed if the type of the specified object matches some installed volume populator or dynamic provisioner. + This field will replace the functionality of the DataSource field and as such if both fields are non-empty, they must have the same value. For backwards compatibility, both fields (DataSource and DataSourceRef) will be set to the same value automatically if one of them is empty and the other is non-empty. + There are two important differences between DataSource and DataSourceRef: + * While DataSource only allows two specific types of objects, DataSourceRef allows any non-core object, as well as PersistentVolumeClaim objects. + * While DataSource ignores disallowed values (dropping them), DataSourceRef preserves all values, and generates an error if a disallowed value is specified. + (Beta) Using this field requires the AnyVolumeDataSource feature gate to be enabled. + properties: + apiGroup: + description: |- + APIGroup is the group for the resource being referenced. + If APIGroup is not specified, the specified Kind must be in the core API group. + For any other third-party types, APIGroup is required. + type: string + kind: + description: Kind is the type of resource + being referenced + type: string + name: + description: Name is the name of resource + being referenced + type: string + namespace: + description: |- + Namespace is the namespace of resource being referenced + Note that when a namespace is specified, a gateway.networking.k8s.io/ReferenceGrant object is required in the referent namespace to allow that namespace's owner to accept the reference. See the ReferenceGrant documentation for details. + (Alpha) This field requires the CrossNamespaceVolumeDataSource feature gate to be enabled. + type: string + required: + - kind + - name + type: object + resources: + description: |- + Resources represents the minimum resources the volume should have. + More info: https://kubernetes.io/docs/concepts/storage/persistent-volumes#resources + properties: + limits: + additionalProperties: + anyOf: + - type: integer + - type: string + pattern: ^(\+|-)?(([0-9]+(\.[0-9]*)?)|(\.[0-9]+))(([KMGTPE]i)|[numkMGTPE]|([eE](\+|-)?(([0-9]+(\.[0-9]*)?)|(\.[0-9]+))))?$ + x-kubernetes-int-or-string: true + description: |- + Limits describes the maximum amount of compute resources allowed. + More info: https://kubernetes.io/docs/concepts/configuration/manage-resources-containers/ + type: object + requests: + additionalProperties: + anyOf: + - type: integer + - type: string + pattern: ^(\+|-)?(([0-9]+(\.[0-9]*)?)|(\.[0-9]+))(([KMGTPE]i)|[numkMGTPE]|([eE](\+|-)?(([0-9]+(\.[0-9]*)?)|(\.[0-9]+))))?$ + x-kubernetes-int-or-string: true + description: |- + Requests describes the minimum amount of compute resources required. + If Requests is omitted for a container, it defaults to Limits if that is explicitly specified, + otherwise to an implementation-defined value. Requests cannot exceed Limits. + More info: https://kubernetes.io/docs/concepts/configuration/manage-resources-containers/ + type: object + type: object + selector: + description: A label query over volumes to consider + for binding. + properties: + matchExpressions: + description: matchExpressions is a list + of label selector requirements. The requirements + are ANDed. + items: + description: |- + A label selector requirement is a selector that contains values, a key, and an operator that + relates the key and values. + properties: + key: + description: key is the label key + that the selector applies to. + type: string + operator: + description: |- + operator represents a key's relationship to a set of values. + Valid operators are In, NotIn, Exists and DoesNotExist. + type: string + values: + description: |- + values is an array of string values. If the operator is In or NotIn, + the values array must be non-empty. If the operator is Exists or DoesNotExist, + the values array must be empty. This array is replaced during a strategic + merge patch. + items: + type: string + type: array + x-kubernetes-list-type: atomic + required: + - key + - operator + type: object + type: array + x-kubernetes-list-type: atomic + matchLabels: + additionalProperties: + type: string + description: |- + matchLabels is a map of {key,value} pairs. A single {key,value} in the matchLabels + map is equivalent to an element of matchExpressions, whose key field is "key", the + operator is "In", and the values array contains only "value". The requirements are ANDed. + type: object + type: object + x-kubernetes-map-type: atomic + storageClassName: + description: |- + Name of the StorageClass required by the claim. + More info: https://kubernetes.io/docs/concepts/storage/persistent-volumes#class-1 + type: string + volumeMode: + description: |- + volumeMode defines what type of volume is required by the claim. + Value of Filesystem is implied when not included in claim spec. + type: string + volumeName: + description: VolumeName is the binding reference + to the PersistentVolume backing this claim. + type: string + type: object + type: object + status: + description: DataVolumeStatus contains the current status + of the DataVolume + properties: + claimName: + description: ClaimName is the name of the underlying + PVC used by the DataVolume. + type: string + conditions: + items: + description: DataVolumeCondition represents the + state of a data volume condition. + properties: + lastHeartbeatTime: + format: date-time + type: string + lastTransitionTime: + format: date-time + type: string + message: + type: string + reason: + type: string + status: + type: string + type: + description: DataVolumeConditionType is the + string representation of known condition + types + type: string + required: + - status + - type + type: object + type: array + phase: + description: Phase is the current phase of the data + volume + type: string + progress: + description: DataVolumeProgress is the current progress + of the DataVolume transfer operation. Value between + 0 and 100 inclusive, N/A if not available + type: string + restartCount: + description: RestartCount is the number of times + the pod populating the DataVolume has restarted + format: int32 + type: integer + type: object + required: + - spec + type: object + required: + - managedDataSource + - schedule + - template + type: object + type: object + type: array + x-kubernetes-list-type: atomic + defaultCPUModel: + description: |- + DefaultCPUModel defines a cluster default for CPU model: default CPU model is set when VMI doesn't have any CPU model. + When VMI has CPU model set, then VMI's CPU model is preferred. + When default CPU model is not set and VMI's CPU model is not set too, host-model will be set. + Default CPU model can be changed when kubevirt is running. + type: string + defaultRuntimeClass: + description: |- + DefaultRuntimeClass defines a cluster default for the RuntimeClass to be used for VMIs pods if not set there. + Default RuntimeClass can be changed when kubevirt is running, existing VMIs are not impacted till + the next restart/live-migration when they are eventually going to consume the new default RuntimeClass. + type: string + deployVmConsoleProxy: + default: false + description: deploy VM console proxy resources in SSP operator + type: boolean + enableApplicationAwareQuota: + default: false + description: EnableApplicationAwareQuota if true, enables the Application + Aware Quota feature + type: boolean + enableCommonBootImageImport: + default: true + description: |- + Opt-in to automatic delivery/updates of the common data import cron templates. + There are two sources for the data import cron templates: hard coded list of common templates, and custom (user + defined) templates that can be added to the dataImportCronTemplates field. This field only controls the common + templates. It is possible to use custom templates by adding them to the dataImportCronTemplates field. + type: boolean + evictionStrategy: + description: |- + EvictionStrategy defines at the cluster level if the VirtualMachineInstance should be + migrated instead of shut-off in case of a node drain. If the VirtualMachineInstance specific + field is set it overrides the cluster level one. + Allowed values: + - `None` no eviction strategy at cluster level. + - `LiveMigrate` migrate the VM on eviction; a not live migratable VM with no specific strategy will block the drain of the node util manually evicted. + - `LiveMigrateIfPossible` migrate the VM on eviction if live migration is possible, otherwise directly evict. + - `External` block the drain, track eviction and notify an external controller. + Defaults to LiveMigrate with multiple worker nodes, None on single worker clusters. + enum: + - None + - LiveMigrate + - LiveMigrateIfPossible + - External + type: string + featureGates: + description: |- + FeatureGates is a set of optional feature gates to enable or disable new + features that are not generally available yet. + Add a new FeatureGate Object to this set, to enable a feature that is + disabled by default, or to disable a feature that is enabled by default. + + A feature gate may be in the following phases: + * Alpha: the feature is in dev-preview. It is disabled by default, but can + be enabled. + * Beta: the feature gate is in tech-preview. It is enabled by default, but + can be disabled. + * GA: the feature is graduated and is always enabled. There is no way to + disable it. + * Deprecated: the feature is no longer supported. There is no way to enable + it + + Feature-Gate list: + * alignCPUs: + Enable KubeVirt to request up to two additional dedicated CPUs in order to + complete the total CPU count to an even parity when using emulator thread + isolation. + Note: this feature is in Developer Preview. + Phase: Alpha + + * decentralizedLiveMigration: + enables the decentralized live migration (cross-cluster migration) feature. + This feature allows live migration of VirtualMachineInstances between + different clusters. + Note: This feature is in Developer Preview. + Phase: Alpha + + * declarativeHotplugVolumes: + enables the use of the declarative volume hotplug feature in KubeVirt. + When enabled, the "DeclarativeHotplugVolumes" feature gate is enabled in + the KubeVirt CR, instead of the "HotplugVolumes" feature gate. + When disabled, the "HotplugVolumes" feature gate is enabled (default + behavior). + Phase: Alpha + + * deployKubeSecondaryDNS: + Deploy KubeSecondaryDNS by CNAO + Phase: Alpha + + * disableMDevConfiguration: + Disable mediated devices handling on KubeVirt + Phase: Alpha + + * downwardMetrics: + Allow to expose a limited set of host metrics to guests. + Phase: Alpha + + * enableMultiArchBootImageImport: + allows the HCO to run on heterogeneous clusters with different CPU + architectures. + Enabling this feature gate will allow the HCO to create Golden Images for + different CPU architectures. + Phase: Alpha + + * objectGraph: + enables the ObjectGraph VM and VMI subresource in KubeVirt. + This subresource returns a structured list of k8s objects that are related + to the specified VM or VMI, enabling better dependency tracking. + Phase: Alpha + + * persistentReservation: + Enable persistent reservation of a LUN through the SCSI Persistent Reserve + commands on Kubevirt. + In order to issue privileged SCSI ioctls, the VM requires activation of the + persistent reservation flag. + Once this feature gate is enabled, then the additional container with the + qemu-pr-helper is deployed inside the virt-handler pod. + Enabling (or removing) the feature gate causes the redeployment of the + virt-handler pod. + Phase: Alpha + + * videoConfig: + allows users to configure video device types for their virtual machines. + This can be useful for workloads that require specific video capabilities + or architectures. + Phase: Beta + + * autoResourceLimits: + Phase: Deprecated + + * deployKubevirtIpamController: + Phase: Deprecated + + * deployTektonTaskResources: + Phase: Deprecated + + * deployVmConsoleProxy: + Phase: Deprecated + + * enableApplicationAwareQuota: + This feature gate is ignored. Use spec.enableApplicationAwareQuota field instead + Phase: Deprecated + + * enableCommonBootImageImport: + This feature gate is ignored. Use spec.enableCommonBootImageImport field instead + Phase: Deprecated + + * enableManagedTenantQuota: + Phase: Deprecated + + * nonRoot: + Phase: Deprecated + + * primaryUserDefinedNetworkBinding: + Phase: Deprecated + + * withHostPassthroughCPU: + Phase: Deprecated + items: + description: FeatureGate is an optional feature gate to enable or + disable a new feature that is not generally available yet. + properties: + name: + description: Name is the feature gate name + type: string + state: + description: State determines if the feature gate is enabled + ("Enabled"), or disabled ("False"). The default value is "Disabled". + enum: + - Enabled + - Disabled + type: string + required: + - name + type: object + type: array + filesystemOverhead: + description: |- + FilesystemOverhead describes the space reserved for overhead when using Filesystem volumes. + A value is between 0 and 1, if not defined it is 0.055 (5.5 percent overhead) + properties: + global: + description: Global is how much space of a Filesystem volume should + be reserved for overhead. This value is used unless overridden + by a more specific value (per storageClass) + pattern: ^(0(?:\.\d{1,3})?|1)$ + type: string + storageClass: + additionalProperties: + description: |- + Percent is a string that can only be a value between [0,1) + (Note: we actually rely on reconcile to reject invalid values) + pattern: ^(0(?:\.\d{1,3})?|1)$ + type: string + description: StorageClass specifies how much space of a Filesystem + volume should be reserved for safety. The keys are the storageClass + and the values are the overhead. This value overrides the global + value + type: object + type: object + higherWorkloadDensity: + default: + memoryOvercommitPercentage: 100 + description: HigherWorkloadDensity holds configuration aimed to increase + virtual machine density + properties: + memoryOvercommitPercentage: + default: 100 + description: |- + MemoryOvercommitPercentage is the percentage of memory we want to give VMIs compared to the amount + given to its parent pod (virt-launcher). For example, a value of 102 means the VMI will + "see" 2% more memory than its parent pod. Values under 100 are effectively "undercommits". + Overcommits can lead to memory exhaustion, which in turn can lead to crashes. Use carefully. + minimum: 10 + type: integer + type: object + infra: + description: |- + infra HyperConvergedConfig influences the pod configuration (currently only placement) + for all the infra components needed on the virtualization enabled cluster + but not necessarily directly on each node running VMs/VMIs. + properties: + nodePlacement: + description: NodePlacement describes node scheduling configuration. + properties: + affinity: + description: |- + affinity enables pod affinity/anti-affinity placement expanding the types of constraints + that can be expressed with nodeSelector. + affinity is going to be applied to the relevant kind of pods in parallel with nodeSelector + See https://kubernetes.io/docs/concepts/scheduling-eviction/assign-pod-node/#affinity-and-anti-affinity + properties: + nodeAffinity: + description: Describes node affinity scheduling rules + for the pod. + properties: + preferredDuringSchedulingIgnoredDuringExecution: + description: |- + The scheduler will prefer to schedule pods to nodes that satisfy + the affinity expressions specified by this field, but it may choose + a node that violates one or more of the expressions. The node that is + most preferred is the one with the greatest sum of weights, i.e. + for each node that meets all of the scheduling requirements (resource + request, requiredDuringScheduling affinity expressions, etc.), + compute a sum by iterating through the elements of this field and adding + "weight" to the sum if the node matches the corresponding matchExpressions; the + node(s) with the highest sum are the most preferred. + items: + description: |- + An empty preferred scheduling term matches all objects with implicit weight 0 + (i.e. it's a no-op). A null preferred scheduling term matches no objects (i.e. is also a no-op). + properties: + preference: + description: A node selector term, associated + with the corresponding weight. + properties: + matchExpressions: + description: A list of node selector requirements + by node's labels. + items: + description: |- + A node selector requirement is a selector that contains values, a key, and an operator + that relates the key and values. + properties: + key: + description: The label key that the + selector applies to. + type: string + operator: + description: |- + Represents a key's relationship to a set of values. + Valid operators are In, NotIn, Exists, DoesNotExist. Gt, and Lt. + type: string + values: + description: |- + An array of string values. If the operator is In or NotIn, + the values array must be non-empty. If the operator is Exists or DoesNotExist, + the values array must be empty. If the operator is Gt or Lt, the values + array must have a single element, which will be interpreted as an integer. + This array is replaced during a strategic merge patch. + items: + type: string + type: array + x-kubernetes-list-type: atomic + required: + - key + - operator + type: object + type: array + x-kubernetes-list-type: atomic + matchFields: + description: A list of node selector requirements + by node's fields. + items: + description: |- + A node selector requirement is a selector that contains values, a key, and an operator + that relates the key and values. + properties: + key: + description: The label key that the + selector applies to. + type: string + operator: + description: |- + Represents a key's relationship to a set of values. + Valid operators are In, NotIn, Exists, DoesNotExist. Gt, and Lt. + type: string + values: + description: |- + An array of string values. If the operator is In or NotIn, + the values array must be non-empty. If the operator is Exists or DoesNotExist, + the values array must be empty. If the operator is Gt or Lt, the values + array must have a single element, which will be interpreted as an integer. + This array is replaced during a strategic merge patch. + items: + type: string + type: array + x-kubernetes-list-type: atomic + required: + - key + - operator + type: object + type: array + x-kubernetes-list-type: atomic + type: object + x-kubernetes-map-type: atomic + weight: + description: Weight associated with matching + the corresponding nodeSelectorTerm, in the + range 1-100. + format: int32 + type: integer + required: + - preference + - weight + type: object + type: array + x-kubernetes-list-type: atomic + requiredDuringSchedulingIgnoredDuringExecution: + description: |- + If the affinity requirements specified by this field are not met at + scheduling time, the pod will not be scheduled onto the node. + If the affinity requirements specified by this field cease to be met + at some point during pod execution (e.g. due to an update), the system + may or may not try to eventually evict the pod from its node. + properties: + nodeSelectorTerms: + description: Required. A list of node selector + terms. The terms are ORed. + items: + description: |- + A null or empty node selector term matches no objects. The requirements of + them are ANDed. + The TopologySelectorTerm type implements a subset of the NodeSelectorTerm. + properties: + matchExpressions: + description: A list of node selector requirements + by node's labels. + items: + description: |- + A node selector requirement is a selector that contains values, a key, and an operator + that relates the key and values. + properties: + key: + description: The label key that the + selector applies to. + type: string + operator: + description: |- + Represents a key's relationship to a set of values. + Valid operators are In, NotIn, Exists, DoesNotExist. Gt, and Lt. + type: string + values: + description: |- + An array of string values. If the operator is In or NotIn, + the values array must be non-empty. If the operator is Exists or DoesNotExist, + the values array must be empty. If the operator is Gt or Lt, the values + array must have a single element, which will be interpreted as an integer. + This array is replaced during a strategic merge patch. + items: + type: string + type: array + x-kubernetes-list-type: atomic + required: + - key + - operator + type: object + type: array + x-kubernetes-list-type: atomic + matchFields: + description: A list of node selector requirements + by node's fields. + items: + description: |- + A node selector requirement is a selector that contains values, a key, and an operator + that relates the key and values. + properties: + key: + description: The label key that the + selector applies to. + type: string + operator: + description: |- + Represents a key's relationship to a set of values. + Valid operators are In, NotIn, Exists, DoesNotExist. Gt, and Lt. + type: string + values: + description: |- + An array of string values. If the operator is In or NotIn, + the values array must be non-empty. If the operator is Exists or DoesNotExist, + the values array must be empty. If the operator is Gt or Lt, the values + array must have a single element, which will be interpreted as an integer. + This array is replaced during a strategic merge patch. + items: + type: string + type: array + x-kubernetes-list-type: atomic + required: + - key + - operator + type: object + type: array + x-kubernetes-list-type: atomic + type: object + x-kubernetes-map-type: atomic + type: array + x-kubernetes-list-type: atomic + required: + - nodeSelectorTerms + type: object + x-kubernetes-map-type: atomic + type: object + podAffinity: + description: Describes pod affinity scheduling rules (e.g. + co-locate this pod in the same node, zone, etc. as some + other pod(s)). + properties: + preferredDuringSchedulingIgnoredDuringExecution: + description: |- + The scheduler will prefer to schedule pods to nodes that satisfy + the affinity expressions specified by this field, but it may choose + a node that violates one or more of the expressions. The node that is + most preferred is the one with the greatest sum of weights, i.e. + for each node that meets all of the scheduling requirements (resource + request, requiredDuringScheduling affinity expressions, etc.), + compute a sum by iterating through the elements of this field and adding + "weight" to the sum if the node has pods which matches the corresponding podAffinityTerm; the + node(s) with the highest sum are the most preferred. + items: + description: The weights of all of the matched WeightedPodAffinityTerm + fields are added per-node to find the most preferred + node(s) + properties: + podAffinityTerm: + description: Required. A pod affinity term, + associated with the corresponding weight. + properties: + labelSelector: + description: |- + A label query over a set of resources, in this case pods. + If it's null, this PodAffinityTerm matches with no Pods. + properties: + matchExpressions: + description: matchExpressions is a list + of label selector requirements. The + requirements are ANDed. + items: + description: |- + A label selector requirement is a selector that contains values, a key, and an operator that + relates the key and values. + properties: + key: + description: key is the label + key that the selector applies + to. + type: string + operator: + description: |- + operator represents a key's relationship to a set of values. + Valid operators are In, NotIn, Exists and DoesNotExist. + type: string + values: + description: |- + values is an array of string values. If the operator is In or NotIn, + the values array must be non-empty. If the operator is Exists or DoesNotExist, + the values array must be empty. This array is replaced during a strategic + merge patch. + items: + type: string + type: array + x-kubernetes-list-type: atomic + required: + - key + - operator + type: object + type: array + x-kubernetes-list-type: atomic + matchLabels: + additionalProperties: + type: string + description: |- + matchLabels is a map of {key,value} pairs. A single {key,value} in the matchLabels + map is equivalent to an element of matchExpressions, whose key field is "key", the + operator is "In", and the values array contains only "value". The requirements are ANDed. + type: object + type: object + x-kubernetes-map-type: atomic + matchLabelKeys: + description: |- + MatchLabelKeys is a set of pod label keys to select which pods will + be taken into consideration. The keys are used to lookup values from the + incoming pod labels, those key-value labels are merged with `labelSelector` as `key in (value)` + to select the group of existing pods which pods will be taken into consideration + for the incoming pod's pod (anti) affinity. Keys that don't exist in the incoming + pod labels will be ignored. The default value is empty. + The same key is forbidden to exist in both matchLabelKeys and labelSelector. + Also, matchLabelKeys cannot be set when labelSelector isn't set. + items: + type: string + type: array + x-kubernetes-list-type: atomic + mismatchLabelKeys: + description: |- + MismatchLabelKeys is a set of pod label keys to select which pods will + be taken into consideration. The keys are used to lookup values from the + incoming pod labels, those key-value labels are merged with `labelSelector` as `key notin (value)` + to select the group of existing pods which pods will be taken into consideration + for the incoming pod's pod (anti) affinity. Keys that don't exist in the incoming + pod labels will be ignored. The default value is empty. + The same key is forbidden to exist in both mismatchLabelKeys and labelSelector. + Also, mismatchLabelKeys cannot be set when labelSelector isn't set. + items: + type: string + type: array + x-kubernetes-list-type: atomic + namespaceSelector: + description: |- + A label query over the set of namespaces that the term applies to. + The term is applied to the union of the namespaces selected by this field + and the ones listed in the namespaces field. + null selector and null or empty namespaces list means "this pod's namespace". + An empty selector ({}) matches all namespaces. + properties: + matchExpressions: + description: matchExpressions is a list + of label selector requirements. The + requirements are ANDed. + items: + description: |- + A label selector requirement is a selector that contains values, a key, and an operator that + relates the key and values. + properties: + key: + description: key is the label + key that the selector applies + to. + type: string + operator: + description: |- + operator represents a key's relationship to a set of values. + Valid operators are In, NotIn, Exists and DoesNotExist. + type: string + values: + description: |- + values is an array of string values. If the operator is In or NotIn, + the values array must be non-empty. If the operator is Exists or DoesNotExist, + the values array must be empty. This array is replaced during a strategic + merge patch. + items: + type: string + type: array + x-kubernetes-list-type: atomic + required: + - key + - operator + type: object + type: array + x-kubernetes-list-type: atomic + matchLabels: + additionalProperties: + type: string + description: |- + matchLabels is a map of {key,value} pairs. A single {key,value} in the matchLabels + map is equivalent to an element of matchExpressions, whose key field is "key", the + operator is "In", and the values array contains only "value". The requirements are ANDed. + type: object + type: object + x-kubernetes-map-type: atomic + namespaces: + description: |- + namespaces specifies a static list of namespace names that the term applies to. + The term is applied to the union of the namespaces listed in this field + and the ones selected by namespaceSelector. + null or empty namespaces list and null namespaceSelector means "this pod's namespace". + items: + type: string + type: array + x-kubernetes-list-type: atomic + topologyKey: + description: |- + This pod should be co-located (affinity) or not co-located (anti-affinity) with the pods matching + the labelSelector in the specified namespaces, where co-located is defined as running on a node + whose value of the label with key topologyKey matches that of any node on which any of the + selected pods is running. + Empty topologyKey is not allowed. + type: string + required: + - topologyKey + type: object + weight: + description: |- + weight associated with matching the corresponding podAffinityTerm, + in the range 1-100. + format: int32 + type: integer + required: + - podAffinityTerm + - weight + type: object + type: array + x-kubernetes-list-type: atomic + requiredDuringSchedulingIgnoredDuringExecution: + description: |- + If the affinity requirements specified by this field are not met at + scheduling time, the pod will not be scheduled onto the node. + If the affinity requirements specified by this field cease to be met + at some point during pod execution (e.g. due to a pod label update), the + system may or may not try to eventually evict the pod from its node. + When there are multiple elements, the lists of nodes corresponding to each + podAffinityTerm are intersected, i.e. all terms must be satisfied. + items: + description: |- + Defines a set of pods (namely those matching the labelSelector + relative to the given namespace(s)) that this pod should be + co-located (affinity) or not co-located (anti-affinity) with, + where co-located is defined as running on a node whose value of + the label with key matches that of any node on which + a pod of the set of pods is running + properties: + labelSelector: + description: |- + A label query over a set of resources, in this case pods. + If it's null, this PodAffinityTerm matches with no Pods. + properties: + matchExpressions: + description: matchExpressions is a list + of label selector requirements. The requirements + are ANDed. + items: + description: |- + A label selector requirement is a selector that contains values, a key, and an operator that + relates the key and values. + properties: + key: + description: key is the label key + that the selector applies to. + type: string + operator: + description: |- + operator represents a key's relationship to a set of values. + Valid operators are In, NotIn, Exists and DoesNotExist. + type: string + values: + description: |- + values is an array of string values. If the operator is In or NotIn, + the values array must be non-empty. If the operator is Exists or DoesNotExist, + the values array must be empty. This array is replaced during a strategic + merge patch. + items: + type: string + type: array + x-kubernetes-list-type: atomic + required: + - key + - operator + type: object + type: array + x-kubernetes-list-type: atomic + matchLabels: + additionalProperties: + type: string + description: |- + matchLabels is a map of {key,value} pairs. A single {key,value} in the matchLabels + map is equivalent to an element of matchExpressions, whose key field is "key", the + operator is "In", and the values array contains only "value". The requirements are ANDed. + type: object + type: object + x-kubernetes-map-type: atomic + matchLabelKeys: + description: |- + MatchLabelKeys is a set of pod label keys to select which pods will + be taken into consideration. The keys are used to lookup values from the + incoming pod labels, those key-value labels are merged with `labelSelector` as `key in (value)` + to select the group of existing pods which pods will be taken into consideration + for the incoming pod's pod (anti) affinity. Keys that don't exist in the incoming + pod labels will be ignored. The default value is empty. + The same key is forbidden to exist in both matchLabelKeys and labelSelector. + Also, matchLabelKeys cannot be set when labelSelector isn't set. + items: + type: string + type: array + x-kubernetes-list-type: atomic + mismatchLabelKeys: + description: |- + MismatchLabelKeys is a set of pod label keys to select which pods will + be taken into consideration. The keys are used to lookup values from the + incoming pod labels, those key-value labels are merged with `labelSelector` as `key notin (value)` + to select the group of existing pods which pods will be taken into consideration + for the incoming pod's pod (anti) affinity. Keys that don't exist in the incoming + pod labels will be ignored. The default value is empty. + The same key is forbidden to exist in both mismatchLabelKeys and labelSelector. + Also, mismatchLabelKeys cannot be set when labelSelector isn't set. + items: + type: string + type: array + x-kubernetes-list-type: atomic + namespaceSelector: + description: |- + A label query over the set of namespaces that the term applies to. + The term is applied to the union of the namespaces selected by this field + and the ones listed in the namespaces field. + null selector and null or empty namespaces list means "this pod's namespace". + An empty selector ({}) matches all namespaces. + properties: + matchExpressions: + description: matchExpressions is a list + of label selector requirements. The requirements + are ANDed. + items: + description: |- + A label selector requirement is a selector that contains values, a key, and an operator that + relates the key and values. + properties: + key: + description: key is the label key + that the selector applies to. + type: string + operator: + description: |- + operator represents a key's relationship to a set of values. + Valid operators are In, NotIn, Exists and DoesNotExist. + type: string + values: + description: |- + values is an array of string values. If the operator is In or NotIn, + the values array must be non-empty. If the operator is Exists or DoesNotExist, + the values array must be empty. This array is replaced during a strategic + merge patch. + items: + type: string + type: array + x-kubernetes-list-type: atomic + required: + - key + - operator + type: object + type: array + x-kubernetes-list-type: atomic + matchLabels: + additionalProperties: + type: string + description: |- + matchLabels is a map of {key,value} pairs. A single {key,value} in the matchLabels + map is equivalent to an element of matchExpressions, whose key field is "key", the + operator is "In", and the values array contains only "value". The requirements are ANDed. + type: object + type: object + x-kubernetes-map-type: atomic + namespaces: + description: |- + namespaces specifies a static list of namespace names that the term applies to. + The term is applied to the union of the namespaces listed in this field + and the ones selected by namespaceSelector. + null or empty namespaces list and null namespaceSelector means "this pod's namespace". + items: + type: string + type: array + x-kubernetes-list-type: atomic + topologyKey: + description: |- + This pod should be co-located (affinity) or not co-located (anti-affinity) with the pods matching + the labelSelector in the specified namespaces, where co-located is defined as running on a node + whose value of the label with key topologyKey matches that of any node on which any of the + selected pods is running. + Empty topologyKey is not allowed. + type: string + required: + - topologyKey + type: object + type: array + x-kubernetes-list-type: atomic + type: object + podAntiAffinity: + description: Describes pod anti-affinity scheduling rules + (e.g. avoid putting this pod in the same node, zone, + etc. as some other pod(s)). + properties: + preferredDuringSchedulingIgnoredDuringExecution: + description: |- + The scheduler will prefer to schedule pods to nodes that satisfy + the anti-affinity expressions specified by this field, but it may choose + a node that violates one or more of the expressions. The node that is + most preferred is the one with the greatest sum of weights, i.e. + for each node that meets all of the scheduling requirements (resource + request, requiredDuringScheduling anti-affinity expressions, etc.), + compute a sum by iterating through the elements of this field and subtracting + "weight" from the sum if the node has pods which matches the corresponding podAffinityTerm; the + node(s) with the highest sum are the most preferred. + items: + description: The weights of all of the matched WeightedPodAffinityTerm + fields are added per-node to find the most preferred + node(s) + properties: + podAffinityTerm: + description: Required. A pod affinity term, + associated with the corresponding weight. + properties: + labelSelector: + description: |- + A label query over a set of resources, in this case pods. + If it's null, this PodAffinityTerm matches with no Pods. + properties: + matchExpressions: + description: matchExpressions is a list + of label selector requirements. The + requirements are ANDed. + items: + description: |- + A label selector requirement is a selector that contains values, a key, and an operator that + relates the key and values. + properties: + key: + description: key is the label + key that the selector applies + to. + type: string + operator: + description: |- + operator represents a key's relationship to a set of values. + Valid operators are In, NotIn, Exists and DoesNotExist. + type: string + values: + description: |- + values is an array of string values. If the operator is In or NotIn, + the values array must be non-empty. If the operator is Exists or DoesNotExist, + the values array must be empty. This array is replaced during a strategic + merge patch. + items: + type: string + type: array + x-kubernetes-list-type: atomic + required: + - key + - operator + type: object + type: array + x-kubernetes-list-type: atomic + matchLabels: + additionalProperties: + type: string + description: |- + matchLabels is a map of {key,value} pairs. A single {key,value} in the matchLabels + map is equivalent to an element of matchExpressions, whose key field is "key", the + operator is "In", and the values array contains only "value". The requirements are ANDed. + type: object + type: object + x-kubernetes-map-type: atomic + matchLabelKeys: + description: |- + MatchLabelKeys is a set of pod label keys to select which pods will + be taken into consideration. The keys are used to lookup values from the + incoming pod labels, those key-value labels are merged with `labelSelector` as `key in (value)` + to select the group of existing pods which pods will be taken into consideration + for the incoming pod's pod (anti) affinity. Keys that don't exist in the incoming + pod labels will be ignored. The default value is empty. + The same key is forbidden to exist in both matchLabelKeys and labelSelector. + Also, matchLabelKeys cannot be set when labelSelector isn't set. + items: + type: string + type: array + x-kubernetes-list-type: atomic + mismatchLabelKeys: + description: |- + MismatchLabelKeys is a set of pod label keys to select which pods will + be taken into consideration. The keys are used to lookup values from the + incoming pod labels, those key-value labels are merged with `labelSelector` as `key notin (value)` + to select the group of existing pods which pods will be taken into consideration + for the incoming pod's pod (anti) affinity. Keys that don't exist in the incoming + pod labels will be ignored. The default value is empty. + The same key is forbidden to exist in both mismatchLabelKeys and labelSelector. + Also, mismatchLabelKeys cannot be set when labelSelector isn't set. + items: + type: string + type: array + x-kubernetes-list-type: atomic + namespaceSelector: + description: |- + A label query over the set of namespaces that the term applies to. + The term is applied to the union of the namespaces selected by this field + and the ones listed in the namespaces field. + null selector and null or empty namespaces list means "this pod's namespace". + An empty selector ({}) matches all namespaces. + properties: + matchExpressions: + description: matchExpressions is a list + of label selector requirements. The + requirements are ANDed. + items: + description: |- + A label selector requirement is a selector that contains values, a key, and an operator that + relates the key and values. + properties: + key: + description: key is the label + key that the selector applies + to. + type: string + operator: + description: |- + operator represents a key's relationship to a set of values. + Valid operators are In, NotIn, Exists and DoesNotExist. + type: string + values: + description: |- + values is an array of string values. If the operator is In or NotIn, + the values array must be non-empty. If the operator is Exists or DoesNotExist, + the values array must be empty. This array is replaced during a strategic + merge patch. + items: + type: string + type: array + x-kubernetes-list-type: atomic + required: + - key + - operator + type: object + type: array + x-kubernetes-list-type: atomic + matchLabels: + additionalProperties: + type: string + description: |- + matchLabels is a map of {key,value} pairs. A single {key,value} in the matchLabels + map is equivalent to an element of matchExpressions, whose key field is "key", the + operator is "In", and the values array contains only "value". The requirements are ANDed. + type: object + type: object + x-kubernetes-map-type: atomic + namespaces: + description: |- + namespaces specifies a static list of namespace names that the term applies to. + The term is applied to the union of the namespaces listed in this field + and the ones selected by namespaceSelector. + null or empty namespaces list and null namespaceSelector means "this pod's namespace". + items: + type: string + type: array + x-kubernetes-list-type: atomic + topologyKey: + description: |- + This pod should be co-located (affinity) or not co-located (anti-affinity) with the pods matching + the labelSelector in the specified namespaces, where co-located is defined as running on a node + whose value of the label with key topologyKey matches that of any node on which any of the + selected pods is running. + Empty topologyKey is not allowed. + type: string + required: + - topologyKey + type: object + weight: + description: |- + weight associated with matching the corresponding podAffinityTerm, + in the range 1-100. + format: int32 + type: integer + required: + - podAffinityTerm + - weight + type: object + type: array + x-kubernetes-list-type: atomic + requiredDuringSchedulingIgnoredDuringExecution: + description: |- + If the anti-affinity requirements specified by this field are not met at + scheduling time, the pod will not be scheduled onto the node. + If the anti-affinity requirements specified by this field cease to be met + at some point during pod execution (e.g. due to a pod label update), the + system may or may not try to eventually evict the pod from its node. + When there are multiple elements, the lists of nodes corresponding to each + podAffinityTerm are intersected, i.e. all terms must be satisfied. + items: + description: |- + Defines a set of pods (namely those matching the labelSelector + relative to the given namespace(s)) that this pod should be + co-located (affinity) or not co-located (anti-affinity) with, + where co-located is defined as running on a node whose value of + the label with key matches that of any node on which + a pod of the set of pods is running + properties: + labelSelector: + description: |- + A label query over a set of resources, in this case pods. + If it's null, this PodAffinityTerm matches with no Pods. + properties: + matchExpressions: + description: matchExpressions is a list + of label selector requirements. The requirements + are ANDed. + items: + description: |- + A label selector requirement is a selector that contains values, a key, and an operator that + relates the key and values. + properties: + key: + description: key is the label key + that the selector applies to. + type: string + operator: + description: |- + operator represents a key's relationship to a set of values. + Valid operators are In, NotIn, Exists and DoesNotExist. + type: string + values: + description: |- + values is an array of string values. If the operator is In or NotIn, + the values array must be non-empty. If the operator is Exists or DoesNotExist, + the values array must be empty. This array is replaced during a strategic + merge patch. + items: + type: string + type: array + x-kubernetes-list-type: atomic + required: + - key + - operator + type: object + type: array + x-kubernetes-list-type: atomic + matchLabels: + additionalProperties: + type: string + description: |- + matchLabels is a map of {key,value} pairs. A single {key,value} in the matchLabels + map is equivalent to an element of matchExpressions, whose key field is "key", the + operator is "In", and the values array contains only "value". The requirements are ANDed. + type: object + type: object + x-kubernetes-map-type: atomic + matchLabelKeys: + description: |- + MatchLabelKeys is a set of pod label keys to select which pods will + be taken into consideration. The keys are used to lookup values from the + incoming pod labels, those key-value labels are merged with `labelSelector` as `key in (value)` + to select the group of existing pods which pods will be taken into consideration + for the incoming pod's pod (anti) affinity. Keys that don't exist in the incoming + pod labels will be ignored. The default value is empty. + The same key is forbidden to exist in both matchLabelKeys and labelSelector. + Also, matchLabelKeys cannot be set when labelSelector isn't set. + items: + type: string + type: array + x-kubernetes-list-type: atomic + mismatchLabelKeys: + description: |- + MismatchLabelKeys is a set of pod label keys to select which pods will + be taken into consideration. The keys are used to lookup values from the + incoming pod labels, those key-value labels are merged with `labelSelector` as `key notin (value)` + to select the group of existing pods which pods will be taken into consideration + for the incoming pod's pod (anti) affinity. Keys that don't exist in the incoming + pod labels will be ignored. The default value is empty. + The same key is forbidden to exist in both mismatchLabelKeys and labelSelector. + Also, mismatchLabelKeys cannot be set when labelSelector isn't set. + items: + type: string + type: array + x-kubernetes-list-type: atomic + namespaceSelector: + description: |- + A label query over the set of namespaces that the term applies to. + The term is applied to the union of the namespaces selected by this field + and the ones listed in the namespaces field. + null selector and null or empty namespaces list means "this pod's namespace". + An empty selector ({}) matches all namespaces. + properties: + matchExpressions: + description: matchExpressions is a list + of label selector requirements. The requirements + are ANDed. + items: + description: |- + A label selector requirement is a selector that contains values, a key, and an operator that + relates the key and values. + properties: + key: + description: key is the label key + that the selector applies to. + type: string + operator: + description: |- + operator represents a key's relationship to a set of values. + Valid operators are In, NotIn, Exists and DoesNotExist. + type: string + values: + description: |- + values is an array of string values. If the operator is In or NotIn, + the values array must be non-empty. If the operator is Exists or DoesNotExist, + the values array must be empty. This array is replaced during a strategic + merge patch. + items: + type: string + type: array + x-kubernetes-list-type: atomic + required: + - key + - operator + type: object + type: array + x-kubernetes-list-type: atomic + matchLabels: + additionalProperties: + type: string + description: |- + matchLabels is a map of {key,value} pairs. A single {key,value} in the matchLabels + map is equivalent to an element of matchExpressions, whose key field is "key", the + operator is "In", and the values array contains only "value". The requirements are ANDed. + type: object + type: object + x-kubernetes-map-type: atomic + namespaces: + description: |- + namespaces specifies a static list of namespace names that the term applies to. + The term is applied to the union of the namespaces listed in this field + and the ones selected by namespaceSelector. + null or empty namespaces list and null namespaceSelector means "this pod's namespace". + items: + type: string + type: array + x-kubernetes-list-type: atomic + topologyKey: + description: |- + This pod should be co-located (affinity) or not co-located (anti-affinity) with the pods matching + the labelSelector in the specified namespaces, where co-located is defined as running on a node + whose value of the label with key topologyKey matches that of any node on which any of the + selected pods is running. + Empty topologyKey is not allowed. + type: string + required: + - topologyKey + type: object + type: array + x-kubernetes-list-type: atomic + type: object + type: object + nodeSelector: + additionalProperties: + type: string + description: |- + nodeSelector is the node selector applied to the relevant kind of pods + It specifies a map of key-value pairs: for the pod to be eligible to run on a node, + the node must have each of the indicated key-value pairs as labels + (it can have additional labels as well). + See https://kubernetes.io/docs/concepts/configuration/assign-pod-node/#nodeselector + type: object + tolerations: + description: |- + tolerations is a list of tolerations applied to the relevant kind of pods + See https://kubernetes.io/docs/concepts/configuration/taint-and-toleration/ for more info. + These are additional tolerations other than default ones. + items: + description: |- + The pod this Toleration is attached to tolerates any taint that matches + the triple using the matching operator . + properties: + effect: + description: |- + Effect indicates the taint effect to match. Empty means match all taint effects. + When specified, allowed values are NoSchedule, PreferNoSchedule and NoExecute. + type: string + key: + description: |- + Key is the taint key that the toleration applies to. Empty means match all taint keys. + If the key is empty, operator must be Exists; this combination means to match all values and all keys. + type: string + operator: + description: |- + Operator represents a key's relationship to the value. + Valid operators are Exists and Equal. Defaults to Equal. + Exists is equivalent to wildcard for value, so that a pod can + tolerate all taints of a particular category. + type: string + tolerationSeconds: + description: |- + TolerationSeconds represents the period of time the toleration (which must be + of effect NoExecute, otherwise this field is ignored) tolerates the taint. By default, + it is not set, which means tolerate the taint forever (do not evict). Zero and + negative values will be treated as 0 (evict immediately) by the system. + format: int64 + type: integer + value: + description: |- + Value is the taint value the toleration matches to. + If the operator is Exists, the value should be empty, otherwise just a regular string. + type: string + type: object + type: array + type: object + type: object + instancetypeConfig: + description: InstancetypeConfig holds the configuration of instance + type related functionality within KubeVirt. + properties: + referencePolicy: + description: |- + ReferencePolicy defines how an instance type or preference should be referenced by the VM after submission, supported values are: + reference (default) - Where a copy of the original object is stashed in a ControllerRevision and referenced by the VM. + expand - Where the instance type or preference are expanded into the VM if no revisionNames have been populated. + expandAll - Where the instance type or preference are expanded into the VM regardless of revisionNames previously being populated. + enum: + - reference + - expand + - expandAll + nullable: true + type: string + type: object + ksmConfiguration: + description: |- + KSMConfiguration holds the information regarding + the enabling the KSM in the nodes (if available). + properties: + nodeLabelSelector: + description: |- + NodeLabelSelector is a selector that filters in which nodes the KSM will be enabled. + Empty NodeLabelSelector will enable ksm for every node. + properties: + matchExpressions: + description: matchExpressions is a list of label selector + requirements. The requirements are ANDed. + items: + description: |- + A label selector requirement is a selector that contains values, a key, and an operator that + relates the key and values. + properties: + key: + description: key is the label key that the selector + applies to. + type: string + operator: + description: |- + operator represents a key's relationship to a set of values. + Valid operators are In, NotIn, Exists and DoesNotExist. + type: string + values: + description: |- + values is an array of string values. If the operator is In or NotIn, + the values array must be non-empty. If the operator is Exists or DoesNotExist, + the values array must be empty. This array is replaced during a strategic + merge patch. + items: + type: string + type: array + x-kubernetes-list-type: atomic + required: + - key + - operator + type: object + type: array + x-kubernetes-list-type: atomic + matchLabels: + additionalProperties: + type: string + description: |- + matchLabels is a map of {key,value} pairs. A single {key,value} in the matchLabels + map is equivalent to an element of matchExpressions, whose key field is "key", the + operator is "In", and the values array contains only "value". The requirements are ANDed. + type: object + type: object + x-kubernetes-map-type: atomic + type: object + kubeMacPoolConfiguration: + description: KubeMacPoolConfiguration holds kubemacpool MAC address + range configuration. + properties: + rangeEnd: + description: |- + RangeEnd defines the last MAC address in the kubemacpool range. + The MAC address format should be AA:BB:CC:DD:EE:FF. + pattern: ^([0-9a-fA-F]{2}:){5}[0-9a-fA-F]{2}$ + type: string + rangeStart: + description: |- + RangeStart defines the first MAC address in the kubemacpool range. + The MAC address format should be AA:BB:CC:DD:EE:FF. + pattern: ^([0-9a-fA-F]{2}:){5}[0-9a-fA-F]{2}$ + type: string + type: object + x-kubernetes-validations: + - message: both rangeStart and rangeEnd must be configured together, + or both omitted + rule: (has(self.rangeStart) && has(self.rangeEnd)) || (!has(self.rangeStart) + && !has(self.rangeEnd)) + kubeSecondaryDNSNameServerIP: + description: KubeSecondaryDNSNameServerIP defines name server IP used + by KubeSecondaryDNS + type: string + liveMigrationConfig: + default: + allowAutoConverge: false + allowPostCopy: false + completionTimeoutPerGiB: 150 + parallelMigrationsPerCluster: 5 + parallelOutboundMigrationsPerNode: 2 + progressTimeout: 150 + description: |- + Live migration limits and timeouts are applied so that migration processes do not + overwhelm the cluster. + properties: + allowAutoConverge: + default: false + description: |- + AllowAutoConverge allows the platform to compromise performance/availability of VMIs to + guarantee successful VMI live migrations. Defaults to false + type: boolean + allowPostCopy: + default: false + description: |- + When enabled, KubeVirt attempts to use post-copy live-migration in case it + reaches its completion timeout while attempting pre-copy live-migration. + Post-copy migrations allow even the busiest VMs to successfully live-migrate. + However, events like a network failure or a failure in any of the source or + destination nodes can cause the migrated VM to crash or reach inconsistency. + Enable this option when evicting nodes is more important than keeping VMs + alive. + Defaults to false. + type: boolean + bandwidthPerMigration: + description: Bandwidth limit of each migration, the value is quantity + of bytes per second (e.g. 2048Mi = 2048MiB/sec) + pattern: ^(\+|-)?(([0-9]+(\.[0-9]*)?)|(\.[0-9]+))(([KMGTPE]i)|[numkMGTPE]|([eE](\+|-)?(([0-9]+(\.[0-9]*)?)|(\.[0-9]+))))?$ + type: string + completionTimeoutPerGiB: + default: 150 + description: |- + If a migrating VM is big and busy, while the connection to the destination node + is slow, migration may never converge. The completion timeout is calculated + based on completionTimeoutPerGiB times the size of the guest (both RAM and + migrated disks, if any). For example, with completionTimeoutPerGiB set to 800, + a virtual machine instance with 6GiB memory will timeout if it has not + completed migration in 1h20m. Use a lower completionTimeoutPerGiB to induce + quicker failure, so that another destination or post-copy is attempted. Use a + higher completionTimeoutPerGiB to let workload with spikes in its memory dirty + rate to converge. + The format is a number. + format: int64 + type: integer + network: + description: The migrations will be performed over a dedicated + multus network to minimize disruption to tenant workloads due + to network saturation when VM live migrations are triggered. + type: string + parallelMigrationsPerCluster: + default: 5 + description: Number of migrations running in parallel in the cluster. + format: int32 + type: integer + parallelOutboundMigrationsPerNode: + default: 2 + description: Maximum number of outbound migrations per node. + format: int32 + type: integer + progressTimeout: + default: 150 + description: The migration will be canceled if memory copy fails + to make progress in this time, in seconds. + format: int64 + type: integer + type: object + liveUpdateConfiguration: + description: |- + LiveUpdateConfiguration holds the cluster configuration for live update of virtual machines - max cpu sockets, + max guest memory and max hotplug ratio. This setting can affect VM CPU and memory settings. + properties: + maxCpuSockets: + description: |- + MaxCpuSockets provides a MaxSockets value for VMs that do not provide their own. + For VMs with more sockets than maximum the MaxSockets will be set to equal number of sockets. + format: int32 + type: integer + maxGuest: + anyOf: + - type: integer + - type: string + description: |- + MaxGuest defines the maximum amount memory that can be allocated + to the guest using hotplug. + pattern: ^(\+|-)?(([0-9]+(\.[0-9]*)?)|(\.[0-9]+))(([KMGTPE]i)|[numkMGTPE]|([eE](\+|-)?(([0-9]+(\.[0-9]*)?)|(\.[0-9]+))))?$ + x-kubernetes-int-or-string: true + maxHotplugRatio: + description: |- + MaxHotplugRatio is the ratio used to define the max amount + of a hotplug resource that can be made available to a VM + when the specific Max* setting is not defined (MaxCpuSockets, MaxGuest) + Example: VM is configured with 512Mi of guest memory, if MaxGuest is not + defined and MaxHotplugRatio is 2 then MaxGuest = 1Gi + defaults to 4 + format: int32 + type: integer + type: object + logVerbosityConfig: + description: |- + LogVerbosityConfig configures the verbosity level of Kubevirt's different components. The higher + the value - the higher the log verbosity. + properties: + cdi: + description: CDI indicates the log verbosity level that controls + the amount of information logged for CDI components. + format: int32 + type: integer + kubevirt: + description: |- + Kubevirt is a struct that allows specifying the log verbosity level that controls the amount of information + logged for each Kubevirt component. + properties: + nodeVerbosity: + additionalProperties: + type: integer + description: NodeVerbosity represents a map of nodes with + a specific verbosity level + type: object + virtAPI: + type: integer + virtController: + type: integer + virtHandler: + type: integer + virtLauncher: + type: integer + virtOperator: + type: integer + virtSynchronizationController: + type: integer + type: object + type: object + mediatedDevicesConfiguration: + description: MediatedDevicesConfiguration holds information about + MDEV types to be defined on nodes, if available + properties: + mediatedDeviceTypes: + items: + type: string + type: array + x-kubernetes-list-type: atomic + nodeMediatedDeviceTypes: + items: + description: NodeMediatedDeviceTypesConfig holds information + about MDEV types to be defined in a specific node that matches + the NodeSelector field. + properties: + mediatedDeviceTypes: + items: + type: string + type: array + x-kubernetes-list-type: atomic + nodeSelector: + additionalProperties: + type: string + description: |- + NodeSelector is a selector which must be true for the vmi to fit on a node. + Selector which must match a node's labels for the vmi to be scheduled on that node. + More info: https://kubernetes.io/docs/concepts/configuration/assign-pod-node/ + type: object + required: + - nodeSelector + type: object + type: array + x-kubernetes-list-type: atomic + type: object + networkBinding: + additionalProperties: + properties: + computeResourceOverhead: + description: |- + ComputeResourceOverhead specifies the resource overhead that should be added to the compute container when using the binding. + version: v1alphav1 + properties: + limits: + additionalProperties: + anyOf: + - type: integer + - type: string + pattern: ^(\+|-)?(([0-9]+(\.[0-9]*)?)|(\.[0-9]+))(([KMGTPE]i)|[numkMGTPE]|([eE](\+|-)?(([0-9]+(\.[0-9]*)?)|(\.[0-9]+))))?$ + x-kubernetes-int-or-string: true + description: |- + Limits describes the maximum amount of compute resources allowed. + More info: https://kubernetes.io/docs/concepts/configuration/manage-resources-containers/ + type: object + requests: + additionalProperties: + anyOf: + - type: integer + - type: string + pattern: ^(\+|-)?(([0-9]+(\.[0-9]*)?)|(\.[0-9]+))(([KMGTPE]i)|[numkMGTPE]|([eE](\+|-)?(([0-9]+(\.[0-9]*)?)|(\.[0-9]+))))?$ + x-kubernetes-int-or-string: true + description: |- + Requests describes the minimum amount of compute resources required. + If Requests is omitted for a container, it defaults to Limits if that is explicitly specified, + otherwise to an implementation-defined value. Requests cannot exceed Limits. + More info: https://kubernetes.io/docs/concepts/configuration/manage-resources-containers/ + type: object + type: object + domainAttachmentType: + description: |- + DomainAttachmentType is a standard domain network attachment method kubevirt supports. + Supported values: "tap", "managedTap" (since v1.4). + The standard domain attachment can be used instead or in addition to the sidecarImage. + version: 1alphav1 + type: string + downwardAPI: + description: |- + DownwardAPI specifies what kind of data should be exposed to the binding plugin sidecar. + Supported values: "device-info" + version: v1alphav1 + type: string + migration: + description: |- + Migration means the VM using the plugin can be safely migrated + version: 1alphav1 + properties: + method: + description: |- + Method defines a pre-defined migration methodology + version: 1alphav1 + type: string + type: object + networkAttachmentDefinition: + description: |- + NetworkAttachmentDefinition references to a NetworkAttachmentDefinition CR object. + Format: , /. + If namespace is not specified, VMI namespace is assumed. + version: 1alphav1 + type: string + sidecarImage: + description: |- + SidecarImage references a container image that runs in the virt-launcher pod. + The sidecar handles (libvirt) domain configuration and optional services. + version: 1alphav1 + type: string + type: object + description: |- + NetworkBinding defines the network binding plugins. + Those bindings can be used when defining virtual machine interfaces. + type: object + obsoleteCPUs: + description: ObsoleteCPUs allows avoiding scheduling of VMs for obsolete + CPU models + properties: + cpuModels: + description: |- + CPUModels is a list of obsolete CPU models. When the node-labeller obtains the list of obsolete CPU models, it + eliminates those CPU models and creates labels for valid CPU models. + The default values for this field is nil, however, HCO uses opinionated values, and adding values to this list + will add them to the opinionated values. + items: + type: string + type: array + x-kubernetes-list-type: set + type: object + permittedHostDevices: + description: PermittedHostDevices holds information about devices + allowed for passthrough + properties: + mediatedDevices: + items: + description: MediatedHostDevice represents a host mediated device + allowed for passthrough + properties: + disabled: + description: |- + HCO enforces the existence of several MediatedHostDevice objects. Set disabled field to true instead of remove + these objects. + type: boolean + externalResourceProvider: + description: indicates that this resource is being provided + by an external device plugin + type: boolean + mdevNameSelector: + description: name of a mediated device type required to + identify a mediated device on a host + type: string + resourceName: + description: name by which a device is advertised and being + requested + type: string + required: + - mdevNameSelector + - resourceName + type: object + type: array + x-kubernetes-list-map-keys: + - mdevNameSelector + x-kubernetes-list-type: map + pciHostDevices: + items: + description: PciHostDevice represents a host PCI device allowed + for passthrough + properties: + disabled: + description: |- + HCO enforces the existence of several PciHostDevice objects. Set disabled field to true instead of remove + these objects. + type: boolean + externalResourceProvider: + description: indicates that this resource is being provided + by an external device plugin + type: boolean + pciDeviceSelector: + description: a combination of a vendor_id:product_id required + to identify a PCI device on a host. + type: string + resourceName: + description: name by which a device is advertised and being + requested + type: string + required: + - pciDeviceSelector + - resourceName + type: object + type: array + x-kubernetes-list-map-keys: + - pciDeviceSelector + x-kubernetes-list-type: map + usbHostDevices: + items: + description: USBHostDevice represents a host USB device allowed + for passthrough + properties: + disabled: + description: |- + HCO enforces the existence of several USBHostDevice objects. Set disabled field to true instead of remove + these objects. + type: boolean + externalResourceProvider: + description: |- + If true, KubeVirt will leave the allocation and monitoring to an + external device plugin + type: boolean + resourceName: + description: |- + Identifies the list of USB host devices. + e.g: kubevirt.io/storage, kubevirt.io/bootable-usb, etc + type: string + selectors: + items: + description: USBSelector represents a selector for a USB + device allowed for passthrough + properties: + product: + type: string + vendor: + type: string + required: + - product + - vendor + type: object + type: array + x-kubernetes-list-type: atomic + required: + - resourceName + type: object + type: array + x-kubernetes-list-map-keys: + - resourceName + x-kubernetes-list-type: map + type: object + resourceRequirements: + default: + vmiCPUAllocationRatio: 10 + description: ResourceRequirements describes the resource requirements + for the operand workloads. + properties: + autoCPULimitNamespaceLabelSelector: + description: |- + When set, AutoCPULimitNamespaceLabelSelector will set a CPU limit on virt-launcher for VMIs running inside + namespaces that match the label selector. + The CPU limit will equal the number of requested vCPUs. + This setting does not apply to VMIs with dedicated CPUs. + properties: + matchExpressions: + description: matchExpressions is a list of label selector + requirements. The requirements are ANDed. + items: + description: |- + A label selector requirement is a selector that contains values, a key, and an operator that + relates the key and values. + properties: + key: + description: key is the label key that the selector + applies to. + type: string + operator: + description: |- + operator represents a key's relationship to a set of values. + Valid operators are In, NotIn, Exists and DoesNotExist. + type: string + values: + description: |- + values is an array of string values. If the operator is In or NotIn, + the values array must be non-empty. If the operator is Exists or DoesNotExist, + the values array must be empty. This array is replaced during a strategic + merge patch. + items: + type: string + type: array + x-kubernetes-list-type: atomic + required: + - key + - operator + type: object + type: array + x-kubernetes-list-type: atomic + matchLabels: + additionalProperties: + type: string + description: |- + matchLabels is a map of {key,value} pairs. A single {key,value} in the matchLabels + map is equivalent to an element of matchExpressions, whose key field is "key", the + operator is "In", and the values array contains only "value". The requirements are ANDed. + type: object + type: object + x-kubernetes-map-type: atomic + storageWorkloads: + description: |- + StorageWorkloads defines the resources requirements for storage workloads. It will propagate to the CDI custom + resource + properties: + claims: + description: |- + Claims lists the names of resources, defined in spec.resourceClaims, + that are used by this container. + + This field depends on the + DynamicResourceAllocation feature gate. + + This field is immutable. It can only be set for containers. + items: + description: ResourceClaim references one entry in PodSpec.ResourceClaims. + properties: + name: + description: |- + Name must match the name of one entry in pod.spec.resourceClaims of + the Pod where this field is used. It makes that resource available + inside a container. + type: string + request: + description: |- + Request is the name chosen for a request in the referenced claim. + If empty, everything from the claim is made available, otherwise + only the result of this request. + type: string + required: + - name + type: object + type: array + x-kubernetes-list-map-keys: + - name + x-kubernetes-list-type: map + limits: + additionalProperties: + anyOf: + - type: integer + - type: string + pattern: ^(\+|-)?(([0-9]+(\.[0-9]*)?)|(\.[0-9]+))(([KMGTPE]i)|[numkMGTPE]|([eE](\+|-)?(([0-9]+(\.[0-9]*)?)|(\.[0-9]+))))?$ + x-kubernetes-int-or-string: true + description: |- + Limits describes the maximum amount of compute resources allowed. + More info: https://kubernetes.io/docs/concepts/configuration/manage-resources-containers/ + type: object + requests: + additionalProperties: + anyOf: + - type: integer + - type: string + pattern: ^(\+|-)?(([0-9]+(\.[0-9]*)?)|(\.[0-9]+))(([KMGTPE]i)|[numkMGTPE]|([eE](\+|-)?(([0-9]+(\.[0-9]*)?)|(\.[0-9]+))))?$ + x-kubernetes-int-or-string: true + description: |- + Requests describes the minimum amount of compute resources required. + If Requests is omitted for a container, it defaults to Limits if that is explicitly specified, + otherwise to an implementation-defined value. Requests cannot exceed Limits. + More info: https://kubernetes.io/docs/concepts/configuration/manage-resources-containers/ + type: object + type: object + vmiCPUAllocationRatio: + default: 10 + description: |- + VmiCPUAllocationRatio defines, for each requested virtual CPU, + how much physical CPU to request per VMI from the + hosting node. The value is in fraction of a CPU thread (or + core on non-hyperthreaded nodes). + VMI POD CPU request = number of vCPUs * 1/vmiCPUAllocationRatio + For example, a value of 1 means 1 physical CPU thread per VMI CPU thread. + A value of 100 would be 1% of a physical thread allocated for each + requested VMI thread. + This option has no effect on VMIs that request dedicated CPUs. + Defaults to 10 + minimum: 1 + type: integer + type: object + x-kubernetes-validations: + - message: vmiCPUAllocationRatio must be greater than 0 + rule: '!has(self.vmiCPUAllocationRatio) || self.vmiCPUAllocationRatio + > 0' + scratchSpaceStorageClass: + description: |- + Override the storage class used for scratch space during transfer operations. The scratch space storage class + is determined in the following order: + value of scratchSpaceStorageClass, if that doesn't exist, use the default storage class, if there is no default + storage class, use the storage class of the DataVolume, if no storage class specified, use no storage class for + scratch space + type: string + storageImport: + description: StorageImport contains configuration for importing containerized + data + properties: + insecureRegistries: + description: |- + InsecureRegistries is a list of image registries URLs that are not secured. Setting an insecure registry URL + in this list allows pulling images from this registry. + items: + type: string + type: array + x-kubernetes-list-type: set + type: object + tlsSecurityProfile: + description: |- + TLSSecurityProfile specifies the settings for TLS connections to be propagated to all kubevirt-hyperconverged components. + If unset, the hyperconverged cluster operator will consume the value set on the APIServer CR on OCP/OKD or Intermediate if on vanilla k8s. + Note that only Old, Intermediate and Custom profiles are currently supported, and the maximum available + MinTLSVersions is VersionTLS12. + properties: + custom: + description: |- + custom is a user-defined TLS security profile. Be extremely careful using a custom + profile as invalid configurations can be catastrophic. An example custom profile + looks like this: + + ciphers: + + - ECDHE-ECDSA-CHACHA20-POLY1305 + + - ECDHE-RSA-CHACHA20-POLY1305 + + - ECDHE-RSA-AES128-GCM-SHA256 + + - ECDHE-ECDSA-AES128-GCM-SHA256 + + minTLSVersion: VersionTLS11 + nullable: true + properties: + ciphers: + description: |- + ciphers is used to specify the cipher algorithms that are negotiated + during the TLS handshake. Operators may remove entries their operands + do not support. For example, to use DES-CBC3-SHA (yaml): + + ciphers: + - DES-CBC3-SHA + items: + type: string + type: array + x-kubernetes-list-type: atomic + minTLSVersion: + description: |- + minTLSVersion is used to specify the minimal version of the TLS protocol + that is negotiated during the TLS handshake. For example, to use TLS + versions 1.1, 1.2 and 1.3 (yaml): + + minTLSVersion: VersionTLS11 + + NOTE: currently the highest minTLSVersion allowed is VersionTLS12 + enum: + - VersionTLS10 + - VersionTLS11 + - VersionTLS12 + - VersionTLS13 + type: string + type: object + intermediate: + description: |- + intermediate is a TLS security profile based on: + + https://wiki.mozilla.org/Security/Server_Side_TLS#Intermediate_compatibility_.28recommended.29 + + and looks like this (yaml): + + ciphers: + + - TLS_AES_128_GCM_SHA256 + + - TLS_AES_256_GCM_SHA384 + + - TLS_CHACHA20_POLY1305_SHA256 + + - ECDHE-ECDSA-AES128-GCM-SHA256 + + - ECDHE-RSA-AES128-GCM-SHA256 + + - ECDHE-ECDSA-AES256-GCM-SHA384 + + - ECDHE-RSA-AES256-GCM-SHA384 + + - ECDHE-ECDSA-CHACHA20-POLY1305 + + - ECDHE-RSA-CHACHA20-POLY1305 + + - DHE-RSA-AES128-GCM-SHA256 + + - DHE-RSA-AES256-GCM-SHA384 + + minTLSVersion: VersionTLS12 + nullable: true + type: object + modern: + description: |- + modern is a TLS security profile based on: + + https://wiki.mozilla.org/Security/Server_Side_TLS#Modern_compatibility + + and looks like this (yaml): + + ciphers: + + - TLS_AES_128_GCM_SHA256 + + - TLS_AES_256_GCM_SHA384 + + - TLS_CHACHA20_POLY1305_SHA256 + + minTLSVersion: VersionTLS13 + nullable: true + type: object + old: + description: |- + old is a TLS security profile based on: + + https://wiki.mozilla.org/Security/Server_Side_TLS#Old_backward_compatibility + + and looks like this (yaml): + + ciphers: + + - TLS_AES_128_GCM_SHA256 + + - TLS_AES_256_GCM_SHA384 + + - TLS_CHACHA20_POLY1305_SHA256 + + - ECDHE-ECDSA-AES128-GCM-SHA256 + + - ECDHE-RSA-AES128-GCM-SHA256 + + - ECDHE-ECDSA-AES256-GCM-SHA384 + + - ECDHE-RSA-AES256-GCM-SHA384 + + - ECDHE-ECDSA-CHACHA20-POLY1305 + + - ECDHE-RSA-CHACHA20-POLY1305 + + - DHE-RSA-AES128-GCM-SHA256 + + - DHE-RSA-AES256-GCM-SHA384 + + - DHE-RSA-CHACHA20-POLY1305 + + - ECDHE-ECDSA-AES128-SHA256 + + - ECDHE-RSA-AES128-SHA256 + + - ECDHE-ECDSA-AES128-SHA + + - ECDHE-RSA-AES128-SHA + + - ECDHE-ECDSA-AES256-SHA384 + + - ECDHE-RSA-AES256-SHA384 + + - ECDHE-ECDSA-AES256-SHA + + - ECDHE-RSA-AES256-SHA + + - DHE-RSA-AES128-SHA256 + + - DHE-RSA-AES256-SHA256 + + - AES128-GCM-SHA256 + + - AES256-GCM-SHA384 + + - AES128-SHA256 + + - AES256-SHA256 + + - AES128-SHA + + - AES256-SHA + + - DES-CBC3-SHA + + minTLSVersion: VersionTLS10 + nullable: true + type: object + type: + description: |- + type is one of Old, Intermediate, Modern or Custom. Custom provides + the ability to specify individual TLS security profile parameters. + Old, Intermediate and Modern are TLS security profiles based on: + + https://wiki.mozilla.org/Security/Server_Side_TLS#Recommended_configurations + + The profiles are intent based, so they may change over time as new ciphers are developed and existing ciphers + are found to be insecure. Depending on precisely which ciphers are available to a process, the list may be + reduced. + + Note that the Modern profile is currently not supported because it is not + yet well adopted by common software libraries. + enum: + - Old + - Intermediate + - Modern + - Custom + type: string + type: object + tuningPolicy: + description: |- + TuningPolicy allows to configure the mode in which the RateLimits of kubevirt are set. + If TuningPolicy is not present the default kubevirt values are used. + It can be set to `annotation` for fine-tuning the kubevirt queryPerSeconds (qps) and burst values. + Qps and burst values are taken from the annotation hco.kubevirt.io/tuningPolicy + enum: + - annotation + - highBurst + type: string + uninstallStrategy: + default: BlockUninstallIfWorkloadsExist + description: |- + UninstallStrategy defines how to proceed on uninstall when workloads (VirtualMachines, DataVolumes) still exist. + BlockUninstallIfWorkloadsExist will prevent the CR from being removed when workloads still exist. + BlockUninstallIfWorkloadsExist is the safest choice to protect your workloads from accidental data loss, so it's strongly advised. + RemoveWorkloads will cause all the workloads to be cascading deleted on uninstallation. + WARNING: please notice that RemoveWorkloads will cause your workloads to be deleted as soon as this CR will be, even accidentally, deleted. + Please correctly consider the implications of this option before setting it. + BlockUninstallIfWorkloadsExist is the default behaviour. + enum: + - RemoveWorkloads + - BlockUninstallIfWorkloadsExist + type: string + virtualMachineOptions: + default: + disableFreePageReporting: false + disableSerialConsoleLog: false + description: VirtualMachineOptions holds the cluster level information + regarding the virtual machine. + properties: + disableFreePageReporting: + default: false + description: |- + DisableFreePageReporting disable the free page reporting of + memory balloon device https://libvirt.org/formatdomain.html#memory-balloon-device. + This will have effect only if AutoattachMemBalloon is not false and the vmi is not + requesting any high performance feature (dedicatedCPU/realtime/hugePages), in which free page reporting is always disabled. + type: boolean + disableSerialConsoleLog: + default: false + description: |- + DisableSerialConsoleLog disables logging the auto-attached default serial console. + If not set, serial console logs will be written to a file and then streamed from a container named `guest-console-log`. + The value can be individually overridden for each VM, not relevant if AutoattachSerialConsole is disabled for the VM. + type: boolean + type: object + vmStateStorageClass: + description: VMStateStorageClass is the name of the storage class + to use for the PVCs created to preserve VM state, like TPM. + type: string + workloadUpdateStrategy: + default: + batchEvictionInterval: 1m0s + batchEvictionSize: 10 + workloadUpdateMethods: + - LiveMigrate + description: WorkloadUpdateStrategy defines at the cluster level how + to handle automated workload updates + properties: + batchEvictionInterval: + default: 1m0s + description: |- + BatchEvictionInterval Represents the interval to wait before issuing the next + batch of shutdowns + type: string + batchEvictionSize: + default: 10 + description: |- + BatchEvictionSize Represents the number of VMIs that can be forced updated per + the BatchShutdownInterval interval + type: integer + workloadUpdateMethods: + default: + - LiveMigrate + description: |- + WorkloadUpdateMethods defines the methods that can be used to disrupt workloads + during automated workload updates. + When multiple methods are present, the least disruptive method takes + precedence over more disruptive methods. For example if both LiveMigrate and Evict + methods are listed, only VMs which are not live migratable will be restarted/shutdown. + An empty list defaults to no automated workload updating. + items: + type: string + type: array + x-kubernetes-list-type: atomic + required: + - workloadUpdateMethods + type: object + workloads: + description: |- + workloads HyperConvergedConfig influences the pod configuration (currently only placement) of components + which need to be running on a node where virtualization workloads should be able to run. + Changes to Workloads HyperConvergedConfig can be applied only without existing workload. + properties: + nodePlacement: + description: NodePlacement describes node scheduling configuration. + properties: + affinity: + description: |- + affinity enables pod affinity/anti-affinity placement expanding the types of constraints + that can be expressed with nodeSelector. + affinity is going to be applied to the relevant kind of pods in parallel with nodeSelector + See https://kubernetes.io/docs/concepts/scheduling-eviction/assign-pod-node/#affinity-and-anti-affinity + properties: + nodeAffinity: + description: Describes node affinity scheduling rules + for the pod. + properties: + preferredDuringSchedulingIgnoredDuringExecution: + description: |- + The scheduler will prefer to schedule pods to nodes that satisfy + the affinity expressions specified by this field, but it may choose + a node that violates one or more of the expressions. The node that is + most preferred is the one with the greatest sum of weights, i.e. + for each node that meets all of the scheduling requirements (resource + request, requiredDuringScheduling affinity expressions, etc.), + compute a sum by iterating through the elements of this field and adding + "weight" to the sum if the node matches the corresponding matchExpressions; the + node(s) with the highest sum are the most preferred. + items: + description: |- + An empty preferred scheduling term matches all objects with implicit weight 0 + (i.e. it's a no-op). A null preferred scheduling term matches no objects (i.e. is also a no-op). + properties: + preference: + description: A node selector term, associated + with the corresponding weight. + properties: + matchExpressions: + description: A list of node selector requirements + by node's labels. + items: + description: |- + A node selector requirement is a selector that contains values, a key, and an operator + that relates the key and values. + properties: + key: + description: The label key that the + selector applies to. + type: string + operator: + description: |- + Represents a key's relationship to a set of values. + Valid operators are In, NotIn, Exists, DoesNotExist. Gt, and Lt. + type: string + values: + description: |- + An array of string values. If the operator is In or NotIn, + the values array must be non-empty. If the operator is Exists or DoesNotExist, + the values array must be empty. If the operator is Gt or Lt, the values + array must have a single element, which will be interpreted as an integer. + This array is replaced during a strategic merge patch. + items: + type: string + type: array + x-kubernetes-list-type: atomic + required: + - key + - operator + type: object + type: array + x-kubernetes-list-type: atomic + matchFields: + description: A list of node selector requirements + by node's fields. + items: + description: |- + A node selector requirement is a selector that contains values, a key, and an operator + that relates the key and values. + properties: + key: + description: The label key that the + selector applies to. + type: string + operator: + description: |- + Represents a key's relationship to a set of values. + Valid operators are In, NotIn, Exists, DoesNotExist. Gt, and Lt. + type: string + values: + description: |- + An array of string values. If the operator is In or NotIn, + the values array must be non-empty. If the operator is Exists or DoesNotExist, + the values array must be empty. If the operator is Gt or Lt, the values + array must have a single element, which will be interpreted as an integer. + This array is replaced during a strategic merge patch. + items: + type: string + type: array + x-kubernetes-list-type: atomic + required: + - key + - operator + type: object + type: array + x-kubernetes-list-type: atomic + type: object + x-kubernetes-map-type: atomic + weight: + description: Weight associated with matching + the corresponding nodeSelectorTerm, in the + range 1-100. + format: int32 + type: integer + required: + - preference + - weight + type: object + type: array + x-kubernetes-list-type: atomic + requiredDuringSchedulingIgnoredDuringExecution: + description: |- + If the affinity requirements specified by this field are not met at + scheduling time, the pod will not be scheduled onto the node. + If the affinity requirements specified by this field cease to be met + at some point during pod execution (e.g. due to an update), the system + may or may not try to eventually evict the pod from its node. + properties: + nodeSelectorTerms: + description: Required. A list of node selector + terms. The terms are ORed. + items: + description: |- + A null or empty node selector term matches no objects. The requirements of + them are ANDed. + The TopologySelectorTerm type implements a subset of the NodeSelectorTerm. + properties: + matchExpressions: + description: A list of node selector requirements + by node's labels. + items: + description: |- + A node selector requirement is a selector that contains values, a key, and an operator + that relates the key and values. + properties: + key: + description: The label key that the + selector applies to. + type: string + operator: + description: |- + Represents a key's relationship to a set of values. + Valid operators are In, NotIn, Exists, DoesNotExist. Gt, and Lt. + type: string + values: + description: |- + An array of string values. If the operator is In or NotIn, + the values array must be non-empty. If the operator is Exists or DoesNotExist, + the values array must be empty. If the operator is Gt or Lt, the values + array must have a single element, which will be interpreted as an integer. + This array is replaced during a strategic merge patch. + items: + type: string + type: array + x-kubernetes-list-type: atomic + required: + - key + - operator + type: object + type: array + x-kubernetes-list-type: atomic + matchFields: + description: A list of node selector requirements + by node's fields. + items: + description: |- + A node selector requirement is a selector that contains values, a key, and an operator + that relates the key and values. + properties: + key: + description: The label key that the + selector applies to. + type: string + operator: + description: |- + Represents a key's relationship to a set of values. + Valid operators are In, NotIn, Exists, DoesNotExist. Gt, and Lt. + type: string + values: + description: |- + An array of string values. If the operator is In or NotIn, + the values array must be non-empty. If the operator is Exists or DoesNotExist, + the values array must be empty. If the operator is Gt or Lt, the values + array must have a single element, which will be interpreted as an integer. + This array is replaced during a strategic merge patch. + items: + type: string + type: array + x-kubernetes-list-type: atomic + required: + - key + - operator + type: object + type: array + x-kubernetes-list-type: atomic + type: object + x-kubernetes-map-type: atomic + type: array + x-kubernetes-list-type: atomic + required: + - nodeSelectorTerms + type: object + x-kubernetes-map-type: atomic + type: object + podAffinity: + description: Describes pod affinity scheduling rules (e.g. + co-locate this pod in the same node, zone, etc. as some + other pod(s)). + properties: + preferredDuringSchedulingIgnoredDuringExecution: + description: |- + The scheduler will prefer to schedule pods to nodes that satisfy + the affinity expressions specified by this field, but it may choose + a node that violates one or more of the expressions. The node that is + most preferred is the one with the greatest sum of weights, i.e. + for each node that meets all of the scheduling requirements (resource + request, requiredDuringScheduling affinity expressions, etc.), + compute a sum by iterating through the elements of this field and adding + "weight" to the sum if the node has pods which matches the corresponding podAffinityTerm; the + node(s) with the highest sum are the most preferred. + items: + description: The weights of all of the matched WeightedPodAffinityTerm + fields are added per-node to find the most preferred + node(s) + properties: + podAffinityTerm: + description: Required. A pod affinity term, + associated with the corresponding weight. + properties: + labelSelector: + description: |- + A label query over a set of resources, in this case pods. + If it's null, this PodAffinityTerm matches with no Pods. + properties: + matchExpressions: + description: matchExpressions is a list + of label selector requirements. The + requirements are ANDed. + items: + description: |- + A label selector requirement is a selector that contains values, a key, and an operator that + relates the key and values. + properties: + key: + description: key is the label + key that the selector applies + to. + type: string + operator: + description: |- + operator represents a key's relationship to a set of values. + Valid operators are In, NotIn, Exists and DoesNotExist. + type: string + values: + description: |- + values is an array of string values. If the operator is In or NotIn, + the values array must be non-empty. If the operator is Exists or DoesNotExist, + the values array must be empty. This array is replaced during a strategic + merge patch. + items: + type: string + type: array + x-kubernetes-list-type: atomic + required: + - key + - operator + type: object + type: array + x-kubernetes-list-type: atomic + matchLabels: + additionalProperties: + type: string + description: |- + matchLabels is a map of {key,value} pairs. A single {key,value} in the matchLabels + map is equivalent to an element of matchExpressions, whose key field is "key", the + operator is "In", and the values array contains only "value". The requirements are ANDed. + type: object + type: object + x-kubernetes-map-type: atomic + matchLabelKeys: + description: |- + MatchLabelKeys is a set of pod label keys to select which pods will + be taken into consideration. The keys are used to lookup values from the + incoming pod labels, those key-value labels are merged with `labelSelector` as `key in (value)` + to select the group of existing pods which pods will be taken into consideration + for the incoming pod's pod (anti) affinity. Keys that don't exist in the incoming + pod labels will be ignored. The default value is empty. + The same key is forbidden to exist in both matchLabelKeys and labelSelector. + Also, matchLabelKeys cannot be set when labelSelector isn't set. + items: + type: string + type: array + x-kubernetes-list-type: atomic + mismatchLabelKeys: + description: |- + MismatchLabelKeys is a set of pod label keys to select which pods will + be taken into consideration. The keys are used to lookup values from the + incoming pod labels, those key-value labels are merged with `labelSelector` as `key notin (value)` + to select the group of existing pods which pods will be taken into consideration + for the incoming pod's pod (anti) affinity. Keys that don't exist in the incoming + pod labels will be ignored. The default value is empty. + The same key is forbidden to exist in both mismatchLabelKeys and labelSelector. + Also, mismatchLabelKeys cannot be set when labelSelector isn't set. + items: + type: string + type: array + x-kubernetes-list-type: atomic + namespaceSelector: + description: |- + A label query over the set of namespaces that the term applies to. + The term is applied to the union of the namespaces selected by this field + and the ones listed in the namespaces field. + null selector and null or empty namespaces list means "this pod's namespace". + An empty selector ({}) matches all namespaces. + properties: + matchExpressions: + description: matchExpressions is a list + of label selector requirements. The + requirements are ANDed. + items: + description: |- + A label selector requirement is a selector that contains values, a key, and an operator that + relates the key and values. + properties: + key: + description: key is the label + key that the selector applies + to. + type: string + operator: + description: |- + operator represents a key's relationship to a set of values. + Valid operators are In, NotIn, Exists and DoesNotExist. + type: string + values: + description: |- + values is an array of string values. If the operator is In or NotIn, + the values array must be non-empty. If the operator is Exists or DoesNotExist, + the values array must be empty. This array is replaced during a strategic + merge patch. + items: + type: string + type: array + x-kubernetes-list-type: atomic + required: + - key + - operator + type: object + type: array + x-kubernetes-list-type: atomic + matchLabels: + additionalProperties: + type: string + description: |- + matchLabels is a map of {key,value} pairs. A single {key,value} in the matchLabels + map is equivalent to an element of matchExpressions, whose key field is "key", the + operator is "In", and the values array contains only "value". The requirements are ANDed. + type: object + type: object + x-kubernetes-map-type: atomic + namespaces: + description: |- + namespaces specifies a static list of namespace names that the term applies to. + The term is applied to the union of the namespaces listed in this field + and the ones selected by namespaceSelector. + null or empty namespaces list and null namespaceSelector means "this pod's namespace". + items: + type: string + type: array + x-kubernetes-list-type: atomic + topologyKey: + description: |- + This pod should be co-located (affinity) or not co-located (anti-affinity) with the pods matching + the labelSelector in the specified namespaces, where co-located is defined as running on a node + whose value of the label with key topologyKey matches that of any node on which any of the + selected pods is running. + Empty topologyKey is not allowed. + type: string + required: + - topologyKey + type: object + weight: + description: |- + weight associated with matching the corresponding podAffinityTerm, + in the range 1-100. + format: int32 + type: integer + required: + - podAffinityTerm + - weight + type: object + type: array + x-kubernetes-list-type: atomic + requiredDuringSchedulingIgnoredDuringExecution: + description: |- + If the affinity requirements specified by this field are not met at + scheduling time, the pod will not be scheduled onto the node. + If the affinity requirements specified by this field cease to be met + at some point during pod execution (e.g. due to a pod label update), the + system may or may not try to eventually evict the pod from its node. + When there are multiple elements, the lists of nodes corresponding to each + podAffinityTerm are intersected, i.e. all terms must be satisfied. + items: + description: |- + Defines a set of pods (namely those matching the labelSelector + relative to the given namespace(s)) that this pod should be + co-located (affinity) or not co-located (anti-affinity) with, + where co-located is defined as running on a node whose value of + the label with key matches that of any node on which + a pod of the set of pods is running + properties: + labelSelector: + description: |- + A label query over a set of resources, in this case pods. + If it's null, this PodAffinityTerm matches with no Pods. + properties: + matchExpressions: + description: matchExpressions is a list + of label selector requirements. The requirements + are ANDed. + items: + description: |- + A label selector requirement is a selector that contains values, a key, and an operator that + relates the key and values. + properties: + key: + description: key is the label key + that the selector applies to. + type: string + operator: + description: |- + operator represents a key's relationship to a set of values. + Valid operators are In, NotIn, Exists and DoesNotExist. + type: string + values: + description: |- + values is an array of string values. If the operator is In or NotIn, + the values array must be non-empty. If the operator is Exists or DoesNotExist, + the values array must be empty. This array is replaced during a strategic + merge patch. + items: + type: string + type: array + x-kubernetes-list-type: atomic + required: + - key + - operator + type: object + type: array + x-kubernetes-list-type: atomic + matchLabels: + additionalProperties: + type: string + description: |- + matchLabels is a map of {key,value} pairs. A single {key,value} in the matchLabels + map is equivalent to an element of matchExpressions, whose key field is "key", the + operator is "In", and the values array contains only "value". The requirements are ANDed. + type: object + type: object + x-kubernetes-map-type: atomic + matchLabelKeys: + description: |- + MatchLabelKeys is a set of pod label keys to select which pods will + be taken into consideration. The keys are used to lookup values from the + incoming pod labels, those key-value labels are merged with `labelSelector` as `key in (value)` + to select the group of existing pods which pods will be taken into consideration + for the incoming pod's pod (anti) affinity. Keys that don't exist in the incoming + pod labels will be ignored. The default value is empty. + The same key is forbidden to exist in both matchLabelKeys and labelSelector. + Also, matchLabelKeys cannot be set when labelSelector isn't set. + items: + type: string + type: array + x-kubernetes-list-type: atomic + mismatchLabelKeys: + description: |- + MismatchLabelKeys is a set of pod label keys to select which pods will + be taken into consideration. The keys are used to lookup values from the + incoming pod labels, those key-value labels are merged with `labelSelector` as `key notin (value)` + to select the group of existing pods which pods will be taken into consideration + for the incoming pod's pod (anti) affinity. Keys that don't exist in the incoming + pod labels will be ignored. The default value is empty. + The same key is forbidden to exist in both mismatchLabelKeys and labelSelector. + Also, mismatchLabelKeys cannot be set when labelSelector isn't set. + items: + type: string + type: array + x-kubernetes-list-type: atomic + namespaceSelector: + description: |- + A label query over the set of namespaces that the term applies to. + The term is applied to the union of the namespaces selected by this field + and the ones listed in the namespaces field. + null selector and null or empty namespaces list means "this pod's namespace". + An empty selector ({}) matches all namespaces. + properties: + matchExpressions: + description: matchExpressions is a list + of label selector requirements. The requirements + are ANDed. + items: + description: |- + A label selector requirement is a selector that contains values, a key, and an operator that + relates the key and values. + properties: + key: + description: key is the label key + that the selector applies to. + type: string + operator: + description: |- + operator represents a key's relationship to a set of values. + Valid operators are In, NotIn, Exists and DoesNotExist. + type: string + values: + description: |- + values is an array of string values. If the operator is In or NotIn, + the values array must be non-empty. If the operator is Exists or DoesNotExist, + the values array must be empty. This array is replaced during a strategic + merge patch. + items: + type: string + type: array + x-kubernetes-list-type: atomic + required: + - key + - operator + type: object + type: array + x-kubernetes-list-type: atomic + matchLabels: + additionalProperties: + type: string + description: |- + matchLabels is a map of {key,value} pairs. A single {key,value} in the matchLabels + map is equivalent to an element of matchExpressions, whose key field is "key", the + operator is "In", and the values array contains only "value". The requirements are ANDed. + type: object + type: object + x-kubernetes-map-type: atomic + namespaces: + description: |- + namespaces specifies a static list of namespace names that the term applies to. + The term is applied to the union of the namespaces listed in this field + and the ones selected by namespaceSelector. + null or empty namespaces list and null namespaceSelector means "this pod's namespace". + items: + type: string + type: array + x-kubernetes-list-type: atomic + topologyKey: + description: |- + This pod should be co-located (affinity) or not co-located (anti-affinity) with the pods matching + the labelSelector in the specified namespaces, where co-located is defined as running on a node + whose value of the label with key topologyKey matches that of any node on which any of the + selected pods is running. + Empty topologyKey is not allowed. + type: string + required: + - topologyKey + type: object + type: array + x-kubernetes-list-type: atomic + type: object + podAntiAffinity: + description: Describes pod anti-affinity scheduling rules + (e.g. avoid putting this pod in the same node, zone, + etc. as some other pod(s)). + properties: + preferredDuringSchedulingIgnoredDuringExecution: + description: |- + The scheduler will prefer to schedule pods to nodes that satisfy + the anti-affinity expressions specified by this field, but it may choose + a node that violates one or more of the expressions. The node that is + most preferred is the one with the greatest sum of weights, i.e. + for each node that meets all of the scheduling requirements (resource + request, requiredDuringScheduling anti-affinity expressions, etc.), + compute a sum by iterating through the elements of this field and subtracting + "weight" from the sum if the node has pods which matches the corresponding podAffinityTerm; the + node(s) with the highest sum are the most preferred. + items: + description: The weights of all of the matched WeightedPodAffinityTerm + fields are added per-node to find the most preferred + node(s) + properties: + podAffinityTerm: + description: Required. A pod affinity term, + associated with the corresponding weight. + properties: + labelSelector: + description: |- + A label query over a set of resources, in this case pods. + If it's null, this PodAffinityTerm matches with no Pods. + properties: + matchExpressions: + description: matchExpressions is a list + of label selector requirements. The + requirements are ANDed. + items: + description: |- + A label selector requirement is a selector that contains values, a key, and an operator that + relates the key and values. + properties: + key: + description: key is the label + key that the selector applies + to. + type: string + operator: + description: |- + operator represents a key's relationship to a set of values. + Valid operators are In, NotIn, Exists and DoesNotExist. + type: string + values: + description: |- + values is an array of string values. If the operator is In or NotIn, + the values array must be non-empty. If the operator is Exists or DoesNotExist, + the values array must be empty. This array is replaced during a strategic + merge patch. + items: + type: string + type: array + x-kubernetes-list-type: atomic + required: + - key + - operator + type: object + type: array + x-kubernetes-list-type: atomic + matchLabels: + additionalProperties: + type: string + description: |- + matchLabels is a map of {key,value} pairs. A single {key,value} in the matchLabels + map is equivalent to an element of matchExpressions, whose key field is "key", the + operator is "In", and the values array contains only "value". The requirements are ANDed. + type: object + type: object + x-kubernetes-map-type: atomic + matchLabelKeys: + description: |- + MatchLabelKeys is a set of pod label keys to select which pods will + be taken into consideration. The keys are used to lookup values from the + incoming pod labels, those key-value labels are merged with `labelSelector` as `key in (value)` + to select the group of existing pods which pods will be taken into consideration + for the incoming pod's pod (anti) affinity. Keys that don't exist in the incoming + pod labels will be ignored. The default value is empty. + The same key is forbidden to exist in both matchLabelKeys and labelSelector. + Also, matchLabelKeys cannot be set when labelSelector isn't set. + items: + type: string + type: array + x-kubernetes-list-type: atomic + mismatchLabelKeys: + description: |- + MismatchLabelKeys is a set of pod label keys to select which pods will + be taken into consideration. The keys are used to lookup values from the + incoming pod labels, those key-value labels are merged with `labelSelector` as `key notin (value)` + to select the group of existing pods which pods will be taken into consideration + for the incoming pod's pod (anti) affinity. Keys that don't exist in the incoming + pod labels will be ignored. The default value is empty. + The same key is forbidden to exist in both mismatchLabelKeys and labelSelector. + Also, mismatchLabelKeys cannot be set when labelSelector isn't set. + items: + type: string + type: array + x-kubernetes-list-type: atomic + namespaceSelector: + description: |- + A label query over the set of namespaces that the term applies to. + The term is applied to the union of the namespaces selected by this field + and the ones listed in the namespaces field. + null selector and null or empty namespaces list means "this pod's namespace". + An empty selector ({}) matches all namespaces. + properties: + matchExpressions: + description: matchExpressions is a list + of label selector requirements. The + requirements are ANDed. + items: + description: |- + A label selector requirement is a selector that contains values, a key, and an operator that + relates the key and values. + properties: + key: + description: key is the label + key that the selector applies + to. + type: string + operator: + description: |- + operator represents a key's relationship to a set of values. + Valid operators are In, NotIn, Exists and DoesNotExist. + type: string + values: + description: |- + values is an array of string values. If the operator is In or NotIn, + the values array must be non-empty. If the operator is Exists or DoesNotExist, + the values array must be empty. This array is replaced during a strategic + merge patch. + items: + type: string + type: array + x-kubernetes-list-type: atomic + required: + - key + - operator + type: object + type: array + x-kubernetes-list-type: atomic + matchLabels: + additionalProperties: + type: string + description: |- + matchLabels is a map of {key,value} pairs. A single {key,value} in the matchLabels + map is equivalent to an element of matchExpressions, whose key field is "key", the + operator is "In", and the values array contains only "value". The requirements are ANDed. + type: object + type: object + x-kubernetes-map-type: atomic + namespaces: + description: |- + namespaces specifies a static list of namespace names that the term applies to. + The term is applied to the union of the namespaces listed in this field + and the ones selected by namespaceSelector. + null or empty namespaces list and null namespaceSelector means "this pod's namespace". + items: + type: string + type: array + x-kubernetes-list-type: atomic + topologyKey: + description: |- + This pod should be co-located (affinity) or not co-located (anti-affinity) with the pods matching + the labelSelector in the specified namespaces, where co-located is defined as running on a node + whose value of the label with key topologyKey matches that of any node on which any of the + selected pods is running. + Empty topologyKey is not allowed. + type: string + required: + - topologyKey + type: object + weight: + description: |- + weight associated with matching the corresponding podAffinityTerm, + in the range 1-100. + format: int32 + type: integer + required: + - podAffinityTerm + - weight + type: object + type: array + x-kubernetes-list-type: atomic + requiredDuringSchedulingIgnoredDuringExecution: + description: |- + If the anti-affinity requirements specified by this field are not met at + scheduling time, the pod will not be scheduled onto the node. + If the anti-affinity requirements specified by this field cease to be met + at some point during pod execution (e.g. due to a pod label update), the + system may or may not try to eventually evict the pod from its node. + When there are multiple elements, the lists of nodes corresponding to each + podAffinityTerm are intersected, i.e. all terms must be satisfied. + items: + description: |- + Defines a set of pods (namely those matching the labelSelector + relative to the given namespace(s)) that this pod should be + co-located (affinity) or not co-located (anti-affinity) with, + where co-located is defined as running on a node whose value of + the label with key matches that of any node on which + a pod of the set of pods is running + properties: + labelSelector: + description: |- + A label query over a set of resources, in this case pods. + If it's null, this PodAffinityTerm matches with no Pods. + properties: + matchExpressions: + description: matchExpressions is a list + of label selector requirements. The requirements + are ANDed. + items: + description: |- + A label selector requirement is a selector that contains values, a key, and an operator that + relates the key and values. + properties: + key: + description: key is the label key + that the selector applies to. + type: string + operator: + description: |- + operator represents a key's relationship to a set of values. + Valid operators are In, NotIn, Exists and DoesNotExist. + type: string + values: + description: |- + values is an array of string values. If the operator is In or NotIn, + the values array must be non-empty. If the operator is Exists or DoesNotExist, + the values array must be empty. This array is replaced during a strategic + merge patch. + items: + type: string + type: array + x-kubernetes-list-type: atomic + required: + - key + - operator + type: object + type: array + x-kubernetes-list-type: atomic + matchLabels: + additionalProperties: + type: string + description: |- + matchLabels is a map of {key,value} pairs. A single {key,value} in the matchLabels + map is equivalent to an element of matchExpressions, whose key field is "key", the + operator is "In", and the values array contains only "value". The requirements are ANDed. + type: object + type: object + x-kubernetes-map-type: atomic + matchLabelKeys: + description: |- + MatchLabelKeys is a set of pod label keys to select which pods will + be taken into consideration. The keys are used to lookup values from the + incoming pod labels, those key-value labels are merged with `labelSelector` as `key in (value)` + to select the group of existing pods which pods will be taken into consideration + for the incoming pod's pod (anti) affinity. Keys that don't exist in the incoming + pod labels will be ignored. The default value is empty. + The same key is forbidden to exist in both matchLabelKeys and labelSelector. + Also, matchLabelKeys cannot be set when labelSelector isn't set. + items: + type: string + type: array + x-kubernetes-list-type: atomic + mismatchLabelKeys: + description: |- + MismatchLabelKeys is a set of pod label keys to select which pods will + be taken into consideration. The keys are used to lookup values from the + incoming pod labels, those key-value labels are merged with `labelSelector` as `key notin (value)` + to select the group of existing pods which pods will be taken into consideration + for the incoming pod's pod (anti) affinity. Keys that don't exist in the incoming + pod labels will be ignored. The default value is empty. + The same key is forbidden to exist in both mismatchLabelKeys and labelSelector. + Also, mismatchLabelKeys cannot be set when labelSelector isn't set. + items: + type: string + type: array + x-kubernetes-list-type: atomic + namespaceSelector: + description: |- + A label query over the set of namespaces that the term applies to. + The term is applied to the union of the namespaces selected by this field + and the ones listed in the namespaces field. + null selector and null or empty namespaces list means "this pod's namespace". + An empty selector ({}) matches all namespaces. + properties: + matchExpressions: + description: matchExpressions is a list + of label selector requirements. The requirements + are ANDed. + items: + description: |- + A label selector requirement is a selector that contains values, a key, and an operator that + relates the key and values. + properties: + key: + description: key is the label key + that the selector applies to. + type: string + operator: + description: |- + operator represents a key's relationship to a set of values. + Valid operators are In, NotIn, Exists and DoesNotExist. + type: string + values: + description: |- + values is an array of string values. If the operator is In or NotIn, + the values array must be non-empty. If the operator is Exists or DoesNotExist, + the values array must be empty. This array is replaced during a strategic + merge patch. + items: + type: string + type: array + x-kubernetes-list-type: atomic + required: + - key + - operator + type: object + type: array + x-kubernetes-list-type: atomic + matchLabels: + additionalProperties: + type: string + description: |- + matchLabels is a map of {key,value} pairs. A single {key,value} in the matchLabels + map is equivalent to an element of matchExpressions, whose key field is "key", the + operator is "In", and the values array contains only "value". The requirements are ANDed. + type: object + type: object + x-kubernetes-map-type: atomic + namespaces: + description: |- + namespaces specifies a static list of namespace names that the term applies to. + The term is applied to the union of the namespaces listed in this field + and the ones selected by namespaceSelector. + null or empty namespaces list and null namespaceSelector means "this pod's namespace". + items: + type: string + type: array + x-kubernetes-list-type: atomic + topologyKey: + description: |- + This pod should be co-located (affinity) or not co-located (anti-affinity) with the pods matching + the labelSelector in the specified namespaces, where co-located is defined as running on a node + whose value of the label with key topologyKey matches that of any node on which any of the + selected pods is running. + Empty topologyKey is not allowed. + type: string + required: + - topologyKey + type: object + type: array + x-kubernetes-list-type: atomic + type: object + type: object + nodeSelector: + additionalProperties: + type: string + description: |- + nodeSelector is the node selector applied to the relevant kind of pods + It specifies a map of key-value pairs: for the pod to be eligible to run on a node, + the node must have each of the indicated key-value pairs as labels + (it can have additional labels as well). + See https://kubernetes.io/docs/concepts/configuration/assign-pod-node/#nodeselector + type: object + tolerations: + description: |- + tolerations is a list of tolerations applied to the relevant kind of pods + See https://kubernetes.io/docs/concepts/configuration/taint-and-toleration/ for more info. + These are additional tolerations other than default ones. + items: + description: |- + The pod this Toleration is attached to tolerates any taint that matches + the triple using the matching operator . + properties: + effect: + description: |- + Effect indicates the taint effect to match. Empty means match all taint effects. + When specified, allowed values are NoSchedule, PreferNoSchedule and NoExecute. + type: string + key: + description: |- + Key is the taint key that the toleration applies to. Empty means match all taint keys. + If the key is empty, operator must be Exists; this combination means to match all values and all keys. + type: string + operator: + description: |- + Operator represents a key's relationship to the value. + Valid operators are Exists and Equal. Defaults to Equal. + Exists is equivalent to wildcard for value, so that a pod can + tolerate all taints of a particular category. + type: string + tolerationSeconds: + description: |- + TolerationSeconds represents the period of time the toleration (which must be + of effect NoExecute, otherwise this field is ignored) tolerates the taint. By default, + it is not set, which means tolerate the taint forever (do not evict). Zero and + negative values will be treated as 0 (evict immediately) by the system. + format: int64 + type: integer + value: + description: |- + Value is the taint value the toleration matches to. + If the operator is Exists, the value should be empty, otherwise just a regular string. + type: string + type: object + type: array + type: object + type: object + type: object + status: + description: HyperConvergedStatus defines the observed state of HyperConverged + properties: + conditions: + description: Conditions describes the state of the HyperConverged + resource. + items: + description: Condition contains details for one aspect of the current + state of this API Resource. + properties: + lastTransitionTime: + description: |- + lastTransitionTime is the last time the condition transitioned from one status to another. + This should be when the underlying condition changed. If that is not known, then using the time when the API field changed is acceptable. + format: date-time + type: string + message: + description: |- + message is a human readable message indicating details about the transition. + This may be an empty string. + maxLength: 32768 + type: string + observedGeneration: + description: |- + observedGeneration represents the .metadata.generation that the condition was set based upon. + For instance, if .metadata.generation is currently 12, but the .status.conditions[x].observedGeneration is 9, the condition is out of date + with respect to the current state of the instance. + format: int64 + minimum: 0 + type: integer + reason: + description: |- + reason contains a programmatic identifier indicating the reason for the condition's last transition. + Producers of specific condition types may define expected values and meanings for this field, + and whether the values are considered a guaranteed API. + The value should be a CamelCase string. + This field may not be empty. + maxLength: 1024 + minLength: 1 + pattern: ^[A-Za-z]([A-Za-z0-9_,:]*[A-Za-z0-9_])?$ + type: string + status: + description: status of the condition, one of True, False, Unknown. + enum: + - "True" + - "False" + - Unknown + type: string + type: + description: type of condition in CamelCase or in foo.example.com/CamelCase. + maxLength: 316 + pattern: ^([a-z0-9]([-a-z0-9]*[a-z0-9])?(\.[a-z0-9]([-a-z0-9]*[a-z0-9])?)*/)?(([A-Za-z0-9][-A-Za-z0-9_.]*)?[A-Za-z0-9])$ + type: string + required: + - lastTransitionTime + - message + - reason + - status + - type + type: object + type: array + x-kubernetes-list-type: atomic + dataImportCronTemplates: + description: |- + DataImportCronTemplates is a list of the actual DataImportCronTemplates as HCO update in the SSP CR. The list + contains both the common and the custom templates, including any modification done by HCO. + items: + description: DataImportCronTemplateStatus is a copy of a dataImportCronTemplate + as defined in the spec, or in the HCO image. + properties: + metadata: + properties: + annotations: + additionalProperties: + type: string + type: object + finalizers: + items: + type: string + type: array + labels: + additionalProperties: + type: string + type: object + name: + type: string + namespace: + type: string + type: object + spec: + description: DataImportCronSpec defines specification for DataImportCron + properties: + garbageCollect: + description: |- + GarbageCollect specifies whether old PVCs should be cleaned up after a new PVC is imported. + Options are currently "Outdated" and "Never", defaults to "Outdated". + type: string + importsToKeep: + description: Number of import PVCs to keep when garbage + collecting. Default is 3. + format: int32 + type: integer + managedDataSource: + description: |- + ManagedDataSource specifies the name of the corresponding DataSource this cron will manage. + DataSource has to be in the same namespace. + type: string + retentionPolicy: + description: RetentionPolicy specifies whether the created + DataVolumes and DataSources are retained when their DataImportCron + is deleted. Default is RatainAll. + type: string + schedule: + description: Schedule specifies in cron format when and + how often to look for new imports + type: string + serviceAccountName: + description: ServiceAccountName is the name of the ServiceAccount + for creating DataVolumes. + minLength: 1 + type: string + template: + description: Template specifies template for the DVs to + be created + properties: + apiVersion: + description: |- + APIVersion defines the versioned schema of this representation of an object. + Servers should convert recognized schemas to the latest internal value, and + may reject unrecognized values. + More info: https://git.k8s.io/community/contributors/devel/sig-architecture/api-conventions.md#resources + type: string + kind: + description: |- + Kind is a string value representing the REST resource this object represents. + Servers may infer this from the endpoint the client submits requests to. + Cannot be updated. + In CamelCase. + More info: https://git.k8s.io/community/contributors/devel/sig-architecture/api-conventions.md#types-kinds + type: string + metadata: + properties: + annotations: + additionalProperties: + type: string + type: object + finalizers: + items: + type: string + type: array + labels: + additionalProperties: + type: string + type: object + name: + type: string + namespace: + type: string + type: object + spec: + description: DataVolumeSpec defines the DataVolume type + specification + properties: + checkpoints: + description: Checkpoints is a list of DataVolumeCheckpoints, + representing stages in a multistage import. + items: + description: DataVolumeCheckpoint defines a stage + in a warm migration. + properties: + current: + description: Current is the identifier of + the snapshot created for this checkpoint. + type: string + previous: + description: Previous is the identifier of + the snapshot from the previous checkpoint. + type: string + required: + - current + - previous + type: object + type: array + contentType: + description: 'DataVolumeContentType options: "kubevirt", + "archive"' + enum: + - kubevirt + - archive + type: string + finalCheckpoint: + description: FinalCheckpoint indicates whether the + current DataVolumeCheckpoint is the final checkpoint. + type: boolean + preallocation: + description: Preallocation controls whether storage + for DataVolumes should be allocated in advance. + type: boolean + priorityClassName: + description: PriorityClassName for Importer, Cloner + and Uploader pod + type: string + pvc: + description: PVC is the PVC specification + properties: + accessModes: + description: |- + accessModes contains the desired access modes the volume should have. + More info: https://kubernetes.io/docs/concepts/storage/persistent-volumes#access-modes-1 + items: + type: string + type: array + x-kubernetes-list-type: atomic + dataSource: + description: |- + dataSource field can be used to specify either: + * An existing VolumeSnapshot object (snapshot.storage.k8s.io/VolumeSnapshot) + * An existing PVC (PersistentVolumeClaim) + If the provisioner or an external controller can support the specified data source, + it will create a new volume based on the contents of the specified data source. + When the AnyVolumeDataSource feature gate is enabled, dataSource contents will be copied to dataSourceRef, + and dataSourceRef contents will be copied to dataSource when dataSourceRef.namespace is not specified. + If the namespace is specified, then dataSourceRef will not be copied to dataSource. + properties: + apiGroup: + description: |- + APIGroup is the group for the resource being referenced. + If APIGroup is not specified, the specified Kind must be in the core API group. + For any other third-party types, APIGroup is required. + type: string + kind: + description: Kind is the type of resource + being referenced + type: string + name: + description: Name is the name of resource + being referenced + type: string + required: + - kind + - name + type: object + x-kubernetes-map-type: atomic + dataSourceRef: + description: |- + dataSourceRef specifies the object from which to populate the volume with data, if a non-empty + volume is desired. This may be any object from a non-empty API group (non + core object) or a PersistentVolumeClaim object. + When this field is specified, volume binding will only succeed if the type of + the specified object matches some installed volume populator or dynamic + provisioner. + This field will replace the functionality of the dataSource field and as such + if both fields are non-empty, they must have the same value. For backwards + compatibility, when namespace isn't specified in dataSourceRef, + both fields (dataSource and dataSourceRef) will be set to the same + value automatically if one of them is empty and the other is non-empty. + When namespace is specified in dataSourceRef, + dataSource isn't set to the same value and must be empty. + There are three important differences between dataSource and dataSourceRef: + * While dataSource only allows two specific types of objects, dataSourceRef + allows any non-core object, as well as PersistentVolumeClaim objects. + * While dataSource ignores disallowed values (dropping them), dataSourceRef + preserves all values, and generates an error if a disallowed value is + specified. + * While dataSource only allows local objects, dataSourceRef allows objects + in any namespaces. + (Beta) Using this field requires the AnyVolumeDataSource feature gate to be enabled. + (Alpha) Using the namespace field of dataSourceRef requires the CrossNamespaceVolumeDataSource feature gate to be enabled. + properties: + apiGroup: + description: |- + APIGroup is the group for the resource being referenced. + If APIGroup is not specified, the specified Kind must be in the core API group. + For any other third-party types, APIGroup is required. + type: string + kind: + description: Kind is the type of resource + being referenced + type: string + name: + description: Name is the name of resource + being referenced + type: string + namespace: + description: |- + Namespace is the namespace of resource being referenced + Note that when a namespace is specified, a gateway.networking.k8s.io/ReferenceGrant object is required in the referent namespace to allow that namespace's owner to accept the reference. See the ReferenceGrant documentation for details. + (Alpha) This field requires the CrossNamespaceVolumeDataSource feature gate to be enabled. + type: string + required: + - kind + - name + type: object + resources: + description: |- + resources represents the minimum resources the volume should have. + If RecoverVolumeExpansionFailure feature is enabled users are allowed to specify resource requirements + that are lower than previous value but must still be higher than capacity recorded in the + status field of the claim. + More info: https://kubernetes.io/docs/concepts/storage/persistent-volumes#resources + properties: + limits: + additionalProperties: + anyOf: + - type: integer + - type: string + pattern: ^(\+|-)?(([0-9]+(\.[0-9]*)?)|(\.[0-9]+))(([KMGTPE]i)|[numkMGTPE]|([eE](\+|-)?(([0-9]+(\.[0-9]*)?)|(\.[0-9]+))))?$ + x-kubernetes-int-or-string: true + description: |- + Limits describes the maximum amount of compute resources allowed. + More info: https://kubernetes.io/docs/concepts/configuration/manage-resources-containers/ + type: object + requests: + additionalProperties: + anyOf: + - type: integer + - type: string + pattern: ^(\+|-)?(([0-9]+(\.[0-9]*)?)|(\.[0-9]+))(([KMGTPE]i)|[numkMGTPE]|([eE](\+|-)?(([0-9]+(\.[0-9]*)?)|(\.[0-9]+))))?$ + x-kubernetes-int-or-string: true + description: |- + Requests describes the minimum amount of compute resources required. + If Requests is omitted for a container, it defaults to Limits if that is explicitly specified, + otherwise to an implementation-defined value. Requests cannot exceed Limits. + More info: https://kubernetes.io/docs/concepts/configuration/manage-resources-containers/ + type: object + type: object + selector: + description: selector is a label query over + volumes to consider for binding. + properties: + matchExpressions: + description: matchExpressions is a list + of label selector requirements. The requirements + are ANDed. + items: + description: |- + A label selector requirement is a selector that contains values, a key, and an operator that + relates the key and values. + properties: + key: + description: key is the label key + that the selector applies to. + type: string + operator: + description: |- + operator represents a key's relationship to a set of values. + Valid operators are In, NotIn, Exists and DoesNotExist. + type: string + values: + description: |- + values is an array of string values. If the operator is In or NotIn, + the values array must be non-empty. If the operator is Exists or DoesNotExist, + the values array must be empty. This array is replaced during a strategic + merge patch. + items: + type: string + type: array + x-kubernetes-list-type: atomic + required: + - key + - operator + type: object + type: array + x-kubernetes-list-type: atomic + matchLabels: + additionalProperties: + type: string + description: |- + matchLabels is a map of {key,value} pairs. A single {key,value} in the matchLabels + map is equivalent to an element of matchExpressions, whose key field is "key", the + operator is "In", and the values array contains only "value". The requirements are ANDed. + type: object + type: object + x-kubernetes-map-type: atomic + storageClassName: + description: |- + storageClassName is the name of the StorageClass required by the claim. + More info: https://kubernetes.io/docs/concepts/storage/persistent-volumes#class-1 + type: string + volumeAttributesClassName: + description: |- + volumeAttributesClassName may be used to set the VolumeAttributesClass used by this claim. + If specified, the CSI driver will create or update the volume with the attributes defined + in the corresponding VolumeAttributesClass. This has a different purpose than storageClassName, + it can be changed after the claim is created. An empty string or nil value indicates that no + VolumeAttributesClass will be applied to the claim. If the claim enters an Infeasible error state, + this field can be reset to its previous value (including nil) to cancel the modification. + If the resource referred to by volumeAttributesClass does not exist, this PersistentVolumeClaim will be + set to a Pending state, as reflected by the modifyVolumeStatus field, until such as a resource + exists. + More info: https://kubernetes.io/docs/concepts/storage/volume-attributes-classes/ + type: string + volumeMode: + description: |- + volumeMode defines what type of volume is required by the claim. + Value of Filesystem is implied when not included in claim spec. + type: string + volumeName: + description: volumeName is the binding reference + to the PersistentVolume backing this claim. + type: string + type: object + source: + description: Source is the src of the data for the + requested DataVolume + properties: + blank: + description: DataVolumeBlankImage provides the + parameters to create a new raw blank image + for the PVC + type: object + gcs: + description: DataVolumeSourceGCS provides the + parameters to create a Data Volume from an + GCS source + properties: + secretRef: + description: SecretRef provides the secret + reference needed to access the GCS source + type: string + url: + description: URL is the url of the GCS source + type: string + required: + - url + type: object + http: + description: DataVolumeSourceHTTP can be either + an http or https endpoint, with an optional + basic auth user name and password, and an + optional configmap containing additional CAs + properties: + certConfigMap: + description: CertConfigMap is a configmap + reference, containing a Certificate Authority(CA) + public key, and a base64 encoded pem certificate + type: string + extraHeaders: + description: ExtraHeaders is a list of strings + containing extra headers to include with + HTTP transfer requests + items: + type: string + type: array + secretExtraHeaders: + description: SecretExtraHeaders is a list + of Secret references, each containing + an extra HTTP header that may include + sensitive information + items: + type: string + type: array + secretRef: + description: SecretRef A Secret reference, + the secret should contain accessKeyId + (user name) base64 encoded, and secretKey + (password) also base64 encoded + type: string + url: + description: URL is the URL of the http(s) + endpoint + type: string + required: + - url + type: object + imageio: + description: DataVolumeSourceImageIO provides + the parameters to create a Data Volume from + an imageio source + properties: + certConfigMap: + description: CertConfigMap provides a reference + to the CA cert + type: string + diskId: + description: DiskID provides id of a disk + to be imported + type: string + insecureSkipVerify: + description: InsecureSkipVerify is a flag + to skip certificate verification + type: boolean + secretRef: + description: SecretRef provides the secret + reference needed to access the ovirt-engine + type: string + url: + description: URL is the URL of the ovirt-engine + type: string + required: + - diskId + - url + type: object + pvc: + description: DataVolumeSourcePVC provides the + parameters to create a Data Volume from an + existing PVC + properties: + name: + description: The name of the source PVC + type: string + namespace: + description: The namespace of the source + PVC + type: string + required: + - name + - namespace + type: object + registry: + description: DataVolumeSourceRegistry provides + the parameters to create a Data Volume from + an registry source + properties: + certConfigMap: + description: CertConfigMap provides a reference + to the Registry certs + type: string + imageStream: + description: ImageStream is the name of + image stream for import + type: string + platform: + description: Platform describes the minimum + runtime requirements of the image + properties: + architecture: + description: Architecture specifies + the image target CPU architecture + type: string + type: object + pullMethod: + description: PullMethod can be either "pod" + (default import), or "node" (node docker + cache based import) + type: string + secretRef: + description: SecretRef provides the secret + reference needed to access the Registry + source + type: string + url: + description: 'URL is the url of the registry + source (starting with the scheme: docker, + oci-archive)' + type: string + type: object + s3: + description: DataVolumeSourceS3 provides the + parameters to create a Data Volume from an + S3 source + properties: + certConfigMap: + description: CertConfigMap is a configmap + reference, containing a Certificate Authority(CA) + public key, and a base64 encoded pem certificate + type: string + secretRef: + description: SecretRef provides the secret + reference needed to access the S3 source + type: string + url: + description: URL is the url of the S3 source + type: string + required: + - url + type: object + snapshot: + description: DataVolumeSourceSnapshot provides + the parameters to create a Data Volume from + an existing VolumeSnapshot + properties: + name: + description: The name of the source VolumeSnapshot + type: string + namespace: + description: The namespace of the source + VolumeSnapshot + type: string + required: + - name + - namespace + type: object + upload: + description: DataVolumeSourceUpload provides + the parameters to create a Data Volume by + uploading the source + type: object + vddk: + description: DataVolumeSourceVDDK provides the + parameters to create a Data Volume from a + Vmware source + properties: + backingFile: + description: BackingFile is the path to + the virtual hard disk to migrate from + vCenter/ESXi + type: string + extraArgs: + description: ExtraArgs is a reference to + a ConfigMap containing extra arguments + to pass directly to the VDDK library + type: string + initImageURL: + description: InitImageURL is an optional + URL to an image containing an extracted + VDDK library, overrides v2v-vmware config + map + type: string + secretRef: + description: SecretRef provides a reference + to a secret containing the username and + password needed to access the vCenter + or ESXi host + type: string + thumbprint: + description: Thumbprint is the certificate + thumbprint of the vCenter or ESXi host + type: string + url: + description: URL is the URL of the vCenter + or ESXi host with the VM to migrate + type: string + uuid: + description: UUID is the UUID of the virtual + machine that the backing file is attached + to in vCenter/ESXi + type: string + type: object + type: object + sourceRef: + description: SourceRef is an indirect reference + to the source of data for the requested DataVolume + properties: + kind: + description: The kind of the source reference, + currently only "DataSource" is supported + type: string + name: + description: The name of the source reference + type: string + namespace: + description: The namespace of the source reference, + defaults to the DataVolume namespace + type: string + required: + - kind + - name + type: object + storage: + description: Storage is the requested storage specification + properties: + accessModes: + description: |- + AccessModes contains the desired access modes the volume should have. + More info: https://kubernetes.io/docs/concepts/storage/persistent-volumes#access-modes-1 + items: + type: string + type: array + dataSource: + description: |- + This field can be used to specify either: * An existing VolumeSnapshot object (snapshot.storage.k8s.io/VolumeSnapshot) * An existing PVC (PersistentVolumeClaim) * An existing custom resource that implements data population (Alpha) In order to use custom resource types that implement data population, the AnyVolumeDataSource feature gate must be enabled. If the provisioner or an external controller can support the specified data source, it will create a new volume based on the contents of the specified data source. + If the AnyVolumeDataSource feature gate is enabled, this field will always have the same contents as the DataSourceRef field. + properties: + apiGroup: + description: |- + APIGroup is the group for the resource being referenced. + If APIGroup is not specified, the specified Kind must be in the core API group. + For any other third-party types, APIGroup is required. + type: string + kind: + description: Kind is the type of resource + being referenced + type: string + name: + description: Name is the name of resource + being referenced + type: string + required: + - kind + - name + type: object + x-kubernetes-map-type: atomic + dataSourceRef: + description: |- + Specifies the object from which to populate the volume with data, if a non-empty volume is desired. This may be any local object from a non-empty API group (non core object) or a PersistentVolumeClaim object. When this field is specified, volume binding will only succeed if the type of the specified object matches some installed volume populator or dynamic provisioner. + This field will replace the functionality of the DataSource field and as such if both fields are non-empty, they must have the same value. For backwards compatibility, both fields (DataSource and DataSourceRef) will be set to the same value automatically if one of them is empty and the other is non-empty. + There are two important differences between DataSource and DataSourceRef: + * While DataSource only allows two specific types of objects, DataSourceRef allows any non-core object, as well as PersistentVolumeClaim objects. + * While DataSource ignores disallowed values (dropping them), DataSourceRef preserves all values, and generates an error if a disallowed value is specified. + (Beta) Using this field requires the AnyVolumeDataSource feature gate to be enabled. + properties: + apiGroup: + description: |- + APIGroup is the group for the resource being referenced. + If APIGroup is not specified, the specified Kind must be in the core API group. + For any other third-party types, APIGroup is required. + type: string + kind: + description: Kind is the type of resource + being referenced + type: string + name: + description: Name is the name of resource + being referenced + type: string + namespace: + description: |- + Namespace is the namespace of resource being referenced + Note that when a namespace is specified, a gateway.networking.k8s.io/ReferenceGrant object is required in the referent namespace to allow that namespace's owner to accept the reference. See the ReferenceGrant documentation for details. + (Alpha) This field requires the CrossNamespaceVolumeDataSource feature gate to be enabled. + type: string + required: + - kind + - name + type: object + resources: + description: |- + Resources represents the minimum resources the volume should have. + More info: https://kubernetes.io/docs/concepts/storage/persistent-volumes#resources + properties: + limits: + additionalProperties: + anyOf: + - type: integer + - type: string + pattern: ^(\+|-)?(([0-9]+(\.[0-9]*)?)|(\.[0-9]+))(([KMGTPE]i)|[numkMGTPE]|([eE](\+|-)?(([0-9]+(\.[0-9]*)?)|(\.[0-9]+))))?$ + x-kubernetes-int-or-string: true + description: |- + Limits describes the maximum amount of compute resources allowed. + More info: https://kubernetes.io/docs/concepts/configuration/manage-resources-containers/ + type: object + requests: + additionalProperties: + anyOf: + - type: integer + - type: string + pattern: ^(\+|-)?(([0-9]+(\.[0-9]*)?)|(\.[0-9]+))(([KMGTPE]i)|[numkMGTPE]|([eE](\+|-)?(([0-9]+(\.[0-9]*)?)|(\.[0-9]+))))?$ + x-kubernetes-int-or-string: true + description: |- + Requests describes the minimum amount of compute resources required. + If Requests is omitted for a container, it defaults to Limits if that is explicitly specified, + otherwise to an implementation-defined value. Requests cannot exceed Limits. + More info: https://kubernetes.io/docs/concepts/configuration/manage-resources-containers/ + type: object + type: object + selector: + description: A label query over volumes to consider + for binding. + properties: + matchExpressions: + description: matchExpressions is a list + of label selector requirements. The requirements + are ANDed. + items: + description: |- + A label selector requirement is a selector that contains values, a key, and an operator that + relates the key and values. + properties: + key: + description: key is the label key + that the selector applies to. + type: string + operator: + description: |- + operator represents a key's relationship to a set of values. + Valid operators are In, NotIn, Exists and DoesNotExist. + type: string + values: + description: |- + values is an array of string values. If the operator is In or NotIn, + the values array must be non-empty. If the operator is Exists or DoesNotExist, + the values array must be empty. This array is replaced during a strategic + merge patch. + items: + type: string + type: array + x-kubernetes-list-type: atomic + required: + - key + - operator + type: object + type: array + x-kubernetes-list-type: atomic + matchLabels: + additionalProperties: + type: string + description: |- + matchLabels is a map of {key,value} pairs. A single {key,value} in the matchLabels + map is equivalent to an element of matchExpressions, whose key field is "key", the + operator is "In", and the values array contains only "value". The requirements are ANDed. + type: object + type: object + x-kubernetes-map-type: atomic + storageClassName: + description: |- + Name of the StorageClass required by the claim. + More info: https://kubernetes.io/docs/concepts/storage/persistent-volumes#class-1 + type: string + volumeMode: + description: |- + volumeMode defines what type of volume is required by the claim. + Value of Filesystem is implied when not included in claim spec. + type: string + volumeName: + description: VolumeName is the binding reference + to the PersistentVolume backing this claim. + type: string + type: object + type: object + status: + description: DataVolumeStatus contains the current status + of the DataVolume + properties: + claimName: + description: ClaimName is the name of the underlying + PVC used by the DataVolume. + type: string + conditions: + items: + description: DataVolumeCondition represents the + state of a data volume condition. + properties: + lastHeartbeatTime: + format: date-time + type: string + lastTransitionTime: + format: date-time + type: string + message: + type: string + reason: + type: string + status: + type: string + type: + description: DataVolumeConditionType is the + string representation of known condition + types + type: string + required: + - status + - type + type: object + type: array + phase: + description: Phase is the current phase of the data + volume + type: string + progress: + description: DataVolumeProgress is the current progress + of the DataVolume transfer operation. Value between + 0 and 100 inclusive, N/A if not available + type: string + restartCount: + description: RestartCount is the number of times + the pod populating the DataVolume has restarted + format: int32 + type: integer + type: object + required: + - spec + type: object + required: + - managedDataSource + - schedule + - template + type: object + status: + description: DataImportCronStatus is the status field of the + DIC template + properties: + commonTemplate: + description: CommonTemplate indicates whether this is a + common template (true), or a custom one (false) + type: boolean + conditions: + description: Conditions is a list of conditions that describe + the state of the DataImportCronTemplate. + items: + description: Condition contains details for one aspect + of the current state of this API Resource. + properties: + lastTransitionTime: + description: |- + lastTransitionTime is the last time the condition transitioned from one status to another. + This should be when the underlying condition changed. If that is not known, then using the time when the API field changed is acceptable. + format: date-time + type: string + message: + description: |- + message is a human readable message indicating details about the transition. + This may be an empty string. + maxLength: 32768 + type: string + observedGeneration: + description: |- + observedGeneration represents the .metadata.generation that the condition was set based upon. + For instance, if .metadata.generation is currently 12, but the .status.conditions[x].observedGeneration is 9, the condition is out of date + with respect to the current state of the instance. + format: int64 + minimum: 0 + type: integer + reason: + description: |- + reason contains a programmatic identifier indicating the reason for the condition's last transition. + Producers of specific condition types may define expected values and meanings for this field, + and whether the values are considered a guaranteed API. + The value should be a CamelCase string. + This field may not be empty. + maxLength: 1024 + minLength: 1 + pattern: ^[A-Za-z]([A-Za-z0-9_,:]*[A-Za-z0-9_])?$ + type: string + status: + description: status of the condition, one of True, + False, Unknown. + enum: + - "True" + - "False" + - Unknown + type: string + type: + description: type of condition in CamelCase or in + foo.example.com/CamelCase. + maxLength: 316 + pattern: ^([a-z0-9]([-a-z0-9]*[a-z0-9])?(\.[a-z0-9]([-a-z0-9]*[a-z0-9])?)*/)?(([A-Za-z0-9][-A-Za-z0-9_.]*)?[A-Za-z0-9])$ + type: string + required: + - lastTransitionTime + - message + - reason + - status + - type + type: object + type: array + modified: + description: Modified indicates if a common template was + customized. Always false for custom templates. + type: boolean + originalSupportedArchitectures: + description: |- + OriginalSupportedArchitectures is a comma-separated list of CPU architectures that the original + template supports. + type: string + type: object + type: object + type: array + dataImportSchedule: + description: |- + DataImportSchedule is the cron expression that is used in for the hard-coded data import cron templates. HCO + generates the value of this field once and stored in the status field, so will survive restart. + type: string + infrastructureHighlyAvailable: + description: |- + InfrastructureHighlyAvailable describes whether the cluster has only one worker node + (false) or more (true). + type: boolean + nodeInfo: + description: NodeInfo holds information about the cluster nodes + properties: + controlPlaneArchitectures: + description: ControlPlaneArchitectures is a distinct list of the + CPU architecture of the control-plane nodes. + items: + type: string + type: array + workloadsArchitectures: + description: WorkloadsArchitectures is a distinct list of the + CPU architectures of the workloads nodes in the cluster. + items: + type: string + type: array + type: object + observedGeneration: + description: |- + ObservedGeneration reflects the HyperConverged resource generation. If the ObservedGeneration is less than the + resource generation in metadata, the status is out of date + format: int64 + type: integer + relatedObjects: + description: |- + RelatedObjects is a list of objects created and maintained by this + operator. Object references will be added to this list after they have + been created AND found in the cluster. + items: + description: ObjectReference contains enough information to let + you inspect or modify the referred object. + properties: + apiVersion: + description: API version of the referent. + type: string + fieldPath: + description: |- + If referring to a piece of an object instead of an entire object, this string + should contain a valid JSON/Go field access statement, such as desiredState.manifest.containers[2]. + For example, if the object reference is to a container within a pod, this would take on a value like: + "spec.containers{name}" (where "name" refers to the name of the container that triggered + the event) or if no container name is specified "spec.containers[2]" (container with + index 2 in this pod). This syntax is chosen only to have some well-defined way of + referencing a part of an object. + type: string + kind: + description: |- + Kind of the referent. + More info: https://git.k8s.io/community/contributors/devel/sig-architecture/api-conventions.md#types-kinds + type: string + name: + description: |- + Name of the referent. + More info: https://kubernetes.io/docs/concepts/overview/working-with-objects/names/#names + type: string + namespace: + description: |- + Namespace of the referent. + More info: https://kubernetes.io/docs/concepts/overview/working-with-objects/namespaces/ + type: string + resourceVersion: + description: |- + Specific resourceVersion to which this reference is made, if any. + More info: https://git.k8s.io/community/contributors/devel/sig-architecture/api-conventions.md#concurrency-control-and-consistency + type: string + uid: + description: |- + UID of the referent. + More info: https://kubernetes.io/docs/concepts/overview/working-with-objects/names/#uids + type: string + type: object + x-kubernetes-map-type: atomic + type: array + x-kubernetes-list-type: atomic + systemHealthStatus: + description: SystemHealthStatus reflects the health of HCO and its + secondary resources, based on the aggregated conditions. + type: string + versions: + description: |- + Versions is a list of HCO component versions, as name/version pairs. The version with a name of "operator" + is the HCO version itself, as described here: + https://github.com/openshift/cluster-version-operator/blob/master/docs/dev/clusteroperator.md#version + items: + properties: + name: + type: string + version: + type: string + type: object + type: array + x-kubernetes-list-type: atomic + type: object + type: object + served: true + storage: false + subresources: + status: {} - additionalPrinterColumns: - jsonPath: .metadata.creationTimestamp name: Age