@@ -100,6 +100,7 @@ func ApplyVirtualMachineSpec(
100100 class * v1alpha2.VirtualMachineClass ,
101101 ipAddress string ,
102102 networkSpec network.InterfaceSpecList ,
103+ isVmRunning bool ,
103104) error {
104105 if err := kvvm .SetRunPolicy (vm .Spec .RunPolicy ); err != nil {
105106 return err
@@ -128,7 +129,7 @@ func ApplyVirtualMachineSpec(
128129 return err
129130 }
130131
131- if err := applyBlockDeviceRefs (kvvm , vm , vdByName , viByName , cviByName ); err != nil {
132+ if err := applyBlockDeviceRefs (kvvm , vm , isVmRunning , vdByName , viByName , cviByName ); err != nil {
132133 return err
133134 }
134135
@@ -158,7 +159,7 @@ func ApplyVirtualMachineSpec(
158159}
159160
160161func applyBlockDeviceRefs (
161- kvvm * KVVM , vm * v1alpha2.VirtualMachine ,
162+ kvvm * KVVM , vm * v1alpha2.VirtualMachine , isVmRunning bool ,
162163 vdByName map [string ]* v1alpha2.VirtualDisk ,
163164 viByName map [string ]* v1alpha2.VirtualImage ,
164165 cviByName map [string ]* v1alpha2.ClusterVirtualImage ,
@@ -171,6 +172,18 @@ func applyBlockDeviceRefs(
171172 }
172173 }
173174
175+ specDiskNames := make (map [string ]struct {}, len (vm .Spec .BlockDeviceRefs ))
176+ for _ , bd := range vm .Spec .BlockDeviceRefs {
177+ specDiskNames [GenerateDiskName (bd .Kind , bd .Name )] = struct {}{}
178+ }
179+ hotpluggableVolumes := make (map [string ]struct {}, len (kvvm .Resource .Spec .Template .Spec .Volumes ))
180+ for _ , v := range kvvm .Resource .Spec .Template .Spec .Volumes {
181+ if v .ContainerDisk != nil && v .ContainerDisk .Hotpluggable || v .PersistentVolumeClaim != nil && v .PersistentVolumeClaim .Hotpluggable {
182+ hotpluggableVolumes [v .Name ] = struct {}{}
183+ }
184+ }
185+ cleanupRemovedStaticDisks (kvvm , specDiskNames , hotpluggableVolumes )
186+
174187 kvvmVolumes := kvvm .Resource .Spec .Template .Spec .Volumes
175188 for i , bd := range vm .Spec .BlockDeviceRefs {
176189 diskName := GenerateDiskName (bd .Kind , bd .Name )
@@ -187,28 +200,32 @@ func applyBlockDeviceRefs(
187200 kvBootOrder = uint (i ) + 1
188201 }
189202
190- hotpluggable := isVolumeHotpluggable (kvvmVolumes , diskName )
191- if err := setBlockDeviceDisk (kvvm , bd , kvBootOrder , hotpluggable , vdByName , viByName , cviByName ); err != nil {
203+ _ , hotpluggable := hotpluggableVolumes [diskName ]
204+ // isVmRunning is used to set static disks as hotpluggable on VM restart
205+ if err := setBlockDeviceDisk (kvvm , bd , kvBootOrder , hotpluggable || ! isVmRunning , vdByName , viByName , cviByName ); err != nil {
192206 return err
193207 }
194208 }
195209
196210 return nil
197211}
198212
199- func isVolumeHotpluggable (volumes []virtv1.Volume , name string ) bool {
200- for _ , v := range volumes {
201- if v .Name != name {
202- continue
203- }
204- if v .PersistentVolumeClaim != nil {
205- return v .PersistentVolumeClaim .Hotpluggable
206- }
207- if v .ContainerDisk != nil {
208- return v .ContainerDisk .Hotpluggable
209- }
213+ func cleanupRemovedStaticDisks (kvvm * KVVM , specDiskNames map [string ]struct {}, hotpluggableVolumes map [string ]struct {}) {
214+ isRemovedStatic := func (name string ) bool {
215+ _ , kind := GetOriginalDiskName (name )
216+ _ , inSpec := specDiskNames [name ]
217+ _ , hotpluggable := hotpluggableVolumes [name ]
218+ return kind != "" && ! inSpec && ! hotpluggable
210219 }
211- return true
220+
221+ kvvm .Resource .Spec .Template .Spec .Domain .Devices .Disks = slices .DeleteFunc (
222+ kvvm .Resource .Spec .Template .Spec .Domain .Devices .Disks ,
223+ func (d virtv1.Disk ) bool { return isRemovedStatic (d .Name ) },
224+ )
225+ kvvm .Resource .Spec .Template .Spec .Volumes = slices .DeleteFunc (
226+ kvvm .Resource .Spec .Template .Spec .Volumes ,
227+ func (v virtv1.Volume ) bool { return isRemovedStatic (v .Name ) },
228+ )
212229}
213230
214231func setBlockDeviceDisk (
0 commit comments