Skip to content

Commit 482d813

Browse files
Add vm-default-images package (#2258)
<!-- Thank you for making a contribution! Here are some tips for you: - Start the PR title with the [label] of Cozystack component: - For system components: [platform], [system], [linstor], [cilium], [kube-ovn], [dashboard], [cluster-api], etc. - For managed apps: [apps], [tenant], [kubernetes], [postgres], [virtual-machine] etc. - For development and maintenance: [tests], [ci], [docs], [maintenance]. - If it's a work in progress, consider creating this PR as a draft. - Don't hesistate to ask for opinion and review in the community chats, even if it's still a draft. - Add the label `backport` if it's a bugfix that needs to be backported to a previous version. --> ## What this PR does ### Release note <!-- Write a release note: - Explain what has changed internally and for users. - Start with the same [label] as in the PR title - Follow the guidelines at https://github.com/kubernetes/community/blob/master/contributors/guide/release-notes.md. --> ```release-note [vm-default-images] Added package that brings set of images that can be used clusterwide [vm-disk] Updated source "image" for prettier dropdown selection [vm-disk] Added new source for vm-disk called disk - to use as source vm-disk from same namespace. ``` <!-- This is an auto-generated comment: release notes by coderabbit.ai --> ## Summary by CodeRabbit * **New Features** * Clone VM disks by specifying an existing vm-disk as the source. * Global default image collection and chart to publish pre-provisioned images. * **UI** * Forms provide selectable lists for default images and existing VM disks. * **Migration** * Migration to rename existing image DataVolumes to the new default-images naming and bumped migration version. * **Documentation** * VM disk docs and README updated to reflect image sourcing and cloning. <!-- end of auto-generated comment: release notes by coderabbit.ai -->
2 parents b28bd59 + e6ba981 commit 482d813

22 files changed

Lines changed: 609 additions & 52 deletions

File tree

‎api/apps/v1alpha1/vmdisk/types.go‎

Lines changed: 9 additions & 2 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

‎api/apps/v1alpha1/vmdisk/zz_generated.deepcopy.go‎

Lines changed: 20 additions & 0 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

‎api/apps/v1alpha1/vminstance/zz_generated.deepcopy.go‎

Lines changed: 17 additions & 12 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

‎api/apps/v1alpha1/vpc/zz_generated.deepcopy.go‎

Lines changed: 40 additions & 0 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

‎api/backups/v1alpha1/zz_generated.deepcopy.go‎

Lines changed: 16 additions & 1 deletion
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

‎hack/cdi_golden_image_create.sh‎

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -16,7 +16,7 @@ kubectl create -f - <<EOF
1616
apiVersion: cdi.kubevirt.io/v1beta1
1717
kind: DataVolume
1818
metadata:
19-
name: "vm-image-$name"
19+
name: "vm-default-images-$name"
2020
namespace: cozy-public
2121
annotations:
2222
cdi.kubevirt.io/storage.bind.immediate.requested: "true"

‎internal/controller/dashboard/customformsoverride.go‎

Lines changed: 57 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -141,7 +141,10 @@ func (m *Manager) ensureCFOMapping(ctx context.Context, crd *cozyv1alpha1.Applic
141141
}
142142

143143
// buildMultilineStringSchema parses OpenAPI schema and creates schema with multilineString
144-
// for all string fields inside spec that don't have enum
144+
// for all string fields inside spec that don't have enum.
145+
// It handles two structures:
146+
// - properties.spec.properties (most resources)
147+
// - properties.properties (VMDisk and similar resources without spec wrapper)
145148
func buildMultilineStringSchema(openAPISchema string) (map[string]any, error) {
146149
if openAPISchema == "" {
147150
return map[string]any{}, nil
@@ -161,15 +164,25 @@ func buildMultilineStringSchema(openAPISchema string) (map[string]any, error) {
161164
"properties": map[string]any{},
162165
}
163166

164-
// Check if there's a spec property
165-
specProp, ok := props["spec"].(map[string]any)
166-
if !ok {
167-
return map[string]any{}, nil
167+
var specProps map[string]any
168+
var hasSpec bool
169+
170+
// First try to find properties under spec
171+
if specProp, ok := props["spec"].(map[string]any); ok {
172+
specProps, hasSpec = specProp["properties"].(map[string]any)
168173
}
169174

170-
specProps, ok := specProp["properties"].(map[string]any)
171-
if !ok {
172-
return map[string]any{}, nil
175+
// If no spec wrapper, use top-level properties directly (VMDisk pattern)
176+
if !hasSpec {
177+
specProps = props
178+
// Still wrap in spec for consistency with applyListInputOverrides
179+
schemaProps := schema["properties"].(map[string]any)
180+
specSchema := map[string]any{
181+
"properties": map[string]any{},
182+
}
183+
schemaProps["spec"] = specSchema
184+
processSpecProperties(specProps, specSchema["properties"].(map[string]any))
185+
return schema, nil
173186
}
174187

175188
// Create spec.properties structure in schema
@@ -231,10 +244,45 @@ func applyListInputOverrides(schema map[string]any, kind string, openAPIProps ma
231244
}
232245

233246
case "ClickHouse", "Harbor", "HTTPCache", "Kubernetes", "MariaDB", "MongoDB",
234-
"NATS", "OpenBAO", "Postgres", "Qdrant", "RabbitMQ", "Redis", "VMDisk":
247+
"NATS", "OpenBAO", "Postgres", "Qdrant", "RabbitMQ", "Redis":
248+
specProps := ensureSchemaPath(schema, "spec")
249+
specProps["storageClass"] = storageClassListInput()
250+
251+
case "VMDisk":
235252
specProps := ensureSchemaPath(schema, "spec")
236253
specProps["storageClass"] = storageClassListInput()
237254

255+
// Override source.image.name to be an API-backed dropdown listing default images
256+
if sourceObj, ok := specProps["source"].(map[string]any); ok {
257+
if imgProps, ok := sourceObj["properties"].(map[string]any); ok {
258+
if imgName, ok := imgProps["image"].(map[string]any); ok {
259+
if imgNameProps, ok := imgName["properties"].(map[string]any); ok {
260+
imgNameProps["name"] = map[string]any{
261+
"type": "listInput",
262+
"customProps": map[string]any{
263+
"valueUri": "/api/clusters/{cluster}/k8s/apis/cdi.kubevirt.io/v1beta1/namespaces/cozy-public/datavolumes",
264+
"keysToValue": []any{"metadata", "annotations", "vm-default-images.cozystack.io/name"},
265+
"keysToLabel": []any{"metadata", "annotations", "vm-default-images.cozystack.io/description"},
266+
},
267+
}
268+
}
269+
}
270+
// Override source.disk.name to be an API-backed dropdown listing VMDisk resources
271+
if diskName, ok := imgProps["disk"].(map[string]any); ok {
272+
if diskNameProps, ok := diskName["properties"].(map[string]any); ok {
273+
diskNameProps["name"] = map[string]any{
274+
"type": "listInput",
275+
"customProps": map[string]any{
276+
"valueUri": "/api/clusters/{cluster}/k8s/apis/apps.cozystack.io/v1alpha1/namespaces/{namespace}/vmdisks",
277+
"keysToValue": []any{"metadata", "name"},
278+
"keysToLabel": []any{"metadata", "name"},
279+
},
280+
}
281+
}
282+
}
283+
}
284+
}
285+
238286
case "FoundationDB":
239287
storageProps := ensureSchemaPath(schema, "spec", "storage")
240288
storageProps["storageClass"] = storageClassListInput()

0 commit comments

Comments
 (0)