1919)
2020from lib .snapshot import Snapshot
2121from lib .vbd import VBD
22+ from lib .vdi import VDI
2223from lib .vif import VIF
2324
2425from typing import TYPE_CHECKING , List , Literal , Optional , Union , overload
@@ -33,6 +34,7 @@ def __init__(self, uuid: str, host: 'Host'):
3334 self .previous_host = None # previous host when migrated or being migrated
3435 self .is_windows = self .param_get ('platform' , 'device_id' , accept_unknown_key = True ) == '0002'
3536 self .is_uefi = self .param_get ('HVM-boot-params' , 'firmware' , accept_unknown_key = True ) == 'uefi'
37+ self .create_vdis_list ()
3638
3739 def power_state (self ) -> str :
3840 return self .param_get ('power-state' )
@@ -273,19 +275,74 @@ def migrate(self, target_host, sr=None, network=None):
273275
274276 self .previous_host = self .host
275277 self .host = target_host
278+ self .create_vdis_list ()
276279
277280 def snapshot (self , ignore_vdis = None ):
278281 logging .info ("Snapshot VM" )
279282 args = {'uuid' : self .uuid , 'new-name-label' : 'Snapshot of %s' % self .uuid }
280283 if ignore_vdis :
281284 args ['ignore-vdi-uuids' ] = ',' .join (ignore_vdis )
282- return Snapshot (self .host .xe ('vm-snapshot' , args ), self .host )
285+ snap_uuid = self .host .xe ('vm-snapshot' , args )
286+ return Snapshot (snap_uuid , self .host , self )
283287
284288 def checkpoint (self ) -> Snapshot :
285289 logging .info ("Checkpoint VM" )
286290 return Snapshot (self .host .xe ('vm-checkpoint' , {'uuid' : self .uuid ,
287291 'new-name-label' : 'Checkpoint of %s' % self .uuid }),
288- self .host )
292+ self .host , self )
293+
294+ def connect_vdi (self , vdi : VDI , device : str = "autodetect" ) -> str :
295+ logging .info (f">> Plugging VDI { vdi .uuid } on VM { self .uuid } " )
296+ vbd_uuid = self .host .xe ("vbd-create" , {
297+ "vdi-uuid" : vdi .uuid ,
298+ "vm-uuid" : self .uuid ,
299+ "device" : device ,
300+ })
301+ try :
302+ self .host .xe ("vbd-plug" , {"uuid" : vbd_uuid })
303+ except commands .SSHCommandFailed :
304+ self .host .xe ("vbd-destroy" , {"uuid" : vbd_uuid })
305+ raise
306+
307+ self .vdis .append (vdi )
308+
309+ return vbd_uuid
310+
311+ def disconnect_vdi (self , vdi : VDI ):
312+ logging .info (f"<< Unplugging VDI { vdi .uuid } from VM { self .uuid } " )
313+ assert vdi in self .vdis , "VDI {vdi.uuid} not in VM {self.uuid} VDI list"
314+ vbd_uuid = self .host .xe ("vbd-list" , {
315+ "vdi-uuid" : vdi .uuid ,
316+ "vm-uuid" : self .uuid
317+ }, minimal = True )
318+ try :
319+ self .host .xe ("vbd-unplug" , {"uuid" : vbd_uuid })
320+ except commands .SSHCommandFailed as e :
321+ if e .stdout == f"The device is not currently attached\n device: { vbd_uuid } " :
322+ logging .info (f"VBD { vbd_uuid } already unplugged" )
323+ else :
324+ raise
325+ self .host .xe ("vbd-destroy" , {"uuid" : vbd_uuid })
326+ self .vdis .remove (vdi )
327+
328+ def destroy_vdi (self , vdi_uuid : str ) -> None :
329+ for vdi in self .vdis :
330+ if vdi .uuid == vdi_uuid :
331+ self .vdis .remove (vdi )
332+ super ().destroy_vdi (vdi_uuid )
333+ break
334+
335+ def create_vdis_list (self ) -> None :
336+ """ Used to redo the VDIs list of the VM when reverting a snapshot. """
337+ try :
338+ self .vdis = [VDI (vdi_uuid , host = self .host ) for vdi_uuid in self .vdi_uuids ()]
339+ except commands .SSHCommandFailed as e :
340+ # Doesn't work with Dom0 since `vm-disk-list` doesn't work on it so we create empty list
341+ if e .stdout == "Error: No matching VMs found" :
342+ logging .info ("Couldn't get disks list. We are Dom0. Continuing..." )
343+ self .vdis = []
344+ else :
345+ raise
289346
290347 def vifs (self ):
291348 _vifs = []
0 commit comments