@@ -175,7 +175,7 @@ def attach_thin(session, journaler, linstor, sr_uuid, vdi_uuid):
175175 lock .release ()
176176
177177
178- def detach_thin (session , linstor , sr_uuid , vdi_uuid ):
178+ def detach_thin_impl (session , linstor , sr_uuid , vdi_uuid ):
179179 volume_metadata = linstor .get_volume_metadata (vdi_uuid )
180180 image_type = volume_metadata .get (VDI_TYPE_TAG )
181181 if image_type == vhdutil .VDI_TYPE_RAW :
@@ -185,21 +185,26 @@ def detach_thin(session, linstor, sr_uuid, vdi_uuid):
185185 try :
186186 lock .acquire ()
187187
188- vdi_ref = session .xenapi .VDI .get_by_uuid (vdi_uuid )
189- vbds = session .xenapi .VBD .get_all_records_where (
190- 'field "VDI" = "{}"' .format (vdi_ref )
191- )
188+ def check_vbd_count ():
189+ vdi_ref = session .xenapi .VDI .get_by_uuid (vdi_uuid )
190+ vbds = session .xenapi .VBD .get_all_records_where (
191+ 'field "VDI" = "{}"' .format (vdi_ref )
192+ )
192193
193- num_plugged = 0
194- for vbd_rec in vbds .values ():
195- if vbd_rec ['currently_attached' ]:
196- num_plugged += 1
197- if num_plugged > 1 :
198- raise xs_errors .XenError (
199- 'VDIUnavailable' ,
200- opterr = 'Cannot deflate VDI {}, already used by '
201- 'at least 2 VBDs' .format (vdi_uuid )
202- )
194+ num_plugged = 0
195+ for vbd_rec in vbds .values ():
196+ if vbd_rec ['currently_attached' ]:
197+ num_plugged += 1
198+ if num_plugged > 1 :
199+ raise xs_errors .XenError (
200+ 'VDIUnavailable' ,
201+ opterr = 'Cannot deflate VDI {}, already used by '
202+ 'at least 2 VBDs' .format (vdi_uuid )
203+ )
204+
205+ # We can have multiple VBDs attached to a VDI during a VM-template clone.
206+ # So we use a timeout to ensure that we can detach the volume properly.
207+ util .retry (check_vbd_count , maxretry = 10 , period = 1 )
203208
204209 device_path = linstor .get_device_path (vdi_uuid )
205210 new_volume_size = LinstorVolumeManager .round_up_volume_size (
@@ -217,6 +222,16 @@ def detach_thin(session, linstor, sr_uuid, vdi_uuid):
217222 lock .release ()
218223
219224
225+ def detach_thin (session , linstor , sr_uuid , vdi_uuid ):
226+ # This function must always return without errors.
227+ # Otherwise it could cause errors in the XAPI regarding the state of the VDI.
228+ # It's why we use this `try` block.
229+ try :
230+ detach_thin_impl (session , linstor , sr_uuid , vdi_uuid )
231+ except Exception as e :
232+ util .SMlog ('Failed to detach properly VDI {}: {}' .format (vdi_uuid , e ))
233+
234+
220235def inflate (journaler , linstor , vdi_uuid , vdi_path , new_size , old_size ):
221236 # Only inflate if the LINSTOR volume capacity is not enough.
222237 new_size = LinstorVolumeManager .round_up_volume_size (new_size )
0 commit comments