1616
1717from .. import logger
1818
19- def clean_pools (inventory : Inventory , dry_run : bool = False ) -> None :
19+ def clean_pools (inventory : Inventory , dry_run : bool = False ) -> int :
2020 """Remove all VMs and all orphan VDIs on local storage from pool(s).
2121
2222 .. note::
@@ -31,6 +31,8 @@ def clean_pools(inventory: Inventory, dry_run: bool = False) -> None:
3131 Each host (key) holds its own config data (values, eg: `enablerepos`).
3232 :param bool dry_run:
3333 When True, only log what would be removed without actually deleting.
34+ :return:
35+ The number of VMs/VDIs/snapshots that failed to be removed.
3436 """
3537 inventory_hosts = inventory ["hosts" ]
3638 pools : list [Pool ] = []
@@ -42,44 +44,64 @@ def clean_pools(inventory: Inventory, dry_run: bool = False) -> None:
4244
4345 with ThreadPoolExecutor () as executor :
4446 futures = {executor .submit (clean_pool , p , dry_run ): p for p in pools }
47+ failures = 0
4548 for future in futures :
4649 pool = futures [future ]
4750 try :
48- future .result ()
51+ failures += future .result ()
4952 except Exception as exc :
50- logger .error (f"Cleaning pool has failed! The master { pool .master } cannot be cleaned." )
51- raise exc
53+ logger .error (f"Cleaning pool has failed! The master { pool .master } cannot be cleaned: { exc } " )
54+ failures += 1
55+ return failures
5256
53- def clean_pool (pool : Pool , dry_run : bool ) -> None :
54- """Remove all VMs and all orphan VDIs on local SRs from a single pool."""
57+ def clean_pool (pool : Pool , dry_run : bool ) -> int :
58+ """Remove all VMs and all orphan VDIs on local SRs from a single pool.
59+
60+ :return:
61+ The number of VMs plus number VDIs that failed to be removed from pool
62+ """
5563 master = pool .master
5664 log_prefix = 'Would remove' if dry_run else 'Removing'
65+ failures = 0
5766
5867 vm_uuids = safe_split (master .xe (
5968 'vm-list' ,
6069 {'is-control-domain' : False , 'is-a-template' : False },
6170 minimal = True ,
71+ )) + safe_split (master .xe (
72+ 'vm-list' ,
73+ {'is-a-snapshot' : True },
74+ minimal = True ,
6275 ))
6376 for vm_uuid in vm_uuids :
6477 vm = VM (vm_uuid , master )
6578 logger .info (f"[{ master } ] { log_prefix } VM { vm .uuid } ({ vm .name ()} )" )
6679 if not dry_run :
67- vm .destroy (verify = True )
80+ try :
81+ vm .destroy (verify = True )
82+ except Exception as exc :
83+ logger .error (f"[{ master } ] Failed to remove VM { vm .uuid } ({ vm .name ()} ): { exc } " )
84+ failures += 1
6885
6986 sr_uuids = local_sr_uuids (pool )
7087 for sr_uuid in sr_uuids :
7188 for vdi_uuid in SR (sr_uuid , pool ).vdi_uuids (managed = True ):
7289 vdi = VDI (vdi_uuid , sr = SR (sr_uuid , pool ))
7390 logger .info (f"[{ master } ] { log_prefix } orphan VDI { vdi .uuid } from local SR { sr_uuid } " )
7491 if not dry_run :
75- vdi .destroy ()
92+ try :
93+ vdi .destroy ()
94+ except Exception as exc :
95+ logger .error (f"[{ master } ] Failed to destroy VDI { vdi .uuid } : { exc } " )
96+ failures += 1
7697
77- if not dry_run :
98+ if not dry_run and failures == 0 :
7899 for sr_uuid in sr_uuids :
79100 wait_for_not (
80101 lambda : len (SR (sr_uuid , pool ).vdi_uuids (managed = True )) > 0 ,
81102 f"Wait for local SR { sr_uuid } to be empty" ,
82103 )
104+ return failures
83105
84106def local_sr_uuids (pool : Pool ) -> list [str ]:
85107 """Return the UUIDs of the pool's local (non-shared, user) SRs."""
0 commit comments