Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
15 changes: 9 additions & 6 deletions api/v1beta1/hyperconverged_types.go
Original file line number Diff line number Diff line change
Expand Up @@ -67,7 +67,7 @@ type HyperConvergedSpec struct {

// featureGates is a map of feature gate flags. Setting a flag to `true` will enable
// 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": true, "declarativeHotplugVolumes": false, "videoConfig": true, "objectGraph": false, "incrementalBackup": false}
// +kubebuilder:default={"downwardMetrics": false, "deployKubeSecondaryDNS": false, "persistentReservation": false, "enableMultiArchBootImageImport": false, "decentralizedLiveMigration": true, "declarativeHotplugVolumes": false, "videoConfig": true, "objectGraph": false, "incrementalBackup": false}
// +optional
FeatureGates HyperConvergedFeatureGates `json:"featureGates,omitempty"`

Expand Down Expand Up @@ -466,10 +466,7 @@ type HyperConvergedFeatureGates struct {
// Deprecated: // Deprecated: This field is ignored and will be removed on the next version of the API.
NonRoot *bool `json:"nonRoot,omitempty"`

// Disable mediated devices handling on KubeVirt
// +optional
// +kubebuilder:default=false
// +default=false
// Deprecated: This field is ignored and use mediatedDevicesConfiguration.Enabled instead , it will be removed in the next version of the API.
Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

we're not ignoring it, but it is deprecated.

DisableMDevConfiguration *bool `json:"disableMDevConfiguration,omitempty"`
Comment on lines +469 to 470
Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

suggestion (typo): Clarify and clean up the deprecation message wording.

The deprecation message is grammatically awkward (mixed tenses, extra space before the comma) and could confuse users. Prefer something like:

"Deprecated: This field is ignored; use spec.mediatedDevicesConfiguration.enabled instead. It will be removed in the next version of the API."

Also, explicitly including the full field path (spec.mediatedDevicesConfiguration.enabled) and correct casing helps users know exactly what to migrate to.

Suggested change
// Deprecated: This field is ignored and use mediatedDevicesConfiguration.Enabled instead , it will be removed in the next version of the API.
DisableMDevConfiguration *bool `json:"disableMDevConfiguration,omitempty"`
// Deprecated: This field is ignored; use spec.mediatedDevicesConfiguration.enabled instead. It will be removed in the next version of the API.
DisableMDevConfiguration *bool `json:"disableMDevConfiguration,omitempty"`


// Enable persistent reservation of a LUN through the SCSI Persistent Reserve commands on Kubevirt.
Expand Down Expand Up @@ -646,6 +643,12 @@ type MediatedDevicesConfiguration struct {
// +optional
// +listType=atomic
NodeMediatedDeviceTypes []NodeMediatedDeviceTypesConfig `json:"nodeMediatedDeviceTypes,omitempty"`

// Enable the creation and removal of mediated devices by virt-handler
// Replaces the deprecated DisableMDEVConfiguration feature gate
// Defaults to true
// +optional
Enabled *bool `json:"enabled,omitempty"`
}

// NodeMediatedDeviceTypesConfig holds information about MDEV types to be defined in a specific node that matches the NodeSelector field.
Expand Down Expand Up @@ -951,7 +954,7 @@ 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"}},"featureGates": {"downwardMetrics": false, "deployKubeSecondaryDNS": false, "disableMDevConfiguration": false, "persistentReservation": false, "enableMultiArchBootImageImport": false, "decentralizedLiveMigration": true, "declarativeHotplugVolumes": false, "videoConfig": true, "objectGraph": false, "incrementalBackup": false}, "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}
// +kubebuilder:default={"certConfig": {"ca": {"duration": "48h0m0s", "renewBefore": "24h0m0s"}, "server": {"duration": "24h0m0s", "renewBefore": "12h0m0s"}},"featureGates": {"downwardMetrics": false, "deployKubeSecondaryDNS": false, "persistentReservation": false, "enableMultiArchBootImageImport": false, "decentralizedLiveMigration": true, "declarativeHotplugVolumes": false, "videoConfig": true, "objectGraph": false, "incrementalBackup": false}, "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"`
Expand Down
5 changes: 5 additions & 0 deletions api/v1beta1/zz_generated.deepcopy.go

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

4 changes: 0 additions & 4 deletions api/v1beta1/zz_generated.defaults.go

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

10 changes: 8 additions & 2 deletions api/v1beta1/zz_generated.openapi.go

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

12 changes: 8 additions & 4 deletions config/crd/bases/hco.kubevirt.io_hyperconvergeds.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -63,7 +63,6 @@ spec:
decentralizedLiveMigration: true
declarativeHotplugVolumes: false
deployKubeSecondaryDNS: false
disableMDevConfiguration: false
downwardMetrics: false
enableMultiArchBootImageImport: false
incrementalBackup: false
Expand Down Expand Up @@ -1091,7 +1090,6 @@ spec:
decentralizedLiveMigration: true
declarativeHotplugVolumes: false
deployKubeSecondaryDNS: false
disableMDevConfiguration: false
downwardMetrics: false
enableMultiArchBootImageImport: false
incrementalBackup: false
Expand Down Expand Up @@ -1146,8 +1144,8 @@ spec:
Use spec.deployVmConsoleProxy instead
type: boolean
disableMDevConfiguration:
default: false
description: Disable mediated devices handling on KubeVirt
description: 'Deprecated: This field is ignored and use mediatedDevicesConfiguration.Enabled
instead , it will be removed in the next version of the API.'
type: boolean
downwardMetrics:
default: false
Expand Down Expand Up @@ -2494,6 +2492,12 @@ spec:
description: MediatedDevicesConfiguration holds information about
MDEV types to be defined on nodes, if available
properties:
enabled:
description: |-
Enable the creation and removal of mediated devices by virt-handler
Replaces the deprecated DisableMDEVConfiguration feature gate
Defaults to true
type: boolean
mediatedDeviceTypes:
items:
type: string
Expand Down
5 changes: 2 additions & 3 deletions controllers/handlers/kubevirt.go
Original file line number Diff line number Diff line change
Expand Up @@ -612,9 +612,8 @@ func getObsoleteCPUConfig(hcObsoleteCPUConf *hcov1beta1.HyperConvergedObsoleteCP

func toKvMediatedDevicesConfiguration(hc *hcov1beta1.HyperConverged) *kubevirtcorev1.MediatedDevicesConfiguration {
mdevsConfig := hc.Spec.MediatedDevicesConfiguration
disabled := ptr.Deref(hc.Spec.FeatureGates.DisableMDevConfiguration, false)
Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

we do need it. we don't ignoring the FG. if only the FG is true, then we need to set the KubeVirt's enabled field to false. If both the FG is set and our enabled field is set, we'll go with the field.


if mdevsConfig == nil && !disabled {
if mdevsConfig == nil {
return nil
}

Expand All @@ -632,7 +631,7 @@ func toKvMediatedDevicesConfiguration(hc *hcov1beta1.HyperConverged) *kubevirtco
kvMdev.NodeMediatedDeviceTypes = toKvNodeMediatedDevicesConfiguration(mdevsConfig.NodeMediatedDeviceTypes)
}

if disabled {
if !ptr.Deref(mdevsConfig.Enabled, true) {
kvMdev.Enabled = ptr.To(false)
}

Expand Down
22 changes: 16 additions & 6 deletions controllers/handlers/kubevirt_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -798,9 +798,19 @@ Version: 1.2.3`)
Expect(kv.Spec.Configuration.MediatedDevicesConfiguration).To(BeNil())
})

It("should propagate the mediated devices configuration, only with the Enabled field, if not set in HCO, and the FG is true", func() {
It("should not propagate the mediated devices configuration is empty", func() {
hco.Spec.MediatedDevicesConfiguration = nil
hco.Spec.FeatureGates.DisableMDevConfiguration = ptr.To(true)

kv, err := NewKubeVirt(hco)
Expect(err).ToNot(HaveOccurred())

Expect(kv.Spec.Configuration.MediatedDevicesConfiguration).To(BeNil())
})

It("should propagate the mediated devices configuration, only with the Enabled field, if enabled set to false in HCO", func() {
hco.Spec.MediatedDevicesConfiguration = &hcov1beta1.MediatedDevicesConfiguration{
Enabled: ptr.To(false),
}

kv, err := NewKubeVirt(hco)
Expect(err).ToNot(HaveOccurred())
Expand Down Expand Up @@ -1081,10 +1091,10 @@ Version: 1.2.3`)
Expect(mdc.MediatedDeviceTypes).To(ContainElements("nvidia-181", "nvidia-191", "nvidia-224"))
})

It("should set the enabled field to false, if the DisableMDevConfiguration FG is enabled", func() {
hco.Spec.FeatureGates.DisableMDevConfiguration = ptr.To(true)
It("should set the enabled field to false, if enabled set to false in HCO", func() {
hco.Spec.MediatedDevicesConfiguration = &hcov1beta1.MediatedDevicesConfiguration{
MediatedDeviceTypes: []string{"nvidia-222", "nvidia-230"},
Enabled: ptr.To(false),
}

kv, err := NewKubeVirt(hco)
Expand All @@ -1095,7 +1105,7 @@ Version: 1.2.3`)
})

It("should not set the enabled field, if the DisableMDevConfiguration FG is disabled", func() {
hco.Spec.FeatureGates.DisableMDevConfiguration = ptr.To(false)
hco.Spec.FeatureGates.DisableMDevConfiguration = ptr.To(false) //nolint:staticcheck // Testing deprecated FG behavior.
hco.Spec.MediatedDevicesConfiguration = &hcov1beta1.MediatedDevicesConfiguration{
MediatedDeviceTypes: []string{"nvidia-222", "nvidia-230"},
}
Expand All @@ -1108,7 +1118,7 @@ Version: 1.2.3`)
})

It("should not set the enabled field, if the DisableMDevConfiguration FG is nil", func() {
hco.Spec.FeatureGates.DisableMDevConfiguration = nil
hco.Spec.FeatureGates.DisableMDevConfiguration = nil //nolint:staticcheck // Testing deprecated FG behavior.
hco.Spec.MediatedDevicesConfiguration = &hcov1beta1.MediatedDevicesConfiguration{
MediatedDeviceTypes: []string{"nvidia-222", "nvidia-230"},
}
Expand Down
33 changes: 33 additions & 0 deletions controllers/hyperconverged/hyperconverged_controller.go
Original file line number Diff line number Diff line change
Expand Up @@ -383,6 +383,13 @@ func (r *ReconcileHyperConverged) doReconcile(req *common.HcoRequest) (reconcile
return reconcile.Result{}, nil
}

// Controller-driven upgrade: if deprecated disableMDevConfiguration is true and
// mediatedDevicesConfiguration.enabled is missing, set enabled=false so the CR
// is migrated without requiring a user edit. updateHyperConverged will persist it.
if r.migrateMDevConfigurationIfNeeded(req) {
req.Logger.Info("Migrated HCO spec: set mediatedDevicesConfiguration.enabled from deprecated disableMDevConfiguration")
}

Comment on lines +386 to +392
Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This code should be in the mutating webhook.

// Add conditions if there are none
init := req.Instance.Status.Conditions == nil
if init {
Expand Down Expand Up @@ -1120,6 +1127,32 @@ func (r *ReconcileHyperConverged) setOperatorUpgradeableStatus(request *common.H
return nil
}

// migrateMDevConfigurationIfNeeded performs a controller-driven upgrade: when the deprecated
Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

same

// spec.featureGates.disableMDevConfiguration is true and spec.mediatedDevicesConfiguration.enabled
// is missing, it sets enabled=false so the CR is migrated without requiring a user edit.
// Returns true if the spec was modified (caller should set req.Dirty and requeue).
func (r *ReconcileHyperConverged) migrateMDevConfigurationIfNeeded(req *common.HcoRequest) bool {
//nolint:staticcheck // Read deprecated field to migrate existing CRs.
if req.Instance.Spec.FeatureGates.DisableMDevConfiguration == nil ||
!*req.Instance.Spec.FeatureGates.DisableMDevConfiguration {
return false
}
mdc := req.Instance.Spec.MediatedDevicesConfiguration
if mdc == nil {
req.Instance.Spec.MediatedDevicesConfiguration = &hcov1beta1.MediatedDevicesConfiguration{
Enabled: ptr.To(false),
}
req.Dirty = true
return true
}
if mdc.Enabled != nil {
return false
}
mdc.Enabled = ptr.To(false)
req.Dirty = true
return true
}

func (r *ReconcileHyperConverged) migrateBeforeUpgrade(req *common.HcoRequest) (bool, error) {
upgradePatched, err := r.applyUpgradePatches(req)
if err != nil {
Expand Down
27 changes: 27 additions & 0 deletions controllers/hyperconverged/hyperconverged_controller_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -860,6 +860,33 @@ var _ = Describe("HyperconvergedController", func() {
Expect(foundResource.Finalizers).To(Equal([]string{FinalizerName}))
})

It("should migrate mediatedDevicesConfiguration.enabled from deprecated disableMDevConfiguration on reconcile", func() {
Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

same

expected := getBasicDeployment()
//nolint:staticcheck // Intentionally set deprecated FG to test controller-driven migration.
expected.hco.Spec.FeatureGates.DisableMDevConfiguration = ptr.To(true)
expected.hco.Spec.MediatedDevicesConfiguration = &hcov1beta1.MediatedDevicesConfiguration{
MediatedDeviceTypes: []string{"nvidia-222"},
Enabled: nil, // missing; controller should set to false
}
cl := expected.initClient()
foundResource, _, _ := doReconcile(cl, expected.hco, nil)
Expect(foundResource.Spec.MediatedDevicesConfiguration).ToNot(BeNil())
Expect(foundResource.Spec.MediatedDevicesConfiguration.Enabled).ToNot(BeNil())
Expect(*foundResource.Spec.MediatedDevicesConfiguration.Enabled).To(BeFalse())
})

It("should create mediatedDevicesConfiguration with enabled=false when FG is true and MDC is nil", func() {
expected := getBasicDeployment()
//nolint:staticcheck // Intentionally set deprecated FG to test controller-driven migration.
expected.hco.Spec.FeatureGates.DisableMDevConfiguration = ptr.To(true)
expected.hco.Spec.MediatedDevicesConfiguration = nil
cl := expected.initClient()
foundResource, _, _ := doReconcile(cl, expected.hco, nil)
Expect(foundResource.Spec.MediatedDevicesConfiguration).ToNot(BeNil())
Expect(foundResource.Spec.MediatedDevicesConfiguration.Enabled).ToNot(BeNil())
Expect(*foundResource.Spec.MediatedDevicesConfiguration.Enabled).To(BeFalse())
})

It("Should not be ready if one of the operands is returns error, on create", func() {
hco := commontestutils.NewHco()
cl := commontestutils.InitClient([]client.Object{hcoNamespace, hco})
Expand Down
12 changes: 8 additions & 4 deletions deploy/crds/hco00.crd.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -63,7 +63,6 @@ spec:
decentralizedLiveMigration: true
declarativeHotplugVolumes: false
deployKubeSecondaryDNS: false
disableMDevConfiguration: false
downwardMetrics: false
enableMultiArchBootImageImport: false
incrementalBackup: false
Expand Down Expand Up @@ -1091,7 +1090,6 @@ spec:
decentralizedLiveMigration: true
declarativeHotplugVolumes: false
deployKubeSecondaryDNS: false
disableMDevConfiguration: false
downwardMetrics: false
enableMultiArchBootImageImport: false
incrementalBackup: false
Expand Down Expand Up @@ -1146,8 +1144,8 @@ spec:
Use spec.deployVmConsoleProxy instead
type: boolean
disableMDevConfiguration:
default: false
description: Disable mediated devices handling on KubeVirt
description: 'Deprecated: This field is ignored and use mediatedDevicesConfiguration.Enabled
instead , it will be removed in the next version of the API.'
type: boolean
downwardMetrics:
default: false
Expand Down Expand Up @@ -2494,6 +2492,12 @@ spec:
description: MediatedDevicesConfiguration holds information about
MDEV types to be defined on nodes, if available
properties:
enabled:
description: |-
Enable the creation and removal of mediated devices by virt-handler
Replaces the deprecated DisableMDEVConfiguration feature gate
Defaults to true
type: boolean
mediatedDeviceTypes:
items:
type: string
Expand Down
1 change: 0 additions & 1 deletion deploy/hco.cr.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -19,7 +19,6 @@ spec:
decentralizedLiveMigration: true
declarativeHotplugVolumes: false
deployKubeSecondaryDNS: false
disableMDevConfiguration: false
downwardMetrics: false
enableMultiArchBootImageImport: false
incrementalBackup: false
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -63,7 +63,6 @@ spec:
decentralizedLiveMigration: true
declarativeHotplugVolumes: false
deployKubeSecondaryDNS: false
disableMDevConfiguration: false
downwardMetrics: false
enableMultiArchBootImageImport: false
incrementalBackup: false
Expand Down Expand Up @@ -1091,7 +1090,6 @@ spec:
decentralizedLiveMigration: true
declarativeHotplugVolumes: false
deployKubeSecondaryDNS: false
disableMDevConfiguration: false
downwardMetrics: false
enableMultiArchBootImageImport: false
incrementalBackup: false
Expand Down Expand Up @@ -1146,8 +1144,8 @@ spec:
Use spec.deployVmConsoleProxy instead
type: boolean
disableMDevConfiguration:
default: false
description: Disable mediated devices handling on KubeVirt
description: 'Deprecated: This field is ignored and use mediatedDevicesConfiguration.Enabled
instead , it will be removed in the next version of the API.'
type: boolean
downwardMetrics:
default: false
Expand Down Expand Up @@ -2494,6 +2492,12 @@ spec:
description: MediatedDevicesConfiguration holds information about
MDEV types to be defined on nodes, if available
properties:
enabled:
description: |-
Enable the creation and removal of mediated devices by virt-handler
Replaces the deprecated DisableMDEVConfiguration feature gate
Defaults to true
type: boolean
mediatedDeviceTypes:
items:
type: string
Expand Down
Loading
Loading