'Detaches a device from the guest. After the initial detach request,
a function is returned which can be used to ensure the device is
successfully removed from the guest domain (retrying the removal as
necessary).
:param get_device_conf_func: function which takes device as a parameter
and returns the configuration for device
:param device: device to detach
:param live: bool to indicate whether it affects the guest in running
state
:param max_retry_count: number of times the returned function will
retry a detach before failing
:param inc_sleep_time: incremental time to sleep in seconds between
detach retries
:param max_sleep_time: max sleep time in seconds beyond which the sleep
time will not be incremented using param
inc_sleep_time. On reaching this threshold,
max_sleep_time will be used as the sleep time.
:param alternative_device_name: This is an alternative identifier for
the device if device is not an ID, used solely for error messages.'

def detach_device_with_retry(self, get_device_conf_func, device, live, max_retry_count=7, inc_sleep_time=2, max_sleep_time=30, alternative_device_name=None):

    alternative_device_name = (alternative_device_name or device)
    def _try_detach_device(conf, persistent=False, live=False):
        try:
            self.detach_device(conf, persistent=persistent, live=live)
            LOG.debug('Successfully    detached    device    %s    from    guest.    Persistent?    %s.    Live?    %s', device, persistent, live)
        except libvirt.libvirtError as ex:
            with excutils.save_and_reraise_exception():
                errcode = ex.get_error_code()
                if (errcode == libvirt.VIR_ERR_OPERATION_FAILED):
                    errmsg = ex.get_error_message()
                    if ('not    found' in errmsg):
                        raise exception.DeviceNotFound(device=alternative_device_name)
                elif (errcode == libvirt.VIR_ERR_INVALID_ARG):
                    errmsg = ex.get_error_message()
                    if ('no    target    device' in errmsg):
                        raise exception.DeviceNotFound(device=alternative_device_name)
    conf = get_device_conf_func(device)
    if (conf is None):
        raise exception.DeviceNotFound(device=alternative_device_name)
    persistent = self.has_persistent_configuration()
    LOG.debug('Attempting    initial    detach    for    device    %s', alternative_device_name)
    try:
        _try_detach_device(conf, persistent, live)
    except exception.DeviceNotFound:
        if (persistent and live):
            pass
        else:
            raise
    LOG.debug('Start    retrying    detach    until    device    %s    is    gone.', alternative_device_name)
    @loopingcall.RetryDecorator(max_retry_count=max_retry_count, inc_sleep_time=inc_sleep_time, max_sleep_time=max_sleep_time, exceptions=exception.DeviceDetachFailed)
    def _do_wait_and_retry_detach():
        config = get_device_conf_func(device)
        if (config is not None):
            _try_detach_device(config, persistent=False, live=live)
            reason = _('Unable    to    detach    from    guest    transient    domain.')
            raise exception.DeviceDetachFailed(device=alternative_device_name, reason=reason)
    return _do_wait_and_retry_detach
