Skip to content

Commit a3f767d

Browse files
committed
fix(vm-disk): refuse to clone a golden image whose import failed
A disk with source.image clones a golden from cozy-public without looking at it. When that golden's import has failed, CDI never populates it, so the clone waits forever and the new disk sits pending with nothing pointing at the image. Fail the render instead when the golden's phase is Failed, naming the image. A golden still importing is left alone because CDI holds the clone until the source is populated. An existing disk is exempt: its clone already started or finished, and a later failure of the golden must not break its upgrades. Assisted-by: LLM Signed-off-by: Aleksei Sviridkin <[email protected]>
1 parent e5ba737 commit a3f767d

2 files changed

Lines changed: 100 additions & 0 deletions

File tree

‎packages/apps/vm-disk/templates/dv.yaml‎

Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -11,6 +11,17 @@
1111
{{- end }}
1212
{{- if hasKey .Values.source "image" }}
1313
{{- $desiredSource = dict "pvc" (dict "name" (printf "vm-default-images-%s" (required "A valid .Values.source.image.name entry required!" .Values.source.image.name)) "namespace" "cozy-public") }}
14+
{{- /* Refuse only a golden whose import Failed: CDI never populates it, so the
15+
clone would wait forever. A golden still importing is left alone because
16+
CDI holds the clone until the source is populated. An existing disk is
17+
exempt, since its clone has already started or finished and a later
18+
failure of the golden must not break this release's upgrades. */}}
19+
{{- if not $existingDV }}
20+
{{- $golden := lookup "cdi.kubevirt.io/v1beta1" "DataVolume" "cozy-public" $desiredSource.pvc.name }}
21+
{{- if eq (dig "status" "phase" "" $golden | toString) "Failed" }}
22+
{{- fail (printf "source.image %q: golden DataVolume %q in cozy-public failed to import (phase Failed), so a clone of it would never complete. Ask the platform administrator to check the importer pod in cozy-public and re-import the image." .Values.source.image.name $desiredSource.pvc.name) }}
23+
{{- end }}
24+
{{- end }}
1425
{{- else if hasKey .Values.source "http" }}
1526
{{- $desiredSource = dict "http" (dict "url" (required "A valid .Values.source.http.url entry required!" .Values.source.http.url)) }}
1627
{{- else if hasKey .Values.source "upload" }}
Lines changed: 89 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,89 @@
1+
suite: vm-disk refuses to clone a golden image whose import failed
2+
# A golden whose import Failed is never populated, and CDI holds a clone of it
3+
# forever, so a new disk on it would sit pending with nothing pointing at the
4+
# image. Only Failed is refused: a golden still importing is safe to clone
5+
# because CDI waits for it, and helm template has no cluster to look it up in.
6+
release:
7+
name: test-vm-disk
8+
namespace: tenant-test
9+
templates:
10+
- templates/dv.yaml
11+
tests:
12+
- it: refuses a new disk on a golden whose import Failed
13+
set:
14+
source: {image: {name: ubuntu}}
15+
kubernetesProvider:
16+
scheme: &scheme
17+
"cdi.kubevirt.io/v1beta1/DataVolume":
18+
gvr: {group: cdi.kubevirt.io, version: v1beta1, resource: datavolumes}
19+
namespaced: true
20+
objects:
21+
- kind: DataVolume
22+
apiVersion: cdi.kubevirt.io/v1beta1
23+
metadata: {name: vm-default-images-ubuntu, namespace: cozy-public}
24+
status: {phase: Failed}
25+
asserts:
26+
- failedTemplate:
27+
errorPattern: 'golden DataVolume "vm-default-images-ubuntu" in cozy-public failed to import \(phase Failed\)'
28+
29+
- it: clones a golden whose import Succeeded
30+
set:
31+
source: {image: {name: ubuntu}}
32+
kubernetesProvider:
33+
scheme: *scheme
34+
objects:
35+
- kind: DataVolume
36+
apiVersion: cdi.kubevirt.io/v1beta1
37+
metadata: {name: vm-default-images-ubuntu, namespace: cozy-public}
38+
status: {phase: Succeeded}
39+
asserts:
40+
- equal:
41+
path: spec.source.pvc
42+
value: {name: vm-default-images-ubuntu, namespace: cozy-public}
43+
44+
- it: clones a golden that is still importing
45+
set:
46+
source: {image: {name: ubuntu}}
47+
kubernetesProvider:
48+
scheme: *scheme
49+
objects:
50+
- kind: DataVolume
51+
apiVersion: cdi.kubevirt.io/v1beta1
52+
metadata: {name: vm-default-images-ubuntu, namespace: cozy-public}
53+
status: {phase: ImportInProgress}
54+
asserts:
55+
- equal:
56+
path: spec.source.pvc
57+
value: {name: vm-default-images-ubuntu, namespace: cozy-public}
58+
59+
- it: renders without a cluster to look the golden up in
60+
set:
61+
source: {image: {name: ubuntu}}
62+
asserts:
63+
- equal:
64+
path: spec.source.pvc
65+
value: {name: vm-default-images-ubuntu, namespace: cozy-public}
66+
67+
- it: leaves an existing disk alone when its golden later Failed
68+
set:
69+
source: {image: {name: ubuntu}}
70+
kubernetesProvider:
71+
scheme: *scheme
72+
objects:
73+
- kind: DataVolume
74+
apiVersion: cdi.kubevirt.io/v1beta1
75+
metadata: {name: vm-default-images-ubuntu, namespace: cozy-public}
76+
status: {phase: Failed}
77+
- kind: DataVolume
78+
apiVersion: cdi.kubevirt.io/v1beta1
79+
metadata:
80+
name: test-vm-disk
81+
namespace: tenant-test
82+
annotations:
83+
vm-disk.cozystack.io/source: '{"image":{"name":"ubuntu"}}'
84+
vm-disk.cozystack.io/storage-class: replicated
85+
spec:
86+
source: {pvc: {name: vm-default-images-ubuntu, namespace: cozy-public}}
87+
storage: {resources: {requests: {storage: 5Gi}}, storageClassName: replicated}
88+
asserts:
89+
- notFailedTemplate: {}

0 commit comments

Comments
 (0)