diff --git a/Taskfile.yaml b/Taskfile.yaml index 93eef4dcee..020d59f4f7 100644 --- a/Taskfile.yaml +++ b/Taskfile.yaml @@ -165,8 +165,7 @@ tasks: "ports": [ { "containerPort": 2345, "name": "dlv" } ], "readinessProbe": null, "livenessProbe": null, - "command": null, - "args": [] + "command": null }, { "name": "proxy", @@ -264,8 +263,7 @@ tasks: "ports": [ { "containerPort": 2345, "name": "dlv" } ], "readinessProbe": null, "livenessProbe": null, - "command": null, - "args": [] + "command": null }, { "name": "proxy", @@ -282,5 +280,5 @@ tasks: } } }' - kubectl -n d8-virtualization port-forward deploy/vit-api 2345:2345 + kubectl -n d8-virtualization port-forward deploy/virt-api 2345:2345 EOF diff --git a/api/client/examples/cancel-evacuation/go.mod b/api/client/examples/cancel-evacuation/go.mod index 63f821ce75..86339fe572 100644 --- a/api/client/examples/cancel-evacuation/go.mod +++ b/api/client/examples/cancel-evacuation/go.mod @@ -53,8 +53,8 @@ require ( k8s.io/klog/v2 v2.130.1 // indirect k8s.io/kube-openapi v0.0.0-20250701173324-9bd5c66d9911 // indirect k8s.io/utils v0.0.0-20241104100929-3ea5e8cea738 // indirect - kubevirt.io/api v1.3.1 // indirect - kubevirt.io/containerized-data-importer-api v1.57.0-alpha1 // indirect + kubevirt.io/api v1.6.2 // indirect + kubevirt.io/containerized-data-importer-api v1.60.3-0.20241105012228-50fbed985de9 // indirect kubevirt.io/controller-lifecycle-operator-sdk/api v0.0.0-20220329064328-f3cc58c6ed90 // indirect sigs.k8s.io/json v0.0.0-20241010143419-9aa6b5e7a4b3 // indirect sigs.k8s.io/randfill v1.0.0 // indirect diff --git a/api/client/examples/cancel-evacuation/go.sum b/api/client/examples/cancel-evacuation/go.sum index d7db165b6a..cf69ab2158 100644 --- a/api/client/examples/cancel-evacuation/go.sum +++ b/api/client/examples/cancel-evacuation/go.sum @@ -372,8 +372,10 @@ k8s.io/utils v0.0.0-20241104100929-3ea5e8cea738 h1:M3sRQVHv7vB20Xc2ybTt7ODCeFj6J k8s.io/utils v0.0.0-20241104100929-3ea5e8cea738/go.mod h1:OLgZIPagt7ERELqWJFomSt595RzquPNLL48iOWgYOg0= kubevirt.io/api v1.3.1 h1:MoTNo/zvDlZ44c2ocXLPln8XTaQOeUodiYbEKrTCqv4= kubevirt.io/api v1.3.1/go.mod h1:tCn7VAZktEvymk490iPSMPCmKM9UjbbfH2OsFR/IOLU= +kubevirt.io/api v1.6.2/go.mod h1:p66fEy/g79x7VpgUwrkUgOoG2lYs5LQq37WM6JXMwj4= kubevirt.io/containerized-data-importer-api v1.57.0-alpha1 h1:IWo12+ei3jltSN5jQN1xjgakfvRSF3G3Rr4GXVOOy2I= kubevirt.io/containerized-data-importer-api v1.57.0-alpha1/go.mod h1:Y/8ETgHS1GjO89bl682DPtQOYEU/1ctPFBz6Sjxm4DM= +kubevirt.io/containerized-data-importer-api v1.60.3-0.20241105012228-50fbed985de9/go.mod h1:SDJjLGhbPyayDqAqawcGmVNapBp0KodOQvhKPLVGCQU= kubevirt.io/controller-lifecycle-operator-sdk/api v0.0.0-20220329064328-f3cc58c6ed90 h1:QMrd0nKP0BGbnxTqakhDZAUhGKxPiPiN5gSDqKUmGGc= kubevirt.io/controller-lifecycle-operator-sdk/api v0.0.0-20220329064328-f3cc58c6ed90/go.mod h1:018lASpFYBsYN6XwmA2TIrPCx6e0gviTd/ZNtSitKgc= sigs.k8s.io/json v0.0.0-20211020170558-c049b76a60c6/go.mod h1:p4QtZmO4uMYipTQNzagwnNoseA6OxSUutVw05NhYDRs= diff --git a/api/client/examples/list-resources/go.mod b/api/client/examples/list-resources/go.mod index 8251bcd219..9888494628 100644 --- a/api/client/examples/list-resources/go.mod +++ b/api/client/examples/list-resources/go.mod @@ -49,8 +49,8 @@ require ( k8s.io/klog/v2 v2.130.1 // indirect k8s.io/kube-openapi v0.0.0-20250701173324-9bd5c66d9911 // indirect k8s.io/utils v0.0.0-20241104100929-3ea5e8cea738 // indirect - kubevirt.io/api v1.3.1 // indirect - kubevirt.io/containerized-data-importer-api v1.57.0-alpha1 // indirect + kubevirt.io/api v1.6.2 // indirect + kubevirt.io/containerized-data-importer-api v1.60.3-0.20241105012228-50fbed985de9 // indirect kubevirt.io/controller-lifecycle-operator-sdk/api v0.0.0-20220329064328-f3cc58c6ed90 // indirect sigs.k8s.io/json v0.0.0-20241010143419-9aa6b5e7a4b3 // indirect sigs.k8s.io/randfill v1.0.0 // indirect diff --git a/api/client/examples/list-resources/go.sum b/api/client/examples/list-resources/go.sum index 3dba2c12dd..2e9bbd8060 100644 --- a/api/client/examples/list-resources/go.sum +++ b/api/client/examples/list-resources/go.sum @@ -365,8 +365,10 @@ k8s.io/utils v0.0.0-20241104100929-3ea5e8cea738 h1:M3sRQVHv7vB20Xc2ybTt7ODCeFj6J k8s.io/utils v0.0.0-20241104100929-3ea5e8cea738/go.mod h1:OLgZIPagt7ERELqWJFomSt595RzquPNLL48iOWgYOg0= kubevirt.io/api v1.3.1 h1:MoTNo/zvDlZ44c2ocXLPln8XTaQOeUodiYbEKrTCqv4= kubevirt.io/api v1.3.1/go.mod h1:tCn7VAZktEvymk490iPSMPCmKM9UjbbfH2OsFR/IOLU= +kubevirt.io/api v1.6.2/go.mod h1:p66fEy/g79x7VpgUwrkUgOoG2lYs5LQq37WM6JXMwj4= kubevirt.io/containerized-data-importer-api v1.57.0-alpha1 h1:IWo12+ei3jltSN5jQN1xjgakfvRSF3G3Rr4GXVOOy2I= kubevirt.io/containerized-data-importer-api v1.57.0-alpha1/go.mod h1:Y/8ETgHS1GjO89bl682DPtQOYEU/1ctPFBz6Sjxm4DM= +kubevirt.io/containerized-data-importer-api v1.60.3-0.20241105012228-50fbed985de9/go.mod h1:SDJjLGhbPyayDqAqawcGmVNapBp0KodOQvhKPLVGCQU= kubevirt.io/controller-lifecycle-operator-sdk/api v0.0.0-20220329064328-f3cc58c6ed90 h1:QMrd0nKP0BGbnxTqakhDZAUhGKxPiPiN5gSDqKUmGGc= kubevirt.io/controller-lifecycle-operator-sdk/api v0.0.0-20220329064328-f3cc58c6ed90/go.mod h1:018lASpFYBsYN6XwmA2TIrPCx6e0gviTd/ZNtSitKgc= sigs.k8s.io/json v0.0.0-20211020170558-c049b76a60c6/go.mod h1:p4QtZmO4uMYipTQNzagwnNoseA6OxSUutVw05NhYDRs= diff --git a/api/go.mod b/api/go.mod index 79b0495d1e..5ecfde9d8f 100644 --- a/api/go.mod +++ b/api/go.mod @@ -17,7 +17,7 @@ require ( k8s.io/apiextensions-apiserver v0.33.3 k8s.io/apimachinery v0.33.3 k8s.io/client-go v0.33.3 - kubevirt.io/api v1.3.1 + kubevirt.io/api v1.6.2 sigs.k8s.io/controller-runtime v0.21.0 ) @@ -46,7 +46,6 @@ require ( github.com/modern-go/concurrent v0.0.0-20180306012644-bacd9c7ef1dd // indirect github.com/modern-go/reflect2 v1.0.2 // indirect github.com/munnerz/goautoneg v0.0.0-20191010083416-a7dc8b61c822 // indirect - github.com/openshift/api v0.0.0-20230503133300-8bbcb7ca7183 // indirect github.com/openshift/custom-resource-status v1.1.2 // indirect github.com/pkg/errors v0.9.1 // indirect github.com/spf13/cobra v1.9.1 // indirect @@ -70,9 +69,8 @@ require ( k8s.io/code-generator v0.33.3 // indirect k8s.io/gengo/v2 v2.0.0-20250604051438-85fd79dbfd9f // indirect k8s.io/klog/v2 v2.130.1 // indirect - k8s.io/kube-openapi v0.0.0-20250701173324-9bd5c66d9911 // indirect k8s.io/utils v0.0.0-20241104100929-3ea5e8cea738 // indirect - kubevirt.io/containerized-data-importer-api v1.57.0-alpha1 // indirect + kubevirt.io/containerized-data-importer-api v1.60.3-0.20241105012228-50fbed985de9 // indirect kubevirt.io/controller-lifecycle-operator-sdk/api v0.0.0-20220329064328-f3cc58c6ed90 // indirect sigs.k8s.io/controller-tools v0.18.0 // indirect sigs.k8s.io/json v0.0.0-20241010143419-9aa6b5e7a4b3 // indirect diff --git a/api/go.sum b/api/go.sum index fd5f073e7c..af967a273e 100644 --- a/api/go.sum +++ b/api/go.sum @@ -208,8 +208,6 @@ github.com/onsi/gomega v1.33.0/go.mod h1:+925n5YtiFsLzzafLUHzVMBpvvRAzrydIBiSIxj github.com/onsi/gomega v1.33.1/go.mod h1:U4R44UsT+9eLIaYRB2a5qajjtQYn0hauxvRm16AVYg0= github.com/onsi/gomega v1.37.0 h1:CdEG8g0S133B4OswTDC/5XPSzE1OeP29QOioj2PID2Y= github.com/onsi/gomega v1.37.0/go.mod h1:8D9+Txp43QWKhM24yyOBEdpkzN8FvJyAwecBgsU4KU0= -github.com/openshift/api v0.0.0-20230503133300-8bbcb7ca7183 h1:t/CahSnpqY46sQR01SoS+Jt0jtjgmhgE6lFmRnO4q70= -github.com/openshift/api v0.0.0-20230503133300-8bbcb7ca7183/go.mod h1:4VWG+W22wrB4HfBL88P40DxLEpSOaiBVxUnfalfJo9k= github.com/openshift/custom-resource-status v1.1.2 h1:C3DL44LEbvlbItfd8mT5jWrqPfHnSOQoQf/sypqA6A4= github.com/openshift/custom-resource-status v1.1.2/go.mod h1:DB/Mf2oTeiAmVVX1gN+NEqweonAPY0TKUwADizj8+ZA= github.com/orisano/pixelmatch v0.0.0-20220722002657-fb0b55479cde/go.mod h1:nZgzbfBr3hhjoZnS66nKrHmduYNpc34ny7RK4z5/HM0= @@ -568,10 +566,10 @@ k8s.io/utils v0.0.0-20211116205334-6203023598ed/go.mod h1:jPW/WVKK9YHAvNhRxK0md/ k8s.io/utils v0.0.0-20240711033017-18e509b52bc8/go.mod h1:OLgZIPagt7ERELqWJFomSt595RzquPNLL48iOWgYOg0= k8s.io/utils v0.0.0-20241104100929-3ea5e8cea738 h1:M3sRQVHv7vB20Xc2ybTt7ODCeFj6JSWYFzOFnYeS6Ro= k8s.io/utils v0.0.0-20241104100929-3ea5e8cea738/go.mod h1:OLgZIPagt7ERELqWJFomSt595RzquPNLL48iOWgYOg0= -kubevirt.io/api v1.3.1 h1:MoTNo/zvDlZ44c2ocXLPln8XTaQOeUodiYbEKrTCqv4= -kubevirt.io/api v1.3.1/go.mod h1:tCn7VAZktEvymk490iPSMPCmKM9UjbbfH2OsFR/IOLU= -kubevirt.io/containerized-data-importer-api v1.57.0-alpha1 h1:IWo12+ei3jltSN5jQN1xjgakfvRSF3G3Rr4GXVOOy2I= -kubevirt.io/containerized-data-importer-api v1.57.0-alpha1/go.mod h1:Y/8ETgHS1GjO89bl682DPtQOYEU/1ctPFBz6Sjxm4DM= +kubevirt.io/api v1.6.2 h1:aoqZ4KsbOyDjLnuDw7H9wEgE/YTd/q5BBmYeQjJNizc= +kubevirt.io/api v1.6.2/go.mod h1:p66fEy/g79x7VpgUwrkUgOoG2lYs5LQq37WM6JXMwj4= +kubevirt.io/containerized-data-importer-api v1.60.3-0.20241105012228-50fbed985de9 h1:KTb8wO1Lxj220DX7d2Rdo9xovvlyWWNo3AVm2ua+1nY= +kubevirt.io/containerized-data-importer-api v1.60.3-0.20241105012228-50fbed985de9/go.mod h1:SDJjLGhbPyayDqAqawcGmVNapBp0KodOQvhKPLVGCQU= kubevirt.io/controller-lifecycle-operator-sdk/api v0.0.0-20220329064328-f3cc58c6ed90 h1:QMrd0nKP0BGbnxTqakhDZAUhGKxPiPiN5gSDqKUmGGc= kubevirt.io/controller-lifecycle-operator-sdk/api v0.0.0-20220329064328-f3cc58c6ed90/go.mod h1:018lASpFYBsYN6XwmA2TIrPCx6e0gviTd/ZNtSitKgc= sigs.k8s.io/controller-runtime v0.21.0 h1:CYfjpEuicjUecRk+KAeyYh+ouUBn4llGyDYytIGcJS8= diff --git a/build/components/versions.yml b/build/components/versions.yml index 906d683c8a..0df96ff257 100644 --- a/build/components/versions.yml +++ b/build/components/versions.yml @@ -3,7 +3,7 @@ firmware: libvirt: v10.9.0 edk2: stable202411 core: - 3p-kubevirt: v1.3.1-v12n.25 + 3p-kubevirt: v1.6.2-virtualization 3p-containerized-data-importer: v1.60.3-v12n.12 distribution: 2.8.3 package: diff --git a/crds/embedded/virtualmachineinstances.yaml b/crds/embedded/virtualmachineinstances.yaml index b9cc1d5949..a36f250777 100644 --- a/crds/embedded/virtualmachineinstances.yaml +++ b/crds/embedded/virtualmachineinstances.yaml @@ -461,7 +461,7 @@ spec: 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. - This is an alpha field and requires enabling MatchLabelKeysInPodAffinity feature gate. + This is a beta field and requires enabling MatchLabelKeysInPodAffinity feature gate (enabled by default). items: type: string type: array @@ -476,7 +476,7 @@ spec: 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. - This is an alpha field and requires enabling MatchLabelKeysInPodAffinity feature gate. + This is a beta field and requires enabling MatchLabelKeysInPodAffinity feature gate (enabled by default). items: type: string type: array @@ -642,7 +642,7 @@ spec: 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. - This is an alpha field and requires enabling MatchLabelKeysInPodAffinity feature gate. + This is a beta field and requires enabling MatchLabelKeysInPodAffinity feature gate (enabled by default). items: type: string type: array @@ -657,7 +657,7 @@ spec: 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. - This is an alpha field and requires enabling MatchLabelKeysInPodAffinity feature gate. + This is a beta field and requires enabling MatchLabelKeysInPodAffinity feature gate (enabled by default). items: type: string type: array @@ -820,7 +820,7 @@ spec: 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. - This is an alpha field and requires enabling MatchLabelKeysInPodAffinity feature gate. + This is a beta field and requires enabling MatchLabelKeysInPodAffinity feature gate (enabled by default). items: type: string type: array @@ -835,7 +835,7 @@ spec: 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. - This is an alpha field and requires enabling MatchLabelKeysInPodAffinity feature gate. + This is a beta field and requires enabling MatchLabelKeysInPodAffinity feature gate (enabled by default). items: type: string type: array @@ -1001,7 +1001,7 @@ spec: 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. - This is an alpha field and requires enabling MatchLabelKeysInPodAffinity feature gate. + This is a beta field and requires enabling MatchLabelKeysInPodAffinity feature gate (enabled by default). items: type: string type: array @@ -1016,7 +1016,7 @@ spec: 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. - This is an alpha field and requires enabling MatchLabelKeysInPodAffinity feature gate. + This is a beta field and requires enabling MatchLabelKeysInPodAffinity feature gate (enabled by default). items: type: string type: array @@ -1127,9 +1127,12 @@ spec: of a pod. properties: name: - description: Required. + description: |- + DNS resolver option name. + Required field. type: string value: + description: DNS resolver option value. type: string type: object type: array @@ -1447,7 +1450,11 @@ spec: cache: description: |- Cache specifies which kvm disk cache mode should be used. - Supported values are: CacheNone, CacheWriteThrough. + Supported values are: + none: Guest I/O not cached on the host, but may be kept in a disk cache. + writethrough: Guest I/O cached on the host but written through to the physical medium. Slowest but with most guarantees. + writeback: Guest I/O cached on the host. + Defaults to none if the storage supports O_DIRECT, otherwise writethrough. type: string cdrom: description: Attach a volume as a cdrom to the vmi. @@ -1567,16 +1574,24 @@ spec: description: Whether to attach a GPU device to the vmi. items: properties: + claimName: + description: |- + Must be provided from `vmi.spec.resourceClaims[].name` where this + device is allocated. + type: string deviceName: + description: Name of the device provisioned by device plugins. type: string name: - description: Name of the GPU device as exposed by a - device plugin + description: Name of the GPU device as exposed by a device plugin. + type: string + requestName: + description: |- + Must be provided from `resourceClaim.spec.devices.requests[].name` where this + device is requested. type: string tag: - description: If specified, the virtual network interface - address and its tag will be provided to the guest - via config drive + description: If specified, the virtual network interface address and its tag will be provided to the guest via config drive. type: string virtualGPUOptions: properties: @@ -1601,7 +1616,6 @@ spec: type: object type: object required: - - deviceName - name type: object type: array @@ -1610,19 +1624,25 @@ spec: description: Whether to attach a host device to the vmi. items: properties: + claimName: + description: |- + Must be provided from `vmi.spec.resourceClaims[].name` where this + device is allocated. + type: string deviceName: - description: DeviceName is the resource name of the - host device exposed by a device plugin + description: Name of the device provisioned by device plugins. type: string name: type: string + requestName: + description: |- + Must be provided from `resourceClaim.spec.devices.requests[].name` where this + device is requested. + type: string tag: - description: If specified, the virtual network interface - address and its tag will be provided to the guest - via config drive + description: If specified, the virtual network interface address and its tag will be provided to the guest via config drive. type: string required: - - deviceName - name type: object type: array @@ -1743,9 +1763,8 @@ spec: model: description: |- Interface model. - One of: e1000, e1000e, ne2k_pci, pcnet, rtl8139, virtio. + One of: e1000, e1000e, igb, ne2k_pci, pcnet, rtl8139, virtio. Defaults to virtio. - TODO:(ihar) switch to enums once opengen-api supports them. See: https://github.com/kubernetes/kube-openapi/issues/51 type: string name: description: |- @@ -1805,7 +1824,11 @@ spec: state: description: |- State represents the requested operational state of the interface. - The (only) value supported is 'absent', expressing a request to remove the interface. + The supported values are: + 'absent', expressing a request to remove the interface. + 'down', expressing a request to set the link down. + 'up', expressing a request to set the link up. + Empty value functions as 'up'. type: string tag: description: If specified, the virtual network interface @@ -1831,6 +1854,18 @@ spec: depends on additional factors of the VirtualMachineInstance, like the number of guest CPUs. type: boolean + panicDevices: + description: Provides additional crash information when a guest crashes. + items: + properties: + model: + description: |- + Type of panic device to provide. + If this attribute is missing, the panic model used depends on the hypervisor and guest architecture. + Valid values: `isa`, `hyperv`, `pvpanic`. + type: string + type: object + type: array rng: description: Whether to have random number generator from host @@ -1853,10 +1888,15 @@ spec: tpm: description: Whether to emulate a TPM device. properties: + enabled: + description: |- + Allows explicitly disabling the vTPM even when one is enabled by a preference referenced by the VirtualMachine. + Defaults to true. + type: boolean persistent: description: |- - Persistent indicates the state of the TPM device should be kept accross reboots - Defaults to false + Indicates whether the state of the TPM device should be kept across reboots. + Defaults to false. type: boolean type: object useVirtioTransitional: @@ -1865,10 +1905,28 @@ spec: This is helpful for old machines like CentOS6 or RHEL6 which do not understand virtio_non_transitional (virtio 1.0). type: boolean + video: + description: Video device configuration for the VMI. + properties: + type: + description: |- + Video device type (e.g., virtio, vga, bochs, ramfb). + If not specified, the default is architecture-dependent: VGA for BIOS-based VMs, Bochs for EFI-based VMs on AMD64, virtio for Arm and s390x. + type: string + type: object watchdog: description: Watchdog describes a watchdog device which can be added to the vmi. properties: + diag288: + description: diag288 watchdog device specific to s390x architecture. + properties: + action: + description: |- + Action to take when the watchdog triggers. Valid values: poweroff, reset, shutdown. + Defaults to reset. + type: string + type: object i6300esb: description: i6300esb watchdog device. properties: @@ -2138,6 +2196,11 @@ spec: acpi: description: Information that can be set in the ACPI table properties: + msdmNameRef: + description: |- + Similar to SlicNameRef, another ACPI entry that is used in more recent Windows versions. + The above points to the spec of MSDM too. + type: string slicNameRef: description: |- SlicNameRef should match the volume name of a secret object. The data in the secret should @@ -2221,11 +2284,19 @@ spec: Defaults to a random generated uid. type: string type: object + ioThreads: + description: IOThreads options. + properties: + supplementalPoolThreadCount: + description: Number of IO threads allocated for the `supplementalPool` policy. + format: int32 + type: integer + type: object ioThreadsPolicy: description: |- - Controls whether or not disks will share IOThreads. - Omitting IOThreadsPolicy disables use of IOThreads. - One of: shared, auto + Controls whether disks share IOThreads. + Omitting this field disables the use of IOThreads. + Valid values: shared, auto, supplementalPool. type: string launchSecurity: description: Launch Security setting of the vmi. @@ -2340,7 +2411,7 @@ spec: - "None": No action will be taken, according to the specified 'RunStrategy' the VirtualMachine will be restarted or shutdown. - "LiveMigrate": the VirtualMachineInstance will be migrated instead of being shutdown. - "LiveMigrateIfPossible": the same as "LiveMigrate" but only if the VirtualMachine is Live-Migratable, otherwise it will behave as "None". - - "External": the VirtualMachineInstance will be protected by a PDB and 'vmi.Status.EvacuationNodeName' will be set on eviction. This is mainly useful for cluster-api-provider-kubevirt (capk) which needs a way for VMI's to be blocked from eviction, yet signal capk that eviction has been called on the VMI so the capk controller can handle tearing the VMI down. Details can be found in the commit description https://github.com/kubevirt/kubevirt/commit/c1d77face705c8b126696bac9a3ee3825f27f1fa. + - "External": the VirtualMachineInstance will be protected and 'vmi.Status.EvacuationNodeName' will be set on eviction. This is mainly useful for cluster-api-provider-kubevirt (capk) which needs a way for VMI's to be blocked from eviction, yet signal capk that eviction has been called on the VMI so the capk controller can handle tearing the VMI down. Details can be found in the commit description https://github.com/kubevirt/kubevirt/commit/c1d77face705c8b126696bac9a3ee3825f27f1fa. type: string hostname: description: |- @@ -2453,7 +2524,6 @@ spec: description: |- TCPSocket specifies an action involving a TCP port. TCP hooks not yet supported - TODO: implement a realistic TCP lifecycle hook properties: host: description: 'Optional: Host name to connect to, defaults @@ -2652,7 +2722,6 @@ spec: description: |- TCPSocket specifies an action involving a TCP port. TCP hooks not yet supported - TODO: implement a realistic TCP lifecycle hook properties: host: description: 'Optional: Host name to connect to, defaults @@ -2682,6 +2751,57 @@ spec: format: int32 type: integer type: object + resourceClaims: + description: |- + Defines which ResourceClaims must be allocated and reserved before the VMI, + hence the `virt-launcher` pod is allowed to start. The resources will be made available to the domain + which consumes them by name. + + This is an alpha field and requires enabling the `DynamicResourceAllocation` feature gate in Kubernetes. + See https://kubernetes.io/docs/concepts/scheduling-eviction/dynamic-resource-allocation/ + This field should only be configured if one of the feature gates `GPUsWithDRA` or `HostDevicesWithDRA` is enabled. + This feature is in alpha. + items: + description: |- + References exactly one ResourceClaim, either directly + or by naming a ResourceClaimTemplate which is then turned into a ResourceClaim + for the pod. + + Adds a name that uniquely identifies the ResourceClaim inside the pod. + Containers that need access to the ResourceClaim reference it with this name. + properties: + name: + description: |- + Uniquely identifies this resource claim inside the pod. + Must be a `DNS_LABEL`. + type: string + resourceClaimName: + description: |- + Name of a ResourceClaim object in the same namespace as this pod. + + Exactly one of `ResourceClaimName` and `ResourceClaimTemplateName` must be set. + type: string + resourceClaimTemplateName: + description: |- + Name of a ResourceClaimTemplate object in the same namespace as this pod. + + The template will be used to create a new ResourceClaim, which will be bound to this pod. + When this pod is deleted, the ResourceClaim will also be deleted. The pod name and resource name, + along with a generated component, will be used to form a unique name for the ResourceClaim, + which will be recorded in `pod.status.resourceClaimStatuses`. + + This field is immutable and no changes will be made to the corresponding ResourceClaim + by the control plane after creating the ResourceClaim. + + Exactly one of `ResourceClaimName` and `ResourceClaimTemplateName` must be set. + type: string + required: + - name + type: object + type: array + x-kubernetes-list-map-keys: + - name + x-kubernetes-list-type: map schedulerName: description: |- If specified, the VMI will be dispatched by specified scheduler. @@ -2809,7 +2929,6 @@ spec: Keys that don't exist in the incoming pod labels will be ignored. A null or empty list means only match against labelSelector. - This is a beta field and requires the MatchLabelKeysInPodTopologySpread feature gate to be enabled (enabled by default). items: type: string @@ -2849,7 +2968,6 @@ spec: Valid values are integers greater than 0. When value is not nil, WhenUnsatisfiable must be DoNotSchedule. - For example, in a 3-zone cluster, MaxSkew is set to 2, MinDomains is set to 5 and pods with the same labelSelector spread as 2/2/2: | zone1 | zone2 | zone3 | @@ -2867,7 +2985,6 @@ spec: - Honor: only nodes matching nodeAffinity/nodeSelector are included in the calculations. - Ignore: nodeAffinity/nodeSelector are ignored. All nodes are included in the calculations. - If this value is nil, the behavior is equivalent to the Honor policy. This is a beta-level feature default enabled by the NodeInclusionPolicyInPodTopologySpread feature flag. type: string @@ -2879,7 +2996,6 @@ spec: has a toleration, are included. - Ignore: node taints are ignored. All nodes are included. - If this value is nil, the behavior is equivalent to the Ignore policy. This is a beta-level feature default enabled by the NodeInclusionPolicyInPodTopologySpread feature flag. type: string @@ -2952,10 +3068,13 @@ spec: that contains config drive networkdata. properties: name: + default: "" description: |- Name of the referent. + This field is effectively required, but due to backwards compatibility is + allowed to be empty. Instances of this type with an empty value here are + almost certainly wrong. More info: https://kubernetes.io/docs/concepts/overview/working-with-objects/names/#names - TODO: Add other useful fields. apiVersion, kind, uid? type: string type: object x-kubernetes-map-type: atomic @@ -2964,10 +3083,13 @@ spec: contains config drive userdata. properties: name: + default: "" description: |- Name of the referent. + This field is effectively required, but due to backwards compatibility is + allowed to be empty. Instances of this type with an empty value here are + almost certainly wrong. More info: https://kubernetes.io/docs/concepts/overview/working-with-objects/names/#names - TODO: Add other useful fields. apiVersion, kind, uid? type: string type: object x-kubernetes-map-type: atomic @@ -2999,10 +3121,13 @@ spec: that contains NoCloud networkdata. properties: name: + default: "" description: |- Name of the referent. + This field is effectively required, but due to backwards compatibility is + allowed to be empty. Instances of this type with an empty value here are + almost certainly wrong. More info: https://kubernetes.io/docs/concepts/overview/working-with-objects/names/#names - TODO: Add other useful fields. apiVersion, kind, uid? type: string type: object x-kubernetes-map-type: atomic @@ -3011,10 +3136,13 @@ spec: contains NoCloud userdata. properties: name: + default: "" description: |- Name of the referent. + This field is effectively required, but due to backwards compatibility is + allowed to be empty. Instances of this type with an empty value here are + almost certainly wrong. More info: https://kubernetes.io/docs/concepts/overview/working-with-objects/names/#names - TODO: Add other useful fields. apiVersion, kind, uid? type: string type: object x-kubernetes-map-type: atomic @@ -3033,10 +3161,13 @@ spec: More info: https://kubernetes.io/docs/tasks/configure-pod-container/configure-pod-configmap/ properties: name: + default: "" description: |- Name of the referent. + This field is effectively required, but due to backwards compatibility is + allowed to be empty. Instances of this type with an empty value here are + almost certainly wrong. More info: https://kubernetes.io/docs/concepts/overview/working-with-objects/names/#names - TODO: Add other useful fields. apiVersion, kind, uid? type: string optional: description: Specify whether the ConfigMap or it's keys @@ -3076,6 +3207,7 @@ spec: description: Path defines the path to disk file in the container type: string hotpluggable: + description: Indicates whether the volume can be hotplugged and hotunplugged. type: boolean required: - image @@ -3086,13 +3218,10 @@ spec: the process of populating that PVC with a disk image. properties: hotpluggable: - description: Hotpluggable indicates whether the volume can - be hotplugged and hotunplugged. + description: Indicates whether the volume can be hotplugged and hotunplugged. type: boolean name: - description: |- - Name of both the DataVolume and the PVC in the same namespace. - After PVC population the DataVolume is garbage collected by default. + description: Name of both the DataVolume and the PVC in the same namespace. type: string required: - name @@ -3258,8 +3387,7 @@ spec: More info: https://kubernetes.io/docs/concepts/storage/persistent-volumes#persistentvolumeclaims type: string hotpluggable: - description: Hotpluggable indicates whether the volume can - be hotplugged and hotunplugged. + description: Indicates whether the volume can be hotplugged and hotunplugged. type: boolean readOnly: description: |- @@ -3287,8 +3415,7 @@ spec: More info: https://kubernetes.io/docs/concepts/storage/persistent-volumes#persistentvolumeclaims type: string hotpluggable: - description: Hotpluggable indicates whether the volume can - be hotplugged and hotunplugged. + description: Indicates whether the volume can be hotplugged and hotunplugged. type: boolean readOnly: description: |- @@ -3340,10 +3467,13 @@ spec: be attached as disk of CDROM type. properties: name: + default: "" description: |- Name of the referent. + This field is effectively required, but due to backwards compatibility is + allowed to be empty. Instances of this type with an empty value here are + almost certainly wrong. More info: https://kubernetes.io/docs/concepts/overview/working-with-objects/names/#names - TODO: Add other useful fields. apiVersion, kind, uid? type: string type: object x-kubernetes-map-type: atomic @@ -3353,10 +3483,13 @@ spec: be attached as disk of CDROM type. properties: name: + default: "" description: |- Name of the referent. + This field is effectively required, but due to backwards compatibility is + allowed to be empty. Instances of this type with an empty value here are + almost certainly wrong. More info: https://kubernetes.io/docs/concepts/overview/working-with-objects/names/#names - TODO: Add other useful fields. apiVersion, kind, uid? type: string type: object x-kubernetes-map-type: atomic @@ -3436,6 +3569,86 @@ spec: format: int32 type: integer type: object + deviceStatus: + description: |- + DeviceStatus reflects the state of devices requested in spec.domain.devices. This is an optional field available + only when DRA feature gate is enabled + This field will only be populated if one of the feature-gates GPUsWithDRA or HostDevicesWithDRA is enabled. + This feature is in alpha. + properties: + gpuStatuses: + description: State of GPUs requested in `spec.domain.devices.gpus`. + items: + properties: + deviceResourceClaimStatus: + description: DRA-related information for the device. + properties: + attributes: + description: |- + Properties of the device that could be used by kubevirt and other components to learn more + about the device, like `pciAddress` or `mdevUUID`. + properties: + mDevUUID: + description: Mediated device UUID of the allocated device. + type: string + pciAddress: + description: PCIe bus address of the allocated device. + type: string + type: object + name: + description: Name of actual device on the host provisioned by the driver as reflected in `resourceclaim.status`. + type: string + resourceClaimName: + description: Name of the resource claims object used to provision this resource. + type: string + type: object + name: + description: Name of the device as specified in `spec.domain.devices.gpus.name` + or `spec.domain.devices.hostDevices.name`. + type: string + required: + - name + type: object + type: array + x-kubernetes-list-type: atomic + hostDeviceStatuses: + description: |- + State of host devices requested in `spec.domain.devices.hostDevices`. + DRA + items: + properties: + deviceResourceClaimStatus: + description: DRA-related information for the device. + properties: + attributes: + description: |- + Properties of the device that could be used by kubevirt and other components to learn more + about the device, like `pciAddress` or `mdevUUID`. + properties: + mDevUUID: + description: Mediated device UUID of the allocated device. + type: string + pciAddress: + description: PCIe bus address of the allocated device. + type: string + type: object + name: + description: Name of actual device on the host provisioned by the driver as reflected in `resourceclaim.status`. + type: string + resourceClaimName: + description: Name of the resource claims object used to provision this resource. + type: string + type: object + name: + description: Name of the device as specified in `spec.domain.devices.gpus.name` + or `spec.domain.devices.hostDevices.name`. + type: string + required: + - name + type: object + type: array + x-kubernetes-list-type: atomic + type: object evacuationNodeName: description: |- EvacuationNodeName is used to track the eviction process of a VMI. It stores the name of the node that we want @@ -3443,8 +3656,9 @@ spec: type: string fsFreezeStatus: description: |- - FSFreezeStatus is the state of the fs of the guest - it can be either frozen or thawed + FSFreezeStatus indicates whether a freeze operation was requested for the guest filesystem. + It will be set to "frozen" if the request was made, or unset otherwise. + This does not reflect the actual state of the guest filesystem. type: string guestOSInfo: description: Guest OS Information @@ -3496,12 +3710,18 @@ spec: items: type: string type: array + linkState: + description: 'Current operational link state. Values: up, down.' + type: string mac: - description: Hardware address of a Virtual Machine interface + description: Hardware address of a Virtual Machine interface. type: string name: description: Name of the interface, corresponds to name of the - network assigned to the interface + network assigned to the interface. + type: string + podInterfaceName: + description: Name of the pod network interface. type: string queueCount: description: Specifies how many queues are allocated by MultiQueue @@ -3731,6 +3951,13 @@ spec: If set to true, migrations will still start in pre-copy, but switch to post-copy when CompletionTimeoutPerGiB triggers. Defaults to false type: boolean + allowWorkloadDisruption: + description: |- + AllowWorkloadDisruption indicates that the migration shouldn't be + canceled after acceptableCompletionTime is exceeded. Instead, if + permitted, migration will be switched to post-copy or the VMI will be + paused to allow the migration to complete + type: boolean bandwidthPerMigration: anyOf: - type: integer @@ -3743,8 +3970,8 @@ spec: completionTimeoutPerGiB: description: |- CompletionTimeoutPerGiB is the maximum number of seconds per GiB a migration is allowed to take. - If a live-migration takes longer to migrate than this value multiplied by the size of the VMI, - the migration will be cancelled, unless AllowPostCopy is true. Defaults to 800 + If the timeout is reached, the migration will be either paused, switched + to post-copy or cancelled depending on other settings. Defaults to 150 format: int64 type: integer disableTLS: @@ -3794,6 +4021,9 @@ spec: indicates the migration will be unsafe to the guest. Defaults to false type: boolean type: object + migrationNetworkType: + description: Type of migration network, either 'pod' or 'migration'. + type: string migrationPolicyName: description: Name of the migration policy. If string is empty, no policy is matched @@ -3809,8 +4039,57 @@ spec: sourceNode: description: The source node that the VMI originated on type: string + sourcePersistentStatePVCName: + description: If the VMI being migrated uses persistent features + (backend-storage), its source PVC name is saved here. + type: string sourcePod: type: string + sourceState: + description: SourceState contains migration state managed by the + source virt handler + properties: + domainName: + description: The name of the domain on the source libvirt + domain + type: string + domainNamespace: + description: Namespace used in the name of the source libvirt + domain. Can be used to find and modify paths in the domain + type: string + migrationUID: + description: The Source VirtualMachineInstanceMigration object + associated with this migration + type: string + node: + description: The source node that the VMI originated on + type: string + nodeSelectors: + additionalProperties: + type: string + description: Node selectors needed by the target to start + the receiving pod. + type: object + persistentStatePVCName: + description: If the VMI being migrated uses persistent features + (backend-storage), its source PVC name is saved here + type: string + pod: + description: The source pod that the VMI is originated on + type: string + selinuxContext: + description: SELinuxContext is the actual SELinux context + of the pod + type: string + syncAddress: + description: The ip address/fqdn:port combination to use to + synchronize the VMI with the target. + type: string + virtualMachineInstanceUID: + description: VirtualMachineInstanceUID is the UID of the target + virtual machine instance + type: string + type: object startTimestamp: description: The time the migration action began format: date-time @@ -3853,9 +4132,87 @@ spec: If the VMI requires dedicated CPUs, this field will hold the numa topology on the target node type: string + targetPersistentStatePVCName: + description: If the VMI being migrated uses persistent features + (backend-storage), its target PVC name is saved here. + type: string targetPod: description: The target pod that the VMI is moving to type: string + targetState: + description: TargetState contains migration state managed by the + target virt handler + properties: + attachmentPodUID: + description: The UID of the target attachment pod for hotplug + volumes + type: string + cpuSet: + description: |- + If the VMI requires dedicated CPUs, this field will + hold the dedicated CPU set on the target node + items: + type: integer + type: array + x-kubernetes-list-type: atomic + directMigrationNodePorts: + additionalProperties: + type: integer + description: The list of ports opened for live migration on + the destination node + type: object + domainDetected: + description: The Target Node has seen the Domain Start Event + type: boolean + domainName: + description: The name of the domain on the source libvirt + domain + type: string + domainNamespace: + description: Namespace used in the name of the source libvirt + domain. Can be used to find and modify paths in the domain + type: string + domainReadyTimestamp: + description: The timestamp at which the target node detects + the domain is active + format: date-time + type: string + migrationUID: + description: The Source VirtualMachineInstanceMigration object + associated with this migration + type: string + node: + description: The source node that the VMI originated on + type: string + nodeAddress: + description: The address of the target node to use for the + migration + type: string + nodeTopology: + description: |- + If the VMI requires dedicated CPUs, this field will + hold the numa topology on the target node + type: string + persistentStatePVCName: + description: If the VMI being migrated uses persistent features + (backend-storage), its source PVC name is saved here + type: string + pod: + description: The source pod that the VMI is originated on + type: string + selinuxContext: + description: SELinuxContext is the actual SELinux context + of the pod + type: string + syncAddress: + description: The ip address/fqdn:port combination to use to + synchronize the VMI with the target. + type: string + virtualMachineInstanceUID: + description: VirtualMachineInstanceUID is the UID of the target + virtual machine instance + type: string + type: object type: object migrationTransport: description: This represents the migration transport diff --git a/crds/embedded/virtualmachines.yaml b/crds/embedded/virtualmachines.yaml index 72d9f865f6..f8da8608f7 100644 --- a/crds/embedded/virtualmachines.yaml +++ b/crds/embedded/virtualmachines.yaml @@ -319,7 +319,7 @@ spec: 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/ - (Alpha) Using this field requires the VolumeAttributesClass feature gate to be enabled. + (Beta) Using this field requires the VolumeAttributesClass feature gate to be enabled (off by default). type: string volumeMode: description: |- @@ -812,6 +812,7 @@ spec: description: |- Running controls whether the associatied VirtualMachineInstance is created or not Mutually exclusive with RunStrategy + Deprecated: VirtualMachineInstance field "Running" is now deprecated, please use RunStrategy instead. type: boolean template: description: Template is the direct specification of VirtualMachineInstance @@ -1219,7 +1220,7 @@ spec: 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. - This is an alpha field and requires enabling MatchLabelKeysInPodAffinity feature gate. + This is a beta field and requires enabling MatchLabelKeysInPodAffinity feature gate (enabled by default). items: type: string type: array @@ -1234,7 +1235,7 @@ spec: 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. - This is an alpha field and requires enabling MatchLabelKeysInPodAffinity feature gate. + This is a beta field and requires enabling MatchLabelKeysInPodAffinity feature gate (enabled by default). items: type: string type: array @@ -1402,7 +1403,7 @@ spec: 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. - This is an alpha field and requires enabling MatchLabelKeysInPodAffinity feature gate. + This is a beta field and requires enabling MatchLabelKeysInPodAffinity feature gate (enabled by default). items: type: string type: array @@ -1417,7 +1418,7 @@ spec: 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. - This is an alpha field and requires enabling MatchLabelKeysInPodAffinity feature gate. + This is a beta field and requires enabling MatchLabelKeysInPodAffinity feature gate (enabled by default). items: type: string type: array @@ -1583,7 +1584,7 @@ spec: 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. - This is an alpha field and requires enabling MatchLabelKeysInPodAffinity feature gate. + This is a beta field and requires enabling MatchLabelKeysInPodAffinity feature gate (enabled by default). items: type: string type: array @@ -1598,7 +1599,7 @@ spec: 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. - This is an alpha field and requires enabling MatchLabelKeysInPodAffinity feature gate. + This is a beta field and requires enabling MatchLabelKeysInPodAffinity feature gate (enabled by default). items: type: string type: array @@ -1766,7 +1767,7 @@ spec: 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. - This is an alpha field and requires enabling MatchLabelKeysInPodAffinity feature gate. + This is a beta field and requires enabling MatchLabelKeysInPodAffinity feature gate (enabled by default). items: type: string type: array @@ -1781,7 +1782,7 @@ spec: 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. - This is an alpha field and requires enabling MatchLabelKeysInPodAffinity feature gate. + This is a beta field and requires enabling MatchLabelKeysInPodAffinity feature gate (enabled by default). items: type: string type: array @@ -1894,9 +1895,12 @@ spec: options of a pod. properties: name: - description: Required. + description: |- + DNS resolver option name. + Required field. type: string value: + description: DNS resolver option value. type: string type: object type: array @@ -2216,8 +2220,12 @@ spec: type: integer cache: description: |- - Cache specifies which kvm disk cache mode should be used. - Supported values are: CacheNone, CacheWriteThrough. + Specifies which KVM disk cache mode should be used. Supported values: + + - `none`: Guest I/O is not cached on the host, but may be kept in a disk cache. + - `writethrough`: Guest I/O is cached on the host but written through to the physical medium. This is the slowest mode but provides the most guarantees. + - `writeback`: Guest I/O is cached on the host. + Defaults to `none` if the storage supports O_DIRECT, otherwise `writethrough`. type: string cdrom: description: Attach a volume as a cdrom to the @@ -2344,16 +2352,24 @@ spec: vmi. items: properties: + claimName: + description: |- + Must be provided from `vmi.spec.resourceClaims[].name` where this + device is allocated. + type: string deviceName: + description: Name of the device provisioned by device plugins. type: string name: - description: Name of the GPU device as exposed - by a device plugin + description: Name of the GPU device as exposed by a device plugin. + type: string + requestName: + description: |- + Must be provided from `resourceClaim.spec.devices.requests[].name` where this + device is requested. type: string tag: - description: If specified, the virtual network - interface address and its tag will be provided - to the guest via config drive + description: If specified, the virtual network interface address and its tag will be provided to the guest via config drive. type: string virtualGPUOptions: properties: @@ -2388,19 +2404,25 @@ spec: vmi. items: properties: + claimName: + description: |- + Must be provided from `vmi.spec.resourceClaims[].name` where this + device is allocated. + type: string deviceName: - description: DeviceName is the resource name - of the host device exposed by a device plugin + description: Name of the device provisioned by device plugins. type: string name: type: string + requestName: + description: |- + Must be provided from `resourceClaim.spec.devices.requests[].name` where this + device is requested. + type: string tag: - description: If specified, the virtual network - interface address and its tag will be provided - to the guest via config drive + description: If specified, the virtual network interface address and its tag will be provided to the guest via config drive. type: string required: - - deviceName - name type: object type: array @@ -2523,9 +2545,8 @@ spec: model: description: |- Interface model. - One of: e1000, e1000e, ne2k_pci, pcnet, rtl8139, virtio. + One of: e1000, e1000e, igb, ne2k_pci, pcnet, rtl8139, virtio. Defaults to virtio. - TODO:(ihar) switch to enums once opengen-api supports them. See: https://github.com/kubernetes/kube-openapi/issues/51 type: string name: description: |- @@ -2586,13 +2607,15 @@ spec: type: object state: description: |- - State represents the requested operational state of the interface. - The (only) value supported is 'absent', expressing a request to remove the interface. + Requested operational state of the interface. Supported values: + + - 'absent': Expresses a request to remove the interface. + - 'down': Expresses a request to set the link down. + - 'up': Expresses a request to set the link up. + An empty value functions as 'up'. type: string tag: - description: If specified, the virtual network - interface address and its tag will be provided - to the guest via config drive + description: If specified, the virtual network interface address and its tag will be provided to the guest via config drive. type: string required: - name @@ -2614,6 +2637,18 @@ spec: of the VirtualMachineInstance, like the number of guest CPUs. type: boolean + panicDevices: + description: Provides additional crash information when a guest crashes. + items: + properties: + model: + description: |- + Type of panic device to provide. + If this attribute is missing, the panic model used depends on the hypervisor and guest architecture. + Valid values: `isa`, `hyperv`, `pvpanic`. + type: string + type: object + type: array rng: description: Whether to have random number generator from host @@ -2637,10 +2672,15 @@ spec: tpm: description: Whether to emulate a TPM device. properties: + enabled: + description: |- + Allows explicitly disabling the vTPM even when one is enabled by a preference referenced by the VirtualMachine. + Defaults to true. + type: boolean persistent: description: |- - Persistent indicates the state of the TPM device should be kept accross reboots - Defaults to false + Indicates whether the state of the TPM device should be kept across reboots. + Defaults to false. type: boolean type: object useVirtioTransitional: @@ -2649,10 +2689,28 @@ spec: This is helpful for old machines like CentOS6 or RHEL6 which do not understand virtio_non_transitional (virtio 1.0). type: boolean + video: + description: Video device configuration for the VMI. + properties: + type: + description: |- + Video device type (e.g., virtio, vga, bochs, ramfb). + If not specified, the default is architecture-dependent: VGA for BIOS-based VMs, Bochs for EFI-based VMs on AMD64, virtio for Arm and s390x. + type: string + type: object watchdog: description: Watchdog describes a watchdog device which can be added to the vmi. properties: + diag288: + description: diag288 watchdog device specific to s390x architecture. + properties: + action: + description: |- + Action to take when the watchdog triggers. Valid values: poweroff, reset, shutdown. + Defaults to reset. + type: string + type: object i6300esb: description: i6300esb watchdog device. properties: @@ -2923,9 +2981,14 @@ spec: description: Information that can be set in the ACPI table properties: + msdmNameRef: + description: |- + Similar to `SlicNameRef`, this is another ACPI entry used in more recent Windows versions. + This field points to the MSDM specification as well. + type: string slicNameRef: description: |- - SlicNameRef should match the volume name of a secret object. The data in the secret should + Should match the volume name of a secret object. The data in the secret should be a binary blob that follows the ACPI SLIC standard, see: https://learn.microsoft.com/en-us/previous-versions/windows/hardware/design/dn653305(v=vs.85) type: string @@ -3009,11 +3072,19 @@ spec: Defaults to a random generated uid. type: string type: object + ioThreads: + description: IOThreads specifies the IOThreads options. + properties: + supplementalPoolThreadCount: + description: Number of IO threads allocated for the supplementalPool policy. + format: int32 + type: integer + type: object ioThreadsPolicy: description: |- - Controls whether or not disks will share IOThreads. - Omitting IOThreadsPolicy disables use of IOThreads. - One of: shared, auto + Controls whether disks share IOThreads. + Omitting this field disables the use of IOThreads. + Valid values: shared, auto, supplementalPool. type: string launchSecurity: description: Launch Security setting of the vmi. @@ -3129,7 +3200,7 @@ spec: - "None": No action will be taken, according to the specified 'RunStrategy' the VirtualMachine will be restarted or shutdown. - "LiveMigrate": the VirtualMachineInstance will be migrated instead of being shutdown. - "LiveMigrateIfPossible": the same as "LiveMigrate" but only if the VirtualMachine is Live-Migratable, otherwise it will behave as "None". - - "External": the VirtualMachineInstance will be protected by a PDB and 'vmi.Status.EvacuationNodeName' will be set on eviction. This is mainly useful for cluster-api-provider-kubevirt (capk) which needs a way for VMI's to be blocked from eviction, yet signal capk that eviction has been called on the VMI so the capk controller can handle tearing the VMI down. Details can be found in the commit description https://github.com/kubevirt/kubevirt/commit/c1d77face705c8b126696bac9a3ee3825f27f1fa. + - "External": the VirtualMachineInstance will be protected and 'vmi.Status.EvacuationNodeName' will be set on eviction. This is mainly useful for cluster-api-provider-kubevirt (capk) which needs a way for VMI's to be blocked from eviction, yet signal capk that eviction has been called on the VMI so the capk controller can handle tearing the VMI down. Details can be found in the commit description https://github.com/kubevirt/kubevirt/commit/c1d77face705c8b126696bac9a3ee3825f27f1fa. type: string hostname: description: |- @@ -3242,7 +3313,6 @@ spec: description: |- TCPSocket specifies an action involving a TCP port. TCP hooks not yet supported - TODO: implement a realistic TCP lifecycle hook properties: host: description: 'Optional: Host name to connect to, defaults @@ -3441,7 +3511,6 @@ spec: description: |- TCPSocket specifies an action involving a TCP port. TCP hooks not yet supported - TODO: implement a realistic TCP lifecycle hook properties: host: description: 'Optional: Host name to connect to, defaults @@ -3471,6 +3540,57 @@ spec: format: int32 type: integer type: object + resourceClaims: + description: |- + Defines which ResourceClaims must be allocated and reserved before the VMI, + hence the `virt-launcher` pod is allowed to start. The resources will be made available to the domain + which consumes them by name. + + This is an alpha field and requires enabling the `DynamicResourceAllocation` feature gate in Kubernetes. + See https://kubernetes.io/docs/concepts/scheduling-eviction/dynamic-resource-allocation/ + This field should only be configured if one of the feature gates `GPUsWithDRA` or `HostDevicesWithDRA` is enabled. + This feature is in alpha. + items: + description: |- + References exactly one ResourceClaim, either directly + or by naming a ResourceClaimTemplate which is then turned into a ResourceClaim + for the pod. + + Adds a name that uniquely identifies the ResourceClaim inside the Pod. + Containers that need access to the ResourceClaim reference it with this name. + properties: + name: + description: |- + Uniquely identifies this resource claim inside the pod. + This must be a `DNS_LABEL`. + type: string + resourceClaimName: + description: |- + Name of a ResourceClaim object in the same namespace as this pod. + + Exactly one of `ResourceClaimName` and `ResourceClaimTemplateName` must be set. + type: string + resourceClaimTemplateName: + description: |- + Name of a ResourceClaimTemplate object in the same namespace as this pod. + + The template will be used to create a new ResourceClaim, which will be bound to this pod. + When this pod is deleted, the ResourceClaim will also be deleted. The pod name and resource name, + along with a generated component, will be used to form a unique name for the ResourceClaim, + which will be recorded in `pod.status.resourceClaimStatuses`. + + This field is immutable and no changes will be made to the corresponding ResourceClaim + by the control plane after creating the ResourceClaim. + + Exactly one of `ResourceClaimName` and `ResourceClaimTemplateName` must be set. + type: string + required: + - name + type: object + type: array + x-kubernetes-list-map-keys: + - name + x-kubernetes-list-type: map schedulerName: description: |- If specified, the VMI will be dispatched by specified scheduler. @@ -3600,7 +3720,6 @@ spec: Keys that don't exist in the incoming pod labels will be ignored. A null or empty list means only match against labelSelector. - This is a beta field and requires the MatchLabelKeysInPodTopologySpread feature gate to be enabled (enabled by default). items: type: string @@ -3640,7 +3759,6 @@ spec: Valid values are integers greater than 0. When value is not nil, WhenUnsatisfiable must be DoNotSchedule. - For example, in a 3-zone cluster, MaxSkew is set to 2, MinDomains is set to 5 and pods with the same labelSelector spread as 2/2/2: | zone1 | zone2 | zone3 | @@ -3658,7 +3776,6 @@ spec: - Honor: only nodes matching nodeAffinity/nodeSelector are included in the calculations. - Ignore: nodeAffinity/nodeSelector are ignored. All nodes are included in the calculations. - If this value is nil, the behavior is equivalent to the Honor policy. This is a beta-level feature default enabled by the NodeInclusionPolicyInPodTopologySpread feature flag. type: string @@ -3670,7 +3787,6 @@ spec: has a toleration, are included. - Ignore: node taints are ignored. All nodes are included. - If this value is nil, the behavior is equivalent to the Ignore policy. This is a beta-level feature default enabled by the NodeInclusionPolicyInPodTopologySpread feature flag. type: string @@ -3743,10 +3859,13 @@ spec: secret that contains config drive networkdata. properties: name: + default: "" description: |- Name of the referent. + This field is effectively required, but due to backwards compatibility is + allowed to be empty. Instances of this type with an empty value here are + almost certainly wrong. More info: https://kubernetes.io/docs/concepts/overview/working-with-objects/names/#names - TODO: Add other useful fields. apiVersion, kind, uid? type: string type: object x-kubernetes-map-type: atomic @@ -3755,10 +3874,13 @@ spec: secret that contains config drive userdata. properties: name: + default: "" description: |- Name of the referent. + This field is effectively required, but due to backwards compatibility is + allowed to be empty. Instances of this type with an empty value here are + almost certainly wrong. More info: https://kubernetes.io/docs/concepts/overview/working-with-objects/names/#names - TODO: Add other useful fields. apiVersion, kind, uid? type: string type: object x-kubernetes-map-type: atomic @@ -3790,10 +3912,13 @@ spec: secret that contains NoCloud networkdata. properties: name: + default: "" description: |- Name of the referent. + This field is effectively required, but due to backwards compatibility is + allowed to be empty. Instances of this type with an empty value here are + almost certainly wrong. More info: https://kubernetes.io/docs/concepts/overview/working-with-objects/names/#names - TODO: Add other useful fields. apiVersion, kind, uid? type: string type: object x-kubernetes-map-type: atomic @@ -3802,10 +3927,13 @@ spec: secret that contains NoCloud userdata. properties: name: + default: "" description: |- Name of the referent. + This field is effectively required, but due to backwards compatibility is + allowed to be empty. Instances of this type with an empty value here are + almost certainly wrong. More info: https://kubernetes.io/docs/concepts/overview/working-with-objects/names/#names - TODO: Add other useful fields. apiVersion, kind, uid? type: string type: object x-kubernetes-map-type: atomic @@ -3824,10 +3952,13 @@ spec: More info: https://kubernetes.io/docs/tasks/configure-pod-container/configure-pod-configmap/ properties: name: + default: "" description: |- Name of the referent. + This field is effectively required, but due to backwards compatibility is + allowed to be empty. Instances of this type with an empty value here are + almost certainly wrong. More info: https://kubernetes.io/docs/concepts/overview/working-with-objects/names/#names - TODO: Add other useful fields. apiVersion, kind, uid? type: string optional: description: Specify whether the ConfigMap or it's @@ -3882,9 +4013,7 @@ spec: volume can be hotplugged and hotunplugged. type: boolean name: - description: |- - Name of both the DataVolume and the PVC in the same namespace. - After PVC population the DataVolume is garbage collected by default. + description: Name of both the DataVolume and the PVC in the same namespace. type: string required: - name @@ -4137,10 +4266,13 @@ spec: that should be attached as disk of CDROM type. properties: name: + default: "" description: |- Name of the referent. + This field is effectively required, but due to backwards compatibility is + allowed to be empty. Instances of this type with an empty value here are + almost certainly wrong. More info: https://kubernetes.io/docs/concepts/overview/working-with-objects/names/#names - TODO: Add other useful fields. apiVersion, kind, uid? type: string type: object x-kubernetes-map-type: atomic @@ -4150,10 +4282,13 @@ spec: that should be attached as disk of CDROM type. properties: name: + default: "" description: |- Name of the referent. + This field is effectively required, but due to backwards compatibility is + allowed to be empty. Instances of this type with an empty value here are + almost certainly wrong. More info: https://kubernetes.io/docs/concepts/overview/working-with-objects/names/#names - TODO: Add other useful fields. apiVersion, kind, uid? type: string type: object x-kubernetes-map-type: atomic @@ -4219,6 +4354,34 @@ spec: updated through an Update() before ObservedGeneration in Status. format: int64 type: integer + instancetypeRef: + description: InstancetypeRef captures the state of any referenced + instance type from the VirtualMachine + nullable: true + properties: + controllerRevisionRef: + description: |- + ControllerRevision storing a copy of the object captured + when it is first seen by the VirtualMachine controller. + properties: + name: + description: Name of ControllerRevision. + type: string + type: object + inferFromVolume: + description: Lists the name of a volume that should + be used to infer or discover the resource. + type: string + inferFromVolumeFailurePolicy: + description: Controls what happens on failure when inferring the resource. + type: string + kind: + description: Kind of resource. + type: string + name: + description: Name of resource. + type: string + type: object memoryDumpRequest: description: |- MemoryDumpRequest tracks memory dump request phase and info of getting a memory @@ -4226,31 +4389,27 @@ spec: nullable: true properties: claimName: - description: ClaimName is the name of the pvc that will contain - the memory dump + description: Name of the PVC that will contain + the memory dump. type: string endTimestamp: - description: EndTimestamp represents the time the memory dump - was completed + description: Time when the memory dump was completed. format: date-time type: string fileName: - description: FileName represents the name of the output file + description: Name of the output file. type: string message: - description: Message is a detailed message about failure of the - memory dump + description: Detailed message about failure of the memory dump. type: string phase: - description: Phase represents the memory dump phase + description: Memory dump phase. type: string remove: - description: Remove represents request of dissociating the memory - dump pvc + description: Request to dissociate the memory dump PVC. type: boolean startTimestamp: - description: StartTimestamp represents the time the memory dump - started + description: Time when the memory dump started. format: date-time type: string required: @@ -4262,6 +4421,34 @@ spec: vmi when started. format: int64 type: integer + preferenceRef: + description: PreferenceRef captures the state of any referenced preference + from the VirtualMachine + nullable: true + properties: + controllerRevisionRef: + description: |- + Specifies the `ControllerRevision` storing a copy of the object captured + when it is first seen by the VirtualMachine controller. + properties: + name: + description: Name of ControllerRevision. + type: string + type: object + inferFromVolume: + description: Lists the name of a volume that should + be used to infer or discover the resource. + type: string + inferFromVolumeFailurePolicy: + description: Controls what happens on failure when inferring the resource. + type: string + kind: + description: Kind of resource. + type: string + name: + description: Name of resource. + type: string + type: object printableStatus: default: Stopped description: PrintableStatus is a human readable, high-level representation @@ -4377,8 +4564,12 @@ spec: type: integer cache: description: |- - Cache specifies which kvm disk cache mode should be used. - Supported values are: CacheNone, CacheWriteThrough. + Cache specifies which KVM disk cache mode should be used. Supported values: + + - `none`: Guest I/O is not cached on the host, but may be kept in a disk cache. + - `writethrough`: Guest I/O is cached on the host but written through to the physical medium. This is the slowest mode but provides the most guarantees. + - `writeback`: Guest I/O is cached on the host. + Defaults to none if the storage supports O_DIRECT, otherwise writethrough. type: string cdrom: description: Attach a volume as a cdrom to the vmi. @@ -4531,9 +4722,7 @@ spec: volume can be hotplugged and hotunplugged. type: boolean name: - description: |- - Name of both the DataVolume and the PVC in the same namespace. - After PVC population the DataVolume is garbage collected by default. + description: Name of both the DataVolume and the PVC in the same namespace. type: string required: - name @@ -4615,6 +4804,134 @@ spec: - name type: object type: array + volumeUpdateState: + description: |- + VolumeUpdateState contains the information about the volumes set + updates related to the volumeUpdateStrategy + properties: + volumeMigrationState: + description: VolumeMigrationState tracks the information related + to the volume migration + properties: + migratedVolumes: + description: MigratedVolumes lists the source and destination + volumes during the volume migration + items: + description: StorageMigratedVolumeInfo tracks the information + about the source and destination volumes during the volume + migration + properties: + destinationPVCInfo: + description: DestinationPVCInfo contains the information + about the destination PVC + 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 + capacity: + 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: Capacity represents the capacity set + on the corresponding PVC status + type: object + claimName: + description: Name of the PVC. + type: string + filesystemOverhead: + description: Percentage of filesystem's size to + be reserved when resizing the PVC + pattern: ^(0(?:\.\d{1,3})?|1)$ + type: string + preallocated: + description: Preallocated indicates if the PVC's + storage is preallocated or not + type: boolean + 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 represents the resources requested + by the corresponding PVC spec + type: object + 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 + type: object + sourcePVCInfo: + description: SourcePVCInfo contains the information + about the source PVC + 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 + capacity: + 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: Capacity represents the capacity set + on the corresponding PVC status + type: object + claimName: + description: Name of the PVC. + type: string + filesystemOverhead: + description: Percentage of filesystem's size to + be reserved when resizing the PVC + pattern: ^(0(?:\.\d{1,3})?|1)$ + type: string + preallocated: + description: Preallocated indicates if the PVC's + storage is preallocated or not + type: boolean + 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 represents the resources requested + by the corresponding PVC spec + type: object + 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 + type: object + volumeName: + description: VolumeName is the name of the volume that + is being migrated + type: string + required: + - volumeName + type: object + type: array + x-kubernetes-list-type: atomic + type: object + type: object type: object required: - spec diff --git a/crds/virtualmachineclasses.yaml b/crds/virtualmachineclasses.yaml index 91390c4a4e..58caf23455 100644 --- a/crds/virtualmachineclasses.yaml +++ b/crds/virtualmachineclasses.yaml @@ -283,8 +283,8 @@ spec: type: array defaultCoreFraction: description: |- - Default `coreFraction` value for the VirtualMachineClass. - Used when creating a VM when `coreFraction` is not specified. + Default core fraction value for the VirtualMachineClass. + This value will be used when creating a VM without an explicitly specified coreFraction. maximum: 100 minimum: 1 type: integer @@ -783,7 +783,7 @@ spec: type: boolean type: array defaultCoreFraction: - description: Default `coreFraction` value for the VirtualMachineClass. + description: Default core fraction value for the VirtualMachineClass. type: string memory: description: Memory sizing policy. diff --git a/images/hooks/go.mod b/images/hooks/go.mod index b83313b898..0b23217359 100644 --- a/images/hooks/go.mod +++ b/images/hooks/go.mod @@ -105,7 +105,7 @@ require ( k8s.io/component-base v0.33.3 // indirect k8s.io/klog/v2 v2.130.1 // indirect k8s.io/kube-openapi v0.0.0-20250701173324-9bd5c66d9911 // indirect - kubevirt.io/api v1.3.1 // indirect + kubevirt.io/api v1.6.2 // indirect kubevirt.io/containerized-data-importer-api v1.60.3 // indirect kubevirt.io/controller-lifecycle-operator-sdk/api v0.0.0-20220329064328-f3cc58c6ed90 // indirect sigs.k8s.io/controller-runtime v0.21.0 // indirect diff --git a/images/hooks/go.sum b/images/hooks/go.sum index 3e1497b592..f94e4c5651 100644 --- a/images/hooks/go.sum +++ b/images/hooks/go.sum @@ -647,8 +647,8 @@ k8s.io/utils v0.0.0-20240711033017-18e509b52bc8/go.mod h1:OLgZIPagt7ERELqWJFomSt k8s.io/utils v0.0.0-20241104100929-3ea5e8cea738/go.mod h1:OLgZIPagt7ERELqWJFomSt595RzquPNLL48iOWgYOg0= k8s.io/utils v0.0.0-20250604170112-4c0f3b243397 h1:hwvWFiBzdWw1FhfY1FooPn3kzWuJ8tmbZBHi4zVsl1Y= k8s.io/utils v0.0.0-20250604170112-4c0f3b243397/go.mod h1:OLgZIPagt7ERELqWJFomSt595RzquPNLL48iOWgYOg0= -kubevirt.io/api v1.3.1 h1:MoTNo/zvDlZ44c2ocXLPln8XTaQOeUodiYbEKrTCqv4= -kubevirt.io/api v1.3.1/go.mod h1:tCn7VAZktEvymk490iPSMPCmKM9UjbbfH2OsFR/IOLU= +kubevirt.io/api v1.6.2 h1:aoqZ4KsbOyDjLnuDw7H9wEgE/YTd/q5BBmYeQjJNizc= +kubevirt.io/api v1.6.2/go.mod h1:p66fEy/g79x7VpgUwrkUgOoG2lYs5LQq37WM6JXMwj4= kubevirt.io/containerized-data-importer-api v1.60.3 h1:kQEXi7scpzUa0RPf3/3MKk1Kmem0ZlqqiuK3kDF5L2I= kubevirt.io/containerized-data-importer-api v1.60.3/go.mod h1:8mwrkZIdy8j/LmCyKt2wFXbiMavLUIqDaegaIF67CZs= kubevirt.io/controller-lifecycle-operator-sdk/api v0.0.0-20220329064328-f3cc58c6ed90 h1:QMrd0nKP0BGbnxTqakhDZAUhGKxPiPiN5gSDqKUmGGc= diff --git a/images/virt-api/debug/dlv.Dockerfile b/images/virt-api/debug/dlv.Dockerfile index bca504a4d3..fe10ced68b 100644 --- a/images/virt-api/debug/dlv.Dockerfile +++ b/images/virt-api/debug/dlv.Dockerfile @@ -1,10 +1,10 @@ -FROM golang:1.22.7 AS builder +FROM golang:1.23 AS builder RUN go install github.com/go-delve/delve/cmd/dlv@latest -ARG BRANCH="1.3.1-virtualization" -ENV VERSION="1.3.1" -ENV GOVERSION="1.22.7" +ARG BRANCH="1.6.2-virtualization" +ENV VERSION="1.6.2" +ENV GOVERSION="1.23.0" # Copy the git commits for rebuilding the image if the branch changes ADD "https://api.github.com/repos/deckhouse/3p-kubevirt/commits/$BRANCH" /.git-commit-hash.tmp @@ -14,7 +14,7 @@ WORKDIR /kubevirt RUN go mod edit -go=$GOVERSION && \ go mod download -RUN go mod vendor +RUN go work vendor ENV GO111MODULE=on ENV GOOS=linux diff --git a/images/virt-artifact/werf.inc.yaml b/images/virt-artifact/werf.inc.yaml index 86f8472824..4e972a4590 100644 --- a/images/virt-artifact/werf.inc.yaml +++ b/images/virt-artifact/werf.inc.yaml @@ -9,6 +9,7 @@ image: {{ .ModuleNamePrefix }}{{ .ImageName }}-src-artifact final: false fromImage: builder/src +fromCacheVersion: "000" # TODO: Delete me secrets: - id: SOURCE_REPO value: {{ $.SOURCE_REPO }} @@ -83,7 +84,7 @@ shell: cd /kubevirt go mod download - go mod vendor + go work vendor for p in patches/*.patch ; do echo -n "Apply ${p} ... " diff --git a/images/virt-controller/debug/dlv.Dockerfile b/images/virt-controller/debug/dlv.Dockerfile index ab4f9606db..fec4948301 100644 --- a/images/virt-controller/debug/dlv.Dockerfile +++ b/images/virt-controller/debug/dlv.Dockerfile @@ -1,10 +1,10 @@ -FROM golang:1.22.7 AS builder +FROM golang:1.23 AS builder RUN go install github.com/go-delve/delve/cmd/dlv@latest -ARG BRANCH="1.3.1-virtualization" -ENV VERSION="1.3.1" -ENV GOVERSION="1.22.7" +ARG BRANCH="v1.6.1-virtualization" +ENV VERSION="1.6.1" +ENV GOVERSION="1.23.0" # Copy the git commits for rebuilding the image if the branch changes ADD "https://api.github.com/repos/deckhouse/3p-kubevirt/commits/$BRANCH" /.git-commit-hash.tmp @@ -14,7 +14,7 @@ WORKDIR /kubevirt RUN go mod edit -go=$GOVERSION && \ go mod download -RUN go mod vendor +RUN go work vendor ENV GO111MODULE=on ENV GOOS=linux diff --git a/images/virt-handler/debug/dlv.Dockerfile b/images/virt-handler/debug/dlv.Dockerfile index 12142d5178..86af33b002 100644 --- a/images/virt-handler/debug/dlv.Dockerfile +++ b/images/virt-handler/debug/dlv.Dockerfile @@ -3,6 +3,7 @@ RUN groupadd --gid 1001 nonroot-user && useradd nonroot-user --uid 1001 --gid 10 FROM basealt AS builder +# TODO add pin repository url RUN apt-get update RUN apt-get install -y \ @@ -17,9 +18,9 @@ RUN apt-get install -y \ RUN go install github.com/go-delve/delve/cmd/dlv@latest -ARG BRANCH="1.3.1-virtualization" -ENV VERSION="1.3.1" -ENV GOVERSION="1.22.7" +ARG BRANCH="1.6.2-virtualization" +ENV VERSION="1.6.2" +ENV GOVERSION="1.23.0" RUN mkdir /kubevirt-config-files && echo "v$VERSION-dirty" > /kubevirt-config-files/.version @@ -31,11 +32,11 @@ WORKDIR /kubevirt RUN go mod edit -go=$GOVERSION && \ go mod download -RUN go mod vendor +RUN go work vendor -RUN for p in patches/*.patch ; do \ - echo -n "Apply ${p} ... " \ - git apply --ignore-space-change --ignore-whitespace ${p} && echo OK || (echo FAIL ; exit 1) \ +RUN for p in patches/*.patch; do \ + echo -n "Apply ${p} ... " && \ + git apply --ignore-space-change --ignore-whitespace "${p}" && echo OK || (echo FAIL && exit 1); \ done ENV GO111MODULE=on @@ -52,9 +53,7 @@ FROM basealt RUN apt-get update && apt-get install --yes \ acl \ procps \ - nftables \ - qemu-img==9.1.2-alt1 \ - xorriso==1.5.6-alt1 && \ + nftables && \ apt-get clean && \ rm --recursive --force /var/lib/apt/lists/ftp.altlinux.org* /var/cache/apt/*.bin @@ -63,7 +62,6 @@ RUN echo "qemu:x:107:107::/home/qemu:/bin/bash" >> /etc/passwd && \ mkdir -p /home/qemu && \ chown -R 107:107 /home/qemu -COPY --from=builder /kubevirt/cmd/virt-handler/virt_launcher.cil /virt_launcher.cil COPY --from=builder /kubevirt-config-files/.version /.version COPY --from=builder /kubevirt/cmd/virt-handler/nsswitch.conf /etc/nsswitch.conf diff --git a/images/virt-handler/werf.inc.yaml b/images/virt-handler/werf.inc.yaml index 4888e05684..3db87a474a 100644 --- a/images/virt-handler/werf.inc.yaml +++ b/images/virt-handler/werf.inc.yaml @@ -25,10 +25,6 @@ import: - virt-chroot - virt-handler - container-disk -- image: {{ .ModuleNamePrefix }}virt-artifact - add: /kubevirt/cmd/{{ $.ImageName }}/virt_launcher.cil - to: /virt_launcher.cil - after: install - image: {{ .ModuleNamePrefix }}virt-artifact add: /kubevirt-config-files/.version to: /.version diff --git a/images/virtualization-artifact/go.mod b/images/virtualization-artifact/go.mod index 19f7218e17..acc024b811 100644 --- a/images/virtualization-artifact/go.mod +++ b/images/virtualization-artifact/go.mod @@ -32,7 +32,7 @@ require ( k8s.io/klog/v2 v2.130.1 k8s.io/kube-openapi v0.0.0-20250701173324-9bd5c66d9911 k8s.io/utils v0.0.0-20250604170112-4c0f3b243397 - kubevirt.io/api v1.3.1 + kubevirt.io/api v1.6.2 kubevirt.io/containerized-data-importer-api v1.60.3 sigs.k8s.io/controller-runtime v0.21.0 sigs.k8s.io/yaml v1.4.0 @@ -165,4 +165,4 @@ replace ( ) // Kubevirt API replaces -replace kubevirt.io/api => github.com/deckhouse/3p-kubevirt/staging/src/kubevirt.io/api v1.3.1-v12n.18 +replace kubevirt.io/api => github.com/deckhouse/3p-kubevirt/staging/src/kubevirt.io/api v1.6.2-v12n.0 diff --git a/images/virtualization-artifact/go.sum b/images/virtualization-artifact/go.sum index 657b17c4fb..13c0de21fe 100644 --- a/images/virtualization-artifact/go.sum +++ b/images/virtualization-artifact/go.sum @@ -45,8 +45,8 @@ github.com/davecgh/go-spew v1.1.0/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSs github.com/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= github.com/davecgh/go-spew v1.1.2-0.20180830191138-d8f796af33cc h1:U9qPSI2PIWSS1VwoXQT9A3Wy9MM3WgvqSxFWenqJduM= github.com/davecgh/go-spew v1.1.2-0.20180830191138-d8f796af33cc/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= -github.com/deckhouse/3p-kubevirt/staging/src/kubevirt.io/api v1.3.1-v12n.18 h1:9pstD3PiPmby/Chh24ickwUNbAcqbceOPp253/jSr8k= -github.com/deckhouse/3p-kubevirt/staging/src/kubevirt.io/api v1.3.1-v12n.18/go.mod h1:tCn7VAZktEvymk490iPSMPCmKM9UjbbfH2OsFR/IOLU= +github.com/deckhouse/3p-kubevirt/staging/src/kubevirt.io/api v1.6.2-v12n.0 h1:Ro9oG/eakqMxfFSEs91BZYhDXggghuJjFvawV6/EKSo= +github.com/deckhouse/3p-kubevirt/staging/src/kubevirt.io/api v1.6.2-v12n.0/go.mod h1:p66fEy/g79x7VpgUwrkUgOoG2lYs5LQq37WM6JXMwj4= github.com/deckhouse/deckhouse/pkg/log v0.0.0-20250226105106-176cd3afcdd5 h1:PsN1E0oxC/+4zdA977txrqUCuObFL3HAuu5Xnud8m8c= github.com/deckhouse/deckhouse/pkg/log v0.0.0-20250226105106-176cd3afcdd5/go.mod h1:Mk5HRzkc5pIcDIZ2JJ6DPuuqnwhXVkb3you8M8Mg+4w= github.com/distribution/reference v0.5.0 h1:/FUIFXtfc/x2gpa5/VGfiGLuOIdYa1t65IKK2OFGvA0= diff --git a/images/virtualization-artifact/hack/dlv.sh b/images/virtualization-artifact/hack/dlv.sh index 9881789165..2cc956599d 100755 --- a/images/virtualization-artifact/hack/dlv.sh +++ b/images/virtualization-artifact/hack/dlv.sh @@ -82,8 +82,7 @@ kubectl -n d8-virtualization patch deployment ${deployment} --type='strategic' - "ports": [{"containerPort": 2345, "name": "dlv"}], "readinessProbe": null, "livenessProbe": null, - "command": null, - "args": [] + "command": null }, { "name": "proxy", diff --git a/images/virtualization-artifact/pkg/common/network/network.go b/images/virtualization-artifact/pkg/common/network/network.go index c53142c755..cc495acf8d 100644 --- a/images/virtualization-artifact/pkg/common/network/network.go +++ b/images/virtualization-artifact/pkg/common/network/network.go @@ -77,6 +77,12 @@ func CreateNetworkSpec(vm *v1alpha2.VirtualMachine, vmmacs []*v1alpha2.VirtualMa } for _, n := range vm.Spec.Networks { if n.Type == v1alpha2.NetworksTypeMain { + res = append(res, InterfaceSpec{ + Type: n.Type, + Name: n.Name, + InterfaceName: NameDefaultInterface, + MAC: "", + }) continue } var mac string @@ -103,8 +109,16 @@ func CreateNetworkSpec(vm *v1alpha2.VirtualMachine, vmmacs []*v1alpha2.VirtualMa return res } -func (c InterfaceSpecList) ToString() (string, error) { - data, err := json.Marshal(c) +func (s InterfaceSpecList) ToString() (string, error) { + filtered := InterfaceSpecList{} + for _, spec := range s { + if spec.Type == v1alpha2.NetworksTypeMain { + continue + } + filtered = append(filtered, spec) + } + + data, err := json.Marshal(filtered) if err != nil { return "", err } diff --git a/images/virtualization-artifact/pkg/common/network/network_test.go b/images/virtualization-artifact/pkg/common/network/network_test.go index 2ac2f823a0..7643aa0ed3 100644 --- a/images/virtualization-artifact/pkg/common/network/network_test.go +++ b/images/virtualization-artifact/pkg/common/network/network_test.go @@ -74,7 +74,10 @@ var _ = Describe("Network Config Generation", func() { configs := CreateNetworkSpec(vm, vmmacs) - Expect(configs).To(HaveLen(0)) + Expect(configs).To(HaveLen(1)) + Expect(configs[0].Name).To(Equal("")) + Expect(configs[0].InterfaceName).To(HavePrefix("default")) + Expect(configs[0].MAC).To(HavePrefix("")) }) It("should generate correct interface name for Network type", func() { @@ -90,10 +93,14 @@ var _ = Describe("Network Config Generation", func() { configs := CreateNetworkSpec(vm, vmmacs) - Expect(configs).To(HaveLen(1)) - Expect(configs[0].Type).To(Equal(v1alpha2.NetworksTypeNetwork)) - Expect(configs[0].Name).To(Equal("mynet")) - Expect(configs[0].InterfaceName).To(HavePrefix("veth_n")) + Expect(configs).To(HaveLen(2)) + Expect(configs[0].Name).To(Equal("")) + Expect(configs[0].InterfaceName).To(HavePrefix("default")) + Expect(configs[0].MAC).To(HavePrefix("")) + + Expect(configs[1].Type).To(Equal(v1alpha2.NetworksTypeNetwork)) + Expect(configs[1].Name).To(Equal("mynet")) + Expect(configs[1].InterfaceName).To(HavePrefix("veth_n")) }) It("should generate correct interface name for ClusterNetwork type", func() { @@ -109,10 +116,13 @@ var _ = Describe("Network Config Generation", func() { configs := CreateNetworkSpec(vm, vmmacs) - Expect(configs).To(HaveLen(1)) - Expect(configs[0].Type).To(Equal(v1alpha2.NetworksTypeClusterNetwork)) - Expect(configs[0].Name).To(Equal("clusternet")) - Expect(configs[0].InterfaceName).To(HavePrefix("veth_cn")) + Expect(configs).To(HaveLen(2)) + Expect(configs[0].Name).To(Equal("")) + Expect(configs[0].InterfaceName).To(HavePrefix("default")) + Expect(configs[0].MAC).To(HavePrefix("")) + Expect(configs[1].Type).To(Equal(v1alpha2.NetworksTypeClusterNetwork)) + Expect(configs[1].Name).To(Equal("clusternet")) + Expect(configs[1].InterfaceName).To(HavePrefix("veth_cn")) }) It("should generate unique names for different networks", func() { @@ -132,8 +142,11 @@ var _ = Describe("Network Config Generation", func() { configs := CreateNetworkSpec(vm, vmmacs) - Expect(configs).To(HaveLen(2)) - Expect(configs[0].InterfaceName).NotTo(Equal(configs[1].InterfaceName)) + Expect(configs).To(HaveLen(3)) + Expect(configs[0].Name).To(Equal("")) + Expect(configs[0].InterfaceName).To(HavePrefix("default")) + Expect(configs[0].MAC).To(HavePrefix("")) + Expect(configs[1].InterfaceName).NotTo(Equal(configs[2].InterfaceName)) }) It("should preserve MAC order for existing networks and assign free MAC to new network", func() { @@ -147,10 +160,12 @@ var _ = Describe("Network Config Generation", func() { MAC: "00:1A:2B:3C:4D:5E", }, { + Type: v1alpha2.NetworksTypeNetwork, Name: "name1", MAC: "00:1A:2B:3C:4D:5F", }, { + Type: v1alpha2.NetworksTypeNetwork, Name: "name1", MAC: "00:1A:2B:3C:4D:6A", }, @@ -186,19 +201,22 @@ var _ = Describe("Network Config Generation", func() { configs := CreateNetworkSpec(vm, vmmacs) - Expect(configs).To(HaveLen(4)) + Expect(configs).To(HaveLen(5)) - Expect(configs[0].Name).To(Equal("name1")) - Expect(configs[0].MAC).To(Equal("00:1A:2B:3C:4D:5E")) + Expect(configs[0].Name).To(Equal("")) + Expect(configs[0].MAC).To(Equal("")) Expect(configs[1].Name).To(Equal("name1")) - Expect(configs[1].MAC).To(Equal("00:1A:2B:3C:4D:5F")) + Expect(configs[1].MAC).To(Equal("00:1A:2B:3C:4D:5E")) - Expect(configs[3].Name).To(Equal("name1")) - Expect(configs[3].MAC).To(Equal("00:1A:2B:3C:4D:6A")) + Expect(configs[2].Name).To(Equal("name1")) + Expect(configs[2].MAC).To(Equal("00:1A:2B:3C:4D:5F")) - Expect(configs[2].Name).To(Equal("name2")) - Expect(configs[2].MAC).To(Equal("00:1A:2B:3C:4D:7F")) + Expect(configs[3].Name).To(Equal("name2")) + Expect(configs[3].MAC).To(Equal("00:1A:2B:3C:4D:7F")) + + Expect(configs[4].Name).To(Equal("name1")) + Expect(configs[4].MAC).To(Equal("00:1A:2B:3C:4D:6A")) }) It("should preserve MAC order when delete network", func() { @@ -252,15 +270,15 @@ var _ = Describe("Network Config Generation", func() { configs := CreateNetworkSpec(vm, vmmacs) - Expect(configs).To(HaveLen(3)) - - Expect(configs[0].Name).To(Equal("name1")) - Expect(configs[0].MAC).To(Equal("00:1A:2B:3C:4D:5E")) + Expect(configs).To(HaveLen(4)) Expect(configs[1].Name).To(Equal("name1")) - Expect(configs[1].MAC).To(Equal("00:1A:2B:3C:4D:5F")) + Expect(configs[1].MAC).To(Equal("00:1A:2B:3C:4D:5E")) Expect(configs[2].Name).To(Equal("name1")) - Expect(configs[2].MAC).To(Equal("00:1A:2B:3C:4D:6A")) + Expect(configs[2].MAC).To(Equal("00:1A:2B:3C:4D:5F")) + + Expect(configs[3].Name).To(Equal("name1")) + Expect(configs[3].MAC).To(Equal("00:1A:2B:3C:4D:6A")) }) }) diff --git a/images/virtualization-artifact/pkg/controller/kvbuilder/kvvm_utils.go b/images/virtualization-artifact/pkg/controller/kvbuilder/kvvm_utils.go index 034d25714a..15529eeb17 100644 --- a/images/virtualization-artifact/pkg/controller/kvbuilder/kvvm_utils.go +++ b/images/virtualization-artifact/pkg/controller/kvbuilder/kvvm_utils.go @@ -282,8 +282,11 @@ func ApplyVirtualMachineSpec( }) kvvm.AddFinalizer(v1alpha2.FinalizerKVVMProtection) - // Set ip address cni request annotation. - kvvm.SetKVVMIAnnotation(netmanager.AnnoIPAddressCNIRequest, ipAddress) + if ipAddress != "" { + // Set ip address cni request annotation. + kvvm.SetKVVMIAnnotation(netmanager.AnnoIPAddressCNIRequest, ipAddress) + } + // Set live migration annotation. kvvm.SetKVVMIAnnotation(virtv1.AllowPodBridgeNetworkLiveMigrationAnnotation, "true") // Set label to skip the check for PodSecurityStandards to avoid irrelevant alerts related to a privileged virtual machine pod. @@ -337,8 +340,6 @@ func ApplyMigrationVolumes(kvvm *KVVM, vm *v1alpha2.VirtualMachine, vdsByName ma func setNetwork(kvvm *KVVM, networkSpec network.InterfaceSpecList) { kvvm.ClearNetworkInterfaces() - kvvm.SetNetworkInterface(network.NameDefaultInterface, "") - for _, n := range networkSpec { kvvm.SetNetworkInterface(n.InterfaceName, n.MAC) } diff --git a/images/virtualization-artifact/pkg/controller/vm/internal/ipam.go b/images/virtualization-artifact/pkg/controller/vm/internal/ipam.go index d26d450f3c..b427588c17 100644 --- a/images/virtualization-artifact/pkg/controller/vm/internal/ipam.go +++ b/images/virtualization-artifact/pkg/controller/vm/internal/ipam.go @@ -23,11 +23,13 @@ import ( "strings" corev1 "k8s.io/api/core/v1" + k8serrors "k8s.io/apimachinery/pkg/api/errors" metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" virtv1 "kubevirt.io/api/core/v1" "sigs.k8s.io/controller-runtime/pkg/client" "sigs.k8s.io/controller-runtime/pkg/reconcile" + "github.com/deckhouse/virtualization-controller/pkg/common/annotations" "github.com/deckhouse/virtualization-controller/pkg/common/network" "github.com/deckhouse/virtualization-controller/pkg/controller/conditions" "github.com/deckhouse/virtualization-controller/pkg/controller/vm/internal/state" @@ -65,38 +67,49 @@ func (h *IPAMHandler) Handle(ctx context.Context, s state.VirtualMachineState) ( if s.VirtualMachine().IsEmpty() { return reconcile.Result{}, nil } - current := s.VirtualMachine().Current() - changed := s.VirtualMachine().Changed() + vm := s.VirtualMachine().Changed() - if update := addAllUnknown(changed, vmcondition.TypeIPAddressReady); update { - return reconcile.Result{Requeue: true}, nil + if isDeletion(vm) { + return reconcile.Result{}, nil } - //nolint:staticcheck // it's deprecated. - mgr := conditions.NewManager(changed.Status.Conditions) cb := conditions.NewConditionBuilder(vmcondition.TypeIPAddressReady). - Generation(current.GetGeneration()) + Status(metav1.ConditionUnknown). + Reason(conditions.ReasonUnknown). + Generation(vm.GetGeneration()) + + defer func() { + conditions.SetCondition(cb, &vm.Status.Conditions) + }() + + if !hasDefaultNetwork(vm.Status.Networks) { + vm.Status.IPAddress = "" + vm.Status.VirtualMachineIPAddress = "" + if err := h.deleteManagedVMIP(ctx, s, vm); err != nil { + cb.Status(metav1.ConditionFalse).Reason(vmcondition.ReasonIPAddressNotReady). + Message(fmt.Sprintf("Failed to delete VirtualMachineIPAddress: %v", err)) + return reconcile.Result{}, err + } + cb.Status(metav1.ConditionTrue).Reason(vmcondition.ReasonIPAddressReady) + return reconcile.Result{}, nil + } ipAddress, err := s.IPAddress(ctx) if err != nil { + cb.Reason(vmcondition.ReasonIPAddressNotReady).Message(fmt.Sprintf("Failed to get VirtualMachineIPAddress: %v", err)) return reconcile.Result{}, err } - if isDeletion(current) { - return reconcile.Result{}, nil - } - // 1. OK: already bound. - if h.ipam.IsBound(current.GetName(), ipAddress) { - mgr.Update(cb.Status(metav1.ConditionTrue). - Reason(vmcondition.ReasonIPAddressReady). - Condition()) - changed.Status.VirtualMachineIPAddress = ipAddress.GetName() - if changed.Status.Phase != v1alpha2.MachineRunning && changed.Status.Phase != v1alpha2.MachineStopping { - changed.Status.IPAddress = ipAddress.Status.Address + if h.ipam.IsBound(vm.GetName(), ipAddress) { + cb.Status(metav1.ConditionTrue).Reason(vmcondition.ReasonIPAddressReady) + vm.Status.VirtualMachineIPAddress = ipAddress.GetName() + if vm.Status.Phase != v1alpha2.MachineRunning && vm.Status.Phase != v1alpha2.MachineStopping { + vm.Status.IPAddress = ipAddress.Status.Address } kvvmi, err := s.KVVMI(ctx) if err != nil { + cb.Reason(vmcondition.ReasonIPAddressNotReady).Message(fmt.Sprintf("Failed to get KVVMI: %v", err)) return reconcile.Result{}, err } if kvvmi != nil && kvvmi.Status.Phase == virtv1.Running { @@ -110,17 +123,13 @@ func (h *IPAMHandler) Handle(ctx context.Context, s state.VirtualMachineState) ( } if !hasClaimedIP { msg := fmt.Sprintf("IP address (%s) is not among addresses assigned to '%s' network interface (%s)", ipAddress.Status.Address, network.NameDefaultInterface, strings.Join(iface.IPs, ", ")) - mgr.Update(cb.Status(metav1.ConditionFalse). - Reason(vmcondition.ReasonIPAddressNotAssigned). - Message(msg). - Condition()) + cb.Status(metav1.ConditionFalse).Reason(vmcondition.ReasonIPAddressNotAssigned).Message(msg) log.Warn(msg) } break } } } - changed.Status.Conditions = mgr.Generate() return reconcile.Result{}, nil } @@ -129,50 +138,64 @@ func (h *IPAMHandler) Handle(ctx context.Context, s state.VirtualMachineState) ( // 2. Ip address not found: create if possible or wait for the ip address. if ipAddress == nil { cb.Reason(vmcondition.ReasonIPAddressNotReady) - if current.Spec.VirtualMachineIPAddress != "" { - log.Info(fmt.Sprintf("The requested ip address (%s) for the virtual machine not found: waiting for the ip address", current.Spec.VirtualMachineIPAddress)) - cb.Message(fmt.Sprintf("The requested ip address (%s) for the virtual machine not found: waiting for the ip address", current.Spec.VirtualMachineIPAddress)) - mgr.Update(cb.Condition()) - changed.Status.Conditions = mgr.Generate() + if vm.Spec.VirtualMachineIPAddress != "" { + log.Info(fmt.Sprintf("The requested ip address (%s) for the virtual machine not found: waiting for the ip address", vm.Spec.VirtualMachineIPAddress)) + cb.Message(fmt.Sprintf("The requested ip address (%s) for the virtual machine not found: waiting for the ip address", vm.Spec.VirtualMachineIPAddress)) return reconcile.Result{}, nil } - log.Info("VirtualMachineIPAddress not found: create the new one", slog.String("vmipName", current.GetName())) - cb.Message(fmt.Sprintf("VirtualMachineIPAddress %q not found: it may be in the process of being created", current.GetName())) - mgr.Update(cb.Condition()) - changed.Status.Conditions = mgr.Generate() - return reconcile.Result{}, h.ipam.CreateIPAddress(ctx, changed, h.client) + log.Info("VirtualMachineIPAddress not found: create the new one", slog.String("vmipName", vm.GetName())) + cb.Message(fmt.Sprintf("VirtualMachineIPAddress %q not found: it may be in the process of being created", vm.GetName())) + return reconcile.Result{}, h.ipam.CreateIPAddress(ctx, vm, h.client) } // 3. Check if possible to bind virtual machine with the found ip address. - err = h.ipam.CheckIPAddressAvailableForBinding(current.GetName(), ipAddress) + err = h.ipam.CheckIPAddressAvailableForBinding(vm.GetName(), ipAddress) if err != nil { - log.Info("Ip address is not available to be bound", "err", err, "vmipName", current.Spec.VirtualMachineIPAddress) + log.Info("Ip address is not available to be bound", "err", err, "vmipName", vm.Spec.VirtualMachineIPAddress) reason := vmcondition.ReasonIPAddressNotAvailable - mgr.Update(cb.Reason(reason).Message(err.Error()).Condition()) - changed.Status.Conditions = mgr.Generate() - h.recorder.Event(changed, corev1.EventTypeWarning, reason.String(), err.Error()) + cb.Reason(reason).Message(err.Error()) + h.recorder.Event(vm, corev1.EventTypeWarning, reason.String(), err.Error()) return reconcile.Result{}, nil } // 4. Ip address exist and attached to another VirtualMachine - if ipAddress.Status.VirtualMachine != "" && ipAddress.Status.VirtualMachine != changed.Name { - msg := fmt.Sprintf("The requested ip address (%s) attached to VirtualMachine '%s': waiting for the ip address", current.Spec.VirtualMachineIPAddress, ipAddress.Status.VirtualMachine) + if ipAddress.Status.VirtualMachine != "" && ipAddress.Status.VirtualMachine != vm.Name { + msg := fmt.Sprintf("The requested ip address (%s) attached to VirtualMachine '%s': waiting for the ip address", vm.Spec.VirtualMachineIPAddress, ipAddress.Status.VirtualMachine) log.Info(msg) - mgr.Update(cb.Reason(vmcondition.ReasonIPAddressNotReady). - Message(msg).Condition()) - changed.Status.Conditions = mgr.Generate() + cb.Reason(vmcondition.ReasonIPAddressNotReady).Message(msg) return reconcile.Result{}, nil } // 5. Ip address exists and available for binding with virtual machine: waiting for the ip address. - log.Info("Waiting for the ip address to be bound to VM", "vmipName", current.Spec.VirtualMachineIPAddress) - mgr.Update(cb.Reason(vmcondition.ReasonIPAddressNotReady). - Message("Ip address not bound: waiting for the ip address").Condition()) - changed.Status.Conditions = mgr.Generate() + log.Info("Waiting for the ip address to be bound to VM", "vmipName", vm.Spec.VirtualMachineIPAddress) + cb.Reason(vmcondition.ReasonIPAddressNotReady).Message("Ip address not bound: waiting for the ip address") return reconcile.Result{}, nil } +func hasDefaultNetwork(ns []v1alpha2.NetworksStatus) bool { + for _, n := range ns { + if n.Type == v1alpha2.NetworksTypeMain { + return true + } + } + return false +} + +func (h *IPAMHandler) deleteManagedVMIP(ctx context.Context, s state.VirtualMachineState, vm *v1alpha2.VirtualMachine) error { + vmip, err := s.IPAddress(ctx) + if err != nil { + return err + } + if vmip == nil || vm == nil || vmip.Labels[annotations.LabelVirtualMachineUID] != string(vm.GetUID()) { + return nil + } + if err := h.client.Delete(ctx, vmip); err != nil && !k8serrors.IsNotFound(err) { + return err + } + return nil +} + func (h *IPAMHandler) Name() string { return nameIpamHandler } diff --git a/images/virtualization-artifact/pkg/controller/vm/internal/mac.go b/images/virtualization-artifact/pkg/controller/vm/internal/mac.go index 62841d21fd..9758984102 100644 --- a/images/virtualization-artifact/pkg/controller/vm/internal/mac.go +++ b/images/virtualization-artifact/pkg/controller/vm/internal/mac.go @@ -82,14 +82,22 @@ func (h *MACHandler) Handle(ctx context.Context, s state.VirtualMachineState) (r vmmacs, err := s.VirtualMachineMACAddresses(ctx) if err != nil { + cb.Status(metav1.ConditionFalse).Reason(vmcondition.ReasonMACAddressNotReady).Message(fmt.Sprintf("Failed to get VirtualMachineMACAddresses: %s", err)) return reconcile.Result{}, err } - // 'Main' network is always present but not require a MAC address. - expectedMACAddresses := len(vm.Spec.Networks) - 1 + expectedMACAddresses := 0 + for _, network := range vm.Spec.Networks { + // 'Main' network not require a MAC address. + if network.Type == v1alpha2.NetworksTypeMain { + continue + } + expectedMACAddresses++ + } kvvm, err := s.KVVM(ctx) if err != nil { + cb.Status(metav1.ConditionFalse).Reason(vmcondition.ReasonMACAddressNotReady).Message(fmt.Sprintf("Failed to get KVVM: %s", err)) return reconcile.Result{}, err } if len(vmmacs) < expectedMACAddresses { @@ -100,6 +108,7 @@ func (h *MACHandler) Handle(ctx context.Context, s state.VirtualMachineState) (r err = h.macManager.CreateMACAddress(ctx, vm, h.client, iface.MacAddress) createdCount++ if err != nil { + cb.Status(metav1.ConditionFalse).Reason(vmcondition.ReasonMACAddressNotReady).Message(fmt.Sprintf("Failed to create VirtualMachineMACAddress: %s", err)) return reconcile.Result{}, err } } @@ -110,6 +119,7 @@ func (h *MACHandler) Handle(ctx context.Context, s state.VirtualMachineState) (r for i := 0; i < macsToCreate; i++ { err = h.macManager.CreateMACAddress(ctx, vm, h.client, "") if err != nil { + cb.Status(metav1.ConditionFalse).Reason(vmcondition.ReasonMACAddressNotReady).Message(fmt.Sprintf("Failed to create VirtualMachineMACAddress: %s", err)) return reconcile.Result{}, err } } @@ -176,7 +186,7 @@ func countNetworksWithMACRequest(networkSpec []v1alpha2.NetworksSpec, vmmacs []* count := 0 for _, ns := range networkSpec { - if ns.Type != v1alpha2.NetworksTypeMain { + if ns.Type == v1alpha2.NetworksTypeMain { continue } diff --git a/images/virtualization-artifact/pkg/controller/vm/internal/network.go b/images/virtualization-artifact/pkg/controller/vm/internal/network.go index e50ff5b0b0..b0b02d75c7 100644 --- a/images/virtualization-artifact/pkg/controller/vm/internal/network.go +++ b/images/virtualization-artifact/pkg/controller/vm/internal/network.go @@ -72,7 +72,7 @@ func (h *NetworkInterfaceHandler) Handle(ctx context.Context, s state.VirtualMac } }() - if len(vm.Spec.Networks) > 1 { + if !hasOnlyDefaultNetwork(vm) { if !h.featureGate.Enabled(featuregates.SDN) { cb.Status(metav1.ConditionFalse).Reason(vmcondition.ReasonSDNModuleDisable).Message("For additional network interfaces, please enable SDN module") return reconcile.Result{}, nil @@ -98,6 +98,11 @@ func (h *NetworkInterfaceHandler) Handle(ctx context.Context, s state.VirtualMac return h.UpdateNetworkStatus(ctx, s, vm) } +func hasOnlyDefaultNetwork(vm *v1alpha2.VirtualMachine) bool { + nets := vm.Spec.Networks + return len(nets) == 0 || (len(nets) == 1 && nets[0].Type == v1alpha2.NetworksTypeMain) +} + func (h *NetworkInterfaceHandler) Name() string { return nameNetworkHandler } @@ -110,6 +115,16 @@ func (h *NetworkInterfaceHandler) UpdateNetworkStatus(ctx context.Context, s sta } } + if hasOnlyDefaultNetwork(vm) { + vm.Status.Networks = []v1alpha2.NetworksStatus{ + { + Type: v1alpha2.NetworksTypeMain, + Name: network.NameDefaultInterface, + }, + } + return reconcile.Result{}, nil + } + kvvm, err := s.KVVM(ctx) if err != nil { return reconcile.Result{}, err @@ -134,14 +149,16 @@ func (h *NetworkInterfaceHandler) UpdateNetworkStatus(ctx context.Context, s sta } } - networksStatus := []v1alpha2.NetworksStatus{ - { - Type: v1alpha2.NetworksTypeMain, - Name: "default", - }, - } - + var networksStatus []v1alpha2.NetworksStatus for _, interfaceSpec := range network.CreateNetworkSpec(vm, vmmacs) { + if interfaceSpec.Type == v1alpha2.NetworksTypeMain { + networksStatus = append(networksStatus, v1alpha2.NetworksStatus{ + Type: v1alpha2.NetworksTypeMain, + Name: network.NameDefaultInterface, + }) + continue + } + networksStatus = append(networksStatus, v1alpha2.NetworksStatus{ Type: interfaceSpec.Type, Name: interfaceSpec.Name, diff --git a/images/virtualization-artifact/pkg/controller/vm/internal/sync_kvvm.go b/images/virtualization-artifact/pkg/controller/vm/internal/sync_kvvm.go index 474b6b5f71..0979bce0e7 100644 --- a/images/virtualization-artifact/pkg/controller/vm/internal/sync_kvvm.go +++ b/images/virtualization-artifact/pkg/controller/vm/internal/sync_kvvm.go @@ -414,8 +414,13 @@ func MakeKVVMFromVMSpec(ctx context.Context, s state.VirtualMachineState) (*virt return nil, err } - if ip.Status.Address == "" { - return nil, fmt.Errorf("the IP address is not found for the virtual machine") + ipAddress := "" + if ip != nil { + if ip.Status.Address == "" { + return nil, fmt.Errorf("the IP address is not found for the virtual machine") + } else { + ipAddress = ip.Status.Address + } } vmmacs, err := s.VirtualMachineMACAddresses(ctx) @@ -431,7 +436,7 @@ func MakeKVVMFromVMSpec(ctx context.Context, s state.VirtualMachineState) (*virt } // Create kubevirt VirtualMachine resource from d8 VirtualMachine spec. - err = kvbuilder.ApplyVirtualMachineSpec(kvvmBuilder, current, bdState.VDByName, bdState.VIByName, bdState.CVIByName, vmbdas, class, ip.Status.Address, networkSpec) + err = kvbuilder.ApplyVirtualMachineSpec(kvvmBuilder, current, bdState.VDByName, bdState.VIByName, bdState.CVIByName, vmbdas, class, ipAddress, networkSpec) if err != nil { return nil, err } diff --git a/images/virtualization-artifact/pkg/controller/vm/internal/validators/ipam_validator.go b/images/virtualization-artifact/pkg/controller/vm/internal/validators/ipam_validator.go index 17996664e0..18a2aa33fa 100644 --- a/images/virtualization-artifact/pkg/controller/vm/internal/validators/ipam_validator.go +++ b/images/virtualization-artifact/pkg/controller/vm/internal/validators/ipam_validator.go @@ -36,7 +36,24 @@ func NewIPAMValidator(client client.Client) *IPAMValidator { return &IPAMValidator{client: client} } +func hasMainNetwork(vm *v1alpha2.VirtualMachine) bool { + if vm.Spec.Networks == nil { + return true + } + + for _, network := range vm.Spec.Networks { + if network.Type == v1alpha2.NetworksTypeMain { + return true + } + } + return false +} + func (v *IPAMValidator) ValidateCreate(ctx context.Context, vm *v1alpha2.VirtualMachine) (admission.Warnings, error) { + if vm.Spec.VirtualMachineIPAddress != "" && !hasMainNetwork(vm) { + return nil, fmt.Errorf("spec.virtualMachineIPAddressName cannot be set without Main network type in spec.networks") + } + vmipName := vm.Spec.VirtualMachineIPAddress if vmipName == "" { vmipName = vm.Name @@ -62,6 +79,10 @@ func (v *IPAMValidator) ValidateCreate(ctx context.Context, vm *v1alpha2.Virtual } func (v *IPAMValidator) ValidateUpdate(ctx context.Context, oldVM, newVM *v1alpha2.VirtualMachine) (admission.Warnings, error) { + if newVM.Spec.VirtualMachineIPAddress != "" && !hasMainNetwork(newVM) { + return nil, fmt.Errorf("spec.virtualMachineIPAddressName cannot be set without Main network type in spec.networks") + } + if oldVM.Spec.VirtualMachineIPAddress == newVM.Spec.VirtualMachineIPAddress { return nil, nil } diff --git a/images/virtualization-artifact/pkg/controller/vm/internal/validators/networks_validator.go b/images/virtualization-artifact/pkg/controller/vm/internal/validators/networks_validator.go index bf441ecda2..b41451f1b1 100644 --- a/images/virtualization-artifact/pkg/controller/vm/internal/validators/networks_validator.go +++ b/images/virtualization-artifact/pkg/controller/vm/internal/validators/networks_validator.go @@ -69,31 +69,50 @@ func (v *NetworksValidator) ValidateUpdate(_ context.Context, oldVM, newVM *v1al } func (v *NetworksValidator) validateNetworksSpec(networksSpec []v1alpha2.NetworksSpec) (admission.Warnings, error) { - if networksSpec[0].Type != v1alpha2.NetworksTypeMain { - return nil, fmt.Errorf("first network in the list must be of type '%s'", v1alpha2.NetworksTypeMain) - } - if networksSpec[0].Name != "" { - return nil, fmt.Errorf("network with type '%s' should not have a name", v1alpha2.NetworksTypeMain) - } - namesSet := make(map[string]struct{}) - for i, network := range networksSpec { - if network.Type == v1alpha2.NetworksTypeMain { - if i > 0 { - return nil, fmt.Errorf("only one network of type '%s' is allowed", v1alpha2.NetworksTypeMain) - } - continue + typ := network.Type + name := network.Name + + if typ == v1alpha2.NetworksTypeMain && i > 0 { + return nil, fmt.Errorf("first network in the list must be of type '%s'", v1alpha2.NetworksTypeMain) } - if network.Name == "" { - return nil, fmt.Errorf("network at index %d with type '%s' must have a non-empty name", i, network.Type) + + if err := v.validateNetworkName(typ, name); err != nil { + return nil, err } - if _, exists := namesSet[network.Name]; exists { - return nil, fmt.Errorf("network name '%s' is duplicated", network.Name) + if err := v.validateNetworkUniqueness(typ, name, namesSet); err != nil { + return nil, err } - namesSet[network.Name] = struct{}{} } return nil, nil } + +func (v *NetworksValidator) validateNetworkName(networkType, networkName string) error { + if networkType == v1alpha2.NetworksTypeMain { + if networkName != "" { + return fmt.Errorf("network with type '%s' should not have a name", v1alpha2.NetworksTypeMain) + } + return nil + } + + if networkName == "" { + return fmt.Errorf("network with type '%s' must have a non-empty name", networkType) + } + + return nil +} + +func (v *NetworksValidator) validateNetworkUniqueness(networkType, networkName string, namesSet map[string]struct{}) error { + key := fmt.Sprintf("%s/%s", networkType, networkName) + if _, exists := namesSet[key]; exists { + if networkName != "" { + return fmt.Errorf("network %s:%s is duplicated", networkType, networkName) + } + return fmt.Errorf("network %s is duplicated", networkType) + } + namesSet[key] = struct{}{} + return nil +} diff --git a/images/virtualization-artifact/pkg/controller/vm/internal/validators/networks_validator_test.go b/images/virtualization-artifact/pkg/controller/vm/internal/validators/networks_validator_test.go index 9a35d4a80d..4ee64f58af 100644 --- a/images/virtualization-artifact/pkg/controller/vm/internal/validators/networks_validator_test.go +++ b/images/virtualization-artifact/pkg/controller/vm/internal/validators/networks_validator_test.go @@ -24,6 +24,12 @@ import ( "github.com/deckhouse/virtualization/api/core/v1alpha2" ) +var ( + mainNetwork = v1alpha2.NetworksSpec{Type: v1alpha2.NetworksTypeMain} + network = v1alpha2.NetworksSpec{Type: v1alpha2.NetworksTypeNetwork, Name: "test"} + clusterNetwork = v1alpha2.NetworksSpec{Type: v1alpha2.NetworksTypeClusterNetwork, Name: "test"} +) + func TestNetworksValidateCreate(t *testing.T) { tests := []struct { networks []v1alpha2.NetworksSpec @@ -31,14 +37,16 @@ func TestNetworksValidateCreate(t *testing.T) { valid bool }{ {[]v1alpha2.NetworksSpec{}, true, true}, - {[]v1alpha2.NetworksSpec{{Type: v1alpha2.NetworksTypeMain}}, true, true}, - {[]v1alpha2.NetworksSpec{{Type: v1alpha2.NetworksTypeMain}, {Type: v1alpha2.NetworksTypeMain}}, true, false}, + {[]v1alpha2.NetworksSpec{mainNetwork}, true, true}, + {[]v1alpha2.NetworksSpec{mainNetwork, mainNetwork}, true, false}, + {[]v1alpha2.NetworksSpec{network, mainNetwork, mainNetwork}, true, false}, {[]v1alpha2.NetworksSpec{{Type: v1alpha2.NetworksTypeMain, Name: "main"}}, true, false}, - {[]v1alpha2.NetworksSpec{{Type: v1alpha2.NetworksTypeNetwork, Name: "test"}, {Type: v1alpha2.NetworksTypeMain}}, true, false}, - {[]v1alpha2.NetworksSpec{{Type: v1alpha2.NetworksTypeMain}, {Type: v1alpha2.NetworksTypeNetwork, Name: "test"}}, true, true}, - {[]v1alpha2.NetworksSpec{{Type: v1alpha2.NetworksTypeMain}, {Type: v1alpha2.NetworksTypeNetwork, Name: "test"}, {Type: v1alpha2.NetworksTypeNetwork, Name: "test"}}, true, false}, - {[]v1alpha2.NetworksSpec{{Type: v1alpha2.NetworksTypeMain}, {Type: v1alpha2.NetworksTypeNetwork}}, true, false}, - {[]v1alpha2.NetworksSpec{{Type: v1alpha2.NetworksTypeMain}}, false, false}, + {[]v1alpha2.NetworksSpec{network}, true, true}, + {[]v1alpha2.NetworksSpec{network, clusterNetwork}, true, true}, + {[]v1alpha2.NetworksSpec{mainNetwork, network}, true, true}, + {[]v1alpha2.NetworksSpec{mainNetwork, network, network}, true, false}, + {[]v1alpha2.NetworksSpec{mainNetwork, {Type: v1alpha2.NetworksTypeNetwork}}, true, false}, + {[]v1alpha2.NetworksSpec{mainNetwork}, false, false}, } for i, test := range tests { @@ -78,15 +86,15 @@ func TestNetworksValidateUpdate(t *testing.T) { }, { oldNetworksSpec: []v1alpha2.NetworksSpec{}, - newNetworksSpec: []v1alpha2.NetworksSpec{{Type: v1alpha2.NetworksTypeMain}}, + newNetworksSpec: []v1alpha2.NetworksSpec{mainNetwork}, sdnEnabled: true, valid: true, }, { oldNetworksSpec: []v1alpha2.NetworksSpec{}, newNetworksSpec: []v1alpha2.NetworksSpec{ - {Type: v1alpha2.NetworksTypeMain}, - {Type: v1alpha2.NetworksTypeNetwork, Name: "test"}, + mainNetwork, + network, }, sdnEnabled: true, valid: true, @@ -94,38 +102,60 @@ func TestNetworksValidateUpdate(t *testing.T) { { oldNetworksSpec: []v1alpha2.NetworksSpec{}, newNetworksSpec: []v1alpha2.NetworksSpec{ - {Type: v1alpha2.NetworksTypeMain}, - {Type: v1alpha2.NetworksTypeNetwork, Name: "test"}, - {Type: v1alpha2.NetworksTypeNetwork, Name: "test"}, + mainNetwork, + network, + network, }, sdnEnabled: true, valid: false, }, { oldNetworksSpec: []v1alpha2.NetworksSpec{ - {Type: v1alpha2.NetworksTypeMain}, - {Type: v1alpha2.NetworksTypeNetwork, Name: "test"}, - {Type: v1alpha2.NetworksTypeNetwork, Name: "test"}, - {Type: v1alpha2.NetworksTypeNetwork, Name: "test"}, + mainNetwork, + network, + network, + network, }, newNetworksSpec: []v1alpha2.NetworksSpec{ - {Type: v1alpha2.NetworksTypeMain}, - {Type: v1alpha2.NetworksTypeNetwork, Name: "test"}, - {Type: v1alpha2.NetworksTypeNetwork, Name: "test"}, + mainNetwork, + network, + network, }, sdnEnabled: true, valid: false, }, { oldNetworksSpec: []v1alpha2.NetworksSpec{ - {Type: v1alpha2.NetworksTypeMain}, - {Type: v1alpha2.NetworksTypeNetwork, Name: "test"}, - {Type: v1alpha2.NetworksTypeNetwork, Name: "test"}, - {Type: v1alpha2.NetworksTypeNetwork, Name: "test"}, + mainNetwork, + network, + network, + network, + }, + newNetworksSpec: []v1alpha2.NetworksSpec{ + mainNetwork, + network, + }, + sdnEnabled: true, + valid: true, + }, + { + oldNetworksSpec: []v1alpha2.NetworksSpec{ + mainNetwork, + network, + }, + newNetworksSpec: []v1alpha2.NetworksSpec{ + network, + }, + sdnEnabled: true, + valid: true, + }, + { + oldNetworksSpec: []v1alpha2.NetworksSpec{ + network, }, newNetworksSpec: []v1alpha2.NetworksSpec{ - {Type: v1alpha2.NetworksTypeMain}, - {Type: v1alpha2.NetworksTypeNetwork, Name: "test"}, + mainNetwork, + network, }, sdnEnabled: true, valid: true, diff --git a/images/virtualization-artifact/pkg/controller/vmip/internal/attached_handler.go b/images/virtualization-artifact/pkg/controller/vmip/internal/attached_handler.go index 9bf4a651b0..5017bc651f 100644 --- a/images/virtualization-artifact/pkg/controller/vmip/internal/attached_handler.go +++ b/images/virtualization-artifact/pkg/controller/vmip/internal/attached_handler.go @@ -102,28 +102,40 @@ func (h *AttachedHandler) getAttachedVirtualMachine(ctx context.Context, vmip *v } } - if attachedVM != nil { - return attachedVM, nil - } + if attachedVM == nil { + // If there's no match for the spec either, then try to find the vm by ownerRef. + var vmName string + for _, ownerRef := range vmip.OwnerReferences { + if ownerRef.Kind == v1alpha2.VirtualMachineKind && string(ownerRef.UID) == vmip.Labels[annotations.LabelVirtualMachineUID] { + vmName = ownerRef.Name + break + } + } - // If there's no match for the spec either, then try to find the vm by ownerRef. - var vmName string - for _, ownerRef := range vmip.OwnerReferences { - if ownerRef.Kind == v1alpha2.VirtualMachineKind && string(ownerRef.UID) == vmip.Labels[annotations.LabelVirtualMachineUID] { - vmName = ownerRef.Name - break + if vmName == "" { + return nil, nil } - } - if vmName == "" { - return nil, nil + vmKey := types.NamespacedName{Name: vmName, Namespace: vmip.Namespace} + attachedVM, err = object.FetchObject(ctx, vmKey, h.client, &v1alpha2.VirtualMachine{}) + if err != nil { + return nil, fmt.Errorf("fetch vm %s: %w", vmKey, err) + } } - vmKey := types.NamespacedName{Name: vmName, Namespace: vmip.Namespace} - attachedVM, err = object.FetchObject(ctx, vmKey, h.client, &v1alpha2.VirtualMachine{}) - if err != nil { - return nil, fmt.Errorf("fetch vm %s: %w", vmKey, err) + if attachedVM != nil { + for _, ns := range attachedVM.Status.Networks { + if ns.Type == v1alpha2.NetworksTypeMain { + return attachedVM, nil + } + } + + for _, ns := range attachedVM.Spec.Networks { + if ns.Type == v1alpha2.NetworksTypeMain { + return attachedVM, nil + } + } } - return attachedVM, nil + return nil, nil } diff --git a/images/virtualization-artifact/pkg/livemigration/migration_configuration.go b/images/virtualization-artifact/pkg/livemigration/migration_configuration.go index 21910bc868..0fe5d9851a 100644 --- a/images/virtualization-artifact/pkg/livemigration/migration_configuration.go +++ b/images/virtualization-artifact/pkg/livemigration/migration_configuration.go @@ -38,6 +38,7 @@ const ( MigrationCompletionTimeoutPerGiB int64 = 800 DefaultUnsafeMigrationOverride bool = false MigrationAllowPostCopy bool = false + MigrationAllowWorkloadDisruption bool = false ) func NewMigrationConfiguration(allowAutoConverge bool, kvconfig virtv1.KubeVirt) *virtv1.MigrationConfiguration { @@ -63,6 +64,7 @@ func NewMigrationConfiguration(allowAutoConverge bool, kvconfig virtv1.KubeVirt) completionTimeoutPerGiB := MigrationCompletionTimeoutPerGiB defaultUnsafeMigrationOverride := DefaultUnsafeMigrationOverride allowPostCopy := MigrationAllowPostCopy + allowWorkloadDisruption := MigrationAllowWorkloadDisruption return &virtv1.MigrationConfiguration{ ParallelMigrationsPerCluster: ¶llelMigrationsPerCluster, @@ -74,6 +76,7 @@ func NewMigrationConfiguration(allowAutoConverge bool, kvconfig virtv1.KubeVirt) UnsafeMigrationOverride: &defaultUnsafeMigrationOverride, AllowAutoConverge: &allowAutoConverge, AllowPostCopy: &allowPostCopy, + AllowWorkloadDisruption: &allowWorkloadDisruption, DisableTLS: nil, Network: nil, MatchSELinuxLevelOnMigration: nil, diff --git a/images/vm-route-forge/go.mod b/images/vm-route-forge/go.mod index 57bbcc5dcc..1748f07e51 100644 --- a/images/vm-route-forge/go.mod +++ b/images/vm-route-forge/go.mod @@ -67,7 +67,6 @@ require ( github.com/modern-go/reflect2 v1.0.2 // indirect github.com/munnerz/goautoneg v0.0.0-20191010083416-a7dc8b61c822 // indirect github.com/oklog/ulid v1.3.1 // indirect - github.com/openshift/api v0.0.0-20230503133300-8bbcb7ca7183 // indirect github.com/openshift/custom-resource-status v1.1.2 // indirect github.com/opentracing/opentracing-go v1.2.1-0.20220228012449-10b1cf09e00b // indirect github.com/pelletier/go-toml/v2 v2.1.0 // indirect @@ -123,8 +122,8 @@ require ( k8s.io/klog/v2 v2.130.1 // indirect k8s.io/kube-openapi v0.0.0-20250701173324-9bd5c66d9911 // indirect k8s.io/utils v0.0.0-20241104100929-3ea5e8cea738 // indirect - kubevirt.io/api v1.3.1 // indirect - kubevirt.io/containerized-data-importer-api v1.57.0-alpha1 // indirect + kubevirt.io/api v1.6.2 // indirect + kubevirt.io/containerized-data-importer-api v1.60.3-0.20241105012228-50fbed985de9 // indirect kubevirt.io/controller-lifecycle-operator-sdk/api v0.0.0-20220329064328-f3cc58c6ed90 // indirect sigs.k8s.io/json v0.0.0-20241010143419-9aa6b5e7a4b3 // indirect sigs.k8s.io/randfill v1.0.0 // indirect diff --git a/images/vm-route-forge/go.sum b/images/vm-route-forge/go.sum index 65cc2e5874..3c63121653 100644 --- a/images/vm-route-forge/go.sum +++ b/images/vm-route-forge/go.sum @@ -300,8 +300,6 @@ github.com/onsi/gomega v1.33.0/go.mod h1:+925n5YtiFsLzzafLUHzVMBpvvRAzrydIBiSIxj github.com/onsi/gomega v1.33.1/go.mod h1:U4R44UsT+9eLIaYRB2a5qajjtQYn0hauxvRm16AVYg0= github.com/onsi/gomega v1.36.1 h1:bJDPBO7ibjxcbHMgSCoo4Yj18UWbKDlLwX1x9sybDcw= github.com/onsi/gomega v1.36.1/go.mod h1:PvZbdDc8J6XJEpDK4HCuRBm8a6Fzp9/DmhC9C7yFlog= -github.com/openshift/api v0.0.0-20230503133300-8bbcb7ca7183 h1:t/CahSnpqY46sQR01SoS+Jt0jtjgmhgE6lFmRnO4q70= -github.com/openshift/api v0.0.0-20230503133300-8bbcb7ca7183/go.mod h1:4VWG+W22wrB4HfBL88P40DxLEpSOaiBVxUnfalfJo9k= github.com/openshift/custom-resource-status v1.1.2 h1:C3DL44LEbvlbItfd8mT5jWrqPfHnSOQoQf/sypqA6A4= github.com/openshift/custom-resource-status v1.1.2/go.mod h1:DB/Mf2oTeiAmVVX1gN+NEqweonAPY0TKUwADizj8+ZA= github.com/opentracing/opentracing-go v1.2.1-0.20220228012449-10b1cf09e00b h1:FfH+VrHHk6Lxt9HdVS0PXzSXFyS2NbZKXv33FYPol0A= @@ -677,10 +675,10 @@ k8s.io/utils v0.0.0-20211116205334-6203023598ed/go.mod h1:jPW/WVKK9YHAvNhRxK0md/ k8s.io/utils v0.0.0-20240711033017-18e509b52bc8/go.mod h1:OLgZIPagt7ERELqWJFomSt595RzquPNLL48iOWgYOg0= k8s.io/utils v0.0.0-20241104100929-3ea5e8cea738 h1:M3sRQVHv7vB20Xc2ybTt7ODCeFj6JSWYFzOFnYeS6Ro= k8s.io/utils v0.0.0-20241104100929-3ea5e8cea738/go.mod h1:OLgZIPagt7ERELqWJFomSt595RzquPNLL48iOWgYOg0= -kubevirt.io/api v1.3.1 h1:MoTNo/zvDlZ44c2ocXLPln8XTaQOeUodiYbEKrTCqv4= -kubevirt.io/api v1.3.1/go.mod h1:tCn7VAZktEvymk490iPSMPCmKM9UjbbfH2OsFR/IOLU= -kubevirt.io/containerized-data-importer-api v1.57.0-alpha1 h1:IWo12+ei3jltSN5jQN1xjgakfvRSF3G3Rr4GXVOOy2I= -kubevirt.io/containerized-data-importer-api v1.57.0-alpha1/go.mod h1:Y/8ETgHS1GjO89bl682DPtQOYEU/1ctPFBz6Sjxm4DM= +kubevirt.io/api v1.6.2 h1:aoqZ4KsbOyDjLnuDw7H9wEgE/YTd/q5BBmYeQjJNizc= +kubevirt.io/api v1.6.2/go.mod h1:p66fEy/g79x7VpgUwrkUgOoG2lYs5LQq37WM6JXMwj4= +kubevirt.io/containerized-data-importer-api v1.60.3-0.20241105012228-50fbed985de9 h1:KTb8wO1Lxj220DX7d2Rdo9xovvlyWWNo3AVm2ua+1nY= +kubevirt.io/containerized-data-importer-api v1.60.3-0.20241105012228-50fbed985de9/go.mod h1:SDJjLGhbPyayDqAqawcGmVNapBp0KodOQvhKPLVGCQU= kubevirt.io/controller-lifecycle-operator-sdk/api v0.0.0-20220329064328-f3cc58c6ed90 h1:QMrd0nKP0BGbnxTqakhDZAUhGKxPiPiN5gSDqKUmGGc= kubevirt.io/controller-lifecycle-operator-sdk/api v0.0.0-20220329064328-f3cc58c6ed90/go.mod h1:018lASpFYBsYN6XwmA2TIrPCx6e0gviTd/ZNtSitKgc= sigs.k8s.io/controller-runtime v0.21.0 h1:CYfjpEuicjUecRk+KAeyYh+ouUBn4llGyDYytIGcJS8= diff --git a/src/cli/go.mod b/src/cli/go.mod index 08d54d3720..b1f4841b36 100644 --- a/src/cli/go.mod +++ b/src/cli/go.mod @@ -66,8 +66,8 @@ require ( k8s.io/api v0.33.3 // indirect k8s.io/apiextensions-apiserver v0.33.3 // indirect k8s.io/kube-openapi v0.0.0-20250710124328-f3f2b991d03b // indirect - kubevirt.io/api v1.3.1 // indirect - kubevirt.io/containerized-data-importer-api v1.57.0-alpha1 // indirect + kubevirt.io/api v1.6.2 // indirect + kubevirt.io/containerized-data-importer-api v1.60.3-0.20241105012228-50fbed985de9 // indirect kubevirt.io/controller-lifecycle-operator-sdk/api v0.0.0-20220329064328-f3cc58c6ed90 // indirect sigs.k8s.io/controller-runtime v0.21.0 // indirect sigs.k8s.io/json v0.0.0-20241010143419-9aa6b5e7a4b3 // indirect diff --git a/src/cli/go.sum b/src/cli/go.sum index 19170b2178..c1dd9838cd 100644 --- a/src/cli/go.sum +++ b/src/cli/go.sum @@ -589,8 +589,12 @@ k8s.io/utils v0.0.0-20250604170112-4c0f3b243397 h1:hwvWFiBzdWw1FhfY1FooPn3kzWuJ8 k8s.io/utils v0.0.0-20250604170112-4c0f3b243397/go.mod h1:OLgZIPagt7ERELqWJFomSt595RzquPNLL48iOWgYOg0= kubevirt.io/api v1.3.1 h1:MoTNo/zvDlZ44c2ocXLPln8XTaQOeUodiYbEKrTCqv4= kubevirt.io/api v1.3.1/go.mod h1:tCn7VAZktEvymk490iPSMPCmKM9UjbbfH2OsFR/IOLU= +kubevirt.io/api v1.6.2 h1:aoqZ4KsbOyDjLnuDw7H9wEgE/YTd/q5BBmYeQjJNizc= +kubevirt.io/api v1.6.2/go.mod h1:p66fEy/g79x7VpgUwrkUgOoG2lYs5LQq37WM6JXMwj4= kubevirt.io/containerized-data-importer-api v1.57.0-alpha1 h1:IWo12+ei3jltSN5jQN1xjgakfvRSF3G3Rr4GXVOOy2I= kubevirt.io/containerized-data-importer-api v1.57.0-alpha1/go.mod h1:Y/8ETgHS1GjO89bl682DPtQOYEU/1ctPFBz6Sjxm4DM= +kubevirt.io/containerized-data-importer-api v1.60.3-0.20241105012228-50fbed985de9 h1:KTb8wO1Lxj220DX7d2Rdo9xovvlyWWNo3AVm2ua+1nY= +kubevirt.io/containerized-data-importer-api v1.60.3-0.20241105012228-50fbed985de9/go.mod h1:SDJjLGhbPyayDqAqawcGmVNapBp0KodOQvhKPLVGCQU= kubevirt.io/controller-lifecycle-operator-sdk/api v0.0.0-20220329064328-f3cc58c6ed90 h1:QMrd0nKP0BGbnxTqakhDZAUhGKxPiPiN5gSDqKUmGGc= kubevirt.io/controller-lifecycle-operator-sdk/api v0.0.0-20220329064328-f3cc58c6ed90/go.mod h1:018lASpFYBsYN6XwmA2TIrPCx6e0gviTd/ZNtSitKgc= sigs.k8s.io/controller-runtime v0.21.0 h1:CYfjpEuicjUecRk+KAeyYh+ouUBn4llGyDYytIGcJS8= diff --git a/templates/kubevirt/kubevirt.yaml b/templates/kubevirt/kubevirt.yaml index 2951618f9d..81b71c9949 100644 --- a/templates/kubevirt/kubevirt.yaml +++ b/templates/kubevirt/kubevirt.yaml @@ -52,16 +52,12 @@ spec: virtOperator: {{ $logVerbosity }} featureGates: - HotplugVolumes - - GPU - Snapshot - ExpandDisks - Root - - VMLiveUpdateFeatures - CPUManager - Sidecar - VolumeSnapshotDataSource - - VolumeMigration - - VolumesUpdateStrategy virtualMachineOptions: disableSerialConsoleLog: {} customizeComponents: diff --git a/templates/kubevirt/virt-operator/rbac-for-us.yaml b/templates/kubevirt/virt-operator/rbac-for-us.yaml index d52cec41b0..91a6311478 100644 --- a/templates/kubevirt/virt-operator/rbac-for-us.yaml +++ b/templates/kubevirt/virt-operator/rbac-for-us.yaml @@ -26,6 +26,8 @@ rules: - kubevirt-virt-api-certs - kubevirt-controller-certs - kubevirt-exportproxy-certs + - kubevirt-synchronization-controller-certs + - kubevirt-synchronization-controller-server-certs resources: - secrets verbs: @@ -834,6 +836,9 @@ rules: - virtualmachineinstances/userlist - virtualmachineinstances/sev/fetchcertchain - virtualmachineinstances/sev/querylaunchmeasurement + - virtualmachineinstances/usbredir + - virtualmachines/objectgraph + - virtualmachineinstances/objectgraph verbs: - get - apiGroups: @@ -846,6 +851,7 @@ rules: - virtualmachineinstances/freeze - virtualmachineinstances/unfreeze - virtualmachineinstances/softreboot + - virtualmachineinstances/reset - virtualmachineinstances/sev/setupsession - virtualmachineinstances/sev/injectlaunchsecret verbs: @@ -1214,6 +1220,15 @@ rules: - subjectaccessreviews verbs: - create +- apiGroups: + - resource.k8s.io + resources: + - resourceclaims + - resourceslices + verbs: + - get + - list + - watch --- apiVersion: rbac.authorization.k8s.io/v1 kind: ClusterRoleBinding diff --git a/test/e2e/go.mod b/test/e2e/go.mod index 337850b52c..5b10ad4c6e 100644 --- a/test/e2e/go.mod +++ b/test/e2e/go.mod @@ -16,7 +16,7 @@ require ( k8s.io/cli-runtime v0.33.3 k8s.io/client-go v0.33.3 k8s.io/utils v0.0.0-20250604170112-4c0f3b243397 - kubevirt.io/api v1.3.1 + kubevirt.io/api v1.6.2 kubevirt.io/containerized-data-importer-api v1.60.3 sigs.k8s.io/controller-runtime v0.21.0 sigs.k8s.io/yaml v1.4.0 diff --git a/test/e2e/go.sum b/test/e2e/go.sum index 8184d943d5..304dba8d26 100644 --- a/test/e2e/go.sum +++ b/test/e2e/go.sum @@ -582,6 +582,8 @@ k8s.io/utils v0.0.0-20250604170112-4c0f3b243397 h1:hwvWFiBzdWw1FhfY1FooPn3kzWuJ8 k8s.io/utils v0.0.0-20250604170112-4c0f3b243397/go.mod h1:OLgZIPagt7ERELqWJFomSt595RzquPNLL48iOWgYOg0= kubevirt.io/api v1.3.1 h1:MoTNo/zvDlZ44c2ocXLPln8XTaQOeUodiYbEKrTCqv4= kubevirt.io/api v1.3.1/go.mod h1:tCn7VAZktEvymk490iPSMPCmKM9UjbbfH2OsFR/IOLU= +kubevirt.io/api v1.6.2 h1:aoqZ4KsbOyDjLnuDw7H9wEgE/YTd/q5BBmYeQjJNizc= +kubevirt.io/api v1.6.2/go.mod h1:p66fEy/g79x7VpgUwrkUgOoG2lYs5LQq37WM6JXMwj4= kubevirt.io/containerized-data-importer-api v1.60.3 h1:kQEXi7scpzUa0RPf3/3MKk1Kmem0ZlqqiuK3kDF5L2I= kubevirt.io/containerized-data-importer-api v1.60.3/go.mod h1:8mwrkZIdy8j/LmCyKt2wFXbiMavLUIqDaegaIF67CZs= kubevirt.io/controller-lifecycle-operator-sdk/api v0.0.0-20220329064328-f3cc58c6ed90 h1:QMrd0nKP0BGbnxTqakhDZAUhGKxPiPiN5gSDqKUmGGc=