From bec35e3aade31fdca231915fc6ba95647a621cef Mon Sep 17 00:00:00 2001 From: Myasnikov Daniil Date: Wed, 8 Apr 2026 13:15:43 +0500 Subject: [PATCH 01/11] [vm-default-images] Added new optional package Signed-off-by: Myasnikov Daniil --- api/apps/v1alpha1/vmdisk/types.go | 11 +- hack/cdi_golden_image_create.sh | 2 +- .../dashboard/customformsoverride.go | 62 ++++++- .../dashboard/customformsoverride_test.go | 102 +++++++++++ packages/apps/vm-disk/README.md | 24 +-- packages/apps/vm-disk/templates/dv.yaml | 8 +- packages/apps/vm-disk/values.schema.json | 17 +- packages/apps/vm-disk/values.yaml | 8 +- .../platform/sources/vm-default-images.yaml | 22 +++ packages/system/vm-default-images/Chart.yaml | 5 + packages/system/vm-default-images/Makefile | 4 + .../vm-default-images/templates/dv.yaml | 45 +++++ packages/system/vm-default-images/values.yaml | 167 ++++++++++++++++++ 13 files changed, 448 insertions(+), 29 deletions(-) create mode 100644 packages/core/platform/sources/vm-default-images.yaml create mode 100644 packages/system/vm-default-images/Chart.yaml create mode 100644 packages/system/vm-default-images/Makefile create mode 100644 packages/system/vm-default-images/templates/dv.yaml create mode 100644 packages/system/vm-default-images/values.yaml diff --git a/api/apps/v1alpha1/vmdisk/types.go b/api/apps/v1alpha1/vmdisk/types.go index aefac1e4..c493f49c 100644 --- a/api/apps/v1alpha1/vmdisk/types.go +++ b/api/apps/v1alpha1/vmdisk/types.go @@ -32,21 +32,28 @@ type ConfigSpec struct { } type Source struct { + // Clone an existing vm-disk. + Disk *SourceDisk `json:"disk,omitempty"` // Download image from an HTTP source. Http *SourceHTTP `json:"http,omitempty"` - // Use image by name. + // Use image by name from default collection. Image *SourceImage `json:"image,omitempty"` // Upload local image. Upload *SourceUpload `json:"upload,omitempty"` } +type SourceDisk struct { + // Name of the vm-disk to clone. + Name string `json:"name"` +} + type SourceHTTP struct { // URL to download the image. Url string `json:"url"` } type SourceImage struct { - // Name of the image to use (uploaded as "golden image" or from the list: `ubuntu`, `fedora`, `cirros`, `alpine`, `talos`). + // Name of the image to use. Name string `json:"name"` } diff --git a/hack/cdi_golden_image_create.sh b/hack/cdi_golden_image_create.sh index be1558d0..f19f9970 100644 --- a/hack/cdi_golden_image_create.sh +++ b/hack/cdi_golden_image_create.sh @@ -16,7 +16,7 @@ kubectl create -f - < Date: Wed, 8 Apr 2026 14:26:51 +0500 Subject: [PATCH 02/11] [vm-disk] Fix vm-disk-rd Signed-off-by: Myasnikov Daniil --- packages/system/vm-disk-rd/cozyrds/vm-disk.yaml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/packages/system/vm-disk-rd/cozyrds/vm-disk.yaml b/packages/system/vm-disk-rd/cozyrds/vm-disk.yaml index 4d0d7e37..3ce046ed 100644 --- a/packages/system/vm-disk-rd/cozyrds/vm-disk.yaml +++ b/packages/system/vm-disk-rd/cozyrds/vm-disk.yaml @@ -8,7 +8,7 @@ spec: singular: vmdisk plural: vmdisks openAPISchema: |- - {"title":"Chart Values","type":"object","properties":{"source":{"description":"The source image location used to create a disk.","type":"object","default":{},"properties":{"http":{"description":"Download image from an HTTP source.","type":"object","required":["url"],"properties":{"url":{"description":"URL to download the image.","type":"string"}}},"image":{"description":"Use image by name.","type":"object","required":["name"],"properties":{"name":{"description":"Name of the image to use (uploaded as \"golden image\" or from the list: `ubuntu`, `fedora`, `cirros`, `alpine`, `talos`).","type":"string"}}},"upload":{"description":"Upload local image.","type":"object"}}},"optical":{"description":"Defines if disk should be considered optical.","type":"boolean","default":false},"storage":{"description":"The size of the disk allocated for the virtual machine.","default":"5Gi","pattern":"^(\\+|-)?(([0-9]+(\\.[0-9]*)?)|(\\.[0-9]+))(([KMGTPE]i)|[numkMGTPE]|([eE](\\+|-)?(([0-9]+(\\.[0-9]*)?)|(\\.[0-9]+))))?$","anyOf":[{"type":"integer"},{"type":"string"}],"x-kubernetes-int-or-string":true},"storageClass":{"description":"StorageClass used to store the data.","type":"string","default":"replicated"}}} + {"title":"Chart Values","type":"object","properties":{"source":{"description":"The source image location used to create a disk.","type":"object","default":{},"properties":{"disk":{"description":"Clone an existing vm-disk.","type":"object","required":["name"],"properties":{"name":{"description":"Name of the vm-disk to clone.","type":"string"}}},"http":{"description":"Download image from an HTTP source.","type":"object","required":["url"],"properties":{"url":{"description":"URL to download the image.","type":"string"}}},"image":{"description":"Use image by name from default collection.","type":"object","required":["name"],"properties":{"name":{"description":"Name of the image to use.","type":"string"}}},"upload":{"description":"Upload local image.","type":"object"}}},"optical":{"description":"Defines if disk should be considered optical.","type":"boolean","default":false},"storage":{"description":"The size of the disk allocated for the virtual machine.","default":"5Gi","pattern":"^(\\+|-)?(([0-9]+(\\.[0-9]*)?)|(\\.[0-9]+))(([KMGTPE]i)|[numkMGTPE]|([eE](\\+|-)?(([0-9]+(\\.[0-9]*)?)|(\\.[0-9]+))))?$","anyOf":[{"type":"integer"},{"type":"string"}],"x-kubernetes-int-or-string":true},"storageClass":{"description":"StorageClass used to store the data.","type":"string","default":"replicated"}}} release: prefix: vm-disk- labels: From 6b6118ce56f559e9136c2543eec075f95b2495e6 Mon Sep 17 00:00:00 2001 From: Myasnikov Daniil Date: Mon, 13 Apr 2026 20:44:13 +0500 Subject: [PATCH 03/11] [platform] Add migration 38 to rename vm-image-* DataVolumes to vm-default-images-* The vm-disk package previously referenced golden-image DataVolumes with the prefix "vm-image-" in the cozy-public namespace. The new vm-default-images package creates them as "vm-default-images-", so any existing vm-disk that sources an image by name would fail to find its PVC after upgrade. Migration 38 renames every DataVolume in cozy-public whose name starts with "vm-image-" to "vm-default-images-" (dropping the old object and re-creating with the new name) so live vm-disk resources keep resolving their source PVC transparently. Co-Authored-By: Claude Opus 4.6 Signed-off-by: Myasnikov Daniil --- .../platform/images/migrations/migrations/38 | 52 +++++++++++++++++++ 1 file changed, 52 insertions(+) create mode 100755 packages/core/platform/images/migrations/migrations/38 diff --git a/packages/core/platform/images/migrations/migrations/38 b/packages/core/platform/images/migrations/migrations/38 new file mode 100755 index 00000000..59536cb1 --- /dev/null +++ b/packages/core/platform/images/migrations/migrations/38 @@ -0,0 +1,52 @@ +#!/bin/sh +# Migration 38 --> 39 +# Rename DataVolumes/PVCs in cozy-public from vm-image- to vm-default-images-. +# +# The vm-disk package previously looked up golden images with the prefix "vm-image-". +# The new vm-default-images package uses the prefix "vm-default-images-". +# This migration renames any existing DataVolumes so that live vm-disk resources +# continue to resolve their source PVC after upgrade. + +set -euo pipefail + +NAMESPACE="cozy-public" + +# Skip if CDI DataVolume CRD is not installed +if ! kubectl api-resources --api-group=cdi.kubevirt.io -o name 2>/dev/null | grep -q '^datavolumes\.'; then + echo "CDI DataVolume CRD not found, skipping rename" + kubectl create configmap -n cozy-system cozystack-version \ + --from-literal=version=39 --dry-run=client -o yaml | kubectl apply -f- + exit 0 +fi + +# Find DataVolumes whose name starts with "vm-image-" +DVNAMES=$(kubectl get datavolumes.cdi.kubevirt.io -n "$NAMESPACE" \ + -o jsonpath='{range .items[*]}{.metadata.name}{"\n"}{end}' 2>/dev/null \ + | grep '^vm-image-' || true) + +if [ -z "$DVNAMES" ]; then + echo "No vm-image-* DataVolumes found in $NAMESPACE, nothing to rename" +else + for DVNAME in $DVNAMES; do + NEWNAME="vm-default-images-${DVNAME#vm-image-}" + echo "Renaming DataVolume $DVNAME -> $NEWNAME in namespace $NAMESPACE" + + # Export existing DV spec, swap name, and apply as new object + kubectl get datavolumes.cdi.kubevirt.io -n "$NAMESPACE" "$DVNAME" -o json \ + | jq --arg new "$NEWNAME" ' + del(.metadata.resourceVersion, .metadata.uid, .metadata.creationTimestamp, + .metadata.generation, .metadata.selfLink, .metadata.managedFields, + .status) + | .metadata.name = $new + ' \ + | kubectl apply -f - + + # Delete the old DataVolume + kubectl delete datavolumes.cdi.kubevirt.io -n "$NAMESPACE" "$DVNAME" --ignore-not-found=true + echo "Renamed $DVNAME -> $NEWNAME" + done +fi + +# Stamp version +kubectl create configmap -n cozy-system cozystack-version \ + --from-literal=version=39 --dry-run=client -o yaml | kubectl apply -f- From b9a17295cccda01f2644399f55236e6e4ab58db4 Mon Sep 17 00:00:00 2001 From: Myasnikov Daniil Date: Mon, 13 Apr 2026 20:44:19 +0500 Subject: [PATCH 04/11] [platform] Wire vm-default-images into iaas bundle The PackageSource for vm-default-images existed but was never included in any bundle, so it would never be installed. Add it to iaas.yaml immediately after kubevirt-cdi (which it depends on) so it is deployed together with the rest of the KubeVirt IaaS stack. Co-Authored-By: Claude Opus 4.6 Signed-off-by: Myasnikov Daniil --- packages/core/platform/templates/bundles/iaas.yaml | 1 + 1 file changed, 1 insertion(+) diff --git a/packages/core/platform/templates/bundles/iaas.yaml b/packages/core/platform/templates/bundles/iaas.yaml index bd002c16..7485eb91 100644 --- a/packages/core/platform/templates/bundles/iaas.yaml +++ b/packages/core/platform/templates/bundles/iaas.yaml @@ -8,6 +8,7 @@ {{- end -}} {{include "cozystack.platform.package" (list "cozystack.kubevirt" "default" $ $kubevirtComponents) }} {{include "cozystack.platform.package.default" (list "cozystack.kubevirt-cdi" $) }} +{{include "cozystack.platform.package.default" (list "cozystack.vm-default-images" $) }} {{include "cozystack.platform.package.optional.default" (list "cozystack.gpu-operator" $) }} {{include "cozystack.platform.package.default" (list "cozystack.kamaji" $) }} {{include "cozystack.platform.package.default" (list "cozystack.capi-operator" $) }} From 15dfc2521ed5c9fa281dafc42be01dca242ecd32 Mon Sep 17 00:00:00 2001 From: Myasnikov Daniil Date: Mon, 13 Apr 2026 20:44:25 +0500 Subject: [PATCH 05/11] [vm-disk] Remove unused DataVolume lookup in dv.yaml The \$dv variable assigned by the lookup call on the image PVC was never read. Remove the dead line to keep the template tidy. Co-Authored-By: Claude Opus 4.6 Signed-off-by: Myasnikov Daniil --- packages/apps/vm-disk/templates/dv.yaml | 1 - 1 file changed, 1 deletion(-) diff --git a/packages/apps/vm-disk/templates/dv.yaml b/packages/apps/vm-disk/templates/dv.yaml index e1227dcd..521a82b8 100644 --- a/packages/apps/vm-disk/templates/dv.yaml +++ b/packages/apps/vm-disk/templates/dv.yaml @@ -21,7 +21,6 @@ spec: {{- end }} source: {{- if hasKey .Values.source "image" }} - {{- $dv := lookup "cdi.kubevirt.io/v1beta1" "DataVolume" "cozy-public" (printf "vm-default-images-%s" .Values.source.image.name) }} pvc: name: vm-default-images-{{ required "A valid .Values.source.image.name entry required!" .Values.source.image.name }} namespace: cozy-public From 551b4e65ac439c8dc310fa583f6961b3ad2ad2a0 Mon Sep 17 00:00:00 2001 From: Myasnikov Daniil Date: Mon, 13 Apr 2026 20:44:32 +0500 Subject: [PATCH 06/11] [vm-default-images] Fix CentOS Stream image URLs The x86_64 architecture token was placed inside the filename segment (CentOS-Stream-GenericCloud-x86_64-N-latest.x86_64.qcow2) which does not match the actual CentOS mirror layout. Correct both CentOS Stream 9 and 10 URLs to the canonical form without the extra architecture infix. Co-Authored-By: Claude Opus 4.6 Signed-off-by: Myasnikov Daniil --- packages/system/vm-default-images/values.yaml | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/packages/system/vm-default-images/values.yaml b/packages/system/vm-default-images/values.yaml index 8d66c281..a4677bc8 100644 --- a/packages/system/vm-default-images/values.yaml +++ b/packages/system/vm-default-images/values.yaml @@ -112,7 +112,7 @@ images: architecture: amd64 description: "Debian 13 (Trixie) generic cloud image" - name: centos-stream-9 - url: https://cloud.centos.org/centos/9-stream/x86_64/images/CentOS-Stream-GenericCloud-x86_64-9-latest.x86_64.qcow2 + url: https://cloud.centos.org/centos/9-stream/x86_64/images/CentOS-Stream-GenericCloud-9-latest.x86_64.qcow2 storage: 20Gi os: family: Linux @@ -121,7 +121,7 @@ images: architecture: amd64 description: "CentOS Stream 9 GenericCloud image" - name: centos-stream-10 - url: https://cloud.centos.org/centos/10-stream/x86_64/images/CentOS-Stream-GenericCloud-x86_64-10-latest.x86_64.qcow2 + url: https://cloud.centos.org/centos/10-stream/x86_64/images/CentOS-Stream-GenericCloud-10-latest.x86_64.qcow2 storage: 20Gi os: family: Linux From 776b4f2c8d9d24c5a5e9501f7276bede666c86df Mon Sep 17 00:00:00 2001 From: Myasnikov Daniil Date: Mon, 13 Apr 2026 20:44:39 +0500 Subject: [PATCH 07/11] [dashboard] Guard nested type assertions in VMDisk customformsoverride Accessing imgName["properties"].(map[string]any) and diskName["properties"].(map[string]any) without an ok-check would panic if the schema does not contain a "properties" key. Wrap both assertions in ok-guarded form consistent with the outer defensive style. Co-Authored-By: Claude Opus 4.6 Signed-off-by: Myasnikov Daniil --- .../dashboard/customformsoverride.go | 32 +++++++++++-------- 1 file changed, 18 insertions(+), 14 deletions(-) diff --git a/internal/controller/dashboard/customformsoverride.go b/internal/controller/dashboard/customformsoverride.go index 13809248..0a20ae71 100644 --- a/internal/controller/dashboard/customformsoverride.go +++ b/internal/controller/dashboard/customformsoverride.go @@ -256,24 +256,28 @@ func applyListInputOverrides(schema map[string]any, kind string, openAPIProps ma if sourceObj, ok := specProps["source"].(map[string]any); ok { if imgProps, ok := sourceObj["properties"].(map[string]any); ok { if imgName, ok := imgProps["image"].(map[string]any); ok { - imgName["properties"].(map[string]any)["name"] = map[string]any{ - "type": "listInput", - "customProps": map[string]any{ - "valueUri": "/api/clusters/{cluster}/k8s/apis/cdi.kubevirt.io/v1beta1/namespaces/cozy-public/datavolumes", - "keysToValue": []any{"metadata", "annotations", "vm-default-images.cozystack.io/name"}, - "keysToLabel": []any{"metadata", "annotations", "vm-default-images.cozystack.io/description"}, - }, + if imgNameProps, ok := imgName["properties"].(map[string]any); ok { + imgNameProps["name"] = map[string]any{ + "type": "listInput", + "customProps": map[string]any{ + "valueUri": "/api/clusters/{cluster}/k8s/apis/cdi.kubevirt.io/v1beta1/namespaces/cozy-public/datavolumes", + "keysToValue": []any{"metadata", "annotations", "vm-default-images.cozystack.io/name"}, + "keysToLabel": []any{"metadata", "annotations", "vm-default-images.cozystack.io/description"}, + }, + } } } // Override source.disk.name to be an API-backed dropdown listing VMDisk resources if diskName, ok := imgProps["disk"].(map[string]any); ok { - diskName["properties"].(map[string]any)["name"] = map[string]any{ - "type": "listInput", - "customProps": map[string]any{ - "valueUri": "/api/clusters/{cluster}/k8s/apis/apps.cozystack.io/v1alpha1/namespaces/{namespace}/vmdisks", - "keysToValue": []any{"metadata", "name"}, - "keysToLabel": []any{"metadata", "name"}, - }, + if diskNameProps, ok := diskName["properties"].(map[string]any); ok { + diskNameProps["name"] = map[string]any{ + "type": "listInput", + "customProps": map[string]any{ + "valueUri": "/api/clusters/{cluster}/k8s/apis/apps.cozystack.io/v1alpha1/namespaces/{namespace}/vmdisks", + "keysToValue": []any{"metadata", "name"}, + "keysToLabel": []any{"metadata", "name"}, + }, + } } } } From eeda31eb95430105e3798a93eb956c134e67d65b Mon Sep 17 00:00:00 2001 From: Myasnikov Daniil Date: Mon, 13 Apr 2026 20:44:47 +0500 Subject: [PATCH 08/11] [api] Regenerate deepcopy and CRD manifests via make generate Running make generate at repo root regenerates the zz_generated.deepcopy.go files. Key fix: Source.DeepCopyInto in the vmdisk package now handles the new Disk *SourceDisk pointer field, which was previously missing and would cause pointer aliasing on deep-copy. Other generated changes are incidental updates to vminstance (Networks field added, Subnet renamed to Network) and backups CRD manifests picked up by controller-gen from the current HEAD. Co-Authored-By: Claude Opus 4.6 Signed-off-by: Myasnikov Daniil --- .../v1alpha1/vmdisk/zz_generated.deepcopy.go | 20 ++++++++++ .../vminstance/zz_generated.deepcopy.go | 37 +++++++++-------- .../v1alpha1/vpc/zz_generated.deepcopy.go | 40 +++++++++++++++++++ api/backups/v1alpha1/zz_generated.deepcopy.go | 17 +++++++- .../backups.cozystack.io_backups.yaml | 16 ++++---- 5 files changed, 105 insertions(+), 25 deletions(-) diff --git a/api/apps/v1alpha1/vmdisk/zz_generated.deepcopy.go b/api/apps/v1alpha1/vmdisk/zz_generated.deepcopy.go index e8ca986e..301bb1d9 100644 --- a/api/apps/v1alpha1/vmdisk/zz_generated.deepcopy.go +++ b/api/apps/v1alpha1/vmdisk/zz_generated.deepcopy.go @@ -70,6 +70,11 @@ func (in *ConfigSpec) DeepCopy() *ConfigSpec { // DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. func (in *Source) DeepCopyInto(out *Source) { *out = *in + if in.Disk != nil { + in, out := &in.Disk, &out.Disk + *out = new(SourceDisk) + **out = **in + } if in.Http != nil { in, out := &in.Http, &out.Http *out = new(SourceHTTP) @@ -97,6 +102,21 @@ func (in *Source) DeepCopy() *Source { return out } +// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. +func (in *SourceDisk) DeepCopyInto(out *SourceDisk) { + *out = *in +} + +// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new SourceDisk. +func (in *SourceDisk) DeepCopy() *SourceDisk { + if in == nil { + return nil + } + out := new(SourceDisk) + in.DeepCopyInto(out) + return out +} + // DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. func (in *SourceHTTP) DeepCopyInto(out *SourceHTTP) { *out = *in diff --git a/api/apps/v1alpha1/vminstance/zz_generated.deepcopy.go b/api/apps/v1alpha1/vminstance/zz_generated.deepcopy.go index 00b2a710..86d5ddfc 100644 --- a/api/apps/v1alpha1/vminstance/zz_generated.deepcopy.go +++ b/api/apps/v1alpha1/vminstance/zz_generated.deepcopy.go @@ -63,9 +63,14 @@ func (in *ConfigSpec) DeepCopyInto(out *ConfigSpec) { *out = make([]Disk, len(*in)) copy(*out, *in) } + if in.Networks != nil { + in, out := &in.Networks, &out.Networks + *out = make([]Network, len(*in)) + copy(*out, *in) + } if in.Subnets != nil { in, out := &in.Subnets, &out.Subnets - *out = make([]Subnet, len(*in)) + *out = make([]Network, len(*in)) copy(*out, *in) } if in.Gpus != nil { @@ -121,6 +126,21 @@ func (in *GPU) DeepCopy() *GPU { return out } +// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. +func (in *Network) DeepCopyInto(out *Network) { + *out = *in +} + +// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new Network. +func (in *Network) DeepCopy() *Network { + if in == nil { + return nil + } + out := new(Network) + in.DeepCopyInto(out) + return out +} + // DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. func (in *Resources) DeepCopyInto(out *Resources) { *out = *in @@ -138,18 +158,3 @@ func (in *Resources) DeepCopy() *Resources { in.DeepCopyInto(out) return out } - -// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. -func (in *Subnet) DeepCopyInto(out *Subnet) { - *out = *in -} - -// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new Subnet. -func (in *Subnet) DeepCopy() *Subnet { - if in == nil { - return nil - } - out := new(Subnet) - in.DeepCopyInto(out) - return out -} diff --git a/api/apps/v1alpha1/vpc/zz_generated.deepcopy.go b/api/apps/v1alpha1/vpc/zz_generated.deepcopy.go index cd718167..3cda29c4 100644 --- a/api/apps/v1alpha1/vpc/zz_generated.deepcopy.go +++ b/api/apps/v1alpha1/vpc/zz_generated.deepcopy.go @@ -58,6 +58,16 @@ func (in *ConfigSpec) DeepCopyInto(out *ConfigSpec) { *out = make([]Subnet, len(*in)) copy(*out, *in) } + if in.Peers != nil { + in, out := &in.Peers, &out.Peers + *out = make([]Peer, len(*in)) + copy(*out, *in) + } + if in.Routes != nil { + in, out := &in.Routes, &out.Routes + *out = make([]Route, len(*in)) + copy(*out, *in) + } } // DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new ConfigSpec. @@ -70,6 +80,36 @@ func (in *ConfigSpec) DeepCopy() *ConfigSpec { return out } +// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. +func (in *Peer) DeepCopyInto(out *Peer) { + *out = *in +} + +// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new Peer. +func (in *Peer) DeepCopy() *Peer { + if in == nil { + return nil + } + out := new(Peer) + in.DeepCopyInto(out) + return out +} + +// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. +func (in *Route) DeepCopyInto(out *Route) { + *out = *in +} + +// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new Route. +func (in *Route) DeepCopy() *Route { + if in == nil { + return nil + } + out := new(Route) + in.DeepCopyInto(out) + return out +} + // DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. func (in *Subnet) DeepCopyInto(out *Subnet) { *out = *in diff --git a/api/backups/v1alpha1/zz_generated.deepcopy.go b/api/backups/v1alpha1/zz_generated.deepcopy.go index b7387772..89f6171f 100644 --- a/api/backups/v1alpha1/zz_generated.deepcopy.go +++ b/api/backups/v1alpha1/zz_generated.deepcopy.go @@ -1,5 +1,21 @@ //go:build !ignore_autogenerated +/* +Copyright 2025 The Cozystack Authors. + +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 controller-gen. DO NOT EDIT. package v1alpha1 @@ -645,4 +661,3 @@ func (in *RestoreJobStatus) DeepCopy() *RestoreJobStatus { in.DeepCopyInto(out) return out } - diff --git a/packages/system/backup-controller/definitions/backups.cozystack.io_backups.yaml b/packages/system/backup-controller/definitions/backups.cozystack.io_backups.yaml index 6e031a84..d48df533 100644 --- a/packages/system/backup-controller/definitions/backups.cozystack.io_backups.yaml +++ b/packages/system/backup-controller/definitions/backups.cozystack.io_backups.yaml @@ -142,14 +142,6 @@ spec: required: - uri type: object - underlyingResources: - description: |- - Holds application-specific resource metadata discovered during backup. - The payload is a self-typed JSON object carrying an inlined TypeMeta - (kind/apiVersion) so the consuming controller can dispatch on the - application kind. - type: object - x-kubernetes-preserve-unknown-fields: true conditions: description: Conditions represents the latest available observations of a Backup's state. @@ -213,6 +205,14 @@ spec: Phase is a simple, high-level summary of the backup's state. Typical values are: Pending, Ready, Failed. type: string + underlyingResources: + description: |- + UnderlyingResources holds application-specific resource metadata discovered + during backup (e.g., VM disks, network configuration). The payload is a + self-typed JSON object carrying an inlined TypeMeta (kind/apiVersion) so + the consuming controller can dispatch on the application kind. + type: object + x-kubernetes-preserve-unknown-fields: true type: object type: object selectableFields: From 2def6cda67e169a065e9b8c3a8f98fb17e702983 Mon Sep 17 00:00:00 2001 From: Myasnikov Daniil Date: Tue, 14 Apr 2026 10:46:12 +0500 Subject: [PATCH 09/11] [vm-default-images] Default to replicated storageClass and document storage requirements MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit The package is wired into the iaas bundle where LINSTOR replicated storage is available. Set storageClass to "replicated" by default and add a note that the full image set needs ~320Gi (16 images × 20Gi). Co-Authored-By: Claude Opus 4.6 Signed-off-by: Myasnikov Daniil --- packages/system/vm-default-images/values.yaml | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/packages/system/vm-default-images/values.yaml b/packages/system/vm-default-images/values.yaml index a4677bc8..9d777f0b 100644 --- a/packages/system/vm-default-images/values.yaml +++ b/packages/system/vm-default-images/values.yaml @@ -3,7 +3,9 @@ ## ## @param {string} storageClass - Default StorageClass for all images. If empty, uses the cluster default StorageClass. -storageClass: "" +## NOTE: The default set of images requires approximately 320Gi of storage (16 images × 20Gi each). +## Adjust the image list or per-image storage sizes to match your cluster capacity. +storageClass: "replicated" ## @typedef {struct} ImageOS - Operating system metadata for a Golden Image. ## @field {string} [family] - OS family (e.g. "Linux", "Windows"). From 0b5a1df3c288de84808a7247aa103e0b797cc5cf Mon Sep 17 00:00:00 2001 From: Myasnikov Daniil Date: Tue, 14 Apr 2026 20:00:25 +0500 Subject: [PATCH 10/11] [platform] Bump migration targetVersion to 39 for migration 38 Address review feedback from lexfrei on migrations/38:2: Migration 38 requires targetVersion 39 to execute, since run-migrations.sh iterates seq $CURRENT_VERSION $((TARGET_VERSION - 1)). Co-Authored-By: Claude Opus 4.6 Signed-off-by: Myasnikov Daniil --- packages/core/platform/values.yaml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/packages/core/platform/values.yaml b/packages/core/platform/values.yaml index 77eb00d7..c21b4f35 100644 --- a/packages/core/platform/values.yaml +++ b/packages/core/platform/values.yaml @@ -6,7 +6,7 @@ sourceRef: migrations: enabled: false image: ghcr.io/cozystack/cozystack/platform-migrations:v1.2.1@sha256:e8fcf006a4451fc0e961455e9b27a61b7103ee49b1a81fe5e4662ffed093fad6 - targetVersion: 38 + targetVersion: 39 # Bundle deployment configuration bundles: system: From e6ba9817be1a42281e73dbedd68aa1ba0b2f9192 Mon Sep 17 00:00:00 2001 From: Myasnikov Daniil Date: Wed, 15 Apr 2026 19:47:25 +0500 Subject: [PATCH 11/11] [platform] Make vm-default-images opt-in, not default in iaas bundle MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit The package imports ~320Gi of golden-image PVCs (ubuntu-noble, fedora, debian, centos, etc.) as soon as it's installed. On small test and dev clusters that's enough to consume the entire replicated storage pool, after which no tenant PVCs — including the ones E2E itself provisions — can be bound. It's also unreasonable to force that cost on every iaas user: many deployments don't need prebuilt images at all, and the ones that do often want to curate their own subset. Switch the bundle entry from 'package.default' to 'package.optional.default', matching the treatment already applied to gpu-operator directly below it. Users who want the golden images can opt in via: bundles: enabledPackages: - cozystack.vm-default-images The package, its Source, and migration 38 all stay in place — nothing else changes for users who explicitly enable it. Users who previously relied on the bundle auto-installing it will need to add the package to enabledPackages on upgrade; this is called out in the release note. Co-Authored-By: Claude Opus 4.6 Signed-off-by: Myasnikov Daniil --- packages/core/platform/templates/bundles/iaas.yaml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/packages/core/platform/templates/bundles/iaas.yaml b/packages/core/platform/templates/bundles/iaas.yaml index 7485eb91..ced0a322 100644 --- a/packages/core/platform/templates/bundles/iaas.yaml +++ b/packages/core/platform/templates/bundles/iaas.yaml @@ -8,7 +8,7 @@ {{- end -}} {{include "cozystack.platform.package" (list "cozystack.kubevirt" "default" $ $kubevirtComponents) }} {{include "cozystack.platform.package.default" (list "cozystack.kubevirt-cdi" $) }} -{{include "cozystack.platform.package.default" (list "cozystack.vm-default-images" $) }} +{{include "cozystack.platform.package.optional.default" (list "cozystack.vm-default-images" $) }} {{include "cozystack.platform.package.optional.default" (list "cozystack.gpu-operator" $) }} {{include "cozystack.platform.package.default" (list "cozystack.kamaji" $) }} {{include "cozystack.platform.package.default" (list "cozystack.capi-operator" $) }}