From 723327c701e2cf0a8574950ec31c651f1079a544 Mon Sep 17 00:00:00 2001 From: Daniil Loktev Date: Mon, 6 Oct 2025 16:09:38 +0300 Subject: [PATCH 01/77] wip Signed-off-by: Daniil Loktev --- api/core/v1alpha2/virtual_machine_class.go | 8 +- crds/clustervirtualimages.yaml | 736 +++++++------- crds/doc-ru-virtualmachineclasses.yaml | 2 +- crds/virtualdisks.yaml | 846 ++++++++-------- crds/virtualimages.yaml | 759 +++++++------- .../virtualmachineblockdeviceattachments.yaml | 324 +++--- crds/virtualmachineclasses.yaml | 932 +++++++++--------- crds/virtualmachineoperations.yaml | 570 ++++++----- crds/virtualmachinerestores.yaml | 337 ++++--- crds/virtualmachinesnapshots.yaml | 373 ++++--- .../generated/openapi/zz_generated.openapi.go | 8 +- .../controller/service/size_policy_service.go | 14 +- .../service/size_policy_service_test.go | 4 +- .../pkg/migration/core_fractions_format.go | 138 +++ .../migration/core_fractions_format_test.go | 242 +++++ .../pkg/migration/migration.go | 1 + .../vmclasses-default.yaml | 8 +- tests/e2e/testdata/sizing-policy/vmc.yaml | 22 +- 18 files changed, 2804 insertions(+), 2520 deletions(-) create mode 100644 images/virtualization-artifact/pkg/migration/core_fractions_format.go create mode 100644 images/virtualization-artifact/pkg/migration/core_fractions_format_test.go diff --git a/api/core/v1alpha2/virtual_machine_class.go b/api/core/v1alpha2/virtual_machine_class.go index 9eeaf5d254..21f83a1e65 100644 --- a/api/core/v1alpha2/virtual_machine_class.go +++ b/api/core/v1alpha2/virtual_machine_class.go @@ -115,7 +115,7 @@ type CpuDiscovery struct { type SizingPolicy struct { // Memory sizing policy. Memory *SizingPolicyMemory `json:"memory,omitempty"` - // Allowed values of the `coreFraction` parameter. + // Allowed values of the `coreFraction` parameter in percentages (e.g., "5%", "10%", "25%", "50%", "100%"). CoreFractions []CoreFractionValue `json:"coreFractions,omitempty"` // Allowed values of the `dedicatedCores` parameter. DedicatedCores []bool `json:"dedicatedCores,omitempty"` @@ -123,9 +123,9 @@ type SizingPolicy struct { Cores *SizingPolicyCores `json:"cores,omitempty"` } -// +kubebuilder:validation:Minimum=1 -// +kubebuilder:validation:Maximum=100 -type CoreFractionValue int +// CoreFractionValue represents CPU core fraction as a percentage string (e.g., "5%", "10%", "25%", "50%", "100%"). +// +kubebuilder:validation:Pattern=`^([1-9]|[1-9][0-9]|100)%?$` +type CoreFractionValue string type SizingPolicyMemory struct { MemoryMinMax `json:",inline"` diff --git a/crds/clustervirtualimages.yaml b/crds/clustervirtualimages.yaml index 93bc215d84..660f357378 100644 --- a/crds/clustervirtualimages.yaml +++ b/crds/clustervirtualimages.yaml @@ -13,411 +13,387 @@ spec: group: virtualization.deckhouse.io names: categories: - - virtualization-cluster + - virtualization-cluster kind: ClusterVirtualImage listKind: ClusterVirtualImageList plural: clustervirtualimages shortNames: - - cvi + - cvi singular: clustervirtualimage scope: Cluster versions: - - additionalPrinterColumns: - - jsonPath: .status.phase - name: Phase - type: string - - jsonPath: .status.cdrom - name: CDROM - type: boolean - - jsonPath: .status.progress - name: Progress - type: string - - jsonPath: .status.size.stored - name: StoredSize - priority: 1 - type: string - - jsonPath: .status.size.unpacked - name: UnpackedSize - priority: 1 - type: string - - jsonPath: .status.target.registryURL - name: Registry URL - priority: 1 - type: string - - jsonPath: .metadata.creationTimestamp - name: Age - type: date - name: v1alpha2 - schema: - openAPIV3Schema: - description: |- - Describes a virtual disk image that can be used as a data source for new VirtualDisks or an installation image (iso) to be mounted in VirtualMachines directly. This resource type is available for all namespaces in the cluster. + - additionalPrinterColumns: + - jsonPath: .status.phase + name: Phase + type: string + - jsonPath: .status.cdrom + name: CDROM + type: boolean + - jsonPath: .status.progress + name: Progress + type: string + - jsonPath: .status.size.stored + name: StoredSize + priority: 1 + type: string + - jsonPath: .status.size.unpacked + name: UnpackedSize + priority: 1 + type: string + - jsonPath: .status.target.registryURL + name: Registry URL + priority: 1 + type: string + - jsonPath: .metadata.creationTimestamp + name: Age + type: date + name: v1alpha2 + schema: + openAPIV3Schema: + description: |- + Describes a virtual disk image that can be used as a data source for new VirtualDisks or an installation image (iso) to be mounted in VirtualMachines directly. This resource type is available for all namespaces in the cluster. - > This resource cannot be modified once it has been created. + > This resource cannot be modified once it has been created. - With this resource in the cluster, a container image is created and stored in a dedicated Deckhouse Virtualization Container Registry (DVCR). - properties: - apiVersion: - description: |- - APIVersion defines the versioned schema of this representation of an object. - Servers should convert recognized schemas to the latest internal value, and - may reject unrecognized values. - More info: https://git.k8s.io/community/contributors/devel/sig-architecture/api-conventions.md#resources - type: string - kind: - description: |- - Kind is a string value representing the REST resource this object represents. - Servers may infer this from the endpoint the client submits requests to. - Cannot be updated. - In CamelCase. - More info: https://git.k8s.io/community/contributors/devel/sig-architecture/api-conventions.md#types-kinds - type: string - metadata: - type: object - spec: - properties: - dataSource: - description: Origin of the image. - properties: - containerImage: - description: - Use an image stored in external container registry. - Only registries with enabled TLS protocol are supported. To - provide a custom Certificate Authority (CA) chain, use the `caBundle` - field. - properties: - caBundle: - description: - CA chain in Base64 format to verify the container - registry. - example: YWFhCg== - format: byte - type: string - image: - description: Path to the image in the container registry. - example: registry.example.com/images/slackware:15 - pattern: ^(?P(?:(?P(?:(?:localhost|[\w-]+(?:\.[\w-]+)+)(?::\d+)?)|[\w]+:\d+)/)?(?P[a-z0-9_.-]+(?:/[a-z0-9_.-]+)*))(?::(?P[\w][\w.-]{0,127}))?(?:@(?P[A-Za-z][A-Za-z0-9]*(?:[+.-_][A-Za-z][A-Za-z0-9]*)*:[0-9a-fA-F]{32,}))?$ - type: string - imagePullSecret: - properties: - name: - description: - Name of the secret keeping container registry - credentials. - type: string - namespace: - description: Namespace where `imagePullSecret` is located. - type: string - type: object - required: - - image - type: object - http: - description: |- - Fill the image with data from an external URL. The following schemas are supported: + With this resource in the cluster, a container image is created and stored in a dedicated Deckhouse Virtualization Container Registry (DVCR). + properties: + apiVersion: + description: |- + APIVersion defines the versioned schema of this representation of an object. + Servers should convert recognized schemas to the latest internal value, and + may reject unrecognized values. + More info: https://git.k8s.io/community/contributors/devel/sig-architecture/api-conventions.md#resources + type: string + kind: + description: |- + Kind is a string value representing the REST resource this object represents. + Servers may infer this from the endpoint the client submits requests to. + Cannot be updated. + In CamelCase. + More info: https://git.k8s.io/community/contributors/devel/sig-architecture/api-conventions.md#types-kinds + type: string + metadata: + type: object + spec: + properties: + dataSource: + description: Origin of the image. + properties: + containerImage: + description: Use an image stored in external container registry. + Only registries with enabled TLS protocol are supported. To + provide a custom Certificate Authority (CA) chain, use the `caBundle` + field. + properties: + caBundle: + description: CA chain in Base64 format to verify the container + registry. + example: YWFhCg== + format: byte + type: string + image: + description: Path to the image in the container registry. + example: registry.example.com/images/slackware:15 + pattern: ^(?P(?:(?P(?:(?:localhost|[\w-]+(?:\.[\w-]+)+)(?::\d+)?)|[\w]+:\d+)/)?(?P[a-z0-9_.-]+(?:/[a-z0-9_.-]+)*))(?::(?P[\w][\w.-]{0,127}))?(?:@(?P[A-Za-z][A-Za-z0-9]*(?:[+.-_][A-Za-z][A-Za-z0-9]*)*:[0-9a-fA-F]{32,}))?$ + type: string + imagePullSecret: + properties: + name: + description: Name of the secret keeping container registry + credentials. + type: string + namespace: + description: Namespace where `imagePullSecret` is located. + type: string + type: object + required: + - image + type: object + http: + description: |- + Fill the image with data from an external URL. The following schemas are supported: - * HTTP - * HTTPS + * HTTP + * HTTPS - For HTTPS schema, there is an option to skip the TLS verification. - properties: - caBundle: - description: CA chain in Base64 format to verify the URL. - example: YWFhCg== - format: byte - type: string - checksum: - description: - Checksum to verify integrity and consistency - of the downloaded file. The file must match all specified - checksums. - properties: - md5: - example: f3b59bed9f91e32fac1210184fcff6f5 - maxLength: 32 - minLength: 32 - pattern: ^[0-9a-fA-F]{32}$ - type: string - sha256: - example: 78be890d71dde316c412da2ce8332ba47b9ce7a29d573801d2777e01aa20b9b5 - maxLength: 64 - minLength: 64 - pattern: ^[0-9a-fA-F]{64}$ - type: string - type: object - url: - description: |- - URL of the file for creating an image. The following file formats are supported: - * qcow2 - * vmdk - * vdi - * iso - * raw - The file can be compressed into an archive in one of the following formats: - * gz - * xz - example: https://mirror.example.com/images/slackware-15.qcow.gz - pattern: ^http[s]?:\/\/(?:[a-zA-Z]|[0-9]|[$-_@.&+]|[!*\(\),]|(?:%[0-9a-fA-F][0-9a-fA-F]))+$ - type: string - required: - - url - type: object - objectRef: - description: - Use an existing VirtualImage, ClusterVirtualImage, - VirtualDisk or VirtualDiskSnapshot resource to create an image. - properties: - kind: - description: - Kind of the existing VirtualImage, ClusterVirtualImage, - VirtualDisk or VirtualDiskSnapshot resource. - enum: - - ClusterVirtualImage - - VirtualImage - - VirtualDisk - - VirtualDiskSnapshot - type: string - name: - description: - Name of the existing VirtualImage, ClusterVirtualImage, - VirtualDisk or VirtualDiskSnapshot resource. - type: string - namespace: - description: - Namespace where the VirtualImage, VirtualDisk - or VirtualDiskSnapshot resource is located. - type: string - required: - - kind - - name - type: object - x-kubernetes-validations: - - message: - The namespace is required for VirtualDisk, VirtualImage - and VirtualDiskSnapshot - rule: - "self.kind == 'VirtualImage' || self.kind == 'VirtualDisk' - || self.kind == 'VirtualDiskSnapshot' ? has(self.__namespace__) - && size(self.__namespace__) > 0 : true" - - message: The namespace must be no longer than 63 characters. - rule: - "self.kind == 'VirtualImage' || self.kind == 'VirtualDisk' - || self.kind == 'VirtualDiskSnapshot' ? has(self.__namespace__) - && size(self.__namespace__) < 64 : true" - type: - description: |- - The following image sources are available for creating an image: - - * `HTTP`: From a file published on an HTTP/HTTPS service at a given URL. - * `ContainerImage`: From another image stored in a container registry. - * `ObjectRef`: From an existing resource. - * `Upload`: From data uploaded by the user via a special interface. - enum: - - HTTP - - ContainerImage - - ObjectRef - - Upload - type: string - required: - - type - type: object - x-kubernetes-validations: - - message: HTTP requires http and cannot have ContainerImage or ObjectRef. - rule: - "self.type == 'HTTP' ? has(self.http) && !has(self.containerImage) - && !has(self.objectRef) : true" - - message: - ContainerImage requires containerImage and cannot have - HTTP or ObjectRef. - rule: - "self.type == 'ContainerImage' ? has(self.containerImage) - && !has(self.http) && !has(self.objectRef) : true" - - message: ObjectRef requires objectRef and cannot have HTTP or ContainerImage. - rule: - "self.type == 'ObjectRef' ? has(self.objectRef) && !has(self.http) - && !has(self.containerImage) : true" - required: - - dataSource - type: object - status: - properties: - cdrom: - description: - Defines whether the image is in a format that needs to - be mounted as a CD-ROM drive, such as iso and so on. - type: boolean - conditions: - description: - The latest available observations of an object's current - state. - items: - description: - Condition contains details for one aspect of the current - state of this API Resource. + For HTTPS schema, there is an option to skip the TLS verification. properties: - lastTransitionTime: - description: |- - lastTransitionTime is the last time the condition transitioned from one status to another. - This should be when the underlying condition changed. If that is not known, then using the time when the API field changed is acceptable. - format: date-time + caBundle: + description: CA chain in Base64 format to verify the URL. + example: YWFhCg== + format: byte type: string - message: + checksum: + description: Checksum to verify integrity and consistency + of the downloaded file. The file must match all specified + checksums. + properties: + md5: + example: f3b59bed9f91e32fac1210184fcff6f5 + maxLength: 32 + minLength: 32 + pattern: ^[0-9a-fA-F]{32}$ + type: string + sha256: + example: 78be890d71dde316c412da2ce8332ba47b9ce7a29d573801d2777e01aa20b9b5 + maxLength: 64 + minLength: 64 + pattern: ^[0-9a-fA-F]{64}$ + type: string + type: object + url: description: |- - message is a human readable message indicating details about the transition. - This may be an empty string. - maxLength: 32768 + URL of the file for creating an image. The following file formats are supported: + * qcow2 + * vmdk + * vdi + * iso + * raw + The file can be compressed into an archive in one of the following formats: + * gz + * xz + example: https://mirror.example.com/images/slackware-15.qcow.gz + pattern: ^http[s]?:\/\/(?:[a-zA-Z]|[0-9]|[$-_@.&+]|[!*\(\),]|(?:%[0-9a-fA-F][0-9a-fA-F]))+$ type: string - observedGeneration: - description: |- - observedGeneration represents the .metadata.generation that the condition was set based upon. - For instance, if .metadata.generation is currently 12, but the .status.conditions[x].observedGeneration is 9, the condition is out of date - with respect to the current state of the instance. - format: int64 - minimum: 0 - type: integer - reason: - description: |- - reason contains a programmatic identifier indicating the reason for the condition's last transition. - Producers of specific condition types may define expected values and meanings for this field, - and whether the values are considered a guaranteed API. - The value should be a CamelCase string. - This field may not be empty. - maxLength: 1024 - minLength: 1 - pattern: ^[A-Za-z]([A-Za-z0-9_,:]*[A-Za-z0-9_])?$ - type: string - status: - description: status of the condition, one of True, False, Unknown. + required: + - url + type: object + objectRef: + description: Use an existing VirtualImage, ClusterVirtualImage, + VirtualDisk or VirtualDiskSnapshot resource to create an image. + properties: + kind: + description: Kind of the existing VirtualImage, ClusterVirtualImage, + VirtualDisk or VirtualDiskSnapshot resource. enum: - - "True" - - "False" - - Unknown + - ClusterVirtualImage + - VirtualImage + - VirtualDisk + - VirtualDiskSnapshot type: string - type: - description: type of condition in CamelCase or in foo.example.com/CamelCase. - maxLength: 316 - pattern: ^([a-z0-9]([-a-z0-9]*[a-z0-9])?(\.[a-z0-9]([-a-z0-9]*[a-z0-9])?)*/)?(([A-Za-z0-9][-A-Za-z0-9_.]*)?[A-Za-z0-9])$ + name: + description: Name of the existing VirtualImage, ClusterVirtualImage, + VirtualDisk or VirtualDiskSnapshot resource. + type: string + namespace: + description: Namespace where the VirtualImage, VirtualDisk + or VirtualDiskSnapshot resource is located. type: string required: - - lastTransitionTime - - message - - reason - - status - - type + - kind + - name type: object - type: array - downloadSpeed: - description: - Image download speed from an external source. Appears - only during the `Provisioning` phase. - properties: - avg: - description: Average download speed. - example: 1 Mbps - type: string - avgBytes: - description: Average download speed in bytes per second. - example: 1012345 - type: string - current: - description: Current download speed. - example: 5 Mbps - type: string - currentBytes: - description: Current download speed in bytes per second. - example: 5123456 - type: string - type: object - format: - description: Discovered image format. - type: string - imageUploadURLs: - properties: - external: - description: - Command to upload the image using `Ingress` from - outside the cluster. - type: string - inCluster: - description: - Command to upload the image using `Service` within - the cluster. - type: string - type: object - observedGeneration: - description: Resource generation last processed by the controller. - format: int64 - type: integer - phase: - description: |- - Current status of the ClusterVirtualImage resource: - * `Pending`: The resource has been created and is on a waiting queue. - * `Provisioning`: The resource is being created: copying, downloading, or building of the image is in progress. - * `WaitForUserUpload`: Waiting for the user to upload the image. The endpoint to upload the image is specified in `.status.uploadCommand`. - * `Ready`: The resource has been created and is ready to use. - * `Failed`: There was an error when creating the resource. - * `Terminating`: The resource is being deleted. - enum: - - Pending - - Provisioning - - WaitForUserUpload - - Ready - - Failed - - Terminating - type: string - progress: - description: - Progress of copying an image from the source to DVCR. - Appears only during the `Provisioning' phase. - type: string - size: - description: Discovered image size data. + x-kubernetes-validations: + - message: The namespace is required for VirtualDisk, VirtualImage + and VirtualDiskSnapshot + rule: 'self.kind == ''VirtualImage'' || self.kind == ''VirtualDisk'' + || self.kind == ''VirtualDiskSnapshot'' ? has(self.__namespace__) + && size(self.__namespace__) > 0 : true' + - message: The namespace must be no longer than 63 characters. + rule: 'self.kind == ''VirtualImage'' || self.kind == ''VirtualDisk'' + || self.kind == ''VirtualDiskSnapshot'' ? has(self.__namespace__) + && size(self.__namespace__) < 64 : true' + type: + description: |- + The following image sources are available for creating an image: + + * `HTTP`: From a file published on an HTTP/HTTPS service at a given URL. + * `ContainerImage`: From another image stored in a container registry. + * `ObjectRef`: From an existing resource. + * `Upload`: From data uploaded by the user via a special interface. + enum: + - HTTP + - ContainerImage + - ObjectRef + - Upload + type: string + required: + - type + type: object + x-kubernetes-validations: + - message: HTTP requires http and cannot have ContainerImage or ObjectRef. + rule: 'self.type == ''HTTP'' ? has(self.http) && !has(self.containerImage) + && !has(self.objectRef) : true' + - message: ContainerImage requires containerImage and cannot have + HTTP or ObjectRef. + rule: 'self.type == ''ContainerImage'' ? has(self.containerImage) + && !has(self.http) && !has(self.objectRef) : true' + - message: ObjectRef requires objectRef and cannot have HTTP or ContainerImage. + rule: 'self.type == ''ObjectRef'' ? has(self.objectRef) && !has(self.http) + && !has(self.containerImage) : true' + required: + - dataSource + type: object + status: + properties: + cdrom: + description: Defines whether the image is in a format that needs to + be mounted as a CD-ROM drive, such as iso and so on. + type: boolean + conditions: + description: The latest available observations of an object's current + state. + items: + description: Condition contains details for one aspect of the current + state of this API Resource. properties: - stored: - description: Image size in human-readable format. - example: 199M + lastTransitionTime: + description: |- + lastTransitionTime is the last time the condition transitioned from one status to another. + This should be when the underlying condition changed. If that is not known, then using the time when the API field changed is acceptable. + format: date-time type: string - storedBytes: - description: Image size in bytes. - example: 199001234 + message: + description: |- + message is a human readable message indicating details about the transition. + This may be an empty string. + maxLength: 32768 type: string - unpacked: - description: Unpacked image size in human-readable format. - example: 1G + observedGeneration: + description: |- + observedGeneration represents the .metadata.generation that the condition was set based upon. + For instance, if .metadata.generation is currently 12, but the .status.conditions[x].observedGeneration is 9, the condition is out of date + with respect to the current state of the instance. + format: int64 + minimum: 0 + type: integer + reason: + description: |- + reason contains a programmatic identifier indicating the reason for the condition's last transition. + Producers of specific condition types may define expected values and meanings for this field, + and whether the values are considered a guaranteed API. + The value should be a CamelCase string. + This field may not be empty. + maxLength: 1024 + minLength: 1 + pattern: ^[A-Za-z]([A-Za-z0-9_,:]*[A-Za-z0-9_])?$ type: string - unpackedBytes: - description: Unpacked image size in bytes. - example: 1000000234 + status: + description: status of the condition, one of True, False, Unknown. + enum: + - "True" + - "False" + - Unknown type: string - type: object - sourceUID: - description: - UID of the source (VirtualImage, ClusterVirtualImage, - VirtualDisk or VirtualDiskSnapshot) used when creating the cluster - virtual image. - type: string - target: - properties: - registryURL: - description: Created image in DVCR. - example: dvcr..svc/cvi/:latest + type: + description: type of condition in CamelCase or in foo.example.com/CamelCase. + maxLength: 316 + pattern: ^([a-z0-9]([-a-z0-9]*[a-z0-9])?(\.[a-z0-9]([-a-z0-9]*[a-z0-9])?)*/)?(([A-Za-z0-9][-A-Za-z0-9_.]*)?[A-Za-z0-9])$ type: string + required: + - lastTransitionTime + - message + - reason + - status + - type type: object - uploadCommand: - description: Deprecated. Use `imageUploadURLs` instead. - type: string - usedInNamespaces: - description: - Displays the list of namespaces where the image is currently - used. - items: + type: array + downloadSpeed: + description: Image download speed from an external source. Appears + only during the `Provisioning` phase. + properties: + avg: + description: Average download speed. + example: 1 Mbps + type: string + avgBytes: + description: Average download speed in bytes per second. + example: 1012345 + type: string + current: + description: Current download speed. + example: 5 Mbps + type: string + currentBytes: + description: Current download speed in bytes per second. + example: 5123456 + type: string + type: object + format: + description: Discovered image format. + type: string + imageUploadURLs: + properties: + external: + description: Command to upload the image using `Ingress` from + outside the cluster. type: string - type: array - type: object - required: - - spec - type: object - served: true - storage: true - subresources: - status: {} + inCluster: + description: Command to upload the image using `Service` within + the cluster. + type: string + type: object + observedGeneration: + description: Resource generation last processed by the controller. + format: int64 + type: integer + phase: + description: |- + Current status of the ClusterVirtualImage resource: + * `Pending`: The resource has been created and is on a waiting queue. + * `Provisioning`: The resource is being created: copying, downloading, or building of the image is in progress. + * `WaitForUserUpload`: Waiting for the user to upload the image. The endpoint to upload the image is specified in `.status.uploadCommand`. + * `Ready`: The resource has been created and is ready to use. + * `Failed`: There was an error when creating the resource. + * `Terminating`: The resource is being deleted. + enum: + - Pending + - Provisioning + - WaitForUserUpload + - Ready + - Failed + - Terminating + type: string + progress: + description: Progress of copying an image from the source to DVCR. + Appears only during the `Provisioning' phase. + type: string + size: + description: Discovered image size data. + properties: + stored: + description: Image size in human-readable format. + example: 199M + type: string + storedBytes: + description: Image size in bytes. + example: 199001234 + type: string + unpacked: + description: Unpacked image size in human-readable format. + example: 1G + type: string + unpackedBytes: + description: Unpacked image size in bytes. + example: 1000000234 + type: string + type: object + sourceUID: + description: UID of the source (VirtualImage, ClusterVirtualImage, + VirtualDisk or VirtualDiskSnapshot) used when creating the cluster + virtual image. + type: string + target: + properties: + registryURL: + description: Created image in DVCR. + example: dvcr..svc/cvi/:latest + type: string + type: object + uploadCommand: + description: Deprecated. Use `imageUploadURLs` instead. + type: string + usedInNamespaces: + description: Displays the list of namespaces where the image is currently + used. + items: + type: string + type: array + type: object + required: + - spec + type: object + served: true + storage: true + subresources: + status: {} diff --git a/crds/doc-ru-virtualmachineclasses.yaml b/crds/doc-ru-virtualmachineclasses.yaml index fd11d51e4f..c0abe39ad8 100644 --- a/crds/doc-ru-virtualmachineclasses.yaml +++ b/crds/doc-ru-virtualmachineclasses.yaml @@ -133,7 +133,7 @@ spec: properties: coreFractions: description: | - Допустимые значения параметра `coreFraction`. + Допустимые значения параметра `coreFraction` в процентах (например, "5%", "10%", "25%", "50%", "100%"). cores: description: | Политика применяется для заданного диапазона числа ядер CPU. diff --git a/crds/virtualdisks.yaml b/crds/virtualdisks.yaml index c00c80d46b..875f85a46a 100644 --- a/crds/virtualdisks.yaml +++ b/crds/virtualdisks.yaml @@ -12,470 +12,448 @@ spec: group: virtualization.deckhouse.io names: categories: - - virtualization + - virtualization kind: VirtualDisk listKind: VirtualDiskList plural: virtualdisks shortNames: - - vd + - vd singular: virtualdisk scope: Namespaced versions: - - additionalPrinterColumns: - - jsonPath: .status.phase - name: Phase - type: string - - jsonPath: .status.capacity - name: Capacity - type: string - - jsonPath: .status.conditions[?(@.type=='InUse')].status - name: InUse - priority: 1 - type: string - - jsonPath: .status.progress - name: Progress - priority: 1 - type: string - - jsonPath: .status.storageClassName - name: StorageClass - priority: 1 - type: string - - jsonPath: .status.target.persistentVolumeClaimName - name: TargetPVC - priority: 1 - type: string - - jsonPath: .metadata.creationTimestamp - name: Age - type: date - name: v1alpha2 - schema: - openAPIV3Schema: - description: |- - The VirtualDisk resource describes the desired virtual machine disk configuration. A VirtualDisk can be mounted statically in the virtual machine by specifying it in the `.spec.blockDeviceRefs` disk list, or mounted on-the-fly using the VirtualMachineBlockDeviceAttachments resource. + - additionalPrinterColumns: + - jsonPath: .status.phase + name: Phase + type: string + - jsonPath: .status.capacity + name: Capacity + type: string + - jsonPath: .status.conditions[?(@.type=='InUse')].status + name: InUse + priority: 1 + type: string + - jsonPath: .status.progress + name: Progress + priority: 1 + type: string + - jsonPath: .status.storageClassName + name: StorageClass + priority: 1 + type: string + - jsonPath: .status.target.persistentVolumeClaimName + name: TargetPVC + priority: 1 + type: string + - jsonPath: .metadata.creationTimestamp + name: Age + type: date + name: v1alpha2 + schema: + openAPIV3Schema: + description: |- + The VirtualDisk resource describes the desired virtual machine disk configuration. A VirtualDisk can be mounted statically in the virtual machine by specifying it in the `.spec.blockDeviceRefs` disk list, or mounted on-the-fly using the VirtualMachineBlockDeviceAttachments resource. - Once a VirtualDisk is created, only the disk size field `.spec.persistentVolumeClaim.size` can be changed. All other fields are immutable. - properties: - apiVersion: - description: |- - APIVersion defines the versioned schema of this representation of an object. - Servers should convert recognized schemas to the latest internal value, and - may reject unrecognized values. - More info: https://git.k8s.io/community/contributors/devel/sig-architecture/api-conventions.md#resources - type: string - kind: - description: |- - Kind is a string value representing the REST resource this object represents. - Servers may infer this from the endpoint the client submits requests to. - Cannot be updated. - In CamelCase. - More info: https://git.k8s.io/community/contributors/devel/sig-architecture/api-conventions.md#types-kinds - type: string - metadata: - type: object - spec: - properties: - dataSource: - properties: - containerImage: - description: - Use an image stored in an external container registry. - Only registries with enabled TLS are supported. To provide a - custom Certificate Authority (CA) chain, use the `caBundle` - field. - properties: - caBundle: - description: - CA chain in Base64 format to verify the container - registry. - example: YWFhCg== - format: byte - type: string - image: - description: Path to the image in the container registry. - example: registry.example.com/images/slackware:15 - pattern: ^(?P(?:(?P(?:(?:localhost|[\w-]+(?:\.[\w-]+)+)(?::\d+)?)|[\w]+:\d+)/)?(?P[a-z0-9_.-]+(?:/[a-z0-9_.-]+)*))(?::(?P[\w][\w.-]{0,127}))?(?:@(?P[A-Za-z][A-Za-z0-9]*(?:[+.-_][A-Za-z][A-Za-z0-9]*)*:[0-9a-fA-F]{32,}))?$ - type: string - imagePullSecret: - properties: - name: - description: - Name of the secret keeping container registry - credentials, which must be located in the same namespace. - type: string - type: object - required: - - image - type: object - http: - description: |- - Fill the image with data from an external URL. The following schemas are supported: - - * HTTP - * HTTPS - - For HTTPS schema, there is an option to skip the TLS verification. - properties: - caBundle: - description: CA chain in Base64 format to verify the URL. - example: YWFhCg== - format: byte - type: string - checksum: - description: - Checksum to verify integrity and consistency - of the downloaded file. The file must match all specified - checksums. - properties: - md5: - example: f3b59bed9f91e32fac1210184fcff6f5 - maxLength: 32 - minLength: 32 - pattern: ^[0-9a-fA-F]{32}$ - type: string - sha256: - example: 78be890d71dde316c412da2ce8332ba47b9ce7a29d573801d2777e01aa20b9b5 - maxLength: 64 - minLength: 64 - pattern: ^[0-9a-fA-F]{64}$ - type: string - type: object - url: - description: |- - URL of the file for creating an image. The following file formats are supported: - * qcow2 - * vmdk - * vdi - * iso - * raw - The file can be compressed into an archive in one of the following formats: - * gz - * xz - example: https://mirror.example.com/images/slackware-15.qcow.gz - pattern: ^http[s]?:\/\/(?:[a-zA-Z]|[0-9]|[$-_@.&+]|[!*\(\),]|(?:%[0-9a-fA-F][0-9a-fA-F]))+$ - type: string - required: - - url - type: object - objectRef: - description: - Use an existing VirtualImage, ClusterVirtualImage, - or VirtualDiskSnapshot resource to create a disk. - properties: - kind: - description: - Kind of the existing VirtualImage, ClusterVirtualImage, - or VirtualDiskSnapshot resource. - enum: - - ClusterVirtualImage - - VirtualImage - - VirtualDiskSnapshot - type: string - name: - description: - Name of the existing VirtualImage, ClusterVirtualImage, - or VirtualDiskSnapshot resource. - type: string - required: - - kind - - name - type: object - type: - description: |- - The following image sources are available for creating an image: - - * `HTTP`: From a file published on an HTTP/HTTPS service at a given URL. - * `ContainerImage`: From another image stored in a container registry. - * `ObjectRef`: From an existing resource. - * `Upload`: From data uploaded by the user via a special interface. - enum: - - HTTP - - ContainerImage - - ObjectRef - - Upload - type: string - type: object - x-kubernetes-validations: - - message: HTTP requires http and cannot have ContainerImage or ObjectRef. - rule: - "self.type == 'HTTP' ? has(self.http) && !has(self.containerImage) - && !has(self.objectRef) : true" - - message: - ContainerImage requires containerImage and cannot have - HTTP or ObjectRef. - rule: - "self.type == 'ContainerImage' ? has(self.containerImage) - && !has(self.http) && !has(self.objectRef) : true" - - message: ObjectRef requires objectRef and cannot have HTTP or ContainerImage. - rule: - "self.type == 'ObjectRef' ? has(self.objectRef) && !has(self.http) - && !has(self.containerImage) : true" - persistentVolumeClaim: - description: Settings for creating PVCs to store the disk. - properties: - size: - anyOf: - - type: integer - - type: string - description: |- - Desired size for PVC to store the disk. If the disk is created from an image, the size must be at least as large as the original unpacked image. - - This parameter can be omitted if the `.spec.dataSource` section is filled out. In this case, the controller will determine the disk size automatically, based on the size of the extracted image from the source specified in `.spec.dataSource`. - pattern: ^(\+|-)?(([0-9]+(\.[0-9]*)?)|(\.[0-9]+))(([KMGTPE]i)|[numkMGTPE]|([eE](\+|-)?(([0-9]+(\.[0-9]*)?)|(\.[0-9]+))))?$ - x-kubernetes-int-or-string: true - storageClassName: - description: |- - StorageClass name required by the claim. For details on using StorageClass for PVC, refer to https://kubernetes.io/docs/concepts/storage/persistent-volumes#class-1. - - When creating disks, the user can specify the required StorageClass. If not specified, the default StorageClass will be used. - - The disk features and virtual machine behavior depend on the selected StorageClass. - - The `VolumeBindingMode` parameter in the StorageClass affects the disk creation process. The following values are allowed: - - `Immediate`: The disk will be created and becomes available for use immediately after creation. - - `WaitForFirstConsumer`: The disk will be created when first used on the node where the virtual machine will be started. - - StorageClass supports multiple storage settings: - - Creating a block device (`Block`) or file system (`FileSystem`). - - Multiple access (`ReadWriteMany`) or single access (`ReadWriteOnce`). The `ReadWriteMany` disks support multiple access, which enables a "live" migration of virtual machines. In contrast, the `ReadWriteOnce` disks, which can be accessed from only one node, don't have this feature. - - For known storage types, Deckhouse automatically determines the most efficient settings when creating disks (by priority, in descending order): - 1. `Block` + `ReadWriteMany` - 2. `FileSystem` + `ReadWriteMany` - 3. `Block` + `ReadWriteOnce` - 4. `FileSystem` + `ReadWriteOnce` - type: string - type: object - type: object - status: - properties: - attachedToVirtualMachines: - description: List of VirtualMachines that use the disk. - example: - - name: VM100 - items: - description: List of VirtualMachines that use the disk. + Once a VirtualDisk is created, only the disk size field `.spec.persistentVolumeClaim.size` can be changed. All other fields are immutable. + properties: + apiVersion: + description: |- + APIVersion defines the versioned schema of this representation of an object. + Servers should convert recognized schemas to the latest internal value, and + may reject unrecognized values. + More info: https://git.k8s.io/community/contributors/devel/sig-architecture/api-conventions.md#resources + type: string + kind: + description: |- + Kind is a string value representing the REST resource this object represents. + Servers may infer this from the endpoint the client submits requests to. + Cannot be updated. + In CamelCase. + More info: https://git.k8s.io/community/contributors/devel/sig-architecture/api-conventions.md#types-kinds + type: string + metadata: + type: object + spec: + properties: + dataSource: + properties: + containerImage: + description: Use an image stored in an external container registry. + Only registries with enabled TLS are supported. To provide a + custom Certificate Authority (CA) chain, use the `caBundle` + field. properties: - mounted: - description: - Flag indicating that VirtualDisk is currently being - used by this attached VirtualMachine. - type: boolean - name: - description: Name of attached VirtualMachine. + caBundle: + description: CA chain in Base64 format to verify the container + registry. + example: YWFhCg== + format: byte type: string + image: + description: Path to the image in the container registry. + example: registry.example.com/images/slackware:15 + pattern: ^(?P(?:(?P(?:(?:localhost|[\w-]+(?:\.[\w-]+)+)(?::\d+)?)|[\w]+:\d+)/)?(?P[a-z0-9_.-]+(?:/[a-z0-9_.-]+)*))(?::(?P[\w][\w.-]{0,127}))?(?:@(?P[A-Za-z][A-Za-z0-9]*(?:[+.-_][A-Za-z][A-Za-z0-9]*)*:[0-9a-fA-F]{32,}))?$ + type: string + imagePullSecret: + properties: + name: + description: Name of the secret keeping container registry + credentials, which must be located in the same namespace. + type: string + type: object + required: + - image type: object - type: array - capacity: - description: Requested PVC capacity in human-readable format. - example: 50G - type: string - conditions: - description: - The latest available observations of an object's current - state. - items: - description: - Condition contains details for one aspect of the current - state of this API Resource. + http: + description: |- + Fill the image with data from an external URL. The following schemas are supported: + + * HTTP + * HTTPS + + For HTTPS schema, there is an option to skip the TLS verification. properties: - lastTransitionTime: - description: |- - lastTransitionTime is the last time the condition transitioned from one status to another. - This should be when the underlying condition changed. If that is not known, then using the time when the API field changed is acceptable. - format: date-time - type: string - message: - description: |- - message is a human readable message indicating details about the transition. - This may be an empty string. - maxLength: 32768 + caBundle: + description: CA chain in Base64 format to verify the URL. + example: YWFhCg== + format: byte type: string - observedGeneration: - description: |- - observedGeneration represents the .metadata.generation that the condition was set based upon. - For instance, if .metadata.generation is currently 12, but the .status.conditions[x].observedGeneration is 9, the condition is out of date - with respect to the current state of the instance. - format: int64 - minimum: 0 - type: integer - reason: + checksum: + description: Checksum to verify integrity and consistency + of the downloaded file. The file must match all specified + checksums. + properties: + md5: + example: f3b59bed9f91e32fac1210184fcff6f5 + maxLength: 32 + minLength: 32 + pattern: ^[0-9a-fA-F]{32}$ + type: string + sha256: + example: 78be890d71dde316c412da2ce8332ba47b9ce7a29d573801d2777e01aa20b9b5 + maxLength: 64 + minLength: 64 + pattern: ^[0-9a-fA-F]{64}$ + type: string + type: object + url: description: |- - reason contains a programmatic identifier indicating the reason for the condition's last transition. - Producers of specific condition types may define expected values and meanings for this field, - and whether the values are considered a guaranteed API. - The value should be a CamelCase string. - This field may not be empty. - maxLength: 1024 - minLength: 1 - pattern: ^[A-Za-z]([A-Za-z0-9_,:]*[A-Za-z0-9_])?$ + URL of the file for creating an image. The following file formats are supported: + * qcow2 + * vmdk + * vdi + * iso + * raw + The file can be compressed into an archive in one of the following formats: + * gz + * xz + example: https://mirror.example.com/images/slackware-15.qcow.gz + pattern: ^http[s]?:\/\/(?:[a-zA-Z]|[0-9]|[$-_@.&+]|[!*\(\),]|(?:%[0-9a-fA-F][0-9a-fA-F]))+$ type: string - status: - description: status of the condition, one of True, False, Unknown. + required: + - url + type: object + objectRef: + description: Use an existing VirtualImage, ClusterVirtualImage, + or VirtualDiskSnapshot resource to create a disk. + properties: + kind: + description: Kind of the existing VirtualImage, ClusterVirtualImage, + or VirtualDiskSnapshot resource. enum: - - "True" - - "False" - - Unknown + - ClusterVirtualImage + - VirtualImage + - VirtualDiskSnapshot type: string - type: - description: type of condition in CamelCase or in foo.example.com/CamelCase. - maxLength: 316 - pattern: ^([a-z0-9]([-a-z0-9]*[a-z0-9])?(\.[a-z0-9]([-a-z0-9]*[a-z0-9])?)*/)?(([A-Za-z0-9][-A-Za-z0-9_.]*)?[A-Za-z0-9])$ + name: + description: Name of the existing VirtualImage, ClusterVirtualImage, + or VirtualDiskSnapshot resource. type: string required: - - lastTransitionTime - - message - - reason - - status - - type + - kind + - name type: object - type: array - downloadSpeed: - description: - Image download speed from an external source. Appears - only during the `Provisioning` phase. - properties: - avg: - description: Average download speed. - example: 1 Mbps - type: string - avgBytes: - description: Average download speed in bytes per second. - example: 1012345 - type: string - current: - description: Current download speed. - example: 5 Mbps - type: string - currentBytes: - description: Current download speed in bytes per second. - example: 5123456 - type: string - type: object - imageUploadURLs: + type: + description: |- + The following image sources are available for creating an image: + + * `HTTP`: From a file published on an HTTP/HTTPS service at a given URL. + * `ContainerImage`: From another image stored in a container registry. + * `ObjectRef`: From an existing resource. + * `Upload`: From data uploaded by the user via a special interface. + enum: + - HTTP + - ContainerImage + - ObjectRef + - Upload + type: string + type: object + x-kubernetes-validations: + - message: HTTP requires http and cannot have ContainerImage or ObjectRef. + rule: 'self.type == ''HTTP'' ? has(self.http) && !has(self.containerImage) + && !has(self.objectRef) : true' + - message: ContainerImage requires containerImage and cannot have + HTTP or ObjectRef. + rule: 'self.type == ''ContainerImage'' ? has(self.containerImage) + && !has(self.http) && !has(self.objectRef) : true' + - message: ObjectRef requires objectRef and cannot have HTTP or ContainerImage. + rule: 'self.type == ''ObjectRef'' ? has(self.objectRef) && !has(self.http) + && !has(self.containerImage) : true' + persistentVolumeClaim: + description: Settings for creating PVCs to store the disk. + properties: + size: + anyOf: + - type: integer + - type: string + description: |- + Desired size for PVC to store the disk. If the disk is created from an image, the size must be at least as large as the original unpacked image. + + This parameter can be omitted if the `.spec.dataSource` section is filled out. In this case, the controller will determine the disk size automatically, based on the size of the extracted image from the source specified in `.spec.dataSource`. + pattern: ^(\+|-)?(([0-9]+(\.[0-9]*)?)|(\.[0-9]+))(([KMGTPE]i)|[numkMGTPE]|([eE](\+|-)?(([0-9]+(\.[0-9]*)?)|(\.[0-9]+))))?$ + x-kubernetes-int-or-string: true + storageClassName: + description: |- + StorageClass name required by the claim. For details on using StorageClass for PVC, refer to https://kubernetes.io/docs/concepts/storage/persistent-volumes#class-1. + + When creating disks, the user can specify the required StorageClass. If not specified, the default StorageClass will be used. + + The disk features and virtual machine behavior depend on the selected StorageClass. + + The `VolumeBindingMode` parameter in the StorageClass affects the disk creation process. The following values are allowed: + - `Immediate`: The disk will be created and becomes available for use immediately after creation. + - `WaitForFirstConsumer`: The disk will be created when first used on the node where the virtual machine will be started. + + StorageClass supports multiple storage settings: + - Creating a block device (`Block`) or file system (`FileSystem`). + - Multiple access (`ReadWriteMany`) or single access (`ReadWriteOnce`). The `ReadWriteMany` disks support multiple access, which enables a "live" migration of virtual machines. In contrast, the `ReadWriteOnce` disks, which can be accessed from only one node, don't have this feature. + + For known storage types, Deckhouse automatically determines the most efficient settings when creating disks (by priority, in descending order): + 1. `Block` + `ReadWriteMany` + 2. `FileSystem` + `ReadWriteMany` + 3. `Block` + `ReadWriteOnce` + 4. `FileSystem` + `ReadWriteOnce` + type: string + type: object + type: object + status: + properties: + attachedToVirtualMachines: + description: List of VirtualMachines that use the disk. + example: + - name: VM100 + items: + description: List of VirtualMachines that use the disk. properties: - external: - description: - Command to upload the image using `Ingress` from - outside the cluster. - type: string - inCluster: - description: - Command to upload the image using `Service` within - the cluster. + mounted: + description: Flag indicating that VirtualDisk is currently being + used by this attached VirtualMachine. + type: boolean + name: + description: Name of attached VirtualMachine. type: string type: object - migrationState: - description: Migration information. + type: array + capacity: + description: Requested PVC capacity in human-readable format. + example: 50G + type: string + conditions: + description: The latest available observations of an object's current + state. + items: + description: Condition contains details for one aspect of the current + state of this API Resource. properties: - endTimestamp: + lastTransitionTime: + description: |- + lastTransitionTime is the last time the condition transitioned from one status to another. + This should be when the underlying condition changed. If that is not known, then using the time when the API field changed is acceptable. format: date-time type: string message: + description: |- + message is a human readable message indicating details about the transition. + This may be an empty string. + maxLength: 32768 type: string - result: - description: - VirtualDiskMigrationResult is the result of the VirtualDisk - migration. - enum: - - Succeeded - - Failed - type: string - sourcePVC: - description: Source PersistentVolumeClaim name. + observedGeneration: + description: |- + observedGeneration represents the .metadata.generation that the condition was set based upon. + For instance, if .metadata.generation is currently 12, but the .status.conditions[x].observedGeneration is 9, the condition is out of date + with respect to the current state of the instance. + format: int64 + minimum: 0 + type: integer + reason: + description: |- + reason contains a programmatic identifier indicating the reason for the condition's last transition. + Producers of specific condition types may define expected values and meanings for this field, + and whether the values are considered a guaranteed API. + The value should be a CamelCase string. + This field may not be empty. + maxLength: 1024 + minLength: 1 + pattern: ^[A-Za-z]([A-Za-z0-9_,:]*[A-Za-z0-9_])?$ type: string - startTimestamp: - format: date-time + status: + description: status of the condition, one of True, False, Unknown. + enum: + - "True" + - "False" + - Unknown type: string - targetPVC: - description: Target PersistentVolumeClaim name. + type: + description: type of condition in CamelCase or in foo.example.com/CamelCase. + maxLength: 316 + pattern: ^([a-z0-9]([-a-z0-9]*[a-z0-9])?(\.[a-z0-9]([-a-z0-9]*[a-z0-9])?)*/)?(([A-Za-z0-9][-A-Za-z0-9_.]*)?[A-Za-z0-9])$ type: string + required: + - lastTransitionTime + - message + - reason + - status + - type type: object - observedGeneration: - description: Resource generation last processed by the controller. - format: int64 - type: integer - phase: - description: |- - Current status of the VirtualDisk resource: - * `Pending`: The resource has been created and is on a waiting queue. - * `Provisioning`: The resource is being created: copying, downloading, loading data to the PVC, or extending the PVC. - * `WaitForUserUpload`: Waiting for the user to upload the image. The endpoint to upload the image is specified in `.status.uploadCommand`. - * `WaitForFirstConsumer`: Waiting for the virtual machine using the disk to be assigned to the node. - * `Ready`: The resource has been created and is ready to use. - * `Resizing`: The process of resource resizing is in progress. - * `Failed`: There was an error when creating the resource. - * `PVCLost`: The child PVC of the resource is missing. The resource cannot be used. - * `Exporting`: The child PV of the resource is in the process of exporting. - * `Terminating`: The resource is being deleted. - * `Migrating`: The resource is being migrating. - enum: - - Pending - - Provisioning - - WaitForUserUpload - - WaitForFirstConsumer - - Ready - - Resizing + type: array + downloadSpeed: + description: Image download speed from an external source. Appears + only during the `Provisioning` phase. + properties: + avg: + description: Average download speed. + example: 1 Mbps + type: string + avgBytes: + description: Average download speed in bytes per second. + example: 1012345 + type: string + current: + description: Current download speed. + example: 5 Mbps + type: string + currentBytes: + description: Current download speed in bytes per second. + example: 5123456 + type: string + type: object + imageUploadURLs: + properties: + external: + description: Command to upload the image using `Ingress` from + outside the cluster. + type: string + inCluster: + description: Command to upload the image using `Service` within + the cluster. + type: string + type: object + migrationState: + description: Migration information. + properties: + endTimestamp: + format: date-time + type: string + message: + type: string + result: + description: VirtualDiskMigrationResult is the result of the VirtualDisk + migration. + enum: + - Succeeded - Failed - - PVCLost - - Exporting - - Terminating - - Migrating - type: string - progress: - description: - Progress of copying an image from a source to PVC. Appears - only during the `Provisioning' phase. - type: string - sourceUID: - description: |- - UID is a type that holds unique ID values, including UUIDs. Because we - don't ONLY use UUIDs, this is an alias to string. Being a type captures - intent and helps make sure that UIDs and names do not get conflated. - type: string - stats: - description: VirtualDisk statistics. - properties: - creationDuration: - description: Waiting time for the virtual disk creation. - properties: - dvcrProvisioning: - description: Duration of the loading into DVCR. - nullable: true - type: string - totalProvisioning: - description: - Duration of the resource creation from the moment - dependencies are ready until the resource transitions to - the Ready state. - nullable: true - type: string - waitingForDependencies: - description: Waiting time for dependent resources. - nullable: true - type: string - type: object - type: object - storageClassName: - description: - Name of the StorageClass used by the PersistentVolumeClaim - if `Kubernetes` storage type is used. - type: string - target: - properties: - persistentVolumeClaimName: - description: - Created PersistentVolumeClaim name for the Kubernetes - storage. - type: string - type: object - uploadCommand: - description: Deprecated. Use `ImageUploadURLs` instead. - type: string - type: object - required: - - spec - type: object - served: true - storage: true - subresources: - status: {} + type: string + sourcePVC: + description: Source PersistentVolumeClaim name. + type: string + startTimestamp: + format: date-time + type: string + targetPVC: + description: Target PersistentVolumeClaim name. + type: string + type: object + observedGeneration: + description: Resource generation last processed by the controller. + format: int64 + type: integer + phase: + description: |- + Current status of the VirtualDisk resource: + * `Pending`: The resource has been created and is on a waiting queue. + * `Provisioning`: The resource is being created: copying, downloading, loading data to the PVC, or extending the PVC. + * `WaitForUserUpload`: Waiting for the user to upload the image. The endpoint to upload the image is specified in `.status.uploadCommand`. + * `WaitForFirstConsumer`: Waiting for the virtual machine using the disk to be assigned to the node. + * `Ready`: The resource has been created and is ready to use. + * `Resizing`: The process of resource resizing is in progress. + * `Failed`: There was an error when creating the resource. + * `PVCLost`: The child PVC of the resource is missing. The resource cannot be used. + * `Exporting`: The child PV of the resource is in the process of exporting. + * `Terminating`: The resource is being deleted. + * `Migrating`: The resource is being migrating. + enum: + - Pending + - Provisioning + - WaitForUserUpload + - WaitForFirstConsumer + - Ready + - Resizing + - Failed + - PVCLost + - Exporting + - Terminating + - Migrating + type: string + progress: + description: Progress of copying an image from a source to PVC. Appears + only during the `Provisioning' phase. + type: string + sourceUID: + description: |- + UID is a type that holds unique ID values, including UUIDs. Because we + don't ONLY use UUIDs, this is an alias to string. Being a type captures + intent and helps make sure that UIDs and names do not get conflated. + type: string + stats: + description: VirtualDisk statistics. + properties: + creationDuration: + description: Waiting time for the virtual disk creation. + properties: + dvcrProvisioning: + description: Duration of the loading into DVCR. + nullable: true + type: string + totalProvisioning: + description: Duration of the resource creation from the moment + dependencies are ready until the resource transitions to + the Ready state. + nullable: true + type: string + waitingForDependencies: + description: Waiting time for dependent resources. + nullable: true + type: string + type: object + type: object + storageClassName: + description: Name of the StorageClass used by the PersistentVolumeClaim + if `Kubernetes` storage type is used. + type: string + target: + properties: + persistentVolumeClaimName: + description: Created PersistentVolumeClaim name for the Kubernetes + storage. + type: string + type: object + uploadCommand: + description: Deprecated. Use `ImageUploadURLs` instead. + type: string + type: object + required: + - spec + type: object + served: true + storage: true + subresources: + status: {} diff --git a/crds/virtualimages.yaml b/crds/virtualimages.yaml index 700a9418b2..9bd63745a7 100644 --- a/crds/virtualimages.yaml +++ b/crds/virtualimages.yaml @@ -12,420 +12,399 @@ spec: group: virtualization.deckhouse.io names: categories: - - virtualization + - virtualization kind: VirtualImage listKind: VirtualImageList plural: virtualimages shortNames: - - vi + - vi singular: virtualimage scope: Namespaced versions: - - additionalPrinterColumns: - - jsonPath: .status.phase - name: Phase - type: string - - jsonPath: .status.cdrom - name: CDROM - type: boolean - - jsonPath: .status.progress - name: Progress - type: string - - jsonPath: .status.size.stored - name: StoredSize - priority: 1 - type: string - - jsonPath: .status.size.unpacked - name: UnpackedSize - priority: 1 - type: string - - jsonPath: .status.target.registryURL - name: Registry URL - priority: 1 - type: string - - jsonPath: .status.target.persistentVolumeClaimName - name: TargetPVC - priority: 1 - type: string - - jsonPath: .metadata.creationTimestamp - name: Age - type: date - name: v1alpha2 - schema: - openAPIV3Schema: - description: |- - This resource describes a virtual disk image to use as a data source for new VirtualDisk resources or an installation image (iso) that can be mounted into the VirtualMachine resource. + - additionalPrinterColumns: + - jsonPath: .status.phase + name: Phase + type: string + - jsonPath: .status.cdrom + name: CDROM + type: boolean + - jsonPath: .status.progress + name: Progress + type: string + - jsonPath: .status.size.stored + name: StoredSize + priority: 1 + type: string + - jsonPath: .status.size.unpacked + name: UnpackedSize + priority: 1 + type: string + - jsonPath: .status.target.registryURL + name: Registry URL + priority: 1 + type: string + - jsonPath: .status.target.persistentVolumeClaimName + name: TargetPVC + priority: 1 + type: string + - jsonPath: .metadata.creationTimestamp + name: Age + type: date + name: v1alpha2 + schema: + openAPIV3Schema: + description: |- + This resource describes a virtual disk image to use as a data source for new VirtualDisk resources or an installation image (iso) that can be mounted into the VirtualMachine resource. - > This resource cannot be modified once it has been created. + > This resource cannot be modified once it has been created. - With this resource in the cluster, a container image is created and stored in a dedicated Deckhouse Virtualization Container Registry (DVCR) or PVC, with the data filled in from the source. - properties: - apiVersion: - description: |- - APIVersion defines the versioned schema of this representation of an object. - Servers should convert recognized schemas to the latest internal value, and - may reject unrecognized values. - More info: https://git.k8s.io/community/contributors/devel/sig-architecture/api-conventions.md#resources - type: string - kind: - description: |- - Kind is a string value representing the REST resource this object represents. - Servers may infer this from the endpoint the client submits requests to. - Cannot be updated. - In CamelCase. - More info: https://git.k8s.io/community/contributors/devel/sig-architecture/api-conventions.md#types-kinds - type: string - metadata: - type: object - spec: - properties: - dataSource: - properties: - containerImage: - description: - Use an image stored in an external container registry. - Only registries with enabled TLS protocol are supported. To - provide a custom Certificate Authority (CA) chain, use the `caBundle` - field. - properties: - caBundle: - description: - CA chain in Base64 format to verify the container - registry. - example: YWFhCg== - format: byte - type: string - image: - description: Path to the image in the container registry. - example: registry.example.com/images/slackware:15 - pattern: ^(?P(?:(?P(?:(?:localhost|[\w-]+(?:\.[\w-]+)+)(?::\d+)?)|[\w]+:\d+)/)?(?P[a-z0-9_.-]+(?:/[a-z0-9_.-]+)*))(?::(?P[\w][\w.-]{0,127}))?(?:@(?P[A-Za-z][A-Za-z0-9]*(?:[+.-_][A-Za-z][A-Za-z0-9]*)*:[0-9a-fA-F]{32,}))?$ - type: string - imagePullSecret: - properties: - name: - description: - Name of the secret keeping container registry - credentials, which must be located in the same namespace. - type: string - type: object - required: - - image - type: object - http: - description: |- - Fill the image with data from an external URL. The following schemas are supported: - - * HTTP - * HTTPS - - For HTTPS schema, there is an option to skip the TLS verification. - properties: - caBundle: - description: CA chain in Base64 format to verify the URL. - example: YWFhCg== - format: byte - type: string - checksum: - description: - Checksum to verify integrity and consistency - of the downloaded file. The file must match all specified - checksums. - properties: - md5: - example: f3b59bed9f91e32fac1210184fcff6f5 - maxLength: 32 - minLength: 32 - pattern: ^[0-9a-fA-F]{32}$ - type: string - sha256: - example: 78be890d71dde316c412da2ce8332ba47b9ce7a29d573801d2777e01aa20b9b5 - maxLength: 64 - minLength: 64 - pattern: ^[0-9a-fA-F]{64}$ - type: string - type: object - url: - description: |- - URL of the file for creating an image. The following file formats are supported: - * qcow2 - * vmdk - * vdi - * iso - * raw - The file can be compressed into an archive in one of the following formats: - * gz - * xz - example: https://mirror.example.com/images/slackware-15.qcow.gz - pattern: ^http[s]?:\/\/(?:[a-zA-Z]|[0-9]|[$-_@.&+]|[!*\(\),]|(?:%[0-9a-fA-F][0-9a-fA-F]))+$ - type: string - required: - - url - type: object - objectRef: - description: - Use an existing VirtualImage, ClusterVirtualImage, - VirtualDisk or VirtualDiskSnapshot resource to create an image. - properties: - kind: - description: - Kind of an existing VirtualImage, ClusterVirtualImage, - VirtualDisk or VirtualDiskSnapshot resource. - enum: - - ClusterVirtualImage - - VirtualImage - - VirtualDisk - - VirtualDiskSnapshot - type: string - name: - description: - Name of an existing VirtualImage, ClusterVirtualImage, - VirtualDisk or VirtualDiskSnapshot resource. - type: string - required: - - kind - - name - type: object - type: - description: |- - The following image sources are available for creating an image: - - * `HTTP`: From a file published on an HTTP/HTTPS service at a given URL. - * `ContainerImage`: From another image stored in a container registry. - * `ObjectRef`: From an existing resource. - * `Upload`: From data uploaded by the user via a special interface. - enum: - - HTTP - - ContainerImage - - ObjectRef - - Upload - type: string - type: object - x-kubernetes-validations: - - message: HTTP requires http and cannot have ContainerImage or ObjectRef. - rule: - "self.type == 'HTTP' ? has(self.http) && !has(self.containerImage) - && !has(self.objectRef) : true" - - message: - ContainerImage requires containerImage and cannot have - HTTP or ObjectRef. - rule: - "self.type == 'ContainerImage' ? has(self.containerImage) - && !has(self.http) && !has(self.objectRef) : true" - - message: ObjectRef requires objectRef and cannot have HTTP or ContainerImage. - rule: - "self.type == 'ObjectRef' ? has(self.objectRef) && !has(self.http) - && !has(self.containerImage) : true" - persistentVolumeClaim: - description: - Settings for creating PVCs to store an image with the - storage type `PersistentVolumeClaim`. - properties: - storageClassName: - description: |- - Name of the StorageClass required by the claim. For details on using StorageClass for PVC, refer to — https://kubernetes.io/docs/concepts/storage/persistent-volumes#class-1. + With this resource in the cluster, a container image is created and stored in a dedicated Deckhouse Virtualization Container Registry (DVCR) or PVC, with the data filled in from the source. + properties: + apiVersion: + description: |- + APIVersion defines the versioned schema of this representation of an object. + Servers should convert recognized schemas to the latest internal value, and + may reject unrecognized values. + More info: https://git.k8s.io/community/contributors/devel/sig-architecture/api-conventions.md#resources + type: string + kind: + description: |- + Kind is a string value representing the REST resource this object represents. + Servers may infer this from the endpoint the client submits requests to. + Cannot be updated. + In CamelCase. + More info: https://git.k8s.io/community/contributors/devel/sig-architecture/api-conventions.md#types-kinds + type: string + metadata: + type: object + spec: + properties: + dataSource: + properties: + containerImage: + description: Use an image stored in an external container registry. + Only registries with enabled TLS protocol are supported. To + provide a custom Certificate Authority (CA) chain, use the `caBundle` + field. + properties: + caBundle: + description: CA chain in Base64 format to verify the container + registry. + example: YWFhCg== + format: byte + type: string + image: + description: Path to the image in the container registry. + example: registry.example.com/images/slackware:15 + pattern: ^(?P(?:(?P(?:(?:localhost|[\w-]+(?:\.[\w-]+)+)(?::\d+)?)|[\w]+:\d+)/)?(?P[a-z0-9_.-]+(?:/[a-z0-9_.-]+)*))(?::(?P[\w][\w.-]{0,127}))?(?:@(?P[A-Za-z][A-Za-z0-9]*(?:[+.-_][A-Za-z][A-Za-z0-9]*)*:[0-9a-fA-F]{32,}))?$ + type: string + imagePullSecret: + properties: + name: + description: Name of the secret keeping container registry + credentials, which must be located in the same namespace. + type: string + type: object + required: + - image + type: object + http: + description: |- + Fill the image with data from an external URL. The following schemas are supported: - When creating an image with the `PersistentVolumeClaim` storage type, the user can specify the required StorageClass. If not specified, the default StorageClass will be used. - type: string - type: object - storage: - default: ContainerRegistry - description: |- - Storage type to keep the image for the current virtualization setup. + * HTTP + * HTTPS - * `ContainerRegistry`: Use the DVCR container registry. In this case, images are downloaded to a container and then to DVCR (shipped with the virtualization module). - * `PersistentVolumeClaim`: Use a PVC. - * `Kubernetes`: A deprecated storage type. Not recommended for use and may be removed in future versions. Use `PersistentVolumeClaim` instead. - enum: - - ContainerRegistry - - Kubernetes - - PersistentVolumeClaim - type: string - required: - - dataSource - - storage - type: object - status: - properties: - cdrom: - description: - Whether the image is in a format that needs to be mounted - as a CD-ROM drive, such as iso and so on. - type: boolean - conditions: - description: - The latest available observations of an object's current - state. - items: - description: - Condition contains details for one aspect of the current - state of this API Resource. + For HTTPS schema, there is an option to skip the TLS verification. properties: - lastTransitionTime: - description: |- - lastTransitionTime is the last time the condition transitioned from one status to another. - This should be when the underlying condition changed. If that is not known, then using the time when the API field changed is acceptable. - format: date-time - type: string - message: - description: |- - message is a human readable message indicating details about the transition. - This may be an empty string. - maxLength: 32768 + caBundle: + description: CA chain in Base64 format to verify the URL. + example: YWFhCg== + format: byte type: string - observedGeneration: - description: |- - observedGeneration represents the .metadata.generation that the condition was set based upon. - For instance, if .metadata.generation is currently 12, but the .status.conditions[x].observedGeneration is 9, the condition is out of date - with respect to the current state of the instance. - format: int64 - minimum: 0 - type: integer - reason: + checksum: + description: Checksum to verify integrity and consistency + of the downloaded file. The file must match all specified + checksums. + properties: + md5: + example: f3b59bed9f91e32fac1210184fcff6f5 + maxLength: 32 + minLength: 32 + pattern: ^[0-9a-fA-F]{32}$ + type: string + sha256: + example: 78be890d71dde316c412da2ce8332ba47b9ce7a29d573801d2777e01aa20b9b5 + maxLength: 64 + minLength: 64 + pattern: ^[0-9a-fA-F]{64}$ + type: string + type: object + url: description: |- - reason contains a programmatic identifier indicating the reason for the condition's last transition. - Producers of specific condition types may define expected values and meanings for this field, - and whether the values are considered a guaranteed API. - The value should be a CamelCase string. - This field may not be empty. - maxLength: 1024 - minLength: 1 - pattern: ^[A-Za-z]([A-Za-z0-9_,:]*[A-Za-z0-9_])?$ + URL of the file for creating an image. The following file formats are supported: + * qcow2 + * vmdk + * vdi + * iso + * raw + The file can be compressed into an archive in one of the following formats: + * gz + * xz + example: https://mirror.example.com/images/slackware-15.qcow.gz + pattern: ^http[s]?:\/\/(?:[a-zA-Z]|[0-9]|[$-_@.&+]|[!*\(\),]|(?:%[0-9a-fA-F][0-9a-fA-F]))+$ type: string - status: - description: status of the condition, one of True, False, Unknown. + required: + - url + type: object + objectRef: + description: Use an existing VirtualImage, ClusterVirtualImage, + VirtualDisk or VirtualDiskSnapshot resource to create an image. + properties: + kind: + description: Kind of an existing VirtualImage, ClusterVirtualImage, + VirtualDisk or VirtualDiskSnapshot resource. enum: - - "True" - - "False" - - Unknown + - ClusterVirtualImage + - VirtualImage + - VirtualDisk + - VirtualDiskSnapshot type: string - type: - description: type of condition in CamelCase or in foo.example.com/CamelCase. - maxLength: 316 - pattern: ^([a-z0-9]([-a-z0-9]*[a-z0-9])?(\.[a-z0-9]([-a-z0-9]*[a-z0-9])?)*/)?(([A-Za-z0-9][-A-Za-z0-9_.]*)?[A-Za-z0-9])$ + name: + description: Name of an existing VirtualImage, ClusterVirtualImage, + VirtualDisk or VirtualDiskSnapshot resource. type: string required: - - lastTransitionTime - - message - - reason - - status - - type + - kind + - name type: object - type: array - downloadSpeed: - description: - Image download speed from an external source. Appears - only during the `Provisioning` phase. - properties: - avg: - description: Average download speed. - example: 1 Mbps - type: string - avgBytes: - description: Average download speed in bytes per second. - example: 1012345 - type: string - current: - description: Current download speed. - example: 5 Mbps - type: string - currentBytes: - description: Current download speed in bytes per second. - example: 5123456 - type: string - type: object - format: - description: Discovered image format. - type: string - imageUploadURLs: - properties: - external: - description: - Command to upload the image using `Ingress` from - outside the cluster. - type: string - inCluster: - description: - Command to upload the image using `Service` within - the cluster. - type: string - type: object - observedGeneration: - description: Resource generation last processed by the controller. - format: int64 - type: integer - phase: - description: |- - Current status of the ClusterVirtualImage resource: - * `Pending`: The resource has been created and is on a waiting queue. - * `Provisioning`: The resource is being created: copying, downloading, or building the image. - * `WaitForUserUpload`: Waiting for the user to upload the image. The endpoint to upload the image is specified in `.status.uploadCommand`. - * `Ready`: The resource has been created and is ready to use. - * `Failed`: There was an error when creating the resource. - * `Terminating`: The resource is being deleted. - * `PVCLost`: The child PVC of the resource is missing. The resource cannot be used. - enum: - - Pending - - Provisioning - - WaitForUserUpload - - Ready - - Failed - - Terminating - - PVCLost - type: string - progress: - description: Progress of copying an image from a source to DVCR. - type: string - size: - description: Discovered image size data. + type: + description: |- + The following image sources are available for creating an image: + + * `HTTP`: From a file published on an HTTP/HTTPS service at a given URL. + * `ContainerImage`: From another image stored in a container registry. + * `ObjectRef`: From an existing resource. + * `Upload`: From data uploaded by the user via a special interface. + enum: + - HTTP + - ContainerImage + - ObjectRef + - Upload + type: string + type: object + x-kubernetes-validations: + - message: HTTP requires http and cannot have ContainerImage or ObjectRef. + rule: 'self.type == ''HTTP'' ? has(self.http) && !has(self.containerImage) + && !has(self.objectRef) : true' + - message: ContainerImage requires containerImage and cannot have + HTTP or ObjectRef. + rule: 'self.type == ''ContainerImage'' ? has(self.containerImage) + && !has(self.http) && !has(self.objectRef) : true' + - message: ObjectRef requires objectRef and cannot have HTTP or ContainerImage. + rule: 'self.type == ''ObjectRef'' ? has(self.objectRef) && !has(self.http) + && !has(self.containerImage) : true' + persistentVolumeClaim: + description: Settings for creating PVCs to store an image with the + storage type `PersistentVolumeClaim`. + properties: + storageClassName: + description: |- + Name of the StorageClass required by the claim. For details on using StorageClass for PVC, refer to — https://kubernetes.io/docs/concepts/storage/persistent-volumes#class-1. + + When creating an image with the `PersistentVolumeClaim` storage type, the user can specify the required StorageClass. If not specified, the default StorageClass will be used. + type: string + type: object + storage: + default: ContainerRegistry + description: |- + Storage type to keep the image for the current virtualization setup. + + * `ContainerRegistry`: Use the DVCR container registry. In this case, images are downloaded to a container and then to DVCR (shipped with the virtualization module). + * `PersistentVolumeClaim`: Use a PVC. + * `Kubernetes`: A deprecated storage type. Not recommended for use and may be removed in future versions. Use `PersistentVolumeClaim` instead. + enum: + - ContainerRegistry + - Kubernetes + - PersistentVolumeClaim + type: string + required: + - dataSource + - storage + type: object + status: + properties: + cdrom: + description: Whether the image is in a format that needs to be mounted + as a CD-ROM drive, such as iso and so on. + type: boolean + conditions: + description: The latest available observations of an object's current + state. + items: + description: Condition contains details for one aspect of the current + state of this API Resource. properties: - stored: - description: Image size in human-readable format. - example: 199M - type: string - storedBytes: - description: Image size in bytes. - example: 199001234 + lastTransitionTime: + description: |- + lastTransitionTime is the last time the condition transitioned from one status to another. + This should be when the underlying condition changed. If that is not known, then using the time when the API field changed is acceptable. + format: date-time type: string - unpacked: - description: Unpacked image size in human-readable format. - example: 1G + message: + description: |- + message is a human readable message indicating details about the transition. + This may be an empty string. + maxLength: 32768 type: string - unpackedBytes: - description: Unpacked image size in bytes. - example: 1000000234 + observedGeneration: + description: |- + observedGeneration represents the .metadata.generation that the condition was set based upon. + For instance, if .metadata.generation is currently 12, but the .status.conditions[x].observedGeneration is 9, the condition is out of date + with respect to the current state of the instance. + format: int64 + minimum: 0 + type: integer + reason: + description: |- + reason contains a programmatic identifier indicating the reason for the condition's last transition. + Producers of specific condition types may define expected values and meanings for this field, + and whether the values are considered a guaranteed API. + The value should be a CamelCase string. + This field may not be empty. + maxLength: 1024 + minLength: 1 + pattern: ^[A-Za-z]([A-Za-z0-9_,:]*[A-Za-z0-9_])?$ type: string - type: object - sourceUID: - description: - UID of the source (VirtualImage, ClusterVirtualImage, - VirtualDisk or VirtualDiskSnapshot) used when creating the virtual - image. - type: string - storageClassName: - description: - Name of the StorageClass used by the PersistentVolumeClaim - if `Kubernetes` storage type is used. - type: string - target: - properties: - persistentVolumeClaimName: - description: - Created PersistentVolumeClaim name for the PersistentVolumeClaim - storage. + status: + description: status of the condition, one of True, False, Unknown. + enum: + - "True" + - "False" + - Unknown type: string - registryURL: - description: Created image in DVCR. - example: dvcr..svc/vi//:latest + type: + description: type of condition in CamelCase or in foo.example.com/CamelCase. + maxLength: 316 + pattern: ^([a-z0-9]([-a-z0-9]*[a-z0-9])?(\.[a-z0-9]([-a-z0-9]*[a-z0-9])?)*/)?(([A-Za-z0-9][-A-Za-z0-9_.]*)?[A-Za-z0-9])$ type: string + required: + - lastTransitionTime + - message + - reason + - status + - type type: object - uploadCommand: - description: Deprecated. Use `imageUploadURLs` instead. - type: string - type: object - required: - - spec - type: object - served: true - storage: true - subresources: - status: {} + type: array + downloadSpeed: + description: Image download speed from an external source. Appears + only during the `Provisioning` phase. + properties: + avg: + description: Average download speed. + example: 1 Mbps + type: string + avgBytes: + description: Average download speed in bytes per second. + example: 1012345 + type: string + current: + description: Current download speed. + example: 5 Mbps + type: string + currentBytes: + description: Current download speed in bytes per second. + example: 5123456 + type: string + type: object + format: + description: Discovered image format. + type: string + imageUploadURLs: + properties: + external: + description: Command to upload the image using `Ingress` from + outside the cluster. + type: string + inCluster: + description: Command to upload the image using `Service` within + the cluster. + type: string + type: object + observedGeneration: + description: Resource generation last processed by the controller. + format: int64 + type: integer + phase: + description: |- + Current status of the ClusterVirtualImage resource: + * `Pending`: The resource has been created and is on a waiting queue. + * `Provisioning`: The resource is being created: copying, downloading, or building the image. + * `WaitForUserUpload`: Waiting for the user to upload the image. The endpoint to upload the image is specified in `.status.uploadCommand`. + * `Ready`: The resource has been created and is ready to use. + * `Failed`: There was an error when creating the resource. + * `Terminating`: The resource is being deleted. + * `PVCLost`: The child PVC of the resource is missing. The resource cannot be used. + enum: + - Pending + - Provisioning + - WaitForUserUpload + - Ready + - Failed + - Terminating + - PVCLost + type: string + progress: + description: Progress of copying an image from a source to DVCR. + type: string + size: + description: Discovered image size data. + properties: + stored: + description: Image size in human-readable format. + example: 199M + type: string + storedBytes: + description: Image size in bytes. + example: 199001234 + type: string + unpacked: + description: Unpacked image size in human-readable format. + example: 1G + type: string + unpackedBytes: + description: Unpacked image size in bytes. + example: 1000000234 + type: string + type: object + sourceUID: + description: UID of the source (VirtualImage, ClusterVirtualImage, + VirtualDisk or VirtualDiskSnapshot) used when creating the virtual + image. + type: string + storageClassName: + description: Name of the StorageClass used by the PersistentVolumeClaim + if `Kubernetes` storage type is used. + type: string + target: + properties: + persistentVolumeClaimName: + description: Created PersistentVolumeClaim name for the PersistentVolumeClaim + storage. + type: string + registryURL: + description: Created image in DVCR. + example: dvcr..svc/vi//:latest + type: string + type: object + uploadCommand: + description: Deprecated. Use `imageUploadURLs` instead. + type: string + type: object + required: + - spec + type: object + served: true + storage: true + subresources: + status: {} diff --git a/crds/virtualmachineblockdeviceattachments.yaml b/crds/virtualmachineblockdeviceattachments.yaml index 939fc91607..6c8130e0e6 100644 --- a/crds/virtualmachineblockdeviceattachments.yaml +++ b/crds/virtualmachineblockdeviceattachments.yaml @@ -12,180 +12,176 @@ spec: group: virtualization.deckhouse.io names: categories: - - virtualization + - virtualization kind: VirtualMachineBlockDeviceAttachment listKind: VirtualMachineBlockDeviceAttachmentList plural: virtualmachineblockdeviceattachments shortNames: - - vmbda + - vmbda singular: virtualmachineblockdeviceattachment scope: Namespaced versions: - - additionalPrinterColumns: - - description: VirtualMachineBlockDeviceAttachment phase. - jsonPath: .status.phase - name: PHASE - type: string - - description: Attached blockdevice kind. - jsonPath: .spec.blockDeviceRef.kind - name: BLOCKDEVICE KIND - priority: 1 - type: string - - description: Attached blockdevice name. - jsonPath: .spec.blockDeviceRef.name - name: BLOCKDEVICE NAME - priority: 1 - type: string - - description: Name of the virtual machine the disk is attached to. - jsonPath: .status.virtualMachineName - name: VIRTUAL MACHINE NAME - type: string - - description: Time of resource creation. - jsonPath: .metadata.creationTimestamp - name: AGE - type: date - name: v1alpha2 - schema: - openAPIV3Schema: - description: - VirtualMachineBlockDeviceAttachment provides a hot plug for attaching - a disk to a virtual machine. - properties: - apiVersion: - description: |- - APIVersion defines the versioned schema of this representation of an object. - Servers should convert recognized schemas to the latest internal value, and - may reject unrecognized values. - More info: https://git.k8s.io/community/contributors/devel/sig-architecture/api-conventions.md#resources - type: string - kind: - description: |- - Kind is a string value representing the REST resource this object represents. - Servers may infer this from the endpoint the client submits requests to. - Cannot be updated. - In CamelCase. - More info: https://git.k8s.io/community/contributors/devel/sig-architecture/api-conventions.md#types-kinds - type: string - metadata: - type: object - spec: - properties: - blockDeviceRef: - description: - Block device that will be connected to the VM as a hot-plug - disk. + - additionalPrinterColumns: + - description: VirtualMachineBlockDeviceAttachment phase. + jsonPath: .status.phase + name: PHASE + type: string + - description: Attached blockdevice kind. + jsonPath: .spec.blockDeviceRef.kind + name: BLOCKDEVICE KIND + priority: 1 + type: string + - description: Attached blockdevice name. + jsonPath: .spec.blockDeviceRef.name + name: BLOCKDEVICE NAME + priority: 1 + type: string + - description: Name of the virtual machine the disk is attached to. + jsonPath: .status.virtualMachineName + name: VIRTUAL MACHINE NAME + type: string + - description: Time of resource creation. + jsonPath: .metadata.creationTimestamp + name: AGE + type: date + name: v1alpha2 + schema: + openAPIV3Schema: + description: VirtualMachineBlockDeviceAttachment provides a hot plug for attaching + a disk to a virtual machine. + properties: + apiVersion: + description: |- + APIVersion defines the versioned schema of this representation of an object. + Servers should convert recognized schemas to the latest internal value, and + may reject unrecognized values. + More info: https://git.k8s.io/community/contributors/devel/sig-architecture/api-conventions.md#resources + type: string + kind: + description: |- + Kind is a string value representing the REST resource this object represents. + Servers may infer this from the endpoint the client submits requests to. + Cannot be updated. + In CamelCase. + More info: https://git.k8s.io/community/contributors/devel/sig-architecture/api-conventions.md#types-kinds + type: string + metadata: + type: object + spec: + properties: + blockDeviceRef: + description: Block device that will be connected to the VM as a hot-plug + disk. + properties: + kind: + description: |- + Block device type. Available options: + * `VirtualDisk`: Use VirtualDisk as the disk. This type is always mounted in RW mode. + * `VirtualImage`: Use VirtualImage as the disk. This type is always mounted in RO mode. + * `ClusterVirtualImage`: Use ClusterVirtualImage as the disk. This type is always mounted in RO mode. + enum: + - VirtualDisk + - VirtualImage + - ClusterVirtualImage + type: string + name: + description: Name of the block device to attach. + type: string + type: object + virtualMachineName: + description: Virtual machine name the disk or image should be attached + to. + type: string + required: + - blockDeviceRef + - virtualMachineName + type: object + status: + properties: + conditions: + description: Contains details of the current API resource state. + items: + description: Condition contains details for one aspect of the current + state of this API Resource. properties: - kind: + lastTransitionTime: description: |- - Block device type. Available options: - * `VirtualDisk`: Use VirtualDisk as the disk. This type is always mounted in RW mode. - * `VirtualImage`: Use VirtualImage as the disk. This type is always mounted in RO mode. - * `ClusterVirtualImage`: Use ClusterVirtualImage as the disk. This type is always mounted in RO mode. + lastTransitionTime is the last time the condition transitioned from one status to another. + This should be when the underlying condition changed. If that is not known, then using the time when the API field changed is acceptable. + format: date-time + type: string + message: + description: |- + message is a human readable message indicating details about the transition. + This may be an empty string. + maxLength: 32768 + type: string + observedGeneration: + description: |- + observedGeneration represents the .metadata.generation that the condition was set based upon. + For instance, if .metadata.generation is currently 12, but the .status.conditions[x].observedGeneration is 9, the condition is out of date + with respect to the current state of the instance. + format: int64 + minimum: 0 + type: integer + reason: + description: |- + reason contains a programmatic identifier indicating the reason for the condition's last transition. + Producers of specific condition types may define expected values and meanings for this field, + and whether the values are considered a guaranteed API. + The value should be a CamelCase string. + This field may not be empty. + maxLength: 1024 + minLength: 1 + pattern: ^[A-Za-z]([A-Za-z0-9_,:]*[A-Za-z0-9_])?$ + type: string + status: + description: status of the condition, one of True, False, Unknown. enum: - - VirtualDisk - - VirtualImage - - ClusterVirtualImage + - "True" + - "False" + - Unknown type: string - name: - description: Name of the block device to attach. + type: + description: type of condition in CamelCase or in foo.example.com/CamelCase. + maxLength: 316 + pattern: ^([a-z0-9]([-a-z0-9]*[a-z0-9])?(\.[a-z0-9]([-a-z0-9]*[a-z0-9])?)*/)?(([A-Za-z0-9][-A-Za-z0-9_.]*)?[A-Za-z0-9])$ type: string + required: + - lastTransitionTime + - message + - reason + - status + - type type: object - virtualMachineName: - description: - Virtual machine name the disk or image should be attached - to. - type: string - required: - - blockDeviceRef - - virtualMachineName - type: object - status: - properties: - conditions: - description: Contains details of the current API resource state. - items: - description: - Condition contains details for one aspect of the current - state of this API Resource. - properties: - lastTransitionTime: - description: |- - lastTransitionTime is the last time the condition transitioned from one status to another. - This should be when the underlying condition changed. If that is not known, then using the time when the API field changed is acceptable. - format: date-time - type: string - message: - description: |- - message is a human readable message indicating details about the transition. - This may be an empty string. - maxLength: 32768 - type: string - observedGeneration: - description: |- - observedGeneration represents the .metadata.generation that the condition was set based upon. - For instance, if .metadata.generation is currently 12, but the .status.conditions[x].observedGeneration is 9, the condition is out of date - with respect to the current state of the instance. - format: int64 - minimum: 0 - type: integer - reason: - description: |- - reason contains a programmatic identifier indicating the reason for the condition's last transition. - Producers of specific condition types may define expected values and meanings for this field, - and whether the values are considered a guaranteed API. - The value should be a CamelCase string. - This field may not be empty. - maxLength: 1024 - minLength: 1 - pattern: ^[A-Za-z]([A-Za-z0-9_,:]*[A-Za-z0-9_])?$ - type: string - status: - description: status of the condition, one of True, False, Unknown. - enum: - - "True" - - "False" - - Unknown - type: string - type: - description: type of condition in CamelCase or in foo.example.com/CamelCase. - maxLength: 316 - pattern: ^([a-z0-9]([-a-z0-9]*[a-z0-9])?(\.[a-z0-9]([-a-z0-9]*[a-z0-9])?)*/)?(([A-Za-z0-9][-A-Za-z0-9_.]*)?[A-Za-z0-9])$ - type: string - required: - - lastTransitionTime - - message - - reason - - status - - type - type: object - type: array - observedGeneration: - description: Resource generation last processed by the controller. - format: int64 - type: integer - phase: - description: |- - BlockDeviceAttachmentPhase defines the current status of the resource: - * `Pending`: The resource has been created and is on a waiting queue. - * `InProgress`: The disk is being attached to the VM. - * `Attached`: The disk has been attached to the VM. - * `Failed`: There was an error when attaching the disk. - * `Terminating`: The resource is being deleted. - enum: - - Pending - - InProgress - - Attached - - Failed - - Terminating - type: string - virtualMachineName: - description: Name of the virtual machine the disk is attached to. - type: string - type: object - required: - - spec - type: object - served: true - storage: true - subresources: - status: {} + type: array + observedGeneration: + description: Resource generation last processed by the controller. + format: int64 + type: integer + phase: + description: |- + BlockDeviceAttachmentPhase defines the current status of the resource: + * `Pending`: The resource has been created and is on a waiting queue. + * `InProgress`: The disk is being attached to the VM. + * `Attached`: The disk has been attached to the VM. + * `Failed`: There was an error when attaching the disk. + * `Terminating`: The resource is being deleted. + enum: + - Pending + - InProgress + - Attached + - Failed + - Terminating + type: string + virtualMachineName: + description: Name of the virtual machine the disk is attached to. + type: string + type: object + required: + - spec + type: object + served: true + storage: true + subresources: + status: {} diff --git a/crds/virtualmachineclasses.yaml b/crds/virtualmachineclasses.yaml index c3fdfa794a..2585375c6d 100644 --- a/crds/virtualmachineclasses.yaml +++ b/crds/virtualmachineclasses.yaml @@ -13,503 +13,489 @@ spec: group: virtualization.deckhouse.io names: categories: - - virtualization-cluster + - virtualization-cluster kind: VirtualMachineClass listKind: VirtualMachineClassList plural: virtualmachineclasses shortNames: - - vmc - - vmclass + - vmc + - vmclass singular: virtualmachineclass scope: Cluster versions: - - additionalPrinterColumns: - - description: VirtualMachineClass phase. - jsonPath: .status.phase - name: Phase - type: string - - description: Default class for virtual machines without specified class. - jsonPath: .metadata.annotations.virtualmachineclass\.virtualization\.deckhouse\.io\/is-default-class - name: IsDefault - type: string - - description: Time of resource creation. - jsonPath: .metadata.creationTimestamp - name: Age - type: date - name: v1alpha2 - schema: - openAPIV3Schema: - description: |- - VirtualMachineClass resource describes CPU requirements, node placement, and sizing policy for VM resources. - A resource cannot be deleted as long as it is used in one of the VMs. - properties: - apiVersion: - description: |- - APIVersion defines the versioned schema of this representation of an object. - Servers should convert recognized schemas to the latest internal value, and - may reject unrecognized values. - More info: https://git.k8s.io/community/contributors/devel/sig-architecture/api-conventions.md#resources - type: string - kind: - description: |- - Kind is a string value representing the REST resource this object represents. - Servers may infer this from the endpoint the client submits requests to. - Cannot be updated. - In CamelCase. - More info: https://git.k8s.io/community/contributors/devel/sig-architecture/api-conventions.md#types-kinds - type: string - metadata: - type: object - spec: - properties: - cpu: - description: CPU defines the requirements for the virtual CPU model. - properties: - discovery: - description: - Create a CPU model based on intersecting CPU features - for selected nodes. - properties: - nodeSelector: - description: - A selection of nodes to be used as the basis - for creating a universal CPU model. - properties: - matchExpressions: - description: - matchExpressions is a list of label selector - requirements. The requirements are ANDed. - items: - description: |- - A label selector requirement is a selector that contains values, a key, and an operator that - relates the key and values. - properties: - key: - description: - key is the label key that the selector - applies to. - type: string - operator: - description: |- - operator represents a key's relationship to a set of values. - Valid operators are In, NotIn, Exists and DoesNotExist. - type: string - values: - description: |- - values is an array of string values. If the operator is In or NotIn, - the values array must be non-empty. If the operator is Exists or DoesNotExist, - the values array must be empty. This array is replaced during a strategic - merge patch. - items: - type: string - type: array - x-kubernetes-list-type: atomic - required: - - key - - operator - type: object - type: array - x-kubernetes-list-type: atomic - matchLabels: - additionalProperties: - type: string - description: |- - matchLabels is a map of {key,value} pairs. A single {key,value} in the matchLabels - map is equivalent to an element of matchExpressions, whose key field is "key", the - operator is "In", and the values array contains only "value". The requirements are ANDed. - type: object - type: object - x-kubernetes-map-type: atomic - type: object - features: - description: |- - List of CPU instructions (features) required when type=Features. - For more information about CPU features, refer to the [libvirt docs](https://libvirt.org/formatdomain.html#cpu-model-and-topology). - example: - - mmx - - vmx - - sse2 - items: - type: string - minItems: 1 - type: array - model: - description: - CPU model name. For more information about CPU models - and topology, refer to the [libvirt docs](https://libvirt.org/formatdomain.html#cpu-model-and-topology). - example: IvyBridge - minLength: 1 - type: string - type: - description: |- - CPUType defines the CPU type, the following options are supported: - * `Host`: Uses a virtual CPU with an instruction set closely matching the platform node's CPU. - This provides high performance and functionality, as well as compatibility with "live" migration for nodes with similar processor types. - For example, VM migration between nodes with Intel and AMD processors will not work. - This is also true for different CPU generations, as their instruction set is different. - * `HostPassthrough`: Uses the platform node's physical CPU directly, without any modifications. - When using this class, the guest VM can only be transferred to a target node with a CPU exactly matching the source node's CPU. - * `Discovery`: Create a virtual CPU based on instruction sets of physical CPUs for a selected set of nodes. - * `Model`: CPU model. A CPU model is a named and previously defined set of supported CPU instructions. - * `Features`: A required set of supported instructions for the CPU. - enum: - - Host - - HostPassthrough - - Discovery - - Model - - Features - type: string - required: - - type - type: object - x-kubernetes-validations: - - message: .spec.cpu is immutable - rule: self == oldSelf - - message: - HostPassthrough and Host cannot have model, features or - discovery - rule: - "self.type == 'HostPassthrough' || self.type == 'Host' - ? !has(self.model) && !has(self.features) && !has(self.discovery) - : true" - - message: Discovery cannot have model or features - rule: - "self.type == 'Discovery' ? !has(self.model) && !has(self.features) - : true" - - message: Model requires model and cannot have features or discovery - rule: - "self.type == 'Model' ? has(self.model) && !has(self.features) - && !has(self.discovery) : true" - - message: Features requires features and cannot have model or discovery - rule: - "self.type == 'Features' ? has(self.features) && !has(self.model) - && !has(self.discovery): true" - nodeSelector: - description: NodeSelector defines the nodes targeted for VM scheduling. - properties: - matchExpressions: - description: A list of node selector requirements by node's labels. - items: - description: |- - A node selector requirement is a selector that contains values, a key, and an operator - that relates the key and values. + - additionalPrinterColumns: + - description: VirtualMachineClass phase. + jsonPath: .status.phase + name: Phase + type: string + - description: Default class for virtual machines without specified class. + jsonPath: .metadata.annotations.virtualmachineclass\.virtualization\.deckhouse\.io\/is-default-class + name: IsDefault + type: string + - description: Time of resource creation. + jsonPath: .metadata.creationTimestamp + name: Age + type: date + name: v1alpha2 + schema: + openAPIV3Schema: + description: |- + VirtualMachineClass resource describes CPU requirements, node placement, and sizing policy for VM resources. + A resource cannot be deleted as long as it is used in one of the VMs. + properties: + apiVersion: + description: |- + APIVersion defines the versioned schema of this representation of an object. + Servers should convert recognized schemas to the latest internal value, and + may reject unrecognized values. + More info: https://git.k8s.io/community/contributors/devel/sig-architecture/api-conventions.md#resources + type: string + kind: + description: |- + Kind is a string value representing the REST resource this object represents. + Servers may infer this from the endpoint the client submits requests to. + Cannot be updated. + In CamelCase. + More info: https://git.k8s.io/community/contributors/devel/sig-architecture/api-conventions.md#types-kinds + type: string + metadata: + type: object + spec: + properties: + cpu: + description: CPU defines the requirements for the virtual CPU model. + properties: + discovery: + description: Create a CPU model based on intersecting CPU features + for selected nodes. + properties: + nodeSelector: + description: A selection of nodes to be used as the basis + for creating a universal CPU model. properties: - key: - description: The label key that the selector applies to. - type: string - operator: - description: |- - Represents a key's relationship to a set of values. - Valid operators are In, NotIn, Exists, DoesNotExist. Gt, and Lt. - type: string - values: - description: |- - An array of string values. If the operator is In or NotIn, - the values array must be non-empty. If the operator is Exists or DoesNotExist, - the values array must be empty. If the operator is Gt or Lt, the values - array must have a single element, which will be interpreted as an integer. - This array is replaced during a strategic merge patch. + matchExpressions: + description: matchExpressions is a list of label selector + requirements. The requirements are ANDed. items: - type: string + description: |- + A label selector requirement is a selector that contains values, a key, and an operator that + relates the key and values. + properties: + key: + description: key is the label key that the selector + applies to. + type: string + operator: + description: |- + operator represents a key's relationship to a set of values. + Valid operators are In, NotIn, Exists and DoesNotExist. + type: string + values: + description: |- + values is an array of string values. If the operator is In or NotIn, + the values array must be non-empty. If the operator is Exists or DoesNotExist, + the values array must be empty. This array is replaced during a strategic + merge patch. + items: + type: string + type: array + x-kubernetes-list-type: atomic + required: + - key + - operator + type: object type: array x-kubernetes-list-type: atomic - required: - - key - - operator - type: object - type: array - matchLabels: - additionalProperties: - type: string - description: |- - A map of {key,value} pairs. - A single {key,value} pair in the matchLabels map is equivalent to an element of matchExpressions whose key field is "key", operator is "In", and the value array contains only "value". - The requirements are ANDed. - type: object - type: object - sizingPolicies: - items: - description: |- - SizingPolicy defines a policy for allocating computational resources to VMs. - It is represented as a list. - The cores.min - cores.max ranges for different elements of the list must not overlap. - properties: - coreFractions: - description: Allowed values of the `coreFraction` parameter. - items: - maximum: 100 - minimum: 1 - type: integer - type: array - cores: - description: - The policy applies for a specified range of the - number of CPU cores. - properties: - max: - description: Maximum number of CPU cores. - example: 10 - maximum: 1024 - type: integer - min: - description: Minimum number of CPU cores. - example: 1 - minimum: 1 - type: integer - step: - description: - Discretization step for the CPU core number. - For example, the combination of `min=2`, `max=10`, and - `step=4` allows to set the number of virtual machine CPU - cores to 2, 6, or 10. - example: 1 - minimum: 1 - type: integer - required: - - max - - min - type: object - x-kubernetes-validations: - - message: The maximum must be greater than the minimum - rule: self.max > self.min - - message: The maximum must be greater than the step - rule: "has(self.step) ? self.max > self.step : true" - dedicatedCores: - description: Allowed values of the `dedicatedCores` parameter. - items: - type: boolean - type: array - memory: - description: Memory sizing policy. - properties: - max: - anyOf: - - type: integer - - type: string - description: Maximum amount of memory. - example: 8Gi - pattern: ^(\+|-)?(([0-9]+(\.[0-9]*)?)|(\.[0-9]+))(([KMGTPE]i)|[numkMGTPE]|([eE](\+|-)?(([0-9]+(\.[0-9]*)?)|(\.[0-9]+))))?$ - x-kubernetes-int-or-string: true - min: - anyOf: - - type: integer - - type: string - description: Minimum amount of memory. - example: 1Gi - pattern: ^(\+|-)?(([0-9]+(\.[0-9]*)?)|(\.[0-9]+))(([KMGTPE]i)|[numkMGTPE]|([eE](\+|-)?(([0-9]+(\.[0-9]*)?)|(\.[0-9]+))))?$ - x-kubernetes-int-or-string: true - perCore: - description: Amount of memory per CPU core. - properties: - max: - anyOf: - - type: integer - - type: string - description: Maximum amount of memory. - example: 8Gi - pattern: ^(\+|-)?(([0-9]+(\.[0-9]*)?)|(\.[0-9]+))(([KMGTPE]i)|[numkMGTPE]|([eE](\+|-)?(([0-9]+(\.[0-9]*)?)|(\.[0-9]+))))?$ - x-kubernetes-int-or-string: true - min: - anyOf: - - type: integer - - type: string - description: Minimum amount of memory. - example: 1Gi - pattern: ^(\+|-)?(([0-9]+(\.[0-9]*)?)|(\.[0-9]+))(([KMGTPE]i)|[numkMGTPE]|([eE](\+|-)?(([0-9]+(\.[0-9]*)?)|(\.[0-9]+))))?$ - x-kubernetes-int-or-string: true + matchLabels: + additionalProperties: + type: string + description: |- + matchLabels is a map of {key,value} pairs. A single {key,value} in the matchLabels + map is equivalent to an element of matchExpressions, whose key field is "key", the + operator is "In", and the values array contains only "value". The requirements are ANDed. type: object - step: - anyOf: - - type: integer - - type: string - description: - Memory size discretization step. For example, - the combination of `min=2Gi, `max=4Gi` and `step=1Gi` - allows to set the virtual machine memory size to 2Gi, - 3Gi, or 4Gi. - example: 512Mi - pattern: ^(\+|-)?(([0-9]+(\.[0-9]*)?)|(\.[0-9]+))(([KMGTPE]i)|[numkMGTPE]|([eE](\+|-)?(([0-9]+(\.[0-9]*)?)|(\.[0-9]+))))?$ - x-kubernetes-int-or-string: true type: object + x-kubernetes-map-type: atomic type: object - type: array - tolerations: - description: |- - Tolerations are the same as `spec.tolerations` for [pods](https://kubernetes.io/docs/concepts/scheduling-eviction/taint-and-toleration/). - These tolerations will be merged with the tolerations specified in the VirtualMachine resource. VirtualMachine tolerations have a higher priority. - items: + features: description: |- - The pod this Toleration is attached to tolerates any taint that matches - the triple using the matching operator . - properties: - effect: - description: |- - Effect indicates the taint effect to match. Empty means match all taint effects. - When specified, allowed values are NoSchedule, PreferNoSchedule and NoExecute. - type: string - key: - description: |- - Key is the taint key that the toleration applies to. Empty means match all taint keys. - If the key is empty, operator must be Exists; this combination means to match all values and all keys. - type: string - operator: - description: |- - Operator represents a key's relationship to the value. - Valid operators are Exists and Equal. Defaults to Equal. - Exists is equivalent to wildcard for value, so that a pod can - tolerate all taints of a particular category. - type: string - tolerationSeconds: - description: |- - TolerationSeconds represents the period of time the toleration (which must be - of effect NoExecute, otherwise this field is ignored) tolerates the taint. By default, - it is not set, which means tolerate the taint forever (do not evict). Zero and - negative values will be treated as 0 (evict immediately) by the system. - format: int64 - type: integer - value: - description: |- - Value is the taint value the toleration matches to. - If the operator is Exists, the value should be empty, otherwise just a regular string. - type: string - type: object - type: array - required: - - cpu - type: object - status: - properties: - availableNodes: - description: |- - List of nodes that support this CPU model. - It is not displayed for the following types: `Host`, `HostPassthrough`. - example: - - node-1 - - node-2 - items: + List of CPU instructions (features) required when type=Features. + For more information about CPU features, refer to the [libvirt docs](https://libvirt.org/formatdomain.html#cpu-model-and-topology). + example: + - mmx + - vmx + - sse2 + items: + type: string + minItems: 1 + type: array + model: + description: CPU model name. For more information about CPU models + and topology, refer to the [libvirt docs](https://libvirt.org/formatdomain.html#cpu-model-and-topology). + example: IvyBridge + minLength: 1 type: string - type: array - conditions: - description: - The latest detailed observations of the VirtualMachineClass - resource. - items: - description: - Condition contains details for one aspect of the current - state of this API Resource. - properties: - lastTransitionTime: - description: |- - lastTransitionTime is the last time the condition transitioned from one status to another. - This should be when the underlying condition changed. If that is not known, then using the time when the API field changed is acceptable. - format: date-time - type: string - message: - description: |- - message is a human readable message indicating details about the transition. - This may be an empty string. - maxLength: 32768 - type: string - observedGeneration: - description: |- - observedGeneration represents the .metadata.generation that the condition was set based upon. - For instance, if .metadata.generation is currently 12, but the .status.conditions[x].observedGeneration is 9, the condition is out of date - with respect to the current state of the instance. - format: int64 - minimum: 0 - type: integer - reason: - description: |- - reason contains a programmatic identifier indicating the reason for the condition's last transition. - Producers of specific condition types may define expected values and meanings for this field, - and whether the values are considered a guaranteed API. - The value should be a CamelCase string. - This field may not be empty. - maxLength: 1024 - minLength: 1 - pattern: ^[A-Za-z]([A-Za-z0-9_,:]*[A-Za-z0-9_])?$ - type: string - status: - description: status of the condition, one of True, False, Unknown. - enum: - - "True" - - "False" - - Unknown - type: string - type: - description: type of condition in CamelCase or in foo.example.com/CamelCase. - maxLength: 316 - pattern: ^([a-z0-9]([-a-z0-9]*[a-z0-9])?(\.[a-z0-9]([-a-z0-9]*[a-z0-9])?)*/)?(([A-Za-z0-9][-A-Za-z0-9_.]*)?[A-Za-z0-9])$ - type: string - required: - - lastTransitionTime - - message - - reason - - status - - type + type: + description: |- + CPUType defines the CPU type, the following options are supported: + * `Host`: Uses a virtual CPU with an instruction set closely matching the platform node's CPU. + This provides high performance and functionality, as well as compatibility with "live" migration for nodes with similar processor types. + For example, VM migration between nodes with Intel and AMD processors will not work. + This is also true for different CPU generations, as their instruction set is different. + * `HostPassthrough`: Uses the platform node's physical CPU directly, without any modifications. + When using this class, the guest VM can only be transferred to a target node with a CPU exactly matching the source node's CPU. + * `Discovery`: Create a virtual CPU based on instruction sets of physical CPUs for a selected set of nodes. + * `Model`: CPU model. A CPU model is a named and previously defined set of supported CPU instructions. + * `Features`: A required set of supported instructions for the CPU. + enum: + - Host + - HostPassthrough + - Discovery + - Model + - Features + type: string + required: + - type + type: object + x-kubernetes-validations: + - message: .spec.cpu is immutable + rule: self == oldSelf + - message: HostPassthrough and Host cannot have model, features or + discovery + rule: 'self.type == ''HostPassthrough'' || self.type == ''Host'' + ? !has(self.model) && !has(self.features) && !has(self.discovery) + : true' + - message: Discovery cannot have model or features + rule: 'self.type == ''Discovery'' ? !has(self.model) && !has(self.features) + : true' + - message: Model requires model and cannot have features or discovery + rule: 'self.type == ''Model'' ? has(self.model) && !has(self.features) + && !has(self.discovery) : true' + - message: Features requires features and cannot have model or discovery + rule: 'self.type == ''Features'' ? has(self.features) && !has(self.model) + && !has(self.discovery): true' + nodeSelector: + description: NodeSelector defines the nodes targeted for VM scheduling. + properties: + matchExpressions: + description: A list of node selector requirements by node's labels. + items: + description: |- + A node selector requirement is a selector that contains values, a key, and an operator + that relates the key and values. + properties: + key: + description: The label key that the selector applies to. + type: string + operator: + description: |- + Represents a key's relationship to a set of values. + Valid operators are In, NotIn, Exists, DoesNotExist. Gt, and Lt. + type: string + values: + description: |- + An array of string values. If the operator is In or NotIn, + the values array must be non-empty. If the operator is Exists or DoesNotExist, + the values array must be empty. If the operator is Gt or Lt, the values + array must have a single element, which will be interpreted as an integer. + This array is replaced during a strategic merge patch. + items: + type: string + type: array + x-kubernetes-list-type: atomic + required: + - key + - operator + type: object + type: array + matchLabels: + additionalProperties: + type: string + description: |- + A map of {key,value} pairs. + A single {key,value} pair in the matchLabels map is equivalent to an element of matchExpressions whose key field is "key", operator is "In", and the value array contains only "value". + The requirements are ANDed. type: object - type: array - cpuFeatures: + type: object + sizingPolicies: + items: description: |- - CpuFeatures - Information on CPU features supported by this model. - Shown only for `Features` or `Discovery` types. + SizingPolicy defines a policy for allocating computational resources to VMs. + It is represented as a list. + The cores.min - cores.max ranges for different elements of the list must not overlap. properties: - enabled: - description: " List of CPU features for this model." - example: - - mmx - - vmx - - sse2 + coreFractions: + description: Allowed values of the `coreFraction` parameter + in percentages (e.g., "5%", "10%", "25%", "50%", "100%"). items: + description: |- + CoreFractionValue represents CPU core fraction as a percentage string (e.g., "5%", "10%", "25%", "50%", "100%"). + For backward compatibility, plain integers are also accepted (e.g., "5", "10", "25", "50", "100"). + pattern: ^([1-9]|[1-9][0-9]|100)%?$ type: string type: array - notEnabledCommon: - description: - List of unused processor features additionally available - for a given group of nodes. - example: - - ssse3 - - vme + cores: + description: The policy applies for a specified range of the + number of CPU cores. + properties: + max: + description: Maximum number of CPU cores. + example: 10 + maximum: 1024 + type: integer + min: + description: Minimum number of CPU cores. + example: 1 + minimum: 1 + type: integer + step: + description: Discretization step for the CPU core number. + For example, the combination of `min=2`, `max=10`, and + `step=4` allows to set the number of virtual machine CPU + cores to 2, 6, or 10. + example: 1 + minimum: 1 + type: integer + required: + - max + - min + type: object + x-kubernetes-validations: + - message: The maximum must be greater than the minimum + rule: self.max > self.min + - message: The maximum must be greater than the step + rule: 'has(self.step) ? self.max > self.step : true' + dedicatedCores: + description: Allowed values of the `dedicatedCores` parameter. items: - type: string + type: boolean type: array + memory: + description: Memory sizing policy. + properties: + max: + anyOf: + - type: integer + - type: string + description: Maximum amount of memory. + example: 8Gi + pattern: ^(\+|-)?(([0-9]+(\.[0-9]*)?)|(\.[0-9]+))(([KMGTPE]i)|[numkMGTPE]|([eE](\+|-)?(([0-9]+(\.[0-9]*)?)|(\.[0-9]+))))?$ + x-kubernetes-int-or-string: true + min: + anyOf: + - type: integer + - type: string + description: Minimum amount of memory. + example: 1Gi + pattern: ^(\+|-)?(([0-9]+(\.[0-9]*)?)|(\.[0-9]+))(([KMGTPE]i)|[numkMGTPE]|([eE](\+|-)?(([0-9]+(\.[0-9]*)?)|(\.[0-9]+))))?$ + x-kubernetes-int-or-string: true + perCore: + description: Amount of memory per CPU core. + properties: + max: + anyOf: + - type: integer + - type: string + description: Maximum amount of memory. + example: 8Gi + pattern: ^(\+|-)?(([0-9]+(\.[0-9]*)?)|(\.[0-9]+))(([KMGTPE]i)|[numkMGTPE]|([eE](\+|-)?(([0-9]+(\.[0-9]*)?)|(\.[0-9]+))))?$ + x-kubernetes-int-or-string: true + min: + anyOf: + - type: integer + - type: string + description: Minimum amount of memory. + example: 1Gi + pattern: ^(\+|-)?(([0-9]+(\.[0-9]*)?)|(\.[0-9]+))(([KMGTPE]i)|[numkMGTPE]|([eE](\+|-)?(([0-9]+(\.[0-9]*)?)|(\.[0-9]+))))?$ + x-kubernetes-int-or-string: true + type: object + step: + anyOf: + - type: integer + - type: string + description: Memory size discretization step. For example, + the combination of `min=2Gi, `max=4Gi` and `step=1Gi` + allows to set the virtual machine memory size to 2Gi, + 3Gi, or 4Gi. + example: 512Mi + pattern: ^(\+|-)?(([0-9]+(\.[0-9]*)?)|(\.[0-9]+))(([KMGTPE]i)|[numkMGTPE]|([eE](\+|-)?(([0-9]+(\.[0-9]*)?)|(\.[0-9]+))))?$ + x-kubernetes-int-or-string: true + type: object type: object - maxAllocatableResources: - 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: - Maximum amount of free CPU and memory resources observed - among all available nodes. - example: - - 'maxAllocatableResources: {"cpu": 1, "memory": "10Gi"}' - type: object - observedGeneration: - description: Resource generation last processed by the controller. - format: int64 - type: integer - phase: + type: array + tolerations: + description: |- + Tolerations are the same as `spec.tolerations` for [pods](https://kubernetes.io/docs/concepts/scheduling-eviction/taint-and-toleration/). + These tolerations will be merged with the tolerations specified in the VirtualMachine resource. VirtualMachine tolerations have a higher priority. + items: description: |- - VirtualMachineClassPhase defines the current resource status: - * `Pending`: The resource is not ready and waits until the suitable nodes supporting the required CPU model are available. - * `Ready`: The resource is ready and available for use. - * `Terminating`: The resource is terminating. - enum: - - Pending - - Ready - - Terminating + The pod this Toleration is attached to tolerates any taint that matches + the triple using the matching operator . + properties: + effect: + description: |- + Effect indicates the taint effect to match. Empty means match all taint effects. + When specified, allowed values are NoSchedule, PreferNoSchedule and NoExecute. + type: string + key: + description: |- + Key is the taint key that the toleration applies to. Empty means match all taint keys. + If the key is empty, operator must be Exists; this combination means to match all values and all keys. + type: string + operator: + description: |- + Operator represents a key's relationship to the value. + Valid operators are Exists and Equal. Defaults to Equal. + Exists is equivalent to wildcard for value, so that a pod can + tolerate all taints of a particular category. + type: string + tolerationSeconds: + description: |- + TolerationSeconds represents the period of time the toleration (which must be + of effect NoExecute, otherwise this field is ignored) tolerates the taint. By default, + it is not set, which means tolerate the taint forever (do not evict). Zero and + negative values will be treated as 0 (evict immediately) by the system. + format: int64 + type: integer + value: + description: |- + Value is the taint value the toleration matches to. + If the operator is Exists, the value should be empty, otherwise just a regular string. + type: string + type: object + type: array + required: + - cpu + type: object + status: + properties: + availableNodes: + description: |- + List of nodes that support this CPU model. + It is not displayed for the following types: `Host`, `HostPassthrough`. + example: + - node-1 + - node-2 + items: type: string - required: - - phase - type: object - required: - - spec - type: object - served: true - storage: true - subresources: - status: {} + type: array + conditions: + description: The latest detailed observations of the VirtualMachineClass + resource. + items: + description: Condition contains details for one aspect of the current + state of this API Resource. + properties: + lastTransitionTime: + description: |- + lastTransitionTime is the last time the condition transitioned from one status to another. + This should be when the underlying condition changed. If that is not known, then using the time when the API field changed is acceptable. + format: date-time + type: string + message: + description: |- + message is a human readable message indicating details about the transition. + This may be an empty string. + maxLength: 32768 + type: string + observedGeneration: + description: |- + observedGeneration represents the .metadata.generation that the condition was set based upon. + For instance, if .metadata.generation is currently 12, but the .status.conditions[x].observedGeneration is 9, the condition is out of date + with respect to the current state of the instance. + format: int64 + minimum: 0 + type: integer + reason: + description: |- + reason contains a programmatic identifier indicating the reason for the condition's last transition. + Producers of specific condition types may define expected values and meanings for this field, + and whether the values are considered a guaranteed API. + The value should be a CamelCase string. + This field may not be empty. + maxLength: 1024 + minLength: 1 + pattern: ^[A-Za-z]([A-Za-z0-9_,:]*[A-Za-z0-9_])?$ + type: string + status: + description: status of the condition, one of True, False, Unknown. + enum: + - "True" + - "False" + - Unknown + type: string + type: + description: type of condition in CamelCase or in foo.example.com/CamelCase. + maxLength: 316 + pattern: ^([a-z0-9]([-a-z0-9]*[a-z0-9])?(\.[a-z0-9]([-a-z0-9]*[a-z0-9])?)*/)?(([A-Za-z0-9][-A-Za-z0-9_.]*)?[A-Za-z0-9])$ + type: string + required: + - lastTransitionTime + - message + - reason + - status + - type + type: object + type: array + cpuFeatures: + description: |- + CpuFeatures + Information on CPU features supported by this model. + Shown only for `Features` or `Discovery` types. + properties: + enabled: + description: ' List of CPU features for this model.' + example: + - mmx + - vmx + - sse2 + items: + type: string + type: array + notEnabledCommon: + description: List of unused processor features additionally available + for a given group of nodes. + example: + - ssse3 + - vme + items: + type: string + type: array + type: object + maxAllocatableResources: + 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: Maximum amount of free CPU and memory resources observed + among all available nodes. + example: + - 'maxAllocatableResources: {"cpu": 1, "memory": "10Gi"}' + type: object + observedGeneration: + description: Resource generation last processed by the controller. + format: int64 + type: integer + phase: + description: |- + VirtualMachineClassPhase defines the current resource status: + * `Pending`: The resource is not ready and waits until the suitable nodes supporting the required CPU model are available. + * `Ready`: The resource is ready and available for use. + * `Terminating`: The resource is terminating. + enum: + - Pending + - Ready + - Terminating + type: string + required: + - phase + type: object + required: + - spec + type: object + served: true + storage: true + subresources: + status: {} diff --git a/crds/virtualmachineoperations.yaml b/crds/virtualmachineoperations.yaml index f941b062f3..d35b2c7db8 100644 --- a/crds/virtualmachineoperations.yaml +++ b/crds/virtualmachineoperations.yaml @@ -12,313 +12,303 @@ spec: group: virtualization.deckhouse.io names: categories: - - virtualization + - virtualization kind: VirtualMachineOperation listKind: VirtualMachineOperationList plural: virtualmachineoperations shortNames: - - vmop + - vmop singular: virtualmachineoperation scope: Namespaced versions: - - additionalPrinterColumns: - - description: VirtualMachineOperation phase. - jsonPath: .status.phase - name: Phase - type: string - - description: VirtualMachineOperation type. - jsonPath: .spec.type - name: Type - type: string - - description: VirtualMachine name. - jsonPath: .spec.virtualMachineName - name: VirtualMachine - type: string - - description: Time of resource creation. - jsonPath: .metadata.creationTimestamp - name: Age - type: date - name: v1alpha2 - schema: - openAPIV3Schema: - description: - VirtualMachineOperation enables declarative management of virtual - machine state changes. - properties: - apiVersion: - description: |- - APIVersion defines the versioned schema of this representation of an object. - Servers should convert recognized schemas to the latest internal value, and - may reject unrecognized values. - More info: https://git.k8s.io/community/contributors/devel/sig-architecture/api-conventions.md#resources - type: string - kind: - description: |- - Kind is a string value representing the REST resource this object represents. - Servers may infer this from the endpoint the client submits requests to. - Cannot be updated. - In CamelCase. - More info: https://git.k8s.io/community/contributors/devel/sig-architecture/api-conventions.md#types-kinds - type: string - metadata: - type: object - spec: - properties: - clone: - description: Clone defines the clone operation. - properties: - customization: - description: Customization defines customization options for cloning. + - additionalPrinterColumns: + - description: VirtualMachineOperation phase. + jsonPath: .status.phase + name: Phase + type: string + - description: VirtualMachineOperation type. + jsonPath: .spec.type + name: Type + type: string + - description: VirtualMachine name. + jsonPath: .spec.virtualMachineName + name: VirtualMachine + type: string + - description: Time of resource creation. + jsonPath: .metadata.creationTimestamp + name: Age + type: date + name: v1alpha2 + schema: + openAPIV3Schema: + description: VirtualMachineOperation enables declarative management of virtual + machine state changes. + properties: + apiVersion: + description: |- + APIVersion defines the versioned schema of this representation of an object. + Servers should convert recognized schemas to the latest internal value, and + may reject unrecognized values. + More info: https://git.k8s.io/community/contributors/devel/sig-architecture/api-conventions.md#resources + type: string + kind: + description: |- + Kind is a string value representing the REST resource this object represents. + Servers may infer this from the endpoint the client submits requests to. + Cannot be updated. + In CamelCase. + More info: https://git.k8s.io/community/contributors/devel/sig-architecture/api-conventions.md#types-kinds + type: string + metadata: + type: object + spec: + properties: + clone: + description: Clone defines the clone operation. + properties: + customization: + description: Customization defines customization options for cloning. + properties: + namePrefix: + description: |- + NamePrefix adds a prefix to resource names during cloning. + Applied to VirtualDisk, VirtualMachineIPAddress, VirtualMachineMACAddress, and Secret resources. + type: string + nameSuffix: + description: |- + NameSuffix adds a suffix to resource names during cloning. + Applied to VirtualDisk, VirtualMachineIPAddress, VirtualMachineMACAddress, and Secret resources. + type: string + type: object + mode: + description: |- + VMOPRestoreMode defines the kind of the restore operation. + * `DryRun`: DryRun run without any changes. Compatibility shows in status. + * `Strict`: Strict restore as is in the snapshot. + * `BestEffort`: BestEffort restore without deleted external missing dependencies. + enum: + - DryRun + - Strict + - BestEffort + type: string + nameReplacement: + description: NameReplacement defines rules for renaming resources + during cloning. + items: + description: NameReplacement represents a rule for redefining + the virtual machine resource names. properties: - namePrefix: - description: |- - NamePrefix adds a prefix to resource names during cloning. - Applied to VirtualMachine, VirtualDisk, VirtualMachineBlockDeviceAttachment, and Secret resources. - type: string - nameSuffix: - description: |- - NameSuffix adds a suffix to resource names during cloning. - Applied to VirtualMachine, VirtualDisk, VirtualMachineBlockDeviceAttachment, and Secret resources. + from: + description: Selector to choose resources for name replacement. + properties: + kind: + description: Kind of a resource to rename. + type: string + name: + description: Current name of a resource to rename. + type: string + required: + - name + type: object + to: + description: New resource name. type: string + required: + - from + - to type: object - mode: + type: array + required: + - mode + type: object + force: + description: |- + Force execution of an operation. + + * Effect on `Restart` and `Stop`: operation performs immediately. + * Effect on `Evict` and `Migrate`: enable the AutoConverge feature to force migration via CPU throttling if the `PreferSafe` or `PreferForced` policies are used for live migration. + type: boolean + restore: + description: Restore defines the restore operation. + properties: + mode: + description: |- + VMOPRestoreMode defines the kind of the restore operation. + * `DryRun`: DryRun run without any changes. Compatibility shows in status. + * `Strict`: Strict restore as is in the snapshot. + * `BestEffort`: BestEffort restore without deleted external missing dependencies. + enum: + - DryRun + - Strict + - BestEffort + type: string + virtualMachineSnapshotName: + description: VirtualMachineSnapshotName defines the source of + the restore operation. + type: string + required: + - mode + - virtualMachineSnapshotName + type: object + type: + description: |- + Type of the operation to execute on a virtual machine: + * `Start`: Start the virtual machine. + * `Stop`: Stop the virtual machine. + * `Restart`: Restart the virtual machine. + * `Migrate` (deprecated): Migrate the virtual machine to another node where it can be started. + * `Evict`: Migrate the virtual machine to another node where it can be started. + * `Restore`: Restore the virtual machine from a snapshot. + * `Clone`: Clone the virtual machine to a new virtual machine. + enum: + - Restart + - Start + - Stop + - Migrate + - Evict + - Restore + - Clone + type: string + virtualMachineName: + description: Name of the virtual machine the operation is performed + for. + type: string + required: + - type + - virtualMachineName + type: object + x-kubernetes-validations: + - message: .spec is immutable + rule: self == oldSelf + - message: The `Start` operation cannot be performed forcibly. + rule: 'self.type == ''Start'' ? !has(self.force) || !self.force : true' + - message: The `Migrate` operation cannot be performed forcibly. + rule: 'self.type == ''Migrate'' ? !has(self.force) || !self.force : + true' + - message: Restore requires restore field. + rule: 'self.type == ''Restore'' ? has(self.restore) : true' + - message: Clone requires clone field. + rule: 'self.type == ''Clone'' ? has(self.clone) : true' + status: + properties: + conditions: + description: The latest detailed observations of the VirtualMachineOperation + resource. + items: + description: Condition contains details for one aspect of the current + state of this API Resource. + properties: + lastTransitionTime: description: |- - VMOPRestoreMode defines the kind of the restore operation. - * `DryRun`: DryRun run without any changes. Compatibility shows in status. - * `Strict`: Strict restore as is in the snapshot. - * `BestEffort`: BestEffort restore without deleted external missing dependencies. + lastTransitionTime is the last time the condition transitioned from one status to another. + This should be when the underlying condition changed. If that is not known, then using the time when the API field changed is acceptable. + format: date-time + type: string + message: + description: |- + message is a human readable message indicating details about the transition. + This may be an empty string. + maxLength: 32768 + type: string + observedGeneration: + description: |- + observedGeneration represents the .metadata.generation that the condition was set based upon. + For instance, if .metadata.generation is currently 12, but the .status.conditions[x].observedGeneration is 9, the condition is out of date + with respect to the current state of the instance. + format: int64 + minimum: 0 + type: integer + reason: + description: |- + reason contains a programmatic identifier indicating the reason for the condition's last transition. + Producers of specific condition types may define expected values and meanings for this field, + and whether the values are considered a guaranteed API. + The value should be a CamelCase string. + This field may not be empty. + maxLength: 1024 + minLength: 1 + pattern: ^[A-Za-z]([A-Za-z0-9_,:]*[A-Za-z0-9_])?$ + type: string + status: + description: status of the condition, one of True, False, Unknown. enum: - - DryRun - - Strict - - BestEffort + - "True" + - "False" + - Unknown + type: string + type: + description: type of condition in CamelCase or in foo.example.com/CamelCase. + maxLength: 316 + pattern: ^([a-z0-9]([-a-z0-9]*[a-z0-9])?(\.[a-z0-9]([-a-z0-9]*[a-z0-9])?)*/)?(([A-Za-z0-9][-A-Za-z0-9_.]*)?[A-Za-z0-9])$ type: string - nameReplacement: - description: - NameReplacement defines rules for renaming resources - during cloning. - items: - description: - NameReplacement represents a rule for redefining - the virtual machine resource names. - properties: - from: - description: Selector to choose resources for name replacement. - properties: - kind: - description: Kind of a resource to rename. - type: string - name: - description: Current name of a resource to rename. - type: string - required: - - name - type: object - to: - description: New resource name. - type: string - required: - - from - - to - type: object - type: array required: - - mode + - lastTransitionTime + - message + - reason + - status + - type type: object - force: - description: |- - Force execution of an operation. - - * Effect on `Restart` and `Stop`: operation performs immediately. - * Effect on `Evict` and `Migrate`: enable the AutoConverge feature to force migration via CPU throttling if the `PreferSafe` or `PreferForced` policies are used for live migration. - type: boolean - restore: - description: Restore defines the restore operation. + type: array + observedGeneration: + description: ' Resource generation last processed by the controller.' + format: int64 + type: integer + phase: + description: |- + Current phase of the resource: + * `Pending`: The operation is queued for execution. + * `InProgress`: The operation is in progress. + * `Completed`: The operation has been completed successfully. + * `Failed`: The operation failed. For details, refer to the `conditions` field and events. + * `Terminating`: The operation is being deleted. + enum: + - Pending + - InProgress + - Completed + - Failed + - Terminating + type: string + resources: + description: Resources contains the list of resources that are affected + by the snapshot operation. + items: + description: VirtualMachineOperationResource defines the resource + affected by the operation. properties: - mode: - description: |- - VMOPRestoreMode defines the kind of the restore operation. - * `DryRun`: DryRun run without any changes. Compatibility shows in status. - * `Strict`: Strict restore as is in the snapshot. - * `BestEffort`: BestEffort restore without deleted external missing dependencies. - enum: - - DryRun - - Strict - - BestEffort + apiVersion: + description: API version of the resource. + type: string + kind: + description: Kind of the resource. type: string - virtualMachineSnapshotName: - description: - VirtualMachineSnapshotName defines the source of - the restore operation. + message: + description: Message about the resource. + type: string + name: + description: Name of the resource. + type: string + status: + description: Status of the resource. + enum: + - InProgress + - Completed + - Failed type: string required: - - mode - - virtualMachineSnapshotName + - apiVersion + - kind + - message + - name + - status type: object - type: - description: |- - Type of the operation to execute on a virtual machine: - * `Start`: Start the virtual machine. - * `Stop`: Stop the virtual machine. - * `Restart`: Restart the virtual machine. - * `Migrate` (deprecated): Migrate the virtual machine to another node where it can be started. - * `Evict`: Migrate the virtual machine to another node where it can be started. - * `Restore`: Restore the virtual machine from a snapshot. - * `Clone`: Clone the virtual machine to a new virtual machine. - enum: - - Restart - - Start - - Stop - - Migrate - - Evict - - Restore - - Clone - type: string - virtualMachineName: - description: - Name of the virtual machine the operation is performed - for. - type: string - required: - - type - - virtualMachineName - type: object - x-kubernetes-validations: - - message: .spec is immutable - rule: self == oldSelf - - message: The `Start` operation cannot be performed forcibly. - rule: "self.type == 'Start' ? !has(self.force) || !self.force : true" - - message: The `Migrate` operation cannot be performed forcibly. - rule: - "self.type == 'Migrate' ? !has(self.force) || !self.force : - true" - - message: Restore requires restore field. - rule: "self.type == 'Restore' ? has(self.restore) : true" - - message: Clone requires clone field. - rule: "self.type == 'Clone' ? has(self.clone) : true" - status: - properties: - conditions: - description: - The latest detailed observations of the VirtualMachineOperation - resource. - items: - description: - Condition contains details for one aspect of the current - state of this API Resource. - properties: - lastTransitionTime: - description: |- - lastTransitionTime is the last time the condition transitioned from one status to another. - This should be when the underlying condition changed. If that is not known, then using the time when the API field changed is acceptable. - format: date-time - type: string - message: - description: |- - message is a human readable message indicating details about the transition. - This may be an empty string. - maxLength: 32768 - type: string - observedGeneration: - description: |- - observedGeneration represents the .metadata.generation that the condition was set based upon. - For instance, if .metadata.generation is currently 12, but the .status.conditions[x].observedGeneration is 9, the condition is out of date - with respect to the current state of the instance. - format: int64 - minimum: 0 - type: integer - reason: - description: |- - reason contains a programmatic identifier indicating the reason for the condition's last transition. - Producers of specific condition types may define expected values and meanings for this field, - and whether the values are considered a guaranteed API. - The value should be a CamelCase string. - This field may not be empty. - maxLength: 1024 - minLength: 1 - pattern: ^[A-Za-z]([A-Za-z0-9_,:]*[A-Za-z0-9_])?$ - type: string - status: - description: status of the condition, one of True, False, Unknown. - enum: - - "True" - - "False" - - Unknown - type: string - type: - description: type of condition in CamelCase or in foo.example.com/CamelCase. - maxLength: 316 - pattern: ^([a-z0-9]([-a-z0-9]*[a-z0-9])?(\.[a-z0-9]([-a-z0-9]*[a-z0-9])?)*/)?(([A-Za-z0-9][-A-Za-z0-9_.]*)?[A-Za-z0-9])$ - type: string - required: - - lastTransitionTime - - message - - reason - - status - - type - type: object - type: array - observedGeneration: - description: " Resource generation last processed by the controller." - format: int64 - type: integer - phase: - description: |- - Current phase of the resource: - * `Pending`: The operation is queued for execution. - * `InProgress`: The operation is in progress. - * `Completed`: The operation has been completed successfully. - * `Failed`: The operation failed. For details, refer to the `conditions` field and events. - * `Terminating`: The operation is being deleted. - enum: - - Pending - - InProgress - - Completed - - Failed - - Terminating - type: string - resources: - description: - Resources contains the list of resources that are affected - by the snapshot operation. - items: - description: - VirtualMachineOperationResource defines the resource - affected by the operation. - properties: - apiVersion: - description: API version of the resource. - type: string - kind: - description: Kind of the resource. - type: string - message: - description: Message about the resource. - type: string - name: - description: Name of the resource. - type: string - status: - description: Status of the resource. - enum: - - InProgress - - Completed - - Failed - type: string - required: - - apiVersion - - kind - - message - - name - - status - type: object - type: array - required: - - phase - type: object - required: - - spec - type: object - served: true - storage: true - subresources: - status: {} + type: array + required: + - phase + type: object + required: + - spec + type: object + served: true + storage: true + subresources: + status: {} diff --git a/crds/virtualmachinerestores.yaml b/crds/virtualmachinerestores.yaml index eb848d5250..d2c8926b9c 100644 --- a/crds/virtualmachinerestores.yaml +++ b/crds/virtualmachinerestores.yaml @@ -12,181 +12,178 @@ spec: group: virtualization.deckhouse.io names: categories: - - virtualization + - virtualization kind: VirtualMachineRestore listKind: VirtualMachineRestoreList plural: virtualmachinerestores shortNames: - - vmrestore + - vmrestore singular: virtualmachinerestore scope: Namespaced versions: - - additionalPrinterColumns: - - description: VirtualMachineRestore phase. - jsonPath: .status.phase - name: Phase - type: string - - description: VirtualMachineRestore age. - jsonPath: .metadata.creationTimestamp - name: Age - type: date - name: v1alpha2 - schema: - openAPIV3Schema: - description: - VirtualMachineRestore provides a resource for restoring a virtual - machine and all associated resources from a snapshot. - properties: - apiVersion: - description: |- - APIVersion defines the versioned schema of this representation of an object. - Servers should convert recognized schemas to the latest internal value, and - may reject unrecognized values. - More info: https://git.k8s.io/community/contributors/devel/sig-architecture/api-conventions.md#resources - type: string - kind: - description: |- - Kind is a string value representing the REST resource this object represents. - Servers may infer this from the endpoint the client submits requests to. - Cannot be updated. - In CamelCase. - More info: https://git.k8s.io/community/contributors/devel/sig-architecture/api-conventions.md#types-kinds - type: string - metadata: - type: object - spec: - properties: - nameReplacements: - description: Renaming conventions for virtual machine resources. - items: - description: - NameReplacement represents a rule for redefining the - virtual machine resource names. - properties: - from: - description: Selector to choose resources for name replacement. - properties: - kind: - description: Kind of a resource to rename. - type: string - name: - description: Current name of a resource to rename. - type: string - required: - - name - type: object - to: - description: New resource name. - type: string - required: - - from - - to - type: object - type: array - restoreMode: - default: Safe - description: |- - Virtual machine restore mode: + - additionalPrinterColumns: + - description: VirtualMachineRestore phase. + jsonPath: .status.phase + name: Phase + type: string + - description: VirtualMachineRestore age. + jsonPath: .metadata.creationTimestamp + name: Age + type: date + name: v1alpha2 + schema: + openAPIV3Schema: + description: VirtualMachineRestore provides a resource for restoring a virtual + machine and all associated resources from a snapshot. + properties: + apiVersion: + description: |- + APIVersion defines the versioned schema of this representation of an object. + Servers should convert recognized schemas to the latest internal value, and + may reject unrecognized values. + More info: https://git.k8s.io/community/contributors/devel/sig-architecture/api-conventions.md#resources + type: string + kind: + description: |- + Kind is a string value representing the REST resource this object represents. + Servers may infer this from the endpoint the client submits requests to. + Cannot be updated. + In CamelCase. + More info: https://git.k8s.io/community/contributors/devel/sig-architecture/api-conventions.md#types-kinds + type: string + metadata: + type: object + spec: + properties: + nameReplacements: + description: Renaming conventions for virtual machine resources. + items: + description: NameReplacement represents a rule for redefining the + virtual machine resource names. + properties: + from: + description: Selector to choose resources for name replacement. + properties: + kind: + description: Kind of a resource to rename. + type: string + name: + description: Current name of a resource to rename. + type: string + required: + - name + type: object + to: + description: New resource name. + type: string + required: + - from + - to + type: object + type: array + restoreMode: + default: Safe + description: |- + Virtual machine restore mode: - * Safe — in this mode, the virtual machine will not be restored if unresolvable conflicts are detected during the restoration process. - * Forced — in this mode, the virtual machine configuration will be updated and all associated resources will be recreated. The virtual machine may malfunction if the recovery process fails. Use the mode when you need to restore the virtual machine despite conflicts. - enum: - - Safe - - Forced - type: string - virtualMachineSnapshotName: - description: Snapshot name to restore a virtual machine from. - minLength: 1 - type: string - required: - - virtualMachineSnapshotName - type: object - status: - properties: - conditions: - description: Contains details of the current API resource state. - items: - description: - Condition contains details for one aspect of the current - state of this API Resource. - properties: - lastTransitionTime: - description: |- - lastTransitionTime is the last time the condition transitioned from one status to another. - This should be when the underlying condition changed. If that is not known, then using the time when the API field changed is acceptable. - format: date-time - type: string - message: - description: |- - message is a human readable message indicating details about the transition. - This may be an empty string. - maxLength: 32768 - type: string - observedGeneration: - description: |- - observedGeneration represents the .metadata.generation that the condition was set based upon. - For instance, if .metadata.generation is currently 12, but the .status.conditions[x].observedGeneration is 9, the condition is out of date - with respect to the current state of the instance. - format: int64 - minimum: 0 - type: integer - reason: - description: |- - reason contains a programmatic identifier indicating the reason for the condition's last transition. - Producers of specific condition types may define expected values and meanings for this field, - and whether the values are considered a guaranteed API. - The value should be a CamelCase string. - This field may not be empty. - maxLength: 1024 - minLength: 1 - pattern: ^[A-Za-z]([A-Za-z0-9_,:]*[A-Za-z0-9_])?$ - type: string - status: - description: status of the condition, one of True, False, Unknown. - enum: - - "True" - - "False" - - Unknown - type: string - type: - description: type of condition in CamelCase or in foo.example.com/CamelCase. - maxLength: 316 - pattern: ^([a-z0-9]([-a-z0-9]*[a-z0-9])?(\.[a-z0-9]([-a-z0-9]*[a-z0-9])?)*/)?(([A-Za-z0-9][-A-Za-z0-9_.]*)?[A-Za-z0-9])$ - type: string - required: - - lastTransitionTime - - message - - reason - - status - - type - type: object - type: array - observedGeneration: - description: Resource generation last processed by the controller. - format: int64 - type: integer - phase: - description: |- - VirtualMachineRestorePhase defines the current status of a resource: - * `Pending`: The resource has been created and is on a waiting queue. - * `InProgress`: A virtual machine is being restored from a snapshot. - * `Ready`: A virtual machine has been successfully restored from a snapshot. - * `Failed`: An error occurred when restoring a virtual machine from a snapshot. - * `Terminating`: The resource is being deleted. - enum: - - Pending - - InProgress - - Ready - - Failed - - Terminating - type: string - required: - - phase - type: object - required: - - spec - type: object - served: true - storage: true - subresources: - status: {} + * Safe — in this mode, the virtual machine will not be restored if unresolvable conflicts are detected during the restoration process. + * Forced — in this mode, the virtual machine configuration will be updated and all associated resources will be recreated. The virtual machine may malfunction if the recovery process fails. Use the mode when you need to restore the virtual machine despite conflicts. + enum: + - Safe + - Forced + type: string + virtualMachineSnapshotName: + description: Snapshot name to restore a virtual machine from. + minLength: 1 + type: string + required: + - virtualMachineSnapshotName + type: object + status: + properties: + conditions: + description: Contains details of the current API resource state. + items: + description: Condition contains details for one aspect of the current + state of this API Resource. + properties: + lastTransitionTime: + description: |- + lastTransitionTime is the last time the condition transitioned from one status to another. + This should be when the underlying condition changed. If that is not known, then using the time when the API field changed is acceptable. + format: date-time + type: string + message: + description: |- + message is a human readable message indicating details about the transition. + This may be an empty string. + maxLength: 32768 + type: string + observedGeneration: + description: |- + observedGeneration represents the .metadata.generation that the condition was set based upon. + For instance, if .metadata.generation is currently 12, but the .status.conditions[x].observedGeneration is 9, the condition is out of date + with respect to the current state of the instance. + format: int64 + minimum: 0 + type: integer + reason: + description: |- + reason contains a programmatic identifier indicating the reason for the condition's last transition. + Producers of specific condition types may define expected values and meanings for this field, + and whether the values are considered a guaranteed API. + The value should be a CamelCase string. + This field may not be empty. + maxLength: 1024 + minLength: 1 + pattern: ^[A-Za-z]([A-Za-z0-9_,:]*[A-Za-z0-9_])?$ + type: string + status: + description: status of the condition, one of True, False, Unknown. + enum: + - "True" + - "False" + - Unknown + type: string + type: + description: type of condition in CamelCase or in foo.example.com/CamelCase. + maxLength: 316 + pattern: ^([a-z0-9]([-a-z0-9]*[a-z0-9])?(\.[a-z0-9]([-a-z0-9]*[a-z0-9])?)*/)?(([A-Za-z0-9][-A-Za-z0-9_.]*)?[A-Za-z0-9])$ + type: string + required: + - lastTransitionTime + - message + - reason + - status + - type + type: object + type: array + observedGeneration: + description: Resource generation last processed by the controller. + format: int64 + type: integer + phase: + description: |- + VirtualMachineRestorePhase defines the current status of a resource: + * `Pending`: The resource has been created and is on a waiting queue. + * `InProgress`: A virtual machine is being restored from a snapshot. + * `Ready`: A virtual machine has been successfully restored from a snapshot. + * `Failed`: An error occurred when restoring a virtual machine from a snapshot. + * `Terminating`: The resource is being deleted. + enum: + - Pending + - InProgress + - Ready + - Failed + - Terminating + type: string + required: + - phase + type: object + required: + - spec + type: object + served: true + storage: true + subresources: + status: {} diff --git a/crds/virtualmachinesnapshots.yaml b/crds/virtualmachinesnapshots.yaml index c1b681a99e..223865b5f8 100644 --- a/crds/virtualmachinesnapshots.yaml +++ b/crds/virtualmachinesnapshots.yaml @@ -12,203 +12,198 @@ spec: group: virtualization.deckhouse.io names: categories: - - virtualization + - virtualization kind: VirtualMachineSnapshot listKind: VirtualMachineSnapshotList plural: virtualmachinesnapshots shortNames: - - vmsnapshot - - vms + - vmsnapshot + - vms singular: virtualmachinesnapshot scope: Namespaced versions: - - additionalPrinterColumns: - - description: VirtualMachineSnapshot phase. - jsonPath: .status.phase - name: Phase - type: string - - description: VirtualMachineSnapshot consistency. - jsonPath: .status.consistent - name: Consistent - type: boolean - - description: VirtualMachineSnapshot age. - jsonPath: .metadata.creationTimestamp - name: Age - type: date - name: v1alpha2 - schema: - openAPIV3Schema: - description: - VirtualMachineSnapshot provides a resource for creating snapshots - of virtual machines. - properties: - apiVersion: - description: |- - APIVersion defines the versioned schema of this representation of an object. - Servers should convert recognized schemas to the latest internal value, and - may reject unrecognized values. - More info: https://git.k8s.io/community/contributors/devel/sig-architecture/api-conventions.md#resources - type: string - kind: - description: |- - Kind is a string value representing the REST resource this object represents. - Servers may infer this from the endpoint the client submits requests to. - Cannot be updated. - In CamelCase. - More info: https://git.k8s.io/community/contributors/devel/sig-architecture/api-conventions.md#types-kinds - type: string - metadata: - type: object - spec: - properties: - keepIPAddress: - default: Always - description: |- - KeepIPAddress defines whether to keep the IP address of a virtual machine or not: + - additionalPrinterColumns: + - description: VirtualMachineSnapshot phase. + jsonPath: .status.phase + name: Phase + type: string + - description: VirtualMachineSnapshot consistency. + jsonPath: .status.consistent + name: Consistent + type: boolean + - description: VirtualMachineSnapshot age. + jsonPath: .metadata.creationTimestamp + name: Age + type: date + name: v1alpha2 + schema: + openAPIV3Schema: + description: VirtualMachineSnapshot provides a resource for creating snapshots + of virtual machines. + properties: + apiVersion: + description: |- + APIVersion defines the versioned schema of this representation of an object. + Servers should convert recognized schemas to the latest internal value, and + may reject unrecognized values. + More info: https://git.k8s.io/community/contributors/devel/sig-architecture/api-conventions.md#resources + type: string + kind: + description: |- + Kind is a string value representing the REST resource this object represents. + Servers may infer this from the endpoint the client submits requests to. + Cannot be updated. + In CamelCase. + More info: https://git.k8s.io/community/contributors/devel/sig-architecture/api-conventions.md#types-kinds + type: string + metadata: + type: object + spec: + properties: + keepIPAddress: + default: Always + description: |- + KeepIPAddress defines whether to keep the IP address of a virtual machine or not: - * `Always`: When creating a snapshot, the virtual machine's IP address will be converted from `Auto` to `Static` and saved. - * `Never`: When creating a snapshot, the virtual machine's IP address will not be converted. - enum: - - Always - - Never - type: string - requiredConsistency: - default: true - description: |- - Create a snapshot of a virtual machine only if it is possible to freeze the machine through the agent. + * `Always`: When creating a snapshot, the virtual machine's IP address will be converted from `Auto` to `Static` and saved. + * `Never`: When creating a snapshot, the virtual machine's IP address will not be converted. + enum: + - Always + - Never + type: string + requiredConsistency: + default: true + description: |- + Create a snapshot of a virtual machine only if it is possible to freeze the machine through the agent. - If set to `true`, the virtual machine snapshot will be created only in the following cases: - - When the virtual machine is powered off. - - When the virtual machine has an agent, and the freeze operation was successful. - type: boolean - virtualMachineName: - description: Name of the virtual machine to take a snapshot of. - minLength: 1 - type: string - required: - - keepIPAddress - - requiredConsistency - - virtualMachineName - type: object - status: - properties: - conditions: - description: - The latest detailed observations of the VirtualMachineSnapshot - resource. - items: - description: - Condition contains details for one aspect of the current - state of this API Resource. - properties: - lastTransitionTime: - description: |- - lastTransitionTime is the last time the condition transitioned from one status to another. - This should be when the underlying condition changed. If that is not known, then using the time when the API field changed is acceptable. - format: date-time - type: string - message: - description: |- - message is a human readable message indicating details about the transition. - This may be an empty string. - maxLength: 32768 - type: string - observedGeneration: - description: |- - observedGeneration represents the .metadata.generation that the condition was set based upon. - For instance, if .metadata.generation is currently 12, but the .status.conditions[x].observedGeneration is 9, the condition is out of date - with respect to the current state of the instance. - format: int64 - minimum: 0 - type: integer - reason: - description: |- - reason contains a programmatic identifier indicating the reason for the condition's last transition. - Producers of specific condition types may define expected values and meanings for this field, - and whether the values are considered a guaranteed API. - The value should be a CamelCase string. - This field may not be empty. - maxLength: 1024 - minLength: 1 - pattern: ^[A-Za-z]([A-Za-z0-9_,:]*[A-Za-z0-9_])?$ - type: string - status: - description: status of the condition, one of True, False, Unknown. - enum: - - "True" - - "False" - - Unknown - type: string - type: - description: type of condition in CamelCase or in foo.example.com/CamelCase. - maxLength: 316 - pattern: ^([a-z0-9]([-a-z0-9]*[a-z0-9])?(\.[a-z0-9]([-a-z0-9]*[a-z0-9])?)*/)?(([A-Za-z0-9][-A-Za-z0-9_.]*)?[A-Za-z0-9])$ - type: string - required: - - lastTransitionTime - - message - - reason - - status - - type - type: object - type: array - consistent: - description: Whether a virtual machine snapshot is consistent. - type: boolean - observedGeneration: - description: Resource generation last processed by the controller. - format: int64 - type: integer - phase: - description: |- - VirtualMachineSnapshotPhase defines the current status of a resource: + If set to `true`, the virtual machine snapshot will be created only in the following cases: + - When the virtual machine is powered off. + - When the virtual machine has an agent, and the freeze operation was successful. + type: boolean + virtualMachineName: + description: Name of the virtual machine to take a snapshot of. + minLength: 1 + type: string + required: + - keepIPAddress + - requiredConsistency + - virtualMachineName + type: object + status: + properties: + conditions: + description: The latest detailed observations of the VirtualMachineSnapshot + resource. + items: + description: Condition contains details for one aspect of the current + state of this API Resource. + properties: + lastTransitionTime: + description: |- + lastTransitionTime is the last time the condition transitioned from one status to another. + This should be when the underlying condition changed. If that is not known, then using the time when the API field changed is acceptable. + format: date-time + type: string + message: + description: |- + message is a human readable message indicating details about the transition. + This may be an empty string. + maxLength: 32768 + type: string + observedGeneration: + description: |- + observedGeneration represents the .metadata.generation that the condition was set based upon. + For instance, if .metadata.generation is currently 12, but the .status.conditions[x].observedGeneration is 9, the condition is out of date + with respect to the current state of the instance. + format: int64 + minimum: 0 + type: integer + reason: + description: |- + reason contains a programmatic identifier indicating the reason for the condition's last transition. + Producers of specific condition types may define expected values and meanings for this field, + and whether the values are considered a guaranteed API. + The value should be a CamelCase string. + This field may not be empty. + maxLength: 1024 + minLength: 1 + pattern: ^[A-Za-z]([A-Za-z0-9_,:]*[A-Za-z0-9_])?$ + type: string + status: + description: status of the condition, one of True, False, Unknown. + enum: + - "True" + - "False" + - Unknown + type: string + type: + description: type of condition in CamelCase or in foo.example.com/CamelCase. + maxLength: 316 + pattern: ^([a-z0-9]([-a-z0-9]*[a-z0-9])?(\.[a-z0-9]([-a-z0-9]*[a-z0-9])?)*/)?(([A-Za-z0-9][-A-Za-z0-9_.]*)?[A-Za-z0-9])$ + type: string + required: + - lastTransitionTime + - message + - reason + - status + - type + type: object + type: array + consistent: + description: Whether a virtual machine snapshot is consistent. + type: boolean + observedGeneration: + description: Resource generation last processed by the controller. + format: int64 + type: integer + phase: + description: |- + VirtualMachineSnapshotPhase defines the current status of a resource: - * `Pending`: The resource has been created and is on a waiting queue. - * `InProgress`: A virtual machine snapshot is being created. - * `Ready`: A snapshot has been created successfully, and now it's available to use. - * `Failed`: An error occurred when creating a virtual machine snapshot. - * `Terminating`: The resource is being deleted. - enum: - - Pending - - InProgress - - Ready - - Failed - - Terminating - type: string - resources: - description: List of snapshot resources. - items: - properties: - apiVersion: - description: API version of the resource. - type: string - kind: - description: Kind of the resource. - type: string - name: - description: Name of the resource. - type: string - type: object - type: array - virtualDiskSnapshotNames: - description: - List of VirtualDiskSnapshot names for the snapshots taken - from the virtual disks of the associated virtual machine. - items: - type: string - type: array - virtualMachineSnapshotSecretName: - description: - Name of the underlying `Secret` created for virtual machine - snapshotting. + * `Pending`: The resource has been created and is on a waiting queue. + * `InProgress`: A virtual machine snapshot is being created. + * `Ready`: A snapshot has been created successfully, and now it's available to use. + * `Failed`: An error occurred when creating a virtual machine snapshot. + * `Terminating`: The resource is being deleted. + enum: + - Pending + - InProgress + - Ready + - Failed + - Terminating + type: string + resources: + description: List of snapshot resources. + items: + properties: + apiVersion: + description: API version of the resource. + type: string + kind: + description: Kind of the resource. + type: string + name: + description: Name of the resource. + type: string + type: object + type: array + virtualDiskSnapshotNames: + description: List of VirtualDiskSnapshot names for the snapshots taken + from the virtual disks of the associated virtual machine. + items: type: string - required: - - phase - type: object - required: - - spec - type: object - served: true - storage: true - subresources: - status: {} + type: array + virtualMachineSnapshotSecretName: + description: Name of the underlying `Secret` created for virtual machine + snapshotting. + type: string + required: + - phase + type: object + required: + - spec + type: object + served: true + storage: true + subresources: + status: {} diff --git a/images/virtualization-artifact/pkg/apiserver/api/generated/openapi/zz_generated.openapi.go b/images/virtualization-artifact/pkg/apiserver/api/generated/openapi/zz_generated.openapi.go index cbf532813d..6441b5efef 100644 --- a/images/virtualization-artifact/pkg/apiserver/api/generated/openapi/zz_generated.openapi.go +++ b/images/virtualization-artifact/pkg/apiserver/api/generated/openapi/zz_generated.openapi.go @@ -1974,14 +1974,14 @@ func schema_virtualization_api_core_v1alpha2_SizingPolicy(ref common.ReferenceCa }, "coreFractions": { SchemaProps: spec.SchemaProps{ - Description: "Allowed values of the `coreFraction` parameter.", + Description: "Allowed values of the `coreFraction` parameter in percentages (e.g., \"5%\", \"10%\", \"25%\", \"50%\", \"100%\").", Type: []string{"array"}, Items: &spec.SchemaOrArray{ Schema: &spec.Schema{ SchemaProps: spec.SchemaProps{ - Default: 0, - Type: []string{"integer"}, - Format: "int32", + Default: "", + Type: []string{"string"}, + Format: "", }, }, }, diff --git a/images/virtualization-artifact/pkg/controller/service/size_policy_service.go b/images/virtualization-artifact/pkg/controller/service/size_policy_service.go index df49f9c727..50bd28763e 100644 --- a/images/virtualization-artifact/pkg/controller/service/size_policy_service.go +++ b/images/virtualization-artifact/pkg/controller/service/size_policy_service.go @@ -77,8 +77,8 @@ func validateCoreFraction(vm *v1alpha2.VirtualMachine, sp *v1alpha2.SizingPolicy return } - fractionStr := strings.ReplaceAll(vm.Spec.CPU.CoreFraction, "%", "") - fraction, err := strconv.Atoi(fractionStr) + vmFractionStr := strings.ReplaceAll(vm.Spec.CPU.CoreFraction, "%", "") + vmFraction, err := strconv.Atoi(vmFractionStr) if err != nil { errorsArray = append(errorsArray, fmt.Errorf("unable to parse CPU core fraction: %w", err)) return @@ -86,13 +86,19 @@ func validateCoreFraction(vm *v1alpha2.VirtualMachine, sp *v1alpha2.SizingPolicy hasFractionValueInPolicy := false for _, spFraction := range sp.CoreFractions { - if fraction == int(spFraction) { + policyFractionStr := strings.ReplaceAll(string(spFraction), "%", "") + policyFraction, err := strconv.Atoi(policyFractionStr) + if err != nil { + continue + } + if vmFraction == policyFraction { hasFractionValueInPolicy = true + break } } if !hasFractionValueInPolicy { - errorsArray = append(errorsArray, fmt.Errorf("VM core fraction value %d is not within the allowed values", fraction)) + errorsArray = append(errorsArray, fmt.Errorf("VM core fraction value %d%% is not within the allowed values", vmFraction)) } return diff --git a/images/virtualization-artifact/pkg/controller/service/size_policy_service_test.go b/images/virtualization-artifact/pkg/controller/service/size_policy_service_test.go index 171a04b7e7..bd460cc3ce 100644 --- a/images/virtualization-artifact/pkg/controller/service/size_policy_service_test.go +++ b/images/virtualization-artifact/pkg/controller/service/size_policy_service_test.go @@ -272,7 +272,7 @@ var _ = Describe("SizePolicyService", func() { SizingPolicies: []v1alpha2.SizingPolicy{ { Cores: &v1alpha2.SizingPolicyCores{Min: 1, Max: 4}, - CoreFractions: []v1alpha2.CoreFractionValue{10, 25, 50, 100}, + CoreFractions: []v1alpha2.CoreFractionValue{"10%", "25%", "50%", "100%"}, }, }, }, @@ -302,7 +302,7 @@ var _ = Describe("SizePolicyService", func() { SizingPolicies: []v1alpha2.SizingPolicy{ { Cores: &v1alpha2.SizingPolicyCores{Min: 1, Max: 4}, - CoreFractions: []v1alpha2.CoreFractionValue{10, 25, 50, 100}, + CoreFractions: []v1alpha2.CoreFractionValue{"10%", "25%", "50%", "100%"}, }, }, }, diff --git a/images/virtualization-artifact/pkg/migration/core_fractions_format.go b/images/virtualization-artifact/pkg/migration/core_fractions_format.go new file mode 100644 index 0000000000..b1e283350e --- /dev/null +++ b/images/virtualization-artifact/pkg/migration/core_fractions_format.go @@ -0,0 +1,138 @@ +/* +Copyright 2025 Flant JSC + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. +*/ + +package migration + +import ( + "context" + "fmt" + "log/slog" + "strconv" + "strings" + + "k8s.io/apimachinery/pkg/types" + "sigs.k8s.io/controller-runtime/pkg/client" + + "github.com/deckhouse/deckhouse/pkg/log" + "github.com/deckhouse/virtualization-controller/pkg/common/patch" + "github.com/deckhouse/virtualization/api/core/v1alpha2" +) + +const ( + coreFractionsFormatMigrationName = "core-fractions-format" +) + +func newCoreFractionsFormat(client client.Client, logger *log.Logger) (Migration, error) { + return &coreFractionsFormat{ + client: client, + logger: logger, + }, nil +} + +type coreFractionsFormat struct { + client client.Client + logger *log.Logger +} + +func (m *coreFractionsFormat) Name() string { + return coreFractionsFormatMigrationName +} + +func (m *coreFractionsFormat) Migrate(ctx context.Context) error { + vmcList := &v1alpha2.VirtualMachineClassList{} + if err := m.client.List(ctx, vmcList); err != nil { + return fmt.Errorf("failed to list VirtualMachineClasses: %w", err) + } + + for i := range vmcList.Items { + vmc := &vmcList.Items[i] + + needUpdate, genPatch, err := m.genPatch(vmc) + if err != nil { + return fmt.Errorf("failed to generate patch for VMClass %s: %w", vmc.Name, err) + } + if !needUpdate { + continue + } + + m.logger.Info("Migrating VMClass coreFractions format", + slog.String("name", vmc.Name), + ) + + if m.logger.GetLevel() <= log.LevelDebug { + if data, err := genPatch.Data(vmc); err == nil { + m.logger.Debug("Patch VMClass", + slog.String("name", vmc.Name), + slog.String("data", string(data)), + ) + } + } + + if err := m.client.Patch(ctx, vmc, genPatch); err != nil { + return fmt.Errorf("failed to patch VMClass %s: %w", vmc.Name, err) + } + } + + return nil +} + +func (m *coreFractionsFormat) genPatch(vmc *v1alpha2.VirtualMachineClass) (bool, client.Patch, error) { + var ops []patch.JSONPatchOperation + + for policyIdx, policy := range vmc.Spec.SizingPolicies { + if len(policy.CoreFractions) == 0 { + continue + } + + for fractionIdx, fraction := range policy.CoreFractions { + newValue, changed := normalizeCoreFraction(string(fraction)) + if !changed { + continue + } + + ops = append(ops, patch.NewJSONPatchOperation( + patch.PatchReplaceOp, + fmt.Sprintf("/spec/sizingPolicies/%d/coreFractions/%d", policyIdx, fractionIdx), + newValue, + )) + } + } + + if len(ops) == 0 { + return false, nil, nil + } + + bytes, err := patch.NewJSONPatch(ops...).Bytes() + if err != nil { + return false, nil, fmt.Errorf("failed to create JSON patch: %w", err) + } + + return true, client.RawPatch(types.JSONPatchType, bytes), nil +} + +func normalizeCoreFraction(value string) (string, bool) { + trimmed := strings.TrimSpace(value) + + if strings.HasSuffix(trimmed, "%") { + return trimmed, false + } + + if num, err := strconv.Atoi(trimmed); err == nil && num >= 1 && num <= 100 { + return fmt.Sprintf("%d%%", num), true + } + + return value, false +} diff --git a/images/virtualization-artifact/pkg/migration/core_fractions_format_test.go b/images/virtualization-artifact/pkg/migration/core_fractions_format_test.go new file mode 100644 index 0000000000..af187188eb --- /dev/null +++ b/images/virtualization-artifact/pkg/migration/core_fractions_format_test.go @@ -0,0 +1,242 @@ +/* +Copyright 2025 Flant JSC + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. +*/ + +package migration + +import ( + "context" + "testing" + + . "github.com/onsi/ginkgo/v2" + . "github.com/onsi/gomega" + metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" + "k8s.io/apimachinery/pkg/types" + "sigs.k8s.io/controller-runtime/pkg/client" + + "github.com/deckhouse/virtualization-controller/pkg/common/testutil" + "github.com/deckhouse/virtualization/api/core/v1alpha2" +) + +func TestCoreFractionsFormat(t *testing.T) { + RegisterFailHandler(Fail) + RunSpecs(t, "CoreFractionsFormat Migration Suite") +} + +var _ = Describe("CoreFractionsFormat Migration", func() { + var ( + ctx context.Context + client client.Client + ) + + BeforeEach(func() { + ctx = context.Background() + var err error + client, err = testutil.NewFakeClientWithObjects() + Expect(err).NotTo(HaveOccurred()) + }) + + Context("normalizeCoreFraction", func() { + It("should add % sign to plain integer values", func() { + result, changed := normalizeCoreFraction("5") + Expect(changed).To(BeTrue()) + Expect(result).To(Equal("5%")) + + result, changed = normalizeCoreFraction("10") + Expect(changed).To(BeTrue()) + Expect(result).To(Equal("10%")) + + result, changed = normalizeCoreFraction("100") + Expect(changed).To(BeTrue()) + Expect(result).To(Equal("100%")) + }) + + It("should not change values that already have % sign", func() { + result, changed := normalizeCoreFraction("5%") + Expect(changed).To(BeFalse()) + Expect(result).To(Equal("5%")) + + result, changed = normalizeCoreFraction("25%") + Expect(changed).To(BeFalse()) + Expect(result).To(Equal("25%")) + }) + + It("should handle values with spaces", func() { + result, changed := normalizeCoreFraction(" 10 ") + Expect(changed).To(BeTrue()) + Expect(result).To(Equal("10%")) + + result, changed = normalizeCoreFraction(" 50% ") + Expect(changed).To(BeFalse()) + Expect(result).To(Equal("50%")) + }) + + It("should not change invalid values", func() { + result, changed := normalizeCoreFraction("invalid") + Expect(changed).To(BeFalse()) + Expect(result).To(Equal("invalid")) + + result, changed = normalizeCoreFraction("0") + Expect(changed).To(BeFalse()) + Expect(result).To(Equal("0")) + + result, changed = normalizeCoreFraction("101") + Expect(changed).To(BeFalse()) + Expect(result).To(Equal("101")) + }) + }) + + Context("Migrate", func() { + It("should migrate VMClass with plain integer coreFractions", func() { + vmc := &v1alpha2.VirtualMachineClass{ + ObjectMeta: metav1.ObjectMeta{ + Name: "test-class", + }, + Spec: v1alpha2.VirtualMachineClassSpec{ + CPU: v1alpha2.CPU{Type: v1alpha2.CPUTypeHost}, + SizingPolicies: []v1alpha2.SizingPolicy{ + { + Cores: &v1alpha2.SizingPolicyCores{Min: 1, Max: 4}, + CoreFractions: []v1alpha2.CoreFractionValue{"5", "10", "25", "50", "100"}, + }, + }, + }, + } + + err := client.Create(ctx, vmc) + Expect(err).NotTo(HaveOccurred()) + + migration, err := newCoreFractionsFormat(client, testutil.NewNoOpLogger()) + Expect(err).NotTo(HaveOccurred()) + + err = migration.Migrate(ctx) + Expect(err).NotTo(HaveOccurred()) + + updated := &v1alpha2.VirtualMachineClass{} + err = client.Get(ctx, types.NamespacedName{Name: vmc.Name}, updated) + Expect(err).NotTo(HaveOccurred()) + + Expect(updated.Spec.SizingPolicies[0].CoreFractions).To(Equal([]v1alpha2.CoreFractionValue{ + "5%", "10%", "25%", "50%", "100%", + })) + }) + + It("should not change VMClass with already formatted coreFractions", func() { + vmc := &v1alpha2.VirtualMachineClass{ + ObjectMeta: metav1.ObjectMeta{ + Name: "test-class-formatted", + }, + Spec: v1alpha2.VirtualMachineClassSpec{ + CPU: v1alpha2.CPU{Type: v1alpha2.CPUTypeHost}, + SizingPolicies: []v1alpha2.SizingPolicy{ + { + Cores: &v1alpha2.SizingPolicyCores{Min: 1, Max: 4}, + CoreFractions: []v1alpha2.CoreFractionValue{"5%", "10%", "25%", "50%", "100%"}, + }, + }, + }, + } + + err := client.Create(ctx, vmc) + Expect(err).NotTo(HaveOccurred()) + + migration, err := newCoreFractionsFormat(client, testutil.NewNoOpLogger()) + Expect(err).NotTo(HaveOccurred()) + + err = migration.Migrate(ctx) + Expect(err).NotTo(HaveOccurred()) + + updated := &v1alpha2.VirtualMachineClass{} + err = client.Get(ctx, types.NamespacedName{Name: vmc.Name}, updated) + Expect(err).NotTo(HaveOccurred()) + + Expect(updated.Spec.SizingPolicies[0].CoreFractions).To(Equal([]v1alpha2.CoreFractionValue{ + "5%", "10%", "25%", "50%", "100%", + })) + }) + + It("should handle VMClass with multiple sizing policies", func() { + vmc := &v1alpha2.VirtualMachineClass{ + ObjectMeta: metav1.ObjectMeta{ + Name: "test-class-multi", + }, + Spec: v1alpha2.VirtualMachineClassSpec{ + CPU: v1alpha2.CPU{Type: v1alpha2.CPUTypeHost}, + SizingPolicies: []v1alpha2.SizingPolicy{ + { + Cores: &v1alpha2.SizingPolicyCores{Min: 1, Max: 4}, + CoreFractions: []v1alpha2.CoreFractionValue{"5", "10", "25"}, + }, + { + Cores: &v1alpha2.SizingPolicyCores{Min: 5, Max: 8}, + CoreFractions: []v1alpha2.CoreFractionValue{"50", "100"}, + }, + }, + }, + } + + err := client.Create(ctx, vmc) + Expect(err).NotTo(HaveOccurred()) + + migration, err := newCoreFractionsFormat(client, testutil.NewNoOpLogger()) + Expect(err).NotTo(HaveOccurred()) + + err = migration.Migrate(ctx) + Expect(err).NotTo(HaveOccurred()) + + updated := &v1alpha2.VirtualMachineClass{} + err = client.Get(ctx, types.NamespacedName{Name: vmc.Name}, updated) + Expect(err).NotTo(HaveOccurred()) + + Expect(updated.Spec.SizingPolicies[0].CoreFractions).To(Equal([]v1alpha2.CoreFractionValue{ + "5%", "10%", "25%", + })) + Expect(updated.Spec.SizingPolicies[1].CoreFractions).To(Equal([]v1alpha2.CoreFractionValue{ + "50%", "100%", + })) + }) + + It("should handle VMClass without coreFractions", func() { + vmc := &v1alpha2.VirtualMachineClass{ + ObjectMeta: metav1.ObjectMeta{ + Name: "test-class-no-fractions", + }, + Spec: v1alpha2.VirtualMachineClassSpec{ + CPU: v1alpha2.CPU{Type: v1alpha2.CPUTypeHost}, + SizingPolicies: []v1alpha2.SizingPolicy{ + { + Cores: &v1alpha2.SizingPolicyCores{Min: 1, Max: 4}, + }, + }, + }, + } + + err := client.Create(ctx, vmc) + Expect(err).NotTo(HaveOccurred()) + + migration, err := newCoreFractionsFormat(client, testutil.NewNoOpLogger()) + Expect(err).NotTo(HaveOccurred()) + + err = migration.Migrate(ctx) + Expect(err).NotTo(HaveOccurred()) + + updated := &v1alpha2.VirtualMachineClass{} + err = client.Get(ctx, types.NamespacedName{Name: vmc.Name}, updated) + Expect(err).NotTo(HaveOccurred()) + + Expect(updated.Spec.SizingPolicies[0].CoreFractions).To(BeNil()) + }) + }) +}) diff --git a/images/virtualization-artifact/pkg/migration/migration.go b/images/virtualization-artifact/pkg/migration/migration.go index 601acb1c90..ea566803d2 100644 --- a/images/virtualization-artifact/pkg/migration/migration.go +++ b/images/virtualization-artifact/pkg/migration/migration.go @@ -31,6 +31,7 @@ type constructor func(client client.Client, logger *log.Logger) (Migration, erro var newMigrations = []constructor{ newQEMUMaxLength36, + newCoreFractionsFormat, } type Migration interface { diff --git a/templates/virtualization-controller/vmclasses-default.yaml b/templates/virtualization-controller/vmclasses-default.yaml index f2beb27764..6da6926e0f 100644 --- a/templates/virtualization-controller/vmclasses-default.yaml +++ b/templates/virtualization-controller/vmclasses-default.yaml @@ -16,19 +16,19 @@ spec: min: 1 max: 4 dedicatedCores: [false] - coreFractions: [5, 10, 20, 50, 100] + coreFractions: ["5%", "10%", "20%", "50%", "100%"] - cores: min: 5 max: 8 dedicatedCores: [false] - coreFractions: [20, 50, 100] + coreFractions: ["20%", "50%", "100%"] - cores: min: 9 max: 16 dedicatedCores: [true, false] - coreFractions: [50, 100] + coreFractions: ["50%", "100%"] - cores: min: 17 max: 1024 dedicatedCores: [true, false] - coreFractions: [100] + coreFractions: ["100%"] diff --git a/tests/e2e/testdata/sizing-policy/vmc.yaml b/tests/e2e/testdata/sizing-policy/vmc.yaml index 48baa39771..8795b57033 100644 --- a/tests/e2e/testdata/sizing-policy/vmc.yaml +++ b/tests/e2e/testdata/sizing-policy/vmc.yaml @@ -18,11 +18,11 @@ spec: - worker sizingPolicies: - coreFractions: - - 5 - - 10 - - 20 - - 50 - - 100 + - "5%" + - "10%" + - "20%" + - "50%" + - "100%" cores: max: 4 min: 1 @@ -33,9 +33,9 @@ spec: min: 1Gi step: 512Mi - coreFractions: - - 20 - - 50 - - 100 + - "20%" + - "50%" + - "100%" cores: max: 8 min: 5 @@ -46,8 +46,8 @@ spec: min: 5Gi step: 1Gi - coreFractions: - - 50 - - 100 + - "50%" + - "100%" cores: max: 16 min: 9 @@ -59,7 +59,7 @@ spec: min: 9Gi step: 1Gi - coreFractions: - - 100 + - "100%" cores: max: 1024 min: 17 From 58498a2bc0365ed4e51f224be05c753fa20a98f7 Mon Sep 17 00:00:00 2001 From: Daniil Loktev Date: Mon, 20 Oct 2025 18:47:13 +0300 Subject: [PATCH 02/77] wip Signed-off-by: Daniil Loktev --- api/core/v1alpha2/virtual_machine_class.go | 8 +- api/core/v1alpha3/doc.go | 22 + api/core/v1alpha3/register.go | 64 +++ api/core/v1alpha3/virtual_machine_class.go | 244 +++++++++ .../v1alpha3/vmclasscondition/condition.go | 51 ++ api/scripts/update-codegen.sh | 4 +- crds/virtualmachineclasses.yaml | 490 +++++++++++++++++- .../cmd/virtualization-controller/main.go | 2 + .../controller/vmclass/vmclass_controller.go | 3 + .../controller/vmclass/vmclass_conversion.go | 317 +++++++++++ .../pkg/migration/core_fractions_format.go | 138 ----- .../migration/core_fractions_format_test.go | 242 --------- .../pkg/migration/migration.go | 1 - .../vmclasses-default.yaml | 2 +- 14 files changed, 1197 insertions(+), 391 deletions(-) create mode 100644 api/core/v1alpha3/doc.go create mode 100644 api/core/v1alpha3/register.go create mode 100644 api/core/v1alpha3/virtual_machine_class.go create mode 100644 api/core/v1alpha3/vmclasscondition/condition.go create mode 100644 images/virtualization-artifact/pkg/controller/vmclass/vmclass_conversion.go delete mode 100644 images/virtualization-artifact/pkg/migration/core_fractions_format.go delete mode 100644 images/virtualization-artifact/pkg/migration/core_fractions_format_test.go diff --git a/api/core/v1alpha2/virtual_machine_class.go b/api/core/v1alpha2/virtual_machine_class.go index 21f83a1e65..9eeaf5d254 100644 --- a/api/core/v1alpha2/virtual_machine_class.go +++ b/api/core/v1alpha2/virtual_machine_class.go @@ -115,7 +115,7 @@ type CpuDiscovery struct { type SizingPolicy struct { // Memory sizing policy. Memory *SizingPolicyMemory `json:"memory,omitempty"` - // Allowed values of the `coreFraction` parameter in percentages (e.g., "5%", "10%", "25%", "50%", "100%"). + // Allowed values of the `coreFraction` parameter. CoreFractions []CoreFractionValue `json:"coreFractions,omitempty"` // Allowed values of the `dedicatedCores` parameter. DedicatedCores []bool `json:"dedicatedCores,omitempty"` @@ -123,9 +123,9 @@ type SizingPolicy struct { Cores *SizingPolicyCores `json:"cores,omitempty"` } -// CoreFractionValue represents CPU core fraction as a percentage string (e.g., "5%", "10%", "25%", "50%", "100%"). -// +kubebuilder:validation:Pattern=`^([1-9]|[1-9][0-9]|100)%?$` -type CoreFractionValue string +// +kubebuilder:validation:Minimum=1 +// +kubebuilder:validation:Maximum=100 +type CoreFractionValue int type SizingPolicyMemory struct { MemoryMinMax `json:",inline"` diff --git a/api/core/v1alpha3/doc.go b/api/core/v1alpha3/doc.go new file mode 100644 index 0000000000..4474f64c7d --- /dev/null +++ b/api/core/v1alpha3/doc.go @@ -0,0 +1,22 @@ +/* +Copyright 2024 Flant JSC + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. +*/ + +// +k8s:deepcopy-gen=package +// +k8s:openapi-gen=true + +// Package v1alpha3 is the v1alpha3 version of the API. +// +groupName=virtualization.deckhouse.io +package v1alpha3 diff --git a/api/core/v1alpha3/register.go b/api/core/v1alpha3/register.go new file mode 100644 index 0000000000..bc2d297ed1 --- /dev/null +++ b/api/core/v1alpha3/register.go @@ -0,0 +1,64 @@ +/* +Copyright 2024 Flant JSC + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. +*/ + +package v1alpha3 + +import ( + metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" + "k8s.io/apimachinery/pkg/runtime" + "k8s.io/apimachinery/pkg/runtime/schema" + + "github.com/deckhouse/virtualization/api/core" +) + +const Version = "v1alpha3" + +// SchemeGroupVersion is group version used to register these objects +var SchemeGroupVersion = schema.GroupVersion{Group: core.GroupName, Version: Version} + +// VirtualMachineClassGVK is group version kind for VirtualMachineClass +var VirtualMachineClassGVK = schema.GroupVersionKind{Group: SchemeGroupVersion.Group, Version: SchemeGroupVersion.Version, Kind: VirtualMachineClassKind} + +// Kind takes an unqualified kind and returns back a Group qualified GroupKind +func Kind(kind string) schema.GroupKind { + return SchemeGroupVersion.WithKind(kind).GroupKind() +} + +// Resource takes an unqualified resource and returns a Group qualified GroupResource +func Resource(resource string) schema.GroupResource { + return SchemeGroupVersion.WithResource(resource).GroupResource() +} + +func GroupVersionResource(resource string) schema.GroupVersionResource { + return SchemeGroupVersion.WithResource(resource) +} + +var ( + // SchemeBuilder tbd + SchemeBuilder = runtime.NewSchemeBuilder(addKnownTypes) + // AddToScheme tbd + AddToScheme = SchemeBuilder.AddToScheme +) + +// Adds the list of known types to Scheme. +func addKnownTypes(scheme *runtime.Scheme) error { + scheme.AddKnownTypes(SchemeGroupVersion, + &VirtualMachineClass{}, + &VirtualMachineClassList{}, + ) + metav1.AddToGroupVersion(scheme, SchemeGroupVersion) + return nil +} diff --git a/api/core/v1alpha3/virtual_machine_class.go b/api/core/v1alpha3/virtual_machine_class.go new file mode 100644 index 0000000000..5fe1e6bbf1 --- /dev/null +++ b/api/core/v1alpha3/virtual_machine_class.go @@ -0,0 +1,244 @@ +/* +Copyright 2024 Flant JSC + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. +*/ + +// +kubebuilder:object:generate=true +// +groupName=virtualization.deckhouse.io +package v1alpha3 + +import ( + corev1 "k8s.io/api/core/v1" + "k8s.io/apimachinery/pkg/api/resource" + metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" +) + +const ( + VirtualMachineClassKind = "VirtualMachineClass" + VirtualMachineClassResource = "virtualmachineclasses" +) + +// VirtualMachineClass resource describes CPU requirements, node placement, and sizing policy for VM resources. +// A resource cannot be deleted as long as it is used in one of the VMs. +// +// +kubebuilder:object:root=true +// +kubebuilder:metadata:labels={heritage=deckhouse,module=virtualization,backup.deckhouse.io/cluster-config=true} +// +kubebuilder:subresource:status +// +kubebuilder:resource:categories={virtualization-cluster},scope=Cluster,shortName={vmc,vmclass},singular=virtualmachineclass +// +kubebuilder:storageversion +// +kubebuilder:printcolumn:name="Phase",type="string",JSONPath=".status.phase",description="VirtualMachineClass phase." +// +kubebuilder:printcolumn:name="IsDefault",type="string",JSONPath=".metadata.annotations.virtualmachineclass\\.virtualization\\.deckhouse\\.io\\/is-default-class",description="Default class for virtual machines without specified class." +// +kubebuilder:printcolumn:name="Age",type="date",JSONPath=".metadata.creationTimestamp",description="Time of resource creation." +// +genclient +// +genclient:nonNamespaced +// +k8s:deepcopy-gen:interfaces=k8s.io/apimachinery/pkg/runtime.Object +type VirtualMachineClass struct { + metav1.TypeMeta `json:",inline"` + metav1.ObjectMeta `json:"metadata,omitempty"` + + Spec VirtualMachineClassSpec `json:"spec"` + Status VirtualMachineClassStatus `json:"status,omitempty"` +} + +// VirtualMachineClassList contains a list of VirtualMachineClasses. +// +k8s:deepcopy-gen:interfaces=k8s.io/apimachinery/pkg/runtime.Object +type VirtualMachineClassList struct { + metav1.TypeMeta `json:",inline"` + metav1.ListMeta `json:"metadata"` + + // Items provides a list of VirtualMachineClasses. + Items []VirtualMachineClass `json:"items"` +} + +type VirtualMachineClassSpec struct { + NodeSelector NodeSelector `json:"nodeSelector,omitempty"` + // Tolerations are the same as `spec.tolerations` for [pods](https://kubernetes.io/docs/concepts/scheduling-eviction/taint-and-toleration/). + // These tolerations will be merged with the tolerations specified in the VirtualMachine resource. VirtualMachine tolerations have a higher priority. + Tolerations []corev1.Toleration `json:"tolerations,omitempty"` + // +kubebuilder:validation:Required + CPU CPU `json:"cpu"` + SizingPolicies []SizingPolicy `json:"sizingPolicies,omitempty"` +} + +// NodeSelector defines the nodes targeted for VM scheduling. +type NodeSelector struct { + // A map of {key,value} pairs. + // A single {key,value} pair in the matchLabels map is equivalent to an element of matchExpressions whose key field is "key", operator is "In", and the value array contains only "value". + // The requirements are ANDed. + MatchLabels map[string]string `json:"matchLabels,omitempty"` + // A list of node selector requirements by node's labels. + MatchExpressions []corev1.NodeSelectorRequirement `json:"matchExpressions,omitempty"` +} + +// CPU defines the requirements for the virtual CPU model. +// +kubebuilder:validation:XValidation:rule="self == oldSelf",message=".spec.cpu is immutable" +// +kubebuilder:validation:XValidation:rule="self.type == 'HostPassthrough' || self.type == 'Host' ? !has(self.model) && !has(self.features) && !has(self.discovery) : true",message="HostPassthrough and Host cannot have model, features or discovery" +// +kubebuilder:validation:XValidation:rule="self.type == 'Discovery' ? !has(self.model) && !has(self.features) : true",message="Discovery cannot have model or features" +// +kubebuilder:validation:XValidation:rule="self.type == 'Model' ? has(self.model) && !has(self.features) && !has(self.discovery) : true",message="Model requires model and cannot have features or discovery" +// +kubebuilder:validation:XValidation:rule="self.type == 'Features' ? has(self.features) && !has(self.model) && !has(self.discovery): true",message="Features requires features and cannot have model or discovery" +type CPU struct { + // +kubebuilder:validation:Required + Type CPUType `json:"type"` + // CPU model name. For more information about CPU models and topology, refer to the [libvirt docs](https://libvirt.org/formatdomain.html#cpu-model-and-topology). + // + // +kubebuilder:validation:MinLength=1 + // +kubebuilder:example=IvyBridge + Model string `json:"model,omitempty"` + // List of CPU instructions (features) required when type=Features. + // For more information about CPU features, refer to the [libvirt docs](https://libvirt.org/formatdomain.html#cpu-model-and-topology). + // + // +kubebuilder:validation:MinItems=1 + // +kubebuilder:example={mmx, vmx, sse2} + Features []string `json:"features,omitempty"` + // Create a CPU model based on intersecting CPU features for selected nodes. + Discovery CpuDiscovery `json:"discovery,omitempty"` +} + +type CpuDiscovery struct { + // A selection of nodes to be used as the basis for creating a universal CPU model. + NodeSelector metav1.LabelSelector `json:"nodeSelector,omitempty"` +} + +// SizingPolicy defines a policy for allocating computational resources to VMs. +// It is represented as a list. +// The cores.min - cores.max ranges for different elements of the list must not overlap. +type SizingPolicy struct { + // Memory sizing policy. + Memory *SizingPolicyMemory `json:"memory,omitempty"` + // Allowed values of the `coreFraction` parameter in percentages (e.g., "5%", "10%", "25%", "50%", "100%"). + CoreFractions []CoreFractionValue `json:"coreFractions,omitempty"` + // Allowed values of the `dedicatedCores` parameter. + DedicatedCores []bool `json:"dedicatedCores,omitempty"` + // The policy applies for a specified range of the number of CPU cores. + Cores *SizingPolicyCores `json:"cores,omitempty"` +} + +// CoreFractionValue represents CPU core fraction as a percentage string (e.g., "5%", "10%", "25%", "50%", "100%"). +// +kubebuilder:validation:Pattern=`^([1-9]|[1-9][0-9]|100)%?$` +type CoreFractionValue string + +type SizingPolicyMemory struct { + MemoryMinMax `json:",inline"` + // Memory size discretization step. For example, the combination of `min=2Gi, `max=4Gi` and `step=1Gi` allows to set the virtual machine memory size to 2Gi, 3Gi, or 4Gi. + // + // +kubebuilder:example="512Mi" + Step resource.Quantity `json:"step,omitempty"` + + // Amount of memory per CPU core. + PerCore SizingPolicyMemoryPerCore `json:"perCore,omitempty"` +} + +type SizingPolicyMemoryPerCore struct { + MemoryMinMax `json:",inline"` +} + +type MemoryMinMax struct { + // Minimum amount of memory. + // + // +kubebuilder:example="1Gi" + Min resource.Quantity `json:"min,omitempty"` + // Maximum amount of memory. + // + // +kubebuilder:example="8Gi" + Max resource.Quantity `json:"max,omitempty"` +} + +// +kubebuilder:validation:XValidation:rule="self.max > self.min",message="The maximum must be greater than the minimum" +// +kubebuilder:validation:XValidation:rule="has(self.step) ? self.max > self.step : true",message="The maximum must be greater than the step" +type SizingPolicyCores struct { + // Minimum number of CPU cores. + // + // +kubebuilder:validation:Required + // +kubebuilder:validation:Minimum=1 + // +kubebuilder:example=1 + Min int `json:"min"` + // Maximum number of CPU cores. + // + // +kubebuilder:validation:Required + // +kubebuilder:validation:Maximum=1024 + // +kubebuilder:example=10 + Max int `json:"max"` + // Discretization step for the CPU core number. For example, the combination of `min=2`, `max=10`, and `step=4` allows to set the number of virtual machine CPU cores to 2, 6, or 10. + // + // +kubebuilder:validation:Minimum=1 + // +kubebuilder:example=1 + Step int `json:"step,omitempty"` +} + +// CPUType defines the CPU type, the following options are supported: +// * `Host`: Uses a virtual CPU with an instruction set closely matching the platform node's CPU. +// This provides high performance and functionality, as well as compatibility with "live" migration for nodes with similar processor types. +// For example, VM migration between nodes with Intel and AMD processors will not work. +// This is also true for different CPU generations, as their instruction set is different. +// * `HostPassthrough`: Uses the platform node's physical CPU directly, without any modifications. +// When using this class, the guest VM can only be transferred to a target node with a CPU exactly matching the source node's CPU. +// * `Discovery`: Create a virtual CPU based on instruction sets of physical CPUs for a selected set of nodes. +// * `Model`: CPU model. A CPU model is a named and previously defined set of supported CPU instructions. +// * `Features`: A required set of supported instructions for the CPU. +// +// +kubebuilder:validation:Enum={Host,HostPassthrough,Discovery,Model,Features} +type CPUType string + +const ( + CPUTypeHost CPUType = "Host" + CPUTypeHostPassthrough CPUType = "HostPassthrough" + CPUTypeDiscovery CPUType = "Discovery" + CPUTypeModel CPUType = "Model" + CPUTypeFeatures CPUType = "Features" +) + +type VirtualMachineClassStatus struct { + Phase VirtualMachineClassPhase `json:"phase"` + CpuFeatures CpuFeatures `json:"cpuFeatures,omitempty"` + // List of nodes that support this CPU model. + // It is not displayed for the following types: `Host`, `HostPassthrough`. + // + // +kubebuilder:example={node-1, node-2} + AvailableNodes []string `json:"availableNodes,omitempty"` + // Maximum amount of free CPU and memory resources observed among all available nodes. + // +kubebuilder:example={"maxAllocatableResources: {\"cpu\": 1, \"memory\": \"10Gi\"}"} + MaxAllocatableResources corev1.ResourceList `json:"maxAllocatableResources,omitempty"` + // The latest detailed observations of the VirtualMachineClass resource. + Conditions []metav1.Condition `json:"conditions,omitempty"` + // Resource generation last processed by the controller. + ObservedGeneration int64 `json:"observedGeneration,omitempty"` +} + +// CpuFeatures +// Information on CPU features supported by this model. +// Shown only for `Features` or `Discovery` types. +type CpuFeatures struct { + // List of CPU features for this model. + // + // +kubebuilder:example={mmx, vmx, sse2} + Enabled []string `json:"enabled,omitempty"` + // List of unused processor features additionally available for a given group of nodes. + // + // +kubebuilder:example={ssse3, vme} + NotEnabledCommon []string `json:"notEnabledCommon,omitempty"` +} + +// VirtualMachineClassPhase defines the current resource status: +// * `Pending`: The resource is not ready and waits until the suitable nodes supporting the required CPU model are available. +// * `Ready`: The resource is ready and available for use. +// * `Terminating`: The resource is terminating. +// +// +kubebuilder:validation:Enum={Pending,Ready,Terminating} +type VirtualMachineClassPhase string + +const ( + ClassPhasePending VirtualMachineClassPhase = "Pending" + ClassPhaseReady VirtualMachineClassPhase = "Ready" + ClassPhaseTerminating VirtualMachineClassPhase = "Terminating" +) diff --git a/api/core/v1alpha3/vmclasscondition/condition.go b/api/core/v1alpha3/vmclasscondition/condition.go new file mode 100644 index 0000000000..14fef998c2 --- /dev/null +++ b/api/core/v1alpha3/vmclasscondition/condition.go @@ -0,0 +1,51 @@ +/* +Copyright 2024 Flant JSC + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. +*/ + +package vmclasscondition + +type Type string + +func (t Type) String() string { + return string(t) +} + +const ( + TypeReady Type = "Ready" + TypeDiscovered Type = "Discovered" + TypeInUse Type = "InUse" +) + +type Reason string + +func (r Reason) String() string { + return string(r) +} + +const ( + // ReasonNoCpuFeaturesEnabled determines that processor functions are not available. + ReasonNoCpuFeaturesEnabled Reason = "NoCpuFeaturesEnabled" + // ReasonNoSuitableNodesFound determines that no suitable node has been found. + ReasonNoSuitableNodesFound Reason = "NoSuitableNodesFound" + // ReasonSuitableNodesFound determines that suitable node has been found. + ReasonSuitableNodesFound Reason = "SuitableNodesFound" + + ReasonDiscoverySucceeded Reason = "DiscoverySucceeded" + ReasonDiscoverySkip Reason = "DiscoverySkip" + ReasonDiscoveryFailed Reason = "DiscoveryFailed" + + // ReasonVMClassInUse is the event reason indicating that the VMClass is being used by a virtual machine. + ReasonVMClassInUse Reason = "VirtualMachineClassInUse" +) diff --git a/api/scripts/update-codegen.sh b/api/scripts/update-codegen.sh index 759cacea8f..7b4c4008d7 100755 --- a/api/scripts/update-codegen.sh +++ b/api/scripts/update-codegen.sh @@ -55,7 +55,7 @@ function generate::subresources { --output-file "zz_generated.openapi.go" \ --go-header-file "${SCRIPT_DIR}/boilerplate.go.txt" \ -r /dev/null \ - "${THIS_PKG}/core/v1alpha2" "${THIS_PKG}/subresources/v1alpha2" "kubevirt.io/api/core/v1" "k8s.io/apiextensions-apiserver/pkg/apis/apiextensions/v1" "k8s.io/api/core/v1" "k8s.io/apimachinery/pkg/apis/meta/v1" "k8s.io/apimachinery/pkg/api/resource" "k8s.io/apimachinery/pkg/version" + "${THIS_PKG}/core/v1alpha2" "${THIS_PKG}/core/v1alpha3" "${THIS_PKG}/subresources/v1alpha2" "kubevirt.io/api/core/v1" "k8s.io/apiextensions-apiserver/pkg/apis/apiextensions/v1" "k8s.io/api/core/v1" "k8s.io/apimachinery/pkg/apis/meta/v1" "k8s.io/apimachinery/pkg/api/resource" "k8s.io/apimachinery/pkg/version" } function generate::core { @@ -75,7 +75,7 @@ function generate::crds { OUTPUT_BASE=$(mktemp -d) trap 'rm -rf "${OUTPUT_BASE}"' ERR EXIT - go tool controller-gen crd paths="${API_ROOT}/core/v1alpha2/..." output:crd:dir="${OUTPUT_BASE}" + go tool controller-gen crd paths="${API_ROOT}/core/v1alpha2/...;${API_ROOT}/core/v1alpha3/..." output:crd:dir="${OUTPUT_BASE}" # shellcheck disable=SC2044 for file in $(find "${OUTPUT_BASE}"/* -type f -iname "*.yaml"); do diff --git a/crds/virtualmachineclasses.yaml b/crds/virtualmachineclasses.yaml index 2585375c6d..4aa4d647f4 100644 --- a/crds/virtualmachineclasses.yaml +++ b/crds/virtualmachineclasses.yaml @@ -22,6 +22,17 @@ spec: - vmclass singular: virtualmachineclass scope: Cluster + conversion: + strategy: Webhook + webhook: + clientConfig: + service: + name: virtualization-controller + namespace: d8-virtualization + path: /convert/virtualmachineclasses + port: 443 + conversionReviewVersions: + - v1 versions: - additionalPrinterColumns: - description: VirtualMachineClass phase. @@ -217,6 +228,479 @@ spec: The requirements are ANDed. type: object type: object + sizingPolicies: + items: + description: |- + SizingPolicy defines a policy for allocating computational resources to VMs. + It is represented as a list. + The cores.min - cores.max ranges for different elements of the list must not overlap. + properties: + coreFractions: + description: Allowed values of the `coreFraction` parameter. + items: + maximum: 100 + minimum: 1 + type: integer + type: array + cores: + description: The policy applies for a specified range of the + number of CPU cores. + properties: + max: + description: Maximum number of CPU cores. + example: 10 + maximum: 1024 + type: integer + min: + description: Minimum number of CPU cores. + example: 1 + minimum: 1 + type: integer + step: + description: Discretization step for the CPU core number. + For example, the combination of `min=2`, `max=10`, and + `step=4` allows to set the number of virtual machine CPU + cores to 2, 6, or 10. + example: 1 + minimum: 1 + type: integer + required: + - max + - min + type: object + x-kubernetes-validations: + - message: The maximum must be greater than the minimum + rule: self.max > self.min + - message: The maximum must be greater than the step + rule: 'has(self.step) ? self.max > self.step : true' + dedicatedCores: + description: Allowed values of the `dedicatedCores` parameter. + items: + type: boolean + type: array + memory: + description: Memory sizing policy. + properties: + max: + anyOf: + - type: integer + - type: string + description: Maximum amount of memory. + example: 8Gi + pattern: ^(\+|-)?(([0-9]+(\.[0-9]*)?)|(\.[0-9]+))(([KMGTPE]i)|[numkMGTPE]|([eE](\+|-)?(([0-9]+(\.[0-9]*)?)|(\.[0-9]+))))?$ + x-kubernetes-int-or-string: true + min: + anyOf: + - type: integer + - type: string + description: Minimum amount of memory. + example: 1Gi + pattern: ^(\+|-)?(([0-9]+(\.[0-9]*)?)|(\.[0-9]+))(([KMGTPE]i)|[numkMGTPE]|([eE](\+|-)?(([0-9]+(\.[0-9]*)?)|(\.[0-9]+))))?$ + x-kubernetes-int-or-string: true + perCore: + description: Amount of memory per CPU core. + properties: + max: + anyOf: + - type: integer + - type: string + description: Maximum amount of memory. + example: 8Gi + pattern: ^(\+|-)?(([0-9]+(\.[0-9]*)?)|(\.[0-9]+))(([KMGTPE]i)|[numkMGTPE]|([eE](\+|-)?(([0-9]+(\.[0-9]*)?)|(\.[0-9]+))))?$ + x-kubernetes-int-or-string: true + min: + anyOf: + - type: integer + - type: string + description: Minimum amount of memory. + example: 1Gi + pattern: ^(\+|-)?(([0-9]+(\.[0-9]*)?)|(\.[0-9]+))(([KMGTPE]i)|[numkMGTPE]|([eE](\+|-)?(([0-9]+(\.[0-9]*)?)|(\.[0-9]+))))?$ + x-kubernetes-int-or-string: true + type: object + step: + anyOf: + - type: integer + - type: string + description: Memory size discretization step. For example, + the combination of `min=2Gi, `max=4Gi` and `step=1Gi` + allows to set the virtual machine memory size to 2Gi, + 3Gi, or 4Gi. + example: 512Mi + pattern: ^(\+|-)?(([0-9]+(\.[0-9]*)?)|(\.[0-9]+))(([KMGTPE]i)|[numkMGTPE]|([eE](\+|-)?(([0-9]+(\.[0-9]*)?)|(\.[0-9]+))))?$ + x-kubernetes-int-or-string: true + type: object + type: object + type: array + tolerations: + description: |- + Tolerations are the same as `spec.tolerations` for [pods](https://kubernetes.io/docs/concepts/scheduling-eviction/taint-and-toleration/). + These tolerations will be merged with the tolerations specified in the VirtualMachine resource. VirtualMachine tolerations have a higher priority. + items: + description: |- + The pod this Toleration is attached to tolerates any taint that matches + the triple using the matching operator . + properties: + effect: + description: |- + Effect indicates the taint effect to match. Empty means match all taint effects. + When specified, allowed values are NoSchedule, PreferNoSchedule and NoExecute. + type: string + key: + description: |- + Key is the taint key that the toleration applies to. Empty means match all taint keys. + If the key is empty, operator must be Exists; this combination means to match all values and all keys. + type: string + operator: + description: |- + Operator represents a key's relationship to the value. + Valid operators are Exists and Equal. Defaults to Equal. + Exists is equivalent to wildcard for value, so that a pod can + tolerate all taints of a particular category. + type: string + tolerationSeconds: + description: |- + TolerationSeconds represents the period of time the toleration (which must be + of effect NoExecute, otherwise this field is ignored) tolerates the taint. By default, + it is not set, which means tolerate the taint forever (do not evict). Zero and + negative values will be treated as 0 (evict immediately) by the system. + format: int64 + type: integer + value: + description: |- + Value is the taint value the toleration matches to. + If the operator is Exists, the value should be empty, otherwise just a regular string. + type: string + type: object + type: array + required: + - cpu + type: object + status: + properties: + availableNodes: + description: |- + List of nodes that support this CPU model. + It is not displayed for the following types: `Host`, `HostPassthrough`. + example: + - node-1 + - node-2 + items: + type: string + type: array + conditions: + description: The latest detailed observations of the VirtualMachineClass + resource. + items: + description: Condition contains details for one aspect of the current + state of this API Resource. + properties: + lastTransitionTime: + description: |- + lastTransitionTime is the last time the condition transitioned from one status to another. + This should be when the underlying condition changed. If that is not known, then using the time when the API field changed is acceptable. + format: date-time + type: string + message: + description: |- + message is a human readable message indicating details about the transition. + This may be an empty string. + maxLength: 32768 + type: string + observedGeneration: + description: |- + observedGeneration represents the .metadata.generation that the condition was set based upon. + For instance, if .metadata.generation is currently 12, but the .status.conditions[x].observedGeneration is 9, the condition is out of date + with respect to the current state of the instance. + format: int64 + minimum: 0 + type: integer + reason: + description: |- + reason contains a programmatic identifier indicating the reason for the condition's last transition. + Producers of specific condition types may define expected values and meanings for this field, + and whether the values are considered a guaranteed API. + The value should be a CamelCase string. + This field may not be empty. + maxLength: 1024 + minLength: 1 + pattern: ^[A-Za-z]([A-Za-z0-9_,:]*[A-Za-z0-9_])?$ + type: string + status: + description: status of the condition, one of True, False, Unknown. + enum: + - "True" + - "False" + - Unknown + type: string + type: + description: type of condition in CamelCase or in foo.example.com/CamelCase. + maxLength: 316 + pattern: ^([a-z0-9]([-a-z0-9]*[a-z0-9])?(\.[a-z0-9]([-a-z0-9]*[a-z0-9])?)*/)?(([A-Za-z0-9][-A-Za-z0-9_.]*)?[A-Za-z0-9])$ + type: string + required: + - lastTransitionTime + - message + - reason + - status + - type + type: object + type: array + cpuFeatures: + description: |- + CpuFeatures + Information on CPU features supported by this model. + Shown only for `Features` or `Discovery` types. + properties: + enabled: + description: ' List of CPU features for this model.' + example: + - mmx + - vmx + - sse2 + items: + type: string + type: array + notEnabledCommon: + description: List of unused processor features additionally available + for a given group of nodes. + example: + - ssse3 + - vme + items: + type: string + type: array + type: object + maxAllocatableResources: + 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: Maximum amount of free CPU and memory resources observed + among all available nodes. + example: + - 'maxAllocatableResources: {"cpu": 1, "memory": "10Gi"}' + type: object + observedGeneration: + description: Resource generation last processed by the controller. + format: int64 + type: integer + phase: + description: |- + VirtualMachineClassPhase defines the current resource status: + * `Pending`: The resource is not ready and waits until the suitable nodes supporting the required CPU model are available. + * `Ready`: The resource is ready and available for use. + * `Terminating`: The resource is terminating. + enum: + - Pending + - Ready + - Terminating + type: string + required: + - phase + type: object + required: + - spec + type: object + served: true + storage: false + subresources: + status: {} + - additionalPrinterColumns: + - description: VirtualMachineClass phase. + jsonPath: .status.phase + name: Phase + type: string + - description: Default class for virtual machines without specified class. + jsonPath: .metadata.annotations.virtualmachineclass\.virtualization\.deckhouse\.io\/is-default-class + name: IsDefault + type: string + - description: Time of resource creation. + jsonPath: .metadata.creationTimestamp + name: Age + type: date + name: v1alpha3 + schema: + openAPIV3Schema: + description: |- + VirtualMachineClass resource describes CPU requirements, node placement, and sizing policy for VM resources. + A resource cannot be deleted as long as it is used in one of the VMs. + properties: + apiVersion: + description: |- + APIVersion defines the versioned schema of this representation of an object. + Servers should convert recognized schemas to the latest internal value, and + may reject unrecognized values. + More info: https://git.k8s.io/community/contributors/devel/sig-architecture/api-conventions.md#resources + type: string + kind: + description: |- + Kind is a string value representing the REST resource this object represents. + Servers may infer this from the endpoint the client submits requests to. + Cannot be updated. + In CamelCase. + More info: https://git.k8s.io/community/contributors/devel/sig-architecture/api-conventions.md#types-kinds + type: string + metadata: + type: object + spec: + properties: + cpu: + description: CPU defines the requirements for the virtual CPU model. + properties: + discovery: + description: Create a CPU model based on intersecting CPU features + for selected nodes. + properties: + nodeSelector: + description: A selection of nodes to be used as the basis + for creating a universal CPU model. + properties: + matchExpressions: + description: matchExpressions is a list of label selector + requirements. The requirements are ANDed. + items: + description: |- + A label selector requirement is a selector that contains values, a key, and an operator that + relates the key and values. + properties: + key: + description: key is the label key that the selector + applies to. + type: string + operator: + description: |- + operator represents a key's relationship to a set of values. + Valid operators are In, NotIn, Exists and DoesNotExist. + type: string + values: + description: |- + values is an array of string values. If the operator is In or NotIn, + the values array must be non-empty. If the operator is Exists or DoesNotExist, + the values array must be empty. This array is replaced during a strategic + merge patch. + items: + type: string + type: array + x-kubernetes-list-type: atomic + required: + - key + - operator + type: object + type: array + x-kubernetes-list-type: atomic + matchLabels: + additionalProperties: + type: string + description: |- + matchLabels is a map of {key,value} pairs. A single {key,value} in the matchLabels + map is equivalent to an element of matchExpressions, whose key field is "key", the + operator is "In", and the values array contains only "value". The requirements are ANDed. + type: object + type: object + x-kubernetes-map-type: atomic + type: object + features: + description: |- + List of CPU instructions (features) required when type=Features. + For more information about CPU features, refer to the [libvirt docs](https://libvirt.org/formatdomain.html#cpu-model-and-topology). + example: + - mmx + - vmx + - sse2 + items: + type: string + minItems: 1 + type: array + model: + description: CPU model name. For more information about CPU models + and topology, refer to the [libvirt docs](https://libvirt.org/formatdomain.html#cpu-model-and-topology). + example: IvyBridge + minLength: 1 + type: string + type: + description: |- + CPUType defines the CPU type, the following options are supported: + * `Host`: Uses a virtual CPU with an instruction set closely matching the platform node's CPU. + This provides high performance and functionality, as well as compatibility with "live" migration for nodes with similar processor types. + For example, VM migration between nodes with Intel and AMD processors will not work. + This is also true for different CPU generations, as their instruction set is different. + * `HostPassthrough`: Uses the platform node's physical CPU directly, without any modifications. + When using this class, the guest VM can only be transferred to a target node with a CPU exactly matching the source node's CPU. + * `Discovery`: Create a virtual CPU based on instruction sets of physical CPUs for a selected set of nodes. + * `Model`: CPU model. A CPU model is a named and previously defined set of supported CPU instructions. + * `Features`: A required set of supported instructions for the CPU. + enum: + - Host + - HostPassthrough + - Discovery + - Model + - Features + type: string + required: + - type + type: object + x-kubernetes-validations: + - message: .spec.cpu is immutable + rule: self == oldSelf + - message: HostPassthrough and Host cannot have model, features or + discovery + rule: 'self.type == ''HostPassthrough'' || self.type == ''Host'' + ? !has(self.model) && !has(self.features) && !has(self.discovery) + : true' + - message: Discovery cannot have model or features + rule: 'self.type == ''Discovery'' ? !has(self.model) && !has(self.features) + : true' + - message: Model requires model and cannot have features or discovery + rule: 'self.type == ''Model'' ? has(self.model) && !has(self.features) + && !has(self.discovery) : true' + - message: Features requires features and cannot have model or discovery + rule: 'self.type == ''Features'' ? has(self.features) && !has(self.model) + && !has(self.discovery): true' + nodeSelector: + description: NodeSelector defines the nodes targeted for VM scheduling. + properties: + matchExpressions: + description: A list of node selector requirements by node's labels. + items: + description: |- + A node selector requirement is a selector that contains values, a key, and an operator + that relates the key and values. + properties: + key: + description: The label key that the selector applies to. + type: string + operator: + description: |- + Represents a key's relationship to a set of values. + Valid operators are In, NotIn, Exists, DoesNotExist. Gt, and Lt. + type: string + values: + description: |- + An array of string values. If the operator is In or NotIn, + the values array must be non-empty. If the operator is Exists or DoesNotExist, + the values array must be empty. If the operator is Gt or Lt, the values + array must have a single element, which will be interpreted as an integer. + This array is replaced during a strategic merge patch. + items: + type: string + type: array + x-kubernetes-list-type: atomic + required: + - key + - operator + type: object + type: array + matchLabels: + additionalProperties: + type: string + description: |- + A map of {key,value} pairs. + A single {key,value} pair in the matchLabels map is equivalent to an element of matchExpressions whose key field is "key", operator is "In", and the value array contains only "value". + The requirements are ANDed. + type: object + type: object sizingPolicies: items: description: |- @@ -228,9 +712,9 @@ spec: description: Allowed values of the `coreFraction` parameter in percentages (e.g., "5%", "10%", "25%", "50%", "100%"). items: - description: |- - CoreFractionValue represents CPU core fraction as a percentage string (e.g., "5%", "10%", "25%", "50%", "100%"). - For backward compatibility, plain integers are also accepted (e.g., "5", "10", "25", "50", "100"). + description: CoreFractionValue represents CPU core fraction + as a percentage string (e.g., "5%", "10%", "25%", "50%", + "100%"). pattern: ^([1-9]|[1-9][0-9]|100)%?$ type: string type: array diff --git a/images/virtualization-artifact/cmd/virtualization-controller/main.go b/images/virtualization-artifact/cmd/virtualization-controller/main.go index f4b0f9d26a..c67e5ab1a3 100644 --- a/images/virtualization-artifact/cmd/virtualization-controller/main.go +++ b/images/virtualization-artifact/cmd/virtualization-controller/main.go @@ -67,6 +67,7 @@ import ( "github.com/deckhouse/virtualization-controller/pkg/version" "github.com/deckhouse/virtualization/api/client/kubeclient" "github.com/deckhouse/virtualization/api/core/v1alpha2" + "github.com/deckhouse/virtualization/api/core/v1alpha3" ) const ( @@ -222,6 +223,7 @@ func main() { clientgoscheme.AddToScheme, extv1.AddToScheme, v1alpha2.AddToScheme, + v1alpha3.AddToScheme, cdiv1beta1.AddToScheme, virtv1.AddToScheme, vsv1.AddToScheme, diff --git a/images/virtualization-artifact/pkg/controller/vmclass/vmclass_controller.go b/images/virtualization-artifact/pkg/controller/vmclass/vmclass_controller.go index a7c3eaa915..92335fa019 100644 --- a/images/virtualization-artifact/pkg/controller/vmclass/vmclass_controller.go +++ b/images/virtualization-artifact/pkg/controller/vmclass/vmclass_controller.go @@ -74,6 +74,9 @@ func NewController( return nil, err } + conversionHandler := NewConversionHandler() + mgr.GetWebhookServer().Register("/convert/virtualmachineclasses", conversionHandler) + log.Info("Initialized VirtualMachineClass controller") return c, nil } diff --git a/images/virtualization-artifact/pkg/controller/vmclass/vmclass_conversion.go b/images/virtualization-artifact/pkg/controller/vmclass/vmclass_conversion.go new file mode 100644 index 0000000000..9c736e21cc --- /dev/null +++ b/images/virtualization-artifact/pkg/controller/vmclass/vmclass_conversion.go @@ -0,0 +1,317 @@ +/* +Copyright 2024 Flant JSC +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + http://www.apache.org/licenses/LICENSE-2.0 +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. +*/ + +package vmclass + +import ( + "encoding/json" + "fmt" + "io" + "net/http" + "strconv" + + apiextensionsv1 "k8s.io/apiextensions-apiserver/pkg/apis/apiextensions/v1" + metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" + "k8s.io/apimachinery/pkg/runtime" + + "github.com/deckhouse/virtualization/api/core/v1alpha2" + "github.com/deckhouse/virtualization/api/core/v1alpha3" +) + +type ConversionHandler struct{} + +func NewConversionHandler() *ConversionHandler { + return &ConversionHandler{} +} + +func (h *ConversionHandler) ServeHTTP(w http.ResponseWriter, r *http.Request) { + body, err := io.ReadAll(r.Body) + if err != nil { + http.Error(w, fmt.Sprintf("failed to read request body: %v", err), http.StatusBadRequest) + return + } + defer r.Body.Close() + + var conversionReview apiextensionsv1.ConversionReview + if err := json.Unmarshal(body, &conversionReview); err != nil { + http.Error(w, fmt.Sprintf("failed to unmarshal request: %v", err), http.StatusBadRequest) + return + } + + response, err := h.Handle(&conversionReview) + if err != nil { + http.Error(w, fmt.Sprintf("conversion failed: %v", err), http.StatusInternalServerError) + return + } + + responseBody, err := json.Marshal(response) + if err != nil { + http.Error(w, fmt.Sprintf("failed to marshal response: %v", err), http.StatusInternalServerError) + return + } + + w.Header().Set("Content-Type", "application/json") + w.WriteHeader(http.StatusOK) + w.Write(responseBody) +} + +func (h *ConversionHandler) Handle(conversionReview *apiextensionsv1.ConversionReview) (*apiextensionsv1.ConversionReview, error) { + if conversionReview.Request == nil { + return nil, fmt.Errorf("conversion request is nil") + } + + response := &apiextensionsv1.ConversionReview{ + TypeMeta: metav1.TypeMeta{ + APIVersion: "apiextensions.k8s.io/v1", + Kind: "ConversionReview", + }, + Response: &apiextensionsv1.ConversionResponse{ + UID: conversionReview.Request.UID, + Result: metav1.Status{Status: "Success"}, + }, + } + + convertedObjects := make([]runtime.RawExtension, 0, len(conversionReview.Request.Objects)) + for _, obj := range conversionReview.Request.Objects { + convertedObj, err := h.convertObject(obj, conversionReview.Request.DesiredAPIVersion) + if err != nil { + response.Response.Result = metav1.Status{ + Status: "Failure", + Message: err.Error(), + } + return response, nil + } + convertedObjects = append(convertedObjects, runtime.RawExtension{Raw: convertedObj}) + } + + response.Response.ConvertedObjects = convertedObjects + return response, nil +} + +func (h *ConversionHandler) convertObject(obj runtime.RawExtension, desiredAPIVersion string) ([]byte, error) { + var typeMeta metav1.TypeMeta + if err := json.Unmarshal(obj.Raw, &typeMeta); err != nil { + return nil, fmt.Errorf("failed to unmarshal TypeMeta: %w", err) + } + + switch typeMeta.APIVersion { + case "virtualization.deckhouse.io/v1alpha2": + if desiredAPIVersion == "virtualization.deckhouse.io/v1alpha3" { + return h.convertV1alpha2ToV1alpha3(obj.Raw) + } + case "virtualization.deckhouse.io/v1alpha3": + if desiredAPIVersion == "virtualization.deckhouse.io/v1alpha2" { + return h.convertV1alpha3ToV1alpha2(obj.Raw) + } + } + + return obj.Raw, nil +} + +func (h *ConversionHandler) convertV1alpha2ToV1alpha3(data []byte) ([]byte, error) { + var v2Class v1alpha2.VirtualMachineClass + if err := json.Unmarshal(data, &v2Class); err != nil { + return nil, fmt.Errorf("failed to unmarshal v1alpha2 VirtualMachineClass: %w", err) + } + + v3Class := v1alpha3.VirtualMachineClass{ + TypeMeta: metav1.TypeMeta{ + APIVersion: "virtualization.deckhouse.io/v1alpha3", + Kind: "VirtualMachineClass", + }, + ObjectMeta: v2Class.ObjectMeta, + Spec: convertSpecV2ToV3(v2Class.Spec), + Status: convertStatusV2ToV3(v2Class.Status), + } + + return json.Marshal(v3Class) +} + +func (h *ConversionHandler) convertV1alpha3ToV1alpha2(data []byte) ([]byte, error) { + var v3Class v1alpha3.VirtualMachineClass + if err := json.Unmarshal(data, &v3Class); err != nil { + return nil, fmt.Errorf("failed to unmarshal v1alpha3 VirtualMachineClass: %w", err) + } + + v2Class := v1alpha2.VirtualMachineClass{ + TypeMeta: metav1.TypeMeta{ + APIVersion: "virtualization.deckhouse.io/v1alpha2", + Kind: "VirtualMachineClass", + }, + ObjectMeta: v3Class.ObjectMeta, + Spec: convertSpecV3ToV2(v3Class.Spec), + Status: convertStatusV3ToV2(v3Class.Status), + } + + return json.Marshal(v2Class) +} + +func convertSpecV2ToV3(v2Spec v1alpha2.VirtualMachineClassSpec) v1alpha3.VirtualMachineClassSpec { + v3Spec := v1alpha3.VirtualMachineClassSpec{ + NodeSelector: v1alpha3.NodeSelector{ + MatchLabels: v2Spec.NodeSelector.MatchLabels, + MatchExpressions: v2Spec.NodeSelector.MatchExpressions, + }, + Tolerations: v2Spec.Tolerations, + CPU: v1alpha3.CPU{ + Type: v1alpha3.CPUType(v2Spec.CPU.Type), + Model: v2Spec.CPU.Model, + Features: v2Spec.CPU.Features, + Discovery: v1alpha3.CpuDiscovery{ + NodeSelector: v2Spec.CPU.Discovery.NodeSelector, + }, + }, + } + + if len(v2Spec.SizingPolicies) > 0 { + v3Spec.SizingPolicies = make([]v1alpha3.SizingPolicy, len(v2Spec.SizingPolicies)) + for i, v2Policy := range v2Spec.SizingPolicies { + v3Policy := v1alpha3.SizingPolicy{ + DedicatedCores: v2Policy.DedicatedCores, + } + + if v2Policy.Memory != nil { + v3Policy.Memory = &v1alpha3.SizingPolicyMemory{ + MemoryMinMax: v1alpha3.MemoryMinMax{ + Min: v2Policy.Memory.Min, + Max: v2Policy.Memory.Max, + }, + Step: v2Policy.Memory.Step, + PerCore: v1alpha3.SizingPolicyMemoryPerCore{ + MemoryMinMax: v1alpha3.MemoryMinMax{ + Min: v2Policy.Memory.PerCore.Min, + Max: v2Policy.Memory.PerCore.Max, + }, + }, + } + } + + if v2Policy.Cores != nil { + v3Policy.Cores = &v1alpha3.SizingPolicyCores{ + Min: v2Policy.Cores.Min, + Max: v2Policy.Cores.Max, + Step: v2Policy.Cores.Step, + } + } + + if len(v2Policy.CoreFractions) > 0 { + v3Policy.CoreFractions = make([]v1alpha3.CoreFractionValue, len(v2Policy.CoreFractions)) + for j, v2Fraction := range v2Policy.CoreFractions { + v3Policy.CoreFractions[j] = v1alpha3.CoreFractionValue(fmt.Sprintf("%d%%", v2Fraction)) + } + } + + v3Spec.SizingPolicies[i] = v3Policy + } + } + + return v3Spec +} + +func convertSpecV3ToV2(v3Spec v1alpha3.VirtualMachineClassSpec) v1alpha2.VirtualMachineClassSpec { + v2Spec := v1alpha2.VirtualMachineClassSpec{ + NodeSelector: v1alpha2.NodeSelector{ + MatchLabels: v3Spec.NodeSelector.MatchLabels, + MatchExpressions: v3Spec.NodeSelector.MatchExpressions, + }, + Tolerations: v3Spec.Tolerations, + CPU: v1alpha2.CPU{ + Type: v1alpha2.CPUType(v3Spec.CPU.Type), + Model: v3Spec.CPU.Model, + Features: v3Spec.CPU.Features, + Discovery: v1alpha2.CpuDiscovery{ + NodeSelector: v3Spec.CPU.Discovery.NodeSelector, + }, + }, + } + + if len(v3Spec.SizingPolicies) > 0 { + v2Spec.SizingPolicies = make([]v1alpha2.SizingPolicy, len(v3Spec.SizingPolicies)) + for i, v3Policy := range v3Spec.SizingPolicies { + v2Policy := v1alpha2.SizingPolicy{ + DedicatedCores: v3Policy.DedicatedCores, + } + + if v3Policy.Memory != nil { + v2Policy.Memory = &v1alpha2.SizingPolicyMemory{ + MemoryMinMax: v1alpha2.MemoryMinMax{ + Min: v3Policy.Memory.Min, + Max: v3Policy.Memory.Max, + }, + Step: v3Policy.Memory.Step, + PerCore: v1alpha2.SizingPolicyMemoryPerCore{ + MemoryMinMax: v1alpha2.MemoryMinMax{ + Min: v3Policy.Memory.PerCore.Min, + Max: v3Policy.Memory.PerCore.Max, + }, + }, + } + } + + if v3Policy.Cores != nil { + v2Policy.Cores = &v1alpha2.SizingPolicyCores{ + Min: v3Policy.Cores.Min, + Max: v3Policy.Cores.Max, + Step: v3Policy.Cores.Step, + } + } + + if len(v3Policy.CoreFractions) > 0 { + v2Policy.CoreFractions = make([]v1alpha2.CoreFractionValue, len(v3Policy.CoreFractions)) + for j, v3Fraction := range v3Policy.CoreFractions { + fractionStr := string(v3Fraction) + if len(fractionStr) > 0 && fractionStr[len(fractionStr)-1] == '%' { + fractionStr = fractionStr[:len(fractionStr)-1] + } + fractionInt, err := strconv.Atoi(fractionStr) + if err != nil { + fractionInt = 100 + } + v2Policy.CoreFractions[j] = v1alpha2.CoreFractionValue(fractionInt) + } + } + + v2Spec.SizingPolicies[i] = v2Policy + } + } + + return v2Spec +} + +func convertStatusV2ToV3(v2Status v1alpha2.VirtualMachineClassStatus) v1alpha3.VirtualMachineClassStatus { + return v1alpha3.VirtualMachineClassStatus{ + Phase: v1alpha3.VirtualMachineClassPhase(v2Status.Phase), + CpuFeatures: v1alpha3.CpuFeatures{ + Enabled: v2Status.CpuFeatures.Enabled, + NotEnabledCommon: v2Status.CpuFeatures.NotEnabledCommon, + }, + AvailableNodes: v2Status.AvailableNodes, + MaxAllocatableResources: v2Status.MaxAllocatableResources, + Conditions: v2Status.Conditions, + ObservedGeneration: v2Status.ObservedGeneration, + } +} + +func convertStatusV3ToV2(v3Status v1alpha3.VirtualMachineClassStatus) v1alpha2.VirtualMachineClassStatus { + return v1alpha2.VirtualMachineClassStatus{ + Phase: v1alpha2.VirtualMachineClassPhase(v3Status.Phase), + CpuFeatures: v1alpha2.CpuFeatures{ + Enabled: v3Status.CpuFeatures.Enabled, + NotEnabledCommon: v3Status.CpuFeatures.NotEnabledCommon, + }, + AvailableNodes: v3Status.AvailableNodes, + MaxAllocatableResources: v3Status.MaxAllocatableResources, + Conditions: v3Status.Conditions, + ObservedGeneration: v3Status.ObservedGeneration, + } +} diff --git a/images/virtualization-artifact/pkg/migration/core_fractions_format.go b/images/virtualization-artifact/pkg/migration/core_fractions_format.go deleted file mode 100644 index b1e283350e..0000000000 --- a/images/virtualization-artifact/pkg/migration/core_fractions_format.go +++ /dev/null @@ -1,138 +0,0 @@ -/* -Copyright 2025 Flant JSC - -Licensed under the Apache License, Version 2.0 (the "License"); -you may not use this file except in compliance with the License. -You may obtain a copy of the License at - - http://www.apache.org/licenses/LICENSE-2.0 - -Unless required by applicable law or agreed to in writing, software -distributed under the License is distributed on an "AS IS" BASIS, -WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -See the License for the specific language governing permissions and -limitations under the License. -*/ - -package migration - -import ( - "context" - "fmt" - "log/slog" - "strconv" - "strings" - - "k8s.io/apimachinery/pkg/types" - "sigs.k8s.io/controller-runtime/pkg/client" - - "github.com/deckhouse/deckhouse/pkg/log" - "github.com/deckhouse/virtualization-controller/pkg/common/patch" - "github.com/deckhouse/virtualization/api/core/v1alpha2" -) - -const ( - coreFractionsFormatMigrationName = "core-fractions-format" -) - -func newCoreFractionsFormat(client client.Client, logger *log.Logger) (Migration, error) { - return &coreFractionsFormat{ - client: client, - logger: logger, - }, nil -} - -type coreFractionsFormat struct { - client client.Client - logger *log.Logger -} - -func (m *coreFractionsFormat) Name() string { - return coreFractionsFormatMigrationName -} - -func (m *coreFractionsFormat) Migrate(ctx context.Context) error { - vmcList := &v1alpha2.VirtualMachineClassList{} - if err := m.client.List(ctx, vmcList); err != nil { - return fmt.Errorf("failed to list VirtualMachineClasses: %w", err) - } - - for i := range vmcList.Items { - vmc := &vmcList.Items[i] - - needUpdate, genPatch, err := m.genPatch(vmc) - if err != nil { - return fmt.Errorf("failed to generate patch for VMClass %s: %w", vmc.Name, err) - } - if !needUpdate { - continue - } - - m.logger.Info("Migrating VMClass coreFractions format", - slog.String("name", vmc.Name), - ) - - if m.logger.GetLevel() <= log.LevelDebug { - if data, err := genPatch.Data(vmc); err == nil { - m.logger.Debug("Patch VMClass", - slog.String("name", vmc.Name), - slog.String("data", string(data)), - ) - } - } - - if err := m.client.Patch(ctx, vmc, genPatch); err != nil { - return fmt.Errorf("failed to patch VMClass %s: %w", vmc.Name, err) - } - } - - return nil -} - -func (m *coreFractionsFormat) genPatch(vmc *v1alpha2.VirtualMachineClass) (bool, client.Patch, error) { - var ops []patch.JSONPatchOperation - - for policyIdx, policy := range vmc.Spec.SizingPolicies { - if len(policy.CoreFractions) == 0 { - continue - } - - for fractionIdx, fraction := range policy.CoreFractions { - newValue, changed := normalizeCoreFraction(string(fraction)) - if !changed { - continue - } - - ops = append(ops, patch.NewJSONPatchOperation( - patch.PatchReplaceOp, - fmt.Sprintf("/spec/sizingPolicies/%d/coreFractions/%d", policyIdx, fractionIdx), - newValue, - )) - } - } - - if len(ops) == 0 { - return false, nil, nil - } - - bytes, err := patch.NewJSONPatch(ops...).Bytes() - if err != nil { - return false, nil, fmt.Errorf("failed to create JSON patch: %w", err) - } - - return true, client.RawPatch(types.JSONPatchType, bytes), nil -} - -func normalizeCoreFraction(value string) (string, bool) { - trimmed := strings.TrimSpace(value) - - if strings.HasSuffix(trimmed, "%") { - return trimmed, false - } - - if num, err := strconv.Atoi(trimmed); err == nil && num >= 1 && num <= 100 { - return fmt.Sprintf("%d%%", num), true - } - - return value, false -} diff --git a/images/virtualization-artifact/pkg/migration/core_fractions_format_test.go b/images/virtualization-artifact/pkg/migration/core_fractions_format_test.go deleted file mode 100644 index af187188eb..0000000000 --- a/images/virtualization-artifact/pkg/migration/core_fractions_format_test.go +++ /dev/null @@ -1,242 +0,0 @@ -/* -Copyright 2025 Flant JSC - -Licensed under the Apache License, Version 2.0 (the "License"); -you may not use this file except in compliance with the License. -You may obtain a copy of the License at - - http://www.apache.org/licenses/LICENSE-2.0 - -Unless required by applicable law or agreed to in writing, software -distributed under the License is distributed on an "AS IS" BASIS, -WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -See the License for the specific language governing permissions and -limitations under the License. -*/ - -package migration - -import ( - "context" - "testing" - - . "github.com/onsi/ginkgo/v2" - . "github.com/onsi/gomega" - metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" - "k8s.io/apimachinery/pkg/types" - "sigs.k8s.io/controller-runtime/pkg/client" - - "github.com/deckhouse/virtualization-controller/pkg/common/testutil" - "github.com/deckhouse/virtualization/api/core/v1alpha2" -) - -func TestCoreFractionsFormat(t *testing.T) { - RegisterFailHandler(Fail) - RunSpecs(t, "CoreFractionsFormat Migration Suite") -} - -var _ = Describe("CoreFractionsFormat Migration", func() { - var ( - ctx context.Context - client client.Client - ) - - BeforeEach(func() { - ctx = context.Background() - var err error - client, err = testutil.NewFakeClientWithObjects() - Expect(err).NotTo(HaveOccurred()) - }) - - Context("normalizeCoreFraction", func() { - It("should add % sign to plain integer values", func() { - result, changed := normalizeCoreFraction("5") - Expect(changed).To(BeTrue()) - Expect(result).To(Equal("5%")) - - result, changed = normalizeCoreFraction("10") - Expect(changed).To(BeTrue()) - Expect(result).To(Equal("10%")) - - result, changed = normalizeCoreFraction("100") - Expect(changed).To(BeTrue()) - Expect(result).To(Equal("100%")) - }) - - It("should not change values that already have % sign", func() { - result, changed := normalizeCoreFraction("5%") - Expect(changed).To(BeFalse()) - Expect(result).To(Equal("5%")) - - result, changed = normalizeCoreFraction("25%") - Expect(changed).To(BeFalse()) - Expect(result).To(Equal("25%")) - }) - - It("should handle values with spaces", func() { - result, changed := normalizeCoreFraction(" 10 ") - Expect(changed).To(BeTrue()) - Expect(result).To(Equal("10%")) - - result, changed = normalizeCoreFraction(" 50% ") - Expect(changed).To(BeFalse()) - Expect(result).To(Equal("50%")) - }) - - It("should not change invalid values", func() { - result, changed := normalizeCoreFraction("invalid") - Expect(changed).To(BeFalse()) - Expect(result).To(Equal("invalid")) - - result, changed = normalizeCoreFraction("0") - Expect(changed).To(BeFalse()) - Expect(result).To(Equal("0")) - - result, changed = normalizeCoreFraction("101") - Expect(changed).To(BeFalse()) - Expect(result).To(Equal("101")) - }) - }) - - Context("Migrate", func() { - It("should migrate VMClass with plain integer coreFractions", func() { - vmc := &v1alpha2.VirtualMachineClass{ - ObjectMeta: metav1.ObjectMeta{ - Name: "test-class", - }, - Spec: v1alpha2.VirtualMachineClassSpec{ - CPU: v1alpha2.CPU{Type: v1alpha2.CPUTypeHost}, - SizingPolicies: []v1alpha2.SizingPolicy{ - { - Cores: &v1alpha2.SizingPolicyCores{Min: 1, Max: 4}, - CoreFractions: []v1alpha2.CoreFractionValue{"5", "10", "25", "50", "100"}, - }, - }, - }, - } - - err := client.Create(ctx, vmc) - Expect(err).NotTo(HaveOccurred()) - - migration, err := newCoreFractionsFormat(client, testutil.NewNoOpLogger()) - Expect(err).NotTo(HaveOccurred()) - - err = migration.Migrate(ctx) - Expect(err).NotTo(HaveOccurred()) - - updated := &v1alpha2.VirtualMachineClass{} - err = client.Get(ctx, types.NamespacedName{Name: vmc.Name}, updated) - Expect(err).NotTo(HaveOccurred()) - - Expect(updated.Spec.SizingPolicies[0].CoreFractions).To(Equal([]v1alpha2.CoreFractionValue{ - "5%", "10%", "25%", "50%", "100%", - })) - }) - - It("should not change VMClass with already formatted coreFractions", func() { - vmc := &v1alpha2.VirtualMachineClass{ - ObjectMeta: metav1.ObjectMeta{ - Name: "test-class-formatted", - }, - Spec: v1alpha2.VirtualMachineClassSpec{ - CPU: v1alpha2.CPU{Type: v1alpha2.CPUTypeHost}, - SizingPolicies: []v1alpha2.SizingPolicy{ - { - Cores: &v1alpha2.SizingPolicyCores{Min: 1, Max: 4}, - CoreFractions: []v1alpha2.CoreFractionValue{"5%", "10%", "25%", "50%", "100%"}, - }, - }, - }, - } - - err := client.Create(ctx, vmc) - Expect(err).NotTo(HaveOccurred()) - - migration, err := newCoreFractionsFormat(client, testutil.NewNoOpLogger()) - Expect(err).NotTo(HaveOccurred()) - - err = migration.Migrate(ctx) - Expect(err).NotTo(HaveOccurred()) - - updated := &v1alpha2.VirtualMachineClass{} - err = client.Get(ctx, types.NamespacedName{Name: vmc.Name}, updated) - Expect(err).NotTo(HaveOccurred()) - - Expect(updated.Spec.SizingPolicies[0].CoreFractions).To(Equal([]v1alpha2.CoreFractionValue{ - "5%", "10%", "25%", "50%", "100%", - })) - }) - - It("should handle VMClass with multiple sizing policies", func() { - vmc := &v1alpha2.VirtualMachineClass{ - ObjectMeta: metav1.ObjectMeta{ - Name: "test-class-multi", - }, - Spec: v1alpha2.VirtualMachineClassSpec{ - CPU: v1alpha2.CPU{Type: v1alpha2.CPUTypeHost}, - SizingPolicies: []v1alpha2.SizingPolicy{ - { - Cores: &v1alpha2.SizingPolicyCores{Min: 1, Max: 4}, - CoreFractions: []v1alpha2.CoreFractionValue{"5", "10", "25"}, - }, - { - Cores: &v1alpha2.SizingPolicyCores{Min: 5, Max: 8}, - CoreFractions: []v1alpha2.CoreFractionValue{"50", "100"}, - }, - }, - }, - } - - err := client.Create(ctx, vmc) - Expect(err).NotTo(HaveOccurred()) - - migration, err := newCoreFractionsFormat(client, testutil.NewNoOpLogger()) - Expect(err).NotTo(HaveOccurred()) - - err = migration.Migrate(ctx) - Expect(err).NotTo(HaveOccurred()) - - updated := &v1alpha2.VirtualMachineClass{} - err = client.Get(ctx, types.NamespacedName{Name: vmc.Name}, updated) - Expect(err).NotTo(HaveOccurred()) - - Expect(updated.Spec.SizingPolicies[0].CoreFractions).To(Equal([]v1alpha2.CoreFractionValue{ - "5%", "10%", "25%", - })) - Expect(updated.Spec.SizingPolicies[1].CoreFractions).To(Equal([]v1alpha2.CoreFractionValue{ - "50%", "100%", - })) - }) - - It("should handle VMClass without coreFractions", func() { - vmc := &v1alpha2.VirtualMachineClass{ - ObjectMeta: metav1.ObjectMeta{ - Name: "test-class-no-fractions", - }, - Spec: v1alpha2.VirtualMachineClassSpec{ - CPU: v1alpha2.CPU{Type: v1alpha2.CPUTypeHost}, - SizingPolicies: []v1alpha2.SizingPolicy{ - { - Cores: &v1alpha2.SizingPolicyCores{Min: 1, Max: 4}, - }, - }, - }, - } - - err := client.Create(ctx, vmc) - Expect(err).NotTo(HaveOccurred()) - - migration, err := newCoreFractionsFormat(client, testutil.NewNoOpLogger()) - Expect(err).NotTo(HaveOccurred()) - - err = migration.Migrate(ctx) - Expect(err).NotTo(HaveOccurred()) - - updated := &v1alpha2.VirtualMachineClass{} - err = client.Get(ctx, types.NamespacedName{Name: vmc.Name}, updated) - Expect(err).NotTo(HaveOccurred()) - - Expect(updated.Spec.SizingPolicies[0].CoreFractions).To(BeNil()) - }) - }) -}) diff --git a/images/virtualization-artifact/pkg/migration/migration.go b/images/virtualization-artifact/pkg/migration/migration.go index ea566803d2..601acb1c90 100644 --- a/images/virtualization-artifact/pkg/migration/migration.go +++ b/images/virtualization-artifact/pkg/migration/migration.go @@ -31,7 +31,6 @@ type constructor func(client client.Client, logger *log.Logger) (Migration, erro var newMigrations = []constructor{ newQEMUMaxLength36, - newCoreFractionsFormat, } type Migration interface { diff --git a/templates/virtualization-controller/vmclasses-default.yaml b/templates/virtualization-controller/vmclasses-default.yaml index 6da6926e0f..2bbf9c7288 100644 --- a/templates/virtualization-controller/vmclasses-default.yaml +++ b/templates/virtualization-controller/vmclasses-default.yaml @@ -1,4 +1,4 @@ -apiVersion: virtualization.deckhouse.io/v1alpha2 +apiVersion: virtualization.deckhouse.io/v1alpha3 kind: VirtualMachineClass metadata: name: generic From 0cab994991645a0e9b71c2e3304b8a6d496bafe9 Mon Sep 17 00:00:00 2001 From: Daniil Loktev Date: Tue, 21 Oct 2025 11:10:11 +0300 Subject: [PATCH 03/77] wip Signed-off-by: Daniil Loktev --- api/core/v1alpha3/doc.go | 2 +- api/core/v1alpha3/register.go | 2 +- api/core/v1alpha3/virtual_machine_class.go | 2 +- api/core/v1alpha3/vmclasscondition/condition.go | 2 +- .../pkg/controller/vmclass/vmclass_conversion.go | 2 +- 5 files changed, 5 insertions(+), 5 deletions(-) diff --git a/api/core/v1alpha3/doc.go b/api/core/v1alpha3/doc.go index 4474f64c7d..0d53bde091 100644 --- a/api/core/v1alpha3/doc.go +++ b/api/core/v1alpha3/doc.go @@ -1,5 +1,5 @@ /* -Copyright 2024 Flant JSC +Copyright 2025 Flant JSC Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with the License. diff --git a/api/core/v1alpha3/register.go b/api/core/v1alpha3/register.go index bc2d297ed1..0028d52785 100644 --- a/api/core/v1alpha3/register.go +++ b/api/core/v1alpha3/register.go @@ -1,5 +1,5 @@ /* -Copyright 2024 Flant JSC +Copyright 2025 Flant JSC Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with the License. diff --git a/api/core/v1alpha3/virtual_machine_class.go b/api/core/v1alpha3/virtual_machine_class.go index 5fe1e6bbf1..76fd26381d 100644 --- a/api/core/v1alpha3/virtual_machine_class.go +++ b/api/core/v1alpha3/virtual_machine_class.go @@ -1,5 +1,5 @@ /* -Copyright 2024 Flant JSC +Copyright 2025 Flant JSC Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with the License. diff --git a/api/core/v1alpha3/vmclasscondition/condition.go b/api/core/v1alpha3/vmclasscondition/condition.go index 14fef998c2..8790297ff9 100644 --- a/api/core/v1alpha3/vmclasscondition/condition.go +++ b/api/core/v1alpha3/vmclasscondition/condition.go @@ -1,5 +1,5 @@ /* -Copyright 2024 Flant JSC +Copyright 2025 Flant JSC Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with the License. diff --git a/images/virtualization-artifact/pkg/controller/vmclass/vmclass_conversion.go b/images/virtualization-artifact/pkg/controller/vmclass/vmclass_conversion.go index 9c736e21cc..0e5eab6ba8 100644 --- a/images/virtualization-artifact/pkg/controller/vmclass/vmclass_conversion.go +++ b/images/virtualization-artifact/pkg/controller/vmclass/vmclass_conversion.go @@ -1,5 +1,5 @@ /* -Copyright 2024 Flant JSC +Copyright 2025 Flant JSC Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with the License. You may obtain a copy of the License at From 6e978efac833249ccf40bc69330ac3d10ac81b5a Mon Sep 17 00:00:00 2001 From: Daniil Loktev Date: Tue, 21 Oct 2025 14:03:30 +0300 Subject: [PATCH 04/77] remove formating changes Signed-off-by: Daniil Loktev --- crds/clustervirtualimages.yaml | 736 +++++++-------- crds/virtualdisks.yaml | 846 +++++++++--------- crds/virtualimages.yaml | 759 ++++++++-------- .../virtualmachineblockdeviceattachments.yaml | 324 +++---- crds/virtualmachineoperations.yaml | 423 +++++---- crds/virtualmachinerestores.yaml | 337 +++---- crds/virtualmachinesnapshots.yaml | 373 ++++---- 7 files changed, 1978 insertions(+), 1820 deletions(-) diff --git a/crds/clustervirtualimages.yaml b/crds/clustervirtualimages.yaml index 660f357378..93bc215d84 100644 --- a/crds/clustervirtualimages.yaml +++ b/crds/clustervirtualimages.yaml @@ -13,387 +13,411 @@ spec: group: virtualization.deckhouse.io names: categories: - - virtualization-cluster + - virtualization-cluster kind: ClusterVirtualImage listKind: ClusterVirtualImageList plural: clustervirtualimages shortNames: - - cvi + - cvi singular: clustervirtualimage scope: Cluster versions: - - additionalPrinterColumns: - - jsonPath: .status.phase - name: Phase - type: string - - jsonPath: .status.cdrom - name: CDROM - type: boolean - - jsonPath: .status.progress - name: Progress - type: string - - jsonPath: .status.size.stored - name: StoredSize - priority: 1 - type: string - - jsonPath: .status.size.unpacked - name: UnpackedSize - priority: 1 - type: string - - jsonPath: .status.target.registryURL - name: Registry URL - priority: 1 - type: string - - jsonPath: .metadata.creationTimestamp - name: Age - type: date - name: v1alpha2 - schema: - openAPIV3Schema: - description: |- - Describes a virtual disk image that can be used as a data source for new VirtualDisks or an installation image (iso) to be mounted in VirtualMachines directly. This resource type is available for all namespaces in the cluster. + - additionalPrinterColumns: + - jsonPath: .status.phase + name: Phase + type: string + - jsonPath: .status.cdrom + name: CDROM + type: boolean + - jsonPath: .status.progress + name: Progress + type: string + - jsonPath: .status.size.stored + name: StoredSize + priority: 1 + type: string + - jsonPath: .status.size.unpacked + name: UnpackedSize + priority: 1 + type: string + - jsonPath: .status.target.registryURL + name: Registry URL + priority: 1 + type: string + - jsonPath: .metadata.creationTimestamp + name: Age + type: date + name: v1alpha2 + schema: + openAPIV3Schema: + description: |- + Describes a virtual disk image that can be used as a data source for new VirtualDisks or an installation image (iso) to be mounted in VirtualMachines directly. This resource type is available for all namespaces in the cluster. - > This resource cannot be modified once it has been created. + > This resource cannot be modified once it has been created. - With this resource in the cluster, a container image is created and stored in a dedicated Deckhouse Virtualization Container Registry (DVCR). - properties: - apiVersion: - description: |- - APIVersion defines the versioned schema of this representation of an object. - Servers should convert recognized schemas to the latest internal value, and - may reject unrecognized values. - More info: https://git.k8s.io/community/contributors/devel/sig-architecture/api-conventions.md#resources - type: string - kind: - description: |- - Kind is a string value representing the REST resource this object represents. - Servers may infer this from the endpoint the client submits requests to. - Cannot be updated. - In CamelCase. - More info: https://git.k8s.io/community/contributors/devel/sig-architecture/api-conventions.md#types-kinds - type: string - metadata: - type: object - spec: - properties: - dataSource: - description: Origin of the image. - properties: - containerImage: - description: Use an image stored in external container registry. - Only registries with enabled TLS protocol are supported. To - provide a custom Certificate Authority (CA) chain, use the `caBundle` - field. - properties: - caBundle: - description: CA chain in Base64 format to verify the container - registry. - example: YWFhCg== - format: byte - type: string - image: - description: Path to the image in the container registry. - example: registry.example.com/images/slackware:15 - pattern: ^(?P(?:(?P(?:(?:localhost|[\w-]+(?:\.[\w-]+)+)(?::\d+)?)|[\w]+:\d+)/)?(?P[a-z0-9_.-]+(?:/[a-z0-9_.-]+)*))(?::(?P[\w][\w.-]{0,127}))?(?:@(?P[A-Za-z][A-Za-z0-9]*(?:[+.-_][A-Za-z][A-Za-z0-9]*)*:[0-9a-fA-F]{32,}))?$ - type: string - imagePullSecret: - properties: - name: - description: Name of the secret keeping container registry - credentials. - type: string - namespace: - description: Namespace where `imagePullSecret` is located. - type: string - type: object - required: - - image - type: object - http: - description: |- - Fill the image with data from an external URL. The following schemas are supported: + With this resource in the cluster, a container image is created and stored in a dedicated Deckhouse Virtualization Container Registry (DVCR). + properties: + apiVersion: + description: |- + APIVersion defines the versioned schema of this representation of an object. + Servers should convert recognized schemas to the latest internal value, and + may reject unrecognized values. + More info: https://git.k8s.io/community/contributors/devel/sig-architecture/api-conventions.md#resources + type: string + kind: + description: |- + Kind is a string value representing the REST resource this object represents. + Servers may infer this from the endpoint the client submits requests to. + Cannot be updated. + In CamelCase. + More info: https://git.k8s.io/community/contributors/devel/sig-architecture/api-conventions.md#types-kinds + type: string + metadata: + type: object + spec: + properties: + dataSource: + description: Origin of the image. + properties: + containerImage: + description: + Use an image stored in external container registry. + Only registries with enabled TLS protocol are supported. To + provide a custom Certificate Authority (CA) chain, use the `caBundle` + field. + properties: + caBundle: + description: + CA chain in Base64 format to verify the container + registry. + example: YWFhCg== + format: byte + type: string + image: + description: Path to the image in the container registry. + example: registry.example.com/images/slackware:15 + pattern: ^(?P(?:(?P(?:(?:localhost|[\w-]+(?:\.[\w-]+)+)(?::\d+)?)|[\w]+:\d+)/)?(?P[a-z0-9_.-]+(?:/[a-z0-9_.-]+)*))(?::(?P[\w][\w.-]{0,127}))?(?:@(?P[A-Za-z][A-Za-z0-9]*(?:[+.-_][A-Za-z][A-Za-z0-9]*)*:[0-9a-fA-F]{32,}))?$ + type: string + imagePullSecret: + properties: + name: + description: + Name of the secret keeping container registry + credentials. + type: string + namespace: + description: Namespace where `imagePullSecret` is located. + type: string + type: object + required: + - image + type: object + http: + description: |- + Fill the image with data from an external URL. The following schemas are supported: - * HTTP - * HTTPS + * HTTP + * HTTPS - For HTTPS schema, there is an option to skip the TLS verification. + For HTTPS schema, there is an option to skip the TLS verification. + properties: + caBundle: + description: CA chain in Base64 format to verify the URL. + example: YWFhCg== + format: byte + type: string + checksum: + description: + Checksum to verify integrity and consistency + of the downloaded file. The file must match all specified + checksums. + properties: + md5: + example: f3b59bed9f91e32fac1210184fcff6f5 + maxLength: 32 + minLength: 32 + pattern: ^[0-9a-fA-F]{32}$ + type: string + sha256: + example: 78be890d71dde316c412da2ce8332ba47b9ce7a29d573801d2777e01aa20b9b5 + maxLength: 64 + minLength: 64 + pattern: ^[0-9a-fA-F]{64}$ + type: string + type: object + url: + description: |- + URL of the file for creating an image. The following file formats are supported: + * qcow2 + * vmdk + * vdi + * iso + * raw + The file can be compressed into an archive in one of the following formats: + * gz + * xz + example: https://mirror.example.com/images/slackware-15.qcow.gz + pattern: ^http[s]?:\/\/(?:[a-zA-Z]|[0-9]|[$-_@.&+]|[!*\(\),]|(?:%[0-9a-fA-F][0-9a-fA-F]))+$ + type: string + required: + - url + type: object + objectRef: + description: + Use an existing VirtualImage, ClusterVirtualImage, + VirtualDisk or VirtualDiskSnapshot resource to create an image. + properties: + kind: + description: + Kind of the existing VirtualImage, ClusterVirtualImage, + VirtualDisk or VirtualDiskSnapshot resource. + enum: + - ClusterVirtualImage + - VirtualImage + - VirtualDisk + - VirtualDiskSnapshot + type: string + name: + description: + Name of the existing VirtualImage, ClusterVirtualImage, + VirtualDisk or VirtualDiskSnapshot resource. + type: string + namespace: + description: + Namespace where the VirtualImage, VirtualDisk + or VirtualDiskSnapshot resource is located. + type: string + required: + - kind + - name + type: object + x-kubernetes-validations: + - message: + The namespace is required for VirtualDisk, VirtualImage + and VirtualDiskSnapshot + rule: + "self.kind == 'VirtualImage' || self.kind == 'VirtualDisk' + || self.kind == 'VirtualDiskSnapshot' ? has(self.__namespace__) + && size(self.__namespace__) > 0 : true" + - message: The namespace must be no longer than 63 characters. + rule: + "self.kind == 'VirtualImage' || self.kind == 'VirtualDisk' + || self.kind == 'VirtualDiskSnapshot' ? has(self.__namespace__) + && size(self.__namespace__) < 64 : true" + type: + description: |- + The following image sources are available for creating an image: + + * `HTTP`: From a file published on an HTTP/HTTPS service at a given URL. + * `ContainerImage`: From another image stored in a container registry. + * `ObjectRef`: From an existing resource. + * `Upload`: From data uploaded by the user via a special interface. + enum: + - HTTP + - ContainerImage + - ObjectRef + - Upload + type: string + required: + - type + type: object + x-kubernetes-validations: + - message: HTTP requires http and cannot have ContainerImage or ObjectRef. + rule: + "self.type == 'HTTP' ? has(self.http) && !has(self.containerImage) + && !has(self.objectRef) : true" + - message: + ContainerImage requires containerImage and cannot have + HTTP or ObjectRef. + rule: + "self.type == 'ContainerImage' ? has(self.containerImage) + && !has(self.http) && !has(self.objectRef) : true" + - message: ObjectRef requires objectRef and cannot have HTTP or ContainerImage. + rule: + "self.type == 'ObjectRef' ? has(self.objectRef) && !has(self.http) + && !has(self.containerImage) : true" + required: + - dataSource + type: object + status: + properties: + cdrom: + description: + Defines whether the image is in a format that needs to + be mounted as a CD-ROM drive, such as iso and so on. + type: boolean + conditions: + description: + The latest available observations of an object's current + state. + items: + description: + Condition contains details for one aspect of the current + state of this API Resource. properties: - caBundle: - description: CA chain in Base64 format to verify the URL. - example: YWFhCg== - format: byte + lastTransitionTime: + description: |- + lastTransitionTime is the last time the condition transitioned from one status to another. + This should be when the underlying condition changed. If that is not known, then using the time when the API field changed is acceptable. + format: date-time type: string - checksum: - description: Checksum to verify integrity and consistency - of the downloaded file. The file must match all specified - checksums. - properties: - md5: - example: f3b59bed9f91e32fac1210184fcff6f5 - maxLength: 32 - minLength: 32 - pattern: ^[0-9a-fA-F]{32}$ - type: string - sha256: - example: 78be890d71dde316c412da2ce8332ba47b9ce7a29d573801d2777e01aa20b9b5 - maxLength: 64 - minLength: 64 - pattern: ^[0-9a-fA-F]{64}$ - type: string - type: object - url: + message: description: |- - URL of the file for creating an image. The following file formats are supported: - * qcow2 - * vmdk - * vdi - * iso - * raw - The file can be compressed into an archive in one of the following formats: - * gz - * xz - example: https://mirror.example.com/images/slackware-15.qcow.gz - pattern: ^http[s]?:\/\/(?:[a-zA-Z]|[0-9]|[$-_@.&+]|[!*\(\),]|(?:%[0-9a-fA-F][0-9a-fA-F]))+$ + message is a human readable message indicating details about the transition. + This may be an empty string. + maxLength: 32768 type: string - required: - - url - type: object - objectRef: - description: Use an existing VirtualImage, ClusterVirtualImage, - VirtualDisk or VirtualDiskSnapshot resource to create an image. - properties: - kind: - description: Kind of the existing VirtualImage, ClusterVirtualImage, - VirtualDisk or VirtualDiskSnapshot resource. - enum: - - ClusterVirtualImage - - VirtualImage - - VirtualDisk - - VirtualDiskSnapshot + observedGeneration: + description: |- + observedGeneration represents the .metadata.generation that the condition was set based upon. + For instance, if .metadata.generation is currently 12, but the .status.conditions[x].observedGeneration is 9, the condition is out of date + with respect to the current state of the instance. + format: int64 + minimum: 0 + type: integer + reason: + description: |- + reason contains a programmatic identifier indicating the reason for the condition's last transition. + Producers of specific condition types may define expected values and meanings for this field, + and whether the values are considered a guaranteed API. + The value should be a CamelCase string. + This field may not be empty. + maxLength: 1024 + minLength: 1 + pattern: ^[A-Za-z]([A-Za-z0-9_,:]*[A-Za-z0-9_])?$ type: string - name: - description: Name of the existing VirtualImage, ClusterVirtualImage, - VirtualDisk or VirtualDiskSnapshot resource. + status: + description: status of the condition, one of True, False, Unknown. + enum: + - "True" + - "False" + - Unknown type: string - namespace: - description: Namespace where the VirtualImage, VirtualDisk - or VirtualDiskSnapshot resource is located. + type: + description: type of condition in CamelCase or in foo.example.com/CamelCase. + maxLength: 316 + pattern: ^([a-z0-9]([-a-z0-9]*[a-z0-9])?(\.[a-z0-9]([-a-z0-9]*[a-z0-9])?)*/)?(([A-Za-z0-9][-A-Za-z0-9_.]*)?[A-Za-z0-9])$ type: string required: - - kind - - name + - lastTransitionTime + - message + - reason + - status + - type type: object - x-kubernetes-validations: - - message: The namespace is required for VirtualDisk, VirtualImage - and VirtualDiskSnapshot - rule: 'self.kind == ''VirtualImage'' || self.kind == ''VirtualDisk'' - || self.kind == ''VirtualDiskSnapshot'' ? has(self.__namespace__) - && size(self.__namespace__) > 0 : true' - - message: The namespace must be no longer than 63 characters. - rule: 'self.kind == ''VirtualImage'' || self.kind == ''VirtualDisk'' - || self.kind == ''VirtualDiskSnapshot'' ? has(self.__namespace__) - && size(self.__namespace__) < 64 : true' - type: - description: |- - The following image sources are available for creating an image: - - * `HTTP`: From a file published on an HTTP/HTTPS service at a given URL. - * `ContainerImage`: From another image stored in a container registry. - * `ObjectRef`: From an existing resource. - * `Upload`: From data uploaded by the user via a special interface. - enum: - - HTTP - - ContainerImage - - ObjectRef - - Upload - type: string - required: - - type - type: object - x-kubernetes-validations: - - message: HTTP requires http and cannot have ContainerImage or ObjectRef. - rule: 'self.type == ''HTTP'' ? has(self.http) && !has(self.containerImage) - && !has(self.objectRef) : true' - - message: ContainerImage requires containerImage and cannot have - HTTP or ObjectRef. - rule: 'self.type == ''ContainerImage'' ? has(self.containerImage) - && !has(self.http) && !has(self.objectRef) : true' - - message: ObjectRef requires objectRef and cannot have HTTP or ContainerImage. - rule: 'self.type == ''ObjectRef'' ? has(self.objectRef) && !has(self.http) - && !has(self.containerImage) : true' - required: - - dataSource - type: object - status: - properties: - cdrom: - description: Defines whether the image is in a format that needs to - be mounted as a CD-ROM drive, such as iso and so on. - type: boolean - conditions: - description: The latest available observations of an object's current - state. - items: - description: Condition contains details for one aspect of the current - state of this API Resource. + type: array + downloadSpeed: + description: + Image download speed from an external source. Appears + only during the `Provisioning` phase. properties: - lastTransitionTime: - description: |- - lastTransitionTime is the last time the condition transitioned from one status to another. - This should be when the underlying condition changed. If that is not known, then using the time when the API field changed is acceptable. - format: date-time + avg: + description: Average download speed. + example: 1 Mbps type: string - message: - description: |- - message is a human readable message indicating details about the transition. - This may be an empty string. - maxLength: 32768 + avgBytes: + description: Average download speed in bytes per second. + example: 1012345 type: string - observedGeneration: - description: |- - observedGeneration represents the .metadata.generation that the condition was set based upon. - For instance, if .metadata.generation is currently 12, but the .status.conditions[x].observedGeneration is 9, the condition is out of date - with respect to the current state of the instance. - format: int64 - minimum: 0 - type: integer - reason: - description: |- - reason contains a programmatic identifier indicating the reason for the condition's last transition. - Producers of specific condition types may define expected values and meanings for this field, - and whether the values are considered a guaranteed API. - The value should be a CamelCase string. - This field may not be empty. - maxLength: 1024 - minLength: 1 - pattern: ^[A-Za-z]([A-Za-z0-9_,:]*[A-Za-z0-9_])?$ + current: + description: Current download speed. + example: 5 Mbps type: string - status: - description: status of the condition, one of True, False, Unknown. - enum: - - "True" - - "False" - - Unknown + currentBytes: + description: Current download speed in bytes per second. + example: 5123456 type: string - type: - description: type of condition in CamelCase or in foo.example.com/CamelCase. - maxLength: 316 - pattern: ^([a-z0-9]([-a-z0-9]*[a-z0-9])?(\.[a-z0-9]([-a-z0-9]*[a-z0-9])?)*/)?(([A-Za-z0-9][-A-Za-z0-9_.]*)?[A-Za-z0-9])$ + type: object + format: + description: Discovered image format. + type: string + imageUploadURLs: + properties: + external: + description: + Command to upload the image using `Ingress` from + outside the cluster. + type: string + inCluster: + description: + Command to upload the image using `Service` within + the cluster. type: string - required: - - lastTransitionTime - - message - - reason - - status - - type type: object - type: array - downloadSpeed: - description: Image download speed from an external source. Appears - only during the `Provisioning` phase. - properties: - avg: - description: Average download speed. - example: 1 Mbps - type: string - avgBytes: - description: Average download speed in bytes per second. - example: 1012345 - type: string - current: - description: Current download speed. - example: 5 Mbps - type: string - currentBytes: - description: Current download speed in bytes per second. - example: 5123456 - type: string - type: object - format: - description: Discovered image format. - type: string - imageUploadURLs: - properties: - external: - description: Command to upload the image using `Ingress` from - outside the cluster. - type: string - inCluster: - description: Command to upload the image using `Service` within - the cluster. - type: string - type: object - observedGeneration: - description: Resource generation last processed by the controller. - format: int64 - type: integer - phase: - description: |- - Current status of the ClusterVirtualImage resource: - * `Pending`: The resource has been created and is on a waiting queue. - * `Provisioning`: The resource is being created: copying, downloading, or building of the image is in progress. - * `WaitForUserUpload`: Waiting for the user to upload the image. The endpoint to upload the image is specified in `.status.uploadCommand`. - * `Ready`: The resource has been created and is ready to use. - * `Failed`: There was an error when creating the resource. - * `Terminating`: The resource is being deleted. - enum: - - Pending - - Provisioning - - WaitForUserUpload - - Ready - - Failed - - Terminating - type: string - progress: - description: Progress of copying an image from the source to DVCR. - Appears only during the `Provisioning' phase. - type: string - size: - description: Discovered image size data. - properties: - stored: - description: Image size in human-readable format. - example: 199M - type: string - storedBytes: - description: Image size in bytes. - example: 199001234 - type: string - unpacked: - description: Unpacked image size in human-readable format. - example: 1G - type: string - unpackedBytes: - description: Unpacked image size in bytes. - example: 1000000234 - type: string - type: object - sourceUID: - description: UID of the source (VirtualImage, ClusterVirtualImage, - VirtualDisk or VirtualDiskSnapshot) used when creating the cluster - virtual image. - type: string - target: - properties: - registryURL: - description: Created image in DVCR. - example: dvcr..svc/cvi/:latest - type: string - type: object - uploadCommand: - description: Deprecated. Use `imageUploadURLs` instead. - type: string - usedInNamespaces: - description: Displays the list of namespaces where the image is currently - used. - items: + observedGeneration: + description: Resource generation last processed by the controller. + format: int64 + type: integer + phase: + description: |- + Current status of the ClusterVirtualImage resource: + * `Pending`: The resource has been created and is on a waiting queue. + * `Provisioning`: The resource is being created: copying, downloading, or building of the image is in progress. + * `WaitForUserUpload`: Waiting for the user to upload the image. The endpoint to upload the image is specified in `.status.uploadCommand`. + * `Ready`: The resource has been created and is ready to use. + * `Failed`: There was an error when creating the resource. + * `Terminating`: The resource is being deleted. + enum: + - Pending + - Provisioning + - WaitForUserUpload + - Ready + - Failed + - Terminating + type: string + progress: + description: + Progress of copying an image from the source to DVCR. + Appears only during the `Provisioning' phase. + type: string + size: + description: Discovered image size data. + properties: + stored: + description: Image size in human-readable format. + example: 199M + type: string + storedBytes: + description: Image size in bytes. + example: 199001234 + type: string + unpacked: + description: Unpacked image size in human-readable format. + example: 1G + type: string + unpackedBytes: + description: Unpacked image size in bytes. + example: 1000000234 + type: string + type: object + sourceUID: + description: + UID of the source (VirtualImage, ClusterVirtualImage, + VirtualDisk or VirtualDiskSnapshot) used when creating the cluster + virtual image. type: string - type: array - type: object - required: - - spec - type: object - served: true - storage: true - subresources: - status: {} + target: + properties: + registryURL: + description: Created image in DVCR. + example: dvcr..svc/cvi/:latest + type: string + type: object + uploadCommand: + description: Deprecated. Use `imageUploadURLs` instead. + type: string + usedInNamespaces: + description: + Displays the list of namespaces where the image is currently + used. + items: + type: string + type: array + type: object + required: + - spec + type: object + served: true + storage: true + subresources: + status: {} diff --git a/crds/virtualdisks.yaml b/crds/virtualdisks.yaml index 875f85a46a..c00c80d46b 100644 --- a/crds/virtualdisks.yaml +++ b/crds/virtualdisks.yaml @@ -12,448 +12,470 @@ spec: group: virtualization.deckhouse.io names: categories: - - virtualization + - virtualization kind: VirtualDisk listKind: VirtualDiskList plural: virtualdisks shortNames: - - vd + - vd singular: virtualdisk scope: Namespaced versions: - - additionalPrinterColumns: - - jsonPath: .status.phase - name: Phase - type: string - - jsonPath: .status.capacity - name: Capacity - type: string - - jsonPath: .status.conditions[?(@.type=='InUse')].status - name: InUse - priority: 1 - type: string - - jsonPath: .status.progress - name: Progress - priority: 1 - type: string - - jsonPath: .status.storageClassName - name: StorageClass - priority: 1 - type: string - - jsonPath: .status.target.persistentVolumeClaimName - name: TargetPVC - priority: 1 - type: string - - jsonPath: .metadata.creationTimestamp - name: Age - type: date - name: v1alpha2 - schema: - openAPIV3Schema: - description: |- - The VirtualDisk resource describes the desired virtual machine disk configuration. A VirtualDisk can be mounted statically in the virtual machine by specifying it in the `.spec.blockDeviceRefs` disk list, or mounted on-the-fly using the VirtualMachineBlockDeviceAttachments resource. + - additionalPrinterColumns: + - jsonPath: .status.phase + name: Phase + type: string + - jsonPath: .status.capacity + name: Capacity + type: string + - jsonPath: .status.conditions[?(@.type=='InUse')].status + name: InUse + priority: 1 + type: string + - jsonPath: .status.progress + name: Progress + priority: 1 + type: string + - jsonPath: .status.storageClassName + name: StorageClass + priority: 1 + type: string + - jsonPath: .status.target.persistentVolumeClaimName + name: TargetPVC + priority: 1 + type: string + - jsonPath: .metadata.creationTimestamp + name: Age + type: date + name: v1alpha2 + schema: + openAPIV3Schema: + description: |- + The VirtualDisk resource describes the desired virtual machine disk configuration. A VirtualDisk can be mounted statically in the virtual machine by specifying it in the `.spec.blockDeviceRefs` disk list, or mounted on-the-fly using the VirtualMachineBlockDeviceAttachments resource. - Once a VirtualDisk is created, only the disk size field `.spec.persistentVolumeClaim.size` can be changed. All other fields are immutable. - properties: - apiVersion: - description: |- - APIVersion defines the versioned schema of this representation of an object. - Servers should convert recognized schemas to the latest internal value, and - may reject unrecognized values. - More info: https://git.k8s.io/community/contributors/devel/sig-architecture/api-conventions.md#resources - type: string - kind: - description: |- - Kind is a string value representing the REST resource this object represents. - Servers may infer this from the endpoint the client submits requests to. - Cannot be updated. - In CamelCase. - More info: https://git.k8s.io/community/contributors/devel/sig-architecture/api-conventions.md#types-kinds - type: string - metadata: - type: object - spec: - properties: - dataSource: - properties: - containerImage: - description: Use an image stored in an external container registry. - Only registries with enabled TLS are supported. To provide a - custom Certificate Authority (CA) chain, use the `caBundle` - field. + Once a VirtualDisk is created, only the disk size field `.spec.persistentVolumeClaim.size` can be changed. All other fields are immutable. + properties: + apiVersion: + description: |- + APIVersion defines the versioned schema of this representation of an object. + Servers should convert recognized schemas to the latest internal value, and + may reject unrecognized values. + More info: https://git.k8s.io/community/contributors/devel/sig-architecture/api-conventions.md#resources + type: string + kind: + description: |- + Kind is a string value representing the REST resource this object represents. + Servers may infer this from the endpoint the client submits requests to. + Cannot be updated. + In CamelCase. + More info: https://git.k8s.io/community/contributors/devel/sig-architecture/api-conventions.md#types-kinds + type: string + metadata: + type: object + spec: + properties: + dataSource: + properties: + containerImage: + description: + Use an image stored in an external container registry. + Only registries with enabled TLS are supported. To provide a + custom Certificate Authority (CA) chain, use the `caBundle` + field. + properties: + caBundle: + description: + CA chain in Base64 format to verify the container + registry. + example: YWFhCg== + format: byte + type: string + image: + description: Path to the image in the container registry. + example: registry.example.com/images/slackware:15 + pattern: ^(?P(?:(?P(?:(?:localhost|[\w-]+(?:\.[\w-]+)+)(?::\d+)?)|[\w]+:\d+)/)?(?P[a-z0-9_.-]+(?:/[a-z0-9_.-]+)*))(?::(?P[\w][\w.-]{0,127}))?(?:@(?P[A-Za-z][A-Za-z0-9]*(?:[+.-_][A-Za-z][A-Za-z0-9]*)*:[0-9a-fA-F]{32,}))?$ + type: string + imagePullSecret: + properties: + name: + description: + Name of the secret keeping container registry + credentials, which must be located in the same namespace. + type: string + type: object + required: + - image + type: object + http: + description: |- + Fill the image with data from an external URL. The following schemas are supported: + + * HTTP + * HTTPS + + For HTTPS schema, there is an option to skip the TLS verification. + properties: + caBundle: + description: CA chain in Base64 format to verify the URL. + example: YWFhCg== + format: byte + type: string + checksum: + description: + Checksum to verify integrity and consistency + of the downloaded file. The file must match all specified + checksums. + properties: + md5: + example: f3b59bed9f91e32fac1210184fcff6f5 + maxLength: 32 + minLength: 32 + pattern: ^[0-9a-fA-F]{32}$ + type: string + sha256: + example: 78be890d71dde316c412da2ce8332ba47b9ce7a29d573801d2777e01aa20b9b5 + maxLength: 64 + minLength: 64 + pattern: ^[0-9a-fA-F]{64}$ + type: string + type: object + url: + description: |- + URL of the file for creating an image. The following file formats are supported: + * qcow2 + * vmdk + * vdi + * iso + * raw + The file can be compressed into an archive in one of the following formats: + * gz + * xz + example: https://mirror.example.com/images/slackware-15.qcow.gz + pattern: ^http[s]?:\/\/(?:[a-zA-Z]|[0-9]|[$-_@.&+]|[!*\(\),]|(?:%[0-9a-fA-F][0-9a-fA-F]))+$ + type: string + required: + - url + type: object + objectRef: + description: + Use an existing VirtualImage, ClusterVirtualImage, + or VirtualDiskSnapshot resource to create a disk. + properties: + kind: + description: + Kind of the existing VirtualImage, ClusterVirtualImage, + or VirtualDiskSnapshot resource. + enum: + - ClusterVirtualImage + - VirtualImage + - VirtualDiskSnapshot + type: string + name: + description: + Name of the existing VirtualImage, ClusterVirtualImage, + or VirtualDiskSnapshot resource. + type: string + required: + - kind + - name + type: object + type: + description: |- + The following image sources are available for creating an image: + + * `HTTP`: From a file published on an HTTP/HTTPS service at a given URL. + * `ContainerImage`: From another image stored in a container registry. + * `ObjectRef`: From an existing resource. + * `Upload`: From data uploaded by the user via a special interface. + enum: + - HTTP + - ContainerImage + - ObjectRef + - Upload + type: string + type: object + x-kubernetes-validations: + - message: HTTP requires http and cannot have ContainerImage or ObjectRef. + rule: + "self.type == 'HTTP' ? has(self.http) && !has(self.containerImage) + && !has(self.objectRef) : true" + - message: + ContainerImage requires containerImage and cannot have + HTTP or ObjectRef. + rule: + "self.type == 'ContainerImage' ? has(self.containerImage) + && !has(self.http) && !has(self.objectRef) : true" + - message: ObjectRef requires objectRef and cannot have HTTP or ContainerImage. + rule: + "self.type == 'ObjectRef' ? has(self.objectRef) && !has(self.http) + && !has(self.containerImage) : true" + persistentVolumeClaim: + description: Settings for creating PVCs to store the disk. + properties: + size: + anyOf: + - type: integer + - type: string + description: |- + Desired size for PVC to store the disk. If the disk is created from an image, the size must be at least as large as the original unpacked image. + + This parameter can be omitted if the `.spec.dataSource` section is filled out. In this case, the controller will determine the disk size automatically, based on the size of the extracted image from the source specified in `.spec.dataSource`. + pattern: ^(\+|-)?(([0-9]+(\.[0-9]*)?)|(\.[0-9]+))(([KMGTPE]i)|[numkMGTPE]|([eE](\+|-)?(([0-9]+(\.[0-9]*)?)|(\.[0-9]+))))?$ + x-kubernetes-int-or-string: true + storageClassName: + description: |- + StorageClass name required by the claim. For details on using StorageClass for PVC, refer to https://kubernetes.io/docs/concepts/storage/persistent-volumes#class-1. + + When creating disks, the user can specify the required StorageClass. If not specified, the default StorageClass will be used. + + The disk features and virtual machine behavior depend on the selected StorageClass. + + The `VolumeBindingMode` parameter in the StorageClass affects the disk creation process. The following values are allowed: + - `Immediate`: The disk will be created and becomes available for use immediately after creation. + - `WaitForFirstConsumer`: The disk will be created when first used on the node where the virtual machine will be started. + + StorageClass supports multiple storage settings: + - Creating a block device (`Block`) or file system (`FileSystem`). + - Multiple access (`ReadWriteMany`) or single access (`ReadWriteOnce`). The `ReadWriteMany` disks support multiple access, which enables a "live" migration of virtual machines. In contrast, the `ReadWriteOnce` disks, which can be accessed from only one node, don't have this feature. + + For known storage types, Deckhouse automatically determines the most efficient settings when creating disks (by priority, in descending order): + 1. `Block` + `ReadWriteMany` + 2. `FileSystem` + `ReadWriteMany` + 3. `Block` + `ReadWriteOnce` + 4. `FileSystem` + `ReadWriteOnce` + type: string + type: object + type: object + status: + properties: + attachedToVirtualMachines: + description: List of VirtualMachines that use the disk. + example: + - name: VM100 + items: + description: List of VirtualMachines that use the disk. properties: - caBundle: - description: CA chain in Base64 format to verify the container - registry. - example: YWFhCg== - format: byte - type: string - image: - description: Path to the image in the container registry. - example: registry.example.com/images/slackware:15 - pattern: ^(?P(?:(?P(?:(?:localhost|[\w-]+(?:\.[\w-]+)+)(?::\d+)?)|[\w]+:\d+)/)?(?P[a-z0-9_.-]+(?:/[a-z0-9_.-]+)*))(?::(?P[\w][\w.-]{0,127}))?(?:@(?P[A-Za-z][A-Za-z0-9]*(?:[+.-_][A-Za-z][A-Za-z0-9]*)*:[0-9a-fA-F]{32,}))?$ + mounted: + description: + Flag indicating that VirtualDisk is currently being + used by this attached VirtualMachine. + type: boolean + name: + description: Name of attached VirtualMachine. type: string - imagePullSecret: - properties: - name: - description: Name of the secret keeping container registry - credentials, which must be located in the same namespace. - type: string - type: object - required: - - image type: object - http: - description: |- - Fill the image with data from an external URL. The following schemas are supported: - - * HTTP - * HTTPS - - For HTTPS schema, there is an option to skip the TLS verification. + type: array + capacity: + description: Requested PVC capacity in human-readable format. + example: 50G + type: string + conditions: + description: + The latest available observations of an object's current + state. + items: + description: + Condition contains details for one aspect of the current + state of this API Resource. properties: - caBundle: - description: CA chain in Base64 format to verify the URL. - example: YWFhCg== - format: byte + lastTransitionTime: + description: |- + lastTransitionTime is the last time the condition transitioned from one status to another. + This should be when the underlying condition changed. If that is not known, then using the time when the API field changed is acceptable. + format: date-time type: string - checksum: - description: Checksum to verify integrity and consistency - of the downloaded file. The file must match all specified - checksums. - properties: - md5: - example: f3b59bed9f91e32fac1210184fcff6f5 - maxLength: 32 - minLength: 32 - pattern: ^[0-9a-fA-F]{32}$ - type: string - sha256: - example: 78be890d71dde316c412da2ce8332ba47b9ce7a29d573801d2777e01aa20b9b5 - maxLength: 64 - minLength: 64 - pattern: ^[0-9a-fA-F]{64}$ - type: string - type: object - url: + message: description: |- - URL of the file for creating an image. The following file formats are supported: - * qcow2 - * vmdk - * vdi - * iso - * raw - The file can be compressed into an archive in one of the following formats: - * gz - * xz - example: https://mirror.example.com/images/slackware-15.qcow.gz - pattern: ^http[s]?:\/\/(?:[a-zA-Z]|[0-9]|[$-_@.&+]|[!*\(\),]|(?:%[0-9a-fA-F][0-9a-fA-F]))+$ + message is a human readable message indicating details about the transition. + This may be an empty string. + maxLength: 32768 type: string - required: - - url - type: object - objectRef: - description: Use an existing VirtualImage, ClusterVirtualImage, - or VirtualDiskSnapshot resource to create a disk. - properties: - kind: - description: Kind of the existing VirtualImage, ClusterVirtualImage, - or VirtualDiskSnapshot resource. + observedGeneration: + description: |- + observedGeneration represents the .metadata.generation that the condition was set based upon. + For instance, if .metadata.generation is currently 12, but the .status.conditions[x].observedGeneration is 9, the condition is out of date + with respect to the current state of the instance. + format: int64 + minimum: 0 + type: integer + reason: + description: |- + reason contains a programmatic identifier indicating the reason for the condition's last transition. + Producers of specific condition types may define expected values and meanings for this field, + and whether the values are considered a guaranteed API. + The value should be a CamelCase string. + This field may not be empty. + maxLength: 1024 + minLength: 1 + pattern: ^[A-Za-z]([A-Za-z0-9_,:]*[A-Za-z0-9_])?$ + type: string + status: + description: status of the condition, one of True, False, Unknown. enum: - - ClusterVirtualImage - - VirtualImage - - VirtualDiskSnapshot + - "True" + - "False" + - Unknown type: string - name: - description: Name of the existing VirtualImage, ClusterVirtualImage, - or VirtualDiskSnapshot resource. + type: + description: type of condition in CamelCase or in foo.example.com/CamelCase. + maxLength: 316 + pattern: ^([a-z0-9]([-a-z0-9]*[a-z0-9])?(\.[a-z0-9]([-a-z0-9]*[a-z0-9])?)*/)?(([A-Za-z0-9][-A-Za-z0-9_.]*)?[A-Za-z0-9])$ type: string required: - - kind - - name + - lastTransitionTime + - message + - reason + - status + - type type: object - type: - description: |- - The following image sources are available for creating an image: - - * `HTTP`: From a file published on an HTTP/HTTPS service at a given URL. - * `ContainerImage`: From another image stored in a container registry. - * `ObjectRef`: From an existing resource. - * `Upload`: From data uploaded by the user via a special interface. - enum: - - HTTP - - ContainerImage - - ObjectRef - - Upload - type: string - type: object - x-kubernetes-validations: - - message: HTTP requires http and cannot have ContainerImage or ObjectRef. - rule: 'self.type == ''HTTP'' ? has(self.http) && !has(self.containerImage) - && !has(self.objectRef) : true' - - message: ContainerImage requires containerImage and cannot have - HTTP or ObjectRef. - rule: 'self.type == ''ContainerImage'' ? has(self.containerImage) - && !has(self.http) && !has(self.objectRef) : true' - - message: ObjectRef requires objectRef and cannot have HTTP or ContainerImage. - rule: 'self.type == ''ObjectRef'' ? has(self.objectRef) && !has(self.http) - && !has(self.containerImage) : true' - persistentVolumeClaim: - description: Settings for creating PVCs to store the disk. - properties: - size: - anyOf: - - type: integer - - type: string - description: |- - Desired size for PVC to store the disk. If the disk is created from an image, the size must be at least as large as the original unpacked image. - - This parameter can be omitted if the `.spec.dataSource` section is filled out. In this case, the controller will determine the disk size automatically, based on the size of the extracted image from the source specified in `.spec.dataSource`. - pattern: ^(\+|-)?(([0-9]+(\.[0-9]*)?)|(\.[0-9]+))(([KMGTPE]i)|[numkMGTPE]|([eE](\+|-)?(([0-9]+(\.[0-9]*)?)|(\.[0-9]+))))?$ - x-kubernetes-int-or-string: true - storageClassName: - description: |- - StorageClass name required by the claim. For details on using StorageClass for PVC, refer to https://kubernetes.io/docs/concepts/storage/persistent-volumes#class-1. - - When creating disks, the user can specify the required StorageClass. If not specified, the default StorageClass will be used. - - The disk features and virtual machine behavior depend on the selected StorageClass. - - The `VolumeBindingMode` parameter in the StorageClass affects the disk creation process. The following values are allowed: - - `Immediate`: The disk will be created and becomes available for use immediately after creation. - - `WaitForFirstConsumer`: The disk will be created when first used on the node where the virtual machine will be started. - - StorageClass supports multiple storage settings: - - Creating a block device (`Block`) or file system (`FileSystem`). - - Multiple access (`ReadWriteMany`) or single access (`ReadWriteOnce`). The `ReadWriteMany` disks support multiple access, which enables a "live" migration of virtual machines. In contrast, the `ReadWriteOnce` disks, which can be accessed from only one node, don't have this feature. - - For known storage types, Deckhouse automatically determines the most efficient settings when creating disks (by priority, in descending order): - 1. `Block` + `ReadWriteMany` - 2. `FileSystem` + `ReadWriteMany` - 3. `Block` + `ReadWriteOnce` - 4. `FileSystem` + `ReadWriteOnce` - type: string - type: object - type: object - status: - properties: - attachedToVirtualMachines: - description: List of VirtualMachines that use the disk. - example: - - name: VM100 - items: - description: List of VirtualMachines that use the disk. + type: array + downloadSpeed: + description: + Image download speed from an external source. Appears + only during the `Provisioning` phase. properties: - mounted: - description: Flag indicating that VirtualDisk is currently being - used by this attached VirtualMachine. - type: boolean - name: - description: Name of attached VirtualMachine. + avg: + description: Average download speed. + example: 1 Mbps + type: string + avgBytes: + description: Average download speed in bytes per second. + example: 1012345 + type: string + current: + description: Current download speed. + example: 5 Mbps + type: string + currentBytes: + description: Current download speed in bytes per second. + example: 5123456 type: string type: object - type: array - capacity: - description: Requested PVC capacity in human-readable format. - example: 50G - type: string - conditions: - description: The latest available observations of an object's current - state. - items: - description: Condition contains details for one aspect of the current - state of this API Resource. + imageUploadURLs: properties: - lastTransitionTime: - description: |- - lastTransitionTime is the last time the condition transitioned from one status to another. - This should be when the underlying condition changed. If that is not known, then using the time when the API field changed is acceptable. + external: + description: + Command to upload the image using `Ingress` from + outside the cluster. + type: string + inCluster: + description: + Command to upload the image using `Service` within + the cluster. + type: string + type: object + migrationState: + description: Migration information. + properties: + endTimestamp: format: date-time type: string message: - description: |- - message is a human readable message indicating details about the transition. - This may be an empty string. - maxLength: 32768 type: string - observedGeneration: - description: |- - observedGeneration represents the .metadata.generation that the condition was set based upon. - For instance, if .metadata.generation is currently 12, but the .status.conditions[x].observedGeneration is 9, the condition is out of date - with respect to the current state of the instance. - format: int64 - minimum: 0 - type: integer - reason: - description: |- - reason contains a programmatic identifier indicating the reason for the condition's last transition. - Producers of specific condition types may define expected values and meanings for this field, - and whether the values are considered a guaranteed API. - The value should be a CamelCase string. - This field may not be empty. - maxLength: 1024 - minLength: 1 - pattern: ^[A-Za-z]([A-Za-z0-9_,:]*[A-Za-z0-9_])?$ - type: string - status: - description: status of the condition, one of True, False, Unknown. + result: + description: + VirtualDiskMigrationResult is the result of the VirtualDisk + migration. enum: - - "True" - - "False" - - Unknown + - Succeeded + - Failed type: string - type: - description: type of condition in CamelCase or in foo.example.com/CamelCase. - maxLength: 316 - pattern: ^([a-z0-9]([-a-z0-9]*[a-z0-9])?(\.[a-z0-9]([-a-z0-9]*[a-z0-9])?)*/)?(([A-Za-z0-9][-A-Za-z0-9_.]*)?[A-Za-z0-9])$ + sourcePVC: + description: Source PersistentVolumeClaim name. + type: string + startTimestamp: + format: date-time + type: string + targetPVC: + description: Target PersistentVolumeClaim name. type: string - required: - - lastTransitionTime - - message - - reason - - status - - type type: object - type: array - downloadSpeed: - description: Image download speed from an external source. Appears - only during the `Provisioning` phase. - properties: - avg: - description: Average download speed. - example: 1 Mbps - type: string - avgBytes: - description: Average download speed in bytes per second. - example: 1012345 - type: string - current: - description: Current download speed. - example: 5 Mbps - type: string - currentBytes: - description: Current download speed in bytes per second. - example: 5123456 - type: string - type: object - imageUploadURLs: - properties: - external: - description: Command to upload the image using `Ingress` from - outside the cluster. - type: string - inCluster: - description: Command to upload the image using `Service` within - the cluster. - type: string - type: object - migrationState: - description: Migration information. - properties: - endTimestamp: - format: date-time - type: string - message: - type: string - result: - description: VirtualDiskMigrationResult is the result of the VirtualDisk - migration. - enum: - - Succeeded + observedGeneration: + description: Resource generation last processed by the controller. + format: int64 + type: integer + phase: + description: |- + Current status of the VirtualDisk resource: + * `Pending`: The resource has been created and is on a waiting queue. + * `Provisioning`: The resource is being created: copying, downloading, loading data to the PVC, or extending the PVC. + * `WaitForUserUpload`: Waiting for the user to upload the image. The endpoint to upload the image is specified in `.status.uploadCommand`. + * `WaitForFirstConsumer`: Waiting for the virtual machine using the disk to be assigned to the node. + * `Ready`: The resource has been created and is ready to use. + * `Resizing`: The process of resource resizing is in progress. + * `Failed`: There was an error when creating the resource. + * `PVCLost`: The child PVC of the resource is missing. The resource cannot be used. + * `Exporting`: The child PV of the resource is in the process of exporting. + * `Terminating`: The resource is being deleted. + * `Migrating`: The resource is being migrating. + enum: + - Pending + - Provisioning + - WaitForUserUpload + - WaitForFirstConsumer + - Ready + - Resizing - Failed - type: string - sourcePVC: - description: Source PersistentVolumeClaim name. - type: string - startTimestamp: - format: date-time - type: string - targetPVC: - description: Target PersistentVolumeClaim name. - type: string - type: object - observedGeneration: - description: Resource generation last processed by the controller. - format: int64 - type: integer - phase: - description: |- - Current status of the VirtualDisk resource: - * `Pending`: The resource has been created and is on a waiting queue. - * `Provisioning`: The resource is being created: copying, downloading, loading data to the PVC, or extending the PVC. - * `WaitForUserUpload`: Waiting for the user to upload the image. The endpoint to upload the image is specified in `.status.uploadCommand`. - * `WaitForFirstConsumer`: Waiting for the virtual machine using the disk to be assigned to the node. - * `Ready`: The resource has been created and is ready to use. - * `Resizing`: The process of resource resizing is in progress. - * `Failed`: There was an error when creating the resource. - * `PVCLost`: The child PVC of the resource is missing. The resource cannot be used. - * `Exporting`: The child PV of the resource is in the process of exporting. - * `Terminating`: The resource is being deleted. - * `Migrating`: The resource is being migrating. - enum: - - Pending - - Provisioning - - WaitForUserUpload - - WaitForFirstConsumer - - Ready - - Resizing - - Failed - - PVCLost - - Exporting - - Terminating - - Migrating - type: string - progress: - description: Progress of copying an image from a source to PVC. Appears - only during the `Provisioning' phase. - type: string - sourceUID: - description: |- - UID is a type that holds unique ID values, including UUIDs. Because we - don't ONLY use UUIDs, this is an alias to string. Being a type captures - intent and helps make sure that UIDs and names do not get conflated. - type: string - stats: - description: VirtualDisk statistics. - properties: - creationDuration: - description: Waiting time for the virtual disk creation. - properties: - dvcrProvisioning: - description: Duration of the loading into DVCR. - nullable: true - type: string - totalProvisioning: - description: Duration of the resource creation from the moment - dependencies are ready until the resource transitions to - the Ready state. - nullable: true - type: string - waitingForDependencies: - description: Waiting time for dependent resources. - nullable: true - type: string - type: object - type: object - storageClassName: - description: Name of the StorageClass used by the PersistentVolumeClaim - if `Kubernetes` storage type is used. - type: string - target: - properties: - persistentVolumeClaimName: - description: Created PersistentVolumeClaim name for the Kubernetes - storage. - type: string - type: object - uploadCommand: - description: Deprecated. Use `ImageUploadURLs` instead. - type: string - type: object - required: - - spec - type: object - served: true - storage: true - subresources: - status: {} + - PVCLost + - Exporting + - Terminating + - Migrating + type: string + progress: + description: + Progress of copying an image from a source to PVC. Appears + only during the `Provisioning' phase. + type: string + sourceUID: + description: |- + UID is a type that holds unique ID values, including UUIDs. Because we + don't ONLY use UUIDs, this is an alias to string. Being a type captures + intent and helps make sure that UIDs and names do not get conflated. + type: string + stats: + description: VirtualDisk statistics. + properties: + creationDuration: + description: Waiting time for the virtual disk creation. + properties: + dvcrProvisioning: + description: Duration of the loading into DVCR. + nullable: true + type: string + totalProvisioning: + description: + Duration of the resource creation from the moment + dependencies are ready until the resource transitions to + the Ready state. + nullable: true + type: string + waitingForDependencies: + description: Waiting time for dependent resources. + nullable: true + type: string + type: object + type: object + storageClassName: + description: + Name of the StorageClass used by the PersistentVolumeClaim + if `Kubernetes` storage type is used. + type: string + target: + properties: + persistentVolumeClaimName: + description: + Created PersistentVolumeClaim name for the Kubernetes + storage. + type: string + type: object + uploadCommand: + description: Deprecated. Use `ImageUploadURLs` instead. + type: string + type: object + required: + - spec + type: object + served: true + storage: true + subresources: + status: {} diff --git a/crds/virtualimages.yaml b/crds/virtualimages.yaml index 9bd63745a7..700a9418b2 100644 --- a/crds/virtualimages.yaml +++ b/crds/virtualimages.yaml @@ -12,399 +12,420 @@ spec: group: virtualization.deckhouse.io names: categories: - - virtualization + - virtualization kind: VirtualImage listKind: VirtualImageList plural: virtualimages shortNames: - - vi + - vi singular: virtualimage scope: Namespaced versions: - - additionalPrinterColumns: - - jsonPath: .status.phase - name: Phase - type: string - - jsonPath: .status.cdrom - name: CDROM - type: boolean - - jsonPath: .status.progress - name: Progress - type: string - - jsonPath: .status.size.stored - name: StoredSize - priority: 1 - type: string - - jsonPath: .status.size.unpacked - name: UnpackedSize - priority: 1 - type: string - - jsonPath: .status.target.registryURL - name: Registry URL - priority: 1 - type: string - - jsonPath: .status.target.persistentVolumeClaimName - name: TargetPVC - priority: 1 - type: string - - jsonPath: .metadata.creationTimestamp - name: Age - type: date - name: v1alpha2 - schema: - openAPIV3Schema: - description: |- - This resource describes a virtual disk image to use as a data source for new VirtualDisk resources or an installation image (iso) that can be mounted into the VirtualMachine resource. + - additionalPrinterColumns: + - jsonPath: .status.phase + name: Phase + type: string + - jsonPath: .status.cdrom + name: CDROM + type: boolean + - jsonPath: .status.progress + name: Progress + type: string + - jsonPath: .status.size.stored + name: StoredSize + priority: 1 + type: string + - jsonPath: .status.size.unpacked + name: UnpackedSize + priority: 1 + type: string + - jsonPath: .status.target.registryURL + name: Registry URL + priority: 1 + type: string + - jsonPath: .status.target.persistentVolumeClaimName + name: TargetPVC + priority: 1 + type: string + - jsonPath: .metadata.creationTimestamp + name: Age + type: date + name: v1alpha2 + schema: + openAPIV3Schema: + description: |- + This resource describes a virtual disk image to use as a data source for new VirtualDisk resources or an installation image (iso) that can be mounted into the VirtualMachine resource. - > This resource cannot be modified once it has been created. + > This resource cannot be modified once it has been created. - With this resource in the cluster, a container image is created and stored in a dedicated Deckhouse Virtualization Container Registry (DVCR) or PVC, with the data filled in from the source. - properties: - apiVersion: - description: |- - APIVersion defines the versioned schema of this representation of an object. - Servers should convert recognized schemas to the latest internal value, and - may reject unrecognized values. - More info: https://git.k8s.io/community/contributors/devel/sig-architecture/api-conventions.md#resources - type: string - kind: - description: |- - Kind is a string value representing the REST resource this object represents. - Servers may infer this from the endpoint the client submits requests to. - Cannot be updated. - In CamelCase. - More info: https://git.k8s.io/community/contributors/devel/sig-architecture/api-conventions.md#types-kinds - type: string - metadata: - type: object - spec: - properties: - dataSource: - properties: - containerImage: - description: Use an image stored in an external container registry. - Only registries with enabled TLS protocol are supported. To - provide a custom Certificate Authority (CA) chain, use the `caBundle` - field. - properties: - caBundle: - description: CA chain in Base64 format to verify the container - registry. - example: YWFhCg== - format: byte - type: string - image: - description: Path to the image in the container registry. - example: registry.example.com/images/slackware:15 - pattern: ^(?P(?:(?P(?:(?:localhost|[\w-]+(?:\.[\w-]+)+)(?::\d+)?)|[\w]+:\d+)/)?(?P[a-z0-9_.-]+(?:/[a-z0-9_.-]+)*))(?::(?P[\w][\w.-]{0,127}))?(?:@(?P[A-Za-z][A-Za-z0-9]*(?:[+.-_][A-Za-z][A-Za-z0-9]*)*:[0-9a-fA-F]{32,}))?$ - type: string - imagePullSecret: - properties: - name: - description: Name of the secret keeping container registry - credentials, which must be located in the same namespace. - type: string - type: object - required: - - image - type: object - http: - description: |- - Fill the image with data from an external URL. The following schemas are supported: + With this resource in the cluster, a container image is created and stored in a dedicated Deckhouse Virtualization Container Registry (DVCR) or PVC, with the data filled in from the source. + properties: + apiVersion: + description: |- + APIVersion defines the versioned schema of this representation of an object. + Servers should convert recognized schemas to the latest internal value, and + may reject unrecognized values. + More info: https://git.k8s.io/community/contributors/devel/sig-architecture/api-conventions.md#resources + type: string + kind: + description: |- + Kind is a string value representing the REST resource this object represents. + Servers may infer this from the endpoint the client submits requests to. + Cannot be updated. + In CamelCase. + More info: https://git.k8s.io/community/contributors/devel/sig-architecture/api-conventions.md#types-kinds + type: string + metadata: + type: object + spec: + properties: + dataSource: + properties: + containerImage: + description: + Use an image stored in an external container registry. + Only registries with enabled TLS protocol are supported. To + provide a custom Certificate Authority (CA) chain, use the `caBundle` + field. + properties: + caBundle: + description: + CA chain in Base64 format to verify the container + registry. + example: YWFhCg== + format: byte + type: string + image: + description: Path to the image in the container registry. + example: registry.example.com/images/slackware:15 + pattern: ^(?P(?:(?P(?:(?:localhost|[\w-]+(?:\.[\w-]+)+)(?::\d+)?)|[\w]+:\d+)/)?(?P[a-z0-9_.-]+(?:/[a-z0-9_.-]+)*))(?::(?P[\w][\w.-]{0,127}))?(?:@(?P[A-Za-z][A-Za-z0-9]*(?:[+.-_][A-Za-z][A-Za-z0-9]*)*:[0-9a-fA-F]{32,}))?$ + type: string + imagePullSecret: + properties: + name: + description: + Name of the secret keeping container registry + credentials, which must be located in the same namespace. + type: string + type: object + required: + - image + type: object + http: + description: |- + Fill the image with data from an external URL. The following schemas are supported: + + * HTTP + * HTTPS + + For HTTPS schema, there is an option to skip the TLS verification. + properties: + caBundle: + description: CA chain in Base64 format to verify the URL. + example: YWFhCg== + format: byte + type: string + checksum: + description: + Checksum to verify integrity and consistency + of the downloaded file. The file must match all specified + checksums. + properties: + md5: + example: f3b59bed9f91e32fac1210184fcff6f5 + maxLength: 32 + minLength: 32 + pattern: ^[0-9a-fA-F]{32}$ + type: string + sha256: + example: 78be890d71dde316c412da2ce8332ba47b9ce7a29d573801d2777e01aa20b9b5 + maxLength: 64 + minLength: 64 + pattern: ^[0-9a-fA-F]{64}$ + type: string + type: object + url: + description: |- + URL of the file for creating an image. The following file formats are supported: + * qcow2 + * vmdk + * vdi + * iso + * raw + The file can be compressed into an archive in one of the following formats: + * gz + * xz + example: https://mirror.example.com/images/slackware-15.qcow.gz + pattern: ^http[s]?:\/\/(?:[a-zA-Z]|[0-9]|[$-_@.&+]|[!*\(\),]|(?:%[0-9a-fA-F][0-9a-fA-F]))+$ + type: string + required: + - url + type: object + objectRef: + description: + Use an existing VirtualImage, ClusterVirtualImage, + VirtualDisk or VirtualDiskSnapshot resource to create an image. + properties: + kind: + description: + Kind of an existing VirtualImage, ClusterVirtualImage, + VirtualDisk or VirtualDiskSnapshot resource. + enum: + - ClusterVirtualImage + - VirtualImage + - VirtualDisk + - VirtualDiskSnapshot + type: string + name: + description: + Name of an existing VirtualImage, ClusterVirtualImage, + VirtualDisk or VirtualDiskSnapshot resource. + type: string + required: + - kind + - name + type: object + type: + description: |- + The following image sources are available for creating an image: + + * `HTTP`: From a file published on an HTTP/HTTPS service at a given URL. + * `ContainerImage`: From another image stored in a container registry. + * `ObjectRef`: From an existing resource. + * `Upload`: From data uploaded by the user via a special interface. + enum: + - HTTP + - ContainerImage + - ObjectRef + - Upload + type: string + type: object + x-kubernetes-validations: + - message: HTTP requires http and cannot have ContainerImage or ObjectRef. + rule: + "self.type == 'HTTP' ? has(self.http) && !has(self.containerImage) + && !has(self.objectRef) : true" + - message: + ContainerImage requires containerImage and cannot have + HTTP or ObjectRef. + rule: + "self.type == 'ContainerImage' ? has(self.containerImage) + && !has(self.http) && !has(self.objectRef) : true" + - message: ObjectRef requires objectRef and cannot have HTTP or ContainerImage. + rule: + "self.type == 'ObjectRef' ? has(self.objectRef) && !has(self.http) + && !has(self.containerImage) : true" + persistentVolumeClaim: + description: + Settings for creating PVCs to store an image with the + storage type `PersistentVolumeClaim`. + properties: + storageClassName: + description: |- + Name of the StorageClass required by the claim. For details on using StorageClass for PVC, refer to — https://kubernetes.io/docs/concepts/storage/persistent-volumes#class-1. - * HTTP - * HTTPS + When creating an image with the `PersistentVolumeClaim` storage type, the user can specify the required StorageClass. If not specified, the default StorageClass will be used. + type: string + type: object + storage: + default: ContainerRegistry + description: |- + Storage type to keep the image for the current virtualization setup. - For HTTPS schema, there is an option to skip the TLS verification. + * `ContainerRegistry`: Use the DVCR container registry. In this case, images are downloaded to a container and then to DVCR (shipped with the virtualization module). + * `PersistentVolumeClaim`: Use a PVC. + * `Kubernetes`: A deprecated storage type. Not recommended for use and may be removed in future versions. Use `PersistentVolumeClaim` instead. + enum: + - ContainerRegistry + - Kubernetes + - PersistentVolumeClaim + type: string + required: + - dataSource + - storage + type: object + status: + properties: + cdrom: + description: + Whether the image is in a format that needs to be mounted + as a CD-ROM drive, such as iso and so on. + type: boolean + conditions: + description: + The latest available observations of an object's current + state. + items: + description: + Condition contains details for one aspect of the current + state of this API Resource. properties: - caBundle: - description: CA chain in Base64 format to verify the URL. - example: YWFhCg== - format: byte + lastTransitionTime: + description: |- + lastTransitionTime is the last time the condition transitioned from one status to another. + This should be when the underlying condition changed. If that is not known, then using the time when the API field changed is acceptable. + format: date-time type: string - checksum: - description: Checksum to verify integrity and consistency - of the downloaded file. The file must match all specified - checksums. - properties: - md5: - example: f3b59bed9f91e32fac1210184fcff6f5 - maxLength: 32 - minLength: 32 - pattern: ^[0-9a-fA-F]{32}$ - type: string - sha256: - example: 78be890d71dde316c412da2ce8332ba47b9ce7a29d573801d2777e01aa20b9b5 - maxLength: 64 - minLength: 64 - pattern: ^[0-9a-fA-F]{64}$ - type: string - type: object - url: + message: description: |- - URL of the file for creating an image. The following file formats are supported: - * qcow2 - * vmdk - * vdi - * iso - * raw - The file can be compressed into an archive in one of the following formats: - * gz - * xz - example: https://mirror.example.com/images/slackware-15.qcow.gz - pattern: ^http[s]?:\/\/(?:[a-zA-Z]|[0-9]|[$-_@.&+]|[!*\(\),]|(?:%[0-9a-fA-F][0-9a-fA-F]))+$ + message is a human readable message indicating details about the transition. + This may be an empty string. + maxLength: 32768 type: string - required: - - url - type: object - objectRef: - description: Use an existing VirtualImage, ClusterVirtualImage, - VirtualDisk or VirtualDiskSnapshot resource to create an image. - properties: - kind: - description: Kind of an existing VirtualImage, ClusterVirtualImage, - VirtualDisk or VirtualDiskSnapshot resource. + observedGeneration: + description: |- + observedGeneration represents the .metadata.generation that the condition was set based upon. + For instance, if .metadata.generation is currently 12, but the .status.conditions[x].observedGeneration is 9, the condition is out of date + with respect to the current state of the instance. + format: int64 + minimum: 0 + type: integer + reason: + description: |- + reason contains a programmatic identifier indicating the reason for the condition's last transition. + Producers of specific condition types may define expected values and meanings for this field, + and whether the values are considered a guaranteed API. + The value should be a CamelCase string. + This field may not be empty. + maxLength: 1024 + minLength: 1 + pattern: ^[A-Za-z]([A-Za-z0-9_,:]*[A-Za-z0-9_])?$ + type: string + status: + description: status of the condition, one of True, False, Unknown. enum: - - ClusterVirtualImage - - VirtualImage - - VirtualDisk - - VirtualDiskSnapshot + - "True" + - "False" + - Unknown type: string - name: - description: Name of an existing VirtualImage, ClusterVirtualImage, - VirtualDisk or VirtualDiskSnapshot resource. + type: + description: type of condition in CamelCase or in foo.example.com/CamelCase. + maxLength: 316 + pattern: ^([a-z0-9]([-a-z0-9]*[a-z0-9])?(\.[a-z0-9]([-a-z0-9]*[a-z0-9])?)*/)?(([A-Za-z0-9][-A-Za-z0-9_.]*)?[A-Za-z0-9])$ type: string required: - - kind - - name + - lastTransitionTime + - message + - reason + - status + - type type: object - type: - description: |- - The following image sources are available for creating an image: - - * `HTTP`: From a file published on an HTTP/HTTPS service at a given URL. - * `ContainerImage`: From another image stored in a container registry. - * `ObjectRef`: From an existing resource. - * `Upload`: From data uploaded by the user via a special interface. - enum: - - HTTP - - ContainerImage - - ObjectRef - - Upload - type: string - type: object - x-kubernetes-validations: - - message: HTTP requires http and cannot have ContainerImage or ObjectRef. - rule: 'self.type == ''HTTP'' ? has(self.http) && !has(self.containerImage) - && !has(self.objectRef) : true' - - message: ContainerImage requires containerImage and cannot have - HTTP or ObjectRef. - rule: 'self.type == ''ContainerImage'' ? has(self.containerImage) - && !has(self.http) && !has(self.objectRef) : true' - - message: ObjectRef requires objectRef and cannot have HTTP or ContainerImage. - rule: 'self.type == ''ObjectRef'' ? has(self.objectRef) && !has(self.http) - && !has(self.containerImage) : true' - persistentVolumeClaim: - description: Settings for creating PVCs to store an image with the - storage type `PersistentVolumeClaim`. - properties: - storageClassName: - description: |- - Name of the StorageClass required by the claim. For details on using StorageClass for PVC, refer to — https://kubernetes.io/docs/concepts/storage/persistent-volumes#class-1. - - When creating an image with the `PersistentVolumeClaim` storage type, the user can specify the required StorageClass. If not specified, the default StorageClass will be used. - type: string - type: object - storage: - default: ContainerRegistry - description: |- - Storage type to keep the image for the current virtualization setup. - - * `ContainerRegistry`: Use the DVCR container registry. In this case, images are downloaded to a container and then to DVCR (shipped with the virtualization module). - * `PersistentVolumeClaim`: Use a PVC. - * `Kubernetes`: A deprecated storage type. Not recommended for use and may be removed in future versions. Use `PersistentVolumeClaim` instead. - enum: - - ContainerRegistry - - Kubernetes - - PersistentVolumeClaim - type: string - required: - - dataSource - - storage - type: object - status: - properties: - cdrom: - description: Whether the image is in a format that needs to be mounted - as a CD-ROM drive, such as iso and so on. - type: boolean - conditions: - description: The latest available observations of an object's current - state. - items: - description: Condition contains details for one aspect of the current - state of this API Resource. + type: array + downloadSpeed: + description: + Image download speed from an external source. Appears + only during the `Provisioning` phase. properties: - lastTransitionTime: - description: |- - lastTransitionTime is the last time the condition transitioned from one status to another. - This should be when the underlying condition changed. If that is not known, then using the time when the API field changed is acceptable. - format: date-time + avg: + description: Average download speed. + example: 1 Mbps type: string - message: - description: |- - message is a human readable message indicating details about the transition. - This may be an empty string. - maxLength: 32768 + avgBytes: + description: Average download speed in bytes per second. + example: 1012345 type: string - observedGeneration: - description: |- - observedGeneration represents the .metadata.generation that the condition was set based upon. - For instance, if .metadata.generation is currently 12, but the .status.conditions[x].observedGeneration is 9, the condition is out of date - with respect to the current state of the instance. - format: int64 - minimum: 0 - type: integer - reason: - description: |- - reason contains a programmatic identifier indicating the reason for the condition's last transition. - Producers of specific condition types may define expected values and meanings for this field, - and whether the values are considered a guaranteed API. - The value should be a CamelCase string. - This field may not be empty. - maxLength: 1024 - minLength: 1 - pattern: ^[A-Za-z]([A-Za-z0-9_,:]*[A-Za-z0-9_])?$ + current: + description: Current download speed. + example: 5 Mbps type: string - status: - description: status of the condition, one of True, False, Unknown. - enum: - - "True" - - "False" - - Unknown + currentBytes: + description: Current download speed in bytes per second. + example: 5123456 type: string - type: - description: type of condition in CamelCase or in foo.example.com/CamelCase. - maxLength: 316 - pattern: ^([a-z0-9]([-a-z0-9]*[a-z0-9])?(\.[a-z0-9]([-a-z0-9]*[a-z0-9])?)*/)?(([A-Za-z0-9][-A-Za-z0-9_.]*)?[A-Za-z0-9])$ + type: object + format: + description: Discovered image format. + type: string + imageUploadURLs: + properties: + external: + description: + Command to upload the image using `Ingress` from + outside the cluster. + type: string + inCluster: + description: + Command to upload the image using `Service` within + the cluster. + type: string + type: object + observedGeneration: + description: Resource generation last processed by the controller. + format: int64 + type: integer + phase: + description: |- + Current status of the ClusterVirtualImage resource: + * `Pending`: The resource has been created and is on a waiting queue. + * `Provisioning`: The resource is being created: copying, downloading, or building the image. + * `WaitForUserUpload`: Waiting for the user to upload the image. The endpoint to upload the image is specified in `.status.uploadCommand`. + * `Ready`: The resource has been created and is ready to use. + * `Failed`: There was an error when creating the resource. + * `Terminating`: The resource is being deleted. + * `PVCLost`: The child PVC of the resource is missing. The resource cannot be used. + enum: + - Pending + - Provisioning + - WaitForUserUpload + - Ready + - Failed + - Terminating + - PVCLost + type: string + progress: + description: Progress of copying an image from a source to DVCR. + type: string + size: + description: Discovered image size data. + properties: + stored: + description: Image size in human-readable format. + example: 199M + type: string + storedBytes: + description: Image size in bytes. + example: 199001234 + type: string + unpacked: + description: Unpacked image size in human-readable format. + example: 1G + type: string + unpackedBytes: + description: Unpacked image size in bytes. + example: 1000000234 + type: string + type: object + sourceUID: + description: + UID of the source (VirtualImage, ClusterVirtualImage, + VirtualDisk or VirtualDiskSnapshot) used when creating the virtual + image. + type: string + storageClassName: + description: + Name of the StorageClass used by the PersistentVolumeClaim + if `Kubernetes` storage type is used. + type: string + target: + properties: + persistentVolumeClaimName: + description: + Created PersistentVolumeClaim name for the PersistentVolumeClaim + storage. + type: string + registryURL: + description: Created image in DVCR. + example: dvcr..svc/vi//:latest type: string - required: - - lastTransitionTime - - message - - reason - - status - - type type: object - type: array - downloadSpeed: - description: Image download speed from an external source. Appears - only during the `Provisioning` phase. - properties: - avg: - description: Average download speed. - example: 1 Mbps - type: string - avgBytes: - description: Average download speed in bytes per second. - example: 1012345 - type: string - current: - description: Current download speed. - example: 5 Mbps - type: string - currentBytes: - description: Current download speed in bytes per second. - example: 5123456 - type: string - type: object - format: - description: Discovered image format. - type: string - imageUploadURLs: - properties: - external: - description: Command to upload the image using `Ingress` from - outside the cluster. - type: string - inCluster: - description: Command to upload the image using `Service` within - the cluster. - type: string - type: object - observedGeneration: - description: Resource generation last processed by the controller. - format: int64 - type: integer - phase: - description: |- - Current status of the ClusterVirtualImage resource: - * `Pending`: The resource has been created and is on a waiting queue. - * `Provisioning`: The resource is being created: copying, downloading, or building the image. - * `WaitForUserUpload`: Waiting for the user to upload the image. The endpoint to upload the image is specified in `.status.uploadCommand`. - * `Ready`: The resource has been created and is ready to use. - * `Failed`: There was an error when creating the resource. - * `Terminating`: The resource is being deleted. - * `PVCLost`: The child PVC of the resource is missing. The resource cannot be used. - enum: - - Pending - - Provisioning - - WaitForUserUpload - - Ready - - Failed - - Terminating - - PVCLost - type: string - progress: - description: Progress of copying an image from a source to DVCR. - type: string - size: - description: Discovered image size data. - properties: - stored: - description: Image size in human-readable format. - example: 199M - type: string - storedBytes: - description: Image size in bytes. - example: 199001234 - type: string - unpacked: - description: Unpacked image size in human-readable format. - example: 1G - type: string - unpackedBytes: - description: Unpacked image size in bytes. - example: 1000000234 - type: string - type: object - sourceUID: - description: UID of the source (VirtualImage, ClusterVirtualImage, - VirtualDisk or VirtualDiskSnapshot) used when creating the virtual - image. - type: string - storageClassName: - description: Name of the StorageClass used by the PersistentVolumeClaim - if `Kubernetes` storage type is used. - type: string - target: - properties: - persistentVolumeClaimName: - description: Created PersistentVolumeClaim name for the PersistentVolumeClaim - storage. - type: string - registryURL: - description: Created image in DVCR. - example: dvcr..svc/vi//:latest - type: string - type: object - uploadCommand: - description: Deprecated. Use `imageUploadURLs` instead. - type: string - type: object - required: - - spec - type: object - served: true - storage: true - subresources: - status: {} + uploadCommand: + description: Deprecated. Use `imageUploadURLs` instead. + type: string + type: object + required: + - spec + type: object + served: true + storage: true + subresources: + status: {} diff --git a/crds/virtualmachineblockdeviceattachments.yaml b/crds/virtualmachineblockdeviceattachments.yaml index 6c8130e0e6..939fc91607 100644 --- a/crds/virtualmachineblockdeviceattachments.yaml +++ b/crds/virtualmachineblockdeviceattachments.yaml @@ -12,176 +12,180 @@ spec: group: virtualization.deckhouse.io names: categories: - - virtualization + - virtualization kind: VirtualMachineBlockDeviceAttachment listKind: VirtualMachineBlockDeviceAttachmentList plural: virtualmachineblockdeviceattachments shortNames: - - vmbda + - vmbda singular: virtualmachineblockdeviceattachment scope: Namespaced versions: - - additionalPrinterColumns: - - description: VirtualMachineBlockDeviceAttachment phase. - jsonPath: .status.phase - name: PHASE - type: string - - description: Attached blockdevice kind. - jsonPath: .spec.blockDeviceRef.kind - name: BLOCKDEVICE KIND - priority: 1 - type: string - - description: Attached blockdevice name. - jsonPath: .spec.blockDeviceRef.name - name: BLOCKDEVICE NAME - priority: 1 - type: string - - description: Name of the virtual machine the disk is attached to. - jsonPath: .status.virtualMachineName - name: VIRTUAL MACHINE NAME - type: string - - description: Time of resource creation. - jsonPath: .metadata.creationTimestamp - name: AGE - type: date - name: v1alpha2 - schema: - openAPIV3Schema: - description: VirtualMachineBlockDeviceAttachment provides a hot plug for attaching - a disk to a virtual machine. - properties: - apiVersion: - description: |- - APIVersion defines the versioned schema of this representation of an object. - Servers should convert recognized schemas to the latest internal value, and - may reject unrecognized values. - More info: https://git.k8s.io/community/contributors/devel/sig-architecture/api-conventions.md#resources - type: string - kind: - description: |- - Kind is a string value representing the REST resource this object represents. - Servers may infer this from the endpoint the client submits requests to. - Cannot be updated. - In CamelCase. - More info: https://git.k8s.io/community/contributors/devel/sig-architecture/api-conventions.md#types-kinds - type: string - metadata: - type: object - spec: - properties: - blockDeviceRef: - description: Block device that will be connected to the VM as a hot-plug - disk. - properties: - kind: - description: |- - Block device type. Available options: - * `VirtualDisk`: Use VirtualDisk as the disk. This type is always mounted in RW mode. - * `VirtualImage`: Use VirtualImage as the disk. This type is always mounted in RO mode. - * `ClusterVirtualImage`: Use ClusterVirtualImage as the disk. This type is always mounted in RO mode. - enum: - - VirtualDisk - - VirtualImage - - ClusterVirtualImage - type: string - name: - description: Name of the block device to attach. - type: string - type: object - virtualMachineName: - description: Virtual machine name the disk or image should be attached - to. - type: string - required: - - blockDeviceRef - - virtualMachineName - type: object - status: - properties: - conditions: - description: Contains details of the current API resource state. - items: - description: Condition contains details for one aspect of the current - state of this API Resource. + - additionalPrinterColumns: + - description: VirtualMachineBlockDeviceAttachment phase. + jsonPath: .status.phase + name: PHASE + type: string + - description: Attached blockdevice kind. + jsonPath: .spec.blockDeviceRef.kind + name: BLOCKDEVICE KIND + priority: 1 + type: string + - description: Attached blockdevice name. + jsonPath: .spec.blockDeviceRef.name + name: BLOCKDEVICE NAME + priority: 1 + type: string + - description: Name of the virtual machine the disk is attached to. + jsonPath: .status.virtualMachineName + name: VIRTUAL MACHINE NAME + type: string + - description: Time of resource creation. + jsonPath: .metadata.creationTimestamp + name: AGE + type: date + name: v1alpha2 + schema: + openAPIV3Schema: + description: + VirtualMachineBlockDeviceAttachment provides a hot plug for attaching + a disk to a virtual machine. + properties: + apiVersion: + description: |- + APIVersion defines the versioned schema of this representation of an object. + Servers should convert recognized schemas to the latest internal value, and + may reject unrecognized values. + More info: https://git.k8s.io/community/contributors/devel/sig-architecture/api-conventions.md#resources + type: string + kind: + description: |- + Kind is a string value representing the REST resource this object represents. + Servers may infer this from the endpoint the client submits requests to. + Cannot be updated. + In CamelCase. + More info: https://git.k8s.io/community/contributors/devel/sig-architecture/api-conventions.md#types-kinds + type: string + metadata: + type: object + spec: + properties: + blockDeviceRef: + description: + Block device that will be connected to the VM as a hot-plug + disk. properties: - lastTransitionTime: + kind: description: |- - lastTransitionTime is the last time the condition transitioned from one status to another. - This should be when the underlying condition changed. If that is not known, then using the time when the API field changed is acceptable. - format: date-time - type: string - message: - description: |- - message is a human readable message indicating details about the transition. - This may be an empty string. - maxLength: 32768 - type: string - observedGeneration: - description: |- - observedGeneration represents the .metadata.generation that the condition was set based upon. - For instance, if .metadata.generation is currently 12, but the .status.conditions[x].observedGeneration is 9, the condition is out of date - with respect to the current state of the instance. - format: int64 - minimum: 0 - type: integer - reason: - description: |- - reason contains a programmatic identifier indicating the reason for the condition's last transition. - Producers of specific condition types may define expected values and meanings for this field, - and whether the values are considered a guaranteed API. - The value should be a CamelCase string. - This field may not be empty. - maxLength: 1024 - minLength: 1 - pattern: ^[A-Za-z]([A-Za-z0-9_,:]*[A-Za-z0-9_])?$ - type: string - status: - description: status of the condition, one of True, False, Unknown. + Block device type. Available options: + * `VirtualDisk`: Use VirtualDisk as the disk. This type is always mounted in RW mode. + * `VirtualImage`: Use VirtualImage as the disk. This type is always mounted in RO mode. + * `ClusterVirtualImage`: Use ClusterVirtualImage as the disk. This type is always mounted in RO mode. enum: - - "True" - - "False" - - Unknown + - VirtualDisk + - VirtualImage + - ClusterVirtualImage type: string - type: - description: type of condition in CamelCase or in foo.example.com/CamelCase. - maxLength: 316 - pattern: ^([a-z0-9]([-a-z0-9]*[a-z0-9])?(\.[a-z0-9]([-a-z0-9]*[a-z0-9])?)*/)?(([A-Za-z0-9][-A-Za-z0-9_.]*)?[A-Za-z0-9])$ + name: + description: Name of the block device to attach. type: string - required: - - lastTransitionTime - - message - - reason - - status - - type type: object - type: array - observedGeneration: - description: Resource generation last processed by the controller. - format: int64 - type: integer - phase: - description: |- - BlockDeviceAttachmentPhase defines the current status of the resource: - * `Pending`: The resource has been created and is on a waiting queue. - * `InProgress`: The disk is being attached to the VM. - * `Attached`: The disk has been attached to the VM. - * `Failed`: There was an error when attaching the disk. - * `Terminating`: The resource is being deleted. - enum: - - Pending - - InProgress - - Attached - - Failed - - Terminating - type: string - virtualMachineName: - description: Name of the virtual machine the disk is attached to. - type: string - type: object - required: - - spec - type: object - served: true - storage: true - subresources: - status: {} + virtualMachineName: + description: + Virtual machine name the disk or image should be attached + to. + type: string + required: + - blockDeviceRef + - virtualMachineName + type: object + status: + properties: + conditions: + description: Contains details of the current API resource state. + items: + description: + Condition contains details for one aspect of the current + state of this API Resource. + properties: + lastTransitionTime: + description: |- + lastTransitionTime is the last time the condition transitioned from one status to another. + This should be when the underlying condition changed. If that is not known, then using the time when the API field changed is acceptable. + format: date-time + type: string + message: + description: |- + message is a human readable message indicating details about the transition. + This may be an empty string. + maxLength: 32768 + type: string + observedGeneration: + description: |- + observedGeneration represents the .metadata.generation that the condition was set based upon. + For instance, if .metadata.generation is currently 12, but the .status.conditions[x].observedGeneration is 9, the condition is out of date + with respect to the current state of the instance. + format: int64 + minimum: 0 + type: integer + reason: + description: |- + reason contains a programmatic identifier indicating the reason for the condition's last transition. + Producers of specific condition types may define expected values and meanings for this field, + and whether the values are considered a guaranteed API. + The value should be a CamelCase string. + This field may not be empty. + maxLength: 1024 + minLength: 1 + pattern: ^[A-Za-z]([A-Za-z0-9_,:]*[A-Za-z0-9_])?$ + type: string + status: + description: status of the condition, one of True, False, Unknown. + enum: + - "True" + - "False" + - Unknown + type: string + type: + description: type of condition in CamelCase or in foo.example.com/CamelCase. + maxLength: 316 + pattern: ^([a-z0-9]([-a-z0-9]*[a-z0-9])?(\.[a-z0-9]([-a-z0-9]*[a-z0-9])?)*/)?(([A-Za-z0-9][-A-Za-z0-9_.]*)?[A-Za-z0-9])$ + type: string + required: + - lastTransitionTime + - message + - reason + - status + - type + type: object + type: array + observedGeneration: + description: Resource generation last processed by the controller. + format: int64 + type: integer + phase: + description: |- + BlockDeviceAttachmentPhase defines the current status of the resource: + * `Pending`: The resource has been created and is on a waiting queue. + * `InProgress`: The disk is being attached to the VM. + * `Attached`: The disk has been attached to the VM. + * `Failed`: There was an error when attaching the disk. + * `Terminating`: The resource is being deleted. + enum: + - Pending + - InProgress + - Attached + - Failed + - Terminating + type: string + virtualMachineName: + description: Name of the virtual machine the disk is attached to. + type: string + type: object + required: + - spec + type: object + served: true + storage: true + subresources: + status: {} diff --git a/crds/virtualmachineoperations.yaml b/crds/virtualmachineoperations.yaml index 4336b3b63d..c96023b308 100644 --- a/crds/virtualmachineoperations.yaml +++ b/crds/virtualmachineoperations.yaml @@ -12,110 +12,74 @@ spec: group: virtualization.deckhouse.io names: categories: - - virtualization + - virtualization kind: VirtualMachineOperation listKind: VirtualMachineOperationList plural: virtualmachineoperations shortNames: - - vmop + - vmop singular: virtualmachineoperation scope: Namespaced versions: - - additionalPrinterColumns: - - description: VirtualMachineOperation phase. - jsonPath: .status.phase - name: Phase - type: string - - description: VirtualMachineOperation type. - jsonPath: .spec.type - name: Type - type: string - - description: VirtualMachine name. - jsonPath: .spec.virtualMachineName - name: VirtualMachine - type: string - - description: Time of resource creation. - jsonPath: .metadata.creationTimestamp - name: Age - type: date - name: v1alpha2 - schema: - openAPIV3Schema: - description: VirtualMachineOperation enables declarative management of virtual - machine state changes. - properties: - apiVersion: - description: |- - APIVersion defines the versioned schema of this representation of an object. - Servers should convert recognized schemas to the latest internal value, and - may reject unrecognized values. - More info: https://git.k8s.io/community/contributors/devel/sig-architecture/api-conventions.md#resources - type: string - kind: - description: |- - Kind is a string value representing the REST resource this object represents. - Servers may infer this from the endpoint the client submits requests to. - Cannot be updated. - In CamelCase. - More info: https://git.k8s.io/community/contributors/devel/sig-architecture/api-conventions.md#types-kinds - type: string - metadata: - type: object - spec: - properties: - clone: - description: Clone defines the clone operation. - properties: - customization: - description: Customization defines customization options for cloning. - properties: - namePrefix: - description: |- - NamePrefix adds a prefix to resource names during cloning. - Applied to VirtualDisk, VirtualMachineIPAddress, VirtualMachineMACAddress, and Secret resources. - type: string - nameSuffix: - description: |- - NameSuffix adds a suffix to resource names during cloning. - Applied to VirtualDisk, VirtualMachineIPAddress, VirtualMachineMACAddress, and Secret resources. - type: string - type: object - mode: - description: |- - VMOPRestoreMode defines the kind of the restore operation. - * `DryRun`: DryRun run without any changes. Compatibility shows in status. - * `Strict`: Strict restore as is in the snapshot. - * `BestEffort`: BestEffort restore without deleted external missing dependencies. - enum: - - DryRun - - Strict - - BestEffort - type: string - nameReplacement: - description: NameReplacement defines rules for renaming resources - during cloning. - items: - description: NameReplacement represents a rule for redefining - the virtual machine resource names. + - additionalPrinterColumns: + - description: VirtualMachineOperation phase. + jsonPath: .status.phase + name: Phase + type: string + - description: VirtualMachineOperation type. + jsonPath: .spec.type + name: Type + type: string + - description: VirtualMachine name. + jsonPath: .spec.virtualMachineName + name: VirtualMachine + type: string + - description: Time of resource creation. + jsonPath: .metadata.creationTimestamp + name: Age + type: date + name: v1alpha2 + schema: + openAPIV3Schema: + description: + VirtualMachineOperation enables declarative management of virtual + machine state changes. + properties: + apiVersion: + description: |- + APIVersion defines the versioned schema of this representation of an object. + Servers should convert recognized schemas to the latest internal value, and + may reject unrecognized values. + More info: https://git.k8s.io/community/contributors/devel/sig-architecture/api-conventions.md#resources + type: string + kind: + description: |- + Kind is a string value representing the REST resource this object represents. + Servers may infer this from the endpoint the client submits requests to. + Cannot be updated. + In CamelCase. + More info: https://git.k8s.io/community/contributors/devel/sig-architecture/api-conventions.md#types-kinds + type: string + metadata: + type: object + spec: + properties: + clone: + description: Clone defines the clone operation. + properties: + customization: + description: Customization defines customization options for cloning. properties: - from: - description: Selector to choose resources for name replacement. - properties: - kind: - description: Kind of a resource to rename. - type: string - name: - description: Current name of a resource to rename. - type: string - required: - - name - type: object - to: - description: New resource name. + namePrefix: + description: |- + NamePrefix adds a prefix to resource names during cloning. + Applied to VirtualMachine, VirtualDisk, VirtualMachineBlockDeviceAttachment, and Secret resources. + type: string + nameSuffix: + description: |- + NameSuffix adds a suffix to resource names during cloning. + Applied to VirtualMachine, VirtualDisk, VirtualMachineBlockDeviceAttachment, and Secret resources. type: string - required: - - from - - to type: object x-kubernetes-validations: - message: @@ -132,46 +96,14 @@ spec: && size(self.nameSuffix) <= 59)" mode: description: |- - lastTransitionTime is the last time the condition transitioned from one status to another. - This should be when the underlying condition changed. If that is not known, then using the time when the API field changed is acceptable. - format: date-time - type: string - message: - description: |- - message is a human readable message indicating details about the transition. - This may be an empty string. - maxLength: 32768 - type: string - observedGeneration: - description: |- - observedGeneration represents the .metadata.generation that the condition was set based upon. - For instance, if .metadata.generation is currently 12, but the .status.conditions[x].observedGeneration is 9, the condition is out of date - with respect to the current state of the instance. - format: int64 - minimum: 0 - type: integer - reason: - description: |- - reason contains a programmatic identifier indicating the reason for the condition's last transition. - Producers of specific condition types may define expected values and meanings for this field, - and whether the values are considered a guaranteed API. - The value should be a CamelCase string. - This field may not be empty. - maxLength: 1024 - minLength: 1 - pattern: ^[A-Za-z]([A-Za-z0-9_,:]*[A-Za-z0-9_])?$ - type: string - status: - description: status of the condition, one of True, False, Unknown. + VMOPRestoreMode defines the kind of the restore operation. + * `DryRun`: DryRun run without any changes. Compatibility shows in status. + * `Strict`: Strict restore as is in the snapshot. + * `BestEffort`: BestEffort restore without deleted external missing dependencies. enum: - - "True" - - "False" - - Unknown - type: string - type: - description: type of condition in CamelCase or in foo.example.com/CamelCase. - maxLength: 316 - pattern: ^([a-z0-9]([-a-z0-9]*[a-z0-9])?(\.[a-z0-9]([-a-z0-9]*[a-z0-9])?)*/)?(([A-Za-z0-9][-A-Za-z0-9_.]*)?[A-Za-z0-9])$ + - DryRun + - Strict + - BestEffort type: string nameReplacement: description: @@ -208,11 +140,7 @@ spec: self.all(nr, has(nr.to) && size(nr.to) >= 1 && size(nr.to) <= 59) required: - - lastTransitionTime - - message - - reason - - status - - type + - mode type: object x-kubernetes-validations: - message: @@ -233,40 +161,191 @@ spec: restore: description: Restore defines the restore operation. properties: - apiVersion: - description: API version of the resource. - type: string - kind: - description: Kind of the resource. - type: string - message: - description: Message about the resource. - type: string - name: - description: Name of the resource. - type: string - status: - description: Status of the resource. + mode: + description: |- + VMOPRestoreMode defines the kind of the restore operation. + * `DryRun`: DryRun run without any changes. Compatibility shows in status. + * `Strict`: Strict restore as is in the snapshot. + * `BestEffort`: BestEffort restore without deleted external missing dependencies. enum: - - InProgress - - Completed - - Failed + - DryRun + - Strict + - BestEffort + type: string + virtualMachineSnapshotName: + description: + VirtualMachineSnapshotName defines the source of + the restore operation. type: string required: - - apiVersion - - kind - - message - - name - - status + - mode + - virtualMachineSnapshotName type: object - type: array - required: - - phase - type: object - required: - - spec - type: object - served: true - storage: true - subresources: - status: {} + type: + description: |- + Type of the operation to execute on a virtual machine: + * `Start`: Start the virtual machine. + * `Stop`: Stop the virtual machine. + * `Restart`: Restart the virtual machine. + * `Migrate` (deprecated): Migrate the virtual machine to another node where it can be started. + * `Evict`: Migrate the virtual machine to another node where it can be started. + * `Restore`: Restore the virtual machine from a snapshot. + * `Clone`: Clone the virtual machine to a new virtual machine. + enum: + - Restart + - Start + - Stop + - Migrate + - Evict + - Restore + - Clone + type: string + virtualMachineName: + description: + Name of the virtual machine the operation is performed + for. + type: string + required: + - type + - virtualMachineName + type: object + x-kubernetes-validations: + - message: .spec is immutable + rule: self == oldSelf + - message: The `Start` operation cannot be performed forcibly. + rule: "self.type == 'Start' ? !has(self.force) || !self.force : true" + - message: The `Migrate` operation cannot be performed forcibly. + rule: + "self.type == 'Migrate' ? !has(self.force) || !self.force : + true" + - message: Restore requires restore field. + rule: "self.type == 'Restore' ? has(self.restore) : true" + - message: Clone requires clone field. + rule: "self.type == 'Clone' ? has(self.clone) : true" + status: + properties: + conditions: + description: + The latest detailed observations of the VirtualMachineOperation + resource. + items: + description: + Condition contains details for one aspect of the current + state of this API Resource. + properties: + lastTransitionTime: + description: |- + lastTransitionTime is the last time the condition transitioned from one status to another. + This should be when the underlying condition changed. If that is not known, then using the time when the API field changed is acceptable. + format: date-time + type: string + message: + description: |- + message is a human readable message indicating details about the transition. + This may be an empty string. + maxLength: 32768 + type: string + observedGeneration: + description: |- + observedGeneration represents the .metadata.generation that the condition was set based upon. + For instance, if .metadata.generation is currently 12, but the .status.conditions[x].observedGeneration is 9, the condition is out of date + with respect to the current state of the instance. + format: int64 + minimum: 0 + type: integer + reason: + description: |- + reason contains a programmatic identifier indicating the reason for the condition's last transition. + Producers of specific condition types may define expected values and meanings for this field, + and whether the values are considered a guaranteed API. + The value should be a CamelCase string. + This field may not be empty. + maxLength: 1024 + minLength: 1 + pattern: ^[A-Za-z]([A-Za-z0-9_,:]*[A-Za-z0-9_])?$ + type: string + status: + description: status of the condition, one of True, False, Unknown. + enum: + - "True" + - "False" + - Unknown + type: string + type: + description: type of condition in CamelCase or in foo.example.com/CamelCase. + maxLength: 316 + pattern: ^([a-z0-9]([-a-z0-9]*[a-z0-9])?(\.[a-z0-9]([-a-z0-9]*[a-z0-9])?)*/)?(([A-Za-z0-9][-A-Za-z0-9_.]*)?[A-Za-z0-9])$ + type: string + required: + - lastTransitionTime + - message + - reason + - status + - type + type: object + type: array + observedGeneration: + description: " Resource generation last processed by the controller." + format: int64 + type: integer + phase: + description: |- + Current phase of the resource: + * `Pending`: The operation is queued for execution. + * `InProgress`: The operation is in progress. + * `Completed`: The operation has been completed successfully. + * `Failed`: The operation failed. For details, refer to the `conditions` field and events. + * `Terminating`: The operation is being deleted. + enum: + - Pending + - InProgress + - Completed + - Failed + - Terminating + type: string + resources: + description: + Resources contains the list of resources that are affected + by the snapshot operation. + items: + description: + VirtualMachineOperationResource defines the resource + affected by the operation. + properties: + apiVersion: + description: API version of the resource. + type: string + kind: + description: Kind of the resource. + type: string + message: + description: Message about the resource. + type: string + name: + description: Name of the resource. + type: string + status: + description: Status of the resource. + enum: + - InProgress + - Completed + - Failed + type: string + required: + - apiVersion + - kind + - message + - name + - status + type: object + type: array + required: + - phase + type: object + required: + - spec + type: object + served: true + storage: true + subresources: + status: {} diff --git a/crds/virtualmachinerestores.yaml b/crds/virtualmachinerestores.yaml index d2c8926b9c..eb848d5250 100644 --- a/crds/virtualmachinerestores.yaml +++ b/crds/virtualmachinerestores.yaml @@ -12,178 +12,181 @@ spec: group: virtualization.deckhouse.io names: categories: - - virtualization + - virtualization kind: VirtualMachineRestore listKind: VirtualMachineRestoreList plural: virtualmachinerestores shortNames: - - vmrestore + - vmrestore singular: virtualmachinerestore scope: Namespaced versions: - - additionalPrinterColumns: - - description: VirtualMachineRestore phase. - jsonPath: .status.phase - name: Phase - type: string - - description: VirtualMachineRestore age. - jsonPath: .metadata.creationTimestamp - name: Age - type: date - name: v1alpha2 - schema: - openAPIV3Schema: - description: VirtualMachineRestore provides a resource for restoring a virtual - machine and all associated resources from a snapshot. - properties: - apiVersion: - description: |- - APIVersion defines the versioned schema of this representation of an object. - Servers should convert recognized schemas to the latest internal value, and - may reject unrecognized values. - More info: https://git.k8s.io/community/contributors/devel/sig-architecture/api-conventions.md#resources - type: string - kind: - description: |- - Kind is a string value representing the REST resource this object represents. - Servers may infer this from the endpoint the client submits requests to. - Cannot be updated. - In CamelCase. - More info: https://git.k8s.io/community/contributors/devel/sig-architecture/api-conventions.md#types-kinds - type: string - metadata: - type: object - spec: - properties: - nameReplacements: - description: Renaming conventions for virtual machine resources. - items: - description: NameReplacement represents a rule for redefining the - virtual machine resource names. - properties: - from: - description: Selector to choose resources for name replacement. - properties: - kind: - description: Kind of a resource to rename. - type: string - name: - description: Current name of a resource to rename. - type: string - required: - - name - type: object - to: - description: New resource name. - type: string - required: - - from - - to - type: object - type: array - restoreMode: - default: Safe - description: |- - Virtual machine restore mode: + - additionalPrinterColumns: + - description: VirtualMachineRestore phase. + jsonPath: .status.phase + name: Phase + type: string + - description: VirtualMachineRestore age. + jsonPath: .metadata.creationTimestamp + name: Age + type: date + name: v1alpha2 + schema: + openAPIV3Schema: + description: + VirtualMachineRestore provides a resource for restoring a virtual + machine and all associated resources from a snapshot. + properties: + apiVersion: + description: |- + APIVersion defines the versioned schema of this representation of an object. + Servers should convert recognized schemas to the latest internal value, and + may reject unrecognized values. + More info: https://git.k8s.io/community/contributors/devel/sig-architecture/api-conventions.md#resources + type: string + kind: + description: |- + Kind is a string value representing the REST resource this object represents. + Servers may infer this from the endpoint the client submits requests to. + Cannot be updated. + In CamelCase. + More info: https://git.k8s.io/community/contributors/devel/sig-architecture/api-conventions.md#types-kinds + type: string + metadata: + type: object + spec: + properties: + nameReplacements: + description: Renaming conventions for virtual machine resources. + items: + description: + NameReplacement represents a rule for redefining the + virtual machine resource names. + properties: + from: + description: Selector to choose resources for name replacement. + properties: + kind: + description: Kind of a resource to rename. + type: string + name: + description: Current name of a resource to rename. + type: string + required: + - name + type: object + to: + description: New resource name. + type: string + required: + - from + - to + type: object + type: array + restoreMode: + default: Safe + description: |- + Virtual machine restore mode: - * Safe — in this mode, the virtual machine will not be restored if unresolvable conflicts are detected during the restoration process. - * Forced — in this mode, the virtual machine configuration will be updated and all associated resources will be recreated. The virtual machine may malfunction if the recovery process fails. Use the mode when you need to restore the virtual machine despite conflicts. - enum: - - Safe - - Forced - type: string - virtualMachineSnapshotName: - description: Snapshot name to restore a virtual machine from. - minLength: 1 - type: string - required: - - virtualMachineSnapshotName - type: object - status: - properties: - conditions: - description: Contains details of the current API resource state. - items: - description: Condition contains details for one aspect of the current - state of this API Resource. - properties: - lastTransitionTime: - description: |- - lastTransitionTime is the last time the condition transitioned from one status to another. - This should be when the underlying condition changed. If that is not known, then using the time when the API field changed is acceptable. - format: date-time - type: string - message: - description: |- - message is a human readable message indicating details about the transition. - This may be an empty string. - maxLength: 32768 - type: string - observedGeneration: - description: |- - observedGeneration represents the .metadata.generation that the condition was set based upon. - For instance, if .metadata.generation is currently 12, but the .status.conditions[x].observedGeneration is 9, the condition is out of date - with respect to the current state of the instance. - format: int64 - minimum: 0 - type: integer - reason: - description: |- - reason contains a programmatic identifier indicating the reason for the condition's last transition. - Producers of specific condition types may define expected values and meanings for this field, - and whether the values are considered a guaranteed API. - The value should be a CamelCase string. - This field may not be empty. - maxLength: 1024 - minLength: 1 - pattern: ^[A-Za-z]([A-Za-z0-9_,:]*[A-Za-z0-9_])?$ - type: string - status: - description: status of the condition, one of True, False, Unknown. - enum: - - "True" - - "False" - - Unknown - type: string - type: - description: type of condition in CamelCase or in foo.example.com/CamelCase. - maxLength: 316 - pattern: ^([a-z0-9]([-a-z0-9]*[a-z0-9])?(\.[a-z0-9]([-a-z0-9]*[a-z0-9])?)*/)?(([A-Za-z0-9][-A-Za-z0-9_.]*)?[A-Za-z0-9])$ - type: string - required: - - lastTransitionTime - - message - - reason - - status - - type - type: object - type: array - observedGeneration: - description: Resource generation last processed by the controller. - format: int64 - type: integer - phase: - description: |- - VirtualMachineRestorePhase defines the current status of a resource: - * `Pending`: The resource has been created and is on a waiting queue. - * `InProgress`: A virtual machine is being restored from a snapshot. - * `Ready`: A virtual machine has been successfully restored from a snapshot. - * `Failed`: An error occurred when restoring a virtual machine from a snapshot. - * `Terminating`: The resource is being deleted. - enum: - - Pending - - InProgress - - Ready - - Failed - - Terminating - type: string - required: - - phase - type: object - required: - - spec - type: object - served: true - storage: true - subresources: - status: {} + * Safe — in this mode, the virtual machine will not be restored if unresolvable conflicts are detected during the restoration process. + * Forced — in this mode, the virtual machine configuration will be updated and all associated resources will be recreated. The virtual machine may malfunction if the recovery process fails. Use the mode when you need to restore the virtual machine despite conflicts. + enum: + - Safe + - Forced + type: string + virtualMachineSnapshotName: + description: Snapshot name to restore a virtual machine from. + minLength: 1 + type: string + required: + - virtualMachineSnapshotName + type: object + status: + properties: + conditions: + description: Contains details of the current API resource state. + items: + description: + Condition contains details for one aspect of the current + state of this API Resource. + properties: + lastTransitionTime: + description: |- + lastTransitionTime is the last time the condition transitioned from one status to another. + This should be when the underlying condition changed. If that is not known, then using the time when the API field changed is acceptable. + format: date-time + type: string + message: + description: |- + message is a human readable message indicating details about the transition. + This may be an empty string. + maxLength: 32768 + type: string + observedGeneration: + description: |- + observedGeneration represents the .metadata.generation that the condition was set based upon. + For instance, if .metadata.generation is currently 12, but the .status.conditions[x].observedGeneration is 9, the condition is out of date + with respect to the current state of the instance. + format: int64 + minimum: 0 + type: integer + reason: + description: |- + reason contains a programmatic identifier indicating the reason for the condition's last transition. + Producers of specific condition types may define expected values and meanings for this field, + and whether the values are considered a guaranteed API. + The value should be a CamelCase string. + This field may not be empty. + maxLength: 1024 + minLength: 1 + pattern: ^[A-Za-z]([A-Za-z0-9_,:]*[A-Za-z0-9_])?$ + type: string + status: + description: status of the condition, one of True, False, Unknown. + enum: + - "True" + - "False" + - Unknown + type: string + type: + description: type of condition in CamelCase or in foo.example.com/CamelCase. + maxLength: 316 + pattern: ^([a-z0-9]([-a-z0-9]*[a-z0-9])?(\.[a-z0-9]([-a-z0-9]*[a-z0-9])?)*/)?(([A-Za-z0-9][-A-Za-z0-9_.]*)?[A-Za-z0-9])$ + type: string + required: + - lastTransitionTime + - message + - reason + - status + - type + type: object + type: array + observedGeneration: + description: Resource generation last processed by the controller. + format: int64 + type: integer + phase: + description: |- + VirtualMachineRestorePhase defines the current status of a resource: + * `Pending`: The resource has been created and is on a waiting queue. + * `InProgress`: A virtual machine is being restored from a snapshot. + * `Ready`: A virtual machine has been successfully restored from a snapshot. + * `Failed`: An error occurred when restoring a virtual machine from a snapshot. + * `Terminating`: The resource is being deleted. + enum: + - Pending + - InProgress + - Ready + - Failed + - Terminating + type: string + required: + - phase + type: object + required: + - spec + type: object + served: true + storage: true + subresources: + status: {} diff --git a/crds/virtualmachinesnapshots.yaml b/crds/virtualmachinesnapshots.yaml index 223865b5f8..c1b681a99e 100644 --- a/crds/virtualmachinesnapshots.yaml +++ b/crds/virtualmachinesnapshots.yaml @@ -12,198 +12,203 @@ spec: group: virtualization.deckhouse.io names: categories: - - virtualization + - virtualization kind: VirtualMachineSnapshot listKind: VirtualMachineSnapshotList plural: virtualmachinesnapshots shortNames: - - vmsnapshot - - vms + - vmsnapshot + - vms singular: virtualmachinesnapshot scope: Namespaced versions: - - additionalPrinterColumns: - - description: VirtualMachineSnapshot phase. - jsonPath: .status.phase - name: Phase - type: string - - description: VirtualMachineSnapshot consistency. - jsonPath: .status.consistent - name: Consistent - type: boolean - - description: VirtualMachineSnapshot age. - jsonPath: .metadata.creationTimestamp - name: Age - type: date - name: v1alpha2 - schema: - openAPIV3Schema: - description: VirtualMachineSnapshot provides a resource for creating snapshots - of virtual machines. - properties: - apiVersion: - description: |- - APIVersion defines the versioned schema of this representation of an object. - Servers should convert recognized schemas to the latest internal value, and - may reject unrecognized values. - More info: https://git.k8s.io/community/contributors/devel/sig-architecture/api-conventions.md#resources - type: string - kind: - description: |- - Kind is a string value representing the REST resource this object represents. - Servers may infer this from the endpoint the client submits requests to. - Cannot be updated. - In CamelCase. - More info: https://git.k8s.io/community/contributors/devel/sig-architecture/api-conventions.md#types-kinds - type: string - metadata: - type: object - spec: - properties: - keepIPAddress: - default: Always - description: |- - KeepIPAddress defines whether to keep the IP address of a virtual machine or not: + - additionalPrinterColumns: + - description: VirtualMachineSnapshot phase. + jsonPath: .status.phase + name: Phase + type: string + - description: VirtualMachineSnapshot consistency. + jsonPath: .status.consistent + name: Consistent + type: boolean + - description: VirtualMachineSnapshot age. + jsonPath: .metadata.creationTimestamp + name: Age + type: date + name: v1alpha2 + schema: + openAPIV3Schema: + description: + VirtualMachineSnapshot provides a resource for creating snapshots + of virtual machines. + properties: + apiVersion: + description: |- + APIVersion defines the versioned schema of this representation of an object. + Servers should convert recognized schemas to the latest internal value, and + may reject unrecognized values. + More info: https://git.k8s.io/community/contributors/devel/sig-architecture/api-conventions.md#resources + type: string + kind: + description: |- + Kind is a string value representing the REST resource this object represents. + Servers may infer this from the endpoint the client submits requests to. + Cannot be updated. + In CamelCase. + More info: https://git.k8s.io/community/contributors/devel/sig-architecture/api-conventions.md#types-kinds + type: string + metadata: + type: object + spec: + properties: + keepIPAddress: + default: Always + description: |- + KeepIPAddress defines whether to keep the IP address of a virtual machine or not: - * `Always`: When creating a snapshot, the virtual machine's IP address will be converted from `Auto` to `Static` and saved. - * `Never`: When creating a snapshot, the virtual machine's IP address will not be converted. - enum: - - Always - - Never - type: string - requiredConsistency: - default: true - description: |- - Create a snapshot of a virtual machine only if it is possible to freeze the machine through the agent. + * `Always`: When creating a snapshot, the virtual machine's IP address will be converted from `Auto` to `Static` and saved. + * `Never`: When creating a snapshot, the virtual machine's IP address will not be converted. + enum: + - Always + - Never + type: string + requiredConsistency: + default: true + description: |- + Create a snapshot of a virtual machine only if it is possible to freeze the machine through the agent. - If set to `true`, the virtual machine snapshot will be created only in the following cases: - - When the virtual machine is powered off. - - When the virtual machine has an agent, and the freeze operation was successful. - type: boolean - virtualMachineName: - description: Name of the virtual machine to take a snapshot of. - minLength: 1 - type: string - required: - - keepIPAddress - - requiredConsistency - - virtualMachineName - type: object - status: - properties: - conditions: - description: The latest detailed observations of the VirtualMachineSnapshot - resource. - items: - description: Condition contains details for one aspect of the current - state of this API Resource. - properties: - lastTransitionTime: - description: |- - lastTransitionTime is the last time the condition transitioned from one status to another. - This should be when the underlying condition changed. If that is not known, then using the time when the API field changed is acceptable. - format: date-time - type: string - message: - description: |- - message is a human readable message indicating details about the transition. - This may be an empty string. - maxLength: 32768 - type: string - observedGeneration: - description: |- - observedGeneration represents the .metadata.generation that the condition was set based upon. - For instance, if .metadata.generation is currently 12, but the .status.conditions[x].observedGeneration is 9, the condition is out of date - with respect to the current state of the instance. - format: int64 - minimum: 0 - type: integer - reason: - description: |- - reason contains a programmatic identifier indicating the reason for the condition's last transition. - Producers of specific condition types may define expected values and meanings for this field, - and whether the values are considered a guaranteed API. - The value should be a CamelCase string. - This field may not be empty. - maxLength: 1024 - minLength: 1 - pattern: ^[A-Za-z]([A-Za-z0-9_,:]*[A-Za-z0-9_])?$ - type: string - status: - description: status of the condition, one of True, False, Unknown. - enum: - - "True" - - "False" - - Unknown - type: string - type: - description: type of condition in CamelCase or in foo.example.com/CamelCase. - maxLength: 316 - pattern: ^([a-z0-9]([-a-z0-9]*[a-z0-9])?(\.[a-z0-9]([-a-z0-9]*[a-z0-9])?)*/)?(([A-Za-z0-9][-A-Za-z0-9_.]*)?[A-Za-z0-9])$ - type: string - required: - - lastTransitionTime - - message - - reason - - status - - type - type: object - type: array - consistent: - description: Whether a virtual machine snapshot is consistent. - type: boolean - observedGeneration: - description: Resource generation last processed by the controller. - format: int64 - type: integer - phase: - description: |- - VirtualMachineSnapshotPhase defines the current status of a resource: + If set to `true`, the virtual machine snapshot will be created only in the following cases: + - When the virtual machine is powered off. + - When the virtual machine has an agent, and the freeze operation was successful. + type: boolean + virtualMachineName: + description: Name of the virtual machine to take a snapshot of. + minLength: 1 + type: string + required: + - keepIPAddress + - requiredConsistency + - virtualMachineName + type: object + status: + properties: + conditions: + description: + The latest detailed observations of the VirtualMachineSnapshot + resource. + items: + description: + Condition contains details for one aspect of the current + state of this API Resource. + properties: + lastTransitionTime: + description: |- + lastTransitionTime is the last time the condition transitioned from one status to another. + This should be when the underlying condition changed. If that is not known, then using the time when the API field changed is acceptable. + format: date-time + type: string + message: + description: |- + message is a human readable message indicating details about the transition. + This may be an empty string. + maxLength: 32768 + type: string + observedGeneration: + description: |- + observedGeneration represents the .metadata.generation that the condition was set based upon. + For instance, if .metadata.generation is currently 12, but the .status.conditions[x].observedGeneration is 9, the condition is out of date + with respect to the current state of the instance. + format: int64 + minimum: 0 + type: integer + reason: + description: |- + reason contains a programmatic identifier indicating the reason for the condition's last transition. + Producers of specific condition types may define expected values and meanings for this field, + and whether the values are considered a guaranteed API. + The value should be a CamelCase string. + This field may not be empty. + maxLength: 1024 + minLength: 1 + pattern: ^[A-Za-z]([A-Za-z0-9_,:]*[A-Za-z0-9_])?$ + type: string + status: + description: status of the condition, one of True, False, Unknown. + enum: + - "True" + - "False" + - Unknown + type: string + type: + description: type of condition in CamelCase or in foo.example.com/CamelCase. + maxLength: 316 + pattern: ^([a-z0-9]([-a-z0-9]*[a-z0-9])?(\.[a-z0-9]([-a-z0-9]*[a-z0-9])?)*/)?(([A-Za-z0-9][-A-Za-z0-9_.]*)?[A-Za-z0-9])$ + type: string + required: + - lastTransitionTime + - message + - reason + - status + - type + type: object + type: array + consistent: + description: Whether a virtual machine snapshot is consistent. + type: boolean + observedGeneration: + description: Resource generation last processed by the controller. + format: int64 + type: integer + phase: + description: |- + VirtualMachineSnapshotPhase defines the current status of a resource: - * `Pending`: The resource has been created and is on a waiting queue. - * `InProgress`: A virtual machine snapshot is being created. - * `Ready`: A snapshot has been created successfully, and now it's available to use. - * `Failed`: An error occurred when creating a virtual machine snapshot. - * `Terminating`: The resource is being deleted. - enum: - - Pending - - InProgress - - Ready - - Failed - - Terminating - type: string - resources: - description: List of snapshot resources. - items: - properties: - apiVersion: - description: API version of the resource. - type: string - kind: - description: Kind of the resource. - type: string - name: - description: Name of the resource. - type: string - type: object - type: array - virtualDiskSnapshotNames: - description: List of VirtualDiskSnapshot names for the snapshots taken - from the virtual disks of the associated virtual machine. - items: + * `Pending`: The resource has been created and is on a waiting queue. + * `InProgress`: A virtual machine snapshot is being created. + * `Ready`: A snapshot has been created successfully, and now it's available to use. + * `Failed`: An error occurred when creating a virtual machine snapshot. + * `Terminating`: The resource is being deleted. + enum: + - Pending + - InProgress + - Ready + - Failed + - Terminating + type: string + resources: + description: List of snapshot resources. + items: + properties: + apiVersion: + description: API version of the resource. + type: string + kind: + description: Kind of the resource. + type: string + name: + description: Name of the resource. + type: string + type: object + type: array + virtualDiskSnapshotNames: + description: + List of VirtualDiskSnapshot names for the snapshots taken + from the virtual disks of the associated virtual machine. + items: + type: string + type: array + virtualMachineSnapshotSecretName: + description: + Name of the underlying `Secret` created for virtual machine + snapshotting. type: string - type: array - virtualMachineSnapshotSecretName: - description: Name of the underlying `Secret` created for virtual machine - snapshotting. - type: string - required: - - phase - type: object - required: - - spec - type: object - served: true - storage: true - subresources: - status: {} + required: + - phase + type: object + required: + - spec + type: object + served: true + storage: true + subresources: + status: {} From b033f173e3b2e6875f72a91717e36c56ffbd7b90 Mon Sep 17 00:00:00 2001 From: Daniil Loktev Date: Tue, 21 Oct 2025 14:48:36 +0300 Subject: [PATCH 05/77] wip Signed-off-by: Daniil Loktev --- api/scripts/update-codegen.sh | 22 +- crds/virtualmachineclasses.yaml | 1785 +++++++++++++++---------------- 2 files changed, 890 insertions(+), 917 deletions(-) diff --git a/api/scripts/update-codegen.sh b/api/scripts/update-codegen.sh index 7b4c4008d7..0385c78a6e 100755 --- a/api/scripts/update-codegen.sh +++ b/api/scripts/update-codegen.sh @@ -84,7 +84,27 @@ function generate::crds { if ! [[ " ${ALLOWED_RESOURCE_GEN_CRD[*]} " =~ [[:space:]]$(cat "$file" | yq '.spec.names.kind')[[:space:]] ]]; then continue fi - cp "$file" "${ROOT}/crds/$(echo $file | awk -Fio_ '{print $2}')" + + DEST_FILE="${ROOT}/crds/$(echo $file | awk -Fio_ '{print $2}')" + cp "$file" "${DEST_FILE}" + + # Add conversion webhook configuration for VirtualMachineClass + if [[ "${DEST_FILE}" == *"virtualmachineclasses.yaml" ]]; then + yq eval -i '.spec.conversion = { + "strategy": "Webhook", + "webhook": { + "clientConfig": { + "service": { + "name": "virtualization-controller", + "namespace": "d8-virtualization", + "path": "/convert/virtualmachineclasses", + "port": 443 + } + }, + "conversionReviewVersions": ["v1"] + } + }' "${DEST_FILE}" + fi done } diff --git a/crds/virtualmachineclasses.yaml b/crds/virtualmachineclasses.yaml index 4aa4d647f4..ac9234b694 100644 --- a/crds/virtualmachineclasses.yaml +++ b/crds/virtualmachineclasses.yaml @@ -13,973 +13,926 @@ spec: group: virtualization.deckhouse.io names: categories: - - virtualization-cluster + - virtualization-cluster kind: VirtualMachineClass listKind: VirtualMachineClassList plural: virtualmachineclasses shortNames: - - vmc - - vmclass + - vmc + - vmclass singular: virtualmachineclass scope: Cluster - conversion: - strategy: Webhook - webhook: - clientConfig: - service: - name: virtualization-controller - namespace: d8-virtualization - path: /convert/virtualmachineclasses - port: 443 - conversionReviewVersions: - - v1 versions: - - additionalPrinterColumns: - - description: VirtualMachineClass phase. - jsonPath: .status.phase - name: Phase - type: string - - description: Default class for virtual machines without specified class. - jsonPath: .metadata.annotations.virtualmachineclass\.virtualization\.deckhouse\.io\/is-default-class - name: IsDefault - type: string - - description: Time of resource creation. - jsonPath: .metadata.creationTimestamp - name: Age - type: date - name: v1alpha2 - schema: - openAPIV3Schema: - description: |- - VirtualMachineClass resource describes CPU requirements, node placement, and sizing policy for VM resources. - A resource cannot be deleted as long as it is used in one of the VMs. - properties: - apiVersion: - description: |- - APIVersion defines the versioned schema of this representation of an object. - Servers should convert recognized schemas to the latest internal value, and - may reject unrecognized values. - More info: https://git.k8s.io/community/contributors/devel/sig-architecture/api-conventions.md#resources - type: string - kind: - description: |- - Kind is a string value representing the REST resource this object represents. - Servers may infer this from the endpoint the client submits requests to. - Cannot be updated. - In CamelCase. - More info: https://git.k8s.io/community/contributors/devel/sig-architecture/api-conventions.md#types-kinds - type: string - metadata: - type: object - spec: - properties: - cpu: - description: CPU defines the requirements for the virtual CPU model. - properties: - discovery: - description: Create a CPU model based on intersecting CPU features - for selected nodes. - properties: - nodeSelector: - description: A selection of nodes to be used as the basis - for creating a universal CPU model. - properties: - matchExpressions: - description: matchExpressions is a list of label selector - requirements. The requirements are ANDed. - items: - description: |- - A label selector requirement is a selector that contains values, a key, and an operator that - relates the key and values. - properties: - key: - description: key is the label key that the selector - applies to. - type: string - operator: - description: |- - operator represents a key's relationship to a set of values. - Valid operators are In, NotIn, Exists and DoesNotExist. - type: string - values: - description: |- - values is an array of string values. If the operator is In or NotIn, - the values array must be non-empty. If the operator is Exists or DoesNotExist, - the values array must be empty. This array is replaced during a strategic - merge patch. - items: + - additionalPrinterColumns: + - description: VirtualMachineClass phase. + jsonPath: .status.phase + name: Phase + type: string + - description: Default class for virtual machines without specified class. + jsonPath: .metadata.annotations.virtualmachineclass\.virtualization\.deckhouse\.io\/is-default-class + name: IsDefault + type: string + - description: Time of resource creation. + jsonPath: .metadata.creationTimestamp + name: Age + type: date + name: v1alpha2 + schema: + openAPIV3Schema: + description: |- + VirtualMachineClass resource describes CPU requirements, node placement, and sizing policy for VM resources. + A resource cannot be deleted as long as it is used in one of the VMs. + properties: + apiVersion: + description: |- + APIVersion defines the versioned schema of this representation of an object. + Servers should convert recognized schemas to the latest internal value, and + may reject unrecognized values. + More info: https://git.k8s.io/community/contributors/devel/sig-architecture/api-conventions.md#resources + type: string + kind: + description: |- + Kind is a string value representing the REST resource this object represents. + Servers may infer this from the endpoint the client submits requests to. + Cannot be updated. + In CamelCase. + More info: https://git.k8s.io/community/contributors/devel/sig-architecture/api-conventions.md#types-kinds + type: string + metadata: + type: object + spec: + properties: + cpu: + description: CPU defines the requirements for the virtual CPU model. + properties: + discovery: + description: Create a CPU model based on intersecting CPU features for selected nodes. + properties: + nodeSelector: + description: A selection of nodes to be used as the basis for creating a universal CPU model. + properties: + matchExpressions: + description: matchExpressions is a list of label selector requirements. The requirements are ANDed. + items: + description: |- + A label selector requirement is a selector that contains values, a key, and an operator that + relates the key and values. + properties: + key: + description: key is the label key that the selector applies to. + type: string + operator: + description: |- + operator represents a key's relationship to a set of values. + Valid operators are In, NotIn, Exists and DoesNotExist. type: string - type: array - x-kubernetes-list-type: atomic - required: - - key - - operator + values: + description: |- + values is an array of string values. If the operator is In or NotIn, + the values array must be non-empty. If the operator is Exists or DoesNotExist, + the values array must be empty. This array is replaced during a strategic + merge patch. + items: + type: string + type: array + x-kubernetes-list-type: atomic + required: + - key + - operator + type: object + type: array + x-kubernetes-list-type: atomic + matchLabels: + additionalProperties: + type: string + description: |- + matchLabels is a map of {key,value} pairs. A single {key,value} in the matchLabels + map is equivalent to an element of matchExpressions, whose key field is "key", the + operator is "In", and the values array contains only "value". The requirements are ANDed. type: object + type: object + x-kubernetes-map-type: atomic + type: object + features: + description: |- + List of CPU instructions (features) required when type=Features. + For more information about CPU features, refer to the [libvirt docs](https://libvirt.org/formatdomain.html#cpu-model-and-topology). + example: + - mmx + - vmx + - sse2 + items: + type: string + minItems: 1 + type: array + model: + description: CPU model name. For more information about CPU models and topology, refer to the [libvirt docs](https://libvirt.org/formatdomain.html#cpu-model-and-topology). + example: IvyBridge + minLength: 1 + type: string + type: + description: |- + CPUType defines the CPU type, the following options are supported: + * `Host`: Uses a virtual CPU with an instruction set closely matching the platform node's CPU. + This provides high performance and functionality, as well as compatibility with "live" migration for nodes with similar processor types. + For example, VM migration between nodes with Intel and AMD processors will not work. + This is also true for different CPU generations, as their instruction set is different. + * `HostPassthrough`: Uses the platform node's physical CPU directly, without any modifications. + When using this class, the guest VM can only be transferred to a target node with a CPU exactly matching the source node's CPU. + * `Discovery`: Create a virtual CPU based on instruction sets of physical CPUs for a selected set of nodes. + * `Model`: CPU model. A CPU model is a named and previously defined set of supported CPU instructions. + * `Features`: A required set of supported instructions for the CPU. + enum: + - Host + - HostPassthrough + - Discovery + - Model + - Features + type: string + required: + - type + type: object + x-kubernetes-validations: + - message: .spec.cpu is immutable + rule: self == oldSelf + - message: HostPassthrough and Host cannot have model, features or discovery + rule: "self.type == 'HostPassthrough' || self.type == 'Host' ? !has(self.model) && !has(self.features) && !has(self.discovery) : true" + - message: Discovery cannot have model or features + rule: "self.type == 'Discovery' ? !has(self.model) && !has(self.features) : true" + - message: Model requires model and cannot have features or discovery + rule: "self.type == 'Model' ? has(self.model) && !has(self.features) && !has(self.discovery) : true" + - message: Features requires features and cannot have model or discovery + rule: "self.type == 'Features' ? has(self.features) && !has(self.model) && !has(self.discovery): true" + nodeSelector: + description: NodeSelector defines the nodes targeted for VM scheduling. + properties: + matchExpressions: + description: A list of node selector requirements by node's labels. + items: + description: |- + A node selector requirement is a selector that contains values, a key, and an operator + that relates the key and values. + properties: + key: + description: The label key that the selector applies to. + type: string + operator: + description: |- + Represents a key's relationship to a set of values. + Valid operators are In, NotIn, Exists, DoesNotExist. Gt, and Lt. + type: string + values: + description: |- + An array of string values. If the operator is In or NotIn, + the values array must be non-empty. If the operator is Exists or DoesNotExist, + the values array must be empty. If the operator is Gt or Lt, the values + array must have a single element, which will be interpreted as an integer. + This array is replaced during a strategic merge patch. + items: + type: string type: array x-kubernetes-list-type: atomic - matchLabels: - additionalProperties: - type: string - description: |- - matchLabels is a map of {key,value} pairs. A single {key,value} in the matchLabels - map is equivalent to an element of matchExpressions, whose key field is "key", the - operator is "In", and the values array contains only "value". The requirements are ANDed. + required: + - key + - operator + type: object + type: array + matchLabels: + additionalProperties: + type: string + description: |- + A map of {key,value} pairs. + A single {key,value} pair in the matchLabels map is equivalent to an element of matchExpressions whose key field is "key", operator is "In", and the value array contains only "value". + The requirements are ANDed. + type: object + type: object + sizingPolicies: + items: + description: |- + SizingPolicy defines a policy for allocating computational resources to VMs. + It is represented as a list. + The cores.min - cores.max ranges for different elements of the list must not overlap. + properties: + coreFractions: + description: Allowed values of the `coreFraction` parameter. + items: + maximum: 100 + minimum: 1 + type: integer + type: array + cores: + description: The policy applies for a specified range of the number of CPU cores. + properties: + max: + description: Maximum number of CPU cores. + example: 10 + maximum: 1024 + type: integer + min: + description: Minimum number of CPU cores. + example: 1 + minimum: 1 + type: integer + step: + description: Discretization step for the CPU core number. For example, the combination of `min=2`, `max=10`, and `step=4` allows to set the number of virtual machine CPU cores to 2, 6, or 10. + example: 1 + minimum: 1 + type: integer + required: + - max + - min + type: object + x-kubernetes-validations: + - message: The maximum must be greater than the minimum + rule: self.max > self.min + - message: The maximum must be greater than the step + rule: "has(self.step) ? self.max > self.step : true" + dedicatedCores: + description: Allowed values of the `dedicatedCores` parameter. + items: + type: boolean + type: array + memory: + description: Memory sizing policy. + properties: + max: + anyOf: + - type: integer + - type: string + description: Maximum amount of memory. + example: 8Gi + pattern: ^(\+|-)?(([0-9]+(\.[0-9]*)?)|(\.[0-9]+))(([KMGTPE]i)|[numkMGTPE]|([eE](\+|-)?(([0-9]+(\.[0-9]*)?)|(\.[0-9]+))))?$ + x-kubernetes-int-or-string: true + min: + anyOf: + - type: integer + - type: string + description: Minimum amount of memory. + example: 1Gi + pattern: ^(\+|-)?(([0-9]+(\.[0-9]*)?)|(\.[0-9]+))(([KMGTPE]i)|[numkMGTPE]|([eE](\+|-)?(([0-9]+(\.[0-9]*)?)|(\.[0-9]+))))?$ + x-kubernetes-int-or-string: true + perCore: + description: Amount of memory per CPU core. + properties: + max: + anyOf: + - type: integer + - type: string + description: Maximum amount of memory. + example: 8Gi + pattern: ^(\+|-)?(([0-9]+(\.[0-9]*)?)|(\.[0-9]+))(([KMGTPE]i)|[numkMGTPE]|([eE](\+|-)?(([0-9]+(\.[0-9]*)?)|(\.[0-9]+))))?$ + x-kubernetes-int-or-string: true + min: + anyOf: + - type: integer + - type: string + description: Minimum amount of memory. + example: 1Gi + pattern: ^(\+|-)?(([0-9]+(\.[0-9]*)?)|(\.[0-9]+))(([KMGTPE]i)|[numkMGTPE]|([eE](\+|-)?(([0-9]+(\.[0-9]*)?)|(\.[0-9]+))))?$ + x-kubernetes-int-or-string: true type: object + step: + anyOf: + - type: integer + - type: string + description: Memory size discretization step. For example, the combination of `min=2Gi, `max=4Gi` and `step=1Gi` allows to set the virtual machine memory size to 2Gi, 3Gi, or 4Gi. + example: 512Mi + pattern: ^(\+|-)?(([0-9]+(\.[0-9]*)?)|(\.[0-9]+))(([KMGTPE]i)|[numkMGTPE]|([eE](\+|-)?(([0-9]+(\.[0-9]*)?)|(\.[0-9]+))))?$ + x-kubernetes-int-or-string: true type: object - x-kubernetes-map-type: atomic type: object - features: - description: |- - List of CPU instructions (features) required when type=Features. - For more information about CPU features, refer to the [libvirt docs](https://libvirt.org/formatdomain.html#cpu-model-and-topology). - example: - - mmx - - vmx - - sse2 - items: - type: string - minItems: 1 - type: array - model: - description: CPU model name. For more information about CPU models - and topology, refer to the [libvirt docs](https://libvirt.org/formatdomain.html#cpu-model-and-topology). - example: IvyBridge - minLength: 1 - type: string - type: + type: array + tolerations: + description: |- + Tolerations are the same as `spec.tolerations` for [pods](https://kubernetes.io/docs/concepts/scheduling-eviction/taint-and-toleration/). + These tolerations will be merged with the tolerations specified in the VirtualMachine resource. VirtualMachine tolerations have a higher priority. + items: description: |- - CPUType defines the CPU type, the following options are supported: - * `Host`: Uses a virtual CPU with an instruction set closely matching the platform node's CPU. - This provides high performance and functionality, as well as compatibility with "live" migration for nodes with similar processor types. - For example, VM migration between nodes with Intel and AMD processors will not work. - This is also true for different CPU generations, as their instruction set is different. - * `HostPassthrough`: Uses the platform node's physical CPU directly, without any modifications. - When using this class, the guest VM can only be transferred to a target node with a CPU exactly matching the source node's CPU. - * `Discovery`: Create a virtual CPU based on instruction sets of physical CPUs for a selected set of nodes. - * `Model`: CPU model. A CPU model is a named and previously defined set of supported CPU instructions. - * `Features`: A required set of supported instructions for the CPU. - enum: - - Host - - HostPassthrough - - Discovery - - Model - - Features + The pod this Toleration is attached to tolerates any taint that matches + the triple using the matching operator . + properties: + effect: + description: |- + Effect indicates the taint effect to match. Empty means match all taint effects. + When specified, allowed values are NoSchedule, PreferNoSchedule and NoExecute. + type: string + key: + description: |- + Key is the taint key that the toleration applies to. Empty means match all taint keys. + If the key is empty, operator must be Exists; this combination means to match all values and all keys. + type: string + operator: + description: |- + Operator represents a key's relationship to the value. + Valid operators are Exists and Equal. Defaults to Equal. + Exists is equivalent to wildcard for value, so that a pod can + tolerate all taints of a particular category. + type: string + tolerationSeconds: + description: |- + TolerationSeconds represents the period of time the toleration (which must be + of effect NoExecute, otherwise this field is ignored) tolerates the taint. By default, + it is not set, which means tolerate the taint forever (do not evict). Zero and + negative values will be treated as 0 (evict immediately) by the system. + format: int64 + type: integer + value: + description: |- + Value is the taint value the toleration matches to. + If the operator is Exists, the value should be empty, otherwise just a regular string. + type: string + type: object + type: array + required: + - cpu + type: object + status: + properties: + availableNodes: + description: |- + List of nodes that support this CPU model. + It is not displayed for the following types: `Host`, `HostPassthrough`. + example: + - node-1 + - node-2 + items: type: string - required: - - type - type: object - x-kubernetes-validations: - - message: .spec.cpu is immutable - rule: self == oldSelf - - message: HostPassthrough and Host cannot have model, features or - discovery - rule: 'self.type == ''HostPassthrough'' || self.type == ''Host'' - ? !has(self.model) && !has(self.features) && !has(self.discovery) - : true' - - message: Discovery cannot have model or features - rule: 'self.type == ''Discovery'' ? !has(self.model) && !has(self.features) - : true' - - message: Model requires model and cannot have features or discovery - rule: 'self.type == ''Model'' ? has(self.model) && !has(self.features) - && !has(self.discovery) : true' - - message: Features requires features and cannot have model or discovery - rule: 'self.type == ''Features'' ? has(self.features) && !has(self.model) - && !has(self.discovery): true' - nodeSelector: - description: NodeSelector defines the nodes targeted for VM scheduling. - properties: - matchExpressions: - description: A list of node selector requirements by node's labels. - items: - description: |- - A node selector requirement is a selector that contains values, a key, and an operator - that relates the key and values. - properties: - key: - description: The label key that the selector applies to. - type: string - operator: - description: |- - Represents a key's relationship to a set of values. - Valid operators are In, NotIn, Exists, DoesNotExist. Gt, and Lt. - type: string - values: - description: |- - An array of string values. If the operator is In or NotIn, - the values array must be non-empty. If the operator is Exists or DoesNotExist, - the values array must be empty. If the operator is Gt or Lt, the values - array must have a single element, which will be interpreted as an integer. - This array is replaced during a strategic merge patch. - items: - type: string - type: array - x-kubernetes-list-type: atomic - required: - - key - - operator - type: object - type: array - matchLabels: - additionalProperties: - type: string - description: |- - A map of {key,value} pairs. - A single {key,value} pair in the matchLabels map is equivalent to an element of matchExpressions whose key field is "key", operator is "In", and the value array contains only "value". - The requirements are ANDed. + type: array + conditions: + description: The latest detailed observations of the VirtualMachineClass resource. + items: + description: Condition contains details for one aspect of the current state of this API Resource. + properties: + lastTransitionTime: + description: |- + lastTransitionTime is the last time the condition transitioned from one status to another. + This should be when the underlying condition changed. If that is not known, then using the time when the API field changed is acceptable. + format: date-time + type: string + message: + description: |- + message is a human readable message indicating details about the transition. + This may be an empty string. + maxLength: 32768 + type: string + observedGeneration: + description: |- + observedGeneration represents the .metadata.generation that the condition was set based upon. + For instance, if .metadata.generation is currently 12, but the .status.conditions[x].observedGeneration is 9, the condition is out of date + with respect to the current state of the instance. + format: int64 + minimum: 0 + type: integer + reason: + description: |- + reason contains a programmatic identifier indicating the reason for the condition's last transition. + Producers of specific condition types may define expected values and meanings for this field, + and whether the values are considered a guaranteed API. + The value should be a CamelCase string. + This field may not be empty. + maxLength: 1024 + minLength: 1 + pattern: ^[A-Za-z]([A-Za-z0-9_,:]*[A-Za-z0-9_])?$ + type: string + status: + description: status of the condition, one of True, False, Unknown. + enum: + - "True" + - "False" + - Unknown + type: string + type: + description: type of condition in CamelCase or in foo.example.com/CamelCase. + maxLength: 316 + pattern: ^([a-z0-9]([-a-z0-9]*[a-z0-9])?(\.[a-z0-9]([-a-z0-9]*[a-z0-9])?)*/)?(([A-Za-z0-9][-A-Za-z0-9_.]*)?[A-Za-z0-9])$ + type: string + required: + - lastTransitionTime + - message + - reason + - status + - type type: object - type: object - sizingPolicies: - items: + type: array + cpuFeatures: description: |- - SizingPolicy defines a policy for allocating computational resources to VMs. - It is represented as a list. - The cores.min - cores.max ranges for different elements of the list must not overlap. + CpuFeatures + Information on CPU features supported by this model. + Shown only for `Features` or `Discovery` types. properties: - coreFractions: - description: Allowed values of the `coreFraction` parameter. + enabled: + description: " List of CPU features for this model." + example: + - mmx + - vmx + - sse2 items: - maximum: 100 - minimum: 1 - type: integer + type: string type: array - cores: - description: The policy applies for a specified range of the - number of CPU cores. - properties: - max: - description: Maximum number of CPU cores. - example: 10 - maximum: 1024 - type: integer - min: - description: Minimum number of CPU cores. - example: 1 - minimum: 1 - type: integer - step: - description: Discretization step for the CPU core number. - For example, the combination of `min=2`, `max=10`, and - `step=4` allows to set the number of virtual machine CPU - cores to 2, 6, or 10. - example: 1 - minimum: 1 - type: integer - required: - - max - - min - type: object - x-kubernetes-validations: - - message: The maximum must be greater than the minimum - rule: self.max > self.min - - message: The maximum must be greater than the step - rule: 'has(self.step) ? self.max > self.step : true' - dedicatedCores: - description: Allowed values of the `dedicatedCores` parameter. + notEnabledCommon: + description: List of unused processor features additionally available for a given group of nodes. + example: + - ssse3 + - vme items: - type: boolean + type: string type: array - memory: - description: Memory sizing policy. - properties: - max: - anyOf: - - type: integer - - type: string - description: Maximum amount of memory. - example: 8Gi - pattern: ^(\+|-)?(([0-9]+(\.[0-9]*)?)|(\.[0-9]+))(([KMGTPE]i)|[numkMGTPE]|([eE](\+|-)?(([0-9]+(\.[0-9]*)?)|(\.[0-9]+))))?$ - x-kubernetes-int-or-string: true - min: - anyOf: - - type: integer - - type: string - description: Minimum amount of memory. - example: 1Gi - pattern: ^(\+|-)?(([0-9]+(\.[0-9]*)?)|(\.[0-9]+))(([KMGTPE]i)|[numkMGTPE]|([eE](\+|-)?(([0-9]+(\.[0-9]*)?)|(\.[0-9]+))))?$ - x-kubernetes-int-or-string: true - perCore: - description: Amount of memory per CPU core. - properties: - max: - anyOf: - - type: integer - - type: string - description: Maximum amount of memory. - example: 8Gi - pattern: ^(\+|-)?(([0-9]+(\.[0-9]*)?)|(\.[0-9]+))(([KMGTPE]i)|[numkMGTPE]|([eE](\+|-)?(([0-9]+(\.[0-9]*)?)|(\.[0-9]+))))?$ - x-kubernetes-int-or-string: true - min: - anyOf: - - type: integer - - type: string - description: Minimum amount of memory. - example: 1Gi - pattern: ^(\+|-)?(([0-9]+(\.[0-9]*)?)|(\.[0-9]+))(([KMGTPE]i)|[numkMGTPE]|([eE](\+|-)?(([0-9]+(\.[0-9]*)?)|(\.[0-9]+))))?$ - x-kubernetes-int-or-string: true - type: object - step: - anyOf: - - type: integer - - type: string - description: Memory size discretization step. For example, - the combination of `min=2Gi, `max=4Gi` and `step=1Gi` - allows to set the virtual machine memory size to 2Gi, - 3Gi, or 4Gi. - example: 512Mi - pattern: ^(\+|-)?(([0-9]+(\.[0-9]*)?)|(\.[0-9]+))(([KMGTPE]i)|[numkMGTPE]|([eE](\+|-)?(([0-9]+(\.[0-9]*)?)|(\.[0-9]+))))?$ - x-kubernetes-int-or-string: true - type: object type: object - type: array - tolerations: - description: |- - Tolerations are the same as `spec.tolerations` for [pods](https://kubernetes.io/docs/concepts/scheduling-eviction/taint-and-toleration/). - These tolerations will be merged with the tolerations specified in the VirtualMachine resource. VirtualMachine tolerations have a higher priority. - items: - description: |- - The pod this Toleration is attached to tolerates any taint that matches - the triple using the matching operator . - properties: - effect: - description: |- - Effect indicates the taint effect to match. Empty means match all taint effects. - When specified, allowed values are NoSchedule, PreferNoSchedule and NoExecute. - type: string - key: - description: |- - Key is the taint key that the toleration applies to. Empty means match all taint keys. - If the key is empty, operator must be Exists; this combination means to match all values and all keys. - type: string - operator: - description: |- - Operator represents a key's relationship to the value. - Valid operators are Exists and Equal. Defaults to Equal. - Exists is equivalent to wildcard for value, so that a pod can - tolerate all taints of a particular category. - type: string - tolerationSeconds: - description: |- - TolerationSeconds represents the period of time the toleration (which must be - of effect NoExecute, otherwise this field is ignored) tolerates the taint. By default, - it is not set, which means tolerate the taint forever (do not evict). Zero and - negative values will be treated as 0 (evict immediately) by the system. - format: int64 - type: integer - value: - description: |- - Value is the taint value the toleration matches to. - If the operator is Exists, the value should be empty, otherwise just a regular string. - type: string + maxAllocatableResources: + 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: Maximum amount of free CPU and memory resources observed among all available nodes. + example: + - 'maxAllocatableResources: {"cpu": 1, "memory": "10Gi"}' type: object - type: array - required: - - cpu - type: object - status: - properties: - availableNodes: - description: |- - List of nodes that support this CPU model. - It is not displayed for the following types: `Host`, `HostPassthrough`. - example: - - node-1 - - node-2 - items: + observedGeneration: + description: Resource generation last processed by the controller. + format: int64 + type: integer + phase: + description: |- + VirtualMachineClassPhase defines the current resource status: + * `Pending`: The resource is not ready and waits until the suitable nodes supporting the required CPU model are available. + * `Ready`: The resource is ready and available for use. + * `Terminating`: The resource is terminating. + enum: + - Pending + - Ready + - Terminating type: string - type: array - conditions: - description: The latest detailed observations of the VirtualMachineClass - resource. - items: - description: Condition contains details for one aspect of the current - state of this API Resource. + required: + - phase + type: object + required: + - spec + type: object + served: true + storage: false + subresources: + status: {} + - additionalPrinterColumns: + - description: VirtualMachineClass phase. + jsonPath: .status.phase + name: Phase + type: string + - description: Default class for virtual machines without specified class. + jsonPath: .metadata.annotations.virtualmachineclass\.virtualization\.deckhouse\.io\/is-default-class + name: IsDefault + type: string + - description: Time of resource creation. + jsonPath: .metadata.creationTimestamp + name: Age + type: date + name: v1alpha3 + schema: + openAPIV3Schema: + description: |- + VirtualMachineClass resource describes CPU requirements, node placement, and sizing policy for VM resources. + A resource cannot be deleted as long as it is used in one of the VMs. + properties: + apiVersion: + description: |- + APIVersion defines the versioned schema of this representation of an object. + Servers should convert recognized schemas to the latest internal value, and + may reject unrecognized values. + More info: https://git.k8s.io/community/contributors/devel/sig-architecture/api-conventions.md#resources + type: string + kind: + description: |- + Kind is a string value representing the REST resource this object represents. + Servers may infer this from the endpoint the client submits requests to. + Cannot be updated. + In CamelCase. + More info: https://git.k8s.io/community/contributors/devel/sig-architecture/api-conventions.md#types-kinds + type: string + metadata: + type: object + spec: + properties: + cpu: + description: CPU defines the requirements for the virtual CPU model. properties: - lastTransitionTime: - description: |- - lastTransitionTime is the last time the condition transitioned from one status to another. - This should be when the underlying condition changed. If that is not known, then using the time when the API field changed is acceptable. - format: date-time - type: string - message: - description: |- - message is a human readable message indicating details about the transition. - This may be an empty string. - maxLength: 32768 - type: string - observedGeneration: - description: |- - observedGeneration represents the .metadata.generation that the condition was set based upon. - For instance, if .metadata.generation is currently 12, but the .status.conditions[x].observedGeneration is 9, the condition is out of date - with respect to the current state of the instance. - format: int64 - minimum: 0 - type: integer - reason: + discovery: + description: Create a CPU model based on intersecting CPU features for selected nodes. + properties: + nodeSelector: + description: A selection of nodes to be used as the basis for creating a universal CPU model. + properties: + matchExpressions: + description: matchExpressions is a list of label selector requirements. The requirements are ANDed. + items: + description: |- + A label selector requirement is a selector that contains values, a key, and an operator that + relates the key and values. + properties: + key: + description: key is the label key that the selector applies to. + type: string + operator: + description: |- + operator represents a key's relationship to a set of values. + Valid operators are In, NotIn, Exists and DoesNotExist. + type: string + values: + description: |- + values is an array of string values. If the operator is In or NotIn, + the values array must be non-empty. If the operator is Exists or DoesNotExist, + the values array must be empty. This array is replaced during a strategic + merge patch. + items: + type: string + type: array + x-kubernetes-list-type: atomic + required: + - key + - operator + type: object + type: array + x-kubernetes-list-type: atomic + matchLabels: + additionalProperties: + type: string + description: |- + matchLabels is a map of {key,value} pairs. A single {key,value} in the matchLabels + map is equivalent to an element of matchExpressions, whose key field is "key", the + operator is "In", and the values array contains only "value". The requirements are ANDed. + type: object + type: object + x-kubernetes-map-type: atomic + type: object + features: description: |- - reason contains a programmatic identifier indicating the reason for the condition's last transition. - Producers of specific condition types may define expected values and meanings for this field, - and whether the values are considered a guaranteed API. - The value should be a CamelCase string. - This field may not be empty. - maxLength: 1024 + List of CPU instructions (features) required when type=Features. + For more information about CPU features, refer to the [libvirt docs](https://libvirt.org/formatdomain.html#cpu-model-and-topology). + example: + - mmx + - vmx + - sse2 + items: + type: string + minItems: 1 + type: array + model: + description: CPU model name. For more information about CPU models and topology, refer to the [libvirt docs](https://libvirt.org/formatdomain.html#cpu-model-and-topology). + example: IvyBridge minLength: 1 - pattern: ^[A-Za-z]([A-Za-z0-9_,:]*[A-Za-z0-9_])?$ - type: string - status: - description: status of the condition, one of True, False, Unknown. - enum: - - "True" - - "False" - - Unknown type: string type: - description: type of condition in CamelCase or in foo.example.com/CamelCase. - maxLength: 316 - pattern: ^([a-z0-9]([-a-z0-9]*[a-z0-9])?(\.[a-z0-9]([-a-z0-9]*[a-z0-9])?)*/)?(([A-Za-z0-9][-A-Za-z0-9_.]*)?[A-Za-z0-9])$ + description: |- + CPUType defines the CPU type, the following options are supported: + * `Host`: Uses a virtual CPU with an instruction set closely matching the platform node's CPU. + This provides high performance and functionality, as well as compatibility with "live" migration for nodes with similar processor types. + For example, VM migration between nodes with Intel and AMD processors will not work. + This is also true for different CPU generations, as their instruction set is different. + * `HostPassthrough`: Uses the platform node's physical CPU directly, without any modifications. + When using this class, the guest VM can only be transferred to a target node with a CPU exactly matching the source node's CPU. + * `Discovery`: Create a virtual CPU based on instruction sets of physical CPUs for a selected set of nodes. + * `Model`: CPU model. A CPU model is a named and previously defined set of supported CPU instructions. + * `Features`: A required set of supported instructions for the CPU. + enum: + - Host + - HostPassthrough + - Discovery + - Model + - Features type: string required: - - lastTransitionTime - - message - - reason - - status - - type + - type type: object - type: array - cpuFeatures: - description: |- - CpuFeatures - Information on CPU features supported by this model. - Shown only for `Features` or `Discovery` types. - properties: - enabled: - description: ' List of CPU features for this model.' - example: - - mmx - - vmx - - sse2 - items: - type: string - type: array - notEnabledCommon: - description: List of unused processor features additionally available - for a given group of nodes. - example: - - ssse3 - - vme - items: - type: string - type: array - type: object - maxAllocatableResources: - 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: Maximum amount of free CPU and memory resources observed - among all available nodes. - example: - - 'maxAllocatableResources: {"cpu": 1, "memory": "10Gi"}' - type: object - observedGeneration: - description: Resource generation last processed by the controller. - format: int64 - type: integer - phase: - description: |- - VirtualMachineClassPhase defines the current resource status: - * `Pending`: The resource is not ready and waits until the suitable nodes supporting the required CPU model are available. - * `Ready`: The resource is ready and available for use. - * `Terminating`: The resource is terminating. - enum: - - Pending - - Ready - - Terminating - type: string - required: - - phase - type: object - required: - - spec - type: object - served: true - storage: false - subresources: - status: {} - - additionalPrinterColumns: - - description: VirtualMachineClass phase. - jsonPath: .status.phase - name: Phase - type: string - - description: Default class for virtual machines without specified class. - jsonPath: .metadata.annotations.virtualmachineclass\.virtualization\.deckhouse\.io\/is-default-class - name: IsDefault - type: string - - description: Time of resource creation. - jsonPath: .metadata.creationTimestamp - name: Age - type: date - name: v1alpha3 - schema: - openAPIV3Schema: - description: |- - VirtualMachineClass resource describes CPU requirements, node placement, and sizing policy for VM resources. - A resource cannot be deleted as long as it is used in one of the VMs. - properties: - apiVersion: - description: |- - APIVersion defines the versioned schema of this representation of an object. - Servers should convert recognized schemas to the latest internal value, and - may reject unrecognized values. - More info: https://git.k8s.io/community/contributors/devel/sig-architecture/api-conventions.md#resources - type: string - kind: - description: |- - Kind is a string value representing the REST resource this object represents. - Servers may infer this from the endpoint the client submits requests to. - Cannot be updated. - In CamelCase. - More info: https://git.k8s.io/community/contributors/devel/sig-architecture/api-conventions.md#types-kinds - type: string - metadata: - type: object - spec: - properties: - cpu: - description: CPU defines the requirements for the virtual CPU model. - properties: - discovery: - description: Create a CPU model based on intersecting CPU features - for selected nodes. - properties: - nodeSelector: - description: A selection of nodes to be used as the basis - for creating a universal CPU model. + x-kubernetes-validations: + - message: .spec.cpu is immutable + rule: self == oldSelf + - message: HostPassthrough and Host cannot have model, features or discovery + rule: "self.type == 'HostPassthrough' || self.type == 'Host' ? !has(self.model) && !has(self.features) && !has(self.discovery) : true" + - message: Discovery cannot have model or features + rule: "self.type == 'Discovery' ? !has(self.model) && !has(self.features) : true" + - message: Model requires model and cannot have features or discovery + rule: "self.type == 'Model' ? has(self.model) && !has(self.features) && !has(self.discovery) : true" + - message: Features requires features and cannot have model or discovery + rule: "self.type == 'Features' ? has(self.features) && !has(self.model) && !has(self.discovery): true" + nodeSelector: + description: NodeSelector defines the nodes targeted for VM scheduling. + properties: + matchExpressions: + description: A list of node selector requirements by node's labels. + items: + description: |- + A node selector requirement is a selector that contains values, a key, and an operator + that relates the key and values. properties: - matchExpressions: - description: matchExpressions is a list of label selector - requirements. The requirements are ANDed. + key: + description: The label key that the selector applies to. + type: string + operator: + description: |- + Represents a key's relationship to a set of values. + Valid operators are In, NotIn, Exists, DoesNotExist. Gt, and Lt. + type: string + values: + description: |- + An array of string values. If the operator is In or NotIn, + the values array must be non-empty. If the operator is Exists or DoesNotExist, + the values array must be empty. If the operator is Gt or Lt, the values + array must have a single element, which will be interpreted as an integer. + This array is replaced during a strategic merge patch. items: - description: |- - A label selector requirement is a selector that contains values, a key, and an operator that - relates the key and values. - properties: - key: - description: key is the label key that the selector - applies to. - type: string - operator: - description: |- - operator represents a key's relationship to a set of values. - Valid operators are In, NotIn, Exists and DoesNotExist. - type: string - values: - description: |- - values is an array of string values. If the operator is In or NotIn, - the values array must be non-empty. If the operator is Exists or DoesNotExist, - the values array must be empty. This array is replaced during a strategic - merge patch. - items: - type: string - type: array - x-kubernetes-list-type: atomic - required: - - key - - operator - type: object + type: string type: array x-kubernetes-list-type: atomic - matchLabels: - additionalProperties: - type: string - description: |- - matchLabels is a map of {key,value} pairs. A single {key,value} in the matchLabels - map is equivalent to an element of matchExpressions, whose key field is "key", the - operator is "In", and the values array contains only "value". The requirements are ANDed. + required: + - key + - operator + type: object + type: array + matchLabels: + additionalProperties: + type: string + description: |- + A map of {key,value} pairs. + A single {key,value} pair in the matchLabels map is equivalent to an element of matchExpressions whose key field is "key", operator is "In", and the value array contains only "value". + The requirements are ANDed. + type: object + type: object + sizingPolicies: + items: + description: |- + SizingPolicy defines a policy for allocating computational resources to VMs. + It is represented as a list. + The cores.min - cores.max ranges for different elements of the list must not overlap. + properties: + coreFractions: + description: Allowed values of the `coreFraction` parameter in percentages (e.g., "5%", "10%", "25%", "50%", "100%"). + items: + description: CoreFractionValue represents CPU core fraction as a percentage string (e.g., "5%", "10%", "25%", "50%", "100%"). + pattern: ^([1-9]|[1-9][0-9]|100)%?$ + type: string + type: array + cores: + description: The policy applies for a specified range of the number of CPU cores. + properties: + max: + description: Maximum number of CPU cores. + example: 10 + maximum: 1024 + type: integer + min: + description: Minimum number of CPU cores. + example: 1 + minimum: 1 + type: integer + step: + description: Discretization step for the CPU core number. For example, the combination of `min=2`, `max=10`, and `step=4` allows to set the number of virtual machine CPU cores to 2, 6, or 10. + example: 1 + minimum: 1 + type: integer + required: + - max + - min + type: object + x-kubernetes-validations: + - message: The maximum must be greater than the minimum + rule: self.max > self.min + - message: The maximum must be greater than the step + rule: "has(self.step) ? self.max > self.step : true" + dedicatedCores: + description: Allowed values of the `dedicatedCores` parameter. + items: + type: boolean + type: array + memory: + description: Memory sizing policy. + properties: + max: + anyOf: + - type: integer + - type: string + description: Maximum amount of memory. + example: 8Gi + pattern: ^(\+|-)?(([0-9]+(\.[0-9]*)?)|(\.[0-9]+))(([KMGTPE]i)|[numkMGTPE]|([eE](\+|-)?(([0-9]+(\.[0-9]*)?)|(\.[0-9]+))))?$ + x-kubernetes-int-or-string: true + min: + anyOf: + - type: integer + - type: string + description: Minimum amount of memory. + example: 1Gi + pattern: ^(\+|-)?(([0-9]+(\.[0-9]*)?)|(\.[0-9]+))(([KMGTPE]i)|[numkMGTPE]|([eE](\+|-)?(([0-9]+(\.[0-9]*)?)|(\.[0-9]+))))?$ + x-kubernetes-int-or-string: true + perCore: + description: Amount of memory per CPU core. + properties: + max: + anyOf: + - type: integer + - type: string + description: Maximum amount of memory. + example: 8Gi + pattern: ^(\+|-)?(([0-9]+(\.[0-9]*)?)|(\.[0-9]+))(([KMGTPE]i)|[numkMGTPE]|([eE](\+|-)?(([0-9]+(\.[0-9]*)?)|(\.[0-9]+))))?$ + x-kubernetes-int-or-string: true + min: + anyOf: + - type: integer + - type: string + description: Minimum amount of memory. + example: 1Gi + pattern: ^(\+|-)?(([0-9]+(\.[0-9]*)?)|(\.[0-9]+))(([KMGTPE]i)|[numkMGTPE]|([eE](\+|-)?(([0-9]+(\.[0-9]*)?)|(\.[0-9]+))))?$ + x-kubernetes-int-or-string: true type: object + step: + anyOf: + - type: integer + - type: string + description: Memory size discretization step. For example, the combination of `min=2Gi, `max=4Gi` and `step=1Gi` allows to set the virtual machine memory size to 2Gi, 3Gi, or 4Gi. + example: 512Mi + pattern: ^(\+|-)?(([0-9]+(\.[0-9]*)?)|(\.[0-9]+))(([KMGTPE]i)|[numkMGTPE]|([eE](\+|-)?(([0-9]+(\.[0-9]*)?)|(\.[0-9]+))))?$ + x-kubernetes-int-or-string: true type: object - x-kubernetes-map-type: atomic type: object - features: - description: |- - List of CPU instructions (features) required when type=Features. - For more information about CPU features, refer to the [libvirt docs](https://libvirt.org/formatdomain.html#cpu-model-and-topology). - example: - - mmx - - vmx - - sse2 - items: - type: string - minItems: 1 - type: array - model: - description: CPU model name. For more information about CPU models - and topology, refer to the [libvirt docs](https://libvirt.org/formatdomain.html#cpu-model-and-topology). - example: IvyBridge - minLength: 1 - type: string - type: + type: array + tolerations: + description: |- + Tolerations are the same as `spec.tolerations` for [pods](https://kubernetes.io/docs/concepts/scheduling-eviction/taint-and-toleration/). + These tolerations will be merged with the tolerations specified in the VirtualMachine resource. VirtualMachine tolerations have a higher priority. + items: description: |- - CPUType defines the CPU type, the following options are supported: - * `Host`: Uses a virtual CPU with an instruction set closely matching the platform node's CPU. - This provides high performance and functionality, as well as compatibility with "live" migration for nodes with similar processor types. - For example, VM migration between nodes with Intel and AMD processors will not work. - This is also true for different CPU generations, as their instruction set is different. - * `HostPassthrough`: Uses the platform node's physical CPU directly, without any modifications. - When using this class, the guest VM can only be transferred to a target node with a CPU exactly matching the source node's CPU. - * `Discovery`: Create a virtual CPU based on instruction sets of physical CPUs for a selected set of nodes. - * `Model`: CPU model. A CPU model is a named and previously defined set of supported CPU instructions. - * `Features`: A required set of supported instructions for the CPU. - enum: - - Host - - HostPassthrough - - Discovery - - Model - - Features + The pod this Toleration is attached to tolerates any taint that matches + the triple using the matching operator . + properties: + effect: + description: |- + Effect indicates the taint effect to match. Empty means match all taint effects. + When specified, allowed values are NoSchedule, PreferNoSchedule and NoExecute. + type: string + key: + description: |- + Key is the taint key that the toleration applies to. Empty means match all taint keys. + If the key is empty, operator must be Exists; this combination means to match all values and all keys. + type: string + operator: + description: |- + Operator represents a key's relationship to the value. + Valid operators are Exists and Equal. Defaults to Equal. + Exists is equivalent to wildcard for value, so that a pod can + tolerate all taints of a particular category. + type: string + tolerationSeconds: + description: |- + TolerationSeconds represents the period of time the toleration (which must be + of effect NoExecute, otherwise this field is ignored) tolerates the taint. By default, + it is not set, which means tolerate the taint forever (do not evict). Zero and + negative values will be treated as 0 (evict immediately) by the system. + format: int64 + type: integer + value: + description: |- + Value is the taint value the toleration matches to. + If the operator is Exists, the value should be empty, otherwise just a regular string. + type: string + type: object + type: array + required: + - cpu + type: object + status: + properties: + availableNodes: + description: |- + List of nodes that support this CPU model. + It is not displayed for the following types: `Host`, `HostPassthrough`. + example: + - node-1 + - node-2 + items: type: string - required: - - type - type: object - x-kubernetes-validations: - - message: .spec.cpu is immutable - rule: self == oldSelf - - message: HostPassthrough and Host cannot have model, features or - discovery - rule: 'self.type == ''HostPassthrough'' || self.type == ''Host'' - ? !has(self.model) && !has(self.features) && !has(self.discovery) - : true' - - message: Discovery cannot have model or features - rule: 'self.type == ''Discovery'' ? !has(self.model) && !has(self.features) - : true' - - message: Model requires model and cannot have features or discovery - rule: 'self.type == ''Model'' ? has(self.model) && !has(self.features) - && !has(self.discovery) : true' - - message: Features requires features and cannot have model or discovery - rule: 'self.type == ''Features'' ? has(self.features) && !has(self.model) - && !has(self.discovery): true' - nodeSelector: - description: NodeSelector defines the nodes targeted for VM scheduling. - properties: - matchExpressions: - description: A list of node selector requirements by node's labels. - items: - description: |- - A node selector requirement is a selector that contains values, a key, and an operator - that relates the key and values. - properties: - key: - description: The label key that the selector applies to. - type: string - operator: - description: |- - Represents a key's relationship to a set of values. - Valid operators are In, NotIn, Exists, DoesNotExist. Gt, and Lt. - type: string - values: - description: |- - An array of string values. If the operator is In or NotIn, - the values array must be non-empty. If the operator is Exists or DoesNotExist, - the values array must be empty. If the operator is Gt or Lt, the values - array must have a single element, which will be interpreted as an integer. - This array is replaced during a strategic merge patch. - items: - type: string - type: array - x-kubernetes-list-type: atomic - required: - - key - - operator - type: object - type: array - matchLabels: - additionalProperties: - type: string - description: |- - A map of {key,value} pairs. - A single {key,value} pair in the matchLabels map is equivalent to an element of matchExpressions whose key field is "key", operator is "In", and the value array contains only "value". - The requirements are ANDed. + type: array + conditions: + description: The latest detailed observations of the VirtualMachineClass resource. + items: + description: Condition contains details for one aspect of the current state of this API Resource. + properties: + lastTransitionTime: + description: |- + lastTransitionTime is the last time the condition transitioned from one status to another. + This should be when the underlying condition changed. If that is not known, then using the time when the API field changed is acceptable. + format: date-time + type: string + message: + description: |- + message is a human readable message indicating details about the transition. + This may be an empty string. + maxLength: 32768 + type: string + observedGeneration: + description: |- + observedGeneration represents the .metadata.generation that the condition was set based upon. + For instance, if .metadata.generation is currently 12, but the .status.conditions[x].observedGeneration is 9, the condition is out of date + with respect to the current state of the instance. + format: int64 + minimum: 0 + type: integer + reason: + description: |- + reason contains a programmatic identifier indicating the reason for the condition's last transition. + Producers of specific condition types may define expected values and meanings for this field, + and whether the values are considered a guaranteed API. + The value should be a CamelCase string. + This field may not be empty. + maxLength: 1024 + minLength: 1 + pattern: ^[A-Za-z]([A-Za-z0-9_,:]*[A-Za-z0-9_])?$ + type: string + status: + description: status of the condition, one of True, False, Unknown. + enum: + - "True" + - "False" + - Unknown + type: string + type: + description: type of condition in CamelCase or in foo.example.com/CamelCase. + maxLength: 316 + pattern: ^([a-z0-9]([-a-z0-9]*[a-z0-9])?(\.[a-z0-9]([-a-z0-9]*[a-z0-9])?)*/)?(([A-Za-z0-9][-A-Za-z0-9_.]*)?[A-Za-z0-9])$ + type: string + required: + - lastTransitionTime + - message + - reason + - status + - type type: object - type: object - sizingPolicies: - items: + type: array + cpuFeatures: description: |- - SizingPolicy defines a policy for allocating computational resources to VMs. - It is represented as a list. - The cores.min - cores.max ranges for different elements of the list must not overlap. + CpuFeatures + Information on CPU features supported by this model. + Shown only for `Features` or `Discovery` types. properties: - coreFractions: - description: Allowed values of the `coreFraction` parameter - in percentages (e.g., "5%", "10%", "25%", "50%", "100%"). + enabled: + description: " List of CPU features for this model." + example: + - mmx + - vmx + - sse2 items: - description: CoreFractionValue represents CPU core fraction - as a percentage string (e.g., "5%", "10%", "25%", "50%", - "100%"). - pattern: ^([1-9]|[1-9][0-9]|100)%?$ type: string type: array - cores: - description: The policy applies for a specified range of the - number of CPU cores. - properties: - max: - description: Maximum number of CPU cores. - example: 10 - maximum: 1024 - type: integer - min: - description: Minimum number of CPU cores. - example: 1 - minimum: 1 - type: integer - step: - description: Discretization step for the CPU core number. - For example, the combination of `min=2`, `max=10`, and - `step=4` allows to set the number of virtual machine CPU - cores to 2, 6, or 10. - example: 1 - minimum: 1 - type: integer - required: - - max - - min - type: object - x-kubernetes-validations: - - message: The maximum must be greater than the minimum - rule: self.max > self.min - - message: The maximum must be greater than the step - rule: 'has(self.step) ? self.max > self.step : true' - dedicatedCores: - description: Allowed values of the `dedicatedCores` parameter. + notEnabledCommon: + description: List of unused processor features additionally available for a given group of nodes. + example: + - ssse3 + - vme items: - type: boolean + type: string type: array - memory: - description: Memory sizing policy. - properties: - max: - anyOf: - - type: integer - - type: string - description: Maximum amount of memory. - example: 8Gi - pattern: ^(\+|-)?(([0-9]+(\.[0-9]*)?)|(\.[0-9]+))(([KMGTPE]i)|[numkMGTPE]|([eE](\+|-)?(([0-9]+(\.[0-9]*)?)|(\.[0-9]+))))?$ - x-kubernetes-int-or-string: true - min: - anyOf: - - type: integer - - type: string - description: Minimum amount of memory. - example: 1Gi - pattern: ^(\+|-)?(([0-9]+(\.[0-9]*)?)|(\.[0-9]+))(([KMGTPE]i)|[numkMGTPE]|([eE](\+|-)?(([0-9]+(\.[0-9]*)?)|(\.[0-9]+))))?$ - x-kubernetes-int-or-string: true - perCore: - description: Amount of memory per CPU core. - properties: - max: - anyOf: - - type: integer - - type: string - description: Maximum amount of memory. - example: 8Gi - pattern: ^(\+|-)?(([0-9]+(\.[0-9]*)?)|(\.[0-9]+))(([KMGTPE]i)|[numkMGTPE]|([eE](\+|-)?(([0-9]+(\.[0-9]*)?)|(\.[0-9]+))))?$ - x-kubernetes-int-or-string: true - min: - anyOf: - - type: integer - - type: string - description: Minimum amount of memory. - example: 1Gi - pattern: ^(\+|-)?(([0-9]+(\.[0-9]*)?)|(\.[0-9]+))(([KMGTPE]i)|[numkMGTPE]|([eE](\+|-)?(([0-9]+(\.[0-9]*)?)|(\.[0-9]+))))?$ - x-kubernetes-int-or-string: true - type: object - step: - anyOf: - - type: integer - - type: string - description: Memory size discretization step. For example, - the combination of `min=2Gi, `max=4Gi` and `step=1Gi` - allows to set the virtual machine memory size to 2Gi, - 3Gi, or 4Gi. - example: 512Mi - pattern: ^(\+|-)?(([0-9]+(\.[0-9]*)?)|(\.[0-9]+))(([KMGTPE]i)|[numkMGTPE]|([eE](\+|-)?(([0-9]+(\.[0-9]*)?)|(\.[0-9]+))))?$ - x-kubernetes-int-or-string: true - type: object type: object - type: array - tolerations: - description: |- - Tolerations are the same as `spec.tolerations` for [pods](https://kubernetes.io/docs/concepts/scheduling-eviction/taint-and-toleration/). - These tolerations will be merged with the tolerations specified in the VirtualMachine resource. VirtualMachine tolerations have a higher priority. - items: - description: |- - The pod this Toleration is attached to tolerates any taint that matches - the triple using the matching operator . - properties: - effect: - description: |- - Effect indicates the taint effect to match. Empty means match all taint effects. - When specified, allowed values are NoSchedule, PreferNoSchedule and NoExecute. - type: string - key: - description: |- - Key is the taint key that the toleration applies to. Empty means match all taint keys. - If the key is empty, operator must be Exists; this combination means to match all values and all keys. - type: string - operator: - description: |- - Operator represents a key's relationship to the value. - Valid operators are Exists and Equal. Defaults to Equal. - Exists is equivalent to wildcard for value, so that a pod can - tolerate all taints of a particular category. - type: string - tolerationSeconds: - description: |- - TolerationSeconds represents the period of time the toleration (which must be - of effect NoExecute, otherwise this field is ignored) tolerates the taint. By default, - it is not set, which means tolerate the taint forever (do not evict). Zero and - negative values will be treated as 0 (evict immediately) by the system. - format: int64 - type: integer - value: - description: |- - Value is the taint value the toleration matches to. - If the operator is Exists, the value should be empty, otherwise just a regular string. - type: string + maxAllocatableResources: + 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: Maximum amount of free CPU and memory resources observed among all available nodes. + example: + - 'maxAllocatableResources: {"cpu": 1, "memory": "10Gi"}' type: object - type: array - required: - - cpu - type: object - status: - properties: - availableNodes: - description: |- - List of nodes that support this CPU model. - It is not displayed for the following types: `Host`, `HostPassthrough`. - example: - - node-1 - - node-2 - items: + observedGeneration: + description: Resource generation last processed by the controller. + format: int64 + type: integer + phase: + description: |- + VirtualMachineClassPhase defines the current resource status: + * `Pending`: The resource is not ready and waits until the suitable nodes supporting the required CPU model are available. + * `Ready`: The resource is ready and available for use. + * `Terminating`: The resource is terminating. + enum: + - Pending + - Ready + - Terminating type: string - type: array - conditions: - description: The latest detailed observations of the VirtualMachineClass - resource. - items: - description: Condition contains details for one aspect of the current - state of this API Resource. - properties: - lastTransitionTime: - description: |- - lastTransitionTime is the last time the condition transitioned from one status to another. - This should be when the underlying condition changed. If that is not known, then using the time when the API field changed is acceptable. - format: date-time - type: string - message: - description: |- - message is a human readable message indicating details about the transition. - This may be an empty string. - maxLength: 32768 - type: string - observedGeneration: - description: |- - observedGeneration represents the .metadata.generation that the condition was set based upon. - For instance, if .metadata.generation is currently 12, but the .status.conditions[x].observedGeneration is 9, the condition is out of date - with respect to the current state of the instance. - format: int64 - minimum: 0 - type: integer - reason: - description: |- - reason contains a programmatic identifier indicating the reason for the condition's last transition. - Producers of specific condition types may define expected values and meanings for this field, - and whether the values are considered a guaranteed API. - The value should be a CamelCase string. - This field may not be empty. - maxLength: 1024 - minLength: 1 - pattern: ^[A-Za-z]([A-Za-z0-9_,:]*[A-Za-z0-9_])?$ - type: string - status: - description: status of the condition, one of True, False, Unknown. - enum: - - "True" - - "False" - - Unknown - type: string - type: - description: type of condition in CamelCase or in foo.example.com/CamelCase. - maxLength: 316 - pattern: ^([a-z0-9]([-a-z0-9]*[a-z0-9])?(\.[a-z0-9]([-a-z0-9]*[a-z0-9])?)*/)?(([A-Za-z0-9][-A-Za-z0-9_.]*)?[A-Za-z0-9])$ - type: string - required: - - lastTransitionTime - - message - - reason - - status - - type - type: object - type: array - cpuFeatures: - description: |- - CpuFeatures - Information on CPU features supported by this model. - Shown only for `Features` or `Discovery` types. - properties: - enabled: - description: ' List of CPU features for this model.' - example: - - mmx - - vmx - - sse2 - items: - type: string - type: array - notEnabledCommon: - description: List of unused processor features additionally available - for a given group of nodes. - example: - - ssse3 - - vme - items: - type: string - type: array - type: object - maxAllocatableResources: - 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: Maximum amount of free CPU and memory resources observed - among all available nodes. - example: - - 'maxAllocatableResources: {"cpu": 1, "memory": "10Gi"}' - type: object - observedGeneration: - description: Resource generation last processed by the controller. - format: int64 - type: integer - phase: - description: |- - VirtualMachineClassPhase defines the current resource status: - * `Pending`: The resource is not ready and waits until the suitable nodes supporting the required CPU model are available. - * `Ready`: The resource is ready and available for use. - * `Terminating`: The resource is terminating. - enum: - - Pending - - Ready - - Terminating - type: string - required: - - phase - type: object - required: - - spec - type: object - served: true - storage: true - subresources: - status: {} + required: + - phase + type: object + required: + - spec + type: object + served: true + storage: true + subresources: + status: {} + conversion: + strategy: Webhook + webhook: + clientConfig: + service: + name: virtualization-controller + namespace: d8-virtualization + path: /convert/virtualmachineclasses + port: 443 + conversionReviewVersions: + - v1 From 28a0f915aa3abd0d31b5abf824f44b6e2652e479 Mon Sep 17 00:00:00 2001 From: Daniil Loktev Date: Tue, 21 Oct 2025 16:55:18 +0300 Subject: [PATCH 06/77] wip Signed-off-by: Daniil Loktev --- .../clientset/versioned/clientset.go | 13 + .../versioned/fake/clientset_generated.go | 7 + .../clientset/versioned/fake/register.go | 2 + .../clientset/versioned/scheme/register.go | 2 + .../typed/core/v1alpha3/core_client.go | 101 +++++ .../versioned/typed/core/v1alpha3/doc.go | 20 + .../versioned/typed/core/v1alpha3/fake/doc.go | 20 + .../core/v1alpha3/fake/fake_core_client.go | 40 ++ .../v1alpha3/fake/fake_virtualmachineclass.go | 52 +++ .../core/v1alpha3/generated_expansion.go | 21 + .../core/v1alpha3/virtualmachineclass.go | 70 ++++ .../externalversions/core/interface.go | 8 + .../core/v1alpha3/interface.go | 45 +++ .../core/v1alpha3/virtualmachineclass.go | 101 +++++ .../informers/externalversions/generic.go | 5 + .../core/v1alpha3/expansion_generated.go | 23 ++ .../core/v1alpha3/virtualmachineclass.go | 48 +++ api/core/v1alpha2/virtual_machine_class.go | 1 + .../virtual_machine_class_conversion.go | 208 ++++++++++ api/core/v1alpha3/virtual_machine_class.go | 1 + api/core/v1alpha3/zz_generated.deepcopy.go | 358 ++++++++++++++++++ api/go.mod | 11 + api/go.sum | 21 + api/scripts/update-codegen.sh | 3 +- .../controller/vmclass/vmclass_controller.go | 3 - .../controller/vmclass/vmclass_conversion.go | 317 ---------------- 26 files changed, 1179 insertions(+), 322 deletions(-) create mode 100644 api/client/generated/clientset/versioned/typed/core/v1alpha3/core_client.go create mode 100644 api/client/generated/clientset/versioned/typed/core/v1alpha3/doc.go create mode 100644 api/client/generated/clientset/versioned/typed/core/v1alpha3/fake/doc.go create mode 100644 api/client/generated/clientset/versioned/typed/core/v1alpha3/fake/fake_core_client.go create mode 100644 api/client/generated/clientset/versioned/typed/core/v1alpha3/fake/fake_virtualmachineclass.go create mode 100644 api/client/generated/clientset/versioned/typed/core/v1alpha3/generated_expansion.go create mode 100644 api/client/generated/clientset/versioned/typed/core/v1alpha3/virtualmachineclass.go create mode 100644 api/client/generated/informers/externalversions/core/v1alpha3/interface.go create mode 100644 api/client/generated/informers/externalversions/core/v1alpha3/virtualmachineclass.go create mode 100644 api/client/generated/listers/core/v1alpha3/expansion_generated.go create mode 100644 api/client/generated/listers/core/v1alpha3/virtualmachineclass.go create mode 100644 api/core/v1alpha2/virtual_machine_class_conversion.go create mode 100644 api/core/v1alpha3/zz_generated.deepcopy.go delete mode 100644 images/virtualization-artifact/pkg/controller/vmclass/vmclass_conversion.go diff --git a/api/client/generated/clientset/versioned/clientset.go b/api/client/generated/clientset/versioned/clientset.go index d2a4e3bbec..e3027ebb46 100644 --- a/api/client/generated/clientset/versioned/clientset.go +++ b/api/client/generated/clientset/versioned/clientset.go @@ -23,6 +23,7 @@ import ( http "net/http" virtualizationv1alpha2 "github.com/deckhouse/virtualization/api/client/generated/clientset/versioned/typed/core/v1alpha2" + virtualizationv1alpha3 "github.com/deckhouse/virtualization/api/client/generated/clientset/versioned/typed/core/v1alpha3" discovery "k8s.io/client-go/discovery" rest "k8s.io/client-go/rest" flowcontrol "k8s.io/client-go/util/flowcontrol" @@ -31,12 +32,14 @@ import ( type Interface interface { Discovery() discovery.DiscoveryInterface VirtualizationV1alpha2() virtualizationv1alpha2.VirtualizationV1alpha2Interface + VirtualizationV1alpha3() virtualizationv1alpha3.VirtualizationV1alpha3Interface } // Clientset contains the clients for groups. type Clientset struct { *discovery.DiscoveryClient virtualizationV1alpha2 *virtualizationv1alpha2.VirtualizationV1alpha2Client + virtualizationV1alpha3 *virtualizationv1alpha3.VirtualizationV1alpha3Client } // VirtualizationV1alpha2 retrieves the VirtualizationV1alpha2Client @@ -44,6 +47,11 @@ func (c *Clientset) VirtualizationV1alpha2() virtualizationv1alpha2.Virtualizati return c.virtualizationV1alpha2 } +// VirtualizationV1alpha3 retrieves the VirtualizationV1alpha3Client +func (c *Clientset) VirtualizationV1alpha3() virtualizationv1alpha3.VirtualizationV1alpha3Interface { + return c.virtualizationV1alpha3 +} + // Discovery retrieves the DiscoveryClient func (c *Clientset) Discovery() discovery.DiscoveryInterface { if c == nil { @@ -92,6 +100,10 @@ func NewForConfigAndClient(c *rest.Config, httpClient *http.Client) (*Clientset, if err != nil { return nil, err } + cs.virtualizationV1alpha3, err = virtualizationv1alpha3.NewForConfigAndClient(&configShallowCopy, httpClient) + if err != nil { + return nil, err + } cs.DiscoveryClient, err = discovery.NewDiscoveryClientForConfigAndClient(&configShallowCopy, httpClient) if err != nil { @@ -114,6 +126,7 @@ func NewForConfigOrDie(c *rest.Config) *Clientset { func New(c rest.Interface) *Clientset { var cs Clientset cs.virtualizationV1alpha2 = virtualizationv1alpha2.New(c) + cs.virtualizationV1alpha3 = virtualizationv1alpha3.New(c) cs.DiscoveryClient = discovery.NewDiscoveryClient(c) return &cs diff --git a/api/client/generated/clientset/versioned/fake/clientset_generated.go b/api/client/generated/clientset/versioned/fake/clientset_generated.go index 732401580d..0976b8490f 100644 --- a/api/client/generated/clientset/versioned/fake/clientset_generated.go +++ b/api/client/generated/clientset/versioned/fake/clientset_generated.go @@ -22,6 +22,8 @@ import ( clientset "github.com/deckhouse/virtualization/api/client/generated/clientset/versioned" virtualizationv1alpha2 "github.com/deckhouse/virtualization/api/client/generated/clientset/versioned/typed/core/v1alpha2" fakevirtualizationv1alpha2 "github.com/deckhouse/virtualization/api/client/generated/clientset/versioned/typed/core/v1alpha2/fake" + virtualizationv1alpha3 "github.com/deckhouse/virtualization/api/client/generated/clientset/versioned/typed/core/v1alpha3" + fakevirtualizationv1alpha3 "github.com/deckhouse/virtualization/api/client/generated/clientset/versioned/typed/core/v1alpha3/fake" metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" "k8s.io/apimachinery/pkg/runtime" "k8s.io/apimachinery/pkg/watch" @@ -92,3 +94,8 @@ var ( func (c *Clientset) VirtualizationV1alpha2() virtualizationv1alpha2.VirtualizationV1alpha2Interface { return &fakevirtualizationv1alpha2.FakeVirtualizationV1alpha2{Fake: &c.Fake} } + +// VirtualizationV1alpha3 retrieves the VirtualizationV1alpha3Client +func (c *Clientset) VirtualizationV1alpha3() virtualizationv1alpha3.VirtualizationV1alpha3Interface { + return &fakevirtualizationv1alpha3.FakeVirtualizationV1alpha3{Fake: &c.Fake} +} diff --git a/api/client/generated/clientset/versioned/fake/register.go b/api/client/generated/clientset/versioned/fake/register.go index 1edca93ed7..599b8a83a9 100644 --- a/api/client/generated/clientset/versioned/fake/register.go +++ b/api/client/generated/clientset/versioned/fake/register.go @@ -20,6 +20,7 @@ package fake import ( virtualizationv1alpha2 "github.com/deckhouse/virtualization/api/core/v1alpha2" + virtualizationv1alpha3 "github.com/deckhouse/virtualization/api/core/v1alpha3" v1 "k8s.io/apimachinery/pkg/apis/meta/v1" runtime "k8s.io/apimachinery/pkg/runtime" schema "k8s.io/apimachinery/pkg/runtime/schema" @@ -32,6 +33,7 @@ var codecs = serializer.NewCodecFactory(scheme) var localSchemeBuilder = runtime.SchemeBuilder{ virtualizationv1alpha2.AddToScheme, + virtualizationv1alpha3.AddToScheme, } // AddToScheme adds all types of this clientset into the given scheme. This allows composition diff --git a/api/client/generated/clientset/versioned/scheme/register.go b/api/client/generated/clientset/versioned/scheme/register.go index e4dd8c01b4..6e5bae592a 100644 --- a/api/client/generated/clientset/versioned/scheme/register.go +++ b/api/client/generated/clientset/versioned/scheme/register.go @@ -20,6 +20,7 @@ package scheme import ( virtualizationv1alpha2 "github.com/deckhouse/virtualization/api/core/v1alpha2" + virtualizationv1alpha3 "github.com/deckhouse/virtualization/api/core/v1alpha3" v1 "k8s.io/apimachinery/pkg/apis/meta/v1" runtime "k8s.io/apimachinery/pkg/runtime" schema "k8s.io/apimachinery/pkg/runtime/schema" @@ -32,6 +33,7 @@ var Codecs = serializer.NewCodecFactory(Scheme) var ParameterCodec = runtime.NewParameterCodec(Scheme) var localSchemeBuilder = runtime.SchemeBuilder{ virtualizationv1alpha2.AddToScheme, + virtualizationv1alpha3.AddToScheme, } // AddToScheme adds all types of this clientset into the given scheme. This allows composition diff --git a/api/client/generated/clientset/versioned/typed/core/v1alpha3/core_client.go b/api/client/generated/clientset/versioned/typed/core/v1alpha3/core_client.go new file mode 100644 index 0000000000..667a073b12 --- /dev/null +++ b/api/client/generated/clientset/versioned/typed/core/v1alpha3/core_client.go @@ -0,0 +1,101 @@ +/* +Copyright Flant JSC + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. +*/ + +// Code generated by client-gen. DO NOT EDIT. + +package v1alpha3 + +import ( + http "net/http" + + scheme "github.com/deckhouse/virtualization/api/client/generated/clientset/versioned/scheme" + corev1alpha3 "github.com/deckhouse/virtualization/api/core/v1alpha3" + rest "k8s.io/client-go/rest" +) + +type VirtualizationV1alpha3Interface interface { + RESTClient() rest.Interface + VirtualMachineClassesGetter +} + +// VirtualizationV1alpha3Client is used to interact with features provided by the virtualization.deckhouse.io group. +type VirtualizationV1alpha3Client struct { + restClient rest.Interface +} + +func (c *VirtualizationV1alpha3Client) VirtualMachineClasses() VirtualMachineClassInterface { + return newVirtualMachineClasses(c) +} + +// NewForConfig creates a new VirtualizationV1alpha3Client for the given config. +// NewForConfig is equivalent to NewForConfigAndClient(c, httpClient), +// where httpClient was generated with rest.HTTPClientFor(c). +func NewForConfig(c *rest.Config) (*VirtualizationV1alpha3Client, error) { + config := *c + setConfigDefaults(&config) + httpClient, err := rest.HTTPClientFor(&config) + if err != nil { + return nil, err + } + return NewForConfigAndClient(&config, httpClient) +} + +// NewForConfigAndClient creates a new VirtualizationV1alpha3Client for the given config and http client. +// Note the http client provided takes precedence over the configured transport values. +func NewForConfigAndClient(c *rest.Config, h *http.Client) (*VirtualizationV1alpha3Client, error) { + config := *c + setConfigDefaults(&config) + client, err := rest.RESTClientForConfigAndClient(&config, h) + if err != nil { + return nil, err + } + return &VirtualizationV1alpha3Client{client}, nil +} + +// NewForConfigOrDie creates a new VirtualizationV1alpha3Client for the given config and +// panics if there is an error in the config. +func NewForConfigOrDie(c *rest.Config) *VirtualizationV1alpha3Client { + client, err := NewForConfig(c) + if err != nil { + panic(err) + } + return client +} + +// New creates a new VirtualizationV1alpha3Client for the given RESTClient. +func New(c rest.Interface) *VirtualizationV1alpha3Client { + return &VirtualizationV1alpha3Client{c} +} + +func setConfigDefaults(config *rest.Config) { + gv := corev1alpha3.SchemeGroupVersion + config.GroupVersion = &gv + config.APIPath = "/apis" + config.NegotiatedSerializer = rest.CodecFactoryForGeneratedClient(scheme.Scheme, scheme.Codecs).WithoutConversion() + + if config.UserAgent == "" { + config.UserAgent = rest.DefaultKubernetesUserAgent() + } +} + +// RESTClient returns a RESTClient that is used to communicate +// with API server by this client implementation. +func (c *VirtualizationV1alpha3Client) RESTClient() rest.Interface { + if c == nil { + return nil + } + return c.restClient +} diff --git a/api/client/generated/clientset/versioned/typed/core/v1alpha3/doc.go b/api/client/generated/clientset/versioned/typed/core/v1alpha3/doc.go new file mode 100644 index 0000000000..cc161d1e74 --- /dev/null +++ b/api/client/generated/clientset/versioned/typed/core/v1alpha3/doc.go @@ -0,0 +1,20 @@ +/* +Copyright Flant JSC + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. +*/ + +// Code generated by client-gen. DO NOT EDIT. + +// This package has the automatically generated typed clients. +package v1alpha3 diff --git a/api/client/generated/clientset/versioned/typed/core/v1alpha3/fake/doc.go b/api/client/generated/clientset/versioned/typed/core/v1alpha3/fake/doc.go new file mode 100644 index 0000000000..302a814007 --- /dev/null +++ b/api/client/generated/clientset/versioned/typed/core/v1alpha3/fake/doc.go @@ -0,0 +1,20 @@ +/* +Copyright Flant JSC + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. +*/ + +// Code generated by client-gen. DO NOT EDIT. + +// Package fake has the automatically generated clients. +package fake diff --git a/api/client/generated/clientset/versioned/typed/core/v1alpha3/fake/fake_core_client.go b/api/client/generated/clientset/versioned/typed/core/v1alpha3/fake/fake_core_client.go new file mode 100644 index 0000000000..e86d5e9b67 --- /dev/null +++ b/api/client/generated/clientset/versioned/typed/core/v1alpha3/fake/fake_core_client.go @@ -0,0 +1,40 @@ +/* +Copyright Flant JSC + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. +*/ + +// Code generated by client-gen. DO NOT EDIT. + +package fake + +import ( + v1alpha3 "github.com/deckhouse/virtualization/api/client/generated/clientset/versioned/typed/core/v1alpha3" + rest "k8s.io/client-go/rest" + testing "k8s.io/client-go/testing" +) + +type FakeVirtualizationV1alpha3 struct { + *testing.Fake +} + +func (c *FakeVirtualizationV1alpha3) VirtualMachineClasses() v1alpha3.VirtualMachineClassInterface { + return newFakeVirtualMachineClasses(c) +} + +// RESTClient returns a RESTClient that is used to communicate +// with API server by this client implementation. +func (c *FakeVirtualizationV1alpha3) RESTClient() rest.Interface { + var ret *rest.RESTClient + return ret +} diff --git a/api/client/generated/clientset/versioned/typed/core/v1alpha3/fake/fake_virtualmachineclass.go b/api/client/generated/clientset/versioned/typed/core/v1alpha3/fake/fake_virtualmachineclass.go new file mode 100644 index 0000000000..b00b1bd86e --- /dev/null +++ b/api/client/generated/clientset/versioned/typed/core/v1alpha3/fake/fake_virtualmachineclass.go @@ -0,0 +1,52 @@ +/* +Copyright Flant JSC + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. +*/ + +// Code generated by client-gen. DO NOT EDIT. + +package fake + +import ( + corev1alpha3 "github.com/deckhouse/virtualization/api/client/generated/clientset/versioned/typed/core/v1alpha3" + v1alpha3 "github.com/deckhouse/virtualization/api/core/v1alpha3" + gentype "k8s.io/client-go/gentype" +) + +// fakeVirtualMachineClasses implements VirtualMachineClassInterface +type fakeVirtualMachineClasses struct { + *gentype.FakeClientWithList[*v1alpha3.VirtualMachineClass, *v1alpha3.VirtualMachineClassList] + Fake *FakeVirtualizationV1alpha3 +} + +func newFakeVirtualMachineClasses(fake *FakeVirtualizationV1alpha3) corev1alpha3.VirtualMachineClassInterface { + return &fakeVirtualMachineClasses{ + gentype.NewFakeClientWithList[*v1alpha3.VirtualMachineClass, *v1alpha3.VirtualMachineClassList]( + fake.Fake, + "", + v1alpha3.SchemeGroupVersion.WithResource("virtualmachineclasses"), + v1alpha3.SchemeGroupVersion.WithKind("VirtualMachineClass"), + func() *v1alpha3.VirtualMachineClass { return &v1alpha3.VirtualMachineClass{} }, + func() *v1alpha3.VirtualMachineClassList { return &v1alpha3.VirtualMachineClassList{} }, + func(dst, src *v1alpha3.VirtualMachineClassList) { dst.ListMeta = src.ListMeta }, + func(list *v1alpha3.VirtualMachineClassList) []*v1alpha3.VirtualMachineClass { + return gentype.ToPointerSlice(list.Items) + }, + func(list *v1alpha3.VirtualMachineClassList, items []*v1alpha3.VirtualMachineClass) { + list.Items = gentype.FromPointerSlice(items) + }, + ), + fake, + } +} diff --git a/api/client/generated/clientset/versioned/typed/core/v1alpha3/generated_expansion.go b/api/client/generated/clientset/versioned/typed/core/v1alpha3/generated_expansion.go new file mode 100644 index 0000000000..4d90e21047 --- /dev/null +++ b/api/client/generated/clientset/versioned/typed/core/v1alpha3/generated_expansion.go @@ -0,0 +1,21 @@ +/* +Copyright Flant JSC + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. +*/ + +// Code generated by client-gen. DO NOT EDIT. + +package v1alpha3 + +type VirtualMachineClassExpansion interface{} diff --git a/api/client/generated/clientset/versioned/typed/core/v1alpha3/virtualmachineclass.go b/api/client/generated/clientset/versioned/typed/core/v1alpha3/virtualmachineclass.go new file mode 100644 index 0000000000..86c69a1c87 --- /dev/null +++ b/api/client/generated/clientset/versioned/typed/core/v1alpha3/virtualmachineclass.go @@ -0,0 +1,70 @@ +/* +Copyright Flant JSC + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. +*/ + +// Code generated by client-gen. DO NOT EDIT. + +package v1alpha3 + +import ( + context "context" + + scheme "github.com/deckhouse/virtualization/api/client/generated/clientset/versioned/scheme" + corev1alpha3 "github.com/deckhouse/virtualization/api/core/v1alpha3" + v1 "k8s.io/apimachinery/pkg/apis/meta/v1" + types "k8s.io/apimachinery/pkg/types" + watch "k8s.io/apimachinery/pkg/watch" + gentype "k8s.io/client-go/gentype" +) + +// VirtualMachineClassesGetter has a method to return a VirtualMachineClassInterface. +// A group's client should implement this interface. +type VirtualMachineClassesGetter interface { + VirtualMachineClasses() VirtualMachineClassInterface +} + +// VirtualMachineClassInterface has methods to work with VirtualMachineClass resources. +type VirtualMachineClassInterface interface { + Create(ctx context.Context, virtualMachineClass *corev1alpha3.VirtualMachineClass, opts v1.CreateOptions) (*corev1alpha3.VirtualMachineClass, error) + Update(ctx context.Context, virtualMachineClass *corev1alpha3.VirtualMachineClass, opts v1.UpdateOptions) (*corev1alpha3.VirtualMachineClass, error) + // Add a +genclient:noStatus comment above the type to avoid generating UpdateStatus(). + UpdateStatus(ctx context.Context, virtualMachineClass *corev1alpha3.VirtualMachineClass, opts v1.UpdateOptions) (*corev1alpha3.VirtualMachineClass, error) + Delete(ctx context.Context, name string, opts v1.DeleteOptions) error + DeleteCollection(ctx context.Context, opts v1.DeleteOptions, listOpts v1.ListOptions) error + Get(ctx context.Context, name string, opts v1.GetOptions) (*corev1alpha3.VirtualMachineClass, error) + List(ctx context.Context, opts v1.ListOptions) (*corev1alpha3.VirtualMachineClassList, error) + Watch(ctx context.Context, opts v1.ListOptions) (watch.Interface, error) + Patch(ctx context.Context, name string, pt types.PatchType, data []byte, opts v1.PatchOptions, subresources ...string) (result *corev1alpha3.VirtualMachineClass, err error) + VirtualMachineClassExpansion +} + +// virtualMachineClasses implements VirtualMachineClassInterface +type virtualMachineClasses struct { + *gentype.ClientWithList[*corev1alpha3.VirtualMachineClass, *corev1alpha3.VirtualMachineClassList] +} + +// newVirtualMachineClasses returns a VirtualMachineClasses +func newVirtualMachineClasses(c *VirtualizationV1alpha3Client) *virtualMachineClasses { + return &virtualMachineClasses{ + gentype.NewClientWithList[*corev1alpha3.VirtualMachineClass, *corev1alpha3.VirtualMachineClassList]( + "virtualmachineclasses", + c.RESTClient(), + scheme.ParameterCodec, + "", + func() *corev1alpha3.VirtualMachineClass { return &corev1alpha3.VirtualMachineClass{} }, + func() *corev1alpha3.VirtualMachineClassList { return &corev1alpha3.VirtualMachineClassList{} }, + ), + } +} diff --git a/api/client/generated/informers/externalversions/core/interface.go b/api/client/generated/informers/externalversions/core/interface.go index 1364a78eb7..f1da9e577c 100644 --- a/api/client/generated/informers/externalversions/core/interface.go +++ b/api/client/generated/informers/externalversions/core/interface.go @@ -20,6 +20,7 @@ package core import ( v1alpha2 "github.com/deckhouse/virtualization/api/client/generated/informers/externalversions/core/v1alpha2" + v1alpha3 "github.com/deckhouse/virtualization/api/client/generated/informers/externalversions/core/v1alpha3" internalinterfaces "github.com/deckhouse/virtualization/api/client/generated/informers/externalversions/internalinterfaces" ) @@ -27,6 +28,8 @@ import ( type Interface interface { // V1alpha2 provides access to shared informers for resources in V1alpha2. V1alpha2() v1alpha2.Interface + // V1alpha3 provides access to shared informers for resources in V1alpha3. + V1alpha3() v1alpha3.Interface } type group struct { @@ -44,3 +47,8 @@ func New(f internalinterfaces.SharedInformerFactory, namespace string, tweakList func (g *group) V1alpha2() v1alpha2.Interface { return v1alpha2.New(g.factory, g.namespace, g.tweakListOptions) } + +// V1alpha3 returns a new v1alpha3.Interface. +func (g *group) V1alpha3() v1alpha3.Interface { + return v1alpha3.New(g.factory, g.namespace, g.tweakListOptions) +} diff --git a/api/client/generated/informers/externalversions/core/v1alpha3/interface.go b/api/client/generated/informers/externalversions/core/v1alpha3/interface.go new file mode 100644 index 0000000000..e201f89fa0 --- /dev/null +++ b/api/client/generated/informers/externalversions/core/v1alpha3/interface.go @@ -0,0 +1,45 @@ +/* +Copyright Flant JSC + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. +*/ + +// Code generated by informer-gen. DO NOT EDIT. + +package v1alpha3 + +import ( + internalinterfaces "github.com/deckhouse/virtualization/api/client/generated/informers/externalversions/internalinterfaces" +) + +// Interface provides access to all the informers in this group version. +type Interface interface { + // VirtualMachineClasses returns a VirtualMachineClassInformer. + VirtualMachineClasses() VirtualMachineClassInformer +} + +type version struct { + factory internalinterfaces.SharedInformerFactory + namespace string + tweakListOptions internalinterfaces.TweakListOptionsFunc +} + +// New returns a new Interface. +func New(f internalinterfaces.SharedInformerFactory, namespace string, tweakListOptions internalinterfaces.TweakListOptionsFunc) Interface { + return &version{factory: f, namespace: namespace, tweakListOptions: tweakListOptions} +} + +// VirtualMachineClasses returns a VirtualMachineClassInformer. +func (v *version) VirtualMachineClasses() VirtualMachineClassInformer { + return &virtualMachineClassInformer{factory: v.factory, tweakListOptions: v.tweakListOptions} +} diff --git a/api/client/generated/informers/externalversions/core/v1alpha3/virtualmachineclass.go b/api/client/generated/informers/externalversions/core/v1alpha3/virtualmachineclass.go new file mode 100644 index 0000000000..f94694cc8e --- /dev/null +++ b/api/client/generated/informers/externalversions/core/v1alpha3/virtualmachineclass.go @@ -0,0 +1,101 @@ +/* +Copyright Flant JSC + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. +*/ + +// Code generated by informer-gen. DO NOT EDIT. + +package v1alpha3 + +import ( + context "context" + time "time" + + versioned "github.com/deckhouse/virtualization/api/client/generated/clientset/versioned" + internalinterfaces "github.com/deckhouse/virtualization/api/client/generated/informers/externalversions/internalinterfaces" + corev1alpha3 "github.com/deckhouse/virtualization/api/client/generated/listers/core/v1alpha3" + apicorev1alpha3 "github.com/deckhouse/virtualization/api/core/v1alpha3" + v1 "k8s.io/apimachinery/pkg/apis/meta/v1" + runtime "k8s.io/apimachinery/pkg/runtime" + watch "k8s.io/apimachinery/pkg/watch" + cache "k8s.io/client-go/tools/cache" +) + +// VirtualMachineClassInformer provides access to a shared informer and lister for +// VirtualMachineClasses. +type VirtualMachineClassInformer interface { + Informer() cache.SharedIndexInformer + Lister() corev1alpha3.VirtualMachineClassLister +} + +type virtualMachineClassInformer struct { + factory internalinterfaces.SharedInformerFactory + tweakListOptions internalinterfaces.TweakListOptionsFunc +} + +// NewVirtualMachineClassInformer constructs a new informer for VirtualMachineClass type. +// Always prefer using an informer factory to get a shared informer instead of getting an independent +// one. This reduces memory footprint and number of connections to the server. +func NewVirtualMachineClassInformer(client versioned.Interface, resyncPeriod time.Duration, indexers cache.Indexers) cache.SharedIndexInformer { + return NewFilteredVirtualMachineClassInformer(client, resyncPeriod, indexers, nil) +} + +// NewFilteredVirtualMachineClassInformer constructs a new informer for VirtualMachineClass type. +// Always prefer using an informer factory to get a shared informer instead of getting an independent +// one. This reduces memory footprint and number of connections to the server. +func NewFilteredVirtualMachineClassInformer(client versioned.Interface, resyncPeriod time.Duration, indexers cache.Indexers, tweakListOptions internalinterfaces.TweakListOptionsFunc) cache.SharedIndexInformer { + return cache.NewSharedIndexInformer( + &cache.ListWatch{ + ListFunc: func(options v1.ListOptions) (runtime.Object, error) { + if tweakListOptions != nil { + tweakListOptions(&options) + } + return client.VirtualizationV1alpha3().VirtualMachineClasses().List(context.Background(), options) + }, + WatchFunc: func(options v1.ListOptions) (watch.Interface, error) { + if tweakListOptions != nil { + tweakListOptions(&options) + } + return client.VirtualizationV1alpha3().VirtualMachineClasses().Watch(context.Background(), options) + }, + ListWithContextFunc: func(ctx context.Context, options v1.ListOptions) (runtime.Object, error) { + if tweakListOptions != nil { + tweakListOptions(&options) + } + return client.VirtualizationV1alpha3().VirtualMachineClasses().List(ctx, options) + }, + WatchFuncWithContext: func(ctx context.Context, options v1.ListOptions) (watch.Interface, error) { + if tweakListOptions != nil { + tweakListOptions(&options) + } + return client.VirtualizationV1alpha3().VirtualMachineClasses().Watch(ctx, options) + }, + }, + &apicorev1alpha3.VirtualMachineClass{}, + resyncPeriod, + indexers, + ) +} + +func (f *virtualMachineClassInformer) defaultInformer(client versioned.Interface, resyncPeriod time.Duration) cache.SharedIndexInformer { + return NewFilteredVirtualMachineClassInformer(client, resyncPeriod, cache.Indexers{cache.NamespaceIndex: cache.MetaNamespaceIndexFunc}, f.tweakListOptions) +} + +func (f *virtualMachineClassInformer) Informer() cache.SharedIndexInformer { + return f.factory.InformerFor(&apicorev1alpha3.VirtualMachineClass{}, f.defaultInformer) +} + +func (f *virtualMachineClassInformer) Lister() corev1alpha3.VirtualMachineClassLister { + return corev1alpha3.NewVirtualMachineClassLister(f.Informer().GetIndexer()) +} diff --git a/api/client/generated/informers/externalversions/generic.go b/api/client/generated/informers/externalversions/generic.go index 1d37a9b7ae..938b674b16 100644 --- a/api/client/generated/informers/externalversions/generic.go +++ b/api/client/generated/informers/externalversions/generic.go @@ -22,6 +22,7 @@ import ( fmt "fmt" v1alpha2 "github.com/deckhouse/virtualization/api/core/v1alpha2" + v1alpha3 "github.com/deckhouse/virtualization/api/core/v1alpha3" schema "k8s.io/apimachinery/pkg/runtime/schema" cache "k8s.io/client-go/tools/cache" ) @@ -82,6 +83,10 @@ func (f *sharedInformerFactory) ForResource(resource schema.GroupVersionResource case v1alpha2.SchemeGroupVersion.WithResource("virtualmachinesnapshots"): return &genericInformer{resource: resource.GroupResource(), informer: f.Virtualization().V1alpha2().VirtualMachineSnapshots().Informer()}, nil + // Group=virtualization.deckhouse.io, Version=v1alpha3 + case v1alpha3.SchemeGroupVersion.WithResource("virtualmachineclasses"): + return &genericInformer{resource: resource.GroupResource(), informer: f.Virtualization().V1alpha3().VirtualMachineClasses().Informer()}, nil + } return nil, fmt.Errorf("no informer found for %v", resource) diff --git a/api/client/generated/listers/core/v1alpha3/expansion_generated.go b/api/client/generated/listers/core/v1alpha3/expansion_generated.go new file mode 100644 index 0000000000..4aed995351 --- /dev/null +++ b/api/client/generated/listers/core/v1alpha3/expansion_generated.go @@ -0,0 +1,23 @@ +/* +Copyright Flant JSC + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. +*/ + +// Code generated by lister-gen. DO NOT EDIT. + +package v1alpha3 + +// VirtualMachineClassListerExpansion allows custom methods to be added to +// VirtualMachineClassLister. +type VirtualMachineClassListerExpansion interface{} diff --git a/api/client/generated/listers/core/v1alpha3/virtualmachineclass.go b/api/client/generated/listers/core/v1alpha3/virtualmachineclass.go new file mode 100644 index 0000000000..f3616caec8 --- /dev/null +++ b/api/client/generated/listers/core/v1alpha3/virtualmachineclass.go @@ -0,0 +1,48 @@ +/* +Copyright Flant JSC + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. +*/ + +// Code generated by lister-gen. DO NOT EDIT. + +package v1alpha3 + +import ( + corev1alpha3 "github.com/deckhouse/virtualization/api/core/v1alpha3" + labels "k8s.io/apimachinery/pkg/labels" + listers "k8s.io/client-go/listers" + cache "k8s.io/client-go/tools/cache" +) + +// VirtualMachineClassLister helps list VirtualMachineClasses. +// All objects returned here must be treated as read-only. +type VirtualMachineClassLister interface { + // List lists all VirtualMachineClasses in the indexer. + // Objects returned here must be treated as read-only. + List(selector labels.Selector) (ret []*corev1alpha3.VirtualMachineClass, err error) + // Get retrieves the VirtualMachineClass from the index for a given name. + // Objects returned here must be treated as read-only. + Get(name string) (*corev1alpha3.VirtualMachineClass, error) + VirtualMachineClassListerExpansion +} + +// virtualMachineClassLister implements the VirtualMachineClassLister interface. +type virtualMachineClassLister struct { + listers.ResourceIndexer[*corev1alpha3.VirtualMachineClass] +} + +// NewVirtualMachineClassLister returns a new VirtualMachineClassLister. +func NewVirtualMachineClassLister(indexer cache.Indexer) VirtualMachineClassLister { + return &virtualMachineClassLister{listers.New[*corev1alpha3.VirtualMachineClass](indexer, corev1alpha3.Resource("virtualmachineclass"))} +} diff --git a/api/core/v1alpha2/virtual_machine_class.go b/api/core/v1alpha2/virtual_machine_class.go index 9eeaf5d254..08134017c5 100644 --- a/api/core/v1alpha2/virtual_machine_class.go +++ b/api/core/v1alpha2/virtual_machine_class.go @@ -42,6 +42,7 @@ const ( // +genclient // +genclient:nonNamespaced // +k8s:deepcopy-gen:interfaces=k8s.io/apimachinery/pkg/runtime.Object +// +kubebuilder:conversion:spoke type VirtualMachineClass struct { metav1.TypeMeta `json:",inline"` metav1.ObjectMeta `json:"metadata,omitempty"` diff --git a/api/core/v1alpha2/virtual_machine_class_conversion.go b/api/core/v1alpha2/virtual_machine_class_conversion.go new file mode 100644 index 0000000000..61e8a8f828 --- /dev/null +++ b/api/core/v1alpha2/virtual_machine_class_conversion.go @@ -0,0 +1,208 @@ +/* +Copyright 2025 Flant JSC + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. +*/ + +package v1alpha2 + +import ( + "fmt" + "strconv" + + "sigs.k8s.io/controller-runtime/pkg/conversion" + + "github.com/deckhouse/virtualization/api/core/v1alpha3" +) + +var _ conversion.Convertible = &VirtualMachineClass{} + +func (src *VirtualMachineClass) ConvertTo(dstRaw conversion.Hub) error { + dst := dstRaw.(*v1alpha3.VirtualMachineClass) + + dst.ObjectMeta = src.ObjectMeta + dst.Spec = convertSpecV2ToV3(src.Spec) + dst.Status = convertStatusV2ToV3(src.Status) + + return nil +} + +func (dst *VirtualMachineClass) ConvertFrom(srcRaw conversion.Hub) error { + src := srcRaw.(*v1alpha3.VirtualMachineClass) + + dst.ObjectMeta = src.ObjectMeta + dst.Spec = convertSpecV3ToV2(src.Spec) + dst.Status = convertStatusV3ToV2(src.Status) + + return nil +} + +func convertSpecV2ToV3(v2Spec VirtualMachineClassSpec) v1alpha3.VirtualMachineClassSpec { + v3Spec := v1alpha3.VirtualMachineClassSpec{ + NodeSelector: v1alpha3.NodeSelector{ + MatchLabels: v2Spec.NodeSelector.MatchLabels, + MatchExpressions: v2Spec.NodeSelector.MatchExpressions, + }, + Tolerations: v2Spec.Tolerations, + CPU: v1alpha3.CPU{ + Type: v1alpha3.CPUType(v2Spec.CPU.Type), + Model: v2Spec.CPU.Model, + Features: v2Spec.CPU.Features, + Discovery: v1alpha3.CpuDiscovery{ + NodeSelector: v2Spec.CPU.Discovery.NodeSelector, + }, + }, + } + + if len(v2Spec.SizingPolicies) > 0 { + v3Spec.SizingPolicies = make([]v1alpha3.SizingPolicy, len(v2Spec.SizingPolicies)) + for i, v2Policy := range v2Spec.SizingPolicies { + v3Policy := v1alpha3.SizingPolicy{ + DedicatedCores: v2Policy.DedicatedCores, + } + + if v2Policy.Memory != nil { + v3Policy.Memory = &v1alpha3.SizingPolicyMemory{ + MemoryMinMax: v1alpha3.MemoryMinMax{ + Min: v2Policy.Memory.Min, + Max: v2Policy.Memory.Max, + }, + Step: v2Policy.Memory.Step, + PerCore: v1alpha3.SizingPolicyMemoryPerCore{ + MemoryMinMax: v1alpha3.MemoryMinMax{ + Min: v2Policy.Memory.PerCore.Min, + Max: v2Policy.Memory.PerCore.Max, + }, + }, + } + } + + if v2Policy.Cores != nil { + v3Policy.Cores = &v1alpha3.SizingPolicyCores{ + Min: v2Policy.Cores.Min, + Max: v2Policy.Cores.Max, + Step: v2Policy.Cores.Step, + } + } + + if len(v2Policy.CoreFractions) > 0 { + v3Policy.CoreFractions = make([]v1alpha3.CoreFractionValue, len(v2Policy.CoreFractions)) + for j, v2Fraction := range v2Policy.CoreFractions { + v3Policy.CoreFractions[j] = v1alpha3.CoreFractionValue(fmt.Sprintf("%d%%", v2Fraction)) + } + } + + v3Spec.SizingPolicies[i] = v3Policy + } + } + + return v3Spec +} + +func convertSpecV3ToV2(v3Spec v1alpha3.VirtualMachineClassSpec) VirtualMachineClassSpec { + v2Spec := VirtualMachineClassSpec{ + NodeSelector: NodeSelector{ + MatchLabels: v3Spec.NodeSelector.MatchLabels, + MatchExpressions: v3Spec.NodeSelector.MatchExpressions, + }, + Tolerations: v3Spec.Tolerations, + CPU: CPU{ + Type: CPUType(v3Spec.CPU.Type), + Model: v3Spec.CPU.Model, + Features: v3Spec.CPU.Features, + Discovery: CpuDiscovery{ + NodeSelector: v3Spec.CPU.Discovery.NodeSelector, + }, + }, + } + + if len(v3Spec.SizingPolicies) > 0 { + v2Spec.SizingPolicies = make([]SizingPolicy, len(v3Spec.SizingPolicies)) + for i, v3Policy := range v3Spec.SizingPolicies { + v2Policy := SizingPolicy{ + DedicatedCores: v3Policy.DedicatedCores, + } + + if v3Policy.Memory != nil { + v2Policy.Memory = &SizingPolicyMemory{ + MemoryMinMax: MemoryMinMax{ + Min: v3Policy.Memory.Min, + Max: v3Policy.Memory.Max, + }, + Step: v3Policy.Memory.Step, + PerCore: SizingPolicyMemoryPerCore{ + MemoryMinMax: MemoryMinMax{ + Min: v3Policy.Memory.PerCore.Min, + Max: v3Policy.Memory.PerCore.Max, + }, + }, + } + } + + if v3Policy.Cores != nil { + v2Policy.Cores = &SizingPolicyCores{ + Min: v3Policy.Cores.Min, + Max: v3Policy.Cores.Max, + Step: v3Policy.Cores.Step, + } + } + + if len(v3Policy.CoreFractions) > 0 { + v2Policy.CoreFractions = make([]CoreFractionValue, len(v3Policy.CoreFractions)) + for j, v3Fraction := range v3Policy.CoreFractions { + fractionStr := string(v3Fraction) + if len(fractionStr) > 0 && fractionStr[len(fractionStr)-1] == '%' { + fractionStr = fractionStr[:len(fractionStr)-1] + } + fractionInt, err := strconv.Atoi(fractionStr) + if err != nil { + fractionInt = 100 + } + v2Policy.CoreFractions[j] = CoreFractionValue(fractionInt) + } + } + + v2Spec.SizingPolicies[i] = v2Policy + } + } + + return v2Spec +} + +func convertStatusV2ToV3(v2Status VirtualMachineClassStatus) v1alpha3.VirtualMachineClassStatus { + return v1alpha3.VirtualMachineClassStatus{ + Phase: v1alpha3.VirtualMachineClassPhase(v2Status.Phase), + CpuFeatures: v1alpha3.CpuFeatures{ + Enabled: v2Status.CpuFeatures.Enabled, + NotEnabledCommon: v2Status.CpuFeatures.NotEnabledCommon, + }, + AvailableNodes: v2Status.AvailableNodes, + MaxAllocatableResources: v2Status.MaxAllocatableResources, + Conditions: v2Status.Conditions, + ObservedGeneration: v2Status.ObservedGeneration, + } +} + +func convertStatusV3ToV2(v3Status v1alpha3.VirtualMachineClassStatus) VirtualMachineClassStatus { + return VirtualMachineClassStatus{ + Phase: VirtualMachineClassPhase(v3Status.Phase), + CpuFeatures: CpuFeatures{ + Enabled: v3Status.CpuFeatures.Enabled, + NotEnabledCommon: v3Status.CpuFeatures.NotEnabledCommon, + }, + AvailableNodes: v3Status.AvailableNodes, + MaxAllocatableResources: v3Status.MaxAllocatableResources, + Conditions: v3Status.Conditions, + ObservedGeneration: v3Status.ObservedGeneration, + } +} diff --git a/api/core/v1alpha3/virtual_machine_class.go b/api/core/v1alpha3/virtual_machine_class.go index 76fd26381d..807a661826 100644 --- a/api/core/v1alpha3/virtual_machine_class.go +++ b/api/core/v1alpha3/virtual_machine_class.go @@ -43,6 +43,7 @@ const ( // +genclient // +genclient:nonNamespaced // +k8s:deepcopy-gen:interfaces=k8s.io/apimachinery/pkg/runtime.Object +// +kubebuilder:conversion:hub type VirtualMachineClass struct { metav1.TypeMeta `json:",inline"` metav1.ObjectMeta `json:"metadata,omitempty"` diff --git a/api/core/v1alpha3/zz_generated.deepcopy.go b/api/core/v1alpha3/zz_generated.deepcopy.go new file mode 100644 index 0000000000..bccb1f69f5 --- /dev/null +++ b/api/core/v1alpha3/zz_generated.deepcopy.go @@ -0,0 +1,358 @@ +//go:build !ignore_autogenerated +// +build !ignore_autogenerated + +/* +Copyright Flant JSC + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. +*/ + +// Code generated by deepcopy-gen. DO NOT EDIT. + +package v1alpha3 + +import ( + v1 "k8s.io/api/core/v1" + metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" + runtime "k8s.io/apimachinery/pkg/runtime" +) + +// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. +func (in *CPU) DeepCopyInto(out *CPU) { + *out = *in + if in.Features != nil { + in, out := &in.Features, &out.Features + *out = make([]string, len(*in)) + copy(*out, *in) + } + in.Discovery.DeepCopyInto(&out.Discovery) + return +} + +// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new CPU. +func (in *CPU) DeepCopy() *CPU { + if in == nil { + return nil + } + out := new(CPU) + in.DeepCopyInto(out) + return out +} + +// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. +func (in *CpuDiscovery) DeepCopyInto(out *CpuDiscovery) { + *out = *in + in.NodeSelector.DeepCopyInto(&out.NodeSelector) + return +} + +// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new CpuDiscovery. +func (in *CpuDiscovery) DeepCopy() *CpuDiscovery { + if in == nil { + return nil + } + out := new(CpuDiscovery) + in.DeepCopyInto(out) + return out +} + +// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. +func (in *CpuFeatures) DeepCopyInto(out *CpuFeatures) { + *out = *in + if in.Enabled != nil { + in, out := &in.Enabled, &out.Enabled + *out = make([]string, len(*in)) + copy(*out, *in) + } + if in.NotEnabledCommon != nil { + in, out := &in.NotEnabledCommon, &out.NotEnabledCommon + *out = make([]string, len(*in)) + copy(*out, *in) + } + return +} + +// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new CpuFeatures. +func (in *CpuFeatures) DeepCopy() *CpuFeatures { + if in == nil { + return nil + } + out := new(CpuFeatures) + in.DeepCopyInto(out) + return out +} + +// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. +func (in *MemoryMinMax) DeepCopyInto(out *MemoryMinMax) { + *out = *in + out.Min = in.Min.DeepCopy() + out.Max = in.Max.DeepCopy() + return +} + +// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new MemoryMinMax. +func (in *MemoryMinMax) DeepCopy() *MemoryMinMax { + if in == nil { + return nil + } + out := new(MemoryMinMax) + in.DeepCopyInto(out) + return out +} + +// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. +func (in *NodeSelector) DeepCopyInto(out *NodeSelector) { + *out = *in + if in.MatchLabels != nil { + in, out := &in.MatchLabels, &out.MatchLabels + *out = make(map[string]string, len(*in)) + for key, val := range *in { + (*out)[key] = val + } + } + if in.MatchExpressions != nil { + in, out := &in.MatchExpressions, &out.MatchExpressions + *out = make([]v1.NodeSelectorRequirement, len(*in)) + for i := range *in { + (*in)[i].DeepCopyInto(&(*out)[i]) + } + } + return +} + +// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new NodeSelector. +func (in *NodeSelector) DeepCopy() *NodeSelector { + if in == nil { + return nil + } + out := new(NodeSelector) + in.DeepCopyInto(out) + return out +} + +// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. +func (in *SizingPolicy) DeepCopyInto(out *SizingPolicy) { + *out = *in + if in.Memory != nil { + in, out := &in.Memory, &out.Memory + *out = new(SizingPolicyMemory) + (*in).DeepCopyInto(*out) + } + if in.CoreFractions != nil { + in, out := &in.CoreFractions, &out.CoreFractions + *out = make([]CoreFractionValue, len(*in)) + copy(*out, *in) + } + if in.DedicatedCores != nil { + in, out := &in.DedicatedCores, &out.DedicatedCores + *out = make([]bool, len(*in)) + copy(*out, *in) + } + if in.Cores != nil { + in, out := &in.Cores, &out.Cores + *out = new(SizingPolicyCores) + **out = **in + } + return +} + +// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new SizingPolicy. +func (in *SizingPolicy) DeepCopy() *SizingPolicy { + if in == nil { + return nil + } + out := new(SizingPolicy) + in.DeepCopyInto(out) + return out +} + +// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. +func (in *SizingPolicyCores) DeepCopyInto(out *SizingPolicyCores) { + *out = *in + return +} + +// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new SizingPolicyCores. +func (in *SizingPolicyCores) DeepCopy() *SizingPolicyCores { + if in == nil { + return nil + } + out := new(SizingPolicyCores) + in.DeepCopyInto(out) + return out +} + +// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. +func (in *SizingPolicyMemory) DeepCopyInto(out *SizingPolicyMemory) { + *out = *in + in.MemoryMinMax.DeepCopyInto(&out.MemoryMinMax) + out.Step = in.Step.DeepCopy() + in.PerCore.DeepCopyInto(&out.PerCore) + return +} + +// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new SizingPolicyMemory. +func (in *SizingPolicyMemory) DeepCopy() *SizingPolicyMemory { + if in == nil { + return nil + } + out := new(SizingPolicyMemory) + in.DeepCopyInto(out) + return out +} + +// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. +func (in *SizingPolicyMemoryPerCore) DeepCopyInto(out *SizingPolicyMemoryPerCore) { + *out = *in + in.MemoryMinMax.DeepCopyInto(&out.MemoryMinMax) + return +} + +// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new SizingPolicyMemoryPerCore. +func (in *SizingPolicyMemoryPerCore) DeepCopy() *SizingPolicyMemoryPerCore { + if in == nil { + return nil + } + out := new(SizingPolicyMemoryPerCore) + in.DeepCopyInto(out) + return out +} + +// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. +func (in *VirtualMachineClass) DeepCopyInto(out *VirtualMachineClass) { + *out = *in + out.TypeMeta = in.TypeMeta + in.ObjectMeta.DeepCopyInto(&out.ObjectMeta) + in.Spec.DeepCopyInto(&out.Spec) + in.Status.DeepCopyInto(&out.Status) + return +} + +// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new VirtualMachineClass. +func (in *VirtualMachineClass) DeepCopy() *VirtualMachineClass { + if in == nil { + return nil + } + out := new(VirtualMachineClass) + in.DeepCopyInto(out) + return out +} + +// DeepCopyObject is an autogenerated deepcopy function, copying the receiver, creating a new runtime.Object. +func (in *VirtualMachineClass) DeepCopyObject() runtime.Object { + if c := in.DeepCopy(); c != nil { + return c + } + return nil +} + +// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. +func (in *VirtualMachineClassList) DeepCopyInto(out *VirtualMachineClassList) { + *out = *in + out.TypeMeta = in.TypeMeta + in.ListMeta.DeepCopyInto(&out.ListMeta) + if in.Items != nil { + in, out := &in.Items, &out.Items + *out = make([]VirtualMachineClass, len(*in)) + for i := range *in { + (*in)[i].DeepCopyInto(&(*out)[i]) + } + } + return +} + +// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new VirtualMachineClassList. +func (in *VirtualMachineClassList) DeepCopy() *VirtualMachineClassList { + if in == nil { + return nil + } + out := new(VirtualMachineClassList) + in.DeepCopyInto(out) + return out +} + +// DeepCopyObject is an autogenerated deepcopy function, copying the receiver, creating a new runtime.Object. +func (in *VirtualMachineClassList) DeepCopyObject() runtime.Object { + if c := in.DeepCopy(); c != nil { + return c + } + return nil +} + +// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. +func (in *VirtualMachineClassSpec) DeepCopyInto(out *VirtualMachineClassSpec) { + *out = *in + in.NodeSelector.DeepCopyInto(&out.NodeSelector) + if in.Tolerations != nil { + in, out := &in.Tolerations, &out.Tolerations + *out = make([]v1.Toleration, len(*in)) + for i := range *in { + (*in)[i].DeepCopyInto(&(*out)[i]) + } + } + in.CPU.DeepCopyInto(&out.CPU) + if in.SizingPolicies != nil { + in, out := &in.SizingPolicies, &out.SizingPolicies + *out = make([]SizingPolicy, len(*in)) + for i := range *in { + (*in)[i].DeepCopyInto(&(*out)[i]) + } + } + return +} + +// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new VirtualMachineClassSpec. +func (in *VirtualMachineClassSpec) DeepCopy() *VirtualMachineClassSpec { + if in == nil { + return nil + } + out := new(VirtualMachineClassSpec) + in.DeepCopyInto(out) + return out +} + +// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. +func (in *VirtualMachineClassStatus) DeepCopyInto(out *VirtualMachineClassStatus) { + *out = *in + in.CpuFeatures.DeepCopyInto(&out.CpuFeatures) + if in.AvailableNodes != nil { + in, out := &in.AvailableNodes, &out.AvailableNodes + *out = make([]string, len(*in)) + copy(*out, *in) + } + if in.MaxAllocatableResources != nil { + in, out := &in.MaxAllocatableResources, &out.MaxAllocatableResources + *out = make(v1.ResourceList, len(*in)) + for key, val := range *in { + (*out)[key] = val.DeepCopy() + } + } + if in.Conditions != nil { + in, out := &in.Conditions, &out.Conditions + *out = make([]metav1.Condition, len(*in)) + for i := range *in { + (*in)[i].DeepCopyInto(&(*out)[i]) + } + } + return +} + +// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new VirtualMachineClassStatus. +func (in *VirtualMachineClassStatus) DeepCopy() *VirtualMachineClassStatus { + if in == nil { + return nil + } + out := new(VirtualMachineClassStatus) + in.DeepCopyInto(out) + return out +} diff --git a/api/go.mod b/api/go.mod index 0aece635b3..eb3cd40deb 100644 --- a/api/go.mod +++ b/api/go.mod @@ -20,9 +20,13 @@ require ( ) require ( + github.com/beorn7/perks v1.0.1 // indirect + github.com/cespare/xxhash/v2 v2.3.0 // indirect github.com/davecgh/go-spew v1.1.2-0.20180830191138-d8f796af33cc // indirect github.com/emicklei/go-restful/v3 v3.11.0 // indirect + github.com/evanphx/json-patch/v5 v5.9.11 // indirect github.com/fatih/color v1.18.0 // indirect + github.com/fsnotify/fsnotify v1.7.0 // indirect github.com/fxamacker/cbor/v2 v2.7.0 // indirect github.com/go-logr/logr v1.4.2 // indirect github.com/go-openapi/jsonpointer v0.21.0 // indirect @@ -30,6 +34,7 @@ require ( github.com/go-openapi/swag v0.23.0 // indirect github.com/gobuffalo/flect v1.0.3 // indirect github.com/gogo/protobuf v1.3.2 // indirect + github.com/google/btree v1.1.3 // indirect github.com/google/gnostic-models v0.7.0 // indirect github.com/google/go-cmp v0.7.0 // indirect github.com/google/uuid v1.6.0 // indirect @@ -45,6 +50,10 @@ require ( 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/prometheus/client_golang v1.22.0 // indirect + github.com/prometheus/client_model v0.6.1 // indirect + github.com/prometheus/common v0.62.0 // indirect + github.com/prometheus/procfs v0.15.1 // indirect github.com/spf13/cobra v1.9.1 // indirect github.com/x448/float16 v0.8.4 // indirect go.yaml.in/yaml/v2 v2.4.2 // indirect @@ -58,6 +67,7 @@ require ( golang.org/x/text v0.24.0 // indirect golang.org/x/time v0.9.0 // indirect golang.org/x/tools v0.32.0 // indirect + gomodules.xyz/jsonpatch/v2 v2.4.0 // indirect google.golang.org/protobuf v1.36.5 // indirect gopkg.in/evanphx/json-patch.v4 v4.12.0 // indirect gopkg.in/inf.v0 v0.9.1 // indirect @@ -69,6 +79,7 @@ require ( k8s.io/utils v0.0.0-20241104100929-3ea5e8cea738 // indirect kubevirt.io/containerized-data-importer-api v1.57.0-alpha1 // 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/controller-tools v0.18.0 // indirect sigs.k8s.io/json v0.0.0-20241010143419-9aa6b5e7a4b3 // indirect sigs.k8s.io/randfill v1.0.0 // indirect diff --git a/api/go.sum b/api/go.sum index 8bb4a2fd8b..ba78d13cd6 100644 --- a/api/go.sum +++ b/api/go.sum @@ -3,7 +3,11 @@ github.com/BurntSushi/toml v0.3.1/go.mod h1:xHWCNGjB5oqiDr8zfno3MHue2Ht5sIBksp03 github.com/NYTimes/gziphandler v1.1.1/go.mod h1:n/CVRwUEOgIxrgPvAQhUUr9oeUtvrhMomdKFjzJNB0c= github.com/PuerkitoBio/purell v1.1.1/go.mod h1:c11w/QuzBsJSee3cPx9rAFu61PvFxuPbtSwDGJws/X0= github.com/PuerkitoBio/urlesc v0.0.0-20170810143723-de5bf2ad4578/go.mod h1:uGdkoq3SwY9Y+13GIhn11/XLaGBb4BfwItxLd5jeuXE= +github.com/beorn7/perks v1.0.1 h1:VlbKKnNfV8bJzeqoa4cOKqO6bYr3WgKZxO8Z16+hsOM= +github.com/beorn7/perks v1.0.1/go.mod h1:G2ZrVWU2WbWT9wwq4/hrbKbnv/1ERSJQ0ibhJ6rlkpw= github.com/census-instrumentation/opencensus-proto v0.2.1/go.mod h1:f6KPmirojxKA12rnyqOA5BBL4O983OfeGPqjHWSTneU= +github.com/cespare/xxhash/v2 v2.3.0 h1:UL815xU9SqsFlibzuggzjXhog7bL6oX9BbNZnL2UFvs= +github.com/cespare/xxhash/v2 v2.3.0/go.mod h1:VGX0DQ3Q6kWi7AoAeZDth3/j3BFtOZR5XLFGgcrjCOs= github.com/chromedp/cdproto v0.0.0-20230802225258-3cf4e6d46a89/go.mod h1:GKljq0VrfU4D5yc+2qA6OVr8pmO/MBbPEWqWQ/oqGEs= github.com/chromedp/chromedp v0.9.2/go.mod h1:LkSXJKONWTCHAfQasKFUZI+mxqS4tZqhmtGzzhLsnLs= github.com/chromedp/sysutil v1.0.0/go.mod h1:kgWmDdq8fTzXYcKIBqIYvRRTnYb9aNS9moAV0xufSww= @@ -28,7 +32,10 @@ github.com/emicklei/go-restful/v3 v3.11.0 h1:rAQeMHw1c7zTmncogyy8VvRZwtkmkZ4FxER github.com/emicklei/go-restful/v3 v3.11.0/go.mod h1:6n3XBCmQQb25CM2LCACGz8ukIrRry+4bhvbpWn3mrbc= github.com/envoyproxy/go-control-plane v0.9.1-0.20191026205805-5f8ba28d4473/go.mod h1:YTl/9mNaCwkRvm6d1a2C3ymFceY/DCBVvsKhRF0iEA4= github.com/envoyproxy/protoc-gen-validate v0.1.0/go.mod h1:iSmxcyjqTsJpI2R4NaDN7+kN2VEUnK/pcBlmesArF7c= +github.com/evanphx/json-patch v4.12.0+incompatible h1:4onqiflcdA9EOZ4RxV643DvftH5pOlLGNtQ5lPWQu84= github.com/evanphx/json-patch v4.12.0+incompatible/go.mod h1:50XU6AFN0ol/bzJsmQLiYLvXMP4fmwYFNcr97nuDLSk= +github.com/evanphx/json-patch/v5 v5.9.11 h1:/8HVnzMq13/3x9TPvjG08wUGqBTmZBsCWzjTM0wiaDU= +github.com/evanphx/json-patch/v5 v5.9.11/go.mod h1:3j+LviiESTElxA4p3EMKAB9HXj3/XEtnUf6OZxqIQTM= github.com/fatih/color v1.18.0 h1:S8gINlzdQ840/4pfAwic/ZE0djQEH3wM94VfqLTZcOM= github.com/fatih/color v1.18.0/go.mod h1:4FelSpRwEGDpQ12mAdzqdOukCy4u8WUtOY6lkT/6HfU= github.com/fsnotify/fsnotify v1.4.7/go.mod h1:jwhsz4b93w/PPRr/qN1Yymfu8t87LnFCMoQvtojpjFo= @@ -87,6 +94,8 @@ github.com/golang/protobuf v1.4.2/go.mod h1:oDoupMAO8OvCJWAcko0GGGIgR6R6ocIYbsSw github.com/golang/protobuf v1.5.0/go.mod h1:FsONVRAS9T7sI+LIUmWTfcYkHO4aIWwzhcaSAoJOfIk= github.com/golang/protobuf v1.5.2/go.mod h1:XVQd3VNwM+JqD3oG2Ue2ip4fOMUkwXdXDdiuN0vRsmY= github.com/golang/protobuf v1.5.3/go.mod h1:XVQd3VNwM+JqD3oG2Ue2ip4fOMUkwXdXDdiuN0vRsmY= +github.com/google/btree v1.1.3 h1:CVpQJjYgC4VbzxeGVHfvZrv1ctoYCAI8vbl07Fcxlyg= +github.com/google/btree v1.1.3/go.mod h1:qOPhT0dTNdNzV6Z/lhRX0YXUafgPLFUh+gZMl761Gm4= github.com/google/gnostic-models v0.7.0 h1:qwTtogB15McXDaNqTZdzPJRHvaVJlAl+HVQnLmJEJxo= github.com/google/gnostic-models v0.7.0/go.mod h1:whL5G0m6dmc5cPxKc5bdKdEN3UjI7OUGxBlw57miDrQ= github.com/google/go-cmp v0.2.0/go.mod h1:oXzfMopK8JAjlY9xF4vHSVASa0yLyX7SntLO5aqRK0M= @@ -219,7 +228,15 @@ github.com/pkg/errors v0.9.1 h1:FEBLx1zS214owpjy7qsBeixbURkuhQAwrK5UwLGTwt4= github.com/pkg/errors v0.9.1/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0= github.com/pmezard/go-difflib v1.0.0 h1:4DBwDE0NGyQoBHbLQYPwSUPoCMWR5BEzIk/f1lZbAQM= github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4= +github.com/prometheus/client_golang v1.22.0 h1:rb93p9lokFEsctTys46VnV1kLCDpVZ0a/Y92Vm0Zc6Q= +github.com/prometheus/client_golang v1.22.0/go.mod h1:R7ljNsLXhuQXYZYtw6GAE9AZg8Y7vEW5scdCXrWRXC0= github.com/prometheus/client_model v0.0.0-20190812154241-14fe0d1b01d4/go.mod h1:xMI15A0UPsDsEKsMN9yxemIoYk6Tm2C1GtYGdfGttqA= +github.com/prometheus/client_model v0.6.1 h1:ZKSh/rekM+n3CeS952MLRAdFwIKqeY8b62p8ais2e9E= +github.com/prometheus/client_model v0.6.1/go.mod h1:OrxVMOVHjw3lKMa8+x6HeMGkHMQyHDk9E3jmP2AmGiY= +github.com/prometheus/common v0.62.0 h1:xasJaQlnWAeyHdUBeGjXmutelfJHWMRr+Fg4QszZ2Io= +github.com/prometheus/common v0.62.0/go.mod h1:vyBcEuLSvWos9B1+CyL7JZ2up+uFzXhkqml0W5zIY1I= +github.com/prometheus/procfs v0.15.1 h1:YagwOFzUgYfKKHX6Dr+sHT7km/hxC76UB0learggepc= +github.com/prometheus/procfs v0.15.1/go.mod h1:fB45yRUv8NstnjriLhBQLuOUt+WW4BsoGhij/e3PBqk= github.com/rogpeppe/go-internal v1.9.0/go.mod h1:WtVeX8xhTBvf0smdhujwtBcq4Qrzq/fJaraNFVN+nFs= github.com/rogpeppe/go-internal v1.12.0/go.mod h1:E+RYuTGaKKdloAfM02xzb0FW3Paa99yedzYV+kq4uf4= github.com/rogpeppe/go-internal v1.13.1 h1:KvO1DLK/DRN07sQ1LQKScxyZJuNnedQ5/wKSR38lUII= @@ -488,6 +505,8 @@ golang.org/x/xerrors v0.0.0-20190717185122-a985d3407aa7/go.mod h1:I/5z698sn9Ka8T golang.org/x/xerrors v0.0.0-20191011141410-1b5146add898/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= golang.org/x/xerrors v0.0.0-20191204190536-9bdfabe68543/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= golang.org/x/xerrors v0.0.0-20200804184101-5ec99f83aff1/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= +gomodules.xyz/jsonpatch/v2 v2.4.0 h1:Ci3iUJyx9UeRx7CeFN8ARgGbkESwJK+KB9lLcWxY/Zw= +gomodules.xyz/jsonpatch/v2 v2.4.0/go.mod h1:AH3dM2RI6uoBZxn3LVrfvJ3E0/9dG4cSrbuBJT4moAY= google.golang.org/appengine v1.1.0/go.mod h1:EbEs0AVv82hx2wNQdGPgUI5lhzA/G0D9YwlJXL52JkM= google.golang.org/appengine v1.4.0/go.mod h1:xpcJRLb0r/rnEns0DIKYYv+WjYCduHsrkT7/EB5XEv4= google.golang.org/genproto v0.0.0-20180817151627-c66870c02cf8/go.mod h1:JiN7NxoALGmiZfu7CAH4rXhgtRTLTxftemlI0sWmxmc= @@ -575,6 +594,8 @@ kubevirt.io/containerized-data-importer-api v1.57.0-alpha1 h1:IWo12+ei3jltSN5jQN kubevirt.io/containerized-data-importer-api v1.57.0-alpha1/go.mod h1:Y/8ETgHS1GjO89bl682DPtQOYEU/1ctPFBz6Sjxm4DM= 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= +sigs.k8s.io/controller-runtime v0.21.0/go.mod h1:OSg14+F65eWqIu4DceX7k/+QRAbTTvxeQSNSOQpukWM= sigs.k8s.io/controller-tools v0.18.0 h1:rGxGZCZTV2wJreeRgqVoWab/mfcumTMmSwKzoM9xrsE= sigs.k8s.io/controller-tools v0.18.0/go.mod h1:gLKoiGBriyNh+x1rWtUQnakUYEujErjXs9pf+x/8n1U= sigs.k8s.io/json v0.0.0-20211020170558-c049b76a60c6/go.mod h1:p4QtZmO4uMYipTQNzagwnNoseA6OxSUutVw05NhYDRs= diff --git a/api/scripts/update-codegen.sh b/api/scripts/update-codegen.sh index 0385c78a6e..93a9e9814e 100755 --- a/api/scripts/update-codegen.sh +++ b/api/scripts/update-codegen.sh @@ -75,7 +75,7 @@ function generate::crds { OUTPUT_BASE=$(mktemp -d) trap 'rm -rf "${OUTPUT_BASE}"' ERR EXIT - go tool controller-gen crd paths="${API_ROOT}/core/v1alpha2/...;${API_ROOT}/core/v1alpha3/..." output:crd:dir="${OUTPUT_BASE}" + go tool controller-gen crd:crdVersions=v1 paths="${API_ROOT}/core/v1alpha2/...;${API_ROOT}/core/v1alpha3/..." output:crd:dir="${OUTPUT_BASE}" # shellcheck disable=SC2044 for file in $(find "${OUTPUT_BASE}"/* -type f -iname "*.yaml"); do @@ -88,7 +88,6 @@ function generate::crds { DEST_FILE="${ROOT}/crds/$(echo $file | awk -Fio_ '{print $2}')" cp "$file" "${DEST_FILE}" - # Add conversion webhook configuration for VirtualMachineClass if [[ "${DEST_FILE}" == *"virtualmachineclasses.yaml" ]]; then yq eval -i '.spec.conversion = { "strategy": "Webhook", diff --git a/images/virtualization-artifact/pkg/controller/vmclass/vmclass_controller.go b/images/virtualization-artifact/pkg/controller/vmclass/vmclass_controller.go index 92335fa019..a7c3eaa915 100644 --- a/images/virtualization-artifact/pkg/controller/vmclass/vmclass_controller.go +++ b/images/virtualization-artifact/pkg/controller/vmclass/vmclass_controller.go @@ -74,9 +74,6 @@ func NewController( return nil, err } - conversionHandler := NewConversionHandler() - mgr.GetWebhookServer().Register("/convert/virtualmachineclasses", conversionHandler) - log.Info("Initialized VirtualMachineClass controller") return c, nil } diff --git a/images/virtualization-artifact/pkg/controller/vmclass/vmclass_conversion.go b/images/virtualization-artifact/pkg/controller/vmclass/vmclass_conversion.go deleted file mode 100644 index 0e5eab6ba8..0000000000 --- a/images/virtualization-artifact/pkg/controller/vmclass/vmclass_conversion.go +++ /dev/null @@ -1,317 +0,0 @@ -/* -Copyright 2025 Flant JSC -Licensed under the Apache License, Version 2.0 (the "License"); -you may not use this file except in compliance with the License. -You may obtain a copy of the License at - http://www.apache.org/licenses/LICENSE-2.0 -Unless required by applicable law or agreed to in writing, software -distributed under the License is distributed on an "AS IS" BASIS, -WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -See the License for the specific language governing permissions and -limitations under the License. -*/ - -package vmclass - -import ( - "encoding/json" - "fmt" - "io" - "net/http" - "strconv" - - apiextensionsv1 "k8s.io/apiextensions-apiserver/pkg/apis/apiextensions/v1" - metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" - "k8s.io/apimachinery/pkg/runtime" - - "github.com/deckhouse/virtualization/api/core/v1alpha2" - "github.com/deckhouse/virtualization/api/core/v1alpha3" -) - -type ConversionHandler struct{} - -func NewConversionHandler() *ConversionHandler { - return &ConversionHandler{} -} - -func (h *ConversionHandler) ServeHTTP(w http.ResponseWriter, r *http.Request) { - body, err := io.ReadAll(r.Body) - if err != nil { - http.Error(w, fmt.Sprintf("failed to read request body: %v", err), http.StatusBadRequest) - return - } - defer r.Body.Close() - - var conversionReview apiextensionsv1.ConversionReview - if err := json.Unmarshal(body, &conversionReview); err != nil { - http.Error(w, fmt.Sprintf("failed to unmarshal request: %v", err), http.StatusBadRequest) - return - } - - response, err := h.Handle(&conversionReview) - if err != nil { - http.Error(w, fmt.Sprintf("conversion failed: %v", err), http.StatusInternalServerError) - return - } - - responseBody, err := json.Marshal(response) - if err != nil { - http.Error(w, fmt.Sprintf("failed to marshal response: %v", err), http.StatusInternalServerError) - return - } - - w.Header().Set("Content-Type", "application/json") - w.WriteHeader(http.StatusOK) - w.Write(responseBody) -} - -func (h *ConversionHandler) Handle(conversionReview *apiextensionsv1.ConversionReview) (*apiextensionsv1.ConversionReview, error) { - if conversionReview.Request == nil { - return nil, fmt.Errorf("conversion request is nil") - } - - response := &apiextensionsv1.ConversionReview{ - TypeMeta: metav1.TypeMeta{ - APIVersion: "apiextensions.k8s.io/v1", - Kind: "ConversionReview", - }, - Response: &apiextensionsv1.ConversionResponse{ - UID: conversionReview.Request.UID, - Result: metav1.Status{Status: "Success"}, - }, - } - - convertedObjects := make([]runtime.RawExtension, 0, len(conversionReview.Request.Objects)) - for _, obj := range conversionReview.Request.Objects { - convertedObj, err := h.convertObject(obj, conversionReview.Request.DesiredAPIVersion) - if err != nil { - response.Response.Result = metav1.Status{ - Status: "Failure", - Message: err.Error(), - } - return response, nil - } - convertedObjects = append(convertedObjects, runtime.RawExtension{Raw: convertedObj}) - } - - response.Response.ConvertedObjects = convertedObjects - return response, nil -} - -func (h *ConversionHandler) convertObject(obj runtime.RawExtension, desiredAPIVersion string) ([]byte, error) { - var typeMeta metav1.TypeMeta - if err := json.Unmarshal(obj.Raw, &typeMeta); err != nil { - return nil, fmt.Errorf("failed to unmarshal TypeMeta: %w", err) - } - - switch typeMeta.APIVersion { - case "virtualization.deckhouse.io/v1alpha2": - if desiredAPIVersion == "virtualization.deckhouse.io/v1alpha3" { - return h.convertV1alpha2ToV1alpha3(obj.Raw) - } - case "virtualization.deckhouse.io/v1alpha3": - if desiredAPIVersion == "virtualization.deckhouse.io/v1alpha2" { - return h.convertV1alpha3ToV1alpha2(obj.Raw) - } - } - - return obj.Raw, nil -} - -func (h *ConversionHandler) convertV1alpha2ToV1alpha3(data []byte) ([]byte, error) { - var v2Class v1alpha2.VirtualMachineClass - if err := json.Unmarshal(data, &v2Class); err != nil { - return nil, fmt.Errorf("failed to unmarshal v1alpha2 VirtualMachineClass: %w", err) - } - - v3Class := v1alpha3.VirtualMachineClass{ - TypeMeta: metav1.TypeMeta{ - APIVersion: "virtualization.deckhouse.io/v1alpha3", - Kind: "VirtualMachineClass", - }, - ObjectMeta: v2Class.ObjectMeta, - Spec: convertSpecV2ToV3(v2Class.Spec), - Status: convertStatusV2ToV3(v2Class.Status), - } - - return json.Marshal(v3Class) -} - -func (h *ConversionHandler) convertV1alpha3ToV1alpha2(data []byte) ([]byte, error) { - var v3Class v1alpha3.VirtualMachineClass - if err := json.Unmarshal(data, &v3Class); err != nil { - return nil, fmt.Errorf("failed to unmarshal v1alpha3 VirtualMachineClass: %w", err) - } - - v2Class := v1alpha2.VirtualMachineClass{ - TypeMeta: metav1.TypeMeta{ - APIVersion: "virtualization.deckhouse.io/v1alpha2", - Kind: "VirtualMachineClass", - }, - ObjectMeta: v3Class.ObjectMeta, - Spec: convertSpecV3ToV2(v3Class.Spec), - Status: convertStatusV3ToV2(v3Class.Status), - } - - return json.Marshal(v2Class) -} - -func convertSpecV2ToV3(v2Spec v1alpha2.VirtualMachineClassSpec) v1alpha3.VirtualMachineClassSpec { - v3Spec := v1alpha3.VirtualMachineClassSpec{ - NodeSelector: v1alpha3.NodeSelector{ - MatchLabels: v2Spec.NodeSelector.MatchLabels, - MatchExpressions: v2Spec.NodeSelector.MatchExpressions, - }, - Tolerations: v2Spec.Tolerations, - CPU: v1alpha3.CPU{ - Type: v1alpha3.CPUType(v2Spec.CPU.Type), - Model: v2Spec.CPU.Model, - Features: v2Spec.CPU.Features, - Discovery: v1alpha3.CpuDiscovery{ - NodeSelector: v2Spec.CPU.Discovery.NodeSelector, - }, - }, - } - - if len(v2Spec.SizingPolicies) > 0 { - v3Spec.SizingPolicies = make([]v1alpha3.SizingPolicy, len(v2Spec.SizingPolicies)) - for i, v2Policy := range v2Spec.SizingPolicies { - v3Policy := v1alpha3.SizingPolicy{ - DedicatedCores: v2Policy.DedicatedCores, - } - - if v2Policy.Memory != nil { - v3Policy.Memory = &v1alpha3.SizingPolicyMemory{ - MemoryMinMax: v1alpha3.MemoryMinMax{ - Min: v2Policy.Memory.Min, - Max: v2Policy.Memory.Max, - }, - Step: v2Policy.Memory.Step, - PerCore: v1alpha3.SizingPolicyMemoryPerCore{ - MemoryMinMax: v1alpha3.MemoryMinMax{ - Min: v2Policy.Memory.PerCore.Min, - Max: v2Policy.Memory.PerCore.Max, - }, - }, - } - } - - if v2Policy.Cores != nil { - v3Policy.Cores = &v1alpha3.SizingPolicyCores{ - Min: v2Policy.Cores.Min, - Max: v2Policy.Cores.Max, - Step: v2Policy.Cores.Step, - } - } - - if len(v2Policy.CoreFractions) > 0 { - v3Policy.CoreFractions = make([]v1alpha3.CoreFractionValue, len(v2Policy.CoreFractions)) - for j, v2Fraction := range v2Policy.CoreFractions { - v3Policy.CoreFractions[j] = v1alpha3.CoreFractionValue(fmt.Sprintf("%d%%", v2Fraction)) - } - } - - v3Spec.SizingPolicies[i] = v3Policy - } - } - - return v3Spec -} - -func convertSpecV3ToV2(v3Spec v1alpha3.VirtualMachineClassSpec) v1alpha2.VirtualMachineClassSpec { - v2Spec := v1alpha2.VirtualMachineClassSpec{ - NodeSelector: v1alpha2.NodeSelector{ - MatchLabels: v3Spec.NodeSelector.MatchLabels, - MatchExpressions: v3Spec.NodeSelector.MatchExpressions, - }, - Tolerations: v3Spec.Tolerations, - CPU: v1alpha2.CPU{ - Type: v1alpha2.CPUType(v3Spec.CPU.Type), - Model: v3Spec.CPU.Model, - Features: v3Spec.CPU.Features, - Discovery: v1alpha2.CpuDiscovery{ - NodeSelector: v3Spec.CPU.Discovery.NodeSelector, - }, - }, - } - - if len(v3Spec.SizingPolicies) > 0 { - v2Spec.SizingPolicies = make([]v1alpha2.SizingPolicy, len(v3Spec.SizingPolicies)) - for i, v3Policy := range v3Spec.SizingPolicies { - v2Policy := v1alpha2.SizingPolicy{ - DedicatedCores: v3Policy.DedicatedCores, - } - - if v3Policy.Memory != nil { - v2Policy.Memory = &v1alpha2.SizingPolicyMemory{ - MemoryMinMax: v1alpha2.MemoryMinMax{ - Min: v3Policy.Memory.Min, - Max: v3Policy.Memory.Max, - }, - Step: v3Policy.Memory.Step, - PerCore: v1alpha2.SizingPolicyMemoryPerCore{ - MemoryMinMax: v1alpha2.MemoryMinMax{ - Min: v3Policy.Memory.PerCore.Min, - Max: v3Policy.Memory.PerCore.Max, - }, - }, - } - } - - if v3Policy.Cores != nil { - v2Policy.Cores = &v1alpha2.SizingPolicyCores{ - Min: v3Policy.Cores.Min, - Max: v3Policy.Cores.Max, - Step: v3Policy.Cores.Step, - } - } - - if len(v3Policy.CoreFractions) > 0 { - v2Policy.CoreFractions = make([]v1alpha2.CoreFractionValue, len(v3Policy.CoreFractions)) - for j, v3Fraction := range v3Policy.CoreFractions { - fractionStr := string(v3Fraction) - if len(fractionStr) > 0 && fractionStr[len(fractionStr)-1] == '%' { - fractionStr = fractionStr[:len(fractionStr)-1] - } - fractionInt, err := strconv.Atoi(fractionStr) - if err != nil { - fractionInt = 100 - } - v2Policy.CoreFractions[j] = v1alpha2.CoreFractionValue(fractionInt) - } - } - - v2Spec.SizingPolicies[i] = v2Policy - } - } - - return v2Spec -} - -func convertStatusV2ToV3(v2Status v1alpha2.VirtualMachineClassStatus) v1alpha3.VirtualMachineClassStatus { - return v1alpha3.VirtualMachineClassStatus{ - Phase: v1alpha3.VirtualMachineClassPhase(v2Status.Phase), - CpuFeatures: v1alpha3.CpuFeatures{ - Enabled: v2Status.CpuFeatures.Enabled, - NotEnabledCommon: v2Status.CpuFeatures.NotEnabledCommon, - }, - AvailableNodes: v2Status.AvailableNodes, - MaxAllocatableResources: v2Status.MaxAllocatableResources, - Conditions: v2Status.Conditions, - ObservedGeneration: v2Status.ObservedGeneration, - } -} - -func convertStatusV3ToV2(v3Status v1alpha3.VirtualMachineClassStatus) v1alpha2.VirtualMachineClassStatus { - return v1alpha2.VirtualMachineClassStatus{ - Phase: v1alpha2.VirtualMachineClassPhase(v3Status.Phase), - CpuFeatures: v1alpha2.CpuFeatures{ - Enabled: v3Status.CpuFeatures.Enabled, - NotEnabledCommon: v3Status.CpuFeatures.NotEnabledCommon, - }, - AvailableNodes: v3Status.AvailableNodes, - MaxAllocatableResources: v3Status.MaxAllocatableResources, - Conditions: v3Status.Conditions, - ObservedGeneration: v3Status.ObservedGeneration, - } -} From 1c477add0e6a0447d46d71085b980c4893928524 Mon Sep 17 00:00:00 2001 From: Daniil Loktev Date: Tue, 21 Oct 2025 17:03:52 +0300 Subject: [PATCH 07/77] wip Signed-off-by: Daniil Loktev --- .../generated/openapi/zz_generated.openapi.go | 596 +++++++++++++++++- 1 file changed, 592 insertions(+), 4 deletions(-) diff --git a/images/virtualization-artifact/pkg/apiserver/api/generated/openapi/zz_generated.openapi.go b/images/virtualization-artifact/pkg/apiserver/api/generated/openapi/zz_generated.openapi.go index 26b96afe44..715ea0bc24 100644 --- a/images/virtualization-artifact/pkg/apiserver/api/generated/openapi/zz_generated.openapi.go +++ b/images/virtualization-artifact/pkg/apiserver/api/generated/openapi/zz_generated.openapi.go @@ -158,6 +158,19 @@ func GetOpenAPIDefinitions(ref common.ReferenceCallback) map[string]common.OpenA "github.com/deckhouse/virtualization/api/core/v1alpha2.VirtualMachineStats": schema_virtualization_api_core_v1alpha2_VirtualMachineStats(ref), "github.com/deckhouse/virtualization/api/core/v1alpha2.VirtualMachineStatus": schema_virtualization_api_core_v1alpha2_VirtualMachineStatus(ref), "github.com/deckhouse/virtualization/api/core/v1alpha2.WeightedVirtualMachineAndPodAffinityTerm": schema_virtualization_api_core_v1alpha2_WeightedVirtualMachineAndPodAffinityTerm(ref), + "github.com/deckhouse/virtualization/api/core/v1alpha3.CPU": schema_virtualization_api_core_v1alpha3_CPU(ref), + "github.com/deckhouse/virtualization/api/core/v1alpha3.CpuDiscovery": schema_virtualization_api_core_v1alpha3_CpuDiscovery(ref), + "github.com/deckhouse/virtualization/api/core/v1alpha3.CpuFeatures": schema_virtualization_api_core_v1alpha3_CpuFeatures(ref), + "github.com/deckhouse/virtualization/api/core/v1alpha3.MemoryMinMax": schema_virtualization_api_core_v1alpha3_MemoryMinMax(ref), + "github.com/deckhouse/virtualization/api/core/v1alpha3.NodeSelector": schema_virtualization_api_core_v1alpha3_NodeSelector(ref), + "github.com/deckhouse/virtualization/api/core/v1alpha3.SizingPolicy": schema_virtualization_api_core_v1alpha3_SizingPolicy(ref), + "github.com/deckhouse/virtualization/api/core/v1alpha3.SizingPolicyCores": schema_virtualization_api_core_v1alpha3_SizingPolicyCores(ref), + "github.com/deckhouse/virtualization/api/core/v1alpha3.SizingPolicyMemory": schema_virtualization_api_core_v1alpha3_SizingPolicyMemory(ref), + "github.com/deckhouse/virtualization/api/core/v1alpha3.SizingPolicyMemoryPerCore": schema_virtualization_api_core_v1alpha3_SizingPolicyMemoryPerCore(ref), + "github.com/deckhouse/virtualization/api/core/v1alpha3.VirtualMachineClass": schema_virtualization_api_core_v1alpha3_VirtualMachineClass(ref), + "github.com/deckhouse/virtualization/api/core/v1alpha3.VirtualMachineClassList": schema_virtualization_api_core_v1alpha3_VirtualMachineClassList(ref), + "github.com/deckhouse/virtualization/api/core/v1alpha3.VirtualMachineClassSpec": schema_virtualization_api_core_v1alpha3_VirtualMachineClassSpec(ref), + "github.com/deckhouse/virtualization/api/core/v1alpha3.VirtualMachineClassStatus": schema_virtualization_api_core_v1alpha3_VirtualMachineClassStatus(ref), "github.com/deckhouse/virtualization/api/subresources/v1alpha2.VirtualMachineAddVolume": schema_virtualization_api_subresources_v1alpha2_VirtualMachineAddVolume(ref), "github.com/deckhouse/virtualization/api/subresources/v1alpha2.VirtualMachineCancelEvacuation": schema_virtualization_api_subresources_v1alpha2_VirtualMachineCancelEvacuation(ref), "github.com/deckhouse/virtualization/api/subresources/v1alpha2.VirtualMachineConsole": schema_virtualization_api_subresources_v1alpha2_VirtualMachineConsole(ref), @@ -1974,14 +1987,14 @@ func schema_virtualization_api_core_v1alpha2_SizingPolicy(ref common.ReferenceCa }, "coreFractions": { SchemaProps: spec.SchemaProps{ - Description: "Allowed values of the `coreFraction` parameter in percentages (e.g., \"5%\", \"10%\", \"25%\", \"50%\", \"100%\").", + Description: "Allowed values of the `coreFraction` parameter.", Type: []string{"array"}, Items: &spec.SchemaOrArray{ Schema: &spec.Schema{ SchemaProps: spec.SchemaProps{ - Default: "", - Type: []string{"string"}, - Format: "", + Default: 0, + Type: []string{"integer"}, + Format: "int32", }, }, }, @@ -6061,6 +6074,581 @@ func schema_virtualization_api_core_v1alpha2_WeightedVirtualMachineAndPodAffinit } } +func schema_virtualization_api_core_v1alpha3_CPU(ref common.ReferenceCallback) common.OpenAPIDefinition { + return common.OpenAPIDefinition{ + Schema: spec.Schema{ + SchemaProps: spec.SchemaProps{ + Description: "CPU defines the requirements for the virtual CPU model.", + Type: []string{"object"}, + Properties: map[string]spec.Schema{ + "type": { + SchemaProps: spec.SchemaProps{ + Default: "", + Type: []string{"string"}, + Format: "", + }, + }, + "model": { + SchemaProps: spec.SchemaProps{ + Description: "CPU model name. For more information about CPU models and topology, refer to the [libvirt docs](https://libvirt.org/formatdomain.html#cpu-model-and-topology).", + Type: []string{"string"}, + Format: "", + }, + }, + "features": { + SchemaProps: spec.SchemaProps{ + Description: "List of CPU instructions (features) required when type=Features. For more information about CPU features, refer to the [libvirt docs](https://libvirt.org/formatdomain.html#cpu-model-and-topology).", + Type: []string{"array"}, + Items: &spec.SchemaOrArray{ + Schema: &spec.Schema{ + SchemaProps: spec.SchemaProps{ + Default: "", + Type: []string{"string"}, + Format: "", + }, + }, + }, + }, + }, + "discovery": { + SchemaProps: spec.SchemaProps{ + Description: "Create a CPU model based on intersecting CPU features for selected nodes.", + Default: map[string]interface{}{}, + Ref: ref("github.com/deckhouse/virtualization/api/core/v1alpha3.CpuDiscovery"), + }, + }, + }, + Required: []string{"type"}, + }, + }, + Dependencies: []string{ + "github.com/deckhouse/virtualization/api/core/v1alpha3.CpuDiscovery"}, + } +} + +func schema_virtualization_api_core_v1alpha3_CpuDiscovery(ref common.ReferenceCallback) common.OpenAPIDefinition { + return common.OpenAPIDefinition{ + Schema: spec.Schema{ + SchemaProps: spec.SchemaProps{ + Type: []string{"object"}, + Properties: map[string]spec.Schema{ + "nodeSelector": { + SchemaProps: spec.SchemaProps{ + Description: "A selection of nodes to be used as the basis for creating a universal CPU model.", + Default: map[string]interface{}{}, + Ref: ref("k8s.io/apimachinery/pkg/apis/meta/v1.LabelSelector"), + }, + }, + }, + }, + }, + Dependencies: []string{ + "k8s.io/apimachinery/pkg/apis/meta/v1.LabelSelector"}, + } +} + +func schema_virtualization_api_core_v1alpha3_CpuFeatures(ref common.ReferenceCallback) common.OpenAPIDefinition { + return common.OpenAPIDefinition{ + Schema: spec.Schema{ + SchemaProps: spec.SchemaProps{ + Description: "CpuFeatures Information on CPU features supported by this model. Shown only for `Features` or `Discovery` types.", + Type: []string{"object"}, + Properties: map[string]spec.Schema{ + "enabled": { + SchemaProps: spec.SchemaProps{ + Description: "List of CPU features for this model.", + Type: []string{"array"}, + Items: &spec.SchemaOrArray{ + Schema: &spec.Schema{ + SchemaProps: spec.SchemaProps{ + Default: "", + Type: []string{"string"}, + Format: "", + }, + }, + }, + }, + }, + "notEnabledCommon": { + SchemaProps: spec.SchemaProps{ + Description: "List of unused processor features additionally available for a given group of nodes.", + Type: []string{"array"}, + Items: &spec.SchemaOrArray{ + Schema: &spec.Schema{ + SchemaProps: spec.SchemaProps{ + Default: "", + Type: []string{"string"}, + Format: "", + }, + }, + }, + }, + }, + }, + }, + }, + } +} + +func schema_virtualization_api_core_v1alpha3_MemoryMinMax(ref common.ReferenceCallback) common.OpenAPIDefinition { + return common.OpenAPIDefinition{ + Schema: spec.Schema{ + SchemaProps: spec.SchemaProps{ + Type: []string{"object"}, + Properties: map[string]spec.Schema{ + "min": { + SchemaProps: spec.SchemaProps{ + Description: "Minimum amount of memory.", + Ref: ref("k8s.io/apimachinery/pkg/api/resource.Quantity"), + }, + }, + "max": { + SchemaProps: spec.SchemaProps{ + Description: "Maximum amount of memory.", + Ref: ref("k8s.io/apimachinery/pkg/api/resource.Quantity"), + }, + }, + }, + }, + }, + Dependencies: []string{ + "k8s.io/apimachinery/pkg/api/resource.Quantity"}, + } +} + +func schema_virtualization_api_core_v1alpha3_NodeSelector(ref common.ReferenceCallback) common.OpenAPIDefinition { + return common.OpenAPIDefinition{ + Schema: spec.Schema{ + SchemaProps: spec.SchemaProps{ + Description: "NodeSelector defines the nodes targeted for VM scheduling.", + Type: []string{"object"}, + Properties: map[string]spec.Schema{ + "matchLabels": { + SchemaProps: spec.SchemaProps{ + Description: "A map of {key,value} pairs. A single {key,value} pair in the matchLabels map is equivalent to an element of matchExpressions whose key field is \"key\", operator is \"In\", and the value array contains only \"value\". The requirements are ANDed.", + Type: []string{"object"}, + AdditionalProperties: &spec.SchemaOrBool{ + Allows: true, + Schema: &spec.Schema{ + SchemaProps: spec.SchemaProps{ + Default: "", + Type: []string{"string"}, + Format: "", + }, + }, + }, + }, + }, + "matchExpressions": { + SchemaProps: spec.SchemaProps{ + Description: "A list of node selector requirements by node's labels.", + Type: []string{"array"}, + Items: &spec.SchemaOrArray{ + Schema: &spec.Schema{ + SchemaProps: spec.SchemaProps{ + Default: map[string]interface{}{}, + Ref: ref("k8s.io/api/core/v1.NodeSelectorRequirement"), + }, + }, + }, + }, + }, + }, + }, + }, + Dependencies: []string{ + "k8s.io/api/core/v1.NodeSelectorRequirement"}, + } +} + +func schema_virtualization_api_core_v1alpha3_SizingPolicy(ref common.ReferenceCallback) common.OpenAPIDefinition { + return common.OpenAPIDefinition{ + Schema: spec.Schema{ + SchemaProps: spec.SchemaProps{ + Description: "SizingPolicy defines a policy for allocating computational resources to VMs. It is represented as a list. The cores.min - cores.max ranges for different elements of the list must not overlap.", + Type: []string{"object"}, + Properties: map[string]spec.Schema{ + "memory": { + SchemaProps: spec.SchemaProps{ + Description: "Memory sizing policy.", + Ref: ref("github.com/deckhouse/virtualization/api/core/v1alpha3.SizingPolicyMemory"), + }, + }, + "coreFractions": { + SchemaProps: spec.SchemaProps{ + Description: "Allowed values of the `coreFraction` parameter in percentages (e.g., \"5%\", \"10%\", \"25%\", \"50%\", \"100%\").", + Type: []string{"array"}, + Items: &spec.SchemaOrArray{ + Schema: &spec.Schema{ + SchemaProps: spec.SchemaProps{ + Default: "", + Type: []string{"string"}, + Format: "", + }, + }, + }, + }, + }, + "dedicatedCores": { + SchemaProps: spec.SchemaProps{ + Description: "Allowed values of the `dedicatedCores` parameter.", + Type: []string{"array"}, + Items: &spec.SchemaOrArray{ + Schema: &spec.Schema{ + SchemaProps: spec.SchemaProps{ + Default: false, + Type: []string{"boolean"}, + Format: "", + }, + }, + }, + }, + }, + "cores": { + SchemaProps: spec.SchemaProps{ + Description: "The policy applies for a specified range of the number of CPU cores.", + Ref: ref("github.com/deckhouse/virtualization/api/core/v1alpha3.SizingPolicyCores"), + }, + }, + }, + }, + }, + Dependencies: []string{ + "github.com/deckhouse/virtualization/api/core/v1alpha3.SizingPolicyCores", "github.com/deckhouse/virtualization/api/core/v1alpha3.SizingPolicyMemory"}, + } +} + +func schema_virtualization_api_core_v1alpha3_SizingPolicyCores(ref common.ReferenceCallback) common.OpenAPIDefinition { + return common.OpenAPIDefinition{ + Schema: spec.Schema{ + SchemaProps: spec.SchemaProps{ + Type: []string{"object"}, + Properties: map[string]spec.Schema{ + "min": { + SchemaProps: spec.SchemaProps{ + Description: "Minimum number of CPU cores.", + Default: 0, + Type: []string{"integer"}, + Format: "int32", + }, + }, + "max": { + SchemaProps: spec.SchemaProps{ + Description: "Maximum number of CPU cores.", + Default: 0, + Type: []string{"integer"}, + Format: "int32", + }, + }, + "step": { + SchemaProps: spec.SchemaProps{ + Description: "Discretization step for the CPU core number. For example, the combination of `min=2`, `max=10`, and `step=4` allows to set the number of virtual machine CPU cores to 2, 6, or 10.", + Type: []string{"integer"}, + Format: "int32", + }, + }, + }, + Required: []string{"min", "max"}, + }, + }, + } +} + +func schema_virtualization_api_core_v1alpha3_SizingPolicyMemory(ref common.ReferenceCallback) common.OpenAPIDefinition { + return common.OpenAPIDefinition{ + Schema: spec.Schema{ + SchemaProps: spec.SchemaProps{ + Type: []string{"object"}, + Properties: map[string]spec.Schema{ + "min": { + SchemaProps: spec.SchemaProps{ + Description: "Minimum amount of memory.", + Ref: ref("k8s.io/apimachinery/pkg/api/resource.Quantity"), + }, + }, + "max": { + SchemaProps: spec.SchemaProps{ + Description: "Maximum amount of memory.", + Ref: ref("k8s.io/apimachinery/pkg/api/resource.Quantity"), + }, + }, + "step": { + SchemaProps: spec.SchemaProps{ + Description: "Memory size discretization step. For example, the combination of `min=2Gi, `max=4Gi` and `step=1Gi` allows to set the virtual machine memory size to 2Gi, 3Gi, or 4Gi.", + Ref: ref("k8s.io/apimachinery/pkg/api/resource.Quantity"), + }, + }, + "perCore": { + SchemaProps: spec.SchemaProps{ + Description: "Amount of memory per CPU core.", + Default: map[string]interface{}{}, + Ref: ref("github.com/deckhouse/virtualization/api/core/v1alpha3.SizingPolicyMemoryPerCore"), + }, + }, + }, + }, + }, + Dependencies: []string{ + "github.com/deckhouse/virtualization/api/core/v1alpha3.SizingPolicyMemoryPerCore", "k8s.io/apimachinery/pkg/api/resource.Quantity"}, + } +} + +func schema_virtualization_api_core_v1alpha3_SizingPolicyMemoryPerCore(ref common.ReferenceCallback) common.OpenAPIDefinition { + return common.OpenAPIDefinition{ + Schema: spec.Schema{ + SchemaProps: spec.SchemaProps{ + Type: []string{"object"}, + Properties: map[string]spec.Schema{ + "min": { + SchemaProps: spec.SchemaProps{ + Description: "Minimum amount of memory.", + Ref: ref("k8s.io/apimachinery/pkg/api/resource.Quantity"), + }, + }, + "max": { + SchemaProps: spec.SchemaProps{ + Description: "Maximum amount of memory.", + Ref: ref("k8s.io/apimachinery/pkg/api/resource.Quantity"), + }, + }, + }, + }, + }, + Dependencies: []string{ + "k8s.io/apimachinery/pkg/api/resource.Quantity"}, + } +} + +func schema_virtualization_api_core_v1alpha3_VirtualMachineClass(ref common.ReferenceCallback) common.OpenAPIDefinition { + return common.OpenAPIDefinition{ + Schema: spec.Schema{ + SchemaProps: spec.SchemaProps{ + Description: "VirtualMachineClass resource describes CPU requirements, node placement, and sizing policy for VM resources. A resource cannot be deleted as long as it is used in one of the VMs.", + Type: []string{"object"}, + Properties: map[string]spec.Schema{ + "kind": { + SchemaProps: spec.SchemaProps{ + Description: "Kind is a string value representing the REST resource this object represents. Servers may infer this from the endpoint the client submits requests to. Cannot be updated. In CamelCase. More info: https://git.k8s.io/community/contributors/devel/sig-architecture/api-conventions.md#types-kinds", + Type: []string{"string"}, + Format: "", + }, + }, + "apiVersion": { + SchemaProps: spec.SchemaProps{ + Description: "APIVersion defines the versioned schema of this representation of an object. Servers should convert recognized schemas to the latest internal value, and may reject unrecognized values. More info: https://git.k8s.io/community/contributors/devel/sig-architecture/api-conventions.md#resources", + Type: []string{"string"}, + Format: "", + }, + }, + "metadata": { + SchemaProps: spec.SchemaProps{ + Default: map[string]interface{}{}, + Ref: ref("k8s.io/apimachinery/pkg/apis/meta/v1.ObjectMeta"), + }, + }, + "spec": { + SchemaProps: spec.SchemaProps{ + Default: map[string]interface{}{}, + Ref: ref("github.com/deckhouse/virtualization/api/core/v1alpha3.VirtualMachineClassSpec"), + }, + }, + "status": { + SchemaProps: spec.SchemaProps{ + Default: map[string]interface{}{}, + Ref: ref("github.com/deckhouse/virtualization/api/core/v1alpha3.VirtualMachineClassStatus"), + }, + }, + }, + Required: []string{"spec"}, + }, + }, + Dependencies: []string{ + "github.com/deckhouse/virtualization/api/core/v1alpha3.VirtualMachineClassSpec", "github.com/deckhouse/virtualization/api/core/v1alpha3.VirtualMachineClassStatus", "k8s.io/apimachinery/pkg/apis/meta/v1.ObjectMeta"}, + } +} + +func schema_virtualization_api_core_v1alpha3_VirtualMachineClassList(ref common.ReferenceCallback) common.OpenAPIDefinition { + return common.OpenAPIDefinition{ + Schema: spec.Schema{ + SchemaProps: spec.SchemaProps{ + Description: "VirtualMachineClassList contains a list of VirtualMachineClasses.", + Type: []string{"object"}, + Properties: map[string]spec.Schema{ + "kind": { + SchemaProps: spec.SchemaProps{ + Description: "Kind is a string value representing the REST resource this object represents. Servers may infer this from the endpoint the client submits requests to. Cannot be updated. In CamelCase. More info: https://git.k8s.io/community/contributors/devel/sig-architecture/api-conventions.md#types-kinds", + Type: []string{"string"}, + Format: "", + }, + }, + "apiVersion": { + SchemaProps: spec.SchemaProps{ + Description: "APIVersion defines the versioned schema of this representation of an object. Servers should convert recognized schemas to the latest internal value, and may reject unrecognized values. More info: https://git.k8s.io/community/contributors/devel/sig-architecture/api-conventions.md#resources", + Type: []string{"string"}, + Format: "", + }, + }, + "metadata": { + SchemaProps: spec.SchemaProps{ + Default: map[string]interface{}{}, + Ref: ref("k8s.io/apimachinery/pkg/apis/meta/v1.ListMeta"), + }, + }, + "items": { + SchemaProps: spec.SchemaProps{ + Description: "Items provides a list of VirtualMachineClasses.", + Type: []string{"array"}, + Items: &spec.SchemaOrArray{ + Schema: &spec.Schema{ + SchemaProps: spec.SchemaProps{ + Default: map[string]interface{}{}, + Ref: ref("github.com/deckhouse/virtualization/api/core/v1alpha3.VirtualMachineClass"), + }, + }, + }, + }, + }, + }, + Required: []string{"metadata", "items"}, + }, + }, + Dependencies: []string{ + "github.com/deckhouse/virtualization/api/core/v1alpha3.VirtualMachineClass", "k8s.io/apimachinery/pkg/apis/meta/v1.ListMeta"}, + } +} + +func schema_virtualization_api_core_v1alpha3_VirtualMachineClassSpec(ref common.ReferenceCallback) common.OpenAPIDefinition { + return common.OpenAPIDefinition{ + Schema: spec.Schema{ + SchemaProps: spec.SchemaProps{ + Type: []string{"object"}, + Properties: map[string]spec.Schema{ + "nodeSelector": { + SchemaProps: spec.SchemaProps{ + Default: map[string]interface{}{}, + Ref: ref("github.com/deckhouse/virtualization/api/core/v1alpha3.NodeSelector"), + }, + }, + "tolerations": { + SchemaProps: spec.SchemaProps{ + Description: "Tolerations are the same as `spec.tolerations` for [pods](https://kubernetes.io/docs/concepts/scheduling-eviction/taint-and-toleration/). These tolerations will be merged with the tolerations specified in the VirtualMachine resource. VirtualMachine tolerations have a higher priority.", + Type: []string{"array"}, + Items: &spec.SchemaOrArray{ + Schema: &spec.Schema{ + SchemaProps: spec.SchemaProps{ + Default: map[string]interface{}{}, + Ref: ref("k8s.io/api/core/v1.Toleration"), + }, + }, + }, + }, + }, + "cpu": { + SchemaProps: spec.SchemaProps{ + Default: map[string]interface{}{}, + Ref: ref("github.com/deckhouse/virtualization/api/core/v1alpha3.CPU"), + }, + }, + "sizingPolicies": { + SchemaProps: spec.SchemaProps{ + Type: []string{"array"}, + Items: &spec.SchemaOrArray{ + Schema: &spec.Schema{ + SchemaProps: spec.SchemaProps{ + Default: map[string]interface{}{}, + Ref: ref("github.com/deckhouse/virtualization/api/core/v1alpha3.SizingPolicy"), + }, + }, + }, + }, + }, + }, + Required: []string{"cpu"}, + }, + }, + Dependencies: []string{ + "github.com/deckhouse/virtualization/api/core/v1alpha3.CPU", "github.com/deckhouse/virtualization/api/core/v1alpha3.NodeSelector", "github.com/deckhouse/virtualization/api/core/v1alpha3.SizingPolicy", "k8s.io/api/core/v1.Toleration"}, + } +} + +func schema_virtualization_api_core_v1alpha3_VirtualMachineClassStatus(ref common.ReferenceCallback) common.OpenAPIDefinition { + return common.OpenAPIDefinition{ + Schema: spec.Schema{ + SchemaProps: spec.SchemaProps{ + Type: []string{"object"}, + Properties: map[string]spec.Schema{ + "phase": { + SchemaProps: spec.SchemaProps{ + Default: "", + Type: []string{"string"}, + Format: "", + }, + }, + "cpuFeatures": { + SchemaProps: spec.SchemaProps{ + Default: map[string]interface{}{}, + Ref: ref("github.com/deckhouse/virtualization/api/core/v1alpha3.CpuFeatures"), + }, + }, + "availableNodes": { + SchemaProps: spec.SchemaProps{ + Description: "List of nodes that support this CPU model. It is not displayed for the following types: `Host`, `HostPassthrough`.", + Type: []string{"array"}, + Items: &spec.SchemaOrArray{ + Schema: &spec.Schema{ + SchemaProps: spec.SchemaProps{ + Default: "", + Type: []string{"string"}, + Format: "", + }, + }, + }, + }, + }, + "maxAllocatableResources": { + SchemaProps: spec.SchemaProps{ + Description: "Maximum amount of free CPU and memory resources observed among all available nodes.", + Type: []string{"object"}, + AdditionalProperties: &spec.SchemaOrBool{ + Allows: true, + Schema: &spec.Schema{ + SchemaProps: spec.SchemaProps{ + Ref: ref("k8s.io/apimachinery/pkg/api/resource.Quantity"), + }, + }, + }, + }, + }, + "conditions": { + SchemaProps: spec.SchemaProps{ + Description: "The latest detailed observations of the VirtualMachineClass resource.", + Type: []string{"array"}, + Items: &spec.SchemaOrArray{ + Schema: &spec.Schema{ + SchemaProps: spec.SchemaProps{ + Default: map[string]interface{}{}, + Ref: ref("k8s.io/apimachinery/pkg/apis/meta/v1.Condition"), + }, + }, + }, + }, + }, + "observedGeneration": { + SchemaProps: spec.SchemaProps{ + Description: "Resource generation last processed by the controller.", + Type: []string{"integer"}, + Format: "int64", + }, + }, + }, + Required: []string{"phase"}, + }, + }, + Dependencies: []string{ + "github.com/deckhouse/virtualization/api/core/v1alpha3.CpuFeatures", "k8s.io/apimachinery/pkg/api/resource.Quantity", "k8s.io/apimachinery/pkg/apis/meta/v1.Condition"}, + } +} + func schema_virtualization_api_subresources_v1alpha2_VirtualMachineAddVolume(ref common.ReferenceCallback) common.OpenAPIDefinition { return common.OpenAPIDefinition{ Schema: spec.Schema{ From 774de408bab31e038cc27fa39503f4e099b7f911 Mon Sep 17 00:00:00 2001 From: Daniil Loktev Date: Tue, 21 Oct 2025 17:23:54 +0300 Subject: [PATCH 08/77] wip Signed-off-by: Daniil Loktev --- api/core/v1alpha2/virtual_machine_class.go | 1 - .../virtual_machine_class_conversion.go | 19 +++++++++++++++++++ 2 files changed, 19 insertions(+), 1 deletion(-) create mode 100644 api/core/v1alpha3/virtual_machine_class_conversion.go diff --git a/api/core/v1alpha2/virtual_machine_class.go b/api/core/v1alpha2/virtual_machine_class.go index 08134017c5..9eeaf5d254 100644 --- a/api/core/v1alpha2/virtual_machine_class.go +++ b/api/core/v1alpha2/virtual_machine_class.go @@ -42,7 +42,6 @@ const ( // +genclient // +genclient:nonNamespaced // +k8s:deepcopy-gen:interfaces=k8s.io/apimachinery/pkg/runtime.Object -// +kubebuilder:conversion:spoke type VirtualMachineClass struct { metav1.TypeMeta `json:",inline"` metav1.ObjectMeta `json:"metadata,omitempty"` diff --git a/api/core/v1alpha3/virtual_machine_class_conversion.go b/api/core/v1alpha3/virtual_machine_class_conversion.go new file mode 100644 index 0000000000..a2a53a4938 --- /dev/null +++ b/api/core/v1alpha3/virtual_machine_class_conversion.go @@ -0,0 +1,19 @@ +/* +Copyright 2025 Flant JSC + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. +*/ + +package v1alpha3 + +func (*VirtualMachineClass) Hub() {} From 8e155505eb2b5862ed9f3edf2ff305d89144f718 Mon Sep 17 00:00:00 2001 From: Daniil Loktev <70405899+loktev-d@users.noreply.github.com> Date: Wed, 22 Oct 2025 13:19:07 +0300 Subject: [PATCH 09/77] Apply suggestion from @z9r5 Co-authored-by: Artem Kladov <6360800+z9r5@users.noreply.github.com> Signed-off-by: Daniil Loktev <70405899+loktev-d@users.noreply.github.com> Signed-off-by: Daniil Loktev --- crds/doc-ru-virtualmachineclasses.yaml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/crds/doc-ru-virtualmachineclasses.yaml b/crds/doc-ru-virtualmachineclasses.yaml index c0abe39ad8..e745c346be 100644 --- a/crds/doc-ru-virtualmachineclasses.yaml +++ b/crds/doc-ru-virtualmachineclasses.yaml @@ -133,7 +133,7 @@ spec: properties: coreFractions: description: | - Допустимые значения параметра `coreFraction` в процентах (например, "5%", "10%", "25%", "50%", "100%"). + Максимальная доля использования ядра CPU в процентах (например, "5%", "10%", "25%", "50%", "100%"). cores: description: | Политика применяется для заданного диапазона числа ядер CPU. From 5458ff6bee4ce3a8931e7568dee508824f80480a Mon Sep 17 00:00:00 2001 From: Daniil Loktev Date: Wed, 22 Oct 2025 16:39:30 +0300 Subject: [PATCH 10/77] Revert "Apply suggestion from @z9r5" This reverts commit ca8b8403292907c72f433b8004820faea4cb9f32. Signed-off-by: Daniil Loktev --- crds/doc-ru-virtualmachineclasses.yaml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/crds/doc-ru-virtualmachineclasses.yaml b/crds/doc-ru-virtualmachineclasses.yaml index e745c346be..c0abe39ad8 100644 --- a/crds/doc-ru-virtualmachineclasses.yaml +++ b/crds/doc-ru-virtualmachineclasses.yaml @@ -133,7 +133,7 @@ spec: properties: coreFractions: description: | - Максимальная доля использования ядра CPU в процентах (например, "5%", "10%", "25%", "50%", "100%"). + Допустимые значения параметра `coreFraction` в процентах (например, "5%", "10%", "25%", "50%", "100%"). cores: description: | Политика применяется для заданного диапазона числа ядер CPU. From b71d209626266c251971e5265a00a45a34485c2a Mon Sep 17 00:00:00 2001 From: Daniil Loktev Date: Wed, 22 Oct 2025 17:05:16 +0300 Subject: [PATCH 11/77] wip Signed-off-by: Daniil Loktev --- .../pkg/controller/service/size_policy_service.go | 14 ++++---------- 1 file changed, 4 insertions(+), 10 deletions(-) diff --git a/images/virtualization-artifact/pkg/controller/service/size_policy_service.go b/images/virtualization-artifact/pkg/controller/service/size_policy_service.go index 50bd28763e..df49f9c727 100644 --- a/images/virtualization-artifact/pkg/controller/service/size_policy_service.go +++ b/images/virtualization-artifact/pkg/controller/service/size_policy_service.go @@ -77,8 +77,8 @@ func validateCoreFraction(vm *v1alpha2.VirtualMachine, sp *v1alpha2.SizingPolicy return } - vmFractionStr := strings.ReplaceAll(vm.Spec.CPU.CoreFraction, "%", "") - vmFraction, err := strconv.Atoi(vmFractionStr) + fractionStr := strings.ReplaceAll(vm.Spec.CPU.CoreFraction, "%", "") + fraction, err := strconv.Atoi(fractionStr) if err != nil { errorsArray = append(errorsArray, fmt.Errorf("unable to parse CPU core fraction: %w", err)) return @@ -86,19 +86,13 @@ func validateCoreFraction(vm *v1alpha2.VirtualMachine, sp *v1alpha2.SizingPolicy hasFractionValueInPolicy := false for _, spFraction := range sp.CoreFractions { - policyFractionStr := strings.ReplaceAll(string(spFraction), "%", "") - policyFraction, err := strconv.Atoi(policyFractionStr) - if err != nil { - continue - } - if vmFraction == policyFraction { + if fraction == int(spFraction) { hasFractionValueInPolicy = true - break } } if !hasFractionValueInPolicy { - errorsArray = append(errorsArray, fmt.Errorf("VM core fraction value %d%% is not within the allowed values", vmFraction)) + errorsArray = append(errorsArray, fmt.Errorf("VM core fraction value %d is not within the allowed values", fraction)) } return From ccd15e2bee7a68512b555f50ed0f16ece62b5273 Mon Sep 17 00:00:00 2001 From: Daniil Loktev Date: Wed, 22 Oct 2025 17:46:14 +0300 Subject: [PATCH 12/77] wip Signed-off-by: Daniil Loktev --- .../v1alpha2/virtual_machine_class_conversion.go | 12 ++++++++---- 1 file changed, 8 insertions(+), 4 deletions(-) diff --git a/api/core/v1alpha2/virtual_machine_class_conversion.go b/api/core/v1alpha2/virtual_machine_class_conversion.go index 61e8a8f828..3728ff3fe1 100644 --- a/api/core/v1alpha2/virtual_machine_class_conversion.go +++ b/api/core/v1alpha2/virtual_machine_class_conversion.go @@ -41,7 +41,11 @@ func (dst *VirtualMachineClass) ConvertFrom(srcRaw conversion.Hub) error { src := srcRaw.(*v1alpha3.VirtualMachineClass) dst.ObjectMeta = src.ObjectMeta - dst.Spec = convertSpecV3ToV2(src.Spec) + convertedSpec, err := convertSpecV3ToV2(src.Spec) + if err != nil { + return err + } + dst.Spec = convertedSpec dst.Status = convertStatusV3ToV2(src.Status) return nil @@ -109,7 +113,7 @@ func convertSpecV2ToV3(v2Spec VirtualMachineClassSpec) v1alpha3.VirtualMachineCl return v3Spec } -func convertSpecV3ToV2(v3Spec v1alpha3.VirtualMachineClassSpec) VirtualMachineClassSpec { +func convertSpecV3ToV2(v3Spec v1alpha3.VirtualMachineClassSpec) (VirtualMachineClassSpec, error) { v2Spec := VirtualMachineClassSpec{ NodeSelector: NodeSelector{ MatchLabels: v3Spec.NodeSelector.MatchLabels, @@ -166,7 +170,7 @@ func convertSpecV3ToV2(v3Spec v1alpha3.VirtualMachineClassSpec) VirtualMachineCl } fractionInt, err := strconv.Atoi(fractionStr) if err != nil { - fractionInt = 100 + return VirtualMachineClassSpec{}, fmt.Errorf("failed to parse core fraction: %w", err) } v2Policy.CoreFractions[j] = CoreFractionValue(fractionInt) } @@ -176,7 +180,7 @@ func convertSpecV3ToV2(v3Spec v1alpha3.VirtualMachineClassSpec) VirtualMachineCl } } - return v2Spec + return v2Spec, nil } func convertStatusV2ToV3(v2Status VirtualMachineClassStatus) v1alpha3.VirtualMachineClassStatus { From fa19dfffde419e4eed3fe2ec038fb2d49fc58069 Mon Sep 17 00:00:00 2001 From: Daniil Loktev Date: Wed, 22 Oct 2025 19:02:24 +0300 Subject: [PATCH 13/77] wip Signed-off-by: Daniil Loktev --- api/core/v1alpha2/virtual_machine_class.go | 1 + .../virtual_machine_class_conversion.go | 195 +----------------- api/core/v1alpha3/virtual_machine_class.go | 2 - .../virtual_machine_class_conversion.go | 195 +++++++++++++++++- crds/virtualmachineclasses.yaml | 4 +- 5 files changed, 198 insertions(+), 199 deletions(-) diff --git a/api/core/v1alpha2/virtual_machine_class.go b/api/core/v1alpha2/virtual_machine_class.go index 9eeaf5d254..22d960c420 100644 --- a/api/core/v1alpha2/virtual_machine_class.go +++ b/api/core/v1alpha2/virtual_machine_class.go @@ -36,6 +36,7 @@ const ( // +kubebuilder:metadata:labels={heritage=deckhouse,module=virtualization,backup.deckhouse.io/cluster-config=true} // +kubebuilder:subresource:status // +kubebuilder:resource:categories={virtualization-cluster},scope=Cluster,shortName={vmc,vmclass},singular=virtualmachineclass +// +kubebuilder:storageversion // +kubebuilder:printcolumn:name="Phase",type="string",JSONPath=".status.phase",description="VirtualMachineClass phase." // +kubebuilder:printcolumn:name="IsDefault",type="string",JSONPath=".metadata.annotations.virtualmachineclass\\.virtualization\\.deckhouse\\.io\\/is-default-class",description="Default class for virtual machines without specified class." // +kubebuilder:printcolumn:name="Age",type="date",JSONPath=".metadata.creationTimestamp",description="Time of resource creation." diff --git a/api/core/v1alpha2/virtual_machine_class_conversion.go b/api/core/v1alpha2/virtual_machine_class_conversion.go index 3728ff3fe1..0a88b03f14 100644 --- a/api/core/v1alpha2/virtual_machine_class_conversion.go +++ b/api/core/v1alpha2/virtual_machine_class_conversion.go @@ -16,197 +16,4 @@ limitations under the License. package v1alpha2 -import ( - "fmt" - "strconv" - - "sigs.k8s.io/controller-runtime/pkg/conversion" - - "github.com/deckhouse/virtualization/api/core/v1alpha3" -) - -var _ conversion.Convertible = &VirtualMachineClass{} - -func (src *VirtualMachineClass) ConvertTo(dstRaw conversion.Hub) error { - dst := dstRaw.(*v1alpha3.VirtualMachineClass) - - dst.ObjectMeta = src.ObjectMeta - dst.Spec = convertSpecV2ToV3(src.Spec) - dst.Status = convertStatusV2ToV3(src.Status) - - return nil -} - -func (dst *VirtualMachineClass) ConvertFrom(srcRaw conversion.Hub) error { - src := srcRaw.(*v1alpha3.VirtualMachineClass) - - dst.ObjectMeta = src.ObjectMeta - convertedSpec, err := convertSpecV3ToV2(src.Spec) - if err != nil { - return err - } - dst.Spec = convertedSpec - dst.Status = convertStatusV3ToV2(src.Status) - - return nil -} - -func convertSpecV2ToV3(v2Spec VirtualMachineClassSpec) v1alpha3.VirtualMachineClassSpec { - v3Spec := v1alpha3.VirtualMachineClassSpec{ - NodeSelector: v1alpha3.NodeSelector{ - MatchLabels: v2Spec.NodeSelector.MatchLabels, - MatchExpressions: v2Spec.NodeSelector.MatchExpressions, - }, - Tolerations: v2Spec.Tolerations, - CPU: v1alpha3.CPU{ - Type: v1alpha3.CPUType(v2Spec.CPU.Type), - Model: v2Spec.CPU.Model, - Features: v2Spec.CPU.Features, - Discovery: v1alpha3.CpuDiscovery{ - NodeSelector: v2Spec.CPU.Discovery.NodeSelector, - }, - }, - } - - if len(v2Spec.SizingPolicies) > 0 { - v3Spec.SizingPolicies = make([]v1alpha3.SizingPolicy, len(v2Spec.SizingPolicies)) - for i, v2Policy := range v2Spec.SizingPolicies { - v3Policy := v1alpha3.SizingPolicy{ - DedicatedCores: v2Policy.DedicatedCores, - } - - if v2Policy.Memory != nil { - v3Policy.Memory = &v1alpha3.SizingPolicyMemory{ - MemoryMinMax: v1alpha3.MemoryMinMax{ - Min: v2Policy.Memory.Min, - Max: v2Policy.Memory.Max, - }, - Step: v2Policy.Memory.Step, - PerCore: v1alpha3.SizingPolicyMemoryPerCore{ - MemoryMinMax: v1alpha3.MemoryMinMax{ - Min: v2Policy.Memory.PerCore.Min, - Max: v2Policy.Memory.PerCore.Max, - }, - }, - } - } - - if v2Policy.Cores != nil { - v3Policy.Cores = &v1alpha3.SizingPolicyCores{ - Min: v2Policy.Cores.Min, - Max: v2Policy.Cores.Max, - Step: v2Policy.Cores.Step, - } - } - - if len(v2Policy.CoreFractions) > 0 { - v3Policy.CoreFractions = make([]v1alpha3.CoreFractionValue, len(v2Policy.CoreFractions)) - for j, v2Fraction := range v2Policy.CoreFractions { - v3Policy.CoreFractions[j] = v1alpha3.CoreFractionValue(fmt.Sprintf("%d%%", v2Fraction)) - } - } - - v3Spec.SizingPolicies[i] = v3Policy - } - } - - return v3Spec -} - -func convertSpecV3ToV2(v3Spec v1alpha3.VirtualMachineClassSpec) (VirtualMachineClassSpec, error) { - v2Spec := VirtualMachineClassSpec{ - NodeSelector: NodeSelector{ - MatchLabels: v3Spec.NodeSelector.MatchLabels, - MatchExpressions: v3Spec.NodeSelector.MatchExpressions, - }, - Tolerations: v3Spec.Tolerations, - CPU: CPU{ - Type: CPUType(v3Spec.CPU.Type), - Model: v3Spec.CPU.Model, - Features: v3Spec.CPU.Features, - Discovery: CpuDiscovery{ - NodeSelector: v3Spec.CPU.Discovery.NodeSelector, - }, - }, - } - - if len(v3Spec.SizingPolicies) > 0 { - v2Spec.SizingPolicies = make([]SizingPolicy, len(v3Spec.SizingPolicies)) - for i, v3Policy := range v3Spec.SizingPolicies { - v2Policy := SizingPolicy{ - DedicatedCores: v3Policy.DedicatedCores, - } - - if v3Policy.Memory != nil { - v2Policy.Memory = &SizingPolicyMemory{ - MemoryMinMax: MemoryMinMax{ - Min: v3Policy.Memory.Min, - Max: v3Policy.Memory.Max, - }, - Step: v3Policy.Memory.Step, - PerCore: SizingPolicyMemoryPerCore{ - MemoryMinMax: MemoryMinMax{ - Min: v3Policy.Memory.PerCore.Min, - Max: v3Policy.Memory.PerCore.Max, - }, - }, - } - } - - if v3Policy.Cores != nil { - v2Policy.Cores = &SizingPolicyCores{ - Min: v3Policy.Cores.Min, - Max: v3Policy.Cores.Max, - Step: v3Policy.Cores.Step, - } - } - - if len(v3Policy.CoreFractions) > 0 { - v2Policy.CoreFractions = make([]CoreFractionValue, len(v3Policy.CoreFractions)) - for j, v3Fraction := range v3Policy.CoreFractions { - fractionStr := string(v3Fraction) - if len(fractionStr) > 0 && fractionStr[len(fractionStr)-1] == '%' { - fractionStr = fractionStr[:len(fractionStr)-1] - } - fractionInt, err := strconv.Atoi(fractionStr) - if err != nil { - return VirtualMachineClassSpec{}, fmt.Errorf("failed to parse core fraction: %w", err) - } - v2Policy.CoreFractions[j] = CoreFractionValue(fractionInt) - } - } - - v2Spec.SizingPolicies[i] = v2Policy - } - } - - return v2Spec, nil -} - -func convertStatusV2ToV3(v2Status VirtualMachineClassStatus) v1alpha3.VirtualMachineClassStatus { - return v1alpha3.VirtualMachineClassStatus{ - Phase: v1alpha3.VirtualMachineClassPhase(v2Status.Phase), - CpuFeatures: v1alpha3.CpuFeatures{ - Enabled: v2Status.CpuFeatures.Enabled, - NotEnabledCommon: v2Status.CpuFeatures.NotEnabledCommon, - }, - AvailableNodes: v2Status.AvailableNodes, - MaxAllocatableResources: v2Status.MaxAllocatableResources, - Conditions: v2Status.Conditions, - ObservedGeneration: v2Status.ObservedGeneration, - } -} - -func convertStatusV3ToV2(v3Status v1alpha3.VirtualMachineClassStatus) VirtualMachineClassStatus { - return VirtualMachineClassStatus{ - Phase: VirtualMachineClassPhase(v3Status.Phase), - CpuFeatures: CpuFeatures{ - Enabled: v3Status.CpuFeatures.Enabled, - NotEnabledCommon: v3Status.CpuFeatures.NotEnabledCommon, - }, - AvailableNodes: v3Status.AvailableNodes, - MaxAllocatableResources: v3Status.MaxAllocatableResources, - Conditions: v3Status.Conditions, - ObservedGeneration: v3Status.ObservedGeneration, - } -} +func (*VirtualMachineClass) Hub() {} diff --git a/api/core/v1alpha3/virtual_machine_class.go b/api/core/v1alpha3/virtual_machine_class.go index 807a661826..15f7651da8 100644 --- a/api/core/v1alpha3/virtual_machine_class.go +++ b/api/core/v1alpha3/virtual_machine_class.go @@ -36,14 +36,12 @@ const ( // +kubebuilder:metadata:labels={heritage=deckhouse,module=virtualization,backup.deckhouse.io/cluster-config=true} // +kubebuilder:subresource:status // +kubebuilder:resource:categories={virtualization-cluster},scope=Cluster,shortName={vmc,vmclass},singular=virtualmachineclass -// +kubebuilder:storageversion // +kubebuilder:printcolumn:name="Phase",type="string",JSONPath=".status.phase",description="VirtualMachineClass phase." // +kubebuilder:printcolumn:name="IsDefault",type="string",JSONPath=".metadata.annotations.virtualmachineclass\\.virtualization\\.deckhouse\\.io\\/is-default-class",description="Default class for virtual machines without specified class." // +kubebuilder:printcolumn:name="Age",type="date",JSONPath=".metadata.creationTimestamp",description="Time of resource creation." // +genclient // +genclient:nonNamespaced // +k8s:deepcopy-gen:interfaces=k8s.io/apimachinery/pkg/runtime.Object -// +kubebuilder:conversion:hub type VirtualMachineClass struct { metav1.TypeMeta `json:",inline"` metav1.ObjectMeta `json:"metadata,omitempty"` diff --git a/api/core/v1alpha3/virtual_machine_class_conversion.go b/api/core/v1alpha3/virtual_machine_class_conversion.go index a2a53a4938..6a6d82f744 100644 --- a/api/core/v1alpha3/virtual_machine_class_conversion.go +++ b/api/core/v1alpha3/virtual_machine_class_conversion.go @@ -16,4 +16,197 @@ limitations under the License. package v1alpha3 -func (*VirtualMachineClass) Hub() {} +import ( + "fmt" + "strconv" + + "sigs.k8s.io/controller-runtime/pkg/conversion" + + "github.com/deckhouse/virtualization/api/core/v1alpha2" +) + +var _ conversion.Convertible = &VirtualMachineClass{} + +func (src *VirtualMachineClass) ConvertTo(dstRaw conversion.Hub) error { + dst := dstRaw.(*v1alpha2.VirtualMachineClass) + + dst.ObjectMeta = src.ObjectMeta + convertedSpec, err := convertSpecV3ToV2(src.Spec) + if err != nil { + return err + } + dst.Spec = convertedSpec + dst.Status = convertStatusV3ToV2(src.Status) + + return nil +} + +func (dst *VirtualMachineClass) ConvertFrom(srcRaw conversion.Hub) error { + src := srcRaw.(*v1alpha2.VirtualMachineClass) + + dst.ObjectMeta = src.ObjectMeta + dst.Spec = convertSpecV2ToV3(src.Spec) + dst.Status = convertStatusV2ToV3(src.Status) + + return nil +} + +func convertSpecV3ToV2(v3Spec VirtualMachineClassSpec) (v1alpha2.VirtualMachineClassSpec, error) { + v2Spec := v1alpha2.VirtualMachineClassSpec{ + NodeSelector: v1alpha2.NodeSelector{ + MatchLabels: v3Spec.NodeSelector.MatchLabels, + MatchExpressions: v3Spec.NodeSelector.MatchExpressions, + }, + Tolerations: v3Spec.Tolerations, + CPU: v1alpha2.CPU{ + Type: v1alpha2.CPUType(v3Spec.CPU.Type), + Model: v3Spec.CPU.Model, + Features: v3Spec.CPU.Features, + Discovery: v1alpha2.CpuDiscovery{ + NodeSelector: v3Spec.CPU.Discovery.NodeSelector, + }, + }, + } + + if len(v3Spec.SizingPolicies) > 0 { + v2Spec.SizingPolicies = make([]v1alpha2.SizingPolicy, len(v3Spec.SizingPolicies)) + for i, v3Policy := range v3Spec.SizingPolicies { + v2Policy := v1alpha2.SizingPolicy{ + DedicatedCores: v3Policy.DedicatedCores, + } + + if v3Policy.Memory != nil { + v2Policy.Memory = &v1alpha2.SizingPolicyMemory{ + MemoryMinMax: v1alpha2.MemoryMinMax{ + Min: v3Policy.Memory.Min, + Max: v3Policy.Memory.Max, + }, + Step: v3Policy.Memory.Step, + PerCore: v1alpha2.SizingPolicyMemoryPerCore{ + MemoryMinMax: v1alpha2.MemoryMinMax{ + Min: v3Policy.Memory.PerCore.Min, + Max: v3Policy.Memory.PerCore.Max, + }, + }, + } + } + + if v3Policy.Cores != nil { + v2Policy.Cores = &v1alpha2.SizingPolicyCores{ + Min: v3Policy.Cores.Min, + Max: v3Policy.Cores.Max, + Step: v3Policy.Cores.Step, + } + } + + if len(v3Policy.CoreFractions) > 0 { + v2Policy.CoreFractions = make([]v1alpha2.CoreFractionValue, len(v3Policy.CoreFractions)) + for j, v3Fraction := range v3Policy.CoreFractions { + fractionStr := string(v3Fraction) + if len(fractionStr) > 0 && fractionStr[len(fractionStr)-1] == '%' { + fractionStr = fractionStr[:len(fractionStr)-1] + } + fractionInt, err := strconv.Atoi(fractionStr) + if err != nil { + return v1alpha2.VirtualMachineClassSpec{}, fmt.Errorf("failed to parse core fraction: %w", err) + } + v2Policy.CoreFractions[j] = v1alpha2.CoreFractionValue(fractionInt) + } + } + + v2Spec.SizingPolicies[i] = v2Policy + } + } + + return v2Spec, nil +} + +func convertSpecV2ToV3(v2Spec v1alpha2.VirtualMachineClassSpec) VirtualMachineClassSpec { + v3Spec := VirtualMachineClassSpec{ + NodeSelector: NodeSelector{ + MatchLabels: v2Spec.NodeSelector.MatchLabels, + MatchExpressions: v2Spec.NodeSelector.MatchExpressions, + }, + Tolerations: v2Spec.Tolerations, + CPU: CPU{ + Type: CPUType(v2Spec.CPU.Type), + Model: v2Spec.CPU.Model, + Features: v2Spec.CPU.Features, + Discovery: CpuDiscovery{ + NodeSelector: v2Spec.CPU.Discovery.NodeSelector, + }, + }, + } + + if len(v2Spec.SizingPolicies) > 0 { + v3Spec.SizingPolicies = make([]SizingPolicy, len(v2Spec.SizingPolicies)) + for i, v2Policy := range v2Spec.SizingPolicies { + v3Policy := SizingPolicy{ + DedicatedCores: v2Policy.DedicatedCores, + } + + if v2Policy.Memory != nil { + v3Policy.Memory = &SizingPolicyMemory{ + MemoryMinMax: MemoryMinMax{ + Min: v2Policy.Memory.Min, + Max: v2Policy.Memory.Max, + }, + Step: v2Policy.Memory.Step, + PerCore: SizingPolicyMemoryPerCore{ + MemoryMinMax: MemoryMinMax{ + Min: v2Policy.Memory.PerCore.Min, + Max: v2Policy.Memory.PerCore.Max, + }, + }, + } + } + + if v2Policy.Cores != nil { + v3Policy.Cores = &SizingPolicyCores{ + Min: v2Policy.Cores.Min, + Max: v2Policy.Cores.Max, + Step: v2Policy.Cores.Step, + } + } + + if len(v2Policy.CoreFractions) > 0 { + v3Policy.CoreFractions = make([]CoreFractionValue, len(v2Policy.CoreFractions)) + for j, v2Fraction := range v2Policy.CoreFractions { + v3Policy.CoreFractions[j] = CoreFractionValue(fmt.Sprintf("%d%%", v2Fraction)) + } + } + + v3Spec.SizingPolicies[i] = v3Policy + } + } + + return v3Spec +} + +func convertStatusV3ToV2(v3Status VirtualMachineClassStatus) v1alpha2.VirtualMachineClassStatus { + return v1alpha2.VirtualMachineClassStatus{ + Phase: v1alpha2.VirtualMachineClassPhase(v3Status.Phase), + CpuFeatures: v1alpha2.CpuFeatures{ + Enabled: v3Status.CpuFeatures.Enabled, + NotEnabledCommon: v3Status.CpuFeatures.NotEnabledCommon, + }, + AvailableNodes: v3Status.AvailableNodes, + MaxAllocatableResources: v3Status.MaxAllocatableResources, + Conditions: v3Status.Conditions, + ObservedGeneration: v3Status.ObservedGeneration, + } +} + +func convertStatusV2ToV3(v2Status v1alpha2.VirtualMachineClassStatus) VirtualMachineClassStatus { + return VirtualMachineClassStatus{ + Phase: VirtualMachineClassPhase(v2Status.Phase), + CpuFeatures: CpuFeatures{ + Enabled: v2Status.CpuFeatures.Enabled, + NotEnabledCommon: v2Status.CpuFeatures.NotEnabledCommon, + }, + AvailableNodes: v2Status.AvailableNodes, + MaxAllocatableResources: v2Status.MaxAllocatableResources, + Conditions: v2Status.Conditions, + ObservedGeneration: v2Status.ObservedGeneration, + } +} diff --git a/crds/virtualmachineclasses.yaml b/crds/virtualmachineclasses.yaml index ac9234b694..f2a04d095e 100644 --- a/crds/virtualmachineclasses.yaml +++ b/crds/virtualmachineclasses.yaml @@ -471,7 +471,7 @@ spec: - spec type: object served: true - storage: false + storage: true subresources: status: {} - additionalPrinterColumns: @@ -922,7 +922,7 @@ spec: - spec type: object served: true - storage: true + storage: false subresources: status: {} conversion: From b07e3c5de345c48170fd64ca1666b16bf9aa680d Mon Sep 17 00:00:00 2001 From: Daniil Loktev Date: Wed, 22 Oct 2025 19:21:29 +0300 Subject: [PATCH 14/77] wip Signed-off-by: Daniil Loktev --- templates/virtualization-controller/validation-webhook.yaml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/templates/virtualization-controller/validation-webhook.yaml b/templates/virtualization-controller/validation-webhook.yaml index 056baea2c2..d7be7efe44 100644 --- a/templates/virtualization-controller/validation-webhook.yaml +++ b/templates/virtualization-controller/validation-webhook.yaml @@ -212,7 +212,7 @@ webhooks: - name: "vmclass.virtualization-controller.validate.d8-virtualization" rules: - apiGroups: ["virtualization.deckhouse.io"] - apiVersions: ["v1alpha2"] + apiVersions: ["v1alpha2", "v1alpha3"] operations: ["CREATE", "UPDATE"] resources: ["virtualmachineclasses"] scope: "Cluster" From 7dcb2b64f111d8ea7f8bf84fed5f1f13ba347944 Mon Sep 17 00:00:00 2001 From: Daniil Loktev Date: Wed, 22 Oct 2025 19:57:59 +0300 Subject: [PATCH 15/77] wip Signed-off-by: Daniil Loktev --- .../pkg/controller/vmclass/vmclass_webhook.go | 40 +++++++++++++++---- 1 file changed, 33 insertions(+), 7 deletions(-) diff --git a/images/virtualization-artifact/pkg/controller/vmclass/vmclass_webhook.go b/images/virtualization-artifact/pkg/controller/vmclass/vmclass_webhook.go index 5f0fbe6a7e..eea4f0da7c 100644 --- a/images/virtualization-artifact/pkg/controller/vmclass/vmclass_webhook.go +++ b/images/virtualization-artifact/pkg/controller/vmclass/vmclass_webhook.go @@ -26,6 +26,7 @@ import ( "github.com/deckhouse/virtualization-controller/pkg/controller/vmclass/internal/validators" "github.com/deckhouse/virtualization-controller/pkg/eventrecord" "github.com/deckhouse/virtualization/api/core/v1alpha2" + "github.com/deckhouse/virtualization/api/core/v1alpha3" ) type VirtualMachineClassValidator interface { @@ -50,9 +51,18 @@ func NewValidator(client client.Client, log *log.Logger, recorder eventrecord.Ev } func (v *Validator) ValidateCreate(ctx context.Context, obj runtime.Object) (admission.Warnings, error) { - vmclass, ok := obj.(*v1alpha2.VirtualMachineClass) - if !ok { - return nil, fmt.Errorf("expected a new VirtualMachine but got a %T", obj) + var vmclass *v1alpha2.VirtualMachineClass + + switch obj := obj.(type) { + case *v1alpha2.VirtualMachineClass: + vmclass = obj + case *v1alpha3.VirtualMachineClass: + vmclass = &v1alpha2.VirtualMachineClass{} + if err := obj.ConvertTo(vmclass); err != nil { + return nil, fmt.Errorf("failed to convert v1alpha3 to v1alpha2: %w", err) + } + default: + return nil, fmt.Errorf("expected a VirtualMachineClass but got a %T", obj) } var warnings admission.Warnings @@ -69,13 +79,29 @@ func (v *Validator) ValidateCreate(ctx context.Context, obj runtime.Object) (adm } func (v *Validator) ValidateUpdate(ctx context.Context, oldObj, newObj runtime.Object) (admission.Warnings, error) { - oldVMClass, ok := oldObj.(*v1alpha2.VirtualMachineClass) - if !ok { + var oldVMClass, newVMClass *v1alpha2.VirtualMachineClass + + switch oldObj := oldObj.(type) { + case *v1alpha2.VirtualMachineClass: + oldVMClass = oldObj + case *v1alpha3.VirtualMachineClass: + oldVMClass = &v1alpha2.VirtualMachineClass{} + if err := oldObj.ConvertTo(oldVMClass); err != nil { + return nil, fmt.Errorf("failed to convert old v1alpha3 to v1alpha2: %w", err) + } + default: return nil, fmt.Errorf("expected an old VirtualMachineClass but got a %T", oldObj) } - newVMClass, ok := newObj.(*v1alpha2.VirtualMachineClass) - if !ok { + switch newObj := newObj.(type) { + case *v1alpha2.VirtualMachineClass: + newVMClass = newObj + case *v1alpha3.VirtualMachineClass: + newVMClass = &v1alpha2.VirtualMachineClass{} + if err := newObj.ConvertTo(newVMClass); err != nil { + return nil, fmt.Errorf("failed to convert new v1alpha3 to v1alpha2: %w", err) + } + default: return nil, fmt.Errorf("expected a new VirtualMachineClass but got a %T", newObj) } From eff1fa140be419faec3a66b7d12d47fc82c04855 Mon Sep 17 00:00:00 2001 From: Daniil Loktev Date: Wed, 22 Oct 2025 20:07:45 +0300 Subject: [PATCH 16/77] wip Signed-off-by: Daniil Loktev --- api/core/v1alpha3/virtual_machine_class_conversion.go | 11 +++++++---- 1 file changed, 7 insertions(+), 4 deletions(-) diff --git a/api/core/v1alpha3/virtual_machine_class_conversion.go b/api/core/v1alpha3/virtual_machine_class_conversion.go index 6a6d82f744..15a1336cc7 100644 --- a/api/core/v1alpha3/virtual_machine_class_conversion.go +++ b/api/core/v1alpha3/virtual_machine_class_conversion.go @@ -62,7 +62,7 @@ func convertSpecV3ToV2(v3Spec VirtualMachineClassSpec) (v1alpha2.VirtualMachineC Type: v1alpha2.CPUType(v3Spec.CPU.Type), Model: v3Spec.CPU.Model, Features: v3Spec.CPU.Features, - Discovery: v1alpha2.CpuDiscovery{ + Discovery: &v1alpha2.CpuDiscovery{ NodeSelector: v3Spec.CPU.Discovery.NodeSelector, }, }, @@ -132,12 +132,15 @@ func convertSpecV2ToV3(v2Spec v1alpha2.VirtualMachineClassSpec) VirtualMachineCl Type: CPUType(v2Spec.CPU.Type), Model: v2Spec.CPU.Model, Features: v2Spec.CPU.Features, - Discovery: CpuDiscovery{ - NodeSelector: v2Spec.CPU.Discovery.NodeSelector, - }, }, } + if v2Spec.CPU.Discovery != nil { + v3Spec.CPU.Discovery = CpuDiscovery{ + NodeSelector: v2Spec.CPU.Discovery.NodeSelector, + } + } + if len(v2Spec.SizingPolicies) > 0 { v3Spec.SizingPolicies = make([]SizingPolicy, len(v2Spec.SizingPolicies)) for i, v2Policy := range v2Spec.SizingPolicies { From 35bdc0d1a6187f9ca11da6975ee178299c15edf1 Mon Sep 17 00:00:00 2001 From: Daniil Loktev Date: Wed, 22 Oct 2025 20:21:35 +0300 Subject: [PATCH 17/77] wip Signed-off-by: Daniil Loktev --- .../pkg/controller/vmclass/vmclass_controller.go | 12 +++++++++++- 1 file changed, 11 insertions(+), 1 deletion(-) diff --git a/images/virtualization-artifact/pkg/controller/vmclass/vmclass_controller.go b/images/virtualization-artifact/pkg/controller/vmclass/vmclass_controller.go index a7c3eaa915..96033a289c 100644 --- a/images/virtualization-artifact/pkg/controller/vmclass/vmclass_controller.go +++ b/images/virtualization-artifact/pkg/controller/vmclass/vmclass_controller.go @@ -31,6 +31,7 @@ import ( "github.com/deckhouse/virtualization-controller/pkg/eventrecord" "github.com/deckhouse/virtualization-controller/pkg/logger" "github.com/deckhouse/virtualization/api/core/v1alpha2" + "github.com/deckhouse/virtualization/api/core/v1alpha3" ) const ( @@ -67,9 +68,18 @@ func NewController( return nil, err } + validator := NewValidator(mgr.GetClient(), log, recorder, vmClassService) + if err = builder.WebhookManagedBy(mgr). For(&v1alpha2.VirtualMachineClass{}). - WithValidator(NewValidator(mgr.GetClient(), log, recorder, vmClassService)). + WithValidator(validator). + Complete(); err != nil { + return nil, err + } + + if err = builder.WebhookManagedBy(mgr). + For(&v1alpha3.VirtualMachineClass{}). + WithValidator(validator). Complete(); err != nil { return nil, err } From 8293305183e036c4da5137ee4f475d8a870e4bf2 Mon Sep 17 00:00:00 2001 From: Daniil Loktev Date: Wed, 22 Oct 2025 20:47:29 +0300 Subject: [PATCH 18/77] wip Signed-off-by: Daniil Loktev --- .../validation-webhook.yaml | 21 +++++++++++++++++-- 1 file changed, 19 insertions(+), 2 deletions(-) diff --git a/templates/virtualization-controller/validation-webhook.yaml b/templates/virtualization-controller/validation-webhook.yaml index d7be7efe44..671b3496cb 100644 --- a/templates/virtualization-controller/validation-webhook.yaml +++ b/templates/virtualization-controller/validation-webhook.yaml @@ -209,10 +209,10 @@ webhooks: {{ .Values.virtualization.internal.controller.cert.ca | b64enc }} admissionReviewVersions: ["v1"] sideEffects: None - - name: "vmclass.virtualization-controller.validate.d8-virtualization" + - name: "vmclass-v1alpha2.virtualization-controller.validate.d8-virtualization" rules: - apiGroups: ["virtualization.deckhouse.io"] - apiVersions: ["v1alpha2", "v1alpha3"] + apiVersions: ["v1alpha2"] operations: ["CREATE", "UPDATE"] resources: ["virtualmachineclasses"] scope: "Cluster" @@ -226,6 +226,23 @@ webhooks: {{ .Values.virtualization.internal.controller.cert.ca | b64enc }} admissionReviewVersions: ["v1"] sideEffects: None + - name: "vmclass-v1alpha3.virtualization-controller.validate.d8-virtualization" + rules: + - apiGroups: ["virtualization.deckhouse.io"] + apiVersions: ["v1alpha3"] + operations: ["CREATE", "UPDATE"] + resources: ["virtualmachineclasses"] + scope: "Cluster" + clientConfig: + service: + namespace: d8-{{ .Chart.Name }} + name: virtualization-controller + path: /validate-virtualization-deckhouse-io-v1alpha3-virtualmachineclass + port: 443 + caBundle: | + {{ .Values.virtualization.internal.controller.cert.ca | b64enc }} + admissionReviewVersions: ["v1"] + sideEffects: None - name: "moduleconfig.virtualization-controller.validate.d8-virtualization" rules: - apiGroups: ["deckhouse.io"] From 918fad1188fdc53ba6e73863eb69e319eb99ee7e Mon Sep 17 00:00:00 2001 From: Daniil Loktev Date: Wed, 22 Oct 2025 22:22:13 +0300 Subject: [PATCH 19/77] wip Signed-off-by: Daniil Loktev --- .../virtualization-module-hooks/register.go | 1 + .../inject-crd-conversion-cabundle/hook.go | 109 ++++++++++++++++++ 2 files changed, 110 insertions(+) create mode 100644 images/hooks/pkg/hooks/inject-crd-conversion-cabundle/hook.go diff --git a/images/hooks/cmd/virtualization-module-hooks/register.go b/images/hooks/cmd/virtualization-module-hooks/register.go index bc0e1dc2a4..5c24ec4ba7 100644 --- a/images/hooks/cmd/virtualization-module-hooks/register.go +++ b/images/hooks/cmd/virtualization-module-hooks/register.go @@ -22,6 +22,7 @@ import ( _ "hooks/pkg/hooks/discovery-workload-nodes" _ "hooks/pkg/hooks/drop-openshift-labels" _ "hooks/pkg/hooks/generate-secret-for-dvcr" + _ "hooks/pkg/hooks/inject-crd-conversion-cabundle" _ "hooks/pkg/hooks/migrate-delete-renamed-validation-admission-policy" _ "hooks/pkg/hooks/migrate-virthandler-kvm-node-labels" _ "hooks/pkg/hooks/prevent-default-vmclasses-deletion" diff --git a/images/hooks/pkg/hooks/inject-crd-conversion-cabundle/hook.go b/images/hooks/pkg/hooks/inject-crd-conversion-cabundle/hook.go new file mode 100644 index 0000000000..f48b9cb99d --- /dev/null +++ b/images/hooks/pkg/hooks/inject-crd-conversion-cabundle/hook.go @@ -0,0 +1,109 @@ +/* +Copyright 2025 Flant JSC +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. +*/ + +package inject_crd_conversion_cabundle + +import ( + "context" + "encoding/base64" + "fmt" + + "hooks/pkg/settings" + + "github.com/deckhouse/module-sdk/pkg" + "github.com/deckhouse/module-sdk/pkg/registry" + "k8s.io/apimachinery/pkg/apis/meta/v1/unstructured" + "k8s.io/utils/ptr" +) + +const ( + crdSnapshotName = "virtualmachineclasses-crd" + crdName = "virtualmachineclasses.virtualization.deckhouse.io" + crdJQFilter = `{ + "name": .metadata.name, + "hasCABundle": (.spec.conversion.webhook.clientConfig.caBundle != null) + }` +) + +type CRDSnapshot struct { + Name string `json:"name"` + HasCABundle bool `json:"hasCABundle"` +} + +var _ = registry.RegisterFunc(config, reconcile) + +var config = &pkg.HookConfig{ + OnAfterHelm: &pkg.OrderedConfig{Order: 10}, + Kubernetes: []pkg.KubernetesConfig{ + { + Name: crdSnapshotName, + APIVersion: "apiextensions.k8s.io/v1", + Kind: "CustomResourceDefinition", + NameSelector: &pkg.NameSelector{ + MatchNames: []string{crdName}, + }, + JqFilter: crdJQFilter, + ExecuteHookOnSynchronization: ptr.Bool(false), + ExecuteHookOnEvents: ptr.Bool(false), + }, + }, + Queue: fmt.Sprintf("modules/%s", settings.ModuleName), +} + +func reconcile(ctx context.Context, input *pkg.HookInput) error { + input.Logger.Info("Start inject CRD conversion webhook caBundle hook") + + caCert, exists := input.Values.GetOk("virtualization.internal.controller.cert.ca") + if !exists { + input.Logger.Info("CA certificate not found in values, skipping caBundle injection") + return nil + } + + caString, ok := caCert.(string) + if !ok { + return fmt.Errorf("CA certificate is not a string") + } + + caBundle := base64.StdEncoding.EncodeToString([]byte(caString)) + + snapshots := input.Snapshots.Get(crdSnapshotName) + if len(snapshots) == 0 { + input.Logger.Info("CRD %s not found, skipping caBundle injection", crdName) + return nil + } + + var crdSnap CRDSnapshot + if err := snapshots[0].UnmarshalTo(&crdSnap); err != nil { + return fmt.Errorf("failed to unmarshal CRD snapshot: %w", err) + } + + if crdSnap.HasCABundle { + input.Logger.Info("CRD %s already has caBundle, skipping injection", crdName) + return nil + } + + patch := []interface{}{ + map[string]interface{}{ + "op": "add", + "path": "/spec/conversion/webhook/clientConfig/caBundle", + "value": caBundle, + }, + } + + input.PatchCollector.JSONPatch(patch, "apiextensions.k8s.io/v1", "CustomResourceDefinition", "", crdName) + input.Logger.Info("Successfully injected caBundle into CRD %s", crdName) + + return nil +} From da2a9449f6ff59a70a03bb5db24c873323a8f59e Mon Sep 17 00:00:00 2001 From: Daniil Loktev Date: Wed, 22 Oct 2025 22:36:29 +0300 Subject: [PATCH 20/77] wip Signed-off-by: Daniil Loktev --- .../hooks/inject-crd-conversion-cabundle/hook.go | 16 ++++++---------- 1 file changed, 6 insertions(+), 10 deletions(-) diff --git a/images/hooks/pkg/hooks/inject-crd-conversion-cabundle/hook.go b/images/hooks/pkg/hooks/inject-crd-conversion-cabundle/hook.go index f48b9cb99d..531f9bb73d 100644 --- a/images/hooks/pkg/hooks/inject-crd-conversion-cabundle/hook.go +++ b/images/hooks/pkg/hooks/inject-crd-conversion-cabundle/hook.go @@ -24,8 +24,6 @@ import ( "github.com/deckhouse/module-sdk/pkg" "github.com/deckhouse/module-sdk/pkg/registry" - "k8s.io/apimachinery/pkg/apis/meta/v1/unstructured" - "k8s.io/utils/ptr" ) const ( @@ -54,9 +52,7 @@ var config = &pkg.HookConfig{ NameSelector: &pkg.NameSelector{ MatchNames: []string{crdName}, }, - JqFilter: crdJQFilter, - ExecuteHookOnSynchronization: ptr.Bool(false), - ExecuteHookOnEvents: ptr.Bool(false), + JqFilter: crdJQFilter, }, }, Queue: fmt.Sprintf("modules/%s", settings.ModuleName), @@ -65,15 +61,15 @@ var config = &pkg.HookConfig{ func reconcile(ctx context.Context, input *pkg.HookInput) error { input.Logger.Info("Start inject CRD conversion webhook caBundle hook") - caCert, exists := input.Values.GetOk("virtualization.internal.controller.cert.ca") - if !exists { + caCert := input.Values.Get("virtualization.internal.controller.cert.ca") + if !caCert.Exists() { input.Logger.Info("CA certificate not found in values, skipping caBundle injection") return nil } - caString, ok := caCert.(string) - if !ok { - return fmt.Errorf("CA certificate is not a string") + caString := caCert.String() + if caString == "" { + return fmt.Errorf("CA certificate is empty") } caBundle := base64.StdEncoding.EncodeToString([]byte(caString)) From 56cff28c6192b788e02c6e64fb059c6fd8fe7c39 Mon Sep 17 00:00:00 2001 From: Daniil Loktev Date: Wed, 22 Oct 2025 22:49:40 +0300 Subject: [PATCH 21/77] wip Signed-off-by: Daniil Loktev --- images/hooks/pkg/hooks/inject-crd-conversion-cabundle/hook.go | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/images/hooks/pkg/hooks/inject-crd-conversion-cabundle/hook.go b/images/hooks/pkg/hooks/inject-crd-conversion-cabundle/hook.go index 531f9bb73d..c50d5dc844 100644 --- a/images/hooks/pkg/hooks/inject-crd-conversion-cabundle/hook.go +++ b/images/hooks/pkg/hooks/inject-crd-conversion-cabundle/hook.go @@ -61,7 +61,7 @@ var config = &pkg.HookConfig{ func reconcile(ctx context.Context, input *pkg.HookInput) error { input.Logger.Info("Start inject CRD conversion webhook caBundle hook") - caCert := input.Values.Get("virtualization.internal.controller.cert.ca") + caCert := input.Values.Get("virtualization.internal.rootCA.crt") if !caCert.Exists() { input.Logger.Info("CA certificate not found in values, skipping caBundle injection") return nil From 2e16faa766ea5630527d424443efebfffabfa266 Mon Sep 17 00:00:00 2001 From: Daniil Loktev Date: Thu, 23 Oct 2025 10:24:22 +0300 Subject: [PATCH 22/77] wip Signed-off-by: Daniil Loktev --- .../hooks/pkg/hooks/inject-crd-conversion-cabundle/hook.go | 7 ++----- 1 file changed, 2 insertions(+), 5 deletions(-) diff --git a/images/hooks/pkg/hooks/inject-crd-conversion-cabundle/hook.go b/images/hooks/pkg/hooks/inject-crd-conversion-cabundle/hook.go index c50d5dc844..abbbb30c2b 100644 --- a/images/hooks/pkg/hooks/inject-crd-conversion-cabundle/hook.go +++ b/images/hooks/pkg/hooks/inject-crd-conversion-cabundle/hook.go @@ -17,7 +17,6 @@ package inject_crd_conversion_cabundle import ( "context" - "encoding/base64" "fmt" "hooks/pkg/settings" @@ -67,13 +66,11 @@ func reconcile(ctx context.Context, input *pkg.HookInput) error { return nil } - caString := caCert.String() - if caString == "" { + caBundle := caCert.String() + if caBundle == "" { return fmt.Errorf("CA certificate is empty") } - caBundle := base64.StdEncoding.EncodeToString([]byte(caString)) - snapshots := input.Snapshots.Get(crdSnapshotName) if len(snapshots) == 0 { input.Logger.Info("CRD %s not found, skipping caBundle injection", crdName) From 94715687048b447a8ad1b239fe674198e836d366 Mon Sep 17 00:00:00 2001 From: Daniil Loktev Date: Thu, 23 Oct 2025 10:46:08 +0300 Subject: [PATCH 23/77] fix conversion path Signed-off-by: Daniil Loktev --- api/scripts/update-codegen.sh | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/api/scripts/update-codegen.sh b/api/scripts/update-codegen.sh index 93a9e9814e..f6a3ced4bb 100755 --- a/api/scripts/update-codegen.sh +++ b/api/scripts/update-codegen.sh @@ -96,7 +96,7 @@ function generate::crds { "service": { "name": "virtualization-controller", "namespace": "d8-virtualization", - "path": "/convert/virtualmachineclasses", + "path": "/convert", "port": 443 } }, From d75022e9d96cd9b5b83b3562fe59fc841d12a028 Mon Sep 17 00:00:00 2001 From: Daniil Loktev Date: Thu, 23 Oct 2025 10:46:22 +0300 Subject: [PATCH 24/77] fix conversion path Signed-off-by: Daniil Loktev --- crds/virtualmachineclasses.yaml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/crds/virtualmachineclasses.yaml b/crds/virtualmachineclasses.yaml index f2a04d095e..4ae5b6135f 100644 --- a/crds/virtualmachineclasses.yaml +++ b/crds/virtualmachineclasses.yaml @@ -932,7 +932,7 @@ spec: service: name: virtualization-controller namespace: d8-virtualization - path: /convert/virtualmachineclasses + path: /convert port: 443 conversionReviewVersions: - v1 From 2c32efd35c05b72113287ab46123a86763bc8d3a Mon Sep 17 00:00:00 2001 From: Daniil Loktev Date: Thu, 23 Oct 2025 13:31:06 +0300 Subject: [PATCH 25/77] wip Signed-off-by: Daniil Loktev --- .../pkg/controller/service/size_policy_service_test.go | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/images/virtualization-artifact/pkg/controller/service/size_policy_service_test.go b/images/virtualization-artifact/pkg/controller/service/size_policy_service_test.go index bd460cc3ce..171a04b7e7 100644 --- a/images/virtualization-artifact/pkg/controller/service/size_policy_service_test.go +++ b/images/virtualization-artifact/pkg/controller/service/size_policy_service_test.go @@ -272,7 +272,7 @@ var _ = Describe("SizePolicyService", func() { SizingPolicies: []v1alpha2.SizingPolicy{ { Cores: &v1alpha2.SizingPolicyCores{Min: 1, Max: 4}, - CoreFractions: []v1alpha2.CoreFractionValue{"10%", "25%", "50%", "100%"}, + CoreFractions: []v1alpha2.CoreFractionValue{10, 25, 50, 100}, }, }, }, @@ -302,7 +302,7 @@ var _ = Describe("SizePolicyService", func() { SizingPolicies: []v1alpha2.SizingPolicy{ { Cores: &v1alpha2.SizingPolicyCores{Min: 1, Max: 4}, - CoreFractions: []v1alpha2.CoreFractionValue{"10%", "25%", "50%", "100%"}, + CoreFractions: []v1alpha2.CoreFractionValue{10, 25, 50, 100}, }, }, }, From a83c386455252d0b736d330d05a8c6accc715840 Mon Sep 17 00:00:00 2001 From: Daniil Loktev Date: Thu, 23 Oct 2025 13:35:02 +0300 Subject: [PATCH 26/77] wip Signed-off-by: Daniil Loktev --- tests/e2e/testdata/affinity-toleration/vmc.yaml | 2 +- tests/e2e/testdata/complex-test/vmc.yaml | 2 +- tests/e2e/testdata/sizing-policy/vmc.yaml | 2 +- 3 files changed, 3 insertions(+), 3 deletions(-) diff --git a/tests/e2e/testdata/affinity-toleration/vmc.yaml b/tests/e2e/testdata/affinity-toleration/vmc.yaml index d5a4a38b29..68c1540fca 100644 --- a/tests/e2e/testdata/affinity-toleration/vmc.yaml +++ b/tests/e2e/testdata/affinity-toleration/vmc.yaml @@ -1,4 +1,4 @@ -apiVersion: virtualization.deckhouse.io/v1alpha2 +apiVersion: virtualization.deckhouse.io/v1alpha3 kind: VirtualMachineClass metadata: name: affinity-toleration-discovery diff --git a/tests/e2e/testdata/complex-test/vmc.yaml b/tests/e2e/testdata/complex-test/vmc.yaml index 7ef9aaf78b..672336653a 100644 --- a/tests/e2e/testdata/complex-test/vmc.yaml +++ b/tests/e2e/testdata/complex-test/vmc.yaml @@ -1,4 +1,4 @@ -apiVersion: virtualization.deckhouse.io/v1alpha2 +apiVersion: virtualization.deckhouse.io/v1alpha3 kind: VirtualMachineClass metadata: name: complex-discovery diff --git a/tests/e2e/testdata/sizing-policy/vmc.yaml b/tests/e2e/testdata/sizing-policy/vmc.yaml index 8795b57033..50c098e2f8 100644 --- a/tests/e2e/testdata/sizing-policy/vmc.yaml +++ b/tests/e2e/testdata/sizing-policy/vmc.yaml @@ -1,4 +1,4 @@ -apiVersion: virtualization.deckhouse.io/v1alpha2 +apiVersion: virtualization.deckhouse.io/v1alpha3 kind: VirtualMachineClass metadata: name: sizing-policy-discovery From 3f5f0250155a53a575ba92fec4c8392cbc7c50b5 Mon Sep 17 00:00:00 2001 From: Daniil Loktev Date: Thu, 23 Oct 2025 13:51:36 +0300 Subject: [PATCH 27/77] fix cli mod Signed-off-by: Daniil Loktev --- src/cli/go.mod | 1 + src/cli/go.sum | 11 ++++++----- 2 files changed, 7 insertions(+), 5 deletions(-) diff --git a/src/cli/go.mod b/src/cli/go.mod index 4d728824a2..bd767e6226 100644 --- a/src/cli/go.mod +++ b/src/cli/go.mod @@ -69,6 +69,7 @@ require ( kubevirt.io/api v1.3.1 // indirect kubevirt.io/containerized-data-importer-api v1.57.0-alpha1 // 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 sigs.k8s.io/randfill v1.0.0 // indirect sigs.k8s.io/structured-merge-diff/v4 v4.6.0 // indirect diff --git a/src/cli/go.sum b/src/cli/go.sum index a6acb020c5..7c203f2035 100644 --- a/src/cli/go.sum +++ b/src/cli/go.sum @@ -191,8 +191,8 @@ github.com/onsi/ginkgo/v2 v2.13.0/go.mod h1:TE309ZR8s5FsKKpuB1YAQYBzCaAfUgatB/xl github.com/onsi/ginkgo/v2 v2.17.1/go.mod h1:llBI3WDLL9Z6taip6f33H76YcWtJv+7R3HigUjbIBOs= github.com/onsi/ginkgo/v2 v2.17.2/go.mod h1:nP2DPOQoNsQmsVyv5rDA8JkXQoCs6goXIvr/PRJ1eCc= github.com/onsi/ginkgo/v2 v2.19.0/go.mod h1:rlwLi9PilAFJ8jCg9UE1QP6VBpd6/xj3SRC0d6TU0To= -github.com/onsi/ginkgo/v2 v2.21.0 h1:7rg/4f3rB88pb5obDgNZrNHrQ4e6WpjonchcpuBRnZM= -github.com/onsi/ginkgo/v2 v2.21.0/go.mod h1:7Du3c42kxCUegi0IImZ1wUQzMBVecgIHjR1C+NkhLQo= +github.com/onsi/ginkgo/v2 v2.22.0 h1:Yed107/8DjTr0lKCNt7Dn8yQ6ybuDRQoMGrNFKzMfHg= +github.com/onsi/ginkgo/v2 v2.22.0/go.mod h1:7Du3c42kxCUegi0IImZ1wUQzMBVecgIHjR1C+NkhLQo= github.com/onsi/gomega v1.7.1/go.mod h1:XdKZgCCFLUoM/7CFJVPcG8C1xQ1AJ0vpAezJrB7JYyY= github.com/onsi/gomega v1.10.1/go.mod h1:iN09h71vgCQne3DLsj+A5owkum+a2tYe+TOCB1ybHNo= github.com/onsi/gomega v1.17.0/go.mod h1:HnhC7FXeEQY45zxNK3PPoIUhzk/80Xly9PcubAlGdZY= @@ -214,8 +214,8 @@ github.com/onsi/gomega v1.27.10/go.mod h1:RsS8tutOdbdgzbPtzzATp12yT7kM5I5aElG3ev github.com/onsi/gomega v1.30.0/go.mod h1:9sxs+SwGrKI0+PWe4Fxa9tFQQBG5xSsSbMXOI8PPpoQ= github.com/onsi/gomega v1.33.0/go.mod h1:+925n5YtiFsLzzafLUHzVMBpvvRAzrydIBiSIxjX3wY= github.com/onsi/gomega v1.33.1/go.mod h1:U4R44UsT+9eLIaYRB2a5qajjtQYn0hauxvRm16AVYg0= -github.com/onsi/gomega v1.35.1 h1:Cwbd75ZBPxFSuZ6T+rN/WCb/gOc6YgFBXLlZLhC7Ds4= -github.com/onsi/gomega v1.35.1/go.mod h1:PvZbdDc8J6XJEpDK4HCuRBm8a6Fzp9/DmhC9C7yFlog= +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= @@ -593,6 +593,8 @@ kubevirt.io/containerized-data-importer-api v1.57.0-alpha1 h1:IWo12+ei3jltSN5jQN kubevirt.io/containerized-data-importer-api v1.57.0-alpha1/go.mod h1:Y/8ETgHS1GjO89bl682DPtQOYEU/1ctPFBz6Sjxm4DM= 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= +sigs.k8s.io/controller-runtime v0.21.0/go.mod h1:OSg14+F65eWqIu4DceX7k/+QRAbTTvxeQSNSOQpukWM= sigs.k8s.io/json v0.0.0-20211020170558-c049b76a60c6/go.mod h1:p4QtZmO4uMYipTQNzagwnNoseA6OxSUutVw05NhYDRs= sigs.k8s.io/json v0.0.0-20221116044647-bc3834ca7abd/go.mod h1:B8JuhiUyNFVKdsE8h686QcCxMaH6HrOAZj4vswFpcB0= sigs.k8s.io/json v0.0.0-20241010143419-9aa6b5e7a4b3 h1:/Rv+M11QRah1itp8VhT6HoVx1Ray9eB4DBr+K+/sCJ8= @@ -603,7 +605,6 @@ sigs.k8s.io/randfill v1.0.0/go.mod h1:XeLlZ/jmk4i1HRopwe7/aU3H5n1zNUcX6TM94b3QxO sigs.k8s.io/structured-merge-diff/v4 v4.2.1/go.mod h1:j/nl6xW8vLS49O8YvXW1ocPhZawJtm+Yrr7PPRQ0Vg4= sigs.k8s.io/structured-merge-diff/v4 v4.6.0 h1:IUA9nvMmnKWcj5jl84xn+T5MnlZKThmUW1TdblaLVAc= sigs.k8s.io/structured-merge-diff/v4 v4.6.0/go.mod h1:dDy58f92j70zLsuZVuUX5Wp9vtxXpaZnkPGWeqDfCps= -sigs.k8s.io/structured-merge-diff/v6 v6.2.0/go.mod h1:M3W8sfWvn2HhQDIbGWj3S099YozAsymCo/wrT5ohRUE= sigs.k8s.io/yaml v1.2.0/go.mod h1:yfXDCHCao9+ENCvLSE62v9VSji2MKu5jeNfTrofGhJc= sigs.k8s.io/yaml v1.3.0/go.mod h1:GeOyir5tyXNByN85N/dRIT9es5UQNerPYEKK56eTBm8= sigs.k8s.io/yaml v1.4.0 h1:Mk1wCc2gy/F0THH0TAp1QYyJNzRm2KCLy3o5ASXVI5E= From 824e6f442e47ba31639ba82cfc965dcaf6e502f0 Mon Sep 17 00:00:00 2001 From: Daniil Loktev Date: Thu, 23 Oct 2025 19:14:34 +0300 Subject: [PATCH 28/77] fix e2e Signed-off-by: Daniil Loktev --- tests/e2e/testdata/affinity-toleration/transformer.yaml | 2 +- tests/e2e/testdata/affinity-toleration/vm/base/transformer.yaml | 2 +- tests/e2e/testdata/complex-test/transformer.yaml | 2 +- tests/e2e/testdata/complex-test/vm/base/transformer.yaml | 2 +- tests/e2e/testdata/sizing-policy/base/transformer.yaml | 2 +- tests/e2e/testdata/sizing-policy/transformer.yaml | 2 +- 6 files changed, 6 insertions(+), 6 deletions(-) diff --git a/tests/e2e/testdata/affinity-toleration/transformer.yaml b/tests/e2e/testdata/affinity-toleration/transformer.yaml index e827a19238..ec70d37fcd 100644 --- a/tests/e2e/testdata/affinity-toleration/transformer.yaml +++ b/tests/e2e/testdata/affinity-toleration/transformer.yaml @@ -46,7 +46,7 @@ nameReference: - path: spec/virtualMachineName kind: VirtualMachineBlockDeviceAttachment - kind: VirtualMachineClass - version: v1alpha2 + version: v1alpha3 fieldSpecs: - path: spec/virtualMachineClassName kind: VirtualMachine diff --git a/tests/e2e/testdata/affinity-toleration/vm/base/transformer.yaml b/tests/e2e/testdata/affinity-toleration/vm/base/transformer.yaml index c70c289afa..1dc146a3af 100644 --- a/tests/e2e/testdata/affinity-toleration/vm/base/transformer.yaml +++ b/tests/e2e/testdata/affinity-toleration/vm/base/transformer.yaml @@ -48,7 +48,7 @@ nameReference: - path: spec/virtualMachineName kind: VirtualMachineBlockDeviceAttachment - kind: VirtualMachineClass - version: v1alpha2 + version: v1alpha3 fieldSpecs: - path: spec/virtualMachineClassName kind: VirtualMachine diff --git a/tests/e2e/testdata/complex-test/transformer.yaml b/tests/e2e/testdata/complex-test/transformer.yaml index e827a19238..ec70d37fcd 100644 --- a/tests/e2e/testdata/complex-test/transformer.yaml +++ b/tests/e2e/testdata/complex-test/transformer.yaml @@ -46,7 +46,7 @@ nameReference: - path: spec/virtualMachineName kind: VirtualMachineBlockDeviceAttachment - kind: VirtualMachineClass - version: v1alpha2 + version: v1alpha3 fieldSpecs: - path: spec/virtualMachineClassName kind: VirtualMachine diff --git a/tests/e2e/testdata/complex-test/vm/base/transformer.yaml b/tests/e2e/testdata/complex-test/vm/base/transformer.yaml index c70c289afa..1dc146a3af 100644 --- a/tests/e2e/testdata/complex-test/vm/base/transformer.yaml +++ b/tests/e2e/testdata/complex-test/vm/base/transformer.yaml @@ -48,7 +48,7 @@ nameReference: - path: spec/virtualMachineName kind: VirtualMachineBlockDeviceAttachment - kind: VirtualMachineClass - version: v1alpha2 + version: v1alpha3 fieldSpecs: - path: spec/virtualMachineClassName kind: VirtualMachine diff --git a/tests/e2e/testdata/sizing-policy/base/transformer.yaml b/tests/e2e/testdata/sizing-policy/base/transformer.yaml index c70c289afa..1dc146a3af 100644 --- a/tests/e2e/testdata/sizing-policy/base/transformer.yaml +++ b/tests/e2e/testdata/sizing-policy/base/transformer.yaml @@ -48,7 +48,7 @@ nameReference: - path: spec/virtualMachineName kind: VirtualMachineBlockDeviceAttachment - kind: VirtualMachineClass - version: v1alpha2 + version: v1alpha3 fieldSpecs: - path: spec/virtualMachineClassName kind: VirtualMachine diff --git a/tests/e2e/testdata/sizing-policy/transformer.yaml b/tests/e2e/testdata/sizing-policy/transformer.yaml index e827a19238..ec70d37fcd 100644 --- a/tests/e2e/testdata/sizing-policy/transformer.yaml +++ b/tests/e2e/testdata/sizing-policy/transformer.yaml @@ -46,7 +46,7 @@ nameReference: - path: spec/virtualMachineName kind: VirtualMachineBlockDeviceAttachment - kind: VirtualMachineClass - version: v1alpha2 + version: v1alpha3 fieldSpecs: - path: spec/virtualMachineClassName kind: VirtualMachine From 8a59dbfdd37a5e92bb1e7e49fd90acea2063c9ca Mon Sep 17 00:00:00 2001 From: Daniil Loktev Date: Fri, 24 Oct 2025 10:05:02 +0300 Subject: [PATCH 29/77] fix e2e Signed-off-by: Daniil Loktev --- tests/e2e/sizing_policy_test.go | 14 ++++++-------- 1 file changed, 6 insertions(+), 8 deletions(-) diff --git a/tests/e2e/sizing_policy_test.go b/tests/e2e/sizing_policy_test.go index b88fe82423..c0da03c7be 100644 --- a/tests/e2e/sizing_policy_test.go +++ b/tests/e2e/sizing_policy_test.go @@ -19,7 +19,6 @@ package e2e import ( "fmt" "slices" - "strconv" "strings" . "github.com/onsi/ginkgo/v2" @@ -28,6 +27,7 @@ import ( "github.com/deckhouse/virtualization/api/core/v1alpha2" "github.com/deckhouse/virtualization/api/core/v1alpha2/vmcondition" + "github.com/deckhouse/virtualization/api/core/v1alpha3" "github.com/deckhouse/virtualization/tests/e2e/config" "github.com/deckhouse/virtualization/tests/e2e/framework" "github.com/deckhouse/virtualization/tests/e2e/helper" @@ -185,7 +185,7 @@ var _ = Describe("SizingPolicy", framework.CommonE2ETestDecorators(), func() { }) It("creates new `VirtualMachineClass`", func() { - vmClass := v1alpha2.VirtualMachineClass{} + vmClass := v1alpha3.VirtualMachineClass{} err := GetObject(kc.ResourceVMClass, vmClassDiscovery, &vmClass, kc.GetOptions{}) Expect(err).NotTo(HaveOccurred()) vmClass.Name = vmClassDiscoveryCopy @@ -222,7 +222,7 @@ var _ = Describe("SizingPolicy", framework.CommonE2ETestDecorators(), func() { Expect(res.Error()).NotTo(HaveOccurred(), res.StdErr()) vms := strings.Split(res.StdOut(), " ") - vmClass := v1alpha2.VirtualMachineClass{} + vmClass := v1alpha3.VirtualMachineClass{} err := GetObject(kc.ResourceVMClass, vmClassDiscovery, &vmClass, kc.GetOptions{}) Expect(err).NotTo(HaveOccurred()) @@ -246,8 +246,8 @@ var _ = Describe("SizingPolicy", framework.CommonE2ETestDecorators(), func() { }) }) -func ValidateVirtualMachineByClass(virtualMachineClass *v1alpha2.VirtualMachineClass, virtualMachine *v1alpha2.VirtualMachine) { - var sizingPolicy v1alpha2.SizingPolicy +func ValidateVirtualMachineByClass(virtualMachineClass *v1alpha3.VirtualMachineClass, virtualMachine *v1alpha2.VirtualMachine) { + var sizingPolicy v1alpha3.SizingPolicy for _, p := range virtualMachineClass.Spec.SizingPolicies { if virtualMachine.Spec.CPU.Cores >= p.Cores.Min && virtualMachine.Spec.CPU.Cores <= p.Cores.Max { sizingPolicy = *p.DeepCopy() @@ -260,9 +260,7 @@ func ValidateVirtualMachineByClass(virtualMachineClass *v1alpha2.VirtualMachineC checkMemory := checkMinMemory && checkMaxMemory Expect(checkMemory).To(BeTrue(), fmt.Errorf("memory size outside of possible interval '%v - %v': %v", sizingPolicy.Memory.Min, sizingPolicy.Memory.Max, virtualMachine.Spec.Memory.Size)) - coreFraction, err := strconv.Atoi(strings.ReplaceAll(virtualMachine.Spec.CPU.CoreFraction, "%", "")) - Expect(err).NotTo(HaveOccurred(), "cannot convert CoreFraction value to integer: %s", err) - checkCoreFraction := slices.Contains(sizingPolicy.CoreFractions, v1alpha2.CoreFractionValue(coreFraction)) + checkCoreFraction := slices.Contains(sizingPolicy.CoreFractions, v1alpha3.CoreFractionValue(virtualMachine.Spec.CPU.CoreFraction)) Expect(checkCoreFraction).To(BeTrue(), fmt.Errorf("sizing policy core fraction list does not contain value from spec: %s\n%v", virtualMachine.Spec.CPU.CoreFraction, sizingPolicy.CoreFractions)) } From 18d5aa750ff2b10814669598c1b56e6c419a697a Mon Sep 17 00:00:00 2001 From: Daniil Loktev Date: Fri, 24 Oct 2025 10:17:19 +0300 Subject: [PATCH 30/77] fix e2e Signed-off-by: Daniil Loktev --- tests/e2e/sizing_policy_test.go | 1 - 1 file changed, 1 deletion(-) diff --git a/tests/e2e/sizing_policy_test.go b/tests/e2e/sizing_policy_test.go index 12bfc1d007..37a4bede40 100644 --- a/tests/e2e/sizing_policy_test.go +++ b/tests/e2e/sizing_policy_test.go @@ -28,7 +28,6 @@ import ( "github.com/deckhouse/virtualization/api/core/v1alpha2" "github.com/deckhouse/virtualization/api/core/v1alpha2/vmcondition" "github.com/deckhouse/virtualization/api/core/v1alpha3" - "github.com/deckhouse/virtualization/tests/e2e/config" "github.com/deckhouse/virtualization/tests/e2e/framework" "github.com/deckhouse/virtualization/tests/e2e/helper" kc "github.com/deckhouse/virtualization/tests/e2e/kubectl" From afd04f3d7d919a6e363964591340146e8de141a4 Mon Sep 17 00:00:00 2001 From: Daniil Loktev Date: Mon, 27 Oct 2025 12:00:51 +0300 Subject: [PATCH 31/77] fix hook Signed-off-by: Daniil Loktev --- .../pkg/hooks/inject-crd-conversion-cabundle/hook.go | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/images/hooks/pkg/hooks/inject-crd-conversion-cabundle/hook.go b/images/hooks/pkg/hooks/inject-crd-conversion-cabundle/hook.go index abbbb30c2b..5c749f674b 100644 --- a/images/hooks/pkg/hooks/inject-crd-conversion-cabundle/hook.go +++ b/images/hooks/pkg/hooks/inject-crd-conversion-cabundle/hook.go @@ -26,11 +26,11 @@ import ( ) const ( - crdSnapshotName = "virtualmachineclasses-crd" - crdName = "virtualmachineclasses.virtualization.deckhouse.io" - crdJQFilter = `{ + crdSnapshotName = "virtualmachineclasses-crd" + crdName = "virtualmachineclasses.virtualization.deckhouse.io" + crdJQFilter = `{ "name": .metadata.name, - "hasCABundle": (.spec.conversion.webhook.clientConfig.caBundle != null) + "hasCABundle": (.spec.conversion.webhook.clientConfig.caBundle // null | . != null) }` ) From 8770fdf5b839ef35f52b44334975f5be06fdfe68 Mon Sep 17 00:00:00 2001 From: Daniil Loktev Date: Mon, 27 Oct 2025 12:55:37 +0300 Subject: [PATCH 32/77] fix hook Signed-off-by: Daniil Loktev --- .../hooks/pkg/hooks/inject-crd-conversion-cabundle/hook.go | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/images/hooks/pkg/hooks/inject-crd-conversion-cabundle/hook.go b/images/hooks/pkg/hooks/inject-crd-conversion-cabundle/hook.go index 5c749f674b..749d5cc571 100644 --- a/images/hooks/pkg/hooks/inject-crd-conversion-cabundle/hook.go +++ b/images/hooks/pkg/hooks/inject-crd-conversion-cabundle/hook.go @@ -23,6 +23,7 @@ import ( "github.com/deckhouse/module-sdk/pkg" "github.com/deckhouse/module-sdk/pkg/registry" + "github.com/deckhouse/module-sdk/pkg/utils/ptr" ) const ( @@ -30,7 +31,7 @@ const ( crdName = "virtualmachineclasses.virtualization.deckhouse.io" crdJQFilter = `{ "name": .metadata.name, - "hasCABundle": (.spec.conversion.webhook.clientConfig.caBundle // null | . != null) + "hasCABundle": (.spec.conversion.webhook.clientConfig.caBundle | . != null) }` ) @@ -52,6 +53,8 @@ var config = &pkg.HookConfig{ MatchNames: []string{crdName}, }, JqFilter: crdJQFilter, + + ExecuteHookOnSynchronization: ptr.To(false), }, }, Queue: fmt.Sprintf("modules/%s", settings.ModuleName), From 8706c6cbd2100a259cf20b3a21854c6f46d6ee62 Mon Sep 17 00:00:00 2001 From: Daniil Loktev Date: Mon, 27 Oct 2025 14:18:16 +0300 Subject: [PATCH 33/77] wip Signed-off-by: Daniil Loktev --- api/scripts/update-codegen.sh | 21 +-- crds/virtualmachineclasses.yaml | 166 +++++++++++++----- .../virtualization-module-hooks/register.go | 2 +- .../hook.go | 38 ++-- 4 files changed, 148 insertions(+), 79 deletions(-) rename images/hooks/pkg/hooks/{inject-crd-conversion-cabundle => inject-crd-conversion}/hook.go (68%) diff --git a/api/scripts/update-codegen.sh b/api/scripts/update-codegen.sh index f6a3ced4bb..9c6e7d6502 100755 --- a/api/scripts/update-codegen.sh +++ b/api/scripts/update-codegen.sh @@ -84,26 +84,7 @@ function generate::crds { if ! [[ " ${ALLOWED_RESOURCE_GEN_CRD[*]} " =~ [[:space:]]$(cat "$file" | yq '.spec.names.kind')[[:space:]] ]]; then continue fi - - DEST_FILE="${ROOT}/crds/$(echo $file | awk -Fio_ '{print $2}')" - cp "$file" "${DEST_FILE}" - - if [[ "${DEST_FILE}" == *"virtualmachineclasses.yaml" ]]; then - yq eval -i '.spec.conversion = { - "strategy": "Webhook", - "webhook": { - "clientConfig": { - "service": { - "name": "virtualization-controller", - "namespace": "d8-virtualization", - "path": "/convert", - "port": 443 - } - }, - "conversionReviewVersions": ["v1"] - } - }' "${DEST_FILE}" - fi + cp "$file" "${ROOT}/crds/$(echo $file | awk -Fio_ '{print $2}')" done } diff --git a/crds/virtualmachineclasses.yaml b/crds/virtualmachineclasses.yaml index 4ae5b6135f..a79da4cfa0 100644 --- a/crds/virtualmachineclasses.yaml +++ b/crds/virtualmachineclasses.yaml @@ -66,20 +66,28 @@ spec: description: CPU defines the requirements for the virtual CPU model. properties: discovery: - description: Create a CPU model based on intersecting CPU features for selected nodes. + description: + Create a CPU model based on intersecting CPU features + for selected nodes. properties: nodeSelector: - description: A selection of nodes to be used as the basis for creating a universal CPU model. + description: + A selection of nodes to be used as the basis + for creating a universal CPU model. properties: matchExpressions: - description: matchExpressions is a list of label selector requirements. The requirements are ANDed. + description: + matchExpressions is a list of label selector + requirements. The requirements are ANDed. items: description: |- A label selector requirement is a selector that contains values, a key, and an operator that relates the key and values. properties: key: - description: key is the label key that the selector applies to. + description: + key is the label key that the selector + applies to. type: string operator: description: |- @@ -126,7 +134,9 @@ spec: minItems: 1 type: array model: - description: CPU model name. For more information about CPU models and topology, refer to the [libvirt docs](https://libvirt.org/formatdomain.html#cpu-model-and-topology). + description: + CPU model name. For more information about CPU models + and topology, refer to the [libvirt docs](https://libvirt.org/formatdomain.html#cpu-model-and-topology). example: IvyBridge minLength: 1 type: string @@ -155,14 +165,25 @@ spec: x-kubernetes-validations: - message: .spec.cpu is immutable rule: self == oldSelf - - message: HostPassthrough and Host cannot have model, features or discovery - rule: "self.type == 'HostPassthrough' || self.type == 'Host' ? !has(self.model) && !has(self.features) && !has(self.discovery) : true" + - message: + HostPassthrough and Host cannot have model, features or + discovery + rule: + "self.type == 'HostPassthrough' || self.type == 'Host' + ? !has(self.model) && !has(self.features) && !has(self.discovery) + : true" - message: Discovery cannot have model or features - rule: "self.type == 'Discovery' ? !has(self.model) && !has(self.features) : true" + rule: + "self.type == 'Discovery' ? !has(self.model) && !has(self.features) + : true" - message: Model requires model and cannot have features or discovery - rule: "self.type == 'Model' ? has(self.model) && !has(self.features) && !has(self.discovery) : true" + rule: + "self.type == 'Model' ? has(self.model) && !has(self.features) + && !has(self.discovery) : true" - message: Features requires features and cannot have model or discovery - rule: "self.type == 'Features' ? has(self.features) && !has(self.model) && !has(self.discovery): true" + rule: + "self.type == 'Features' ? has(self.features) && !has(self.model) + && !has(self.discovery): true" nodeSelector: description: NodeSelector defines the nodes targeted for VM scheduling. properties: @@ -221,7 +242,9 @@ spec: type: integer type: array cores: - description: The policy applies for a specified range of the number of CPU cores. + description: + The policy applies for a specified range of the + number of CPU cores. properties: max: description: Maximum number of CPU cores. @@ -234,7 +257,11 @@ spec: minimum: 1 type: integer step: - description: Discretization step for the CPU core number. For example, the combination of `min=2`, `max=10`, and `step=4` allows to set the number of virtual machine CPU cores to 2, 6, or 10. + description: + Discretization step for the CPU core number. + For example, the combination of `min=2`, `max=10`, and + `step=4` allows to set the number of virtual machine CPU + cores to 2, 6, or 10. example: 1 minimum: 1 type: integer @@ -295,7 +322,11 @@ spec: anyOf: - type: integer - type: string - description: Memory size discretization step. For example, the combination of `min=2Gi, `max=4Gi` and `step=1Gi` allows to set the virtual machine memory size to 2Gi, 3Gi, or 4Gi. + description: + Memory size discretization step. For example, + the combination of `min=2Gi, `max=4Gi` and `step=1Gi` + allows to set the virtual machine memory size to 2Gi, + 3Gi, or 4Gi. example: 512Mi pattern: ^(\+|-)?(([0-9]+(\.[0-9]*)?)|(\.[0-9]+))(([KMGTPE]i)|[numkMGTPE]|([eE](\+|-)?(([0-9]+(\.[0-9]*)?)|(\.[0-9]+))))?$ x-kubernetes-int-or-string: true @@ -359,9 +390,13 @@ spec: type: string type: array conditions: - description: The latest detailed observations of the VirtualMachineClass resource. + description: + The latest detailed observations of the VirtualMachineClass + resource. items: - description: Condition contains details for one aspect of the current state of this API Resource. + description: + Condition contains details for one aspect of the current + state of this API Resource. properties: lastTransitionTime: description: |- @@ -430,7 +465,9 @@ spec: type: string type: array notEnabledCommon: - description: List of unused processor features additionally available for a given group of nodes. + description: + List of unused processor features additionally available + for a given group of nodes. example: - ssse3 - vme @@ -445,7 +482,9 @@ spec: - 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: Maximum amount of free CPU and memory resources observed among all available nodes. + description: + Maximum amount of free CPU and memory resources observed + among all available nodes. example: - 'maxAllocatableResources: {"cpu": 1, "memory": "10Gi"}' type: object @@ -517,20 +556,28 @@ spec: description: CPU defines the requirements for the virtual CPU model. properties: discovery: - description: Create a CPU model based on intersecting CPU features for selected nodes. + description: + Create a CPU model based on intersecting CPU features + for selected nodes. properties: nodeSelector: - description: A selection of nodes to be used as the basis for creating a universal CPU model. + description: + A selection of nodes to be used as the basis + for creating a universal CPU model. properties: matchExpressions: - description: matchExpressions is a list of label selector requirements. The requirements are ANDed. + description: + matchExpressions is a list of label selector + requirements. The requirements are ANDed. items: description: |- A label selector requirement is a selector that contains values, a key, and an operator that relates the key and values. properties: key: - description: key is the label key that the selector applies to. + description: + key is the label key that the selector + applies to. type: string operator: description: |- @@ -577,7 +624,9 @@ spec: minItems: 1 type: array model: - description: CPU model name. For more information about CPU models and topology, refer to the [libvirt docs](https://libvirt.org/formatdomain.html#cpu-model-and-topology). + description: + CPU model name. For more information about CPU models + and topology, refer to the [libvirt docs](https://libvirt.org/formatdomain.html#cpu-model-and-topology). example: IvyBridge minLength: 1 type: string @@ -606,14 +655,25 @@ spec: x-kubernetes-validations: - message: .spec.cpu is immutable rule: self == oldSelf - - message: HostPassthrough and Host cannot have model, features or discovery - rule: "self.type == 'HostPassthrough' || self.type == 'Host' ? !has(self.model) && !has(self.features) && !has(self.discovery) : true" + - message: + HostPassthrough and Host cannot have model, features or + discovery + rule: + "self.type == 'HostPassthrough' || self.type == 'Host' + ? !has(self.model) && !has(self.features) && !has(self.discovery) + : true" - message: Discovery cannot have model or features - rule: "self.type == 'Discovery' ? !has(self.model) && !has(self.features) : true" + rule: + "self.type == 'Discovery' ? !has(self.model) && !has(self.features) + : true" - message: Model requires model and cannot have features or discovery - rule: "self.type == 'Model' ? has(self.model) && !has(self.features) && !has(self.discovery) : true" + rule: + "self.type == 'Model' ? has(self.model) && !has(self.features) + && !has(self.discovery) : true" - message: Features requires features and cannot have model or discovery - rule: "self.type == 'Features' ? has(self.features) && !has(self.model) && !has(self.discovery): true" + rule: + "self.type == 'Features' ? has(self.features) && !has(self.model) + && !has(self.discovery): true" nodeSelector: description: NodeSelector defines the nodes targeted for VM scheduling. properties: @@ -665,14 +725,21 @@ spec: The cores.min - cores.max ranges for different elements of the list must not overlap. properties: coreFractions: - description: Allowed values of the `coreFraction` parameter in percentages (e.g., "5%", "10%", "25%", "50%", "100%"). + description: + Allowed values of the `coreFraction` parameter + in percentages (e.g., "5%", "10%", "25%", "50%", "100%"). items: - description: CoreFractionValue represents CPU core fraction as a percentage string (e.g., "5%", "10%", "25%", "50%", "100%"). + description: + CoreFractionValue represents CPU core fraction + as a percentage string (e.g., "5%", "10%", "25%", "50%", + "100%"). pattern: ^([1-9]|[1-9][0-9]|100)%?$ type: string type: array cores: - description: The policy applies for a specified range of the number of CPU cores. + description: + The policy applies for a specified range of the + number of CPU cores. properties: max: description: Maximum number of CPU cores. @@ -685,7 +752,11 @@ spec: minimum: 1 type: integer step: - description: Discretization step for the CPU core number. For example, the combination of `min=2`, `max=10`, and `step=4` allows to set the number of virtual machine CPU cores to 2, 6, or 10. + description: + Discretization step for the CPU core number. + For example, the combination of `min=2`, `max=10`, and + `step=4` allows to set the number of virtual machine CPU + cores to 2, 6, or 10. example: 1 minimum: 1 type: integer @@ -746,7 +817,11 @@ spec: anyOf: - type: integer - type: string - description: Memory size discretization step. For example, the combination of `min=2Gi, `max=4Gi` and `step=1Gi` allows to set the virtual machine memory size to 2Gi, 3Gi, or 4Gi. + description: + Memory size discretization step. For example, + the combination of `min=2Gi, `max=4Gi` and `step=1Gi` + allows to set the virtual machine memory size to 2Gi, + 3Gi, or 4Gi. example: 512Mi pattern: ^(\+|-)?(([0-9]+(\.[0-9]*)?)|(\.[0-9]+))(([KMGTPE]i)|[numkMGTPE]|([eE](\+|-)?(([0-9]+(\.[0-9]*)?)|(\.[0-9]+))))?$ x-kubernetes-int-or-string: true @@ -810,9 +885,13 @@ spec: type: string type: array conditions: - description: The latest detailed observations of the VirtualMachineClass resource. + description: + The latest detailed observations of the VirtualMachineClass + resource. items: - description: Condition contains details for one aspect of the current state of this API Resource. + description: + Condition contains details for one aspect of the current + state of this API Resource. properties: lastTransitionTime: description: |- @@ -881,7 +960,9 @@ spec: type: string type: array notEnabledCommon: - description: List of unused processor features additionally available for a given group of nodes. + description: + List of unused processor features additionally available + for a given group of nodes. example: - ssse3 - vme @@ -896,7 +977,9 @@ spec: - 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: Maximum amount of free CPU and memory resources observed among all available nodes. + description: + Maximum amount of free CPU and memory resources observed + among all available nodes. example: - 'maxAllocatableResources: {"cpu": 1, "memory": "10Gi"}' type: object @@ -925,14 +1008,3 @@ spec: storage: false subresources: status: {} - conversion: - strategy: Webhook - webhook: - clientConfig: - service: - name: virtualization-controller - namespace: d8-virtualization - path: /convert - port: 443 - conversionReviewVersions: - - v1 diff --git a/images/hooks/cmd/virtualization-module-hooks/register.go b/images/hooks/cmd/virtualization-module-hooks/register.go index 5c24ec4ba7..6e14bffb1d 100644 --- a/images/hooks/cmd/virtualization-module-hooks/register.go +++ b/images/hooks/cmd/virtualization-module-hooks/register.go @@ -22,7 +22,7 @@ import ( _ "hooks/pkg/hooks/discovery-workload-nodes" _ "hooks/pkg/hooks/drop-openshift-labels" _ "hooks/pkg/hooks/generate-secret-for-dvcr" - _ "hooks/pkg/hooks/inject-crd-conversion-cabundle" + _ "hooks/pkg/hooks/inject-crd-conversion" _ "hooks/pkg/hooks/migrate-delete-renamed-validation-admission-policy" _ "hooks/pkg/hooks/migrate-virthandler-kvm-node-labels" _ "hooks/pkg/hooks/prevent-default-vmclasses-deletion" diff --git a/images/hooks/pkg/hooks/inject-crd-conversion-cabundle/hook.go b/images/hooks/pkg/hooks/inject-crd-conversion/hook.go similarity index 68% rename from images/hooks/pkg/hooks/inject-crd-conversion-cabundle/hook.go rename to images/hooks/pkg/hooks/inject-crd-conversion/hook.go index 749d5cc571..e8b581177a 100644 --- a/images/hooks/pkg/hooks/inject-crd-conversion-cabundle/hook.go +++ b/images/hooks/pkg/hooks/inject-crd-conversion/hook.go @@ -31,13 +31,13 @@ const ( crdName = "virtualmachineclasses.virtualization.deckhouse.io" crdJQFilter = `{ "name": .metadata.name, - "hasCABundle": (.spec.conversion.webhook.clientConfig.caBundle | . != null) + "hasConversion": (.spec.conversion // null | . != null) }` ) type CRDSnapshot struct { - Name string `json:"name"` - HasCABundle bool `json:"hasCABundle"` + Name string `json:"name"` + HasConversion bool `json:"hasConversion"` } var _ = registry.RegisterFunc(config, reconcile) @@ -61,11 +61,11 @@ var config = &pkg.HookConfig{ } func reconcile(ctx context.Context, input *pkg.HookInput) error { - input.Logger.Info("Start inject CRD conversion webhook caBundle hook") + input.Logger.Info("Start inject CRD conversion webhook configuration hook") caCert := input.Values.Get("virtualization.internal.rootCA.crt") if !caCert.Exists() { - input.Logger.Info("CA certificate not found in values, skipping caBundle injection") + input.Logger.Info("CA certificate not found in values, skipping conversion webhook injection") return nil } @@ -76,7 +76,7 @@ func reconcile(ctx context.Context, input *pkg.HookInput) error { snapshots := input.Snapshots.Get(crdSnapshotName) if len(snapshots) == 0 { - input.Logger.Info("CRD %s not found, skipping caBundle injection", crdName) + input.Logger.Info("CRD %s not found, skipping conversion webhook injection", crdName) return nil } @@ -85,21 +85,37 @@ func reconcile(ctx context.Context, input *pkg.HookInput) error { return fmt.Errorf("failed to unmarshal CRD snapshot: %w", err) } - if crdSnap.HasCABundle { - input.Logger.Info("CRD %s already has caBundle, skipping injection", crdName) + if crdSnap.HasConversion { + input.Logger.Info("CRD %s already has conversion configuration, skipping injection", crdName) return nil } + conversionConfig := map[string]interface{}{ + "strategy": "Webhook", + "webhook": map[string]interface{}{ + "clientConfig": map[string]interface{}{ + "service": map[string]interface{}{ + "name": "virtualization-controller", + "namespace": "d8-virtualization", + "path": "/convert", + "port": 443, + }, + "caBundle": caBundle, + }, + "conversionReviewVersions": []string{"v1"}, + }, + } + patch := []interface{}{ map[string]interface{}{ "op": "add", - "path": "/spec/conversion/webhook/clientConfig/caBundle", - "value": caBundle, + "path": "/spec/conversion", + "value": conversionConfig, }, } input.PatchCollector.JSONPatch(patch, "apiextensions.k8s.io/v1", "CustomResourceDefinition", "", crdName) - input.Logger.Info("Successfully injected caBundle into CRD %s", crdName) + input.Logger.Info("Successfully injected conversion webhook configuration into CRD %s", crdName) return nil } From 90fa31da853159a6ec17c95ac1fc524016e7d0fe Mon Sep 17 00:00:00 2001 From: Daniil Loktev Date: Mon, 27 Oct 2025 14:40:44 +0300 Subject: [PATCH 34/77] wip Signed-off-by: Daniil Loktev --- images/hooks/pkg/hooks/inject-crd-conversion/hook.go | 2 -- 1 file changed, 2 deletions(-) diff --git a/images/hooks/pkg/hooks/inject-crd-conversion/hook.go b/images/hooks/pkg/hooks/inject-crd-conversion/hook.go index e8b581177a..f899e6e2b0 100644 --- a/images/hooks/pkg/hooks/inject-crd-conversion/hook.go +++ b/images/hooks/pkg/hooks/inject-crd-conversion/hook.go @@ -53,8 +53,6 @@ var config = &pkg.HookConfig{ MatchNames: []string{crdName}, }, JqFilter: crdJQFilter, - - ExecuteHookOnSynchronization: ptr.To(false), }, }, Queue: fmt.Sprintf("modules/%s", settings.ModuleName), From a23c1075d14724079a3b1bee1bca728713f4b010 Mon Sep 17 00:00:00 2001 From: Daniil Loktev Date: Mon, 27 Oct 2025 14:47:31 +0300 Subject: [PATCH 35/77] wip Signed-off-by: Daniil Loktev --- images/hooks/pkg/hooks/inject-crd-conversion/hook.go | 1 - 1 file changed, 1 deletion(-) diff --git a/images/hooks/pkg/hooks/inject-crd-conversion/hook.go b/images/hooks/pkg/hooks/inject-crd-conversion/hook.go index f899e6e2b0..c3f3f47413 100644 --- a/images/hooks/pkg/hooks/inject-crd-conversion/hook.go +++ b/images/hooks/pkg/hooks/inject-crd-conversion/hook.go @@ -23,7 +23,6 @@ import ( "github.com/deckhouse/module-sdk/pkg" "github.com/deckhouse/module-sdk/pkg/registry" - "github.com/deckhouse/module-sdk/pkg/utils/ptr" ) const ( From b7896498fe935c2ad11e8ecbd53a7bbb3995aac2 Mon Sep 17 00:00:00 2001 From: Daniil Loktev Date: Mon, 27 Oct 2025 15:01:08 +0300 Subject: [PATCH 36/77] wip Signed-off-by: Daniil Loktev --- images/hooks/pkg/hooks/inject-crd-conversion/hook.go | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/images/hooks/pkg/hooks/inject-crd-conversion/hook.go b/images/hooks/pkg/hooks/inject-crd-conversion/hook.go index c3f3f47413..ccfe3afaed 100644 --- a/images/hooks/pkg/hooks/inject-crd-conversion/hook.go +++ b/images/hooks/pkg/hooks/inject-crd-conversion/hook.go @@ -42,7 +42,7 @@ type CRDSnapshot struct { var _ = registry.RegisterFunc(config, reconcile) var config = &pkg.HookConfig{ - OnAfterHelm: &pkg.OrderedConfig{Order: 10}, + OnBeforeHelm: &pkg.OrderedConfig{Order: 10}, Kubernetes: []pkg.KubernetesConfig{ { Name: crdSnapshotName, From 09f092ad88cda3ee3ab49737608267596500729a Mon Sep 17 00:00:00 2001 From: Daniil Loktev Date: Mon, 27 Oct 2025 17:16:58 +0300 Subject: [PATCH 37/77] wip Signed-off-by: Daniil Loktev --- .../hooks/pkg/hooks/inject-crd-conversion/hook.go | 13 +++---------- 1 file changed, 3 insertions(+), 10 deletions(-) diff --git a/images/hooks/pkg/hooks/inject-crd-conversion/hook.go b/images/hooks/pkg/hooks/inject-crd-conversion/hook.go index ccfe3afaed..7b4cfce706 100644 --- a/images/hooks/pkg/hooks/inject-crd-conversion/hook.go +++ b/images/hooks/pkg/hooks/inject-crd-conversion/hook.go @@ -30,13 +30,11 @@ const ( crdName = "virtualmachineclasses.virtualization.deckhouse.io" crdJQFilter = `{ "name": .metadata.name, - "hasConversion": (.spec.conversion // null | . != null) }` ) type CRDSnapshot struct { - Name string `json:"name"` - HasConversion bool `json:"hasConversion"` + Name string `json:"name"` } var _ = registry.RegisterFunc(config, reconcile) @@ -73,7 +71,7 @@ func reconcile(ctx context.Context, input *pkg.HookInput) error { snapshots := input.Snapshots.Get(crdSnapshotName) if len(snapshots) == 0 { - input.Logger.Info("CRD %s not found, skipping conversion webhook injection", crdName) + input.Logger.Info("CRD not found, skipping conversion webhook injection") return nil } @@ -82,11 +80,6 @@ func reconcile(ctx context.Context, input *pkg.HookInput) error { return fmt.Errorf("failed to unmarshal CRD snapshot: %w", err) } - if crdSnap.HasConversion { - input.Logger.Info("CRD %s already has conversion configuration, skipping injection", crdName) - return nil - } - conversionConfig := map[string]interface{}{ "strategy": "Webhook", "webhook": map[string]interface{}{ @@ -105,7 +98,7 @@ func reconcile(ctx context.Context, input *pkg.HookInput) error { patch := []interface{}{ map[string]interface{}{ - "op": "add", + "op": "replace", "path": "/spec/conversion", "value": conversionConfig, }, From 3a3a22fffe4da579f49d202fbcc105e8d75dcaff Mon Sep 17 00:00:00 2001 From: Daniil Loktev Date: Mon, 27 Oct 2025 17:37:32 +0300 Subject: [PATCH 38/77] wip Signed-off-by: Daniil Loktev --- images/hooks/pkg/hooks/inject-crd-conversion/hook.go | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/images/hooks/pkg/hooks/inject-crd-conversion/hook.go b/images/hooks/pkg/hooks/inject-crd-conversion/hook.go index 7b4cfce706..218f01770e 100644 --- a/images/hooks/pkg/hooks/inject-crd-conversion/hook.go +++ b/images/hooks/pkg/hooks/inject-crd-conversion/hook.go @@ -40,7 +40,7 @@ type CRDSnapshot struct { var _ = registry.RegisterFunc(config, reconcile) var config = &pkg.HookConfig{ - OnBeforeHelm: &pkg.OrderedConfig{Order: 10}, + OnAfterHelm: &pkg.OrderedConfig{Order: 10}, Kubernetes: []pkg.KubernetesConfig{ { Name: crdSnapshotName, From e8c8bfe2dc4b5f4d4325562a03c2feb19a47f21b Mon Sep 17 00:00:00 2001 From: Daniil Loktev Date: Mon, 27 Oct 2025 18:33:40 +0300 Subject: [PATCH 39/77] wip Signed-off-by: Daniil Loktev --- images/hooks/pkg/hooks/inject-crd-conversion/hook.go | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/images/hooks/pkg/hooks/inject-crd-conversion/hook.go b/images/hooks/pkg/hooks/inject-crd-conversion/hook.go index 218f01770e..2f0a161427 100644 --- a/images/hooks/pkg/hooks/inject-crd-conversion/hook.go +++ b/images/hooks/pkg/hooks/inject-crd-conversion/hook.go @@ -58,7 +58,7 @@ var config = &pkg.HookConfig{ func reconcile(ctx context.Context, input *pkg.HookInput) error { input.Logger.Info("Start inject CRD conversion webhook configuration hook") - caCert := input.Values.Get("virtualization.internal.rootCA.crt") + caCert := input.Values.Get("virtualization.internal.controller.cert.ca") if !caCert.Exists() { input.Logger.Info("CA certificate not found in values, skipping conversion webhook injection") return nil From 0bf34228d29f94f6b6656faedcabd64e43e7db19 Mon Sep 17 00:00:00 2001 From: Daniil Loktev Date: Mon, 27 Oct 2025 18:46:00 +0300 Subject: [PATCH 40/77] wip Signed-off-by: Daniil Loktev --- .../pkg/hooks/inject-crd-conversion/hook.go | 53 ++++++++++++++----- 1 file changed, 40 insertions(+), 13 deletions(-) diff --git a/images/hooks/pkg/hooks/inject-crd-conversion/hook.go b/images/hooks/pkg/hooks/inject-crd-conversion/hook.go index 2f0a161427..0c084a4774 100644 --- a/images/hooks/pkg/hooks/inject-crd-conversion/hook.go +++ b/images/hooks/pkg/hooks/inject-crd-conversion/hook.go @@ -26,17 +26,26 @@ import ( ) const ( - crdSnapshotName = "virtualmachineclasses-crd" - crdName = "virtualmachineclasses.virtualization.deckhouse.io" - crdJQFilter = `{ + crdSnapshotName = "virtualmachineclasses-crd" + secretSnapshotName = "controller-tls-secret" + crdName = "virtualmachineclasses.virtualization.deckhouse.io" + controllerTLSSecretName = "virtualization-controller-tls" + crdJQFilter = `{ "name": .metadata.name, }` + secretJQFilter = `{ + "ca": .data."ca.crt", + }` ) type CRDSnapshot struct { Name string `json:"name"` } +type SecretSnapshot struct { + CA string `json:"ca"` +} + var _ = registry.RegisterFunc(config, reconcile) var config = &pkg.HookConfig{ @@ -51,6 +60,20 @@ var config = &pkg.HookConfig{ }, JqFilter: crdJQFilter, }, + { + Name: secretSnapshotName, + APIVersion: "v1", + Kind: "Secret", + NameSelector: &pkg.NameSelector{ + MatchNames: []string{controllerTLSSecretName}, + }, + NamespaceSelector: &pkg.NamespaceSelector{ + NameSelector: &pkg.NameSelector{ + MatchNames: []string{settings.ModuleNamespace}, + }, + }, + JqFilter: secretJQFilter, + }, }, Queue: fmt.Sprintf("modules/%s", settings.ModuleName), } @@ -58,25 +81,29 @@ var config = &pkg.HookConfig{ func reconcile(ctx context.Context, input *pkg.HookInput) error { input.Logger.Info("Start inject CRD conversion webhook configuration hook") - caCert := input.Values.Get("virtualization.internal.controller.cert.ca") - if !caCert.Exists() { - input.Logger.Info("CA certificate not found in values, skipping conversion webhook injection") + secretSnapshots := input.Snapshots.Get(secretSnapshotName) + if len(secretSnapshots) == 0 { + input.Logger.Info("Controller TLS secret not found, skipping conversion webhook injection") return nil } - caBundle := caCert.String() - if caBundle == "" { - return fmt.Errorf("CA certificate is empty") + var secretSnap SecretSnapshot + if err := secretSnapshots[0].UnmarshalTo(&secretSnap); err != nil { + return fmt.Errorf("failed to unmarshal secret snapshot: %w", err) + } + + if secretSnap.CA == "" { + return fmt.Errorf("CA certificate is empty in controller TLS secret") } - snapshots := input.Snapshots.Get(crdSnapshotName) - if len(snapshots) == 0 { + crdSnapshots := input.Snapshots.Get(crdSnapshotName) + if len(crdSnapshots) == 0 { input.Logger.Info("CRD not found, skipping conversion webhook injection") return nil } var crdSnap CRDSnapshot - if err := snapshots[0].UnmarshalTo(&crdSnap); err != nil { + if err := crdSnapshots[0].UnmarshalTo(&crdSnap); err != nil { return fmt.Errorf("failed to unmarshal CRD snapshot: %w", err) } @@ -90,7 +117,7 @@ func reconcile(ctx context.Context, input *pkg.HookInput) error { "path": "/convert", "port": 443, }, - "caBundle": caBundle, + "caBundle": secretSnap.CA, }, "conversionReviewVersions": []string{"v1"}, }, From 95551fe6b19da6fe348c2567a740680b7fd5552f Mon Sep 17 00:00:00 2001 From: Daniil Loktev Date: Tue, 28 Oct 2025 17:39:17 +0300 Subject: [PATCH 41/77] wip Signed-off-by: Daniil Loktev --- .../pkg/hooks/inject-crd-conversion/hook.go | 86 +++++-------------- 1 file changed, 22 insertions(+), 64 deletions(-) diff --git a/images/hooks/pkg/hooks/inject-crd-conversion/hook.go b/images/hooks/pkg/hooks/inject-crd-conversion/hook.go index 0c084a4774..d823ccde24 100644 --- a/images/hooks/pkg/hooks/inject-crd-conversion/hook.go +++ b/images/hooks/pkg/hooks/inject-crd-conversion/hook.go @@ -18,93 +18,51 @@ package inject_crd_conversion_cabundle import ( "context" "fmt" + "log/slog" "hooks/pkg/settings" "github.com/deckhouse/module-sdk/pkg" "github.com/deckhouse/module-sdk/pkg/registry" + corev1 "k8s.io/api/core/v1" + "k8s.io/apimachinery/pkg/types" ) const ( - crdSnapshotName = "virtualmachineclasses-crd" - secretSnapshotName = "controller-tls-secret" - crdName = "virtualmachineclasses.virtualization.deckhouse.io" + crdName = "virtualmachineclasses.virtualization.deckhouse.io" controllerTLSSecretName = "virtualization-controller-tls" - crdJQFilter = `{ - "name": .metadata.name, - }` - secretJQFilter = `{ - "ca": .data."ca.crt", - }` ) -type CRDSnapshot struct { - Name string `json:"name"` -} - -type SecretSnapshot struct { - CA string `json:"ca"` -} - var _ = registry.RegisterFunc(config, reconcile) var config = &pkg.HookConfig{ OnAfterHelm: &pkg.OrderedConfig{Order: 10}, - Kubernetes: []pkg.KubernetesConfig{ - { - Name: crdSnapshotName, - APIVersion: "apiextensions.k8s.io/v1", - Kind: "CustomResourceDefinition", - NameSelector: &pkg.NameSelector{ - MatchNames: []string{crdName}, - }, - JqFilter: crdJQFilter, - }, - { - Name: secretSnapshotName, - APIVersion: "v1", - Kind: "Secret", - NameSelector: &pkg.NameSelector{ - MatchNames: []string{controllerTLSSecretName}, - }, - NamespaceSelector: &pkg.NamespaceSelector{ - NameSelector: &pkg.NameSelector{ - MatchNames: []string{settings.ModuleNamespace}, - }, - }, - JqFilter: secretJQFilter, - }, - }, - Queue: fmt.Sprintf("modules/%s", settings.ModuleName), + Queue: fmt.Sprintf("modules/%s", settings.ModuleName), } func reconcile(ctx context.Context, input *pkg.HookInput) error { input.Logger.Info("Start inject CRD conversion webhook configuration hook") - secretSnapshots := input.Snapshots.Get(secretSnapshotName) - if len(secretSnapshots) == 0 { - input.Logger.Info("Controller TLS secret not found, skipping conversion webhook injection") - return nil - } - - var secretSnap SecretSnapshot - if err := secretSnapshots[0].UnmarshalTo(&secretSnap); err != nil { - return fmt.Errorf("failed to unmarshal secret snapshot: %w", err) + // Get Kubernetes client + k8sClient, err := input.DC.GetK8sClient() + if err != nil { + return fmt.Errorf("get k8s client: %w", err) } - if secretSnap.CA == "" { - return fmt.Errorf("CA certificate is empty in controller TLS secret") - } - - crdSnapshots := input.Snapshots.Get(crdSnapshotName) - if len(crdSnapshots) == 0 { - input.Logger.Info("CRD not found, skipping conversion webhook injection") + // Fetch the TLS secret directly + secret := &corev1.Secret{} + err = k8sClient.Get(ctx, types.NamespacedName{ + Namespace: settings.ModuleNamespace, + Name: controllerTLSSecretName, + }, secret) + if err != nil { + input.Logger.Info("Controller TLS secret not found, skipping conversion webhook injection", slog.Any("error", err)) return nil } - var crdSnap CRDSnapshot - if err := crdSnapshots[0].UnmarshalTo(&crdSnap); err != nil { - return fmt.Errorf("failed to unmarshal CRD snapshot: %w", err) + caBundle, ok := secret.Data["ca.crt"] + if !ok || len(caBundle) == 0 { + return fmt.Errorf("CA certificate is empty in controller TLS secret") } conversionConfig := map[string]interface{}{ @@ -117,7 +75,7 @@ func reconcile(ctx context.Context, input *pkg.HookInput) error { "path": "/convert", "port": 443, }, - "caBundle": secretSnap.CA, + "caBundle": string(caBundle), }, "conversionReviewVersions": []string{"v1"}, }, @@ -132,7 +90,7 @@ func reconcile(ctx context.Context, input *pkg.HookInput) error { } input.PatchCollector.JSONPatch(patch, "apiextensions.k8s.io/v1", "CustomResourceDefinition", "", crdName) - input.Logger.Info("Successfully injected conversion webhook configuration into CRD %s", crdName) + input.Logger.Info("Successfully injected conversion webhook configuration into CRD", slog.String("crd", crdName)) return nil } From 5c6f3a90436dea1f91ca0734d7997a05ac800eb3 Mon Sep 17 00:00:00 2001 From: Daniil Loktev Date: Tue, 28 Oct 2025 18:06:43 +0300 Subject: [PATCH 42/77] revert vmclass generic Signed-off-by: Daniil Loktev --- .../virtualization-controller/vmclasses-default.yaml | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/templates/virtualization-controller/vmclasses-default.yaml b/templates/virtualization-controller/vmclasses-default.yaml index 2bbf9c7288..f2beb27764 100644 --- a/templates/virtualization-controller/vmclasses-default.yaml +++ b/templates/virtualization-controller/vmclasses-default.yaml @@ -1,4 +1,4 @@ -apiVersion: virtualization.deckhouse.io/v1alpha3 +apiVersion: virtualization.deckhouse.io/v1alpha2 kind: VirtualMachineClass metadata: name: generic @@ -16,19 +16,19 @@ spec: min: 1 max: 4 dedicatedCores: [false] - coreFractions: ["5%", "10%", "20%", "50%", "100%"] + coreFractions: [5, 10, 20, 50, 100] - cores: min: 5 max: 8 dedicatedCores: [false] - coreFractions: ["20%", "50%", "100%"] + coreFractions: [20, 50, 100] - cores: min: 9 max: 16 dedicatedCores: [true, false] - coreFractions: ["50%", "100%"] + coreFractions: [50, 100] - cores: min: 17 max: 1024 dedicatedCores: [true, false] - coreFractions: ["100%"] + coreFractions: [100] From 5baf89c85a8830337fb98f2bf5ac8c261e87eff3 Mon Sep 17 00:00:00 2001 From: Daniil Loktev Date: Tue, 28 Oct 2025 19:34:57 +0300 Subject: [PATCH 43/77] wip Signed-off-by: Daniil Loktev --- .../pkg/hooks/inject-crd-conversion/hook.go | 26 ++++++++++++++----- 1 file changed, 20 insertions(+), 6 deletions(-) diff --git a/images/hooks/pkg/hooks/inject-crd-conversion/hook.go b/images/hooks/pkg/hooks/inject-crd-conversion/hook.go index d823ccde24..49cf98a4ac 100644 --- a/images/hooks/pkg/hooks/inject-crd-conversion/hook.go +++ b/images/hooks/pkg/hooks/inject-crd-conversion/hook.go @@ -29,27 +29,41 @@ import ( ) const ( - crdName = "virtualmachineclasses.virtualization.deckhouse.io" - controllerTLSSecretName = "virtualization-controller-tls" + crdName = "virtualmachineclasses.virtualization.deckhouse.io" + controllerTLSSecretName = "virtualization-controller-tls" + controllerDeploymentName = "virtualization-controller" + deploymentSnapshotName = "controller-deployment" ) var _ = registry.RegisterFunc(config, reconcile) var config = &pkg.HookConfig{ - OnAfterHelm: &pkg.OrderedConfig{Order: 10}, - Queue: fmt.Sprintf("modules/%s", settings.ModuleName), + Kubernetes: []pkg.KubernetesConfig{ + { + Name: deploymentSnapshotName, + APIVersion: "apps/v1", + Kind: "Deployment", + NameSelector: &pkg.NameSelector{ + MatchNames: []string{controllerDeploymentName}, + }, + NamespaceSelector: &pkg.NamespaceSelector{ + NameSelector: &pkg.NameSelector{ + MatchNames: []string{settings.ModuleNamespace}, + }, + }, + }, + }, + Queue: fmt.Sprintf("modules/%s", settings.ModuleName), } func reconcile(ctx context.Context, input *pkg.HookInput) error { input.Logger.Info("Start inject CRD conversion webhook configuration hook") - // Get Kubernetes client k8sClient, err := input.DC.GetK8sClient() if err != nil { return fmt.Errorf("get k8s client: %w", err) } - // Fetch the TLS secret directly secret := &corev1.Secret{} err = k8sClient.Get(ctx, types.NamespacedName{ Namespace: settings.ModuleNamespace, From f21d532c3cf4b24926291f5d2e9762b84921bd34 Mon Sep 17 00:00:00 2001 From: Daniil Loktev Date: Wed, 29 Oct 2025 10:45:38 +0300 Subject: [PATCH 44/77] wip Signed-off-by: Daniil Loktev --- images/hooks/pkg/hooks/inject-crd-conversion/hook.go | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/images/hooks/pkg/hooks/inject-crd-conversion/hook.go b/images/hooks/pkg/hooks/inject-crd-conversion/hook.go index 49cf98a4ac..359f01bed4 100644 --- a/images/hooks/pkg/hooks/inject-crd-conversion/hook.go +++ b/images/hooks/pkg/hooks/inject-crd-conversion/hook.go @@ -17,6 +17,7 @@ package inject_crd_conversion_cabundle import ( "context" + "encoding/base64" "fmt" "log/slog" @@ -89,7 +90,7 @@ func reconcile(ctx context.Context, input *pkg.HookInput) error { "path": "/convert", "port": 443, }, - "caBundle": string(caBundle), + "caBundle": base64.StdEncoding.EncodeToString(caBundle), }, "conversionReviewVersions": []string{"v1"}, }, From 4fe37f53528826b823601744f33b48b525a65b3f Mon Sep 17 00:00:00 2001 From: Daniil Loktev Date: Wed, 29 Oct 2025 11:11:01 +0300 Subject: [PATCH 45/77] wip Signed-off-by: Daniil Loktev --- .../hooks/pkg/hooks/inject-crd-conversion/hook.go | 13 +++++++++++++ .../vmclasses-default.yaml | 10 +++++----- 2 files changed, 18 insertions(+), 5 deletions(-) diff --git a/images/hooks/pkg/hooks/inject-crd-conversion/hook.go b/images/hooks/pkg/hooks/inject-crd-conversion/hook.go index 359f01bed4..0ee676bb03 100644 --- a/images/hooks/pkg/hooks/inject-crd-conversion/hook.go +++ b/images/hooks/pkg/hooks/inject-crd-conversion/hook.go @@ -26,6 +26,7 @@ import ( "github.com/deckhouse/module-sdk/pkg" "github.com/deckhouse/module-sdk/pkg/registry" corev1 "k8s.io/api/core/v1" + apiextensionsv1 "k8s.io/apiextensions-apiserver/pkg/apis/apiextensions/v1" "k8s.io/apimachinery/pkg/types" ) @@ -65,6 +66,18 @@ func reconcile(ctx context.Context, input *pkg.HookInput) error { return fmt.Errorf("get k8s client: %w", err) } + crd := &apiextensionsv1.CustomResourceDefinition{} + err = k8sClient.Get(ctx, types.NamespacedName{Name: crdName}, crd) + if err != nil { + input.Logger.Info("CRD not found, skipping conversion webhook injection", slog.Any("error", err)) + return nil + } + + if crd.Spec.Conversion != nil && crd.Spec.Conversion.Strategy == apiextensionsv1.WebhookConverter { + input.Logger.Info("CRD already has webhook conversion configured, skipping") + return nil + } + secret := &corev1.Secret{} err = k8sClient.Get(ctx, types.NamespacedName{ Namespace: settings.ModuleNamespace, diff --git a/templates/virtualization-controller/vmclasses-default.yaml b/templates/virtualization-controller/vmclasses-default.yaml index f2beb27764..2bbf9c7288 100644 --- a/templates/virtualization-controller/vmclasses-default.yaml +++ b/templates/virtualization-controller/vmclasses-default.yaml @@ -1,4 +1,4 @@ -apiVersion: virtualization.deckhouse.io/v1alpha2 +apiVersion: virtualization.deckhouse.io/v1alpha3 kind: VirtualMachineClass metadata: name: generic @@ -16,19 +16,19 @@ spec: min: 1 max: 4 dedicatedCores: [false] - coreFractions: [5, 10, 20, 50, 100] + coreFractions: ["5%", "10%", "20%", "50%", "100%"] - cores: min: 5 max: 8 dedicatedCores: [false] - coreFractions: [20, 50, 100] + coreFractions: ["20%", "50%", "100%"] - cores: min: 9 max: 16 dedicatedCores: [true, false] - coreFractions: [50, 100] + coreFractions: ["50%", "100%"] - cores: min: 17 max: 1024 dedicatedCores: [true, false] - coreFractions: [100] + coreFractions: ["100%"] From b30271b4eb97c73c502991d577f3fed688822604 Mon Sep 17 00:00:00 2001 From: Daniil Loktev Date: Wed, 29 Oct 2025 11:48:20 +0300 Subject: [PATCH 46/77] revert generic vmclass Signed-off-by: Daniil Loktev --- images/hooks/pkg/hooks/inject-crd-conversion/hook.go | 1 + .../virtualization-controller/vmclasses-default.yaml | 10 +++++----- 2 files changed, 6 insertions(+), 5 deletions(-) diff --git a/images/hooks/pkg/hooks/inject-crd-conversion/hook.go b/images/hooks/pkg/hooks/inject-crd-conversion/hook.go index 0ee676bb03..e62fbc4e7f 100644 --- a/images/hooks/pkg/hooks/inject-crd-conversion/hook.go +++ b/images/hooks/pkg/hooks/inject-crd-conversion/hook.go @@ -25,6 +25,7 @@ import ( "github.com/deckhouse/module-sdk/pkg" "github.com/deckhouse/module-sdk/pkg/registry" + appsv1 "k8s.io/api/apps/v1" corev1 "k8s.io/api/core/v1" apiextensionsv1 "k8s.io/apiextensions-apiserver/pkg/apis/apiextensions/v1" "k8s.io/apimachinery/pkg/types" diff --git a/templates/virtualization-controller/vmclasses-default.yaml b/templates/virtualization-controller/vmclasses-default.yaml index 2bbf9c7288..f2beb27764 100644 --- a/templates/virtualization-controller/vmclasses-default.yaml +++ b/templates/virtualization-controller/vmclasses-default.yaml @@ -1,4 +1,4 @@ -apiVersion: virtualization.deckhouse.io/v1alpha3 +apiVersion: virtualization.deckhouse.io/v1alpha2 kind: VirtualMachineClass metadata: name: generic @@ -16,19 +16,19 @@ spec: min: 1 max: 4 dedicatedCores: [false] - coreFractions: ["5%", "10%", "20%", "50%", "100%"] + coreFractions: [5, 10, 20, 50, 100] - cores: min: 5 max: 8 dedicatedCores: [false] - coreFractions: ["20%", "50%", "100%"] + coreFractions: [20, 50, 100] - cores: min: 9 max: 16 dedicatedCores: [true, false] - coreFractions: ["50%", "100%"] + coreFractions: [50, 100] - cores: min: 17 max: 1024 dedicatedCores: [true, false] - coreFractions: ["100%"] + coreFractions: [100] From 76c399cdb9e1f2de3e90c8f7020b9918829ca14c Mon Sep 17 00:00:00 2001 From: Daniil Loktev Date: Wed, 29 Oct 2025 11:55:59 +0300 Subject: [PATCH 47/77] wip Signed-off-by: Daniil Loktev --- images/hooks/pkg/hooks/inject-crd-conversion/hook.go | 1 - 1 file changed, 1 deletion(-) diff --git a/images/hooks/pkg/hooks/inject-crd-conversion/hook.go b/images/hooks/pkg/hooks/inject-crd-conversion/hook.go index e62fbc4e7f..0ee676bb03 100644 --- a/images/hooks/pkg/hooks/inject-crd-conversion/hook.go +++ b/images/hooks/pkg/hooks/inject-crd-conversion/hook.go @@ -25,7 +25,6 @@ import ( "github.com/deckhouse/module-sdk/pkg" "github.com/deckhouse/module-sdk/pkg/registry" - appsv1 "k8s.io/api/apps/v1" corev1 "k8s.io/api/core/v1" apiextensionsv1 "k8s.io/apiextensions-apiserver/pkg/apis/apiextensions/v1" "k8s.io/apimachinery/pkg/types" From b4f781c0fa19945be4c25bedb075ed9e7ed69caa Mon Sep 17 00:00:00 2001 From: Daniil Loktev Date: Wed, 29 Oct 2025 13:04:51 +0300 Subject: [PATCH 48/77] remove hook, patch on startup Signed-off-by: Daniil Loktev --- .../virtualization-module-hooks/register.go | 1 - .../pkg/hooks/inject-crd-conversion/hook.go | 124 ------------------ .../cmd/virtualization-controller/main.go | 6 + .../pkg/crd/ensure_conversion.go | 77 +++++++++++ .../vmclasses-default.yaml | 10 +- 5 files changed, 88 insertions(+), 130 deletions(-) delete mode 100644 images/hooks/pkg/hooks/inject-crd-conversion/hook.go create mode 100644 images/virtualization-artifact/pkg/crd/ensure_conversion.go diff --git a/images/hooks/cmd/virtualization-module-hooks/register.go b/images/hooks/cmd/virtualization-module-hooks/register.go index 6e14bffb1d..bc0e1dc2a4 100644 --- a/images/hooks/cmd/virtualization-module-hooks/register.go +++ b/images/hooks/cmd/virtualization-module-hooks/register.go @@ -22,7 +22,6 @@ import ( _ "hooks/pkg/hooks/discovery-workload-nodes" _ "hooks/pkg/hooks/drop-openshift-labels" _ "hooks/pkg/hooks/generate-secret-for-dvcr" - _ "hooks/pkg/hooks/inject-crd-conversion" _ "hooks/pkg/hooks/migrate-delete-renamed-validation-admission-policy" _ "hooks/pkg/hooks/migrate-virthandler-kvm-node-labels" _ "hooks/pkg/hooks/prevent-default-vmclasses-deletion" diff --git a/images/hooks/pkg/hooks/inject-crd-conversion/hook.go b/images/hooks/pkg/hooks/inject-crd-conversion/hook.go deleted file mode 100644 index 0ee676bb03..0000000000 --- a/images/hooks/pkg/hooks/inject-crd-conversion/hook.go +++ /dev/null @@ -1,124 +0,0 @@ -/* -Copyright 2025 Flant JSC -Licensed under the Apache License, Version 2.0 (the "License"); -you may not use this file except in compliance with the License. -You may obtain a copy of the License at - - http://www.apache.org/licenses/LICENSE-2.0 - -Unless required by applicable law or agreed to in writing, software -distributed under the License is distributed on an "AS IS" BASIS, -WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -See the License for the specific language governing permissions and -limitations under the License. -*/ - -package inject_crd_conversion_cabundle - -import ( - "context" - "encoding/base64" - "fmt" - "log/slog" - - "hooks/pkg/settings" - - "github.com/deckhouse/module-sdk/pkg" - "github.com/deckhouse/module-sdk/pkg/registry" - corev1 "k8s.io/api/core/v1" - apiextensionsv1 "k8s.io/apiextensions-apiserver/pkg/apis/apiextensions/v1" - "k8s.io/apimachinery/pkg/types" -) - -const ( - crdName = "virtualmachineclasses.virtualization.deckhouse.io" - controllerTLSSecretName = "virtualization-controller-tls" - controllerDeploymentName = "virtualization-controller" - deploymentSnapshotName = "controller-deployment" -) - -var _ = registry.RegisterFunc(config, reconcile) - -var config = &pkg.HookConfig{ - Kubernetes: []pkg.KubernetesConfig{ - { - Name: deploymentSnapshotName, - APIVersion: "apps/v1", - Kind: "Deployment", - NameSelector: &pkg.NameSelector{ - MatchNames: []string{controllerDeploymentName}, - }, - NamespaceSelector: &pkg.NamespaceSelector{ - NameSelector: &pkg.NameSelector{ - MatchNames: []string{settings.ModuleNamespace}, - }, - }, - }, - }, - Queue: fmt.Sprintf("modules/%s", settings.ModuleName), -} - -func reconcile(ctx context.Context, input *pkg.HookInput) error { - input.Logger.Info("Start inject CRD conversion webhook configuration hook") - - k8sClient, err := input.DC.GetK8sClient() - if err != nil { - return fmt.Errorf("get k8s client: %w", err) - } - - crd := &apiextensionsv1.CustomResourceDefinition{} - err = k8sClient.Get(ctx, types.NamespacedName{Name: crdName}, crd) - if err != nil { - input.Logger.Info("CRD not found, skipping conversion webhook injection", slog.Any("error", err)) - return nil - } - - if crd.Spec.Conversion != nil && crd.Spec.Conversion.Strategy == apiextensionsv1.WebhookConverter { - input.Logger.Info("CRD already has webhook conversion configured, skipping") - return nil - } - - secret := &corev1.Secret{} - err = k8sClient.Get(ctx, types.NamespacedName{ - Namespace: settings.ModuleNamespace, - Name: controllerTLSSecretName, - }, secret) - if err != nil { - input.Logger.Info("Controller TLS secret not found, skipping conversion webhook injection", slog.Any("error", err)) - return nil - } - - caBundle, ok := secret.Data["ca.crt"] - if !ok || len(caBundle) == 0 { - return fmt.Errorf("CA certificate is empty in controller TLS secret") - } - - conversionConfig := map[string]interface{}{ - "strategy": "Webhook", - "webhook": map[string]interface{}{ - "clientConfig": map[string]interface{}{ - "service": map[string]interface{}{ - "name": "virtualization-controller", - "namespace": "d8-virtualization", - "path": "/convert", - "port": 443, - }, - "caBundle": base64.StdEncoding.EncodeToString(caBundle), - }, - "conversionReviewVersions": []string{"v1"}, - }, - } - - patch := []interface{}{ - map[string]interface{}{ - "op": "replace", - "path": "/spec/conversion", - "value": conversionConfig, - }, - } - - input.PatchCollector.JSONPatch(patch, "apiextensions.k8s.io/v1", "CustomResourceDefinition", "", crdName) - input.Logger.Info("Successfully injected conversion webhook configuration into CRD", slog.String("crd", crdName)) - - return nil -} diff --git a/images/virtualization-artifact/cmd/virtualization-controller/main.go b/images/virtualization-artifact/cmd/virtualization-controller/main.go index c67e5ab1a3..728cd9ea24 100644 --- a/images/virtualization-artifact/cmd/virtualization-controller/main.go +++ b/images/virtualization-artifact/cmd/virtualization-controller/main.go @@ -61,6 +61,7 @@ import ( "github.com/deckhouse/virtualization-controller/pkg/controller/vmsnapshot" "github.com/deckhouse/virtualization-controller/pkg/controller/volumemigration" workloadupdater "github.com/deckhouse/virtualization-controller/pkg/controller/workload-updater" + "github.com/deckhouse/virtualization-controller/pkg/crd" "github.com/deckhouse/virtualization-controller/pkg/featuregates" "github.com/deckhouse/virtualization-controller/pkg/logger" "github.com/deckhouse/virtualization-controller/pkg/migration" @@ -310,6 +311,11 @@ func main() { } mCtrl.Run(ctx) + if err = crd.EnsureVMClassConversionWebhook(ctx, mgr.GetClient(), controllerNamespace); err != nil { + log.Error("Failed to ensure VirtualMachineClass CRD conversion webhook", logger.SlogErr(err)) + os.Exit(1) + } + if err = indexer.IndexALL(ctx, mgr); err != nil { log.Error(err.Error()) os.Exit(1) diff --git a/images/virtualization-artifact/pkg/crd/ensure_conversion.go b/images/virtualization-artifact/pkg/crd/ensure_conversion.go new file mode 100644 index 0000000000..8b38ede67b --- /dev/null +++ b/images/virtualization-artifact/pkg/crd/ensure_conversion.go @@ -0,0 +1,77 @@ +/* +Copyright 2025 Flant JSC + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. +*/ + +package crd + +import ( + "context" + "encoding/base64" + "fmt" + "os" + + apiextensionsv1 "k8s.io/apiextensions-apiserver/pkg/apis/apiextensions/v1" + "k8s.io/utils/ptr" + "sigs.k8s.io/controller-runtime/pkg/client" + "sigs.k8s.io/controller-runtime/pkg/log" +) + +const ( + vmClassCRDName = "virtualmachineclasses.virtualization.deckhouse.io" + tlsCertPath = "/tmp/k8s-webhook-server/serving-certs/ca.crt" +) + +// EnsureVMClassConversionWebhook configures the VirtualMachineClass CRD to use webhook-based conversion. +// This allows Kubernetes to convert between v1alpha2 (storage version) and v1alpha3 (served version). +// Returns nil if conversion is already configured, otherwise returns an error. +func EnsureVMClassConversionWebhook(ctx context.Context, c client.Client, controllerNamespace string) error { + logger := log.FromContext(ctx).WithName("crd-conversion") + + crd := &apiextensionsv1.CustomResourceDefinition{} + if err := c.Get(ctx, client.ObjectKey{Name: vmClassCRDName}, crd); err != nil { + return fmt.Errorf("get VirtualMachineClass CRD: %w", err) + } + + caBytes, err := os.ReadFile(tlsCertPath) + if err != nil { + return fmt.Errorf("read TLS CA certificate from %s: %w", tlsCertPath, err) + } + + caBundle := base64.StdEncoding.EncodeToString(caBytes) + + crd.Spec.Conversion = &apiextensionsv1.CustomResourceConversion{ + Strategy: apiextensionsv1.WebhookConverter, + Webhook: &apiextensionsv1.WebhookConversion{ + ClientConfig: &apiextensionsv1.WebhookClientConfig{ + Service: &apiextensionsv1.ServiceReference{ + Name: "virtualization-controller", + Namespace: controllerNamespace, + Path: ptr.To("/convert"), + Port: ptr.To[int32](443), + }, + CABundle: []byte(caBundle), + }, + ConversionReviewVersions: []string{"v1"}, + }, + } + + if err := c.Update(ctx, crd); err != nil { + logger.Error(err, "Failed to update VirtualMachineClass CRD with conversion webhook configuration") + return fmt.Errorf("update CRD with conversion webhook: %w", err) + } + + logger.Info("Successfully configured VirtualMachineClass CRD with webhook conversion") + return nil +} diff --git a/templates/virtualization-controller/vmclasses-default.yaml b/templates/virtualization-controller/vmclasses-default.yaml index f2beb27764..2bbf9c7288 100644 --- a/templates/virtualization-controller/vmclasses-default.yaml +++ b/templates/virtualization-controller/vmclasses-default.yaml @@ -1,4 +1,4 @@ -apiVersion: virtualization.deckhouse.io/v1alpha2 +apiVersion: virtualization.deckhouse.io/v1alpha3 kind: VirtualMachineClass metadata: name: generic @@ -16,19 +16,19 @@ spec: min: 1 max: 4 dedicatedCores: [false] - coreFractions: [5, 10, 20, 50, 100] + coreFractions: ["5%", "10%", "20%", "50%", "100%"] - cores: min: 5 max: 8 dedicatedCores: [false] - coreFractions: [20, 50, 100] + coreFractions: ["20%", "50%", "100%"] - cores: min: 9 max: 16 dedicatedCores: [true, false] - coreFractions: [50, 100] + coreFractions: ["50%", "100%"] - cores: min: 17 max: 1024 dedicatedCores: [true, false] - coreFractions: [100] + coreFractions: ["100%"] From 5f9e6edbbbd84602695e9c2ddb29fd91a24ae4b8 Mon Sep 17 00:00:00 2001 From: Daniil Loktev Date: Wed, 29 Oct 2025 13:31:12 +0300 Subject: [PATCH 49/77] wip Signed-off-by: Daniil Loktev --- .../cmd/virtualization-controller/main.go | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/images/virtualization-artifact/cmd/virtualization-controller/main.go b/images/virtualization-artifact/cmd/virtualization-controller/main.go index 728cd9ea24..eb12610303 100644 --- a/images/virtualization-artifact/cmd/virtualization-controller/main.go +++ b/images/virtualization-artifact/cmd/virtualization-controller/main.go @@ -299,19 +299,19 @@ func main() { // Setup context to gracefully handle termination. ctx := signals.SetupSignalHandler() - onlyMigrationClient, err := client.New(cfg, client.Options{Scheme: scheme}) + preManagerClient, err := client.New(cfg, client.Options{Scheme: scheme}) if err != nil { log.Error(err.Error()) os.Exit(1) } - mCtrl, err := migration.NewController(onlyMigrationClient, log) + mCtrl, err := migration.NewController(preManagerClient, log) if err != nil { log.Error(err.Error()) os.Exit(1) } mCtrl.Run(ctx) - if err = crd.EnsureVMClassConversionWebhook(ctx, mgr.GetClient(), controllerNamespace); err != nil { + if err = crd.EnsureVMClassConversionWebhook(ctx, preManagerClient, controllerNamespace); err != nil { log.Error("Failed to ensure VirtualMachineClass CRD conversion webhook", logger.SlogErr(err)) os.Exit(1) } From 96e3c8d20954255df22f916ee80d076930be2efe Mon Sep 17 00:00:00 2001 From: Daniil Loktev Date: Wed, 29 Oct 2025 13:54:35 +0300 Subject: [PATCH 50/77] fix rbac Signed-off-by: Daniil Loktev --- templates/virtualization-controller/rbac-for-us.yaml | 8 ++++++++ 1 file changed, 8 insertions(+) diff --git a/templates/virtualization-controller/rbac-for-us.yaml b/templates/virtualization-controller/rbac-for-us.yaml index c80363ec94..5355971813 100644 --- a/templates/virtualization-controller/rbac-for-us.yaml +++ b/templates/virtualization-controller/rbac-for-us.yaml @@ -249,6 +249,14 @@ rules: - get - list - watch +- apiGroups: + - apiextensions.k8s.io + resources: + - customresourcedefinitions + verbs: + - get + - update + - patch --- apiVersion: rbac.authorization.k8s.io/v1 kind: ClusterRoleBinding From 6573c6fa80515b3d932293a0db04c2a25ba366b1 Mon Sep 17 00:00:00 2001 From: Daniil Loktev Date: Wed, 29 Oct 2025 14:04:59 +0300 Subject: [PATCH 51/77] wip Signed-off-by: Daniil Loktev --- .../virtualization-artifact/pkg/crd/ensure_conversion.go | 7 ++----- 1 file changed, 2 insertions(+), 5 deletions(-) diff --git a/images/virtualization-artifact/pkg/crd/ensure_conversion.go b/images/virtualization-artifact/pkg/crd/ensure_conversion.go index 8b38ede67b..cc8f1c90f7 100644 --- a/images/virtualization-artifact/pkg/crd/ensure_conversion.go +++ b/images/virtualization-artifact/pkg/crd/ensure_conversion.go @@ -18,7 +18,6 @@ package crd import ( "context" - "encoding/base64" "fmt" "os" @@ -44,13 +43,11 @@ func EnsureVMClassConversionWebhook(ctx context.Context, c client.Client, contro return fmt.Errorf("get VirtualMachineClass CRD: %w", err) } - caBytes, err := os.ReadFile(tlsCertPath) + caBundle, err := os.ReadFile(tlsCertPath) if err != nil { return fmt.Errorf("read TLS CA certificate from %s: %w", tlsCertPath, err) } - caBundle := base64.StdEncoding.EncodeToString(caBytes) - crd.Spec.Conversion = &apiextensionsv1.CustomResourceConversion{ Strategy: apiextensionsv1.WebhookConverter, Webhook: &apiextensionsv1.WebhookConversion{ @@ -61,7 +58,7 @@ func EnsureVMClassConversionWebhook(ctx context.Context, c client.Client, contro Path: ptr.To("/convert"), Port: ptr.To[int32](443), }, - CABundle: []byte(caBundle), + CABundle: caBundle, }, ConversionReviewVersions: []string{"v1"}, }, From 3855e46c0eb8cd68f1d161a9791837ae9c13b281 Mon Sep 17 00:00:00 2001 From: Daniil Loktev Date: Wed, 29 Oct 2025 16:40:23 +0300 Subject: [PATCH 52/77] fix discovery Signed-off-by: Daniil Loktev --- api/core/v1alpha3/virtual_machine_class.go | 2 +- api/core/v1alpha3/virtual_machine_class_conversion.go | 11 +++++++---- api/core/v1alpha3/zz_generated.deepcopy.go | 6 +++++- .../api/generated/openapi/zz_generated.openapi.go | 1 - 4 files changed, 13 insertions(+), 7 deletions(-) diff --git a/api/core/v1alpha3/virtual_machine_class.go b/api/core/v1alpha3/virtual_machine_class.go index 15f7651da8..ad94c35f91 100644 --- a/api/core/v1alpha3/virtual_machine_class.go +++ b/api/core/v1alpha3/virtual_machine_class.go @@ -101,7 +101,7 @@ type CPU struct { // +kubebuilder:example={mmx, vmx, sse2} Features []string `json:"features,omitempty"` // Create a CPU model based on intersecting CPU features for selected nodes. - Discovery CpuDiscovery `json:"discovery,omitempty"` + Discovery *CpuDiscovery `json:"discovery,omitempty"` } type CpuDiscovery struct { diff --git a/api/core/v1alpha3/virtual_machine_class_conversion.go b/api/core/v1alpha3/virtual_machine_class_conversion.go index 15a1336cc7..ceacea2824 100644 --- a/api/core/v1alpha3/virtual_machine_class_conversion.go +++ b/api/core/v1alpha3/virtual_machine_class_conversion.go @@ -62,12 +62,15 @@ func convertSpecV3ToV2(v3Spec VirtualMachineClassSpec) (v1alpha2.VirtualMachineC Type: v1alpha2.CPUType(v3Spec.CPU.Type), Model: v3Spec.CPU.Model, Features: v3Spec.CPU.Features, - Discovery: &v1alpha2.CpuDiscovery{ - NodeSelector: v3Spec.CPU.Discovery.NodeSelector, - }, }, } + if v3Spec.CPU.Discovery != nil { + v2Spec.CPU.Discovery = &v1alpha2.CpuDiscovery{ + NodeSelector: v3Spec.CPU.Discovery.NodeSelector, + } + } + if len(v3Spec.SizingPolicies) > 0 { v2Spec.SizingPolicies = make([]v1alpha2.SizingPolicy, len(v3Spec.SizingPolicies)) for i, v3Policy := range v3Spec.SizingPolicies { @@ -136,7 +139,7 @@ func convertSpecV2ToV3(v2Spec v1alpha2.VirtualMachineClassSpec) VirtualMachineCl } if v2Spec.CPU.Discovery != nil { - v3Spec.CPU.Discovery = CpuDiscovery{ + v3Spec.CPU.Discovery = &CpuDiscovery{ NodeSelector: v2Spec.CPU.Discovery.NodeSelector, } } diff --git a/api/core/v1alpha3/zz_generated.deepcopy.go b/api/core/v1alpha3/zz_generated.deepcopy.go index bccb1f69f5..7034c5d025 100644 --- a/api/core/v1alpha3/zz_generated.deepcopy.go +++ b/api/core/v1alpha3/zz_generated.deepcopy.go @@ -35,7 +35,11 @@ func (in *CPU) DeepCopyInto(out *CPU) { *out = make([]string, len(*in)) copy(*out, *in) } - in.Discovery.DeepCopyInto(&out.Discovery) + if in.Discovery != nil { + in, out := &in.Discovery, &out.Discovery + *out = new(CpuDiscovery) + (*in).DeepCopyInto(*out) + } return } diff --git a/images/virtualization-artifact/pkg/apiserver/api/generated/openapi/zz_generated.openapi.go b/images/virtualization-artifact/pkg/apiserver/api/generated/openapi/zz_generated.openapi.go index 3d56d6f663..fafb20b163 100644 --- a/images/virtualization-artifact/pkg/apiserver/api/generated/openapi/zz_generated.openapi.go +++ b/images/virtualization-artifact/pkg/apiserver/api/generated/openapi/zz_generated.openapi.go @@ -6112,7 +6112,6 @@ func schema_virtualization_api_core_v1alpha3_CPU(ref common.ReferenceCallback) c "discovery": { SchemaProps: spec.SchemaProps{ Description: "Create a CPU model based on intersecting CPU features for selected nodes.", - Default: map[string]interface{}{}, Ref: ref("github.com/deckhouse/virtualization/api/core/v1alpha3.CpuDiscovery"), }, }, From 25ccd68f10db8609e78c323ba58b2255e6f96c58 Mon Sep 17 00:00:00 2001 From: Daniil Loktev Date: Wed, 29 Oct 2025 17:48:38 +0300 Subject: [PATCH 53/77] fix validation, add tests Signed-off-by: Daniil Loktev --- api/core/v1alpha3/conversion_suite_test.go | 29 ++ api/core/v1alpha3/virtual_machine_class.go | 2 +- .../virtual_machine_class_conversion.go | 3 + .../virtual_machine_class_conversion_test.go | 399 ++++++++++++++++++ api/go.mod | 18 +- api/go.sum | 28 +- crds/virtualmachineclasses.yaml | 2 +- 7 files changed, 443 insertions(+), 38 deletions(-) create mode 100644 api/core/v1alpha3/conversion_suite_test.go create mode 100644 api/core/v1alpha3/virtual_machine_class_conversion_test.go diff --git a/api/core/v1alpha3/conversion_suite_test.go b/api/core/v1alpha3/conversion_suite_test.go new file mode 100644 index 0000000000..8499fededf --- /dev/null +++ b/api/core/v1alpha3/conversion_suite_test.go @@ -0,0 +1,29 @@ +/* +Copyright 2025 Flant JSC + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. +*/ + +package v1alpha3 + +import ( + "testing" + + . "github.com/onsi/ginkgo/v2" + . "github.com/onsi/gomega" +) + +func TestConversion(t *testing.T) { + RegisterFailHandler(Fail) + RunSpecs(t, "VirtualMachineClass Conversion Suite") +} diff --git a/api/core/v1alpha3/virtual_machine_class.go b/api/core/v1alpha3/virtual_machine_class.go index ad94c35f91..43f388cc7d 100644 --- a/api/core/v1alpha3/virtual_machine_class.go +++ b/api/core/v1alpha3/virtual_machine_class.go @@ -124,7 +124,7 @@ type SizingPolicy struct { } // CoreFractionValue represents CPU core fraction as a percentage string (e.g., "5%", "10%", "25%", "50%", "100%"). -// +kubebuilder:validation:Pattern=`^([1-9]|[1-9][0-9]|100)%?$` +// +kubebuilder:validation:Pattern=`^([1-9]|[1-9][0-9]|100)%$` type CoreFractionValue string type SizingPolicyMemory struct { diff --git a/api/core/v1alpha3/virtual_machine_class_conversion.go b/api/core/v1alpha3/virtual_machine_class_conversion.go index ceacea2824..03a5ba9530 100644 --- a/api/core/v1alpha3/virtual_machine_class_conversion.go +++ b/api/core/v1alpha3/virtual_machine_class_conversion.go @@ -113,6 +113,9 @@ func convertSpecV3ToV2(v3Spec VirtualMachineClassSpec) (v1alpha2.VirtualMachineC if err != nil { return v1alpha2.VirtualMachineClassSpec{}, fmt.Errorf("failed to parse core fraction: %w", err) } + if fractionInt < 1 || fractionInt > 100 { + return v1alpha2.VirtualMachineClassSpec{}, fmt.Errorf("core fraction value must be between 1 and 100, got %d", fractionInt) + } v2Policy.CoreFractions[j] = v1alpha2.CoreFractionValue(fractionInt) } } diff --git a/api/core/v1alpha3/virtual_machine_class_conversion_test.go b/api/core/v1alpha3/virtual_machine_class_conversion_test.go new file mode 100644 index 0000000000..d267178277 --- /dev/null +++ b/api/core/v1alpha3/virtual_machine_class_conversion_test.go @@ -0,0 +1,399 @@ +/* +Copyright 2025 Flant JSC + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. +*/ + +package v1alpha3 + +import ( + . "github.com/onsi/ginkgo/v2" + . "github.com/onsi/gomega" + corev1 "k8s.io/api/core/v1" + "k8s.io/apimachinery/pkg/api/resource" + metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" + + "github.com/deckhouse/virtualization/api/core/v1alpha2" +) + +var _ = Describe("VirtualMachineClass Conversion", func() { + Context("ConvertTo v1alpha2", func() { + DescribeTable("should convert valid CoreFractionValue strings", + func(coreFractions []CoreFractionValue) { + v3Class := &VirtualMachineClass{ + ObjectMeta: metav1.ObjectMeta{Name: "test-class"}, + Spec: VirtualMachineClassSpec{ + SizingPolicies: []SizingPolicy{ + { + CoreFractions: coreFractions, + Cores: &SizingPolicyCores{ + Min: 1, + Max: 8, + Step: 1, + }, + }, + }, + }, + } + + v2Class := &v1alpha2.VirtualMachineClass{} + err := v3Class.ConvertTo(v2Class) + + Expect(err).NotTo(HaveOccurred()) + Expect(v2Class.Name).To(Equal(v3Class.Name)) + Expect(v2Class.Spec.SizingPolicies).To(HaveLen(1)) + Expect(v2Class.Spec.SizingPolicies[0].CoreFractions).To(HaveLen(len(coreFractions))) + }, + Entry("single value", []CoreFractionValue{"5%"}), + Entry("multiple values", []CoreFractionValue{"5%", "10%", "25%", "50%", "100%"}), + Entry("minimum value 1%", []CoreFractionValue{"1%"}), + Entry("maximum value 100%", []CoreFractionValue{"100%"}), + Entry("mixed valid values", []CoreFractionValue{"1%", "50%", "100%"}), + Entry("value without percent sign", []CoreFractionValue{"50"}), + ) + + DescribeTable("should fail on invalid CoreFractionValue strings", + func(coreFractions []CoreFractionValue, expectedErrorSubstring string) { + v3Class := &VirtualMachineClass{ + ObjectMeta: metav1.ObjectMeta{Name: "test-class"}, + Spec: VirtualMachineClassSpec{ + SizingPolicies: []SizingPolicy{ + { + CoreFractions: coreFractions, + Cores: &SizingPolicyCores{ + Min: 1, + Max: 4, + Step: 1, + }, + }, + }, + }, + } + + v2Class := &v1alpha2.VirtualMachineClass{} + err := v3Class.ConvertTo(v2Class) + + Expect(err).To(HaveOccurred()) + Expect(err.Error()).To(ContainSubstring(expectedErrorSubstring)) + }, + Entry("value below minimum (0%)", []CoreFractionValue{"0%"}, "must be between 1 and 100, got 0"), + Entry("value above maximum (101%)", []CoreFractionValue{"101%"}, "must be between 1 and 100, got 101"), + Entry("negative value", []CoreFractionValue{"-5%"}, "must be between 1 and 100, got -5"), + Entry("non-numeric value", []CoreFractionValue{"abc%"}, "failed to parse core fraction"), + Entry("empty string", []CoreFractionValue{""}, "failed to parse core fraction"), + Entry("percent sign in wrong position", []CoreFractionValue{"%50"}, "failed to parse core fraction"), + Entry("one invalid in multiple", []CoreFractionValue{"5%", "150%", "100%"}, "must be between 1 and 100, got 150"), + ) + + It("should preserve ObjectMeta", func() { + v3Class := &VirtualMachineClass{ + ObjectMeta: metav1.ObjectMeta{ + Name: "test-class", + Namespace: "test-ns", + Labels: map[string]string{ + "test-label": "test-value", + }, + }, + Spec: VirtualMachineClassSpec{}, + } + + v2Class := &v1alpha2.VirtualMachineClass{} + err := v3Class.ConvertTo(v2Class) + + Expect(err).NotTo(HaveOccurred()) + Expect(v2Class.Name).To(Equal("test-class")) + Expect(v2Class.Namespace).To(Equal("test-ns")) + Expect(v2Class.Labels).To(HaveKeyWithValue("test-label", "test-value")) + }) + }) + + Context("ConvertFrom v1alpha2", func() { + DescribeTable("should convert v1alpha2 CoreFractionValue integers to percentage strings", + func(v2CoreFractions []v1alpha2.CoreFractionValue, expectedV3Values []CoreFractionValue) { + v2Class := &v1alpha2.VirtualMachineClass{ + ObjectMeta: metav1.ObjectMeta{Name: "test-class"}, + Spec: v1alpha2.VirtualMachineClassSpec{ + SizingPolicies: []v1alpha2.SizingPolicy{ + { + CoreFractions: v2CoreFractions, + Cores: &v1alpha2.SizingPolicyCores{ + Min: 1, + Max: 8, + Step: 1, + }, + }, + }, + }, + } + + v3Class := &VirtualMachineClass{} + err := v3Class.ConvertFrom(v2Class) + + Expect(err).NotTo(HaveOccurred()) + Expect(v3Class.Spec.SizingPolicies).To(HaveLen(1)) + Expect(v3Class.Spec.SizingPolicies[0].CoreFractions).To(Equal(expectedV3Values)) + }, + Entry("single value", []v1alpha2.CoreFractionValue{5}, []CoreFractionValue{"5%"}), + Entry("multiple values", []v1alpha2.CoreFractionValue{5, 10, 25, 50, 100}, []CoreFractionValue{"5%", "10%", "25%", "50%", "100%"}), + Entry("minimum value", []v1alpha2.CoreFractionValue{1}, []CoreFractionValue{"1%"}), + Entry("maximum value", []v1alpha2.CoreFractionValue{100}, []CoreFractionValue{"100%"}), + ) + }) + + Context("Round-trip conversion", func() { + DescribeTable("should preserve values through v2 -> v3 -> v2 conversion", + func(v2CoreFractions []v1alpha2.CoreFractionValue) { + originalV2 := &v1alpha2.VirtualMachineClass{ + ObjectMeta: metav1.ObjectMeta{Name: "test-class"}, + Spec: v1alpha2.VirtualMachineClassSpec{ + SizingPolicies: []v1alpha2.SizingPolicy{ + { + CoreFractions: v2CoreFractions, + Cores: &v1alpha2.SizingPolicyCores{ + Min: 1, + Max: 8, + Step: 1, + }, + }, + }, + }, + } + + v3Class := &VirtualMachineClass{} + err := v3Class.ConvertFrom(originalV2) + Expect(err).NotTo(HaveOccurred()) + + roundTripV2 := &v1alpha2.VirtualMachineClass{} + err = v3Class.ConvertTo(roundTripV2) + Expect(err).NotTo(HaveOccurred()) + + Expect(roundTripV2.Spec.SizingPolicies).To(HaveLen(1)) + Expect(roundTripV2.Spec.SizingPolicies[0].CoreFractions).To(Equal(v2CoreFractions)) + }, + Entry("single value", []v1alpha2.CoreFractionValue{5}), + Entry("multiple values", []v1alpha2.CoreFractionValue{5, 10, 25, 50, 100}), + Entry("boundary values", []v1alpha2.CoreFractionValue{1, 100}), + ) + }) + + Context("Full spec conversion", func() { + var ( + minMem, maxMem, stepMem resource.Quantity + minPerCoreMem, maxPerCoreMem resource.Quantity + ) + + BeforeEach(func() { + minMem = resource.MustParse("1Gi") + maxMem = resource.MustParse("8Gi") + stepMem = resource.MustParse("1Gi") + minPerCoreMem = resource.MustParse("512Mi") + maxPerCoreMem = resource.MustParse("2Gi") + }) + + It("should preserve all fields in ConvertTo", func() { + v3Class := &VirtualMachineClass{ + ObjectMeta: metav1.ObjectMeta{ + Name: "full-test-class", + Namespace: "test-namespace", + Labels: map[string]string{ + "test-label": "test-value", + }, + Annotations: map[string]string{ + "test-annotation": "test-value", + }, + }, + Spec: VirtualMachineClassSpec{ + NodeSelector: NodeSelector{ + MatchLabels: map[string]string{ + "node-role": "worker", + "zone": "us-east-1a", + }, + MatchExpressions: []corev1.NodeSelectorRequirement{ + { + Key: "cpu-type", + Operator: corev1.NodeSelectorOpIn, + Values: []string{"intel", "amd"}, + }, + }, + }, + Tolerations: []corev1.Toleration{ + { + Key: "dedicated", + Operator: corev1.TolerationOpEqual, + Value: "virtualization", + Effect: corev1.TaintEffectNoSchedule, + }, + }, + CPU: CPU{ + Type: CPUTypeModel, + Model: "IvyBridge", + Features: nil, + Discovery: nil, + }, + SizingPolicies: []SizingPolicy{ + { + Memory: &SizingPolicyMemory{ + MemoryMinMax: MemoryMinMax{ + Min: minMem, + Max: maxMem, + }, + Step: stepMem, + PerCore: SizingPolicyMemoryPerCore{ + MemoryMinMax: MemoryMinMax{ + Min: minPerCoreMem, + Max: maxPerCoreMem, + }, + }, + }, + CoreFractions: []CoreFractionValue{"5%", "10%", "50%", "100%"}, + DedicatedCores: []bool{false, true}, + Cores: &SizingPolicyCores{ + Min: 1, + Max: 16, + Step: 2, + }, + }, + }, + }, + } + + v2Class := &v1alpha2.VirtualMachineClass{} + err := v3Class.ConvertTo(v2Class) + Expect(err).NotTo(HaveOccurred()) + + Expect(v2Class.Name).To(Equal("full-test-class")) + Expect(v2Class.Namespace).To(Equal("test-namespace")) + Expect(v2Class.Labels).To(HaveKeyWithValue("test-label", "test-value")) + Expect(v2Class.Annotations).To(HaveKeyWithValue("test-annotation", "test-value")) + + Expect(v2Class.Spec.NodeSelector.MatchLabels).To(Equal(map[string]string{ + "node-role": "worker", + "zone": "us-east-1a", + })) + Expect(v2Class.Spec.NodeSelector.MatchExpressions).To(HaveLen(1)) + Expect(v2Class.Spec.NodeSelector.MatchExpressions[0].Key).To(Equal("cpu-type")) + + Expect(v2Class.Spec.Tolerations).To(HaveLen(1)) + Expect(v2Class.Spec.Tolerations[0].Key).To(Equal("dedicated")) + Expect(v2Class.Spec.Tolerations[0].Value).To(Equal("virtualization")) + + Expect(string(v2Class.Spec.CPU.Type)).To(Equal("Model")) + Expect(v2Class.Spec.CPU.Model).To(Equal("IvyBridge")) + + Expect(v2Class.Spec.SizingPolicies).To(HaveLen(1)) + policy := v2Class.Spec.SizingPolicies[0] + + Expect(policy.Memory).NotTo(BeNil()) + Expect(policy.Memory.Min.Equal(minMem)).To(BeTrue()) + Expect(policy.Memory.Max.Equal(maxMem)).To(BeTrue()) + Expect(policy.Memory.Step.Equal(stepMem)).To(BeTrue()) + Expect(policy.Memory.PerCore.Min.Equal(minPerCoreMem)).To(BeTrue()) + Expect(policy.Memory.PerCore.Max.Equal(maxPerCoreMem)).To(BeTrue()) + + Expect(policy.CoreFractions).To(Equal([]v1alpha2.CoreFractionValue{5, 10, 50, 100})) + Expect(policy.DedicatedCores).To(Equal([]bool{false, true})) + + Expect(policy.Cores).NotTo(BeNil()) + Expect(policy.Cores.Min).To(Equal(1)) + Expect(policy.Cores.Max).To(Equal(16)) + Expect(policy.Cores.Step).To(Equal(2)) + }) + + It("should preserve all fields in ConvertFrom", func() { + v2Class := &v1alpha2.VirtualMachineClass{ + ObjectMeta: metav1.ObjectMeta{ + Name: "full-test-class", + Namespace: "test-namespace", + Labels: map[string]string{ + "test-label": "test-value", + }, + }, + Spec: v1alpha2.VirtualMachineClassSpec{ + NodeSelector: v1alpha2.NodeSelector{ + MatchLabels: map[string]string{ + "node-role": "worker", + }, + }, + Tolerations: []corev1.Toleration{ + { + Key: "dedicated", + Operator: corev1.TolerationOpEqual, + Value: "virtualization", + Effect: corev1.TaintEffectNoSchedule, + }, + }, + CPU: v1alpha2.CPU{ + Type: v1alpha2.CPUTypeFeatures, + Features: []string{"mmx", "sse2", "vmx"}, + }, + SizingPolicies: []v1alpha2.SizingPolicy{ + { + Memory: &v1alpha2.SizingPolicyMemory{ + MemoryMinMax: v1alpha2.MemoryMinMax{ + Min: minMem, + Max: maxMem, + }, + Step: stepMem, + PerCore: v1alpha2.SizingPolicyMemoryPerCore{ + MemoryMinMax: v1alpha2.MemoryMinMax{ + Min: minPerCoreMem, + Max: maxPerCoreMem, + }, + }, + }, + CoreFractions: []v1alpha2.CoreFractionValue{10, 50, 100}, + DedicatedCores: []bool{true}, + Cores: &v1alpha2.SizingPolicyCores{ + Min: 2, + Max: 8, + Step: 2, + }, + }, + }, + }, + } + + v3Class := &VirtualMachineClass{} + err := v3Class.ConvertFrom(v2Class) + Expect(err).NotTo(HaveOccurred()) + + Expect(v3Class.Name).To(Equal("full-test-class")) + Expect(v3Class.Namespace).To(Equal("test-namespace")) + Expect(v3Class.Labels).To(HaveKeyWithValue("test-label", "test-value")) + + Expect(v3Class.Spec.NodeSelector.MatchLabels).To(HaveKeyWithValue("node-role", "worker")) + + Expect(v3Class.Spec.Tolerations).To(HaveLen(1)) + Expect(v3Class.Spec.Tolerations[0].Key).To(Equal("dedicated")) + + Expect(string(v3Class.Spec.CPU.Type)).To(Equal("Features")) + Expect(v3Class.Spec.CPU.Features).To(Equal([]string{"mmx", "sse2", "vmx"})) + + Expect(v3Class.Spec.SizingPolicies).To(HaveLen(1)) + policy := v3Class.Spec.SizingPolicies[0] + + Expect(policy.Memory).NotTo(BeNil()) + Expect(policy.Memory.Min.Equal(minMem)).To(BeTrue()) + Expect(policy.Memory.Max.Equal(maxMem)).To(BeTrue()) + Expect(policy.Memory.Step.Equal(stepMem)).To(BeTrue()) + + Expect(policy.CoreFractions).To(Equal([]CoreFractionValue{"10%", "50%", "100%"})) + Expect(policy.DedicatedCores).To(Equal([]bool{true})) + + Expect(policy.Cores).NotTo(BeNil()) + Expect(policy.Cores.Min).To(Equal(2)) + Expect(policy.Cores.Max).To(Equal(8)) + Expect(policy.Cores.Step).To(Equal(2)) + }) + }) +}) diff --git a/api/go.mod b/api/go.mod index eb3cd40deb..79b0495d1e 100644 --- a/api/go.mod +++ b/api/go.mod @@ -10,33 +10,32 @@ tool ( require ( github.com/gorilla/websocket v1.5.4-0.20250319132907-e064f32e3674 + github.com/onsi/ginkgo/v2 v2.23.3 + github.com/onsi/gomega v1.37.0 github.com/spf13/pflag v1.0.7 k8s.io/api v0.33.3 k8s.io/apiextensions-apiserver v0.33.3 k8s.io/apimachinery v0.33.3 k8s.io/client-go v0.33.3 - k8s.io/kube-openapi v0.0.0-20250701173324-9bd5c66d9911 kubevirt.io/api v1.3.1 + sigs.k8s.io/controller-runtime v0.21.0 ) require ( - github.com/beorn7/perks v1.0.1 // indirect - github.com/cespare/xxhash/v2 v2.3.0 // indirect github.com/davecgh/go-spew v1.1.2-0.20180830191138-d8f796af33cc // indirect github.com/emicklei/go-restful/v3 v3.11.0 // indirect - github.com/evanphx/json-patch/v5 v5.9.11 // indirect github.com/fatih/color v1.18.0 // indirect - github.com/fsnotify/fsnotify v1.7.0 // indirect github.com/fxamacker/cbor/v2 v2.7.0 // indirect github.com/go-logr/logr v1.4.2 // indirect github.com/go-openapi/jsonpointer v0.21.0 // indirect github.com/go-openapi/jsonreference v0.20.2 // indirect github.com/go-openapi/swag v0.23.0 // indirect + github.com/go-task/slim-sprig/v3 v3.0.0 // indirect github.com/gobuffalo/flect v1.0.3 // indirect github.com/gogo/protobuf v1.3.2 // indirect - github.com/google/btree v1.1.3 // indirect github.com/google/gnostic-models v0.7.0 // indirect github.com/google/go-cmp v0.7.0 // indirect + github.com/google/pprof v0.0.0-20241210010833-40e02aabc2ad // indirect github.com/google/uuid v1.6.0 // indirect github.com/inconshreveable/mousetrap v1.1.0 // indirect github.com/josharian/intern v1.0.0 // indirect @@ -50,10 +49,6 @@ require ( 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/prometheus/client_golang v1.22.0 // indirect - github.com/prometheus/client_model v0.6.1 // indirect - github.com/prometheus/common v0.62.0 // indirect - github.com/prometheus/procfs v0.15.1 // indirect github.com/spf13/cobra v1.9.1 // indirect github.com/x448/float16 v0.8.4 // indirect go.yaml.in/yaml/v2 v2.4.2 // indirect @@ -67,7 +62,6 @@ require ( golang.org/x/text v0.24.0 // indirect golang.org/x/time v0.9.0 // indirect golang.org/x/tools v0.32.0 // indirect - gomodules.xyz/jsonpatch/v2 v2.4.0 // indirect google.golang.org/protobuf v1.36.5 // indirect gopkg.in/evanphx/json-patch.v4 v4.12.0 // indirect gopkg.in/inf.v0 v0.9.1 // indirect @@ -76,10 +70,10 @@ 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/controller-lifecycle-operator-sdk/api v0.0.0-20220329064328-f3cc58c6ed90 // indirect - sigs.k8s.io/controller-runtime v0.21.0 // indirect sigs.k8s.io/controller-tools v0.18.0 // indirect sigs.k8s.io/json v0.0.0-20241010143419-9aa6b5e7a4b3 // indirect sigs.k8s.io/randfill v1.0.0 // indirect diff --git a/api/go.sum b/api/go.sum index ba78d13cd6..fd5f073e7c 100644 --- a/api/go.sum +++ b/api/go.sum @@ -3,11 +3,7 @@ github.com/BurntSushi/toml v0.3.1/go.mod h1:xHWCNGjB5oqiDr8zfno3MHue2Ht5sIBksp03 github.com/NYTimes/gziphandler v1.1.1/go.mod h1:n/CVRwUEOgIxrgPvAQhUUr9oeUtvrhMomdKFjzJNB0c= github.com/PuerkitoBio/purell v1.1.1/go.mod h1:c11w/QuzBsJSee3cPx9rAFu61PvFxuPbtSwDGJws/X0= github.com/PuerkitoBio/urlesc v0.0.0-20170810143723-de5bf2ad4578/go.mod h1:uGdkoq3SwY9Y+13GIhn11/XLaGBb4BfwItxLd5jeuXE= -github.com/beorn7/perks v1.0.1 h1:VlbKKnNfV8bJzeqoa4cOKqO6bYr3WgKZxO8Z16+hsOM= -github.com/beorn7/perks v1.0.1/go.mod h1:G2ZrVWU2WbWT9wwq4/hrbKbnv/1ERSJQ0ibhJ6rlkpw= github.com/census-instrumentation/opencensus-proto v0.2.1/go.mod h1:f6KPmirojxKA12rnyqOA5BBL4O983OfeGPqjHWSTneU= -github.com/cespare/xxhash/v2 v2.3.0 h1:UL815xU9SqsFlibzuggzjXhog7bL6oX9BbNZnL2UFvs= -github.com/cespare/xxhash/v2 v2.3.0/go.mod h1:VGX0DQ3Q6kWi7AoAeZDth3/j3BFtOZR5XLFGgcrjCOs= github.com/chromedp/cdproto v0.0.0-20230802225258-3cf4e6d46a89/go.mod h1:GKljq0VrfU4D5yc+2qA6OVr8pmO/MBbPEWqWQ/oqGEs= github.com/chromedp/chromedp v0.9.2/go.mod h1:LkSXJKONWTCHAfQasKFUZI+mxqS4tZqhmtGzzhLsnLs= github.com/chromedp/sysutil v1.0.0/go.mod h1:kgWmDdq8fTzXYcKIBqIYvRRTnYb9aNS9moAV0xufSww= @@ -32,10 +28,7 @@ github.com/emicklei/go-restful/v3 v3.11.0 h1:rAQeMHw1c7zTmncogyy8VvRZwtkmkZ4FxER github.com/emicklei/go-restful/v3 v3.11.0/go.mod h1:6n3XBCmQQb25CM2LCACGz8ukIrRry+4bhvbpWn3mrbc= github.com/envoyproxy/go-control-plane v0.9.1-0.20191026205805-5f8ba28d4473/go.mod h1:YTl/9mNaCwkRvm6d1a2C3ymFceY/DCBVvsKhRF0iEA4= github.com/envoyproxy/protoc-gen-validate v0.1.0/go.mod h1:iSmxcyjqTsJpI2R4NaDN7+kN2VEUnK/pcBlmesArF7c= -github.com/evanphx/json-patch v4.12.0+incompatible h1:4onqiflcdA9EOZ4RxV643DvftH5pOlLGNtQ5lPWQu84= github.com/evanphx/json-patch v4.12.0+incompatible/go.mod h1:50XU6AFN0ol/bzJsmQLiYLvXMP4fmwYFNcr97nuDLSk= -github.com/evanphx/json-patch/v5 v5.9.11 h1:/8HVnzMq13/3x9TPvjG08wUGqBTmZBsCWzjTM0wiaDU= -github.com/evanphx/json-patch/v5 v5.9.11/go.mod h1:3j+LviiESTElxA4p3EMKAB9HXj3/XEtnUf6OZxqIQTM= github.com/fatih/color v1.18.0 h1:S8gINlzdQ840/4pfAwic/ZE0djQEH3wM94VfqLTZcOM= github.com/fatih/color v1.18.0/go.mod h1:4FelSpRwEGDpQ12mAdzqdOukCy4u8WUtOY6lkT/6HfU= github.com/fsnotify/fsnotify v1.4.7/go.mod h1:jwhsz4b93w/PPRr/qN1Yymfu8t87LnFCMoQvtojpjFo= @@ -69,7 +62,6 @@ github.com/go-openapi/swag v0.22.3/go.mod h1:UzaqsxGiab7freDnrUUra0MwWfN/q7tE4j+ github.com/go-openapi/swag v0.23.0 h1:vsEVJDUo2hPJ2tu0/Xc+4noaxyEffXNIs3cOULZ+GrE= github.com/go-openapi/swag v0.23.0/go.mod h1:esZ8ITTYEsH1V2trKHjAN8Ai7xHb8RV+YSZ577vPjgQ= github.com/go-task/slim-sprig v0.0.0-20210107165309-348f09dbbbc0/go.mod h1:fyg7847qk6SyHyPtNmDHnmrv/HOrqktSC+C9fM+CJOE= -github.com/go-task/slim-sprig v0.0.0-20230315185526-52ccab3ef572 h1:tfuBGBXKqDEevZMzYi5KSi8KkcZtzBcTgAUUtapy0OI= github.com/go-task/slim-sprig v0.0.0-20230315185526-52ccab3ef572/go.mod h1:9Pwr4B2jHnOSGXyyzV8ROjYa2ojvAY6HCGYYfMoC3Ls= github.com/go-task/slim-sprig/v3 v3.0.0 h1:sUs3vkvUymDpBKi3qH1YSqBQk9+9D/8M2mN1vB6EwHI= github.com/go-task/slim-sprig/v3 v3.0.0/go.mod h1:W848ghGpv3Qj3dhTPRyJypKRiqCdHZiAzKg9hl15HA8= @@ -94,8 +86,6 @@ github.com/golang/protobuf v1.4.2/go.mod h1:oDoupMAO8OvCJWAcko0GGGIgR6R6ocIYbsSw github.com/golang/protobuf v1.5.0/go.mod h1:FsONVRAS9T7sI+LIUmWTfcYkHO4aIWwzhcaSAoJOfIk= github.com/golang/protobuf v1.5.2/go.mod h1:XVQd3VNwM+JqD3oG2Ue2ip4fOMUkwXdXDdiuN0vRsmY= github.com/golang/protobuf v1.5.3/go.mod h1:XVQd3VNwM+JqD3oG2Ue2ip4fOMUkwXdXDdiuN0vRsmY= -github.com/google/btree v1.1.3 h1:CVpQJjYgC4VbzxeGVHfvZrv1ctoYCAI8vbl07Fcxlyg= -github.com/google/btree v1.1.3/go.mod h1:qOPhT0dTNdNzV6Z/lhRX0YXUafgPLFUh+gZMl761Gm4= github.com/google/gnostic-models v0.7.0 h1:qwTtogB15McXDaNqTZdzPJRHvaVJlAl+HVQnLmJEJxo= github.com/google/gnostic-models v0.7.0/go.mod h1:whL5G0m6dmc5cPxKc5bdKdEN3UjI7OUGxBlw57miDrQ= github.com/google/go-cmp v0.2.0/go.mod h1:oXzfMopK8JAjlY9xF4vHSVASa0yLyX7SntLO5aqRK0M= @@ -113,8 +103,8 @@ github.com/google/gofuzz v1.1.0/go.mod h1:dBl0BpW6vV/+mYPU4Po3pmUjxk6FQPldtuIdl/ github.com/google/pprof v0.0.0-20210407192527-94a9f03dee38/go.mod h1:kpwsk12EmLew5upagYY7GY0pfYCcupk39gWOCRROcvE= github.com/google/pprof v0.0.0-20240424215950-a892ee059fd6/go.mod h1:kf6iHlnVGwgKolg33glAes7Yg/8iWP8ukqeldJSO7jw= github.com/google/pprof v0.0.0-20240727154555-813a5fbdbec8/go.mod h1:K1liHPHnj73Fdn/EKuT8nrFqBihUSKXoLYU0BuatOYo= -github.com/google/pprof v0.0.0-20241029153458-d1b30febd7db h1:097atOisP2aRj7vFgYQBbFN4U4JNXUNYpxael3UzMyo= -github.com/google/pprof v0.0.0-20241029153458-d1b30febd7db/go.mod h1:vavhavw2zAxS5dIdcRluK6cSGGPlZynqzFM8NdvU144= +github.com/google/pprof v0.0.0-20241210010833-40e02aabc2ad h1:a6HEuzUHeKH6hwfN/ZoQgRgVIWFJljSWa/zetS2WTvg= +github.com/google/pprof v0.0.0-20241210010833-40e02aabc2ad/go.mod h1:vavhavw2zAxS5dIdcRluK6cSGGPlZynqzFM8NdvU144= github.com/google/uuid v1.1.2/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo= github.com/google/uuid v1.6.0 h1:NIvaJDMOsjHA8n1jAhLSgzrAzy1Hgr+hNrb57e+94F0= github.com/google/uuid v1.6.0/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo= @@ -193,8 +183,8 @@ github.com/onsi/ginkgo/v2 v2.13.0/go.mod h1:TE309ZR8s5FsKKpuB1YAQYBzCaAfUgatB/xl github.com/onsi/ginkgo/v2 v2.17.1/go.mod h1:llBI3WDLL9Z6taip6f33H76YcWtJv+7R3HigUjbIBOs= github.com/onsi/ginkgo/v2 v2.17.2/go.mod h1:nP2DPOQoNsQmsVyv5rDA8JkXQoCs6goXIvr/PRJ1eCc= github.com/onsi/ginkgo/v2 v2.19.0/go.mod h1:rlwLi9PilAFJ8jCg9UE1QP6VBpd6/xj3SRC0d6TU0To= -github.com/onsi/ginkgo/v2 v2.21.0 h1:7rg/4f3rB88pb5obDgNZrNHrQ4e6WpjonchcpuBRnZM= -github.com/onsi/ginkgo/v2 v2.21.0/go.mod h1:7Du3c42kxCUegi0IImZ1wUQzMBVecgIHjR1C+NkhLQo= +github.com/onsi/ginkgo/v2 v2.23.3 h1:edHxnszytJ4lD9D5Jjc4tiDkPBZ3siDeJJkUZJJVkp0= +github.com/onsi/ginkgo/v2 v2.23.3/go.mod h1:zXTP6xIp3U8aVuXN8ENK9IXRaTjFnpVB9mGmaSRvxnM= github.com/onsi/gomega v1.7.1/go.mod h1:XdKZgCCFLUoM/7CFJVPcG8C1xQ1AJ0vpAezJrB7JYyY= github.com/onsi/gomega v1.10.1/go.mod h1:iN09h71vgCQne3DLsj+A5owkum+a2tYe+TOCB1ybHNo= github.com/onsi/gomega v1.17.0/go.mod h1:HnhC7FXeEQY45zxNK3PPoIUhzk/80Xly9PcubAlGdZY= @@ -228,15 +218,7 @@ github.com/pkg/errors v0.9.1 h1:FEBLx1zS214owpjy7qsBeixbURkuhQAwrK5UwLGTwt4= github.com/pkg/errors v0.9.1/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0= github.com/pmezard/go-difflib v1.0.0 h1:4DBwDE0NGyQoBHbLQYPwSUPoCMWR5BEzIk/f1lZbAQM= github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4= -github.com/prometheus/client_golang v1.22.0 h1:rb93p9lokFEsctTys46VnV1kLCDpVZ0a/Y92Vm0Zc6Q= -github.com/prometheus/client_golang v1.22.0/go.mod h1:R7ljNsLXhuQXYZYtw6GAE9AZg8Y7vEW5scdCXrWRXC0= github.com/prometheus/client_model v0.0.0-20190812154241-14fe0d1b01d4/go.mod h1:xMI15A0UPsDsEKsMN9yxemIoYk6Tm2C1GtYGdfGttqA= -github.com/prometheus/client_model v0.6.1 h1:ZKSh/rekM+n3CeS952MLRAdFwIKqeY8b62p8ais2e9E= -github.com/prometheus/client_model v0.6.1/go.mod h1:OrxVMOVHjw3lKMa8+x6HeMGkHMQyHDk9E3jmP2AmGiY= -github.com/prometheus/common v0.62.0 h1:xasJaQlnWAeyHdUBeGjXmutelfJHWMRr+Fg4QszZ2Io= -github.com/prometheus/common v0.62.0/go.mod h1:vyBcEuLSvWos9B1+CyL7JZ2up+uFzXhkqml0W5zIY1I= -github.com/prometheus/procfs v0.15.1 h1:YagwOFzUgYfKKHX6Dr+sHT7km/hxC76UB0learggepc= -github.com/prometheus/procfs v0.15.1/go.mod h1:fB45yRUv8NstnjriLhBQLuOUt+WW4BsoGhij/e3PBqk= github.com/rogpeppe/go-internal v1.9.0/go.mod h1:WtVeX8xhTBvf0smdhujwtBcq4Qrzq/fJaraNFVN+nFs= github.com/rogpeppe/go-internal v1.12.0/go.mod h1:E+RYuTGaKKdloAfM02xzb0FW3Paa99yedzYV+kq4uf4= github.com/rogpeppe/go-internal v1.13.1 h1:KvO1DLK/DRN07sQ1LQKScxyZJuNnedQ5/wKSR38lUII= @@ -505,8 +487,6 @@ golang.org/x/xerrors v0.0.0-20190717185122-a985d3407aa7/go.mod h1:I/5z698sn9Ka8T golang.org/x/xerrors v0.0.0-20191011141410-1b5146add898/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= golang.org/x/xerrors v0.0.0-20191204190536-9bdfabe68543/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= golang.org/x/xerrors v0.0.0-20200804184101-5ec99f83aff1/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= -gomodules.xyz/jsonpatch/v2 v2.4.0 h1:Ci3iUJyx9UeRx7CeFN8ARgGbkESwJK+KB9lLcWxY/Zw= -gomodules.xyz/jsonpatch/v2 v2.4.0/go.mod h1:AH3dM2RI6uoBZxn3LVrfvJ3E0/9dG4cSrbuBJT4moAY= google.golang.org/appengine v1.1.0/go.mod h1:EbEs0AVv82hx2wNQdGPgUI5lhzA/G0D9YwlJXL52JkM= google.golang.org/appengine v1.4.0/go.mod h1:xpcJRLb0r/rnEns0DIKYYv+WjYCduHsrkT7/EB5XEv4= google.golang.org/genproto v0.0.0-20180817151627-c66870c02cf8/go.mod h1:JiN7NxoALGmiZfu7CAH4rXhgtRTLTxftemlI0sWmxmc= diff --git a/crds/virtualmachineclasses.yaml b/crds/virtualmachineclasses.yaml index a79da4cfa0..11741dddd3 100644 --- a/crds/virtualmachineclasses.yaml +++ b/crds/virtualmachineclasses.yaml @@ -733,7 +733,7 @@ spec: CoreFractionValue represents CPU core fraction as a percentage string (e.g., "5%", "10%", "25%", "50%", "100%"). - pattern: ^([1-9]|[1-9][0-9]|100)%?$ + pattern: ^([1-9]|[1-9][0-9]|100)%$ type: string type: array cores: From a4e9967a748e08eac3fa7b566b75d138e16425cb Mon Sep 17 00:00:00 2001 From: Daniil Loktev Date: Wed, 29 Oct 2025 18:24:37 +0300 Subject: [PATCH 54/77] wip Signed-off-by: Daniil Loktev --- api/go.mod | 16 +++++++++++++--- api/go.sum | 27 +++++++++++++++++++++++++++ 2 files changed, 40 insertions(+), 3 deletions(-) diff --git a/api/go.mod b/api/go.mod index 79b0495d1e..9887a48cea 100644 --- a/api/go.mod +++ b/api/go.mod @@ -10,8 +10,8 @@ tool ( require ( github.com/gorilla/websocket v1.5.4-0.20250319132907-e064f32e3674 - github.com/onsi/ginkgo/v2 v2.23.3 - github.com/onsi/gomega v1.37.0 + github.com/onsi/ginkgo/v2 v2.22.0 + github.com/onsi/gomega v1.36.1 github.com/spf13/pflag v1.0.7 k8s.io/api v0.33.3 k8s.io/apiextensions-apiserver v0.33.3 @@ -22,9 +22,13 @@ require ( ) require ( + github.com/beorn7/perks v1.0.1 // indirect + github.com/cespare/xxhash/v2 v2.3.0 // indirect github.com/davecgh/go-spew v1.1.2-0.20180830191138-d8f796af33cc // indirect github.com/emicklei/go-restful/v3 v3.11.0 // indirect + github.com/evanphx/json-patch/v5 v5.9.11 // indirect github.com/fatih/color v1.18.0 // indirect + github.com/fsnotify/fsnotify v1.7.0 // indirect github.com/fxamacker/cbor/v2 v2.7.0 // indirect github.com/go-logr/logr v1.4.2 // indirect github.com/go-openapi/jsonpointer v0.21.0 // indirect @@ -33,6 +37,7 @@ require ( github.com/go-task/slim-sprig/v3 v3.0.0 // indirect github.com/gobuffalo/flect v1.0.3 // indirect github.com/gogo/protobuf v1.3.2 // indirect + github.com/google/btree v1.1.3 // indirect github.com/google/gnostic-models v0.7.0 // indirect github.com/google/go-cmp v0.7.0 // indirect github.com/google/pprof v0.0.0-20241210010833-40e02aabc2ad // indirect @@ -49,6 +54,10 @@ require ( 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/prometheus/client_golang v1.22.0 // indirect + github.com/prometheus/client_model v0.6.1 // indirect + github.com/prometheus/common v0.62.0 // indirect + github.com/prometheus/procfs v0.15.1 // indirect github.com/spf13/cobra v1.9.1 // indirect github.com/x448/float16 v0.8.4 // indirect go.yaml.in/yaml/v2 v2.4.2 // indirect @@ -62,6 +71,7 @@ require ( golang.org/x/text v0.24.0 // indirect golang.org/x/time v0.9.0 // indirect golang.org/x/tools v0.32.0 // indirect + gomodules.xyz/jsonpatch/v2 v2.4.0 // indirect google.golang.org/protobuf v1.36.5 // indirect gopkg.in/evanphx/json-patch.v4 v4.12.0 // indirect gopkg.in/inf.v0 v0.9.1 // indirect @@ -74,7 +84,7 @@ require ( k8s.io/utils v0.0.0-20241104100929-3ea5e8cea738 // indirect kubevirt.io/containerized-data-importer-api v1.57.0-alpha1 // 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/controller-tools v0.16.5 // indirect sigs.k8s.io/json v0.0.0-20241010143419-9aa6b5e7a4b3 // indirect sigs.k8s.io/randfill v1.0.0 // indirect sigs.k8s.io/structured-merge-diff/v4 v4.6.0 // indirect diff --git a/api/go.sum b/api/go.sum index fd5f073e7c..ba2f832275 100644 --- a/api/go.sum +++ b/api/go.sum @@ -3,7 +3,11 @@ github.com/BurntSushi/toml v0.3.1/go.mod h1:xHWCNGjB5oqiDr8zfno3MHue2Ht5sIBksp03 github.com/NYTimes/gziphandler v1.1.1/go.mod h1:n/CVRwUEOgIxrgPvAQhUUr9oeUtvrhMomdKFjzJNB0c= github.com/PuerkitoBio/purell v1.1.1/go.mod h1:c11w/QuzBsJSee3cPx9rAFu61PvFxuPbtSwDGJws/X0= github.com/PuerkitoBio/urlesc v0.0.0-20170810143723-de5bf2ad4578/go.mod h1:uGdkoq3SwY9Y+13GIhn11/XLaGBb4BfwItxLd5jeuXE= +github.com/beorn7/perks v1.0.1 h1:VlbKKnNfV8bJzeqoa4cOKqO6bYr3WgKZxO8Z16+hsOM= +github.com/beorn7/perks v1.0.1/go.mod h1:G2ZrVWU2WbWT9wwq4/hrbKbnv/1ERSJQ0ibhJ6rlkpw= github.com/census-instrumentation/opencensus-proto v0.2.1/go.mod h1:f6KPmirojxKA12rnyqOA5BBL4O983OfeGPqjHWSTneU= +github.com/cespare/xxhash/v2 v2.3.0 h1:UL815xU9SqsFlibzuggzjXhog7bL6oX9BbNZnL2UFvs= +github.com/cespare/xxhash/v2 v2.3.0/go.mod h1:VGX0DQ3Q6kWi7AoAeZDth3/j3BFtOZR5XLFGgcrjCOs= github.com/chromedp/cdproto v0.0.0-20230802225258-3cf4e6d46a89/go.mod h1:GKljq0VrfU4D5yc+2qA6OVr8pmO/MBbPEWqWQ/oqGEs= github.com/chromedp/chromedp v0.9.2/go.mod h1:LkSXJKONWTCHAfQasKFUZI+mxqS4tZqhmtGzzhLsnLs= github.com/chromedp/sysutil v1.0.0/go.mod h1:kgWmDdq8fTzXYcKIBqIYvRRTnYb9aNS9moAV0xufSww= @@ -28,7 +32,10 @@ github.com/emicklei/go-restful/v3 v3.11.0 h1:rAQeMHw1c7zTmncogyy8VvRZwtkmkZ4FxER github.com/emicklei/go-restful/v3 v3.11.0/go.mod h1:6n3XBCmQQb25CM2LCACGz8ukIrRry+4bhvbpWn3mrbc= github.com/envoyproxy/go-control-plane v0.9.1-0.20191026205805-5f8ba28d4473/go.mod h1:YTl/9mNaCwkRvm6d1a2C3ymFceY/DCBVvsKhRF0iEA4= github.com/envoyproxy/protoc-gen-validate v0.1.0/go.mod h1:iSmxcyjqTsJpI2R4NaDN7+kN2VEUnK/pcBlmesArF7c= +github.com/evanphx/json-patch v4.12.0+incompatible h1:4onqiflcdA9EOZ4RxV643DvftH5pOlLGNtQ5lPWQu84= github.com/evanphx/json-patch v4.12.0+incompatible/go.mod h1:50XU6AFN0ol/bzJsmQLiYLvXMP4fmwYFNcr97nuDLSk= +github.com/evanphx/json-patch/v5 v5.9.11 h1:/8HVnzMq13/3x9TPvjG08wUGqBTmZBsCWzjTM0wiaDU= +github.com/evanphx/json-patch/v5 v5.9.11/go.mod h1:3j+LviiESTElxA4p3EMKAB9HXj3/XEtnUf6OZxqIQTM= github.com/fatih/color v1.18.0 h1:S8gINlzdQ840/4pfAwic/ZE0djQEH3wM94VfqLTZcOM= github.com/fatih/color v1.18.0/go.mod h1:4FelSpRwEGDpQ12mAdzqdOukCy4u8WUtOY6lkT/6HfU= github.com/fsnotify/fsnotify v1.4.7/go.mod h1:jwhsz4b93w/PPRr/qN1Yymfu8t87LnFCMoQvtojpjFo= @@ -86,6 +93,8 @@ github.com/golang/protobuf v1.4.2/go.mod h1:oDoupMAO8OvCJWAcko0GGGIgR6R6ocIYbsSw github.com/golang/protobuf v1.5.0/go.mod h1:FsONVRAS9T7sI+LIUmWTfcYkHO4aIWwzhcaSAoJOfIk= github.com/golang/protobuf v1.5.2/go.mod h1:XVQd3VNwM+JqD3oG2Ue2ip4fOMUkwXdXDdiuN0vRsmY= github.com/golang/protobuf v1.5.3/go.mod h1:XVQd3VNwM+JqD3oG2Ue2ip4fOMUkwXdXDdiuN0vRsmY= +github.com/google/btree v1.1.3 h1:CVpQJjYgC4VbzxeGVHfvZrv1ctoYCAI8vbl07Fcxlyg= +github.com/google/btree v1.1.3/go.mod h1:qOPhT0dTNdNzV6Z/lhRX0YXUafgPLFUh+gZMl761Gm4= github.com/google/gnostic-models v0.7.0 h1:qwTtogB15McXDaNqTZdzPJRHvaVJlAl+HVQnLmJEJxo= github.com/google/gnostic-models v0.7.0/go.mod h1:whL5G0m6dmc5cPxKc5bdKdEN3UjI7OUGxBlw57miDrQ= github.com/google/go-cmp v0.2.0/go.mod h1:oXzfMopK8JAjlY9xF4vHSVASa0yLyX7SntLO5aqRK0M= @@ -183,6 +192,9 @@ github.com/onsi/ginkgo/v2 v2.13.0/go.mod h1:TE309ZR8s5FsKKpuB1YAQYBzCaAfUgatB/xl github.com/onsi/ginkgo/v2 v2.17.1/go.mod h1:llBI3WDLL9Z6taip6f33H76YcWtJv+7R3HigUjbIBOs= github.com/onsi/ginkgo/v2 v2.17.2/go.mod h1:nP2DPOQoNsQmsVyv5rDA8JkXQoCs6goXIvr/PRJ1eCc= github.com/onsi/ginkgo/v2 v2.19.0/go.mod h1:rlwLi9PilAFJ8jCg9UE1QP6VBpd6/xj3SRC0d6TU0To= +github.com/onsi/ginkgo/v2 v2.21.0 h1:7rg/4f3rB88pb5obDgNZrNHrQ4e6WpjonchcpuBRnZM= +github.com/onsi/ginkgo/v2 v2.21.0/go.mod h1:7Du3c42kxCUegi0IImZ1wUQzMBVecgIHjR1C+NkhLQo= +github.com/onsi/ginkgo/v2 v2.22.0/go.mod h1:7Du3c42kxCUegi0IImZ1wUQzMBVecgIHjR1C+NkhLQo= github.com/onsi/ginkgo/v2 v2.23.3 h1:edHxnszytJ4lD9D5Jjc4tiDkPBZ3siDeJJkUZJJVkp0= github.com/onsi/ginkgo/v2 v2.23.3/go.mod h1:zXTP6xIp3U8aVuXN8ENK9IXRaTjFnpVB9mGmaSRvxnM= github.com/onsi/gomega v1.7.1/go.mod h1:XdKZgCCFLUoM/7CFJVPcG8C1xQ1AJ0vpAezJrB7JYyY= @@ -206,6 +218,9 @@ github.com/onsi/gomega v1.27.10/go.mod h1:RsS8tutOdbdgzbPtzzATp12yT7kM5I5aElG3ev github.com/onsi/gomega v1.30.0/go.mod h1:9sxs+SwGrKI0+PWe4Fxa9tFQQBG5xSsSbMXOI8PPpoQ= github.com/onsi/gomega v1.33.0/go.mod h1:+925n5YtiFsLzzafLUHzVMBpvvRAzrydIBiSIxjX3wY= github.com/onsi/gomega v1.33.1/go.mod h1:U4R44UsT+9eLIaYRB2a5qajjtQYn0hauxvRm16AVYg0= +github.com/onsi/gomega v1.35.1 h1:Cwbd75ZBPxFSuZ6T+rN/WCb/gOc6YgFBXLlZLhC7Ds4= +github.com/onsi/gomega v1.35.1/go.mod h1:PvZbdDc8J6XJEpDK4HCuRBm8a6Fzp9/DmhC9C7yFlog= +github.com/onsi/gomega v1.36.1/go.mod h1:PvZbdDc8J6XJEpDK4HCuRBm8a6Fzp9/DmhC9C7yFlog= 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= @@ -218,7 +233,15 @@ github.com/pkg/errors v0.9.1 h1:FEBLx1zS214owpjy7qsBeixbURkuhQAwrK5UwLGTwt4= github.com/pkg/errors v0.9.1/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0= github.com/pmezard/go-difflib v1.0.0 h1:4DBwDE0NGyQoBHbLQYPwSUPoCMWR5BEzIk/f1lZbAQM= github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4= +github.com/prometheus/client_golang v1.22.0 h1:rb93p9lokFEsctTys46VnV1kLCDpVZ0a/Y92Vm0Zc6Q= +github.com/prometheus/client_golang v1.22.0/go.mod h1:R7ljNsLXhuQXYZYtw6GAE9AZg8Y7vEW5scdCXrWRXC0= github.com/prometheus/client_model v0.0.0-20190812154241-14fe0d1b01d4/go.mod h1:xMI15A0UPsDsEKsMN9yxemIoYk6Tm2C1GtYGdfGttqA= +github.com/prometheus/client_model v0.6.1 h1:ZKSh/rekM+n3CeS952MLRAdFwIKqeY8b62p8ais2e9E= +github.com/prometheus/client_model v0.6.1/go.mod h1:OrxVMOVHjw3lKMa8+x6HeMGkHMQyHDk9E3jmP2AmGiY= +github.com/prometheus/common v0.62.0 h1:xasJaQlnWAeyHdUBeGjXmutelfJHWMRr+Fg4QszZ2Io= +github.com/prometheus/common v0.62.0/go.mod h1:vyBcEuLSvWos9B1+CyL7JZ2up+uFzXhkqml0W5zIY1I= +github.com/prometheus/procfs v0.15.1 h1:YagwOFzUgYfKKHX6Dr+sHT7km/hxC76UB0learggepc= +github.com/prometheus/procfs v0.15.1/go.mod h1:fB45yRUv8NstnjriLhBQLuOUt+WW4BsoGhij/e3PBqk= github.com/rogpeppe/go-internal v1.9.0/go.mod h1:WtVeX8xhTBvf0smdhujwtBcq4Qrzq/fJaraNFVN+nFs= github.com/rogpeppe/go-internal v1.12.0/go.mod h1:E+RYuTGaKKdloAfM02xzb0FW3Paa99yedzYV+kq4uf4= github.com/rogpeppe/go-internal v1.13.1 h1:KvO1DLK/DRN07sQ1LQKScxyZJuNnedQ5/wKSR38lUII= @@ -487,6 +510,8 @@ golang.org/x/xerrors v0.0.0-20190717185122-a985d3407aa7/go.mod h1:I/5z698sn9Ka8T golang.org/x/xerrors v0.0.0-20191011141410-1b5146add898/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= golang.org/x/xerrors v0.0.0-20191204190536-9bdfabe68543/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= golang.org/x/xerrors v0.0.0-20200804184101-5ec99f83aff1/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= +gomodules.xyz/jsonpatch/v2 v2.4.0 h1:Ci3iUJyx9UeRx7CeFN8ARgGbkESwJK+KB9lLcWxY/Zw= +gomodules.xyz/jsonpatch/v2 v2.4.0/go.mod h1:AH3dM2RI6uoBZxn3LVrfvJ3E0/9dG4cSrbuBJT4moAY= google.golang.org/appengine v1.1.0/go.mod h1:EbEs0AVv82hx2wNQdGPgUI5lhzA/G0D9YwlJXL52JkM= google.golang.org/appengine v1.4.0/go.mod h1:xpcJRLb0r/rnEns0DIKYYv+WjYCduHsrkT7/EB5XEv4= google.golang.org/genproto v0.0.0-20180817151627-c66870c02cf8/go.mod h1:JiN7NxoALGmiZfu7CAH4rXhgtRTLTxftemlI0sWmxmc= @@ -574,8 +599,10 @@ kubevirt.io/containerized-data-importer-api v1.57.0-alpha1 h1:IWo12+ei3jltSN5jQN kubevirt.io/containerized-data-importer-api v1.57.0-alpha1/go.mod h1:Y/8ETgHS1GjO89bl682DPtQOYEU/1ctPFBz6Sjxm4DM= 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.20.1/go.mod h1:BrP3w158MwvB3ZbNpaAcIKkHQ7YGpYnzpoSTZ8E14WU= sigs.k8s.io/controller-runtime v0.21.0 h1:CYfjpEuicjUecRk+KAeyYh+ouUBn4llGyDYytIGcJS8= sigs.k8s.io/controller-runtime v0.21.0/go.mod h1:OSg14+F65eWqIu4DceX7k/+QRAbTTvxeQSNSOQpukWM= +sigs.k8s.io/controller-tools v0.16.5/go.mod h1:8vztuRVzs8IuuJqKqbXCSlXcw+lkAv/M2sTpg55qjMY= sigs.k8s.io/controller-tools v0.18.0 h1:rGxGZCZTV2wJreeRgqVoWab/mfcumTMmSwKzoM9xrsE= sigs.k8s.io/controller-tools v0.18.0/go.mod h1:gLKoiGBriyNh+x1rWtUQnakUYEujErjXs9pf+x/8n1U= sigs.k8s.io/json v0.0.0-20211020170558-c049b76a60c6/go.mod h1:p4QtZmO4uMYipTQNzagwnNoseA6OxSUutVw05NhYDRs= From a1f50cb3f41750714bd0f64052b0dee6e7ddce57 Mon Sep 17 00:00:00 2001 From: Daniil Loktev Date: Wed, 29 Oct 2025 18:35:58 +0300 Subject: [PATCH 55/77] wip Signed-off-by: Daniil Loktev --- images/hooks/go.mod | 2 +- images/hooks/go.sum | 3 ++- images/virtualization-artifact/go.mod | 2 +- images/virtualization-artifact/go.sum | 3 ++- 4 files changed, 6 insertions(+), 4 deletions(-) diff --git a/images/hooks/go.mod b/images/hooks/go.mod index 027e9646b4..0f65b8ba81 100644 --- a/images/hooks/go.mod +++ b/images/hooks/go.mod @@ -47,7 +47,7 @@ require ( github.com/google/gnostic-models v0.7.0 // indirect github.com/google/go-cmp v0.7.0 // indirect github.com/google/go-containerregistry v0.17.0 // indirect - github.com/google/pprof v0.0.0-20241029153458-d1b30febd7db // indirect + github.com/google/pprof v0.0.0-20241210010833-40e02aabc2ad // indirect github.com/google/uuid v1.6.0 // indirect github.com/inconshreveable/mousetrap v1.1.0 // indirect github.com/jmoiron/sqlx v1.3.5 // indirect diff --git a/images/hooks/go.sum b/images/hooks/go.sum index d39e4d9de0..0fa95aed83 100644 --- a/images/hooks/go.sum +++ b/images/hooks/go.sum @@ -147,8 +147,9 @@ github.com/google/pprof v0.0.0-20210407192527-94a9f03dee38/go.mod h1:kpwsk12EmLe github.com/google/pprof v0.0.0-20240424215950-a892ee059fd6/go.mod h1:kf6iHlnVGwgKolg33glAes7Yg/8iWP8ukqeldJSO7jw= github.com/google/pprof v0.0.0-20240727154555-813a5fbdbec8/go.mod h1:K1liHPHnj73Fdn/EKuT8nrFqBihUSKXoLYU0BuatOYo= github.com/google/pprof v0.0.0-20240827171923-fa2c70bbbfe5/go.mod h1:vavhavw2zAxS5dIdcRluK6cSGGPlZynqzFM8NdvU144= -github.com/google/pprof v0.0.0-20241029153458-d1b30febd7db h1:097atOisP2aRj7vFgYQBbFN4U4JNXUNYpxael3UzMyo= github.com/google/pprof v0.0.0-20241029153458-d1b30febd7db/go.mod h1:vavhavw2zAxS5dIdcRluK6cSGGPlZynqzFM8NdvU144= +github.com/google/pprof v0.0.0-20241210010833-40e02aabc2ad h1:a6HEuzUHeKH6hwfN/ZoQgRgVIWFJljSWa/zetS2WTvg= +github.com/google/pprof v0.0.0-20241210010833-40e02aabc2ad/go.mod h1:vavhavw2zAxS5dIdcRluK6cSGGPlZynqzFM8NdvU144= github.com/google/uuid v1.6.0 h1:NIvaJDMOsjHA8n1jAhLSgzrAzy1Hgr+hNrb57e+94F0= github.com/google/uuid v1.6.0/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo= github.com/googleapis/gnostic v0.5.5/go.mod h1:7+EbHbldMins07ALC74bsA81Ovc97DwqyJO1AENw9kA= diff --git a/images/virtualization-artifact/go.mod b/images/virtualization-artifact/go.mod index 7acf9e46f5..45fbb3f22a 100644 --- a/images/virtualization-artifact/go.mod +++ b/images/virtualization-artifact/go.mod @@ -83,7 +83,7 @@ require ( github.com/google/cel-go v0.23.2 // indirect github.com/google/gnostic-models v0.7.0 // indirect github.com/google/go-cmp v0.7.0 // indirect - github.com/google/pprof v0.0.0-20241029153458-d1b30febd7db // indirect + github.com/google/pprof v0.0.0-20241210010833-40e02aabc2ad // indirect github.com/google/uuid v1.6.0 github.com/gorilla/websocket v1.5.4-0.20250319132907-e064f32e3674 // indirect github.com/grpc-ecosystem/go-grpc-prometheus v1.2.0 // indirect diff --git a/images/virtualization-artifact/go.sum b/images/virtualization-artifact/go.sum index e1a15aaec0..f1157c9053 100644 --- a/images/virtualization-artifact/go.sum +++ b/images/virtualization-artifact/go.sum @@ -158,8 +158,9 @@ github.com/google/pprof v0.0.0-20210407192527-94a9f03dee38/go.mod h1:kpwsk12EmLe github.com/google/pprof v0.0.0-20240424215950-a892ee059fd6/go.mod h1:kf6iHlnVGwgKolg33glAes7Yg/8iWP8ukqeldJSO7jw= github.com/google/pprof v0.0.0-20240727154555-813a5fbdbec8/go.mod h1:K1liHPHnj73Fdn/EKuT8nrFqBihUSKXoLYU0BuatOYo= github.com/google/pprof v0.0.0-20240827171923-fa2c70bbbfe5/go.mod h1:vavhavw2zAxS5dIdcRluK6cSGGPlZynqzFM8NdvU144= -github.com/google/pprof v0.0.0-20241029153458-d1b30febd7db h1:097atOisP2aRj7vFgYQBbFN4U4JNXUNYpxael3UzMyo= github.com/google/pprof v0.0.0-20241029153458-d1b30febd7db/go.mod h1:vavhavw2zAxS5dIdcRluK6cSGGPlZynqzFM8NdvU144= +github.com/google/pprof v0.0.0-20241210010833-40e02aabc2ad h1:a6HEuzUHeKH6hwfN/ZoQgRgVIWFJljSWa/zetS2WTvg= +github.com/google/pprof v0.0.0-20241210010833-40e02aabc2ad/go.mod h1:vavhavw2zAxS5dIdcRluK6cSGGPlZynqzFM8NdvU144= github.com/google/uuid v1.6.0 h1:NIvaJDMOsjHA8n1jAhLSgzrAzy1Hgr+hNrb57e+94F0= github.com/google/uuid v1.6.0/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo= github.com/googleapis/gnostic v0.5.5/go.mod h1:7+EbHbldMins07ALC74bsA81Ovc97DwqyJO1AENw9kA= From 2bbc17501bcc0644cd6298a211a0d93de2f3ad77 Mon Sep 17 00:00:00 2001 From: Daniil Loktev Date: Thu, 30 Oct 2025 10:34:20 +0300 Subject: [PATCH 56/77] go mod tidy Signed-off-by: Daniil Loktev --- api/go.mod | 10 ---------- api/go.sum | 33 +++------------------------------ test/e2e/go.mod | 4 ++-- test/e2e/go.sum | 4 ++-- 4 files changed, 7 insertions(+), 44 deletions(-) diff --git a/api/go.mod b/api/go.mod index 9887a48cea..f64524d560 100644 --- a/api/go.mod +++ b/api/go.mod @@ -22,13 +22,9 @@ require ( ) require ( - github.com/beorn7/perks v1.0.1 // indirect - github.com/cespare/xxhash/v2 v2.3.0 // indirect github.com/davecgh/go-spew v1.1.2-0.20180830191138-d8f796af33cc // indirect github.com/emicklei/go-restful/v3 v3.11.0 // indirect - github.com/evanphx/json-patch/v5 v5.9.11 // indirect github.com/fatih/color v1.18.0 // indirect - github.com/fsnotify/fsnotify v1.7.0 // indirect github.com/fxamacker/cbor/v2 v2.7.0 // indirect github.com/go-logr/logr v1.4.2 // indirect github.com/go-openapi/jsonpointer v0.21.0 // indirect @@ -37,7 +33,6 @@ require ( github.com/go-task/slim-sprig/v3 v3.0.0 // indirect github.com/gobuffalo/flect v1.0.3 // indirect github.com/gogo/protobuf v1.3.2 // indirect - github.com/google/btree v1.1.3 // indirect github.com/google/gnostic-models v0.7.0 // indirect github.com/google/go-cmp v0.7.0 // indirect github.com/google/pprof v0.0.0-20241210010833-40e02aabc2ad // indirect @@ -54,10 +49,6 @@ require ( 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/prometheus/client_golang v1.22.0 // indirect - github.com/prometheus/client_model v0.6.1 // indirect - github.com/prometheus/common v0.62.0 // indirect - github.com/prometheus/procfs v0.15.1 // indirect github.com/spf13/cobra v1.9.1 // indirect github.com/x448/float16 v0.8.4 // indirect go.yaml.in/yaml/v2 v2.4.2 // indirect @@ -71,7 +62,6 @@ require ( golang.org/x/text v0.24.0 // indirect golang.org/x/time v0.9.0 // indirect golang.org/x/tools v0.32.0 // indirect - gomodules.xyz/jsonpatch/v2 v2.4.0 // indirect google.golang.org/protobuf v1.36.5 // indirect gopkg.in/evanphx/json-patch.v4 v4.12.0 // indirect gopkg.in/inf.v0 v0.9.1 // indirect diff --git a/api/go.sum b/api/go.sum index ba2f832275..ec3dce0a5a 100644 --- a/api/go.sum +++ b/api/go.sum @@ -3,11 +3,7 @@ github.com/BurntSushi/toml v0.3.1/go.mod h1:xHWCNGjB5oqiDr8zfno3MHue2Ht5sIBksp03 github.com/NYTimes/gziphandler v1.1.1/go.mod h1:n/CVRwUEOgIxrgPvAQhUUr9oeUtvrhMomdKFjzJNB0c= github.com/PuerkitoBio/purell v1.1.1/go.mod h1:c11w/QuzBsJSee3cPx9rAFu61PvFxuPbtSwDGJws/X0= github.com/PuerkitoBio/urlesc v0.0.0-20170810143723-de5bf2ad4578/go.mod h1:uGdkoq3SwY9Y+13GIhn11/XLaGBb4BfwItxLd5jeuXE= -github.com/beorn7/perks v1.0.1 h1:VlbKKnNfV8bJzeqoa4cOKqO6bYr3WgKZxO8Z16+hsOM= -github.com/beorn7/perks v1.0.1/go.mod h1:G2ZrVWU2WbWT9wwq4/hrbKbnv/1ERSJQ0ibhJ6rlkpw= github.com/census-instrumentation/opencensus-proto v0.2.1/go.mod h1:f6KPmirojxKA12rnyqOA5BBL4O983OfeGPqjHWSTneU= -github.com/cespare/xxhash/v2 v2.3.0 h1:UL815xU9SqsFlibzuggzjXhog7bL6oX9BbNZnL2UFvs= -github.com/cespare/xxhash/v2 v2.3.0/go.mod h1:VGX0DQ3Q6kWi7AoAeZDth3/j3BFtOZR5XLFGgcrjCOs= github.com/chromedp/cdproto v0.0.0-20230802225258-3cf4e6d46a89/go.mod h1:GKljq0VrfU4D5yc+2qA6OVr8pmO/MBbPEWqWQ/oqGEs= github.com/chromedp/chromedp v0.9.2/go.mod h1:LkSXJKONWTCHAfQasKFUZI+mxqS4tZqhmtGzzhLsnLs= github.com/chromedp/sysutil v1.0.0/go.mod h1:kgWmDdq8fTzXYcKIBqIYvRRTnYb9aNS9moAV0xufSww= @@ -32,10 +28,7 @@ github.com/emicklei/go-restful/v3 v3.11.0 h1:rAQeMHw1c7zTmncogyy8VvRZwtkmkZ4FxER github.com/emicklei/go-restful/v3 v3.11.0/go.mod h1:6n3XBCmQQb25CM2LCACGz8ukIrRry+4bhvbpWn3mrbc= github.com/envoyproxy/go-control-plane v0.9.1-0.20191026205805-5f8ba28d4473/go.mod h1:YTl/9mNaCwkRvm6d1a2C3ymFceY/DCBVvsKhRF0iEA4= github.com/envoyproxy/protoc-gen-validate v0.1.0/go.mod h1:iSmxcyjqTsJpI2R4NaDN7+kN2VEUnK/pcBlmesArF7c= -github.com/evanphx/json-patch v4.12.0+incompatible h1:4onqiflcdA9EOZ4RxV643DvftH5pOlLGNtQ5lPWQu84= github.com/evanphx/json-patch v4.12.0+incompatible/go.mod h1:50XU6AFN0ol/bzJsmQLiYLvXMP4fmwYFNcr97nuDLSk= -github.com/evanphx/json-patch/v5 v5.9.11 h1:/8HVnzMq13/3x9TPvjG08wUGqBTmZBsCWzjTM0wiaDU= -github.com/evanphx/json-patch/v5 v5.9.11/go.mod h1:3j+LviiESTElxA4p3EMKAB9HXj3/XEtnUf6OZxqIQTM= github.com/fatih/color v1.18.0 h1:S8gINlzdQ840/4pfAwic/ZE0djQEH3wM94VfqLTZcOM= github.com/fatih/color v1.18.0/go.mod h1:4FelSpRwEGDpQ12mAdzqdOukCy4u8WUtOY6lkT/6HfU= github.com/fsnotify/fsnotify v1.4.7/go.mod h1:jwhsz4b93w/PPRr/qN1Yymfu8t87LnFCMoQvtojpjFo= @@ -93,8 +86,6 @@ github.com/golang/protobuf v1.4.2/go.mod h1:oDoupMAO8OvCJWAcko0GGGIgR6R6ocIYbsSw github.com/golang/protobuf v1.5.0/go.mod h1:FsONVRAS9T7sI+LIUmWTfcYkHO4aIWwzhcaSAoJOfIk= github.com/golang/protobuf v1.5.2/go.mod h1:XVQd3VNwM+JqD3oG2Ue2ip4fOMUkwXdXDdiuN0vRsmY= github.com/golang/protobuf v1.5.3/go.mod h1:XVQd3VNwM+JqD3oG2Ue2ip4fOMUkwXdXDdiuN0vRsmY= -github.com/google/btree v1.1.3 h1:CVpQJjYgC4VbzxeGVHfvZrv1ctoYCAI8vbl07Fcxlyg= -github.com/google/btree v1.1.3/go.mod h1:qOPhT0dTNdNzV6Z/lhRX0YXUafgPLFUh+gZMl761Gm4= github.com/google/gnostic-models v0.7.0 h1:qwTtogB15McXDaNqTZdzPJRHvaVJlAl+HVQnLmJEJxo= github.com/google/gnostic-models v0.7.0/go.mod h1:whL5G0m6dmc5cPxKc5bdKdEN3UjI7OUGxBlw57miDrQ= github.com/google/go-cmp v0.2.0/go.mod h1:oXzfMopK8JAjlY9xF4vHSVASa0yLyX7SntLO5aqRK0M= @@ -192,11 +183,8 @@ github.com/onsi/ginkgo/v2 v2.13.0/go.mod h1:TE309ZR8s5FsKKpuB1YAQYBzCaAfUgatB/xl github.com/onsi/ginkgo/v2 v2.17.1/go.mod h1:llBI3WDLL9Z6taip6f33H76YcWtJv+7R3HigUjbIBOs= github.com/onsi/ginkgo/v2 v2.17.2/go.mod h1:nP2DPOQoNsQmsVyv5rDA8JkXQoCs6goXIvr/PRJ1eCc= github.com/onsi/ginkgo/v2 v2.19.0/go.mod h1:rlwLi9PilAFJ8jCg9UE1QP6VBpd6/xj3SRC0d6TU0To= -github.com/onsi/ginkgo/v2 v2.21.0 h1:7rg/4f3rB88pb5obDgNZrNHrQ4e6WpjonchcpuBRnZM= -github.com/onsi/ginkgo/v2 v2.21.0/go.mod h1:7Du3c42kxCUegi0IImZ1wUQzMBVecgIHjR1C+NkhLQo= +github.com/onsi/ginkgo/v2 v2.22.0 h1:Yed107/8DjTr0lKCNt7Dn8yQ6ybuDRQoMGrNFKzMfHg= github.com/onsi/ginkgo/v2 v2.22.0/go.mod h1:7Du3c42kxCUegi0IImZ1wUQzMBVecgIHjR1C+NkhLQo= -github.com/onsi/ginkgo/v2 v2.23.3 h1:edHxnszytJ4lD9D5Jjc4tiDkPBZ3siDeJJkUZJJVkp0= -github.com/onsi/ginkgo/v2 v2.23.3/go.mod h1:zXTP6xIp3U8aVuXN8ENK9IXRaTjFnpVB9mGmaSRvxnM= github.com/onsi/gomega v1.7.1/go.mod h1:XdKZgCCFLUoM/7CFJVPcG8C1xQ1AJ0vpAezJrB7JYyY= github.com/onsi/gomega v1.10.1/go.mod h1:iN09h71vgCQne3DLsj+A5owkum+a2tYe+TOCB1ybHNo= github.com/onsi/gomega v1.17.0/go.mod h1:HnhC7FXeEQY45zxNK3PPoIUhzk/80Xly9PcubAlGdZY= @@ -218,11 +206,8 @@ github.com/onsi/gomega v1.27.10/go.mod h1:RsS8tutOdbdgzbPtzzATp12yT7kM5I5aElG3ev github.com/onsi/gomega v1.30.0/go.mod h1:9sxs+SwGrKI0+PWe4Fxa9tFQQBG5xSsSbMXOI8PPpoQ= github.com/onsi/gomega v1.33.0/go.mod h1:+925n5YtiFsLzzafLUHzVMBpvvRAzrydIBiSIxjX3wY= github.com/onsi/gomega v1.33.1/go.mod h1:U4R44UsT+9eLIaYRB2a5qajjtQYn0hauxvRm16AVYg0= -github.com/onsi/gomega v1.35.1 h1:Cwbd75ZBPxFSuZ6T+rN/WCb/gOc6YgFBXLlZLhC7Ds4= -github.com/onsi/gomega v1.35.1/go.mod h1:PvZbdDc8J6XJEpDK4HCuRBm8a6Fzp9/DmhC9C7yFlog= +github.com/onsi/gomega v1.36.1 h1:bJDPBO7ibjxcbHMgSCoo4Yj18UWbKDlLwX1x9sybDcw= github.com/onsi/gomega v1.36.1/go.mod h1:PvZbdDc8J6XJEpDK4HCuRBm8a6Fzp9/DmhC9C7yFlog= -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= @@ -233,15 +218,7 @@ github.com/pkg/errors v0.9.1 h1:FEBLx1zS214owpjy7qsBeixbURkuhQAwrK5UwLGTwt4= github.com/pkg/errors v0.9.1/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0= github.com/pmezard/go-difflib v1.0.0 h1:4DBwDE0NGyQoBHbLQYPwSUPoCMWR5BEzIk/f1lZbAQM= github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4= -github.com/prometheus/client_golang v1.22.0 h1:rb93p9lokFEsctTys46VnV1kLCDpVZ0a/Y92Vm0Zc6Q= -github.com/prometheus/client_golang v1.22.0/go.mod h1:R7ljNsLXhuQXYZYtw6GAE9AZg8Y7vEW5scdCXrWRXC0= github.com/prometheus/client_model v0.0.0-20190812154241-14fe0d1b01d4/go.mod h1:xMI15A0UPsDsEKsMN9yxemIoYk6Tm2C1GtYGdfGttqA= -github.com/prometheus/client_model v0.6.1 h1:ZKSh/rekM+n3CeS952MLRAdFwIKqeY8b62p8ais2e9E= -github.com/prometheus/client_model v0.6.1/go.mod h1:OrxVMOVHjw3lKMa8+x6HeMGkHMQyHDk9E3jmP2AmGiY= -github.com/prometheus/common v0.62.0 h1:xasJaQlnWAeyHdUBeGjXmutelfJHWMRr+Fg4QszZ2Io= -github.com/prometheus/common v0.62.0/go.mod h1:vyBcEuLSvWos9B1+CyL7JZ2up+uFzXhkqml0W5zIY1I= -github.com/prometheus/procfs v0.15.1 h1:YagwOFzUgYfKKHX6Dr+sHT7km/hxC76UB0learggepc= -github.com/prometheus/procfs v0.15.1/go.mod h1:fB45yRUv8NstnjriLhBQLuOUt+WW4BsoGhij/e3PBqk= github.com/rogpeppe/go-internal v1.9.0/go.mod h1:WtVeX8xhTBvf0smdhujwtBcq4Qrzq/fJaraNFVN+nFs= github.com/rogpeppe/go-internal v1.12.0/go.mod h1:E+RYuTGaKKdloAfM02xzb0FW3Paa99yedzYV+kq4uf4= github.com/rogpeppe/go-internal v1.13.1 h1:KvO1DLK/DRN07sQ1LQKScxyZJuNnedQ5/wKSR38lUII= @@ -510,8 +487,6 @@ golang.org/x/xerrors v0.0.0-20190717185122-a985d3407aa7/go.mod h1:I/5z698sn9Ka8T golang.org/x/xerrors v0.0.0-20191011141410-1b5146add898/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= golang.org/x/xerrors v0.0.0-20191204190536-9bdfabe68543/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= golang.org/x/xerrors v0.0.0-20200804184101-5ec99f83aff1/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= -gomodules.xyz/jsonpatch/v2 v2.4.0 h1:Ci3iUJyx9UeRx7CeFN8ARgGbkESwJK+KB9lLcWxY/Zw= -gomodules.xyz/jsonpatch/v2 v2.4.0/go.mod h1:AH3dM2RI6uoBZxn3LVrfvJ3E0/9dG4cSrbuBJT4moAY= google.golang.org/appengine v1.1.0/go.mod h1:EbEs0AVv82hx2wNQdGPgUI5lhzA/G0D9YwlJXL52JkM= google.golang.org/appengine v1.4.0/go.mod h1:xpcJRLb0r/rnEns0DIKYYv+WjYCduHsrkT7/EB5XEv4= google.golang.org/genproto v0.0.0-20180817151627-c66870c02cf8/go.mod h1:JiN7NxoALGmiZfu7CAH4rXhgtRTLTxftemlI0sWmxmc= @@ -599,12 +574,10 @@ kubevirt.io/containerized-data-importer-api v1.57.0-alpha1 h1:IWo12+ei3jltSN5jQN kubevirt.io/containerized-data-importer-api v1.57.0-alpha1/go.mod h1:Y/8ETgHS1GjO89bl682DPtQOYEU/1ctPFBz6Sjxm4DM= 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.20.1/go.mod h1:BrP3w158MwvB3ZbNpaAcIKkHQ7YGpYnzpoSTZ8E14WU= sigs.k8s.io/controller-runtime v0.21.0 h1:CYfjpEuicjUecRk+KAeyYh+ouUBn4llGyDYytIGcJS8= sigs.k8s.io/controller-runtime v0.21.0/go.mod h1:OSg14+F65eWqIu4DceX7k/+QRAbTTvxeQSNSOQpukWM= +sigs.k8s.io/controller-tools v0.16.5 h1:5k9FNRqziBPwqr17AMEPPV/En39ZBplLAdOwwQHruP4= sigs.k8s.io/controller-tools v0.16.5/go.mod h1:8vztuRVzs8IuuJqKqbXCSlXcw+lkAv/M2sTpg55qjMY= -sigs.k8s.io/controller-tools v0.18.0 h1:rGxGZCZTV2wJreeRgqVoWab/mfcumTMmSwKzoM9xrsE= -sigs.k8s.io/controller-tools v0.18.0/go.mod h1:gLKoiGBriyNh+x1rWtUQnakUYEujErjXs9pf+x/8n1U= sigs.k8s.io/json v0.0.0-20211020170558-c049b76a60c6/go.mod h1:p4QtZmO4uMYipTQNzagwnNoseA6OxSUutVw05NhYDRs= sigs.k8s.io/json v0.0.0-20221116044647-bc3834ca7abd/go.mod h1:B8JuhiUyNFVKdsE8h686QcCxMaH6HrOAZj4vswFpcB0= sigs.k8s.io/json v0.0.0-20241010143419-9aa6b5e7a4b3 h1:/Rv+M11QRah1itp8VhT6HoVx1Ray9eB4DBr+K+/sCJ8= diff --git a/test/e2e/go.mod b/test/e2e/go.mod index 34da7ca6ef..03f982b199 100644 --- a/test/e2e/go.mod +++ b/test/e2e/go.mod @@ -9,7 +9,6 @@ require ( github.com/deckhouse/virtualization/api v0.0.0-20240923080356-bb5809dba578 github.com/onsi/ginkgo/v2 v2.22.0 github.com/onsi/gomega v1.36.1 - golang.org/x/sync v0.14.0 gopkg.in/yaml.v3 v3.0.1 k8s.io/api v0.33.3 k8s.io/apimachinery v0.33.3 @@ -38,7 +37,7 @@ require ( github.com/google/btree v1.1.3 // indirect github.com/google/gnostic-models v0.7.0 // indirect github.com/google/go-cmp v0.7.0 // indirect - github.com/google/pprof v0.0.0-20241029153458-d1b30febd7db // indirect + github.com/google/pprof v0.0.0-20241210010833-40e02aabc2ad // indirect github.com/google/shlex v0.0.0-20191202100458-e7afc7fbc510 // indirect github.com/google/uuid v1.6.0 // indirect github.com/gorilla/websocket v1.5.4-0.20250319132907-e064f32e3674 // indirect @@ -64,6 +63,7 @@ require ( go.yaml.in/yaml/v3 v3.0.3 // indirect golang.org/x/net v0.39.0 // indirect golang.org/x/oauth2 v0.27.0 // indirect + golang.org/x/sync v0.14.0 // indirect golang.org/x/sys v0.33.0 // indirect golang.org/x/term v0.32.0 // indirect golang.org/x/text v0.25.0 // indirect diff --git a/test/e2e/go.sum b/test/e2e/go.sum index f59519457d..bcef76dedb 100644 --- a/test/e2e/go.sum +++ b/test/e2e/go.sum @@ -111,8 +111,8 @@ github.com/google/gofuzz v1.1.0/go.mod h1:dBl0BpW6vV/+mYPU4Po3pmUjxk6FQPldtuIdl/ github.com/google/pprof v0.0.0-20210407192527-94a9f03dee38/go.mod h1:kpwsk12EmLew5upagYY7GY0pfYCcupk39gWOCRROcvE= github.com/google/pprof v0.0.0-20240424215950-a892ee059fd6/go.mod h1:kf6iHlnVGwgKolg33glAes7Yg/8iWP8ukqeldJSO7jw= github.com/google/pprof v0.0.0-20240727154555-813a5fbdbec8/go.mod h1:K1liHPHnj73Fdn/EKuT8nrFqBihUSKXoLYU0BuatOYo= -github.com/google/pprof v0.0.0-20241029153458-d1b30febd7db h1:097atOisP2aRj7vFgYQBbFN4U4JNXUNYpxael3UzMyo= -github.com/google/pprof v0.0.0-20241029153458-d1b30febd7db/go.mod h1:vavhavw2zAxS5dIdcRluK6cSGGPlZynqzFM8NdvU144= +github.com/google/pprof v0.0.0-20241210010833-40e02aabc2ad h1:a6HEuzUHeKH6hwfN/ZoQgRgVIWFJljSWa/zetS2WTvg= +github.com/google/pprof v0.0.0-20241210010833-40e02aabc2ad/go.mod h1:vavhavw2zAxS5dIdcRluK6cSGGPlZynqzFM8NdvU144= github.com/google/shlex v0.0.0-20191202100458-e7afc7fbc510 h1:El6M4kTTCOh6aBiKaUGG7oYTSPP8MxqL4YI3kZKwcP4= github.com/google/shlex v0.0.0-20191202100458-e7afc7fbc510/go.mod h1:pupxD2MaaD3pAXIBCelhxNneeOaAeabZDe5s4K6zSpQ= github.com/google/uuid v1.1.2/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo= From b015808c90ab49af0e60dba68ab521f3887692de Mon Sep 17 00:00:00 2001 From: Daniil Loktev Date: Thu, 30 Oct 2025 15:02:52 +0300 Subject: [PATCH 57/77] fix transformers Signed-off-by: Daniil Loktev --- test/e2e/legacy/testdata/disk-resizing/transformer.yaml | 2 +- test/e2e/legacy/testdata/image-hotplug/base/transformer.yaml | 2 +- test/e2e/legacy/testdata/image-hotplug/transformer.yaml | 2 +- test/e2e/legacy/testdata/sizing-policy/base/transformer.yaml | 2 +- test/e2e/legacy/testdata/sizing-policy/transformer.yaml | 2 +- test/e2e/legacy/testdata/templates/transformer.yaml | 2 +- test/e2e/legacy/testdata/vd-snapshots/transformer.yaml | 2 +- test/e2e/legacy/testdata/vd-snapshots/vm/base/transformer.yaml | 2 +- test/e2e/legacy/testdata/vm-configuration/base/transformer.yaml | 2 +- test/e2e/legacy/testdata/vm-configuration/transformer.yaml | 2 +- .../legacy/testdata/vm-disk-attachment/base/transformer.yaml | 2 +- test/e2e/legacy/testdata/vm-disk-attachment/transformer.yaml | 2 +- test/e2e/legacy/testdata/vm-evacuation/transformer.yaml | 2 +- test/e2e/legacy/testdata/vm-evacuation/vm/base/transformer.yaml | 2 +- .../legacy/testdata/vm-label-annotation/base/transformer.yaml | 2 +- test/e2e/legacy/testdata/vm-label-annotation/transformer.yaml | 2 +- test/e2e/legacy/testdata/vm-migration-cancel/transformer.yaml | 2 +- .../testdata/vm-migration-cancel/vm/base/transformer.yaml | 2 +- test/e2e/legacy/testdata/vm-migration/transformer.yaml | 2 +- test/e2e/legacy/testdata/vm-migration/vm/base/transformer.yaml | 2 +- test/e2e/legacy/testdata/vm-restore-force/transformer.yaml | 2 +- .../legacy/testdata/vm-restore-force/vm/base/transformer.yaml | 2 +- test/e2e/legacy/testdata/vm-restore-safe/transformer.yaml | 2 +- .../legacy/testdata/vm-restore-safe/vm/base/transformer.yaml | 2 +- test/e2e/legacy/testdata/vm-versions/transformer.yaml | 2 +- test/e2e/legacy/testdata/vm-versions/vm/transformer.yaml | 2 +- test/e2e/legacy/testdata/vm-vpc/transformer.yaml | 2 +- test/e2e/legacy/testdata/vm-vpc/vm-bar/transformer.yaml | 2 +- test/e2e/legacy/testdata/vm-vpc/vm-foo/transformer.yaml | 2 +- 29 files changed, 29 insertions(+), 29 deletions(-) diff --git a/test/e2e/legacy/testdata/disk-resizing/transformer.yaml b/test/e2e/legacy/testdata/disk-resizing/transformer.yaml index e827a19238..ec70d37fcd 100644 --- a/test/e2e/legacy/testdata/disk-resizing/transformer.yaml +++ b/test/e2e/legacy/testdata/disk-resizing/transformer.yaml @@ -46,7 +46,7 @@ nameReference: - path: spec/virtualMachineName kind: VirtualMachineBlockDeviceAttachment - kind: VirtualMachineClass - version: v1alpha2 + version: v1alpha3 fieldSpecs: - path: spec/virtualMachineClassName kind: VirtualMachine diff --git a/test/e2e/legacy/testdata/image-hotplug/base/transformer.yaml b/test/e2e/legacy/testdata/image-hotplug/base/transformer.yaml index c70c289afa..1dc146a3af 100644 --- a/test/e2e/legacy/testdata/image-hotplug/base/transformer.yaml +++ b/test/e2e/legacy/testdata/image-hotplug/base/transformer.yaml @@ -48,7 +48,7 @@ nameReference: - path: spec/virtualMachineName kind: VirtualMachineBlockDeviceAttachment - kind: VirtualMachineClass - version: v1alpha2 + version: v1alpha3 fieldSpecs: - path: spec/virtualMachineClassName kind: VirtualMachine diff --git a/test/e2e/legacy/testdata/image-hotplug/transformer.yaml b/test/e2e/legacy/testdata/image-hotplug/transformer.yaml index e827a19238..ec70d37fcd 100644 --- a/test/e2e/legacy/testdata/image-hotplug/transformer.yaml +++ b/test/e2e/legacy/testdata/image-hotplug/transformer.yaml @@ -46,7 +46,7 @@ nameReference: - path: spec/virtualMachineName kind: VirtualMachineBlockDeviceAttachment - kind: VirtualMachineClass - version: v1alpha2 + version: v1alpha3 fieldSpecs: - path: spec/virtualMachineClassName kind: VirtualMachine diff --git a/test/e2e/legacy/testdata/sizing-policy/base/transformer.yaml b/test/e2e/legacy/testdata/sizing-policy/base/transformer.yaml index c70c289afa..1dc146a3af 100644 --- a/test/e2e/legacy/testdata/sizing-policy/base/transformer.yaml +++ b/test/e2e/legacy/testdata/sizing-policy/base/transformer.yaml @@ -48,7 +48,7 @@ nameReference: - path: spec/virtualMachineName kind: VirtualMachineBlockDeviceAttachment - kind: VirtualMachineClass - version: v1alpha2 + version: v1alpha3 fieldSpecs: - path: spec/virtualMachineClassName kind: VirtualMachine diff --git a/test/e2e/legacy/testdata/sizing-policy/transformer.yaml b/test/e2e/legacy/testdata/sizing-policy/transformer.yaml index e827a19238..ec70d37fcd 100644 --- a/test/e2e/legacy/testdata/sizing-policy/transformer.yaml +++ b/test/e2e/legacy/testdata/sizing-policy/transformer.yaml @@ -46,7 +46,7 @@ nameReference: - path: spec/virtualMachineName kind: VirtualMachineBlockDeviceAttachment - kind: VirtualMachineClass - version: v1alpha2 + version: v1alpha3 fieldSpecs: - path: spec/virtualMachineClassName kind: VirtualMachine diff --git a/test/e2e/legacy/testdata/templates/transformer.yaml b/test/e2e/legacy/testdata/templates/transformer.yaml index e827a19238..ec70d37fcd 100644 --- a/test/e2e/legacy/testdata/templates/transformer.yaml +++ b/test/e2e/legacy/testdata/templates/transformer.yaml @@ -46,7 +46,7 @@ nameReference: - path: spec/virtualMachineName kind: VirtualMachineBlockDeviceAttachment - kind: VirtualMachineClass - version: v1alpha2 + version: v1alpha3 fieldSpecs: - path: spec/virtualMachineClassName kind: VirtualMachine diff --git a/test/e2e/legacy/testdata/vd-snapshots/transformer.yaml b/test/e2e/legacy/testdata/vd-snapshots/transformer.yaml index e827a19238..ec70d37fcd 100644 --- a/test/e2e/legacy/testdata/vd-snapshots/transformer.yaml +++ b/test/e2e/legacy/testdata/vd-snapshots/transformer.yaml @@ -46,7 +46,7 @@ nameReference: - path: spec/virtualMachineName kind: VirtualMachineBlockDeviceAttachment - kind: VirtualMachineClass - version: v1alpha2 + version: v1alpha3 fieldSpecs: - path: spec/virtualMachineClassName kind: VirtualMachine diff --git a/test/e2e/legacy/testdata/vd-snapshots/vm/base/transformer.yaml b/test/e2e/legacy/testdata/vd-snapshots/vm/base/transformer.yaml index c70c289afa..1dc146a3af 100644 --- a/test/e2e/legacy/testdata/vd-snapshots/vm/base/transformer.yaml +++ b/test/e2e/legacy/testdata/vd-snapshots/vm/base/transformer.yaml @@ -48,7 +48,7 @@ nameReference: - path: spec/virtualMachineName kind: VirtualMachineBlockDeviceAttachment - kind: VirtualMachineClass - version: v1alpha2 + version: v1alpha3 fieldSpecs: - path: spec/virtualMachineClassName kind: VirtualMachine diff --git a/test/e2e/legacy/testdata/vm-configuration/base/transformer.yaml b/test/e2e/legacy/testdata/vm-configuration/base/transformer.yaml index c70c289afa..1dc146a3af 100644 --- a/test/e2e/legacy/testdata/vm-configuration/base/transformer.yaml +++ b/test/e2e/legacy/testdata/vm-configuration/base/transformer.yaml @@ -48,7 +48,7 @@ nameReference: - path: spec/virtualMachineName kind: VirtualMachineBlockDeviceAttachment - kind: VirtualMachineClass - version: v1alpha2 + version: v1alpha3 fieldSpecs: - path: spec/virtualMachineClassName kind: VirtualMachine diff --git a/test/e2e/legacy/testdata/vm-configuration/transformer.yaml b/test/e2e/legacy/testdata/vm-configuration/transformer.yaml index e827a19238..ec70d37fcd 100644 --- a/test/e2e/legacy/testdata/vm-configuration/transformer.yaml +++ b/test/e2e/legacy/testdata/vm-configuration/transformer.yaml @@ -46,7 +46,7 @@ nameReference: - path: spec/virtualMachineName kind: VirtualMachineBlockDeviceAttachment - kind: VirtualMachineClass - version: v1alpha2 + version: v1alpha3 fieldSpecs: - path: spec/virtualMachineClassName kind: VirtualMachine diff --git a/test/e2e/legacy/testdata/vm-disk-attachment/base/transformer.yaml b/test/e2e/legacy/testdata/vm-disk-attachment/base/transformer.yaml index c70c289afa..1dc146a3af 100644 --- a/test/e2e/legacy/testdata/vm-disk-attachment/base/transformer.yaml +++ b/test/e2e/legacy/testdata/vm-disk-attachment/base/transformer.yaml @@ -48,7 +48,7 @@ nameReference: - path: spec/virtualMachineName kind: VirtualMachineBlockDeviceAttachment - kind: VirtualMachineClass - version: v1alpha2 + version: v1alpha3 fieldSpecs: - path: spec/virtualMachineClassName kind: VirtualMachine diff --git a/test/e2e/legacy/testdata/vm-disk-attachment/transformer.yaml b/test/e2e/legacy/testdata/vm-disk-attachment/transformer.yaml index e827a19238..ec70d37fcd 100644 --- a/test/e2e/legacy/testdata/vm-disk-attachment/transformer.yaml +++ b/test/e2e/legacy/testdata/vm-disk-attachment/transformer.yaml @@ -46,7 +46,7 @@ nameReference: - path: spec/virtualMachineName kind: VirtualMachineBlockDeviceAttachment - kind: VirtualMachineClass - version: v1alpha2 + version: v1alpha3 fieldSpecs: - path: spec/virtualMachineClassName kind: VirtualMachine diff --git a/test/e2e/legacy/testdata/vm-evacuation/transformer.yaml b/test/e2e/legacy/testdata/vm-evacuation/transformer.yaml index e827a19238..ec70d37fcd 100644 --- a/test/e2e/legacy/testdata/vm-evacuation/transformer.yaml +++ b/test/e2e/legacy/testdata/vm-evacuation/transformer.yaml @@ -46,7 +46,7 @@ nameReference: - path: spec/virtualMachineName kind: VirtualMachineBlockDeviceAttachment - kind: VirtualMachineClass - version: v1alpha2 + version: v1alpha3 fieldSpecs: - path: spec/virtualMachineClassName kind: VirtualMachine diff --git a/test/e2e/legacy/testdata/vm-evacuation/vm/base/transformer.yaml b/test/e2e/legacy/testdata/vm-evacuation/vm/base/transformer.yaml index c70c289afa..1dc146a3af 100644 --- a/test/e2e/legacy/testdata/vm-evacuation/vm/base/transformer.yaml +++ b/test/e2e/legacy/testdata/vm-evacuation/vm/base/transformer.yaml @@ -48,7 +48,7 @@ nameReference: - path: spec/virtualMachineName kind: VirtualMachineBlockDeviceAttachment - kind: VirtualMachineClass - version: v1alpha2 + version: v1alpha3 fieldSpecs: - path: spec/virtualMachineClassName kind: VirtualMachine diff --git a/test/e2e/legacy/testdata/vm-label-annotation/base/transformer.yaml b/test/e2e/legacy/testdata/vm-label-annotation/base/transformer.yaml index c70c289afa..1dc146a3af 100644 --- a/test/e2e/legacy/testdata/vm-label-annotation/base/transformer.yaml +++ b/test/e2e/legacy/testdata/vm-label-annotation/base/transformer.yaml @@ -48,7 +48,7 @@ nameReference: - path: spec/virtualMachineName kind: VirtualMachineBlockDeviceAttachment - kind: VirtualMachineClass - version: v1alpha2 + version: v1alpha3 fieldSpecs: - path: spec/virtualMachineClassName kind: VirtualMachine diff --git a/test/e2e/legacy/testdata/vm-label-annotation/transformer.yaml b/test/e2e/legacy/testdata/vm-label-annotation/transformer.yaml index e827a19238..ec70d37fcd 100644 --- a/test/e2e/legacy/testdata/vm-label-annotation/transformer.yaml +++ b/test/e2e/legacy/testdata/vm-label-annotation/transformer.yaml @@ -46,7 +46,7 @@ nameReference: - path: spec/virtualMachineName kind: VirtualMachineBlockDeviceAttachment - kind: VirtualMachineClass - version: v1alpha2 + version: v1alpha3 fieldSpecs: - path: spec/virtualMachineClassName kind: VirtualMachine diff --git a/test/e2e/legacy/testdata/vm-migration-cancel/transformer.yaml b/test/e2e/legacy/testdata/vm-migration-cancel/transformer.yaml index e827a19238..ec70d37fcd 100644 --- a/test/e2e/legacy/testdata/vm-migration-cancel/transformer.yaml +++ b/test/e2e/legacy/testdata/vm-migration-cancel/transformer.yaml @@ -46,7 +46,7 @@ nameReference: - path: spec/virtualMachineName kind: VirtualMachineBlockDeviceAttachment - kind: VirtualMachineClass - version: v1alpha2 + version: v1alpha3 fieldSpecs: - path: spec/virtualMachineClassName kind: VirtualMachine diff --git a/test/e2e/legacy/testdata/vm-migration-cancel/vm/base/transformer.yaml b/test/e2e/legacy/testdata/vm-migration-cancel/vm/base/transformer.yaml index c70c289afa..1dc146a3af 100644 --- a/test/e2e/legacy/testdata/vm-migration-cancel/vm/base/transformer.yaml +++ b/test/e2e/legacy/testdata/vm-migration-cancel/vm/base/transformer.yaml @@ -48,7 +48,7 @@ nameReference: - path: spec/virtualMachineName kind: VirtualMachineBlockDeviceAttachment - kind: VirtualMachineClass - version: v1alpha2 + version: v1alpha3 fieldSpecs: - path: spec/virtualMachineClassName kind: VirtualMachine diff --git a/test/e2e/legacy/testdata/vm-migration/transformer.yaml b/test/e2e/legacy/testdata/vm-migration/transformer.yaml index e827a19238..ec70d37fcd 100644 --- a/test/e2e/legacy/testdata/vm-migration/transformer.yaml +++ b/test/e2e/legacy/testdata/vm-migration/transformer.yaml @@ -46,7 +46,7 @@ nameReference: - path: spec/virtualMachineName kind: VirtualMachineBlockDeviceAttachment - kind: VirtualMachineClass - version: v1alpha2 + version: v1alpha3 fieldSpecs: - path: spec/virtualMachineClassName kind: VirtualMachine diff --git a/test/e2e/legacy/testdata/vm-migration/vm/base/transformer.yaml b/test/e2e/legacy/testdata/vm-migration/vm/base/transformer.yaml index c70c289afa..1dc146a3af 100644 --- a/test/e2e/legacy/testdata/vm-migration/vm/base/transformer.yaml +++ b/test/e2e/legacy/testdata/vm-migration/vm/base/transformer.yaml @@ -48,7 +48,7 @@ nameReference: - path: spec/virtualMachineName kind: VirtualMachineBlockDeviceAttachment - kind: VirtualMachineClass - version: v1alpha2 + version: v1alpha3 fieldSpecs: - path: spec/virtualMachineClassName kind: VirtualMachine diff --git a/test/e2e/legacy/testdata/vm-restore-force/transformer.yaml b/test/e2e/legacy/testdata/vm-restore-force/transformer.yaml index e827a19238..ec70d37fcd 100644 --- a/test/e2e/legacy/testdata/vm-restore-force/transformer.yaml +++ b/test/e2e/legacy/testdata/vm-restore-force/transformer.yaml @@ -46,7 +46,7 @@ nameReference: - path: spec/virtualMachineName kind: VirtualMachineBlockDeviceAttachment - kind: VirtualMachineClass - version: v1alpha2 + version: v1alpha3 fieldSpecs: - path: spec/virtualMachineClassName kind: VirtualMachine diff --git a/test/e2e/legacy/testdata/vm-restore-force/vm/base/transformer.yaml b/test/e2e/legacy/testdata/vm-restore-force/vm/base/transformer.yaml index 2a24df6226..2659eb381a 100644 --- a/test/e2e/legacy/testdata/vm-restore-force/vm/base/transformer.yaml +++ b/test/e2e/legacy/testdata/vm-restore-force/vm/base/transformer.yaml @@ -48,7 +48,7 @@ nameReference: - path: spec/virtualMachineName kind: VirtualMachineBlockDeviceAttachment - kind: VirtualMachineClass - version: v1alpha2 + version: v1alpha3 fieldSpecs: - path: spec/virtualMachineClassName kind: VirtualMachine diff --git a/test/e2e/legacy/testdata/vm-restore-safe/transformer.yaml b/test/e2e/legacy/testdata/vm-restore-safe/transformer.yaml index e827a19238..ec70d37fcd 100644 --- a/test/e2e/legacy/testdata/vm-restore-safe/transformer.yaml +++ b/test/e2e/legacy/testdata/vm-restore-safe/transformer.yaml @@ -46,7 +46,7 @@ nameReference: - path: spec/virtualMachineName kind: VirtualMachineBlockDeviceAttachment - kind: VirtualMachineClass - version: v1alpha2 + version: v1alpha3 fieldSpecs: - path: spec/virtualMachineClassName kind: VirtualMachine diff --git a/test/e2e/legacy/testdata/vm-restore-safe/vm/base/transformer.yaml b/test/e2e/legacy/testdata/vm-restore-safe/vm/base/transformer.yaml index 2a24df6226..2659eb381a 100644 --- a/test/e2e/legacy/testdata/vm-restore-safe/vm/base/transformer.yaml +++ b/test/e2e/legacy/testdata/vm-restore-safe/vm/base/transformer.yaml @@ -48,7 +48,7 @@ nameReference: - path: spec/virtualMachineName kind: VirtualMachineBlockDeviceAttachment - kind: VirtualMachineClass - version: v1alpha2 + version: v1alpha3 fieldSpecs: - path: spec/virtualMachineClassName kind: VirtualMachine diff --git a/test/e2e/legacy/testdata/vm-versions/transformer.yaml b/test/e2e/legacy/testdata/vm-versions/transformer.yaml index e827a19238..ec70d37fcd 100644 --- a/test/e2e/legacy/testdata/vm-versions/transformer.yaml +++ b/test/e2e/legacy/testdata/vm-versions/transformer.yaml @@ -46,7 +46,7 @@ nameReference: - path: spec/virtualMachineName kind: VirtualMachineBlockDeviceAttachment - kind: VirtualMachineClass - version: v1alpha2 + version: v1alpha3 fieldSpecs: - path: spec/virtualMachineClassName kind: VirtualMachine diff --git a/test/e2e/legacy/testdata/vm-versions/vm/transformer.yaml b/test/e2e/legacy/testdata/vm-versions/vm/transformer.yaml index c70c289afa..1dc146a3af 100644 --- a/test/e2e/legacy/testdata/vm-versions/vm/transformer.yaml +++ b/test/e2e/legacy/testdata/vm-versions/vm/transformer.yaml @@ -48,7 +48,7 @@ nameReference: - path: spec/virtualMachineName kind: VirtualMachineBlockDeviceAttachment - kind: VirtualMachineClass - version: v1alpha2 + version: v1alpha3 fieldSpecs: - path: spec/virtualMachineClassName kind: VirtualMachine diff --git a/test/e2e/legacy/testdata/vm-vpc/transformer.yaml b/test/e2e/legacy/testdata/vm-vpc/transformer.yaml index e827a19238..ec70d37fcd 100644 --- a/test/e2e/legacy/testdata/vm-vpc/transformer.yaml +++ b/test/e2e/legacy/testdata/vm-vpc/transformer.yaml @@ -46,7 +46,7 @@ nameReference: - path: spec/virtualMachineName kind: VirtualMachineBlockDeviceAttachment - kind: VirtualMachineClass - version: v1alpha2 + version: v1alpha3 fieldSpecs: - path: spec/virtualMachineClassName kind: VirtualMachine diff --git a/test/e2e/legacy/testdata/vm-vpc/vm-bar/transformer.yaml b/test/e2e/legacy/testdata/vm-vpc/vm-bar/transformer.yaml index c70c289afa..1dc146a3af 100644 --- a/test/e2e/legacy/testdata/vm-vpc/vm-bar/transformer.yaml +++ b/test/e2e/legacy/testdata/vm-vpc/vm-bar/transformer.yaml @@ -48,7 +48,7 @@ nameReference: - path: spec/virtualMachineName kind: VirtualMachineBlockDeviceAttachment - kind: VirtualMachineClass - version: v1alpha2 + version: v1alpha3 fieldSpecs: - path: spec/virtualMachineClassName kind: VirtualMachine diff --git a/test/e2e/legacy/testdata/vm-vpc/vm-foo/transformer.yaml b/test/e2e/legacy/testdata/vm-vpc/vm-foo/transformer.yaml index c70c289afa..1dc146a3af 100644 --- a/test/e2e/legacy/testdata/vm-vpc/vm-foo/transformer.yaml +++ b/test/e2e/legacy/testdata/vm-vpc/vm-foo/transformer.yaml @@ -48,7 +48,7 @@ nameReference: - path: spec/virtualMachineName kind: VirtualMachineBlockDeviceAttachment - kind: VirtualMachineClass - version: v1alpha2 + version: v1alpha3 fieldSpecs: - path: spec/virtualMachineClassName kind: VirtualMachine From 1855184d00f372129b6e58ab6197c1ec7befce0a Mon Sep 17 00:00:00 2001 From: Daniil Loktev Date: Fri, 7 Nov 2025 11:17:28 +0300 Subject: [PATCH 58/77] fix validation message Signed-off-by: Daniil Loktev --- api/core/v1alpha3/virtual_machine_class.go | 2 +- crds/clustervirtualimages.yaml | 2 +- crds/virtualdisks.yaml | 2 +- crds/virtualimages.yaml | 2 +- crds/virtualmachineblockdeviceattachments.yaml | 2 +- crds/virtualmachineclasses.yaml | 8 ++++++-- crds/virtualmachineoperations.yaml | 2 +- crds/virtualmachinerestores.yaml | 2 +- crds/virtualmachinesnapshots.yaml | 2 +- 9 files changed, 14 insertions(+), 10 deletions(-) diff --git a/api/core/v1alpha3/virtual_machine_class.go b/api/core/v1alpha3/virtual_machine_class.go index 43f388cc7d..8071a1637c 100644 --- a/api/core/v1alpha3/virtual_machine_class.go +++ b/api/core/v1alpha3/virtual_machine_class.go @@ -124,7 +124,7 @@ type SizingPolicy struct { } // CoreFractionValue represents CPU core fraction as a percentage string (e.g., "5%", "10%", "25%", "50%", "100%"). -// +kubebuilder:validation:Pattern=`^([1-9]|[1-9][0-9]|100)%$` +// +kubebuilder:validation:XValidation:rule="self.matches('^([1-9]|[1-9][0-9]|100)%$')",message="must be a percentage from 1% to 100% (e.g., \"5%\", \"25%\", \"100%\")" type CoreFractionValue string type SizingPolicyMemory struct { diff --git a/crds/clustervirtualimages.yaml b/crds/clustervirtualimages.yaml index 93bc215d84..233ee5ca29 100644 --- a/crds/clustervirtualimages.yaml +++ b/crds/clustervirtualimages.yaml @@ -3,7 +3,7 @@ apiVersion: apiextensions.k8s.io/v1 kind: CustomResourceDefinition metadata: annotations: - controller-gen.kubebuilder.io/version: v0.18.0 + controller-gen.kubebuilder.io/version: v0.16.5 labels: backup.deckhouse.io/cluster-config: "true" heritage: deckhouse diff --git a/crds/virtualdisks.yaml b/crds/virtualdisks.yaml index c00c80d46b..10a8e480c2 100644 --- a/crds/virtualdisks.yaml +++ b/crds/virtualdisks.yaml @@ -3,7 +3,7 @@ apiVersion: apiextensions.k8s.io/v1 kind: CustomResourceDefinition metadata: annotations: - controller-gen.kubebuilder.io/version: v0.18.0 + controller-gen.kubebuilder.io/version: v0.16.5 labels: heritage: deckhouse module: virtualization diff --git a/crds/virtualimages.yaml b/crds/virtualimages.yaml index 700a9418b2..4503916cfd 100644 --- a/crds/virtualimages.yaml +++ b/crds/virtualimages.yaml @@ -3,7 +3,7 @@ apiVersion: apiextensions.k8s.io/v1 kind: CustomResourceDefinition metadata: annotations: - controller-gen.kubebuilder.io/version: v0.18.0 + controller-gen.kubebuilder.io/version: v0.16.5 labels: heritage: deckhouse module: virtualization diff --git a/crds/virtualmachineblockdeviceattachments.yaml b/crds/virtualmachineblockdeviceattachments.yaml index 939fc91607..45e8b70eb6 100644 --- a/crds/virtualmachineblockdeviceattachments.yaml +++ b/crds/virtualmachineblockdeviceattachments.yaml @@ -3,7 +3,7 @@ apiVersion: apiextensions.k8s.io/v1 kind: CustomResourceDefinition metadata: annotations: - controller-gen.kubebuilder.io/version: v0.18.0 + controller-gen.kubebuilder.io/version: v0.16.5 labels: heritage: deckhouse module: virtualization diff --git a/crds/virtualmachineclasses.yaml b/crds/virtualmachineclasses.yaml index 11741dddd3..6561a03dcb 100644 --- a/crds/virtualmachineclasses.yaml +++ b/crds/virtualmachineclasses.yaml @@ -3,7 +3,7 @@ apiVersion: apiextensions.k8s.io/v1 kind: CustomResourceDefinition metadata: annotations: - controller-gen.kubebuilder.io/version: v0.18.0 + controller-gen.kubebuilder.io/version: v0.16.5 labels: backup.deckhouse.io/cluster-config: "true" heritage: deckhouse @@ -733,8 +733,12 @@ spec: CoreFractionValue represents CPU core fraction as a percentage string (e.g., "5%", "10%", "25%", "50%", "100%"). - pattern: ^([1-9]|[1-9][0-9]|100)%$ type: string + x-kubernetes-validations: + - message: + must be a percentage from 1% to 100% (e.g., "5%", + "25%", "100%") + rule: self.matches('^([1-9]|[1-9][0-9]|100)%$') type: array cores: description: diff --git a/crds/virtualmachineoperations.yaml b/crds/virtualmachineoperations.yaml index c96023b308..a67b8e2f84 100644 --- a/crds/virtualmachineoperations.yaml +++ b/crds/virtualmachineoperations.yaml @@ -3,7 +3,7 @@ apiVersion: apiextensions.k8s.io/v1 kind: CustomResourceDefinition metadata: annotations: - controller-gen.kubebuilder.io/version: v0.18.0 + controller-gen.kubebuilder.io/version: v0.16.5 labels: heritage: deckhouse module: virtualization diff --git a/crds/virtualmachinerestores.yaml b/crds/virtualmachinerestores.yaml index eb848d5250..1d37016201 100644 --- a/crds/virtualmachinerestores.yaml +++ b/crds/virtualmachinerestores.yaml @@ -3,7 +3,7 @@ apiVersion: apiextensions.k8s.io/v1 kind: CustomResourceDefinition metadata: annotations: - controller-gen.kubebuilder.io/version: v0.18.0 + controller-gen.kubebuilder.io/version: v0.16.5 labels: heritage: deckhouse module: virtualization diff --git a/crds/virtualmachinesnapshots.yaml b/crds/virtualmachinesnapshots.yaml index c1b681a99e..dcac3a221e 100644 --- a/crds/virtualmachinesnapshots.yaml +++ b/crds/virtualmachinesnapshots.yaml @@ -3,7 +3,7 @@ apiVersion: apiextensions.k8s.io/v1 kind: CustomResourceDefinition metadata: annotations: - controller-gen.kubebuilder.io/version: v0.18.0 + controller-gen.kubebuilder.io/version: v0.16.5 labels: heritage: deckhouse module: virtualization From 6c747b2a6f49dd2391f99f15dfdbd8dc763b3f56 Mon Sep 17 00:00:00 2001 From: Daniil Loktev Date: Fri, 7 Nov 2025 12:57:50 +0300 Subject: [PATCH 59/77] Revert "fix validation message" This reverts commit 1855184d00f372129b6e58ab6197c1ec7befce0a. Signed-off-by: Daniil Loktev --- api/core/v1alpha3/virtual_machine_class.go | 2 +- crds/clustervirtualimages.yaml | 2 +- crds/virtualdisks.yaml | 2 +- crds/virtualimages.yaml | 2 +- crds/virtualmachineblockdeviceattachments.yaml | 2 +- crds/virtualmachineclasses.yaml | 8 ++------ crds/virtualmachineoperations.yaml | 2 +- crds/virtualmachinerestores.yaml | 2 +- crds/virtualmachinesnapshots.yaml | 2 +- 9 files changed, 10 insertions(+), 14 deletions(-) diff --git a/api/core/v1alpha3/virtual_machine_class.go b/api/core/v1alpha3/virtual_machine_class.go index 8071a1637c..43f388cc7d 100644 --- a/api/core/v1alpha3/virtual_machine_class.go +++ b/api/core/v1alpha3/virtual_machine_class.go @@ -124,7 +124,7 @@ type SizingPolicy struct { } // CoreFractionValue represents CPU core fraction as a percentage string (e.g., "5%", "10%", "25%", "50%", "100%"). -// +kubebuilder:validation:XValidation:rule="self.matches('^([1-9]|[1-9][0-9]|100)%$')",message="must be a percentage from 1% to 100% (e.g., \"5%\", \"25%\", \"100%\")" +// +kubebuilder:validation:Pattern=`^([1-9]|[1-9][0-9]|100)%$` type CoreFractionValue string type SizingPolicyMemory struct { diff --git a/crds/clustervirtualimages.yaml b/crds/clustervirtualimages.yaml index 233ee5ca29..93bc215d84 100644 --- a/crds/clustervirtualimages.yaml +++ b/crds/clustervirtualimages.yaml @@ -3,7 +3,7 @@ apiVersion: apiextensions.k8s.io/v1 kind: CustomResourceDefinition metadata: annotations: - controller-gen.kubebuilder.io/version: v0.16.5 + controller-gen.kubebuilder.io/version: v0.18.0 labels: backup.deckhouse.io/cluster-config: "true" heritage: deckhouse diff --git a/crds/virtualdisks.yaml b/crds/virtualdisks.yaml index 10a8e480c2..c00c80d46b 100644 --- a/crds/virtualdisks.yaml +++ b/crds/virtualdisks.yaml @@ -3,7 +3,7 @@ apiVersion: apiextensions.k8s.io/v1 kind: CustomResourceDefinition metadata: annotations: - controller-gen.kubebuilder.io/version: v0.16.5 + controller-gen.kubebuilder.io/version: v0.18.0 labels: heritage: deckhouse module: virtualization diff --git a/crds/virtualimages.yaml b/crds/virtualimages.yaml index 4503916cfd..700a9418b2 100644 --- a/crds/virtualimages.yaml +++ b/crds/virtualimages.yaml @@ -3,7 +3,7 @@ apiVersion: apiextensions.k8s.io/v1 kind: CustomResourceDefinition metadata: annotations: - controller-gen.kubebuilder.io/version: v0.16.5 + controller-gen.kubebuilder.io/version: v0.18.0 labels: heritage: deckhouse module: virtualization diff --git a/crds/virtualmachineblockdeviceattachments.yaml b/crds/virtualmachineblockdeviceattachments.yaml index 45e8b70eb6..939fc91607 100644 --- a/crds/virtualmachineblockdeviceattachments.yaml +++ b/crds/virtualmachineblockdeviceattachments.yaml @@ -3,7 +3,7 @@ apiVersion: apiextensions.k8s.io/v1 kind: CustomResourceDefinition metadata: annotations: - controller-gen.kubebuilder.io/version: v0.16.5 + controller-gen.kubebuilder.io/version: v0.18.0 labels: heritage: deckhouse module: virtualization diff --git a/crds/virtualmachineclasses.yaml b/crds/virtualmachineclasses.yaml index 6561a03dcb..11741dddd3 100644 --- a/crds/virtualmachineclasses.yaml +++ b/crds/virtualmachineclasses.yaml @@ -3,7 +3,7 @@ apiVersion: apiextensions.k8s.io/v1 kind: CustomResourceDefinition metadata: annotations: - controller-gen.kubebuilder.io/version: v0.16.5 + controller-gen.kubebuilder.io/version: v0.18.0 labels: backup.deckhouse.io/cluster-config: "true" heritage: deckhouse @@ -733,12 +733,8 @@ spec: CoreFractionValue represents CPU core fraction as a percentage string (e.g., "5%", "10%", "25%", "50%", "100%"). + pattern: ^([1-9]|[1-9][0-9]|100)%$ type: string - x-kubernetes-validations: - - message: - must be a percentage from 1% to 100% (e.g., "5%", - "25%", "100%") - rule: self.matches('^([1-9]|[1-9][0-9]|100)%$') type: array cores: description: diff --git a/crds/virtualmachineoperations.yaml b/crds/virtualmachineoperations.yaml index a67b8e2f84..c96023b308 100644 --- a/crds/virtualmachineoperations.yaml +++ b/crds/virtualmachineoperations.yaml @@ -3,7 +3,7 @@ apiVersion: apiextensions.k8s.io/v1 kind: CustomResourceDefinition metadata: annotations: - controller-gen.kubebuilder.io/version: v0.16.5 + controller-gen.kubebuilder.io/version: v0.18.0 labels: heritage: deckhouse module: virtualization diff --git a/crds/virtualmachinerestores.yaml b/crds/virtualmachinerestores.yaml index 1d37016201..eb848d5250 100644 --- a/crds/virtualmachinerestores.yaml +++ b/crds/virtualmachinerestores.yaml @@ -3,7 +3,7 @@ apiVersion: apiextensions.k8s.io/v1 kind: CustomResourceDefinition metadata: annotations: - controller-gen.kubebuilder.io/version: v0.16.5 + controller-gen.kubebuilder.io/version: v0.18.0 labels: heritage: deckhouse module: virtualization diff --git a/crds/virtualmachinesnapshots.yaml b/crds/virtualmachinesnapshots.yaml index dcac3a221e..c1b681a99e 100644 --- a/crds/virtualmachinesnapshots.yaml +++ b/crds/virtualmachinesnapshots.yaml @@ -3,7 +3,7 @@ apiVersion: apiextensions.k8s.io/v1 kind: CustomResourceDefinition metadata: annotations: - controller-gen.kubebuilder.io/version: v0.16.5 + controller-gen.kubebuilder.io/version: v0.18.0 labels: heritage: deckhouse module: virtualization From 569b5b8492b23ad5d90a0ba64095f0f107f3a509 Mon Sep 17 00:00:00 2001 From: Daniil Loktev Date: Fri, 7 Nov 2025 17:15:11 +0300 Subject: [PATCH 60/77] set v1alpha3 as storage version Signed-off-by: Daniil Loktev --- api/core/v1alpha2/virtual_machine_class.go | 1 - .../virtual_machine_class_conversion.go | 203 ++++++++++++++++- api/core/v1alpha3/virtual_machine_class.go | 1 + .../virtual_machine_class_conversion.go | 204 +----------------- crds/clustervirtualimages.yaml | 2 +- crds/virtualdisks.yaml | 2 +- crds/virtualimages.yaml | 2 +- .../virtualmachineblockdeviceattachments.yaml | 2 +- crds/virtualmachineclasses.yaml | 6 +- crds/virtualmachineoperations.yaml | 2 +- crds/virtualmachinerestores.yaml | 2 +- crds/virtualmachinesnapshots.yaml | 2 +- .../pkg/controller/vmclass/vmclass_webhook.go | 6 +- 13 files changed, 217 insertions(+), 218 deletions(-) diff --git a/api/core/v1alpha2/virtual_machine_class.go b/api/core/v1alpha2/virtual_machine_class.go index 41ffa49316..1df0a83122 100644 --- a/api/core/v1alpha2/virtual_machine_class.go +++ b/api/core/v1alpha2/virtual_machine_class.go @@ -36,7 +36,6 @@ const ( // +kubebuilder:metadata:labels={heritage=deckhouse,module=virtualization,backup.deckhouse.io/cluster-config=true} // +kubebuilder:subresource:status // +kubebuilder:resource:categories={virtualization-cluster},scope=Cluster,shortName={vmc,vmclass},singular=virtualmachineclass -// +kubebuilder:storageversion // +kubebuilder:printcolumn:name="Phase",type="string",JSONPath=".status.phase",description="VirtualMachineClass phase." // +kubebuilder:printcolumn:name="IsDefault",type="string",JSONPath=".metadata.annotations.virtualmachineclass\\.virtualization\\.deckhouse\\.io\\/is-default-class",description="Default class for virtual machines without specified class." // +kubebuilder:printcolumn:name="Age",type="date",JSONPath=".metadata.creationTimestamp",description="Time of resource creation." diff --git a/api/core/v1alpha2/virtual_machine_class_conversion.go b/api/core/v1alpha2/virtual_machine_class_conversion.go index 0a88b03f14..785bb29973 100644 --- a/api/core/v1alpha2/virtual_machine_class_conversion.go +++ b/api/core/v1alpha2/virtual_machine_class_conversion.go @@ -16,4 +16,205 @@ limitations under the License. package v1alpha2 -func (*VirtualMachineClass) Hub() {} +import ( + "fmt" + "strconv" + + "sigs.k8s.io/controller-runtime/pkg/conversion" + + "github.com/deckhouse/virtualization/api/core/v1alpha3" +) + +var _ conversion.Convertible = &VirtualMachineClass{} + +func (src *VirtualMachineClass) ConvertTo(dstRaw conversion.Hub) error { + dst := dstRaw.(*v1alpha3.VirtualMachineClass) + + dst.ObjectMeta = src.ObjectMeta + dst.Spec = convertSpecV2ToV3(src.Spec) + dst.Status = convertStatusV2ToV3(src.Status) + + return nil +} + +func (dst *VirtualMachineClass) ConvertFrom(srcRaw conversion.Hub) error { + src := srcRaw.(*v1alpha3.VirtualMachineClass) + + dst.ObjectMeta = src.ObjectMeta + convertedSpec, err := convertSpecV3ToV2(src.Spec) + if err != nil { + return err + } + dst.Spec = convertedSpec + dst.Status = convertStatusV3ToV2(src.Status) + + return nil +} +func convertSpecV3ToV2(v3Spec v1alpha3.VirtualMachineClassSpec) (VirtualMachineClassSpec, error) { + v2Spec := VirtualMachineClassSpec{ + NodeSelector: NodeSelector{ + MatchLabels: v3Spec.NodeSelector.MatchLabels, + MatchExpressions: v3Spec.NodeSelector.MatchExpressions, + }, + Tolerations: v3Spec.Tolerations, + CPU: CPU{ + Type: CPUType(v3Spec.CPU.Type), + Model: v3Spec.CPU.Model, + Features: v3Spec.CPU.Features, + }, + } + + if v3Spec.CPU.Discovery != nil { + v2Spec.CPU.Discovery = &CpuDiscovery{ + NodeSelector: v3Spec.CPU.Discovery.NodeSelector, + } + } + + if len(v3Spec.SizingPolicies) > 0 { + v2Spec.SizingPolicies = make([]SizingPolicy, len(v3Spec.SizingPolicies)) + for i, v3Policy := range v3Spec.SizingPolicies { + v2Policy := SizingPolicy{ + DedicatedCores: v3Policy.DedicatedCores, + } + + if v3Policy.Memory != nil { + v2Policy.Memory = &SizingPolicyMemory{ + MemoryMinMax: MemoryMinMax{ + Min: v3Policy.Memory.Min, + Max: v3Policy.Memory.Max, + }, + Step: v3Policy.Memory.Step, + PerCore: SizingPolicyMemoryPerCore{ + MemoryMinMax: MemoryMinMax{ + Min: v3Policy.Memory.PerCore.Min, + Max: v3Policy.Memory.PerCore.Max, + }, + }, + } + } + + if v3Policy.Cores != nil { + v2Policy.Cores = &SizingPolicyCores{ + Min: v3Policy.Cores.Min, + Max: v3Policy.Cores.Max, + Step: v3Policy.Cores.Step, + } + } + + if len(v3Policy.CoreFractions) > 0 { + v2Policy.CoreFractions = make([]CoreFractionValue, len(v3Policy.CoreFractions)) + for j, v3Fraction := range v3Policy.CoreFractions { + fractionStr := string(v3Fraction) + if len(fractionStr) > 0 && fractionStr[len(fractionStr)-1] == '%' { + fractionStr = fractionStr[:len(fractionStr)-1] + } + fractionInt, err := strconv.Atoi(fractionStr) + if err != nil { + return VirtualMachineClassSpec{}, fmt.Errorf("failed to parse core fraction: %w", err) + } + if fractionInt < 1 || fractionInt > 100 { + return VirtualMachineClassSpec{}, fmt.Errorf("core fraction value must be between 1 and 100, got %d", fractionInt) + } + v2Policy.CoreFractions[j] = CoreFractionValue(fractionInt) + } + } + + v2Spec.SizingPolicies[i] = v2Policy + } + } + + return v2Spec, nil +} + +func convertSpecV2ToV3(v2Spec VirtualMachineClassSpec) v1alpha3.VirtualMachineClassSpec { + v3Spec := v1alpha3.VirtualMachineClassSpec{ + NodeSelector: v1alpha3.NodeSelector{ + MatchLabels: v2Spec.NodeSelector.MatchLabels, + MatchExpressions: v2Spec.NodeSelector.MatchExpressions, + }, + Tolerations: v2Spec.Tolerations, + CPU: v1alpha3.CPU{ + Type: v1alpha3.CPUType(v2Spec.CPU.Type), + Model: v2Spec.CPU.Model, + Features: v2Spec.CPU.Features, + }, + } + + if v2Spec.CPU.Discovery != nil { + v3Spec.CPU.Discovery = &v1alpha3.CpuDiscovery{ + NodeSelector: v2Spec.CPU.Discovery.NodeSelector, + } + } + + if len(v2Spec.SizingPolicies) > 0 { + v3Spec.SizingPolicies = make([]v1alpha3.SizingPolicy, len(v2Spec.SizingPolicies)) + for i, v2Policy := range v2Spec.SizingPolicies { + v3Policy := v1alpha3.SizingPolicy{ + DedicatedCores: v2Policy.DedicatedCores, + } + + if v2Policy.Memory != nil { + v3Policy.Memory = &v1alpha3.SizingPolicyMemory{ + MemoryMinMax: v1alpha3.MemoryMinMax{ + Min: v2Policy.Memory.Min, + Max: v2Policy.Memory.Max, + }, + Step: v2Policy.Memory.Step, + PerCore: v1alpha3.SizingPolicyMemoryPerCore{ + MemoryMinMax: v1alpha3.MemoryMinMax{ + Min: v2Policy.Memory.PerCore.Min, + Max: v2Policy.Memory.PerCore.Max, + }, + }, + } + } + + if v2Policy.Cores != nil { + v3Policy.Cores = &v1alpha3.SizingPolicyCores{ + Min: v2Policy.Cores.Min, + Max: v2Policy.Cores.Max, + Step: v2Policy.Cores.Step, + } + } + + if len(v2Policy.CoreFractions) > 0 { + v3Policy.CoreFractions = make([]v1alpha3.CoreFractionValue, len(v2Policy.CoreFractions)) + for j, v2Fraction := range v2Policy.CoreFractions { + v3Policy.CoreFractions[j] = v1alpha3.CoreFractionValue(fmt.Sprintf("%d%%", v2Fraction)) + } + } + + v3Spec.SizingPolicies[i] = v3Policy + } + } + + return v3Spec +} + +func convertStatusV3ToV2(v3Status v1alpha3.VirtualMachineClassStatus) VirtualMachineClassStatus { + return VirtualMachineClassStatus{ + Phase: VirtualMachineClassPhase(v3Status.Phase), + CpuFeatures: CpuFeatures{ + Enabled: v3Status.CpuFeatures.Enabled, + NotEnabledCommon: v3Status.CpuFeatures.NotEnabledCommon, + }, + AvailableNodes: v3Status.AvailableNodes, + MaxAllocatableResources: v3Status.MaxAllocatableResources, + Conditions: v3Status.Conditions, + ObservedGeneration: v3Status.ObservedGeneration, + } +} + +func convertStatusV2ToV3(v2Status VirtualMachineClassStatus) v1alpha3.VirtualMachineClassStatus { + return v1alpha3.VirtualMachineClassStatus{ + Phase: v1alpha3.VirtualMachineClassPhase(v2Status.Phase), + CpuFeatures: v1alpha3.CpuFeatures{ + Enabled: v2Status.CpuFeatures.Enabled, + NotEnabledCommon: v2Status.CpuFeatures.NotEnabledCommon, + }, + AvailableNodes: v2Status.AvailableNodes, + MaxAllocatableResources: v2Status.MaxAllocatableResources, + Conditions: v2Status.Conditions, + ObservedGeneration: v2Status.ObservedGeneration, + } +} diff --git a/api/core/v1alpha3/virtual_machine_class.go b/api/core/v1alpha3/virtual_machine_class.go index 43f388cc7d..6e00228b75 100644 --- a/api/core/v1alpha3/virtual_machine_class.go +++ b/api/core/v1alpha3/virtual_machine_class.go @@ -36,6 +36,7 @@ const ( // +kubebuilder:metadata:labels={heritage=deckhouse,module=virtualization,backup.deckhouse.io/cluster-config=true} // +kubebuilder:subresource:status // +kubebuilder:resource:categories={virtualization-cluster},scope=Cluster,shortName={vmc,vmclass},singular=virtualmachineclass +// +kubebuilder:storageversion // +kubebuilder:printcolumn:name="Phase",type="string",JSONPath=".status.phase",description="VirtualMachineClass phase." // +kubebuilder:printcolumn:name="IsDefault",type="string",JSONPath=".metadata.annotations.virtualmachineclass\\.virtualization\\.deckhouse\\.io\\/is-default-class",description="Default class for virtual machines without specified class." // +kubebuilder:printcolumn:name="Age",type="date",JSONPath=".metadata.creationTimestamp",description="Time of resource creation." diff --git a/api/core/v1alpha3/virtual_machine_class_conversion.go b/api/core/v1alpha3/virtual_machine_class_conversion.go index 03a5ba9530..a2a53a4938 100644 --- a/api/core/v1alpha3/virtual_machine_class_conversion.go +++ b/api/core/v1alpha3/virtual_machine_class_conversion.go @@ -16,206 +16,4 @@ limitations under the License. package v1alpha3 -import ( - "fmt" - "strconv" - - "sigs.k8s.io/controller-runtime/pkg/conversion" - - "github.com/deckhouse/virtualization/api/core/v1alpha2" -) - -var _ conversion.Convertible = &VirtualMachineClass{} - -func (src *VirtualMachineClass) ConvertTo(dstRaw conversion.Hub) error { - dst := dstRaw.(*v1alpha2.VirtualMachineClass) - - dst.ObjectMeta = src.ObjectMeta - convertedSpec, err := convertSpecV3ToV2(src.Spec) - if err != nil { - return err - } - dst.Spec = convertedSpec - dst.Status = convertStatusV3ToV2(src.Status) - - return nil -} - -func (dst *VirtualMachineClass) ConvertFrom(srcRaw conversion.Hub) error { - src := srcRaw.(*v1alpha2.VirtualMachineClass) - - dst.ObjectMeta = src.ObjectMeta - dst.Spec = convertSpecV2ToV3(src.Spec) - dst.Status = convertStatusV2ToV3(src.Status) - - return nil -} - -func convertSpecV3ToV2(v3Spec VirtualMachineClassSpec) (v1alpha2.VirtualMachineClassSpec, error) { - v2Spec := v1alpha2.VirtualMachineClassSpec{ - NodeSelector: v1alpha2.NodeSelector{ - MatchLabels: v3Spec.NodeSelector.MatchLabels, - MatchExpressions: v3Spec.NodeSelector.MatchExpressions, - }, - Tolerations: v3Spec.Tolerations, - CPU: v1alpha2.CPU{ - Type: v1alpha2.CPUType(v3Spec.CPU.Type), - Model: v3Spec.CPU.Model, - Features: v3Spec.CPU.Features, - }, - } - - if v3Spec.CPU.Discovery != nil { - v2Spec.CPU.Discovery = &v1alpha2.CpuDiscovery{ - NodeSelector: v3Spec.CPU.Discovery.NodeSelector, - } - } - - if len(v3Spec.SizingPolicies) > 0 { - v2Spec.SizingPolicies = make([]v1alpha2.SizingPolicy, len(v3Spec.SizingPolicies)) - for i, v3Policy := range v3Spec.SizingPolicies { - v2Policy := v1alpha2.SizingPolicy{ - DedicatedCores: v3Policy.DedicatedCores, - } - - if v3Policy.Memory != nil { - v2Policy.Memory = &v1alpha2.SizingPolicyMemory{ - MemoryMinMax: v1alpha2.MemoryMinMax{ - Min: v3Policy.Memory.Min, - Max: v3Policy.Memory.Max, - }, - Step: v3Policy.Memory.Step, - PerCore: v1alpha2.SizingPolicyMemoryPerCore{ - MemoryMinMax: v1alpha2.MemoryMinMax{ - Min: v3Policy.Memory.PerCore.Min, - Max: v3Policy.Memory.PerCore.Max, - }, - }, - } - } - - if v3Policy.Cores != nil { - v2Policy.Cores = &v1alpha2.SizingPolicyCores{ - Min: v3Policy.Cores.Min, - Max: v3Policy.Cores.Max, - Step: v3Policy.Cores.Step, - } - } - - if len(v3Policy.CoreFractions) > 0 { - v2Policy.CoreFractions = make([]v1alpha2.CoreFractionValue, len(v3Policy.CoreFractions)) - for j, v3Fraction := range v3Policy.CoreFractions { - fractionStr := string(v3Fraction) - if len(fractionStr) > 0 && fractionStr[len(fractionStr)-1] == '%' { - fractionStr = fractionStr[:len(fractionStr)-1] - } - fractionInt, err := strconv.Atoi(fractionStr) - if err != nil { - return v1alpha2.VirtualMachineClassSpec{}, fmt.Errorf("failed to parse core fraction: %w", err) - } - if fractionInt < 1 || fractionInt > 100 { - return v1alpha2.VirtualMachineClassSpec{}, fmt.Errorf("core fraction value must be between 1 and 100, got %d", fractionInt) - } - v2Policy.CoreFractions[j] = v1alpha2.CoreFractionValue(fractionInt) - } - } - - v2Spec.SizingPolicies[i] = v2Policy - } - } - - return v2Spec, nil -} - -func convertSpecV2ToV3(v2Spec v1alpha2.VirtualMachineClassSpec) VirtualMachineClassSpec { - v3Spec := VirtualMachineClassSpec{ - NodeSelector: NodeSelector{ - MatchLabels: v2Spec.NodeSelector.MatchLabels, - MatchExpressions: v2Spec.NodeSelector.MatchExpressions, - }, - Tolerations: v2Spec.Tolerations, - CPU: CPU{ - Type: CPUType(v2Spec.CPU.Type), - Model: v2Spec.CPU.Model, - Features: v2Spec.CPU.Features, - }, - } - - if v2Spec.CPU.Discovery != nil { - v3Spec.CPU.Discovery = &CpuDiscovery{ - NodeSelector: v2Spec.CPU.Discovery.NodeSelector, - } - } - - if len(v2Spec.SizingPolicies) > 0 { - v3Spec.SizingPolicies = make([]SizingPolicy, len(v2Spec.SizingPolicies)) - for i, v2Policy := range v2Spec.SizingPolicies { - v3Policy := SizingPolicy{ - DedicatedCores: v2Policy.DedicatedCores, - } - - if v2Policy.Memory != nil { - v3Policy.Memory = &SizingPolicyMemory{ - MemoryMinMax: MemoryMinMax{ - Min: v2Policy.Memory.Min, - Max: v2Policy.Memory.Max, - }, - Step: v2Policy.Memory.Step, - PerCore: SizingPolicyMemoryPerCore{ - MemoryMinMax: MemoryMinMax{ - Min: v2Policy.Memory.PerCore.Min, - Max: v2Policy.Memory.PerCore.Max, - }, - }, - } - } - - if v2Policy.Cores != nil { - v3Policy.Cores = &SizingPolicyCores{ - Min: v2Policy.Cores.Min, - Max: v2Policy.Cores.Max, - Step: v2Policy.Cores.Step, - } - } - - if len(v2Policy.CoreFractions) > 0 { - v3Policy.CoreFractions = make([]CoreFractionValue, len(v2Policy.CoreFractions)) - for j, v2Fraction := range v2Policy.CoreFractions { - v3Policy.CoreFractions[j] = CoreFractionValue(fmt.Sprintf("%d%%", v2Fraction)) - } - } - - v3Spec.SizingPolicies[i] = v3Policy - } - } - - return v3Spec -} - -func convertStatusV3ToV2(v3Status VirtualMachineClassStatus) v1alpha2.VirtualMachineClassStatus { - return v1alpha2.VirtualMachineClassStatus{ - Phase: v1alpha2.VirtualMachineClassPhase(v3Status.Phase), - CpuFeatures: v1alpha2.CpuFeatures{ - Enabled: v3Status.CpuFeatures.Enabled, - NotEnabledCommon: v3Status.CpuFeatures.NotEnabledCommon, - }, - AvailableNodes: v3Status.AvailableNodes, - MaxAllocatableResources: v3Status.MaxAllocatableResources, - Conditions: v3Status.Conditions, - ObservedGeneration: v3Status.ObservedGeneration, - } -} - -func convertStatusV2ToV3(v2Status v1alpha2.VirtualMachineClassStatus) VirtualMachineClassStatus { - return VirtualMachineClassStatus{ - Phase: VirtualMachineClassPhase(v2Status.Phase), - CpuFeatures: CpuFeatures{ - Enabled: v2Status.CpuFeatures.Enabled, - NotEnabledCommon: v2Status.CpuFeatures.NotEnabledCommon, - }, - AvailableNodes: v2Status.AvailableNodes, - MaxAllocatableResources: v2Status.MaxAllocatableResources, - Conditions: v2Status.Conditions, - ObservedGeneration: v2Status.ObservedGeneration, - } -} +func (*VirtualMachineClass) Hub() {} diff --git a/crds/clustervirtualimages.yaml b/crds/clustervirtualimages.yaml index 93bc215d84..233ee5ca29 100644 --- a/crds/clustervirtualimages.yaml +++ b/crds/clustervirtualimages.yaml @@ -3,7 +3,7 @@ apiVersion: apiextensions.k8s.io/v1 kind: CustomResourceDefinition metadata: annotations: - controller-gen.kubebuilder.io/version: v0.18.0 + controller-gen.kubebuilder.io/version: v0.16.5 labels: backup.deckhouse.io/cluster-config: "true" heritage: deckhouse diff --git a/crds/virtualdisks.yaml b/crds/virtualdisks.yaml index c00c80d46b..10a8e480c2 100644 --- a/crds/virtualdisks.yaml +++ b/crds/virtualdisks.yaml @@ -3,7 +3,7 @@ apiVersion: apiextensions.k8s.io/v1 kind: CustomResourceDefinition metadata: annotations: - controller-gen.kubebuilder.io/version: v0.18.0 + controller-gen.kubebuilder.io/version: v0.16.5 labels: heritage: deckhouse module: virtualization diff --git a/crds/virtualimages.yaml b/crds/virtualimages.yaml index 700a9418b2..4503916cfd 100644 --- a/crds/virtualimages.yaml +++ b/crds/virtualimages.yaml @@ -3,7 +3,7 @@ apiVersion: apiextensions.k8s.io/v1 kind: CustomResourceDefinition metadata: annotations: - controller-gen.kubebuilder.io/version: v0.18.0 + controller-gen.kubebuilder.io/version: v0.16.5 labels: heritage: deckhouse module: virtualization diff --git a/crds/virtualmachineblockdeviceattachments.yaml b/crds/virtualmachineblockdeviceattachments.yaml index 939fc91607..45e8b70eb6 100644 --- a/crds/virtualmachineblockdeviceattachments.yaml +++ b/crds/virtualmachineblockdeviceattachments.yaml @@ -3,7 +3,7 @@ apiVersion: apiextensions.k8s.io/v1 kind: CustomResourceDefinition metadata: annotations: - controller-gen.kubebuilder.io/version: v0.18.0 + controller-gen.kubebuilder.io/version: v0.16.5 labels: heritage: deckhouse module: virtualization diff --git a/crds/virtualmachineclasses.yaml b/crds/virtualmachineclasses.yaml index 11741dddd3..394626214c 100644 --- a/crds/virtualmachineclasses.yaml +++ b/crds/virtualmachineclasses.yaml @@ -3,7 +3,7 @@ apiVersion: apiextensions.k8s.io/v1 kind: CustomResourceDefinition metadata: annotations: - controller-gen.kubebuilder.io/version: v0.18.0 + controller-gen.kubebuilder.io/version: v0.16.5 labels: backup.deckhouse.io/cluster-config: "true" heritage: deckhouse @@ -510,7 +510,7 @@ spec: - spec type: object served: true - storage: true + storage: false subresources: status: {} - additionalPrinterColumns: @@ -1005,6 +1005,6 @@ spec: - spec type: object served: true - storage: false + storage: true subresources: status: {} diff --git a/crds/virtualmachineoperations.yaml b/crds/virtualmachineoperations.yaml index c96023b308..a67b8e2f84 100644 --- a/crds/virtualmachineoperations.yaml +++ b/crds/virtualmachineoperations.yaml @@ -3,7 +3,7 @@ apiVersion: apiextensions.k8s.io/v1 kind: CustomResourceDefinition metadata: annotations: - controller-gen.kubebuilder.io/version: v0.18.0 + controller-gen.kubebuilder.io/version: v0.16.5 labels: heritage: deckhouse module: virtualization diff --git a/crds/virtualmachinerestores.yaml b/crds/virtualmachinerestores.yaml index eb848d5250..1d37016201 100644 --- a/crds/virtualmachinerestores.yaml +++ b/crds/virtualmachinerestores.yaml @@ -3,7 +3,7 @@ apiVersion: apiextensions.k8s.io/v1 kind: CustomResourceDefinition metadata: annotations: - controller-gen.kubebuilder.io/version: v0.18.0 + controller-gen.kubebuilder.io/version: v0.16.5 labels: heritage: deckhouse module: virtualization diff --git a/crds/virtualmachinesnapshots.yaml b/crds/virtualmachinesnapshots.yaml index c1b681a99e..dcac3a221e 100644 --- a/crds/virtualmachinesnapshots.yaml +++ b/crds/virtualmachinesnapshots.yaml @@ -3,7 +3,7 @@ apiVersion: apiextensions.k8s.io/v1 kind: CustomResourceDefinition metadata: annotations: - controller-gen.kubebuilder.io/version: v0.18.0 + controller-gen.kubebuilder.io/version: v0.16.5 labels: heritage: deckhouse module: virtualization diff --git a/images/virtualization-artifact/pkg/controller/vmclass/vmclass_webhook.go b/images/virtualization-artifact/pkg/controller/vmclass/vmclass_webhook.go index eea4f0da7c..b08c84ce79 100644 --- a/images/virtualization-artifact/pkg/controller/vmclass/vmclass_webhook.go +++ b/images/virtualization-artifact/pkg/controller/vmclass/vmclass_webhook.go @@ -58,7 +58,7 @@ func (v *Validator) ValidateCreate(ctx context.Context, obj runtime.Object) (adm vmclass = obj case *v1alpha3.VirtualMachineClass: vmclass = &v1alpha2.VirtualMachineClass{} - if err := obj.ConvertTo(vmclass); err != nil { + if err := vmclass.ConvertFrom(obj); err != nil { return nil, fmt.Errorf("failed to convert v1alpha3 to v1alpha2: %w", err) } default: @@ -86,7 +86,7 @@ func (v *Validator) ValidateUpdate(ctx context.Context, oldObj, newObj runtime.O oldVMClass = oldObj case *v1alpha3.VirtualMachineClass: oldVMClass = &v1alpha2.VirtualMachineClass{} - if err := oldObj.ConvertTo(oldVMClass); err != nil { + if err := oldVMClass.ConvertFrom(oldObj); err != nil { return nil, fmt.Errorf("failed to convert old v1alpha3 to v1alpha2: %w", err) } default: @@ -98,7 +98,7 @@ func (v *Validator) ValidateUpdate(ctx context.Context, oldObj, newObj runtime.O newVMClass = newObj case *v1alpha3.VirtualMachineClass: newVMClass = &v1alpha2.VirtualMachineClass{} - if err := newObj.ConvertTo(newVMClass); err != nil { + if err := newVMClass.ConvertFrom(newObj); err != nil { return nil, fmt.Errorf("failed to convert new v1alpha3 to v1alpha2: %w", err) } default: From cba744cadec121eb85a2144c74c34f75b3c61ab7 Mon Sep 17 00:00:00 2001 From: Daniil Loktev Date: Fri, 7 Nov 2025 18:05:44 +0300 Subject: [PATCH 61/77] fix conversion test Signed-off-by: Daniil Loktev --- .../conversion_suite_test.go | 2 +- .../virtual_machine_class_conversion_test.go | 172 +++++++++--------- 2 files changed, 87 insertions(+), 87 deletions(-) rename api/core/{v1alpha3 => v1alpha2}/conversion_suite_test.go (97%) rename api/core/{v1alpha3 => v1alpha2}/virtual_machine_class_conversion_test.go (69%) diff --git a/api/core/v1alpha3/conversion_suite_test.go b/api/core/v1alpha2/conversion_suite_test.go similarity index 97% rename from api/core/v1alpha3/conversion_suite_test.go rename to api/core/v1alpha2/conversion_suite_test.go index 8499fededf..3771e6d24b 100644 --- a/api/core/v1alpha3/conversion_suite_test.go +++ b/api/core/v1alpha2/conversion_suite_test.go @@ -14,7 +14,7 @@ See the License for the specific language governing permissions and limitations under the License. */ -package v1alpha3 +package v1alpha2 import ( "testing" diff --git a/api/core/v1alpha3/virtual_machine_class_conversion_test.go b/api/core/v1alpha2/virtual_machine_class_conversion_test.go similarity index 69% rename from api/core/v1alpha3/virtual_machine_class_conversion_test.go rename to api/core/v1alpha2/virtual_machine_class_conversion_test.go index d267178277..f182f199b2 100644 --- a/api/core/v1alpha3/virtual_machine_class_conversion_test.go +++ b/api/core/v1alpha2/virtual_machine_class_conversion_test.go @@ -14,7 +14,7 @@ See the License for the specific language governing permissions and limitations under the License. */ -package v1alpha3 +package v1alpha2 import ( . "github.com/onsi/ginkgo/v2" @@ -23,20 +23,20 @@ import ( "k8s.io/apimachinery/pkg/api/resource" metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" - "github.com/deckhouse/virtualization/api/core/v1alpha2" + "github.com/deckhouse/virtualization/api/core/v1alpha3" ) var _ = Describe("VirtualMachineClass Conversion", func() { Context("ConvertTo v1alpha2", func() { DescribeTable("should convert valid CoreFractionValue strings", - func(coreFractions []CoreFractionValue) { - v3Class := &VirtualMachineClass{ + func(coreFractions []v1alpha3.CoreFractionValue) { + v3Class := &v1alpha3.VirtualMachineClass{ ObjectMeta: metav1.ObjectMeta{Name: "test-class"}, - Spec: VirtualMachineClassSpec{ - SizingPolicies: []SizingPolicy{ + Spec: v1alpha3.VirtualMachineClassSpec{ + SizingPolicies: []v1alpha3.SizingPolicy{ { CoreFractions: coreFractions, - Cores: &SizingPolicyCores{ + Cores: &v1alpha3.SizingPolicyCores{ Min: 1, Max: 8, Step: 1, @@ -46,31 +46,31 @@ var _ = Describe("VirtualMachineClass Conversion", func() { }, } - v2Class := &v1alpha2.VirtualMachineClass{} - err := v3Class.ConvertTo(v2Class) + v2Class := &VirtualMachineClass{} + err := v2Class.ConvertFrom(v3Class) Expect(err).NotTo(HaveOccurred()) Expect(v2Class.Name).To(Equal(v3Class.Name)) Expect(v2Class.Spec.SizingPolicies).To(HaveLen(1)) Expect(v2Class.Spec.SizingPolicies[0].CoreFractions).To(HaveLen(len(coreFractions))) }, - Entry("single value", []CoreFractionValue{"5%"}), - Entry("multiple values", []CoreFractionValue{"5%", "10%", "25%", "50%", "100%"}), - Entry("minimum value 1%", []CoreFractionValue{"1%"}), - Entry("maximum value 100%", []CoreFractionValue{"100%"}), - Entry("mixed valid values", []CoreFractionValue{"1%", "50%", "100%"}), - Entry("value without percent sign", []CoreFractionValue{"50"}), + Entry("single value", []v1alpha3.CoreFractionValue{"5%"}), + Entry("multiple values", []v1alpha3.CoreFractionValue{"5%", "10%", "25%", "50%", "100%"}), + Entry("minimum value 1%", []v1alpha3.CoreFractionValue{"1%"}), + Entry("maximum value 100%", []v1alpha3.CoreFractionValue{"100%"}), + Entry("mixed valid values", []v1alpha3.CoreFractionValue{"1%", "50%", "100%"}), + Entry("value without percent sign", []v1alpha3.CoreFractionValue{"50"}), ) DescribeTable("should fail on invalid CoreFractionValue strings", - func(coreFractions []CoreFractionValue, expectedErrorSubstring string) { - v3Class := &VirtualMachineClass{ + func(coreFractions []v1alpha3.CoreFractionValue, expectedErrorSubstring string) { + v3Class := &v1alpha3.VirtualMachineClass{ ObjectMeta: metav1.ObjectMeta{Name: "test-class"}, - Spec: VirtualMachineClassSpec{ - SizingPolicies: []SizingPolicy{ + Spec: v1alpha3.VirtualMachineClassSpec{ + SizingPolicies: []v1alpha3.SizingPolicy{ { CoreFractions: coreFractions, - Cores: &SizingPolicyCores{ + Cores: &v1alpha3.SizingPolicyCores{ Min: 1, Max: 4, Step: 1, @@ -80,23 +80,23 @@ var _ = Describe("VirtualMachineClass Conversion", func() { }, } - v2Class := &v1alpha2.VirtualMachineClass{} - err := v3Class.ConvertTo(v2Class) + v2Class := &VirtualMachineClass{} + err := v2Class.ConvertFrom(v3Class) Expect(err).To(HaveOccurred()) Expect(err.Error()).To(ContainSubstring(expectedErrorSubstring)) }, - Entry("value below minimum (0%)", []CoreFractionValue{"0%"}, "must be between 1 and 100, got 0"), - Entry("value above maximum (101%)", []CoreFractionValue{"101%"}, "must be between 1 and 100, got 101"), - Entry("negative value", []CoreFractionValue{"-5%"}, "must be between 1 and 100, got -5"), - Entry("non-numeric value", []CoreFractionValue{"abc%"}, "failed to parse core fraction"), - Entry("empty string", []CoreFractionValue{""}, "failed to parse core fraction"), - Entry("percent sign in wrong position", []CoreFractionValue{"%50"}, "failed to parse core fraction"), - Entry("one invalid in multiple", []CoreFractionValue{"5%", "150%", "100%"}, "must be between 1 and 100, got 150"), + Entry("value below minimum (0%)", []v1alpha3.CoreFractionValue{"0%"}, "must be between 1 and 100, got 0"), + Entry("value above maximum (101%)", []v1alpha3.CoreFractionValue{"101%"}, "must be between 1 and 100, got 101"), + Entry("negative value", []v1alpha3.CoreFractionValue{"-5%"}, "must be between 1 and 100, got -5"), + Entry("non-numeric value", []v1alpha3.CoreFractionValue{"abc%"}, "failed to parse core fraction"), + Entry("empty string", []v1alpha3.CoreFractionValue{""}, "failed to parse core fraction"), + Entry("percent sign in wrong position", []v1alpha3.CoreFractionValue{"%50"}, "failed to parse core fraction"), + Entry("one invalid in multiple", []v1alpha3.CoreFractionValue{"5%", "150%", "100%"}, "must be between 1 and 100, got 150"), ) It("should preserve ObjectMeta", func() { - v3Class := &VirtualMachineClass{ + v3Class := &v1alpha3.VirtualMachineClass{ ObjectMeta: metav1.ObjectMeta{ Name: "test-class", Namespace: "test-ns", @@ -104,11 +104,11 @@ var _ = Describe("VirtualMachineClass Conversion", func() { "test-label": "test-value", }, }, - Spec: VirtualMachineClassSpec{}, + Spec: v1alpha3.VirtualMachineClassSpec{}, } - v2Class := &v1alpha2.VirtualMachineClass{} - err := v3Class.ConvertTo(v2Class) + v2Class := &VirtualMachineClass{} + err := v2Class.ConvertFrom(v3Class) Expect(err).NotTo(HaveOccurred()) Expect(v2Class.Name).To(Equal("test-class")) @@ -119,14 +119,14 @@ var _ = Describe("VirtualMachineClass Conversion", func() { Context("ConvertFrom v1alpha2", func() { DescribeTable("should convert v1alpha2 CoreFractionValue integers to percentage strings", - func(v2CoreFractions []v1alpha2.CoreFractionValue, expectedV3Values []CoreFractionValue) { - v2Class := &v1alpha2.VirtualMachineClass{ + func(v2CoreFractions []CoreFractionValue, expectedV3Values []v1alpha3.CoreFractionValue) { + v2Class := &VirtualMachineClass{ ObjectMeta: metav1.ObjectMeta{Name: "test-class"}, - Spec: v1alpha2.VirtualMachineClassSpec{ - SizingPolicies: []v1alpha2.SizingPolicy{ + Spec: VirtualMachineClassSpec{ + SizingPolicies: []SizingPolicy{ { CoreFractions: v2CoreFractions, - Cores: &v1alpha2.SizingPolicyCores{ + Cores: &SizingPolicyCores{ Min: 1, Max: 8, Step: 1, @@ -136,30 +136,30 @@ var _ = Describe("VirtualMachineClass Conversion", func() { }, } - v3Class := &VirtualMachineClass{} - err := v3Class.ConvertFrom(v2Class) + v3Class := &v1alpha3.VirtualMachineClass{} + err := v2Class.ConvertTo(v3Class) Expect(err).NotTo(HaveOccurred()) Expect(v3Class.Spec.SizingPolicies).To(HaveLen(1)) Expect(v3Class.Spec.SizingPolicies[0].CoreFractions).To(Equal(expectedV3Values)) }, - Entry("single value", []v1alpha2.CoreFractionValue{5}, []CoreFractionValue{"5%"}), - Entry("multiple values", []v1alpha2.CoreFractionValue{5, 10, 25, 50, 100}, []CoreFractionValue{"5%", "10%", "25%", "50%", "100%"}), - Entry("minimum value", []v1alpha2.CoreFractionValue{1}, []CoreFractionValue{"1%"}), - Entry("maximum value", []v1alpha2.CoreFractionValue{100}, []CoreFractionValue{"100%"}), + Entry("single value", []CoreFractionValue{5}, []v1alpha3.CoreFractionValue{"5%"}), + Entry("multiple values", []CoreFractionValue{5, 10, 25, 50, 100}, []v1alpha3.CoreFractionValue{"5%", "10%", "25%", "50%", "100%"}), + Entry("minimum value", []CoreFractionValue{1}, []v1alpha3.CoreFractionValue{"1%"}), + Entry("maximum value", []CoreFractionValue{100}, []v1alpha3.CoreFractionValue{"100%"}), ) }) Context("Round-trip conversion", func() { DescribeTable("should preserve values through v2 -> v3 -> v2 conversion", - func(v2CoreFractions []v1alpha2.CoreFractionValue) { - originalV2 := &v1alpha2.VirtualMachineClass{ + func(v2CoreFractions []CoreFractionValue) { + originalV2 := &VirtualMachineClass{ ObjectMeta: metav1.ObjectMeta{Name: "test-class"}, - Spec: v1alpha2.VirtualMachineClassSpec{ - SizingPolicies: []v1alpha2.SizingPolicy{ + Spec: VirtualMachineClassSpec{ + SizingPolicies: []SizingPolicy{ { CoreFractions: v2CoreFractions, - Cores: &v1alpha2.SizingPolicyCores{ + Cores: &SizingPolicyCores{ Min: 1, Max: 8, Step: 1, @@ -169,20 +169,20 @@ var _ = Describe("VirtualMachineClass Conversion", func() { }, } - v3Class := &VirtualMachineClass{} - err := v3Class.ConvertFrom(originalV2) + v3Class := &v1alpha3.VirtualMachineClass{} + err := originalV2.ConvertTo(v3Class) Expect(err).NotTo(HaveOccurred()) - roundTripV2 := &v1alpha2.VirtualMachineClass{} - err = v3Class.ConvertTo(roundTripV2) + roundTripV2 := &VirtualMachineClass{} + err = roundTripV2.ConvertFrom(v3Class) Expect(err).NotTo(HaveOccurred()) Expect(roundTripV2.Spec.SizingPolicies).To(HaveLen(1)) Expect(roundTripV2.Spec.SizingPolicies[0].CoreFractions).To(Equal(v2CoreFractions)) }, - Entry("single value", []v1alpha2.CoreFractionValue{5}), - Entry("multiple values", []v1alpha2.CoreFractionValue{5, 10, 25, 50, 100}), - Entry("boundary values", []v1alpha2.CoreFractionValue{1, 100}), + Entry("single value", []CoreFractionValue{5}), + Entry("multiple values", []CoreFractionValue{5, 10, 25, 50, 100}), + Entry("boundary values", []CoreFractionValue{1, 100}), ) }) @@ -201,7 +201,7 @@ var _ = Describe("VirtualMachineClass Conversion", func() { }) It("should preserve all fields in ConvertTo", func() { - v3Class := &VirtualMachineClass{ + v3Class := &v1alpha3.VirtualMachineClass{ ObjectMeta: metav1.ObjectMeta{ Name: "full-test-class", Namespace: "test-namespace", @@ -212,8 +212,8 @@ var _ = Describe("VirtualMachineClass Conversion", func() { "test-annotation": "test-value", }, }, - Spec: VirtualMachineClassSpec{ - NodeSelector: NodeSelector{ + Spec: v1alpha3.VirtualMachineClassSpec{ + NodeSelector: v1alpha3.NodeSelector{ MatchLabels: map[string]string{ "node-role": "worker", "zone": "us-east-1a", @@ -234,30 +234,30 @@ var _ = Describe("VirtualMachineClass Conversion", func() { Effect: corev1.TaintEffectNoSchedule, }, }, - CPU: CPU{ - Type: CPUTypeModel, + CPU: v1alpha3.CPU{ + Type: v1alpha3.CPUTypeModel, Model: "IvyBridge", Features: nil, Discovery: nil, }, - SizingPolicies: []SizingPolicy{ + SizingPolicies: []v1alpha3.SizingPolicy{ { - Memory: &SizingPolicyMemory{ - MemoryMinMax: MemoryMinMax{ + Memory: &v1alpha3.SizingPolicyMemory{ + MemoryMinMax: v1alpha3.MemoryMinMax{ Min: minMem, Max: maxMem, }, Step: stepMem, - PerCore: SizingPolicyMemoryPerCore{ - MemoryMinMax: MemoryMinMax{ + PerCore: v1alpha3.SizingPolicyMemoryPerCore{ + MemoryMinMax: v1alpha3.MemoryMinMax{ Min: minPerCoreMem, Max: maxPerCoreMem, }, }, }, - CoreFractions: []CoreFractionValue{"5%", "10%", "50%", "100%"}, + CoreFractions: []v1alpha3.CoreFractionValue{"5%", "10%", "50%", "100%"}, DedicatedCores: []bool{false, true}, - Cores: &SizingPolicyCores{ + Cores: &v1alpha3.SizingPolicyCores{ Min: 1, Max: 16, Step: 2, @@ -267,8 +267,8 @@ var _ = Describe("VirtualMachineClass Conversion", func() { }, } - v2Class := &v1alpha2.VirtualMachineClass{} - err := v3Class.ConvertTo(v2Class) + v2Class := &VirtualMachineClass{} + err := v2Class.ConvertFrom(v3Class) Expect(err).NotTo(HaveOccurred()) Expect(v2Class.Name).To(Equal("full-test-class")) @@ -300,7 +300,7 @@ var _ = Describe("VirtualMachineClass Conversion", func() { Expect(policy.Memory.PerCore.Min.Equal(minPerCoreMem)).To(BeTrue()) Expect(policy.Memory.PerCore.Max.Equal(maxPerCoreMem)).To(BeTrue()) - Expect(policy.CoreFractions).To(Equal([]v1alpha2.CoreFractionValue{5, 10, 50, 100})) + Expect(policy.CoreFractions).To(Equal([]CoreFractionValue{5, 10, 50, 100})) Expect(policy.DedicatedCores).To(Equal([]bool{false, true})) Expect(policy.Cores).NotTo(BeNil()) @@ -310,7 +310,7 @@ var _ = Describe("VirtualMachineClass Conversion", func() { }) It("should preserve all fields in ConvertFrom", func() { - v2Class := &v1alpha2.VirtualMachineClass{ + v2Class := &VirtualMachineClass{ ObjectMeta: metav1.ObjectMeta{ Name: "full-test-class", Namespace: "test-namespace", @@ -318,8 +318,8 @@ var _ = Describe("VirtualMachineClass Conversion", func() { "test-label": "test-value", }, }, - Spec: v1alpha2.VirtualMachineClassSpec{ - NodeSelector: v1alpha2.NodeSelector{ + Spec: VirtualMachineClassSpec{ + NodeSelector: NodeSelector{ MatchLabels: map[string]string{ "node-role": "worker", }, @@ -332,28 +332,28 @@ var _ = Describe("VirtualMachineClass Conversion", func() { Effect: corev1.TaintEffectNoSchedule, }, }, - CPU: v1alpha2.CPU{ - Type: v1alpha2.CPUTypeFeatures, + CPU: CPU{ + Type: CPUTypeFeatures, Features: []string{"mmx", "sse2", "vmx"}, }, - SizingPolicies: []v1alpha2.SizingPolicy{ + SizingPolicies: []SizingPolicy{ { - Memory: &v1alpha2.SizingPolicyMemory{ - MemoryMinMax: v1alpha2.MemoryMinMax{ + Memory: &SizingPolicyMemory{ + MemoryMinMax: MemoryMinMax{ Min: minMem, Max: maxMem, }, Step: stepMem, - PerCore: v1alpha2.SizingPolicyMemoryPerCore{ - MemoryMinMax: v1alpha2.MemoryMinMax{ + PerCore: SizingPolicyMemoryPerCore{ + MemoryMinMax: MemoryMinMax{ Min: minPerCoreMem, Max: maxPerCoreMem, }, }, }, - CoreFractions: []v1alpha2.CoreFractionValue{10, 50, 100}, + CoreFractions: []CoreFractionValue{10, 50, 100}, DedicatedCores: []bool{true}, - Cores: &v1alpha2.SizingPolicyCores{ + Cores: &SizingPolicyCores{ Min: 2, Max: 8, Step: 2, @@ -363,8 +363,8 @@ var _ = Describe("VirtualMachineClass Conversion", func() { }, } - v3Class := &VirtualMachineClass{} - err := v3Class.ConvertFrom(v2Class) + v3Class := &v1alpha3.VirtualMachineClass{} + err := v2Class.ConvertTo(v3Class) Expect(err).NotTo(HaveOccurred()) Expect(v3Class.Name).To(Equal("full-test-class")) @@ -387,7 +387,7 @@ var _ = Describe("VirtualMachineClass Conversion", func() { Expect(policy.Memory.Max.Equal(maxMem)).To(BeTrue()) Expect(policy.Memory.Step.Equal(stepMem)).To(BeTrue()) - Expect(policy.CoreFractions).To(Equal([]CoreFractionValue{"10%", "50%", "100%"})) + Expect(policy.CoreFractions).To(Equal([]v1alpha3.CoreFractionValue{"10%", "50%", "100%"})) Expect(policy.DedicatedCores).To(Equal([]bool{true})) Expect(policy.Cores).NotTo(BeNil()) From 572df397d0dd2768cd4ff9e7dee5de8562607d53 Mon Sep 17 00:00:00 2001 From: Daniil Loktev Date: Mon, 10 Nov 2025 19:26:08 +0300 Subject: [PATCH 62/77] add deprecation, move coreFractions validation to webhook Signed-off-by: Daniil Loktev --- api/core/v1alpha2/virtual_machine_class.go | 3 +++ api/core/v1alpha3/virtual_machine_class.go | 1 - crds/virtualmachineclasses.yaml | 5 ++++- .../generated/openapi/zz_generated.openapi.go | 2 +- .../pkg/controller/vmclass/vmclass_webhook.go | 18 ++++++++++++++++++ 5 files changed, 26 insertions(+), 3 deletions(-) diff --git a/api/core/v1alpha2/virtual_machine_class.go b/api/core/v1alpha2/virtual_machine_class.go index 1df0a83122..fca739f2de 100644 --- a/api/core/v1alpha2/virtual_machine_class.go +++ b/api/core/v1alpha2/virtual_machine_class.go @@ -32,6 +32,8 @@ const ( // VirtualMachineClass resource describes CPU requirements, node placement, and sizing policy for VM resources. // A resource cannot be deleted as long as it is used in one of the VMs. // +// Deprecated: Use v1alpha3.VirtualMachineClass instead. +// // +kubebuilder:object:root=true // +kubebuilder:metadata:labels={heritage=deckhouse,module=virtualization,backup.deckhouse.io/cluster-config=true} // +kubebuilder:subresource:status @@ -39,6 +41,7 @@ const ( // +kubebuilder:printcolumn:name="Phase",type="string",JSONPath=".status.phase",description="VirtualMachineClass phase." // +kubebuilder:printcolumn:name="IsDefault",type="string",JSONPath=".metadata.annotations.virtualmachineclass\\.virtualization\\.deckhouse\\.io\\/is-default-class",description="Default class for virtual machines without specified class." // +kubebuilder:printcolumn:name="Age",type="date",JSONPath=".metadata.creationTimestamp",description="Time of resource creation." +// +kubebuilder:deprecatedversion:warning="v1alpha2.VirtualMachineClass is deprecated; use v1alpha3.VirtualMachineClass" // +genclient // +genclient:nonNamespaced // +k8s:deepcopy-gen:interfaces=k8s.io/apimachinery/pkg/runtime.Object diff --git a/api/core/v1alpha3/virtual_machine_class.go b/api/core/v1alpha3/virtual_machine_class.go index 6e00228b75..7d900de45e 100644 --- a/api/core/v1alpha3/virtual_machine_class.go +++ b/api/core/v1alpha3/virtual_machine_class.go @@ -125,7 +125,6 @@ type SizingPolicy struct { } // CoreFractionValue represents CPU core fraction as a percentage string (e.g., "5%", "10%", "25%", "50%", "100%"). -// +kubebuilder:validation:Pattern=`^([1-9]|[1-9][0-9]|100)%$` type CoreFractionValue string type SizingPolicyMemory struct { diff --git a/crds/virtualmachineclasses.yaml b/crds/virtualmachineclasses.yaml index 394626214c..5ab54add7d 100644 --- a/crds/virtualmachineclasses.yaml +++ b/crds/virtualmachineclasses.yaml @@ -36,12 +36,16 @@ spec: jsonPath: .metadata.creationTimestamp name: Age type: date + deprecated: true + deprecationWarning: v1alpha2.VirtualMachineClass is deprecated; use v1alpha3.VirtualMachineClass name: v1alpha2 schema: openAPIV3Schema: description: |- VirtualMachineClass resource describes CPU requirements, node placement, and sizing policy for VM resources. A resource cannot be deleted as long as it is used in one of the VMs. + + Deprecated: Use v1alpha3.VirtualMachineClass instead. properties: apiVersion: description: |- @@ -733,7 +737,6 @@ spec: CoreFractionValue represents CPU core fraction as a percentage string (e.g., "5%", "10%", "25%", "50%", "100%"). - pattern: ^([1-9]|[1-9][0-9]|100)%$ type: string type: array cores: diff --git a/images/virtualization-artifact/pkg/apiserver/api/generated/openapi/zz_generated.openapi.go b/images/virtualization-artifact/pkg/apiserver/api/generated/openapi/zz_generated.openapi.go index fafb20b163..c2c474af65 100644 --- a/images/virtualization-artifact/pkg/apiserver/api/generated/openapi/zz_generated.openapi.go +++ b/images/virtualization-artifact/pkg/apiserver/api/generated/openapi/zz_generated.openapi.go @@ -3760,7 +3760,7 @@ func schema_virtualization_api_core_v1alpha2_VirtualMachineClass(ref common.Refe return common.OpenAPIDefinition{ Schema: spec.Schema{ SchemaProps: spec.SchemaProps{ - Description: "VirtualMachineClass resource describes CPU requirements, node placement, and sizing policy for VM resources. A resource cannot be deleted as long as it is used in one of the VMs.", + Description: "VirtualMachineClass resource describes CPU requirements, node placement, and sizing policy for VM resources. A resource cannot be deleted as long as it is used in one of the VMs.\n\nDeprecated: Use v1alpha3.VirtualMachineClass instead.", Type: []string{"object"}, Properties: map[string]spec.Schema{ "kind": { diff --git a/images/virtualization-artifact/pkg/controller/vmclass/vmclass_webhook.go b/images/virtualization-artifact/pkg/controller/vmclass/vmclass_webhook.go index 760c28a13b..a19759310f 100644 --- a/images/virtualization-artifact/pkg/controller/vmclass/vmclass_webhook.go +++ b/images/virtualization-artifact/pkg/controller/vmclass/vmclass_webhook.go @@ -19,6 +19,7 @@ package vmclass import ( "context" "fmt" + "regexp" "k8s.io/apimachinery/pkg/runtime" "sigs.k8s.io/controller-runtime/pkg/client" @@ -60,6 +61,8 @@ func (v *Validator) ValidateCreate(ctx context.Context, obj runtime.Object) (adm case *v1alpha2.VirtualMachineClass: vmclass = obj case *v1alpha3.VirtualMachineClass: + // Validate in webhook instead of CRD to provide clear error message + validateV1Alpha3CoreFractions(obj) vmclass = &v1alpha2.VirtualMachineClass{} if err := vmclass.ConvertFrom(obj); err != nil { return nil, fmt.Errorf("failed to convert v1alpha3 to v1alpha2: %w", err) @@ -88,6 +91,8 @@ func (v *Validator) ValidateUpdate(ctx context.Context, oldObj, newObj runtime.O case *v1alpha2.VirtualMachineClass: oldVMClass = oldObj case *v1alpha3.VirtualMachineClass: + // Validate in webhook instead of CRD to provide clear error message + validateV1Alpha3CoreFractions(oldObj) oldVMClass = &v1alpha2.VirtualMachineClass{} if err := oldVMClass.ConvertFrom(oldObj); err != nil { return nil, fmt.Errorf("failed to convert old v1alpha3 to v1alpha2: %w", err) @@ -100,6 +105,8 @@ func (v *Validator) ValidateUpdate(ctx context.Context, oldObj, newObj runtime.O case *v1alpha2.VirtualMachineClass: newVMClass = newObj case *v1alpha3.VirtualMachineClass: + // Validate in webhook instead of CRD to provide clear error message + validateV1Alpha3CoreFractions(newObj) newVMClass = &v1alpha2.VirtualMachineClass{} if err := newVMClass.ConvertFrom(newObj); err != nil { return nil, fmt.Errorf("failed to convert new v1alpha3 to v1alpha2: %w", err) @@ -126,3 +133,14 @@ func (v *Validator) ValidateDelete(_ context.Context, _ runtime.Object) (admissi v.log.Error("Ensure the correctness of ValidatingWebhookConfiguration", "err", err.Error()) return nil, nil } + +func validateV1Alpha3CoreFractions(vmclass *v1alpha3.VirtualMachineClass) error { + for i, policy := range vmclass.Spec.SizingPolicies { + for j, coreFraction := range policy.CoreFractions { + if !regexp.MustCompile(`^([1-9]|[1-9][0-9]|100)%$`).MatchString(string(coreFraction)) { + return fmt.Errorf("spec.sizingPolicies[%d].coreFractions[%d]: coreFraction must be a percentage between 1%% and 100%% (e.g., 5%%, 10%%, 50%%), got %q", i, j, coreFraction) + } + } + } + return nil +} From 508d036bb28fe7abe5e531c2b7cc6a2deb6808cc Mon Sep 17 00:00:00 2001 From: Daniil Loktev Date: Tue, 11 Nov 2025 10:08:56 +0300 Subject: [PATCH 63/77] wip Signed-off-by: Daniil Loktev --- api/core/v1alpha2/virtual_machine_class.go | 2 -- api/core/v1alpha3/virtual_machine_class_conversion.go | 4 ++++ 2 files changed, 4 insertions(+), 2 deletions(-) diff --git a/api/core/v1alpha2/virtual_machine_class.go b/api/core/v1alpha2/virtual_machine_class.go index fca739f2de..0275d2380f 100644 --- a/api/core/v1alpha2/virtual_machine_class.go +++ b/api/core/v1alpha2/virtual_machine_class.go @@ -32,8 +32,6 @@ const ( // VirtualMachineClass resource describes CPU requirements, node placement, and sizing policy for VM resources. // A resource cannot be deleted as long as it is used in one of the VMs. // -// Deprecated: Use v1alpha3.VirtualMachineClass instead. -// // +kubebuilder:object:root=true // +kubebuilder:metadata:labels={heritage=deckhouse,module=virtualization,backup.deckhouse.io/cluster-config=true} // +kubebuilder:subresource:status diff --git a/api/core/v1alpha3/virtual_machine_class_conversion.go b/api/core/v1alpha3/virtual_machine_class_conversion.go index a2a53a4938..233b260e4c 100644 --- a/api/core/v1alpha3/virtual_machine_class_conversion.go +++ b/api/core/v1alpha3/virtual_machine_class_conversion.go @@ -16,4 +16,8 @@ limitations under the License. package v1alpha3 +import "sigs.k8s.io/controller-runtime/pkg/conversion" + +var _ conversion.Hub = &VirtualMachineClass{} + func (*VirtualMachineClass) Hub() {} From ea605307da1b820cfba311ac008143348d59520f Mon Sep 17 00:00:00 2001 From: Daniil Loktev Date: Tue, 11 Nov 2025 10:13:03 +0300 Subject: [PATCH 64/77] codegen Signed-off-by: Daniil Loktev --- crds/virtualmachineclasses.yaml | 2 -- .../pkg/apiserver/api/generated/openapi/zz_generated.openapi.go | 2 +- 2 files changed, 1 insertion(+), 3 deletions(-) diff --git a/crds/virtualmachineclasses.yaml b/crds/virtualmachineclasses.yaml index 5ab54add7d..b98325cc2b 100644 --- a/crds/virtualmachineclasses.yaml +++ b/crds/virtualmachineclasses.yaml @@ -44,8 +44,6 @@ spec: description: |- VirtualMachineClass resource describes CPU requirements, node placement, and sizing policy for VM resources. A resource cannot be deleted as long as it is used in one of the VMs. - - Deprecated: Use v1alpha3.VirtualMachineClass instead. properties: apiVersion: description: |- diff --git a/images/virtualization-artifact/pkg/apiserver/api/generated/openapi/zz_generated.openapi.go b/images/virtualization-artifact/pkg/apiserver/api/generated/openapi/zz_generated.openapi.go index c2c474af65..fafb20b163 100644 --- a/images/virtualization-artifact/pkg/apiserver/api/generated/openapi/zz_generated.openapi.go +++ b/images/virtualization-artifact/pkg/apiserver/api/generated/openapi/zz_generated.openapi.go @@ -3760,7 +3760,7 @@ func schema_virtualization_api_core_v1alpha2_VirtualMachineClass(ref common.Refe return common.OpenAPIDefinition{ Schema: spec.Schema{ SchemaProps: spec.SchemaProps{ - Description: "VirtualMachineClass resource describes CPU requirements, node placement, and sizing policy for VM resources. A resource cannot be deleted as long as it is used in one of the VMs.\n\nDeprecated: Use v1alpha3.VirtualMachineClass instead.", + Description: "VirtualMachineClass resource describes CPU requirements, node placement, and sizing policy for VM resources. A resource cannot be deleted as long as it is used in one of the VMs.", Type: []string{"object"}, Properties: map[string]spec.Schema{ "kind": { From 9867d72264ab8b5df1d46fb367eafd26e3fa51d9 Mon Sep 17 00:00:00 2001 From: Daniil Loktev Date: Tue, 11 Nov 2025 10:44:02 +0300 Subject: [PATCH 65/77] wip Signed-off-by: Daniil Loktev --- .../pkg/controller/vmclass/vmclass_webhook.go | 15 ++++++++++++--- 1 file changed, 12 insertions(+), 3 deletions(-) diff --git a/images/virtualization-artifact/pkg/controller/vmclass/vmclass_webhook.go b/images/virtualization-artifact/pkg/controller/vmclass/vmclass_webhook.go index a19759310f..dbcc7bdc53 100644 --- a/images/virtualization-artifact/pkg/controller/vmclass/vmclass_webhook.go +++ b/images/virtualization-artifact/pkg/controller/vmclass/vmclass_webhook.go @@ -62,7 +62,10 @@ func (v *Validator) ValidateCreate(ctx context.Context, obj runtime.Object) (adm vmclass = obj case *v1alpha3.VirtualMachineClass: // Validate in webhook instead of CRD to provide clear error message - validateV1Alpha3CoreFractions(obj) + if err := validateV1Alpha3CoreFractions(obj); err != nil { + return nil, err + } + vmclass = &v1alpha2.VirtualMachineClass{} if err := vmclass.ConvertFrom(obj); err != nil { return nil, fmt.Errorf("failed to convert v1alpha3 to v1alpha2: %w", err) @@ -92,7 +95,10 @@ func (v *Validator) ValidateUpdate(ctx context.Context, oldObj, newObj runtime.O oldVMClass = oldObj case *v1alpha3.VirtualMachineClass: // Validate in webhook instead of CRD to provide clear error message - validateV1Alpha3CoreFractions(oldObj) + if err := validateV1Alpha3CoreFractions(oldObj); err != nil { + return nil, err + } + oldVMClass = &v1alpha2.VirtualMachineClass{} if err := oldVMClass.ConvertFrom(oldObj); err != nil { return nil, fmt.Errorf("failed to convert old v1alpha3 to v1alpha2: %w", err) @@ -106,7 +112,10 @@ func (v *Validator) ValidateUpdate(ctx context.Context, oldObj, newObj runtime.O newVMClass = newObj case *v1alpha3.VirtualMachineClass: // Validate in webhook instead of CRD to provide clear error message - validateV1Alpha3CoreFractions(newObj) + if err := validateV1Alpha3CoreFractions(newObj); err != nil { + return nil, err + } + newVMClass = &v1alpha2.VirtualMachineClass{} if err := newVMClass.ConvertFrom(newObj); err != nil { return nil, fmt.Errorf("failed to convert new v1alpha3 to v1alpha2: %w", err) From 3b207fb4e8794ae5c49e3d4f0fcc47b9732e10a0 Mon Sep 17 00:00:00 2001 From: Daniil Loktev Date: Tue, 11 Nov 2025 15:13:31 +0300 Subject: [PATCH 66/77] fix validation Signed-off-by: Daniil Loktev --- api/scripts/update-codegen.sh | 2 +- .../service/virtual_machine_class_service.go | 10 +-- .../defaulter/virtual_machine_class_name.go | 3 +- .../validators/policy_changes_validator.go | 5 +- .../single_default_class_validator.go | 10 +-- .../validators/sizing_policies_validator.go | 30 ++++++-- .../validators/validators_suite_test.go | 48 ++++++------- .../controller/vmclass/vmclass_controller.go | 13 +--- .../pkg/controller/vmclass/vmclass_webhook.go | 72 +++---------------- .../validation-webhook.yaml | 19 +---- 10 files changed, 75 insertions(+), 137 deletions(-) diff --git a/api/scripts/update-codegen.sh b/api/scripts/update-codegen.sh index 9c6e7d6502..7b4c4008d7 100755 --- a/api/scripts/update-codegen.sh +++ b/api/scripts/update-codegen.sh @@ -75,7 +75,7 @@ function generate::crds { OUTPUT_BASE=$(mktemp -d) trap 'rm -rf "${OUTPUT_BASE}"' ERR EXIT - go tool controller-gen crd:crdVersions=v1 paths="${API_ROOT}/core/v1alpha2/...;${API_ROOT}/core/v1alpha3/..." output:crd:dir="${OUTPUT_BASE}" + go tool controller-gen crd paths="${API_ROOT}/core/v1alpha2/...;${API_ROOT}/core/v1alpha3/..." output:crd:dir="${OUTPUT_BASE}" # shellcheck disable=SC2044 for file in $(find "${OUTPUT_BASE}"/* -type f -iname "*.yaml"); do diff --git a/images/virtualization-artifact/pkg/controller/service/virtual_machine_class_service.go b/images/virtualization-artifact/pkg/controller/service/virtual_machine_class_service.go index 420ffe66d6..4f3a755a03 100644 --- a/images/virtualization-artifact/pkg/controller/service/virtual_machine_class_service.go +++ b/images/virtualization-artifact/pkg/controller/service/virtual_machine_class_service.go @@ -22,7 +22,7 @@ import ( "sigs.k8s.io/controller-runtime/pkg/client" "github.com/deckhouse/virtualization-controller/pkg/common/annotations" - "github.com/deckhouse/virtualization/api/core/v1alpha2" + "github.com/deckhouse/virtualization/api/core/v1alpha3" ) type VirtualMachineClassService struct { @@ -35,14 +35,14 @@ func NewVirtualMachineClassService(client client.Client) *VirtualMachineClassSer } } -func (v *VirtualMachineClassService) IsDefault(vmClass *v1alpha2.VirtualMachineClass) bool { +func (v *VirtualMachineClassService) IsDefault(vmClass *v1alpha3.VirtualMachineClass) bool { if vmClass == nil { return false } return vmClass.Annotations[annotations.AnnVirtualMachineClassDefault] == "true" } -func (v *VirtualMachineClassService) ValidateDefaultAnnotation(vmClass *v1alpha2.VirtualMachineClass) error { +func (v *VirtualMachineClassService) ValidateDefaultAnnotation(vmClass *v1alpha3.VirtualMachineClass) error { if vmClass == nil { return nil } @@ -56,12 +56,12 @@ func (v *VirtualMachineClassService) ValidateDefaultAnnotation(vmClass *v1alpha2 return nil } -func (v *VirtualMachineClassService) GetDefault(classes *v1alpha2.VirtualMachineClassList) (*v1alpha2.VirtualMachineClass, error) { +func (v *VirtualMachineClassService) GetDefault(classes *v1alpha3.VirtualMachineClassList) (*v1alpha3.VirtualMachineClass, error) { if classes == nil { return nil, nil } - var defaultClass *v1alpha2.VirtualMachineClass + var defaultClass *v1alpha3.VirtualMachineClass for i := range classes.Items { if !v.IsDefault(&classes.Items[i]) { continue diff --git a/images/virtualization-artifact/pkg/controller/vm/internal/defaulter/virtual_machine_class_name.go b/images/virtualization-artifact/pkg/controller/vm/internal/defaulter/virtual_machine_class_name.go index 834afb6f5f..22298d574c 100644 --- a/images/virtualization-artifact/pkg/controller/vm/internal/defaulter/virtual_machine_class_name.go +++ b/images/virtualization-artifact/pkg/controller/vm/internal/defaulter/virtual_machine_class_name.go @@ -24,6 +24,7 @@ import ( "github.com/deckhouse/virtualization-controller/pkg/controller/service" "github.com/deckhouse/virtualization/api/core/v1alpha2" + "github.com/deckhouse/virtualization/api/core/v1alpha3" ) type VirtualMachineClassNameDefaulter struct { @@ -45,7 +46,7 @@ func (v *VirtualMachineClassNameDefaulter) Default(ctx context.Context, vm *v1al } // Detect and assign default class name. - classes := &v1alpha2.VirtualMachineClassList{} + classes := &v1alpha3.VirtualMachineClassList{} err := v.client.List(ctx, classes) if err != nil { return fmt.Errorf("failed to list virtual machine classes: %w", err) diff --git a/images/virtualization-artifact/pkg/controller/vmclass/internal/validators/policy_changes_validator.go b/images/virtualization-artifact/pkg/controller/vmclass/internal/validators/policy_changes_validator.go index 104f340060..177494455c 100644 --- a/images/virtualization-artifact/pkg/controller/vmclass/internal/validators/policy_changes_validator.go +++ b/images/virtualization-artifact/pkg/controller/vmclass/internal/validators/policy_changes_validator.go @@ -25,6 +25,7 @@ import ( "github.com/deckhouse/virtualization-controller/pkg/eventrecord" "github.com/deckhouse/virtualization/api/core/v1alpha2" + "github.com/deckhouse/virtualization/api/core/v1alpha3" ) type PolicyChangesValidator struct { @@ -35,11 +36,11 @@ func NewPolicyChangesValidator(recorder eventrecord.EventRecorderLogger) *Policy return &PolicyChangesValidator{recorder: recorder} } -func (v *PolicyChangesValidator) ValidateCreate(_ context.Context, _ *v1alpha2.VirtualMachineClass) (admission.Warnings, error) { +func (v *PolicyChangesValidator) ValidateCreate(_ context.Context, _ *v1alpha3.VirtualMachineClass) (admission.Warnings, error) { return nil, nil } -func (v *PolicyChangesValidator) ValidateUpdate(_ context.Context, oldVMClass, newVMClass *v1alpha2.VirtualMachineClass) (admission.Warnings, error) { +func (v *PolicyChangesValidator) ValidateUpdate(_ context.Context, oldVMClass, newVMClass *v1alpha3.VirtualMachineClass) (admission.Warnings, error) { if !reflect.DeepEqual(oldVMClass.Spec.SizingPolicies, newVMClass.Spec.SizingPolicies) { v.recorder.Event(newVMClass, corev1.EventTypeNormal, v1alpha2.ReasonVMClassSizingPoliciesWereChanged, "Sizing policies were changed") } diff --git a/images/virtualization-artifact/pkg/controller/vmclass/internal/validators/single_default_class_validator.go b/images/virtualization-artifact/pkg/controller/vmclass/internal/validators/single_default_class_validator.go index 1fa89031c9..a73d294517 100644 --- a/images/virtualization-artifact/pkg/controller/vmclass/internal/validators/single_default_class_validator.go +++ b/images/virtualization-artifact/pkg/controller/vmclass/internal/validators/single_default_class_validator.go @@ -25,7 +25,7 @@ import ( "github.com/deckhouse/virtualization-controller/pkg/common/annotations" "github.com/deckhouse/virtualization-controller/pkg/controller/service" - "github.com/deckhouse/virtualization/api/core/v1alpha2" + "github.com/deckhouse/virtualization/api/core/v1alpha3" ) type SingleDefaultClassValidator struct { @@ -40,7 +40,7 @@ func NewSingleDefaultClassValidator(client client.Client, vmClassService *servic } } -func (v *SingleDefaultClassValidator) ValidateCreate(ctx context.Context, vmClass *v1alpha2.VirtualMachineClass) (admission.Warnings, error) { +func (v *SingleDefaultClassValidator) ValidateCreate(ctx context.Context, vmClass *v1alpha3.VirtualMachineClass) (admission.Warnings, error) { err := v.vmClassService.ValidateDefaultAnnotation(vmClass) if err != nil { return nil, err @@ -54,7 +54,7 @@ func (v *SingleDefaultClassValidator) ValidateCreate(ctx context.Context, vmClas return nil, nil } -func (v *SingleDefaultClassValidator) ValidateUpdate(ctx context.Context, _, newVMClass *v1alpha2.VirtualMachineClass) (admission.Warnings, error) { +func (v *SingleDefaultClassValidator) ValidateUpdate(ctx context.Context, _, newVMClass *v1alpha3.VirtualMachineClass) (admission.Warnings, error) { err := v.vmClassService.ValidateDefaultAnnotation(newVMClass) if err != nil { return nil, err @@ -68,8 +68,8 @@ func (v *SingleDefaultClassValidator) ValidateUpdate(ctx context.Context, _, new return nil, nil } -func (v *SingleDefaultClassValidator) checkDefaultIsSingle(ctx context.Context, vmClass *v1alpha2.VirtualMachineClass) error { - classes := &v1alpha2.VirtualMachineClassList{} +func (v *SingleDefaultClassValidator) checkDefaultIsSingle(ctx context.Context, vmClass *v1alpha3.VirtualMachineClass) error { + classes := &v1alpha3.VirtualMachineClassList{} err := v.client.List(ctx, classes) if err != nil { return fmt.Errorf("failed to list virtual machine classes: %w", err) diff --git a/images/virtualization-artifact/pkg/controller/vmclass/internal/validators/sizing_policies_validator.go b/images/virtualization-artifact/pkg/controller/vmclass/internal/validators/sizing_policies_validator.go index d31d65029d..0d6ea89a53 100644 --- a/images/virtualization-artifact/pkg/controller/vmclass/internal/validators/sizing_policies_validator.go +++ b/images/virtualization-artifact/pkg/controller/vmclass/internal/validators/sizing_policies_validator.go @@ -19,11 +19,12 @@ package validators import ( "context" "fmt" + "regexp" "sigs.k8s.io/controller-runtime/pkg/client" "sigs.k8s.io/controller-runtime/pkg/webhook/admission" - "github.com/deckhouse/virtualization/api/core/v1alpha2" + "github.com/deckhouse/virtualization/api/core/v1alpha3" ) type SizingPoliciesValidator struct { @@ -34,7 +35,11 @@ func NewSizingPoliciesValidator(client client.Client) *SizingPoliciesValidator { return &SizingPoliciesValidator{client: client} } -func (v *SizingPoliciesValidator) ValidateCreate(_ context.Context, vmclass *v1alpha2.VirtualMachineClass) (admission.Warnings, error) { +func (v *SizingPoliciesValidator) ValidateCreate(_ context.Context, vmclass *v1alpha3.VirtualMachineClass) (admission.Warnings, error) { + if err := validateCoreFractions(vmclass); err != nil { + return nil, err + } + if !HasValidCores(&vmclass.Spec) { return nil, fmt.Errorf("vmclass %s has sizing policies but none of them specify cores", vmclass.Name) } @@ -46,7 +51,11 @@ func (v *SizingPoliciesValidator) ValidateCreate(_ context.Context, vmclass *v1a return nil, nil } -func (v *SizingPoliciesValidator) ValidateUpdate(_ context.Context, _, newVMClass *v1alpha2.VirtualMachineClass) (admission.Warnings, error) { +func (v *SizingPoliciesValidator) ValidateUpdate(_ context.Context, _, newVMClass *v1alpha3.VirtualMachineClass) (admission.Warnings, error) { + if err := validateCoreFractions(newVMClass); err != nil { + return nil, err + } + if HasCPUSizePoliciesCrosses(&newVMClass.Spec) { return nil, fmt.Errorf("vmclass %s has size policy cpu crosses", newVMClass.Name) } @@ -54,7 +63,7 @@ func (v *SizingPoliciesValidator) ValidateUpdate(_ context.Context, _, newVMClas return nil, nil } -func HasCPUSizePoliciesCrosses(vmclass *v1alpha2.VirtualMachineClassSpec) bool { +func HasCPUSizePoliciesCrosses(vmclass *v1alpha3.VirtualMachineClassSpec) bool { usedPairs := make(map[[2]int]struct{}) for i, policy1 := range vmclass.SizingPolicies { @@ -87,7 +96,7 @@ func HasCPUSizePoliciesCrosses(vmclass *v1alpha2.VirtualMachineClassSpec) bool { return false } -func HasValidCores(vmclass *v1alpha2.VirtualMachineClassSpec) bool { +func HasValidCores(vmclass *v1alpha3.VirtualMachineClassSpec) bool { if len(vmclass.SizingPolicies) == 0 { return true } @@ -99,3 +108,14 @@ func HasValidCores(vmclass *v1alpha2.VirtualMachineClassSpec) bool { } return true } + +func validateCoreFractions(vmclass *v1alpha3.VirtualMachineClass) error { + for i, policy := range vmclass.Spec.SizingPolicies { + for j, coreFraction := range policy.CoreFractions { + if !regexp.MustCompile(`^([1-9]|[1-9][0-9]|100)%$`).MatchString(string(coreFraction)) { + return fmt.Errorf("spec.sizingPolicies[%d].coreFractions[%d]: coreFraction must be a percentage between 1%% and 100%% (e.g., 5%%, 10%%, 50%%), got %q", i, j, coreFraction) + } + } + } + return nil +} diff --git a/images/virtualization-artifact/pkg/controller/vmclass/internal/validators/validators_suite_test.go b/images/virtualization-artifact/pkg/controller/vmclass/internal/validators/validators_suite_test.go index 0bd0d5d38b..0441f0f74d 100644 --- a/images/virtualization-artifact/pkg/controller/vmclass/internal/validators/validators_suite_test.go +++ b/images/virtualization-artifact/pkg/controller/vmclass/internal/validators/validators_suite_test.go @@ -28,7 +28,7 @@ import ( "github.com/deckhouse/virtualization-controller/pkg/common/testutil" "github.com/deckhouse/virtualization-controller/pkg/controller/service" "github.com/deckhouse/virtualization-controller/pkg/controller/vmclass/internal/validators" - "github.com/deckhouse/virtualization/api/core/v1alpha2" + "github.com/deckhouse/virtualization/api/core/v1alpha3" ) func TestValidators(t *testing.T) { @@ -37,11 +37,11 @@ func TestValidators(t *testing.T) { } var _ = Describe("Spec policies validator", func() { - var vmclass v1alpha2.VirtualMachineClass + var vmclass v1alpha3.VirtualMachineClass Context("empty vmclass", func() { BeforeEach(func() { - vmclass = v1alpha2.VirtualMachineClass{} + vmclass = v1alpha3.VirtualMachineClass{} }) It("Should return no problem when empty value", func() { @@ -51,23 +51,23 @@ var _ = Describe("Spec policies validator", func() { Context("vmclass with no cpu size policies crosses", func() { BeforeEach(func() { - vmclass = v1alpha2.VirtualMachineClass{} - vmclass.Spec.SizingPolicies = append(vmclass.Spec.SizingPolicies, v1alpha2.SizingPolicy{ - Cores: &v1alpha2.SizingPolicyCores{ + vmclass = v1alpha3.VirtualMachineClass{} + vmclass.Spec.SizingPolicies = append(vmclass.Spec.SizingPolicies, v1alpha3.SizingPolicy{ + Cores: &v1alpha3.SizingPolicyCores{ Min: 1, Max: 4, Step: 1, }, }) - vmclass.Spec.SizingPolicies = append(vmclass.Spec.SizingPolicies, v1alpha2.SizingPolicy{ - Cores: &v1alpha2.SizingPolicyCores{ + vmclass.Spec.SizingPolicies = append(vmclass.Spec.SizingPolicies, v1alpha3.SizingPolicy{ + Cores: &v1alpha3.SizingPolicyCores{ Min: 5, Max: 9, Step: 1, }, }) - vmclass.Spec.SizingPolicies = append(vmclass.Spec.SizingPolicies, v1alpha2.SizingPolicy{ - Cores: &v1alpha2.SizingPolicyCores{ + vmclass.Spec.SizingPolicies = append(vmclass.Spec.SizingPolicies, v1alpha3.SizingPolicy{ + Cores: &v1alpha3.SizingPolicyCores{ Min: 10, Max: 15, Step: 1, @@ -82,23 +82,23 @@ var _ = Describe("Spec policies validator", func() { Context("vmclass with cpu size policies crosses", func() { BeforeEach(func() { - vmclass = v1alpha2.VirtualMachineClass{} - vmclass.Spec.SizingPolicies = append(vmclass.Spec.SizingPolicies, v1alpha2.SizingPolicy{ - Cores: &v1alpha2.SizingPolicyCores{ + vmclass = v1alpha3.VirtualMachineClass{} + vmclass.Spec.SizingPolicies = append(vmclass.Spec.SizingPolicies, v1alpha3.SizingPolicy{ + Cores: &v1alpha3.SizingPolicyCores{ Min: 1, Max: 4, Step: 1, }, }) - vmclass.Spec.SizingPolicies = append(vmclass.Spec.SizingPolicies, v1alpha2.SizingPolicy{ - Cores: &v1alpha2.SizingPolicyCores{ + vmclass.Spec.SizingPolicies = append(vmclass.Spec.SizingPolicies, v1alpha3.SizingPolicy{ + Cores: &v1alpha3.SizingPolicyCores{ Min: 4, Max: 9, Step: 1, }, }) - vmclass.Spec.SizingPolicies = append(vmclass.Spec.SizingPolicies, v1alpha2.SizingPolicy{ - Cores: &v1alpha2.SizingPolicyCores{ + vmclass.Spec.SizingPolicies = append(vmclass.Spec.SizingPolicies, v1alpha3.SizingPolicy{ + Cores: &v1alpha3.SizingPolicyCores{ Min: 10, Max: 15, Step: 1, @@ -126,21 +126,21 @@ var _ = Describe("Single default class validator", func() { validator = validators.NewSingleDefaultClassValidator(fakeClient, vmClassService) } - newVMClass := func(name string) *v1alpha2.VirtualMachineClass { - return &v1alpha2.VirtualMachineClass{ + newVMClass := func(name string) *v1alpha3.VirtualMachineClass { + return &v1alpha3.VirtualMachineClass{ TypeMeta: metav1.TypeMeta{ - Kind: v1alpha2.VirtualMachineClassKind, - APIVersion: v1alpha2.SchemeGroupVersion.String(), + Kind: v1alpha3.VirtualMachineClassKind, + APIVersion: v1alpha3.SchemeGroupVersion.String(), }, ObjectMeta: metav1.ObjectMeta{ Name: name, }, - Spec: v1alpha2.VirtualMachineClassSpec{}, - Status: v1alpha2.VirtualMachineClassStatus{}, + Spec: v1alpha3.VirtualMachineClassSpec{}, + Status: v1alpha3.VirtualMachineClassStatus{}, } } - newDefaultVMClass := func(name string) *v1alpha2.VirtualMachineClass { + newDefaultVMClass := func(name string) *v1alpha3.VirtualMachineClass { vmClass := newVMClass(name) vmClass.Annotations = map[string]string{ annotations.AnnVirtualMachineClassDefault: "true", diff --git a/images/virtualization-artifact/pkg/controller/vmclass/vmclass_controller.go b/images/virtualization-artifact/pkg/controller/vmclass/vmclass_controller.go index 19889dec25..289a7935e3 100644 --- a/images/virtualization-artifact/pkg/controller/vmclass/vmclass_controller.go +++ b/images/virtualization-artifact/pkg/controller/vmclass/vmclass_controller.go @@ -30,7 +30,6 @@ import ( "github.com/deckhouse/virtualization-controller/pkg/controller/vmclass/internal" "github.com/deckhouse/virtualization-controller/pkg/eventrecord" "github.com/deckhouse/virtualization-controller/pkg/logger" - "github.com/deckhouse/virtualization/api/core/v1alpha2" "github.com/deckhouse/virtualization/api/core/v1alpha3" ) @@ -59,7 +58,6 @@ func NewController( RecoverPanic: ptr.To(true), LogConstructor: logger.NewConstructor(log), CacheSyncTimeout: 10 * time.Minute, - UsePriorityQueue: ptr.To(true), }) if err != nil { return nil, err @@ -69,18 +67,9 @@ func NewController( return nil, err } - validator := NewValidator(mgr.GetClient(), log, recorder, vmClassService) - - if err = builder.WebhookManagedBy(mgr). - For(&v1alpha2.VirtualMachineClass{}). - WithValidator(validator). - Complete(); err != nil { - return nil, err - } - if err = builder.WebhookManagedBy(mgr). For(&v1alpha3.VirtualMachineClass{}). - WithValidator(validator). + WithValidator(NewValidator(mgr.GetClient(), log, recorder, vmClassService)). Complete(); err != nil { return nil, err } diff --git a/images/virtualization-artifact/pkg/controller/vmclass/vmclass_webhook.go b/images/virtualization-artifact/pkg/controller/vmclass/vmclass_webhook.go index dbcc7bdc53..090150edf9 100644 --- a/images/virtualization-artifact/pkg/controller/vmclass/vmclass_webhook.go +++ b/images/virtualization-artifact/pkg/controller/vmclass/vmclass_webhook.go @@ -1,12 +1,9 @@ /* Copyright 2024 Flant JSC - Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with the License. You may obtain a copy of the License at - http://www.apache.org/licenses/LICENSE-2.0 - Unless required by applicable law or agreed to in writing, software distributed under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. @@ -19,7 +16,6 @@ package vmclass import ( "context" "fmt" - "regexp" "k8s.io/apimachinery/pkg/runtime" "sigs.k8s.io/controller-runtime/pkg/client" @@ -29,13 +25,12 @@ import ( "github.com/deckhouse/virtualization-controller/pkg/controller/service" "github.com/deckhouse/virtualization-controller/pkg/controller/vmclass/internal/validators" "github.com/deckhouse/virtualization-controller/pkg/eventrecord" - "github.com/deckhouse/virtualization/api/core/v1alpha2" "github.com/deckhouse/virtualization/api/core/v1alpha3" ) type VirtualMachineClassValidator interface { - ValidateCreate(ctx context.Context, vm *v1alpha2.VirtualMachineClass) (admission.Warnings, error) - ValidateUpdate(ctx context.Context, oldVM, newVM *v1alpha2.VirtualMachineClass) (admission.Warnings, error) + ValidateCreate(ctx context.Context, vm *v1alpha3.VirtualMachineClass) (admission.Warnings, error) + ValidateUpdate(ctx context.Context, oldVM, newVM *v1alpha3.VirtualMachineClass) (admission.Warnings, error) } type Validator struct { @@ -55,22 +50,8 @@ func NewValidator(client client.Client, log *log.Logger, recorder eventrecord.Ev } func (v *Validator) ValidateCreate(ctx context.Context, obj runtime.Object) (admission.Warnings, error) { - var vmclass *v1alpha2.VirtualMachineClass - - switch obj := obj.(type) { - case *v1alpha2.VirtualMachineClass: - vmclass = obj - case *v1alpha3.VirtualMachineClass: - // Validate in webhook instead of CRD to provide clear error message - if err := validateV1Alpha3CoreFractions(obj); err != nil { - return nil, err - } - - vmclass = &v1alpha2.VirtualMachineClass{} - if err := vmclass.ConvertFrom(obj); err != nil { - return nil, fmt.Errorf("failed to convert v1alpha3 to v1alpha2: %w", err) - } - default: + vmclass, ok := obj.(*v1alpha3.VirtualMachineClass) + if !ok { return nil, fmt.Errorf("expected a VirtualMachineClass but got a %T", obj) } @@ -88,39 +69,13 @@ func (v *Validator) ValidateCreate(ctx context.Context, obj runtime.Object) (adm } func (v *Validator) ValidateUpdate(ctx context.Context, oldObj, newObj runtime.Object) (admission.Warnings, error) { - var oldVMClass, newVMClass *v1alpha2.VirtualMachineClass - - switch oldObj := oldObj.(type) { - case *v1alpha2.VirtualMachineClass: - oldVMClass = oldObj - case *v1alpha3.VirtualMachineClass: - // Validate in webhook instead of CRD to provide clear error message - if err := validateV1Alpha3CoreFractions(oldObj); err != nil { - return nil, err - } - - oldVMClass = &v1alpha2.VirtualMachineClass{} - if err := oldVMClass.ConvertFrom(oldObj); err != nil { - return nil, fmt.Errorf("failed to convert old v1alpha3 to v1alpha2: %w", err) - } - default: + oldVMClass, ok := oldObj.(*v1alpha3.VirtualMachineClass) + if !ok { return nil, fmt.Errorf("expected an old VirtualMachineClass but got a %T", oldObj) } - switch newObj := newObj.(type) { - case *v1alpha2.VirtualMachineClass: - newVMClass = newObj - case *v1alpha3.VirtualMachineClass: - // Validate in webhook instead of CRD to provide clear error message - if err := validateV1Alpha3CoreFractions(newObj); err != nil { - return nil, err - } - - newVMClass = &v1alpha2.VirtualMachineClass{} - if err := newVMClass.ConvertFrom(newObj); err != nil { - return nil, fmt.Errorf("failed to convert new v1alpha3 to v1alpha2: %w", err) - } - default: + newVMClass, ok := newObj.(*v1alpha3.VirtualMachineClass) + if !ok { return nil, fmt.Errorf("expected a new VirtualMachineClass but got a %T", newObj) } @@ -142,14 +97,3 @@ func (v *Validator) ValidateDelete(_ context.Context, _ runtime.Object) (admissi v.log.Error("Ensure the correctness of ValidatingWebhookConfiguration", "err", err.Error()) return nil, nil } - -func validateV1Alpha3CoreFractions(vmclass *v1alpha3.VirtualMachineClass) error { - for i, policy := range vmclass.Spec.SizingPolicies { - for j, coreFraction := range policy.CoreFractions { - if !regexp.MustCompile(`^([1-9]|[1-9][0-9]|100)%$`).MatchString(string(coreFraction)) { - return fmt.Errorf("spec.sizingPolicies[%d].coreFractions[%d]: coreFraction must be a percentage between 1%% and 100%% (e.g., 5%%, 10%%, 50%%), got %q", i, j, coreFraction) - } - } - } - return nil -} diff --git a/templates/virtualization-controller/validation-webhook.yaml b/templates/virtualization-controller/validation-webhook.yaml index 9d29166f4f..0b52e0bf08 100644 --- a/templates/virtualization-controller/validation-webhook.yaml +++ b/templates/virtualization-controller/validation-webhook.yaml @@ -209,24 +209,7 @@ webhooks: {{ .Values.virtualization.internal.controller.cert.ca | b64enc }} admissionReviewVersions: ["v1"] sideEffects: None - - name: "vmclass-v1alpha2.virtualization-controller.validate.d8-virtualization" - rules: - - apiGroups: ["virtualization.deckhouse.io"] - apiVersions: ["v1alpha2"] - operations: ["CREATE", "UPDATE"] - resources: ["virtualmachineclasses"] - scope: "Cluster" - clientConfig: - service: - namespace: d8-{{ .Chart.Name }} - name: virtualization-controller - path: /validate-virtualization-deckhouse-io-v1alpha2-virtualmachineclass - port: 443 - caBundle: | - {{ .Values.virtualization.internal.controller.cert.ca | b64enc }} - admissionReviewVersions: ["v1"] - sideEffects: None - - name: "vmclass-v1alpha3.virtualization-controller.validate.d8-virtualization" + - name: "vmclass.virtualization-controller.validate.d8-virtualization" rules: - apiGroups: ["virtualization.deckhouse.io"] apiVersions: ["v1alpha3"] From b0b08b06ef428d53e6c67aadaa3d5b0c7f9270ba Mon Sep 17 00:00:00 2001 From: Daniil Loktev Date: Tue, 11 Nov 2025 15:20:44 +0300 Subject: [PATCH 67/77] fix license Signed-off-by: Daniil Loktev --- .../pkg/controller/vmclass/vmclass_webhook.go | 3 +++ 1 file changed, 3 insertions(+) diff --git a/images/virtualization-artifact/pkg/controller/vmclass/vmclass_webhook.go b/images/virtualization-artifact/pkg/controller/vmclass/vmclass_webhook.go index 090150edf9..5b9738452a 100644 --- a/images/virtualization-artifact/pkg/controller/vmclass/vmclass_webhook.go +++ b/images/virtualization-artifact/pkg/controller/vmclass/vmclass_webhook.go @@ -1,9 +1,12 @@ /* Copyright 2024 Flant JSC + Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with the License. You may obtain a copy of the License at + http://www.apache.org/licenses/LICENSE-2.0 + Unless required by applicable law or agreed to in writing, software distributed under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. From adbaa0e02f3c52ba326273e39f753ac2b8053eef Mon Sep 17 00:00:00 2001 From: Daniil Loktev Date: Tue, 11 Nov 2025 15:42:48 +0300 Subject: [PATCH 68/77] fix unit tests Signed-off-by: Daniil Loktev --- .../pkg/common/testutil/testutil.go | 3 +++ .../internal/defaulter/defaulters_suite_test.go | 15 ++++++++------- 2 files changed, 11 insertions(+), 7 deletions(-) diff --git a/images/virtualization-artifact/pkg/common/testutil/testutil.go b/images/virtualization-artifact/pkg/common/testutil/testutil.go index 05fa961d64..c4e139a0a7 100644 --- a/images/virtualization-artifact/pkg/common/testutil/testutil.go +++ b/images/virtualization-artifact/pkg/common/testutil/testutil.go @@ -33,12 +33,14 @@ import ( "github.com/deckhouse/deckhouse/pkg/log" "github.com/deckhouse/virtualization-controller/pkg/controller/indexer" "github.com/deckhouse/virtualization/api/core/v1alpha2" + "github.com/deckhouse/virtualization/api/core/v1alpha3" ) func NewFakeClientWithObjects(objs ...client.Object) (client.WithWatch, error) { scheme := apiruntime.NewScheme() for _, f := range []func(*apiruntime.Scheme) error{ v1alpha2.AddToScheme, + v1alpha3.AddToScheme, virtv1.AddToScheme, cdiv1.AddToScheme, clientgoscheme.AddToScheme, @@ -67,6 +69,7 @@ func NewFakeClientWithInterceptorWithObjects(interceptor interceptor.Funcs, objs scheme := apiruntime.NewScheme() for _, f := range []func(*apiruntime.Scheme) error{ v1alpha2.AddToScheme, + v1alpha3.AddToScheme, virtv1.AddToScheme, cdiv1.AddToScheme, clientgoscheme.AddToScheme, diff --git a/images/virtualization-artifact/pkg/controller/vm/internal/defaulter/defaulters_suite_test.go b/images/virtualization-artifact/pkg/controller/vm/internal/defaulter/defaulters_suite_test.go index 35c9398e98..242747ce35 100644 --- a/images/virtualization-artifact/pkg/controller/vm/internal/defaulter/defaulters_suite_test.go +++ b/images/virtualization-artifact/pkg/controller/vm/internal/defaulter/defaulters_suite_test.go @@ -29,6 +29,7 @@ import ( "github.com/deckhouse/virtualization-controller/pkg/controller/service" "github.com/deckhouse/virtualization-controller/pkg/controller/vm/internal/defaulter" "github.com/deckhouse/virtualization/api/core/v1alpha2" + "github.com/deckhouse/virtualization/api/core/v1alpha3" ) func TestDefaulters(t *testing.T) { @@ -50,21 +51,21 @@ var _ = Describe("Set default class in virtualMachineClasName", func() { classDefaulter = defaulter.NewVirtualMachineClassNameDefaulter(fakeClient, vmClassService) } - newVMClass := func(name string) *v1alpha2.VirtualMachineClass { - return &v1alpha2.VirtualMachineClass{ + newVMClass := func(name string) *v1alpha3.VirtualMachineClass { + return &v1alpha3.VirtualMachineClass{ TypeMeta: metav1.TypeMeta{ - Kind: v1alpha2.VirtualMachineClassKind, - APIVersion: v1alpha2.SchemeGroupVersion.String(), + Kind: v1alpha3.VirtualMachineClassKind, + APIVersion: v1alpha3.SchemeGroupVersion.String(), }, ObjectMeta: metav1.ObjectMeta{ Name: name, }, - Spec: v1alpha2.VirtualMachineClassSpec{}, - Status: v1alpha2.VirtualMachineClassStatus{}, + Spec: v1alpha3.VirtualMachineClassSpec{}, + Status: v1alpha3.VirtualMachineClassStatus{}, } } - newDefaultVMClass := func(name string) *v1alpha2.VirtualMachineClass { + newDefaultVMClass := func(name string) *v1alpha3.VirtualMachineClass { vmClass := newVMClass(name) vmClass.Annotations = map[string]string{ annotations.AnnVirtualMachineClassDefault: "true", From f97746e96c5bcfdced3bdbc4692711bcc92e4c6b Mon Sep 17 00:00:00 2001 From: Daniil Loktev Date: Fri, 14 Nov 2025 12:44:08 +0300 Subject: [PATCH 69/77] revert vmclass generic Signed-off-by: Daniil Loktev --- .../virtualization-controller/vmclasses-default.yaml | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/templates/virtualization-controller/vmclasses-default.yaml b/templates/virtualization-controller/vmclasses-default.yaml index 2bbf9c7288..f2beb27764 100644 --- a/templates/virtualization-controller/vmclasses-default.yaml +++ b/templates/virtualization-controller/vmclasses-default.yaml @@ -1,4 +1,4 @@ -apiVersion: virtualization.deckhouse.io/v1alpha3 +apiVersion: virtualization.deckhouse.io/v1alpha2 kind: VirtualMachineClass metadata: name: generic @@ -16,19 +16,19 @@ spec: min: 1 max: 4 dedicatedCores: [false] - coreFractions: ["5%", "10%", "20%", "50%", "100%"] + coreFractions: [5, 10, 20, 50, 100] - cores: min: 5 max: 8 dedicatedCores: [false] - coreFractions: ["20%", "50%", "100%"] + coreFractions: [20, 50, 100] - cores: min: 9 max: 16 dedicatedCores: [true, false] - coreFractions: ["50%", "100%"] + coreFractions: [50, 100] - cores: min: 17 max: 1024 dedicatedCores: [true, false] - coreFractions: ["100%"] + coreFractions: [100] From 3980645068eedec392151e1310239290c3294bd9 Mon Sep 17 00:00:00 2001 From: Daniil Loktev Date: Fri, 14 Nov 2025 13:15:05 +0300 Subject: [PATCH 70/77] wip Signed-off-by: Daniil Loktev --- templates/virtualization-controller/vmclasses-default.yaml | 3 +++ 1 file changed, 3 insertions(+) diff --git a/templates/virtualization-controller/vmclasses-default.yaml b/templates/virtualization-controller/vmclasses-default.yaml index f2beb27764..7566f91581 100644 --- a/templates/virtualization-controller/vmclasses-default.yaml +++ b/templates/virtualization-controller/vmclasses-default.yaml @@ -2,6 +2,9 @@ apiVersion: virtualization.deckhouse.io/v1alpha2 kind: VirtualMachineClass metadata: name: generic + annotations: + "helm.sh/hook": post-install,post-upgrade + "helm.sh/hook-weight": "100" {{- include "helm_lib_module_labels" (list . (dict "app" "virtualization-controller")) | nindent 2 }} spec: nodeSelector: From be3280dd3109cebdcb5f97bde19d05ed9bab055e Mon Sep 17 00:00:00 2001 From: Daniil Loktev Date: Fri, 14 Nov 2025 13:59:26 +0300 Subject: [PATCH 71/77] add hook for validting webhook configuration Signed-off-by: Daniil Loktev --- templates/virtualization-controller/validation-webhook.yaml | 3 +++ 1 file changed, 3 insertions(+) diff --git a/templates/virtualization-controller/validation-webhook.yaml b/templates/virtualization-controller/validation-webhook.yaml index 0b52e0bf08..e4822613a2 100644 --- a/templates/virtualization-controller/validation-webhook.yaml +++ b/templates/virtualization-controller/validation-webhook.yaml @@ -2,6 +2,9 @@ apiVersion: admissionregistration.k8s.io/v1 kind: ValidatingWebhookConfiguration metadata: + annotations: + "helm.sh/hook": post-install,post-upgrade + "helm.sh/hook-weight": "10" {{- include "helm_lib_module_labels" (list . (dict "app" "virtualization-controller")) | nindent 2 }} name: "virtualization-controller-admission-webhook" webhooks: From 5ac1a9977f52c20447fbc0bf5a2ac338b0bb2a85 Mon Sep 17 00:00:00 2001 From: Daniil Loktev Date: Fri, 14 Nov 2025 15:28:30 +0300 Subject: [PATCH 72/77] wip Signed-off-by: Daniil Loktev --- .../virtualization-controller/vmclasses-default.yaml | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/templates/virtualization-controller/vmclasses-default.yaml b/templates/virtualization-controller/vmclasses-default.yaml index 7566f91581..e8e18f9bce 100644 --- a/templates/virtualization-controller/vmclasses-default.yaml +++ b/templates/virtualization-controller/vmclasses-default.yaml @@ -1,4 +1,4 @@ -apiVersion: virtualization.deckhouse.io/v1alpha2 +apiVersion: virtualization.deckhouse.io/v1alpha3 kind: VirtualMachineClass metadata: name: generic @@ -19,19 +19,19 @@ spec: min: 1 max: 4 dedicatedCores: [false] - coreFractions: [5, 10, 20, 50, 100] + coreFractions: ["5%", "10%", "20%", "50%", "100%"] - cores: min: 5 max: 8 dedicatedCores: [false] - coreFractions: [20, 50, 100] + coreFractions: ["20%", "50%", "100%"] - cores: min: 9 max: 16 dedicatedCores: [true, false] - coreFractions: [50, 100] + coreFractions: ["50%", "100%"] - cores: min: 17 max: 1024 dedicatedCores: [true, false] - coreFractions: [100] + coreFractions: ["100%"] From c1b371623338fb6bd0f6cb61c60dbb6b5184e68c Mon Sep 17 00:00:00 2001 From: Daniil Loktev Date: Fri, 14 Nov 2025 17:01:32 +0300 Subject: [PATCH 73/77] wip Signed-off-by: Daniil Loktev --- templates/virtualization-controller/vmclasses-default.yaml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/templates/virtualization-controller/vmclasses-default.yaml b/templates/virtualization-controller/vmclasses-default.yaml index e8e18f9bce..6baa487f0f 100644 --- a/templates/virtualization-controller/vmclasses-default.yaml +++ b/templates/virtualization-controller/vmclasses-default.yaml @@ -4,7 +4,7 @@ metadata: name: generic annotations: "helm.sh/hook": post-install,post-upgrade - "helm.sh/hook-weight": "100" + "helm.sh/hook-weight": "200" {{- include "helm_lib_module_labels" (list . (dict "app" "virtualization-controller")) | nindent 2 }} spec: nodeSelector: From 3c8f1cdb98500359943c285e4f0c983cd2c6fb9a Mon Sep 17 00:00:00 2001 From: Daniil Loktev Date: Fri, 14 Nov 2025 17:53:17 +0300 Subject: [PATCH 74/77] add v1alpha2 validation Signed-off-by: Daniil Loktev --- .../controller/vmclass/vmclass_controller.go | 12 +++++- .../pkg/controller/vmclass/vmclass_webhook.go | 38 ++++++++++++++++--- .../validation-webhook.yaml | 24 ++++++++++-- .../vmclasses-default.yaml | 3 -- 4 files changed, 63 insertions(+), 14 deletions(-) diff --git a/images/virtualization-artifact/pkg/controller/vmclass/vmclass_controller.go b/images/virtualization-artifact/pkg/controller/vmclass/vmclass_controller.go index 289a7935e3..96033a289c 100644 --- a/images/virtualization-artifact/pkg/controller/vmclass/vmclass_controller.go +++ b/images/virtualization-artifact/pkg/controller/vmclass/vmclass_controller.go @@ -30,6 +30,7 @@ import ( "github.com/deckhouse/virtualization-controller/pkg/controller/vmclass/internal" "github.com/deckhouse/virtualization-controller/pkg/eventrecord" "github.com/deckhouse/virtualization-controller/pkg/logger" + "github.com/deckhouse/virtualization/api/core/v1alpha2" "github.com/deckhouse/virtualization/api/core/v1alpha3" ) @@ -67,9 +68,18 @@ func NewController( return nil, err } + validator := NewValidator(mgr.GetClient(), log, recorder, vmClassService) + + if err = builder.WebhookManagedBy(mgr). + For(&v1alpha2.VirtualMachineClass{}). + WithValidator(validator). + Complete(); err != nil { + return nil, err + } + if err = builder.WebhookManagedBy(mgr). For(&v1alpha3.VirtualMachineClass{}). - WithValidator(NewValidator(mgr.GetClient(), log, recorder, vmClassService)). + WithValidator(validator). Complete(); err != nil { return nil, err } diff --git a/images/virtualization-artifact/pkg/controller/vmclass/vmclass_webhook.go b/images/virtualization-artifact/pkg/controller/vmclass/vmclass_webhook.go index 5b9738452a..3c41129e3f 100644 --- a/images/virtualization-artifact/pkg/controller/vmclass/vmclass_webhook.go +++ b/images/virtualization-artifact/pkg/controller/vmclass/vmclass_webhook.go @@ -28,6 +28,7 @@ import ( "github.com/deckhouse/virtualization-controller/pkg/controller/service" "github.com/deckhouse/virtualization-controller/pkg/controller/vmclass/internal/validators" "github.com/deckhouse/virtualization-controller/pkg/eventrecord" + "github.com/deckhouse/virtualization/api/core/v1alpha2" "github.com/deckhouse/virtualization/api/core/v1alpha3" ) @@ -53,8 +54,17 @@ func NewValidator(client client.Client, log *log.Logger, recorder eventrecord.Ev } func (v *Validator) ValidateCreate(ctx context.Context, obj runtime.Object) (admission.Warnings, error) { - vmclass, ok := obj.(*v1alpha3.VirtualMachineClass) - if !ok { + var vmclass *v1alpha3.VirtualMachineClass + + switch o := obj.(type) { + case *v1alpha3.VirtualMachineClass: + vmclass = o + case *v1alpha2.VirtualMachineClass: + vmclass = &v1alpha3.VirtualMachineClass{} + if err := o.ConvertTo(vmclass); err != nil { + return nil, fmt.Errorf("failed to convert v1alpha2 to v1alpha3: %w", err) + } + default: return nil, fmt.Errorf("expected a VirtualMachineClass but got a %T", obj) } @@ -72,13 +82,29 @@ func (v *Validator) ValidateCreate(ctx context.Context, obj runtime.Object) (adm } func (v *Validator) ValidateUpdate(ctx context.Context, oldObj, newObj runtime.Object) (admission.Warnings, error) { - oldVMClass, ok := oldObj.(*v1alpha3.VirtualMachineClass) - if !ok { + var oldVMClass, newVMClass *v1alpha3.VirtualMachineClass + + switch o := oldObj.(type) { + case *v1alpha3.VirtualMachineClass: + oldVMClass = o + case *v1alpha2.VirtualMachineClass: + oldVMClass = &v1alpha3.VirtualMachineClass{} + if err := o.ConvertTo(oldVMClass); err != nil { + return nil, fmt.Errorf("failed to convert old v1alpha2 to v1alpha3: %w", err) + } + default: return nil, fmt.Errorf("expected an old VirtualMachineClass but got a %T", oldObj) } - newVMClass, ok := newObj.(*v1alpha3.VirtualMachineClass) - if !ok { + switch n := newObj.(type) { + case *v1alpha3.VirtualMachineClass: + newVMClass = n + case *v1alpha2.VirtualMachineClass: + newVMClass = &v1alpha3.VirtualMachineClass{} + if err := n.ConvertTo(newVMClass); err != nil { + return nil, fmt.Errorf("failed to convert new v1alpha2 to v1alpha3: %w", err) + } + default: return nil, fmt.Errorf("expected a new VirtualMachineClass but got a %T", newObj) } diff --git a/templates/virtualization-controller/validation-webhook.yaml b/templates/virtualization-controller/validation-webhook.yaml index e4822613a2..9ca31adaa8 100644 --- a/templates/virtualization-controller/validation-webhook.yaml +++ b/templates/virtualization-controller/validation-webhook.yaml @@ -2,9 +2,6 @@ apiVersion: admissionregistration.k8s.io/v1 kind: ValidatingWebhookConfiguration metadata: - annotations: - "helm.sh/hook": post-install,post-upgrade - "helm.sh/hook-weight": "10" {{- include "helm_lib_module_labels" (list . (dict "app" "virtualization-controller")) | nindent 2 }} name: "virtualization-controller-admission-webhook" webhooks: @@ -212,7 +209,25 @@ webhooks: {{ .Values.virtualization.internal.controller.cert.ca | b64enc }} admissionReviewVersions: ["v1"] sideEffects: None - - name: "vmclass.virtualization-controller.validate.d8-virtualization" + - name: "vmclass-v1alpha2.virtualization-controller.validate.d8-virtualization" + rules: + - apiGroups: ["virtualization.deckhouse.io"] + apiVersions: ["v1alpha2"] + operations: ["CREATE", "UPDATE"] + resources: ["virtualmachineclasses"] + scope: "Cluster" + clientConfig: + service: + namespace: d8-{{ .Chart.Name }} + name: virtualization-controller + path: /validate-virtualization-deckhouse-io-v1alpha2-virtualmachineclass + port: 443 + caBundle: | + {{ .Values.virtualization.internal.controller.cert.ca | b64enc }} + admissionReviewVersions: ["v1"] + sideEffects: None + matchPolicy: Exact + - name: "vmclass-v1alpha3.virtualization-controller.validate.d8-virtualization" rules: - apiGroups: ["virtualization.deckhouse.io"] apiVersions: ["v1alpha3"] @@ -229,6 +244,7 @@ webhooks: {{ .Values.virtualization.internal.controller.cert.ca | b64enc }} admissionReviewVersions: ["v1"] sideEffects: None + matchPolicy: Exact - name: "moduleconfig.virtualization-controller.validate.d8-virtualization" rules: - apiGroups: ["deckhouse.io"] diff --git a/templates/virtualization-controller/vmclasses-default.yaml b/templates/virtualization-controller/vmclasses-default.yaml index 6baa487f0f..2bbf9c7288 100644 --- a/templates/virtualization-controller/vmclasses-default.yaml +++ b/templates/virtualization-controller/vmclasses-default.yaml @@ -2,9 +2,6 @@ apiVersion: virtualization.deckhouse.io/v1alpha3 kind: VirtualMachineClass metadata: name: generic - annotations: - "helm.sh/hook": post-install,post-upgrade - "helm.sh/hook-weight": "200" {{- include "helm_lib_module_labels" (list . (dict "app" "virtualization-controller")) | nindent 2 }} spec: nodeSelector: From 696dee69d2407b5b47c73aeb3a92607c3f4f532c Mon Sep 17 00:00:00 2001 From: Daniil Loktev Date: Fri, 14 Nov 2025 19:14:00 +0300 Subject: [PATCH 75/77] move generic to v1alpha2 Signed-off-by: Daniil Loktev --- .../virtualization-controller/vmclasses-default.yaml | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/templates/virtualization-controller/vmclasses-default.yaml b/templates/virtualization-controller/vmclasses-default.yaml index 2bbf9c7288..f2beb27764 100644 --- a/templates/virtualization-controller/vmclasses-default.yaml +++ b/templates/virtualization-controller/vmclasses-default.yaml @@ -1,4 +1,4 @@ -apiVersion: virtualization.deckhouse.io/v1alpha3 +apiVersion: virtualization.deckhouse.io/v1alpha2 kind: VirtualMachineClass metadata: name: generic @@ -16,19 +16,19 @@ spec: min: 1 max: 4 dedicatedCores: [false] - coreFractions: ["5%", "10%", "20%", "50%", "100%"] + coreFractions: [5, 10, 20, 50, 100] - cores: min: 5 max: 8 dedicatedCores: [false] - coreFractions: ["20%", "50%", "100%"] + coreFractions: [20, 50, 100] - cores: min: 9 max: 16 dedicatedCores: [true, false] - coreFractions: ["50%", "100%"] + coreFractions: [50, 100] - cores: min: 17 max: 1024 dedicatedCores: [true, false] - coreFractions: ["100%"] + coreFractions: [100] From ceccacae988919284616cba95a1c9a8af6659dae Mon Sep 17 00:00:00 2001 From: Daniil Loktev Date: Tue, 18 Nov 2025 14:59:44 +0300 Subject: [PATCH 76/77] upgrade controller-tools to 0.18.0 Signed-off-by: Daniil Loktev --- api/go.mod | 6 +++--- api/go.sum | 12 ++++++------ crds/clustervirtualimages.yaml | 2 +- crds/virtualdisks.yaml | 2 +- crds/virtualimages.yaml | 2 +- crds/virtualmachineblockdeviceattachments.yaml | 2 +- crds/virtualmachineclasses.yaml | 2 +- crds/virtualmachineoperations.yaml | 2 +- crds/virtualmachinerestores.yaml | 2 +- crds/virtualmachinesnapshots.yaml | 2 +- images/hooks/go.mod | 4 ++-- images/hooks/go.sum | 8 ++++---- images/virtualization-artifact/go.mod | 4 ++-- images/virtualization-artifact/go.sum | 8 ++++---- test/e2e/go.mod | 6 +++--- test/e2e/go.sum | 8 ++++---- 16 files changed, 36 insertions(+), 36 deletions(-) diff --git a/api/go.mod b/api/go.mod index f64524d560..79b0495d1e 100644 --- a/api/go.mod +++ b/api/go.mod @@ -10,8 +10,8 @@ tool ( require ( github.com/gorilla/websocket v1.5.4-0.20250319132907-e064f32e3674 - github.com/onsi/ginkgo/v2 v2.22.0 - github.com/onsi/gomega v1.36.1 + github.com/onsi/ginkgo/v2 v2.23.3 + github.com/onsi/gomega v1.37.0 github.com/spf13/pflag v1.0.7 k8s.io/api v0.33.3 k8s.io/apiextensions-apiserver v0.33.3 @@ -74,7 +74,7 @@ require ( k8s.io/utils v0.0.0-20241104100929-3ea5e8cea738 // indirect kubevirt.io/containerized-data-importer-api v1.57.0-alpha1 // indirect kubevirt.io/controller-lifecycle-operator-sdk/api v0.0.0-20220329064328-f3cc58c6ed90 // indirect - sigs.k8s.io/controller-tools v0.16.5 // indirect + sigs.k8s.io/controller-tools v0.18.0 // indirect sigs.k8s.io/json v0.0.0-20241010143419-9aa6b5e7a4b3 // indirect sigs.k8s.io/randfill v1.0.0 // indirect sigs.k8s.io/structured-merge-diff/v4 v4.6.0 // indirect diff --git a/api/go.sum b/api/go.sum index ec3dce0a5a..fd5f073e7c 100644 --- a/api/go.sum +++ b/api/go.sum @@ -183,8 +183,8 @@ github.com/onsi/ginkgo/v2 v2.13.0/go.mod h1:TE309ZR8s5FsKKpuB1YAQYBzCaAfUgatB/xl github.com/onsi/ginkgo/v2 v2.17.1/go.mod h1:llBI3WDLL9Z6taip6f33H76YcWtJv+7R3HigUjbIBOs= github.com/onsi/ginkgo/v2 v2.17.2/go.mod h1:nP2DPOQoNsQmsVyv5rDA8JkXQoCs6goXIvr/PRJ1eCc= github.com/onsi/ginkgo/v2 v2.19.0/go.mod h1:rlwLi9PilAFJ8jCg9UE1QP6VBpd6/xj3SRC0d6TU0To= -github.com/onsi/ginkgo/v2 v2.22.0 h1:Yed107/8DjTr0lKCNt7Dn8yQ6ybuDRQoMGrNFKzMfHg= -github.com/onsi/ginkgo/v2 v2.22.0/go.mod h1:7Du3c42kxCUegi0IImZ1wUQzMBVecgIHjR1C+NkhLQo= +github.com/onsi/ginkgo/v2 v2.23.3 h1:edHxnszytJ4lD9D5Jjc4tiDkPBZ3siDeJJkUZJJVkp0= +github.com/onsi/ginkgo/v2 v2.23.3/go.mod h1:zXTP6xIp3U8aVuXN8ENK9IXRaTjFnpVB9mGmaSRvxnM= github.com/onsi/gomega v1.7.1/go.mod h1:XdKZgCCFLUoM/7CFJVPcG8C1xQ1AJ0vpAezJrB7JYyY= github.com/onsi/gomega v1.10.1/go.mod h1:iN09h71vgCQne3DLsj+A5owkum+a2tYe+TOCB1ybHNo= github.com/onsi/gomega v1.17.0/go.mod h1:HnhC7FXeEQY45zxNK3PPoIUhzk/80Xly9PcubAlGdZY= @@ -206,8 +206,8 @@ github.com/onsi/gomega v1.27.10/go.mod h1:RsS8tutOdbdgzbPtzzATp12yT7kM5I5aElG3ev github.com/onsi/gomega v1.30.0/go.mod h1:9sxs+SwGrKI0+PWe4Fxa9tFQQBG5xSsSbMXOI8PPpoQ= github.com/onsi/gomega v1.33.0/go.mod h1:+925n5YtiFsLzzafLUHzVMBpvvRAzrydIBiSIxjX3wY= 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/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= @@ -576,8 +576,8 @@ kubevirt.io/controller-lifecycle-operator-sdk/api v0.0.0-20220329064328-f3cc58c6 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= sigs.k8s.io/controller-runtime v0.21.0/go.mod h1:OSg14+F65eWqIu4DceX7k/+QRAbTTvxeQSNSOQpukWM= -sigs.k8s.io/controller-tools v0.16.5 h1:5k9FNRqziBPwqr17AMEPPV/En39ZBplLAdOwwQHruP4= -sigs.k8s.io/controller-tools v0.16.5/go.mod h1:8vztuRVzs8IuuJqKqbXCSlXcw+lkAv/M2sTpg55qjMY= +sigs.k8s.io/controller-tools v0.18.0 h1:rGxGZCZTV2wJreeRgqVoWab/mfcumTMmSwKzoM9xrsE= +sigs.k8s.io/controller-tools v0.18.0/go.mod h1:gLKoiGBriyNh+x1rWtUQnakUYEujErjXs9pf+x/8n1U= sigs.k8s.io/json v0.0.0-20211020170558-c049b76a60c6/go.mod h1:p4QtZmO4uMYipTQNzagwnNoseA6OxSUutVw05NhYDRs= sigs.k8s.io/json v0.0.0-20221116044647-bc3834ca7abd/go.mod h1:B8JuhiUyNFVKdsE8h686QcCxMaH6HrOAZj4vswFpcB0= sigs.k8s.io/json v0.0.0-20241010143419-9aa6b5e7a4b3 h1:/Rv+M11QRah1itp8VhT6HoVx1Ray9eB4DBr+K+/sCJ8= diff --git a/crds/clustervirtualimages.yaml b/crds/clustervirtualimages.yaml index 233ee5ca29..93bc215d84 100644 --- a/crds/clustervirtualimages.yaml +++ b/crds/clustervirtualimages.yaml @@ -3,7 +3,7 @@ apiVersion: apiextensions.k8s.io/v1 kind: CustomResourceDefinition metadata: annotations: - controller-gen.kubebuilder.io/version: v0.16.5 + controller-gen.kubebuilder.io/version: v0.18.0 labels: backup.deckhouse.io/cluster-config: "true" heritage: deckhouse diff --git a/crds/virtualdisks.yaml b/crds/virtualdisks.yaml index 10a8e480c2..c00c80d46b 100644 --- a/crds/virtualdisks.yaml +++ b/crds/virtualdisks.yaml @@ -3,7 +3,7 @@ apiVersion: apiextensions.k8s.io/v1 kind: CustomResourceDefinition metadata: annotations: - controller-gen.kubebuilder.io/version: v0.16.5 + controller-gen.kubebuilder.io/version: v0.18.0 labels: heritage: deckhouse module: virtualization diff --git a/crds/virtualimages.yaml b/crds/virtualimages.yaml index 4503916cfd..700a9418b2 100644 --- a/crds/virtualimages.yaml +++ b/crds/virtualimages.yaml @@ -3,7 +3,7 @@ apiVersion: apiextensions.k8s.io/v1 kind: CustomResourceDefinition metadata: annotations: - controller-gen.kubebuilder.io/version: v0.16.5 + controller-gen.kubebuilder.io/version: v0.18.0 labels: heritage: deckhouse module: virtualization diff --git a/crds/virtualmachineblockdeviceattachments.yaml b/crds/virtualmachineblockdeviceattachments.yaml index 45e8b70eb6..939fc91607 100644 --- a/crds/virtualmachineblockdeviceattachments.yaml +++ b/crds/virtualmachineblockdeviceattachments.yaml @@ -3,7 +3,7 @@ apiVersion: apiextensions.k8s.io/v1 kind: CustomResourceDefinition metadata: annotations: - controller-gen.kubebuilder.io/version: v0.16.5 + controller-gen.kubebuilder.io/version: v0.18.0 labels: heritage: deckhouse module: virtualization diff --git a/crds/virtualmachineclasses.yaml b/crds/virtualmachineclasses.yaml index b98325cc2b..6edf3ff75c 100644 --- a/crds/virtualmachineclasses.yaml +++ b/crds/virtualmachineclasses.yaml @@ -3,7 +3,7 @@ apiVersion: apiextensions.k8s.io/v1 kind: CustomResourceDefinition metadata: annotations: - controller-gen.kubebuilder.io/version: v0.16.5 + controller-gen.kubebuilder.io/version: v0.18.0 labels: backup.deckhouse.io/cluster-config: "true" heritage: deckhouse diff --git a/crds/virtualmachineoperations.yaml b/crds/virtualmachineoperations.yaml index a67b8e2f84..c96023b308 100644 --- a/crds/virtualmachineoperations.yaml +++ b/crds/virtualmachineoperations.yaml @@ -3,7 +3,7 @@ apiVersion: apiextensions.k8s.io/v1 kind: CustomResourceDefinition metadata: annotations: - controller-gen.kubebuilder.io/version: v0.16.5 + controller-gen.kubebuilder.io/version: v0.18.0 labels: heritage: deckhouse module: virtualization diff --git a/crds/virtualmachinerestores.yaml b/crds/virtualmachinerestores.yaml index 1d37016201..eb848d5250 100644 --- a/crds/virtualmachinerestores.yaml +++ b/crds/virtualmachinerestores.yaml @@ -3,7 +3,7 @@ apiVersion: apiextensions.k8s.io/v1 kind: CustomResourceDefinition metadata: annotations: - controller-gen.kubebuilder.io/version: v0.16.5 + controller-gen.kubebuilder.io/version: v0.18.0 labels: heritage: deckhouse module: virtualization diff --git a/crds/virtualmachinesnapshots.yaml b/crds/virtualmachinesnapshots.yaml index dcac3a221e..c1b681a99e 100644 --- a/crds/virtualmachinesnapshots.yaml +++ b/crds/virtualmachinesnapshots.yaml @@ -3,7 +3,7 @@ apiVersion: apiextensions.k8s.io/v1 kind: CustomResourceDefinition metadata: annotations: - controller-gen.kubebuilder.io/version: v0.16.5 + controller-gen.kubebuilder.io/version: v0.18.0 labels: heritage: deckhouse module: virtualization diff --git a/images/hooks/go.mod b/images/hooks/go.mod index 0f65b8ba81..bb211a4a08 100644 --- a/images/hooks/go.mod +++ b/images/hooks/go.mod @@ -9,8 +9,8 @@ require ( github.com/deckhouse/module-sdk v0.3.3 github.com/deckhouse/virtualization-controller v0.0.0 github.com/deckhouse/virtualization/api v0.15.0 - github.com/onsi/ginkgo/v2 v2.22.0 - github.com/onsi/gomega v1.36.1 + github.com/onsi/ginkgo/v2 v2.23.3 + github.com/onsi/gomega v1.37.0 github.com/tidwall/gjson v1.18.0 golang.org/x/crypto v0.38.0 k8s.io/api v0.33.3 diff --git a/images/hooks/go.sum b/images/hooks/go.sum index 0fa95aed83..4433af27eb 100644 --- a/images/hooks/go.sum +++ b/images/hooks/go.sum @@ -239,8 +239,8 @@ github.com/onsi/ginkgo/v2 v2.17.2/go.mod h1:nP2DPOQoNsQmsVyv5rDA8JkXQoCs6goXIvr/ github.com/onsi/ginkgo/v2 v2.19.0/go.mod h1:rlwLi9PilAFJ8jCg9UE1QP6VBpd6/xj3SRC0d6TU0To= github.com/onsi/ginkgo/v2 v2.20.1/go.mod h1:lG9ey2Z29hR41WMVthyJBGUBcBhGOtoPF2VFMvBXFCI= github.com/onsi/ginkgo/v2 v2.21.0/go.mod h1:7Du3c42kxCUegi0IImZ1wUQzMBVecgIHjR1C+NkhLQo= -github.com/onsi/ginkgo/v2 v2.22.0 h1:Yed107/8DjTr0lKCNt7Dn8yQ6ybuDRQoMGrNFKzMfHg= -github.com/onsi/ginkgo/v2 v2.22.0/go.mod h1:7Du3c42kxCUegi0IImZ1wUQzMBVecgIHjR1C+NkhLQo= +github.com/onsi/ginkgo/v2 v2.23.3 h1:edHxnszytJ4lD9D5Jjc4tiDkPBZ3siDeJJkUZJJVkp0= +github.com/onsi/ginkgo/v2 v2.23.3/go.mod h1:zXTP6xIp3U8aVuXN8ENK9IXRaTjFnpVB9mGmaSRvxnM= github.com/onsi/gomega v1.7.1/go.mod h1:XdKZgCCFLUoM/7CFJVPcG8C1xQ1AJ0vpAezJrB7JYyY= github.com/onsi/gomega v1.10.1/go.mod h1:iN09h71vgCQne3DLsj+A5owkum+a2tYe+TOCB1ybHNo= github.com/onsi/gomega v1.17.0/go.mod h1:HnhC7FXeEQY45zxNK3PPoIUhzk/80Xly9PcubAlGdZY= @@ -265,8 +265,8 @@ github.com/onsi/gomega v1.33.1/go.mod h1:U4R44UsT+9eLIaYRB2a5qajjtQYn0hauxvRm16A github.com/onsi/gomega v1.34.1/go.mod h1:kU1QgUvBDLXBJq618Xvm2LUX6rSAfRaFRTcdOeDLwwY= github.com/onsi/gomega v1.34.2/go.mod h1:v1xfxRgk0KIsG+QOdm7p8UosrOzPYRo60fd3B/1Dukc= github.com/onsi/gomega v1.35.1/go.mod h1:PvZbdDc8J6XJEpDK4HCuRBm8a6Fzp9/DmhC9C7yFlog= -github.com/onsi/gomega v1.36.1 h1:bJDPBO7ibjxcbHMgSCoo4Yj18UWbKDlLwX1x9sybDcw= -github.com/onsi/gomega v1.36.1/go.mod h1:PvZbdDc8J6XJEpDK4HCuRBm8a6Fzp9/DmhC9C7yFlog= +github.com/onsi/gomega v1.37.0 h1:CdEG8g0S133B4OswTDC/5XPSzE1OeP29QOioj2PID2Y= +github.com/onsi/gomega v1.37.0/go.mod h1:8D9+Txp43QWKhM24yyOBEdpkzN8FvJyAwecBgsU4KU0= github.com/op/go-logging v0.0.0-20160315200505-970db520ece7/go.mod h1:HzydrMdWErDVzsI23lYNej1Htcns9BCg93Dk0bBINWk= github.com/opencontainers/go-digest v1.0.0 h1:apOUWs51W5PlhuyGyz9FCeeBIOUDA/6nW8Oi/yOhh5U= github.com/opencontainers/go-digest v1.0.0/go.mod h1:0JzlMkj0TRzQZfJkVvzbP0HBR3IKzErnv2BNG4W4MAM= diff --git a/images/virtualization-artifact/go.mod b/images/virtualization-artifact/go.mod index 45fbb3f22a..3ade7764fa 100644 --- a/images/virtualization-artifact/go.mod +++ b/images/virtualization-artifact/go.mod @@ -15,8 +15,8 @@ require ( github.com/fsnotify/fsnotify v1.7.0 github.com/go-logr/logr v1.4.2 github.com/kubernetes-csi/external-snapshotter/client/v6 v6.3.0 - github.com/onsi/ginkgo/v2 v2.22.0 - github.com/onsi/gomega v1.36.1 + github.com/onsi/ginkgo/v2 v2.23.3 + github.com/onsi/gomega v1.37.0 github.com/prometheus/client_golang v1.22.0 github.com/robfig/cron/v3 v3.0.1 github.com/spf13/cobra v1.9.1 diff --git a/images/virtualization-artifact/go.sum b/images/virtualization-artifact/go.sum index f1157c9053..39d45d303a 100644 --- a/images/virtualization-artifact/go.sum +++ b/images/virtualization-artifact/go.sum @@ -252,8 +252,8 @@ github.com/onsi/ginkgo/v2 v2.17.2/go.mod h1:nP2DPOQoNsQmsVyv5rDA8JkXQoCs6goXIvr/ github.com/onsi/ginkgo/v2 v2.19.0/go.mod h1:rlwLi9PilAFJ8jCg9UE1QP6VBpd6/xj3SRC0d6TU0To= github.com/onsi/ginkgo/v2 v2.20.1/go.mod h1:lG9ey2Z29hR41WMVthyJBGUBcBhGOtoPF2VFMvBXFCI= github.com/onsi/ginkgo/v2 v2.21.0/go.mod h1:7Du3c42kxCUegi0IImZ1wUQzMBVecgIHjR1C+NkhLQo= -github.com/onsi/ginkgo/v2 v2.22.0 h1:Yed107/8DjTr0lKCNt7Dn8yQ6ybuDRQoMGrNFKzMfHg= -github.com/onsi/ginkgo/v2 v2.22.0/go.mod h1:7Du3c42kxCUegi0IImZ1wUQzMBVecgIHjR1C+NkhLQo= +github.com/onsi/ginkgo/v2 v2.23.3 h1:edHxnszytJ4lD9D5Jjc4tiDkPBZ3siDeJJkUZJJVkp0= +github.com/onsi/ginkgo/v2 v2.23.3/go.mod h1:zXTP6xIp3U8aVuXN8ENK9IXRaTjFnpVB9mGmaSRvxnM= github.com/onsi/gomega v1.7.1/go.mod h1:XdKZgCCFLUoM/7CFJVPcG8C1xQ1AJ0vpAezJrB7JYyY= github.com/onsi/gomega v1.10.1/go.mod h1:iN09h71vgCQne3DLsj+A5owkum+a2tYe+TOCB1ybHNo= github.com/onsi/gomega v1.17.0/go.mod h1:HnhC7FXeEQY45zxNK3PPoIUhzk/80Xly9PcubAlGdZY= @@ -278,8 +278,8 @@ github.com/onsi/gomega v1.33.1/go.mod h1:U4R44UsT+9eLIaYRB2a5qajjtQYn0hauxvRm16A github.com/onsi/gomega v1.34.1/go.mod h1:kU1QgUvBDLXBJq618Xvm2LUX6rSAfRaFRTcdOeDLwwY= github.com/onsi/gomega v1.34.2/go.mod h1:v1xfxRgk0KIsG+QOdm7p8UosrOzPYRo60fd3B/1Dukc= github.com/onsi/gomega v1.35.1/go.mod h1:PvZbdDc8J6XJEpDK4HCuRBm8a6Fzp9/DmhC9C7yFlog= -github.com/onsi/gomega v1.36.1 h1:bJDPBO7ibjxcbHMgSCoo4Yj18UWbKDlLwX1x9sybDcw= -github.com/onsi/gomega v1.36.1/go.mod h1:PvZbdDc8J6XJEpDK4HCuRBm8a6Fzp9/DmhC9C7yFlog= +github.com/onsi/gomega v1.37.0 h1:CdEG8g0S133B4OswTDC/5XPSzE1OeP29QOioj2PID2Y= +github.com/onsi/gomega v1.37.0/go.mod h1:8D9+Txp43QWKhM24yyOBEdpkzN8FvJyAwecBgsU4KU0= github.com/opencontainers/go-digest v1.0.0 h1:apOUWs51W5PlhuyGyz9FCeeBIOUDA/6nW8Oi/yOhh5U= github.com/opencontainers/go-digest v1.0.0/go.mod h1:0JzlMkj0TRzQZfJkVvzbP0HBR3IKzErnv2BNG4W4MAM= github.com/openshift/custom-resource-status v1.1.2 h1:C3DL44LEbvlbItfd8mT5jWrqPfHnSOQoQf/sypqA6A4= diff --git a/test/e2e/go.mod b/test/e2e/go.mod index 03f982b199..da2846ea06 100644 --- a/test/e2e/go.mod +++ b/test/e2e/go.mod @@ -7,8 +7,9 @@ tool github.com/onsi/ginkgo/v2/ginkgo require ( github.com/deckhouse/virtualization-controller v0.0.0-00010101000000-000000000000 github.com/deckhouse/virtualization/api v0.0.0-20240923080356-bb5809dba578 - github.com/onsi/ginkgo/v2 v2.22.0 - github.com/onsi/gomega v1.36.1 + github.com/onsi/ginkgo/v2 v2.23.3 + github.com/onsi/gomega v1.37.0 + golang.org/x/net v0.39.0 gopkg.in/yaml.v3 v3.0.1 k8s.io/api v0.33.3 k8s.io/apimachinery v0.33.3 @@ -61,7 +62,6 @@ require ( github.com/xlab/treeprint v1.2.0 // indirect go.yaml.in/yaml/v2 v2.4.2 // indirect go.yaml.in/yaml/v3 v3.0.3 // indirect - golang.org/x/net v0.39.0 // indirect golang.org/x/oauth2 v0.27.0 // indirect golang.org/x/sync v0.14.0 // indirect golang.org/x/sys v0.33.0 // indirect diff --git a/test/e2e/go.sum b/test/e2e/go.sum index bcef76dedb..f72cde1b6d 100644 --- a/test/e2e/go.sum +++ b/test/e2e/go.sum @@ -193,8 +193,8 @@ github.com/onsi/ginkgo/v2 v2.13.0/go.mod h1:TE309ZR8s5FsKKpuB1YAQYBzCaAfUgatB/xl github.com/onsi/ginkgo/v2 v2.17.1/go.mod h1:llBI3WDLL9Z6taip6f33H76YcWtJv+7R3HigUjbIBOs= github.com/onsi/ginkgo/v2 v2.17.2/go.mod h1:nP2DPOQoNsQmsVyv5rDA8JkXQoCs6goXIvr/PRJ1eCc= github.com/onsi/ginkgo/v2 v2.19.0/go.mod h1:rlwLi9PilAFJ8jCg9UE1QP6VBpd6/xj3SRC0d6TU0To= -github.com/onsi/ginkgo/v2 v2.22.0 h1:Yed107/8DjTr0lKCNt7Dn8yQ6ybuDRQoMGrNFKzMfHg= -github.com/onsi/ginkgo/v2 v2.22.0/go.mod h1:7Du3c42kxCUegi0IImZ1wUQzMBVecgIHjR1C+NkhLQo= +github.com/onsi/ginkgo/v2 v2.23.3 h1:edHxnszytJ4lD9D5Jjc4tiDkPBZ3siDeJJkUZJJVkp0= +github.com/onsi/ginkgo/v2 v2.23.3/go.mod h1:zXTP6xIp3U8aVuXN8ENK9IXRaTjFnpVB9mGmaSRvxnM= github.com/onsi/gomega v1.7.1/go.mod h1:XdKZgCCFLUoM/7CFJVPcG8C1xQ1AJ0vpAezJrB7JYyY= github.com/onsi/gomega v1.10.1/go.mod h1:iN09h71vgCQne3DLsj+A5owkum+a2tYe+TOCB1ybHNo= github.com/onsi/gomega v1.17.0/go.mod h1:HnhC7FXeEQY45zxNK3PPoIUhzk/80Xly9PcubAlGdZY= @@ -216,8 +216,8 @@ github.com/onsi/gomega v1.27.10/go.mod h1:RsS8tutOdbdgzbPtzzATp12yT7kM5I5aElG3ev github.com/onsi/gomega v1.30.0/go.mod h1:9sxs+SwGrKI0+PWe4Fxa9tFQQBG5xSsSbMXOI8PPpoQ= github.com/onsi/gomega v1.33.0/go.mod h1:+925n5YtiFsLzzafLUHzVMBpvvRAzrydIBiSIxjX3wY= 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/onsi/gomega v1.37.0 h1:CdEG8g0S133B4OswTDC/5XPSzE1OeP29QOioj2PID2Y= +github.com/onsi/gomega v1.37.0/go.mod h1:8D9+Txp43QWKhM24yyOBEdpkzN8FvJyAwecBgsU4KU0= 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= From 674b22b71e96ce3c7249685f98c541ab160a1ce9 Mon Sep 17 00:00:00 2001 From: Daniil Loktev Date: Tue, 18 Nov 2025 15:09:21 +0300 Subject: [PATCH 77/77] go mod tidy Signed-off-by: Daniil Loktev --- src/cli/go.sum | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/src/cli/go.sum b/src/cli/go.sum index 7c203f2035..2c8e3bc9b0 100644 --- a/src/cli/go.sum +++ b/src/cli/go.sum @@ -109,8 +109,8 @@ github.com/google/gofuzz v1.1.0/go.mod h1:dBl0BpW6vV/+mYPU4Po3pmUjxk6FQPldtuIdl/ github.com/google/pprof v0.0.0-20210407192527-94a9f03dee38/go.mod h1:kpwsk12EmLew5upagYY7GY0pfYCcupk39gWOCRROcvE= github.com/google/pprof v0.0.0-20240424215950-a892ee059fd6/go.mod h1:kf6iHlnVGwgKolg33glAes7Yg/8iWP8ukqeldJSO7jw= github.com/google/pprof v0.0.0-20240727154555-813a5fbdbec8/go.mod h1:K1liHPHnj73Fdn/EKuT8nrFqBihUSKXoLYU0BuatOYo= -github.com/google/pprof v0.0.0-20241029153458-d1b30febd7db h1:097atOisP2aRj7vFgYQBbFN4U4JNXUNYpxael3UzMyo= -github.com/google/pprof v0.0.0-20241029153458-d1b30febd7db/go.mod h1:vavhavw2zAxS5dIdcRluK6cSGGPlZynqzFM8NdvU144= +github.com/google/pprof v0.0.0-20241210010833-40e02aabc2ad h1:a6HEuzUHeKH6hwfN/ZoQgRgVIWFJljSWa/zetS2WTvg= +github.com/google/pprof v0.0.0-20241210010833-40e02aabc2ad/go.mod h1:vavhavw2zAxS5dIdcRluK6cSGGPlZynqzFM8NdvU144= github.com/google/uuid v1.1.2/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo= github.com/google/uuid v1.6.0 h1:NIvaJDMOsjHA8n1jAhLSgzrAzy1Hgr+hNrb57e+94F0= github.com/google/uuid v1.6.0/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo= @@ -191,8 +191,8 @@ github.com/onsi/ginkgo/v2 v2.13.0/go.mod h1:TE309ZR8s5FsKKpuB1YAQYBzCaAfUgatB/xl github.com/onsi/ginkgo/v2 v2.17.1/go.mod h1:llBI3WDLL9Z6taip6f33H76YcWtJv+7R3HigUjbIBOs= github.com/onsi/ginkgo/v2 v2.17.2/go.mod h1:nP2DPOQoNsQmsVyv5rDA8JkXQoCs6goXIvr/PRJ1eCc= github.com/onsi/ginkgo/v2 v2.19.0/go.mod h1:rlwLi9PilAFJ8jCg9UE1QP6VBpd6/xj3SRC0d6TU0To= -github.com/onsi/ginkgo/v2 v2.22.0 h1:Yed107/8DjTr0lKCNt7Dn8yQ6ybuDRQoMGrNFKzMfHg= -github.com/onsi/ginkgo/v2 v2.22.0/go.mod h1:7Du3c42kxCUegi0IImZ1wUQzMBVecgIHjR1C+NkhLQo= +github.com/onsi/ginkgo/v2 v2.23.3 h1:edHxnszytJ4lD9D5Jjc4tiDkPBZ3siDeJJkUZJJVkp0= +github.com/onsi/ginkgo/v2 v2.23.3/go.mod h1:zXTP6xIp3U8aVuXN8ENK9IXRaTjFnpVB9mGmaSRvxnM= github.com/onsi/gomega v1.7.1/go.mod h1:XdKZgCCFLUoM/7CFJVPcG8C1xQ1AJ0vpAezJrB7JYyY= github.com/onsi/gomega v1.10.1/go.mod h1:iN09h71vgCQne3DLsj+A5owkum+a2tYe+TOCB1ybHNo= github.com/onsi/gomega v1.17.0/go.mod h1:HnhC7FXeEQY45zxNK3PPoIUhzk/80Xly9PcubAlGdZY= @@ -214,8 +214,8 @@ github.com/onsi/gomega v1.27.10/go.mod h1:RsS8tutOdbdgzbPtzzATp12yT7kM5I5aElG3ev github.com/onsi/gomega v1.30.0/go.mod h1:9sxs+SwGrKI0+PWe4Fxa9tFQQBG5xSsSbMXOI8PPpoQ= github.com/onsi/gomega v1.33.0/go.mod h1:+925n5YtiFsLzzafLUHzVMBpvvRAzrydIBiSIxjX3wY= 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/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=