def _get_nm_address(task): """Get Intel Node Manager target channel and address. :param task: a TaskManager instance. :raises: IPMIFailure if Intel Node Manager is not detected on a node or if an error happens during detection. :returns: a tuple with IPMI channel and address of Intel Node Manager. """ node = task.node driver_internal_info = node.driver_internal_info def _save_to_node(channel, address): driver_internal_info['intel_nm_channel'] = channel driver_internal_info['intel_nm_address'] = address node.driver_internal_info = driver_internal_info node.save() channel = driver_internal_info.get('intel_nm_channel') address = driver_internal_info.get('intel_nm_address') if channel and address: return channel, address if channel is False and address is False: raise exception.IPMIFailure( _('Driver data indicates that Intel ' 'Node Manager detection failed.')) LOG.info(_LI('Start detection of Intel Node Manager on node %s'), node.uuid) sdr_filename = os.path.join(CONF.tempdir, node.uuid + '.sdr') res = None try: ipmitool.dump_sdr(task, sdr_filename) res = nm_commands.parse_slave_and_channel(sdr_filename) finally: ironic_utils.unlink_without_raise(sdr_filename) if res is None: _save_to_node(False, False) raise exception.IPMIFailure(_('Intel Node Manager is not detected.')) address, channel = res LOG.debug( 'Intel Node Manager sensors present in SDR on node %(node)s, ' 'channel %(channel)s address %(address)s.', { 'node': node.uuid, 'channel': channel, 'address': address }) # SDR can contain wrong info, try simple command node.driver_info['ipmi_bridging'] = 'single' node.driver_info['ipmi_target_channel'] = channel node.driver_info['ipmi_target_address'] = address try: ipmitool.send_raw(task, _command_to_string(nm_commands.get_version(None))) _save_to_node(channel, address) return channel, address except exception.IPMIFailure: _save_to_node(False, False) raise exception.IPMIFailure( _('Intel Node Manager sensors record ' 'present in SDR but Node Manager is not ' 'responding.'))
def set_boot_device(self, task): try: #BMC boot flag valid bit clearing 1f -> all bit set #P 420 of ipmi spec # https://www.intel.com/content/www/us/en/servers/ipmi/ipmi-second-gen-interface-spec-v2-rev1-1.html cmd = '0x00 0x08 0x03 0x1f' ipmitool.send_raw(task, cmd) self.log.info('Disable timeout for booting') except Exception as err: self.log.warning('Failed to disable booting options: %s', str(err)) #For time being lets do the boot order with ipmitool since, well dell doesn't provide open support #for this. try: # 0x00 0x08 0x05 0x80 0x20: chassis|set|bootdev|for next boot only|remote CD # other options for device (per ipmitool's "ipmi_chassis.c"): # 04: PXE # 08: HDD # 0c: Safe # 10: Diag # 14: CDROM # 18: Setup # 1c: Remote FDD # 24: Remote primary media # 2c: Remote HDD # 3c: FDD ipmitool.send_raw(task, '0x00 0x08 0x05 0x80 0x20 0x00 0x00 0x00') self.log.info('Set next boot to remote media') except Exception as err: self.log.warning('Failed to set next boot to remote media: %s', str(err))
def _toggle_virtual_device(self, enabled, task): # Enable "Mount CD/DVD" in GUI should cause vmedia restart withing 2 seconds. # Seems "Mount CD/DVD" need to be enabled (or toggled) after config. # refresh/vmedia restart is not enough(?) try: status = '01' if enabled else '00' cmd = RAW_SET_VMEDIA_MOUNT_STATUS % ('0x' + status) self.log.debug('Set mount CD/DVD enable status %s' % status) ipmitool.send_raw(task, cmd) self.log.debug('Ensure CD/DVD enable status is %s' % status) tries = 60 while tries > 0: out, err = ipmitool.send_raw(task, RAW_GET_VMEDIA_MOUNT_STATUS) res = out.strip() self.log.debug('CD/DVD enable status is %s' % res) if res == status: return True tries -= 1 time.sleep(2) except Exception as err: self.log.warning( 'Exception when CD/DVD virtual media new firmware? ignoring... Error: %s' % str(err)) self.log.warning( 'Ensure virtual media status failed, attempts exceeded.') return False
def detach_virtual_cd(self, driver_info, task): """Detaches virtual cdrom on the node. :param task: an ironic task object. """ # Stop virtual device and Clear NFS configuration self.log.debug("detach_virtual_cd") ipmitool.send_raw(task, '0x3c 0x00')
def _restart_ris(self, task): try: self.log.debug('Restart RIS') cmd = '0x32 0x9f 0x08 0x0b' ipmitool.send_raw(task, cmd) except Exception as err: self.log.warning('Exception when restarting RIS: %s' % str(err)) return False return True
def _start_virtual_media(self, task): # Enable "Remote Media Support" in GUI (p145) try: cmd = '0x32 0xcb 0x08 0x01' self.log.debug('Start virtual media service') ipmitool.send_raw(task, cmd) except Exception as err: self.log.warning( 'Exception when starting virtual media service: %s' % str(err))
def _restart_virtual_media_service(self, task): try: cmd = RAW_RESTART_VMEDIA self.log.debug('Restart virtual media service') ipmitool.send_raw(task, cmd) except Exception as err: self.log.warning( 'Exception when restarting virtual media service: %s' % str(err))
def _start_virtual_media(self, task): # Enable "Remote Media Support" try: cmd = RAW_SET_VMEDIA_STATUS % '0x01' self.log.debug('Start virtual media service') ipmitool.send_raw(task, cmd) except Exception as err: self.log.warning( 'Exception when starting virtual media service: %s' % str(err))
def _restart_virtual_media_service(self, task): try: cmd = '0x32 0xcb 0x0a 0x01' self.log.debug('Restart virtual media service') ipmitool.send_raw(task, cmd) except Exception as err: self.log.warning( 'Exception when restarting virtual media service: %s' % str(err))
def _set_share_type(self, task): try: cmd = RAW_SET_RIS_NFS self.log.debug('Virtual media share type to NFS.') ipmitool.send_raw(task, cmd) except Exception as err: self.log.warning( 'Exception when setting virtual media service type NFS: %s' % str(err)) raise err
def _restart_ris(self, task): # Restart Remote Image Service try: self.log.debug('Restart Remote Image Service') cmd = RAW_RESTART_RIS ipmitool.send_raw(task, cmd) except Exception as err: self.log.warning('Exception when restarting RIS: %s' % str(err)) return False return True
def _set_share_type(self, task): try: cmd = '0x32 0x9f 0x01 0x05 0x00 0x6e 0x66 0x73 0x00 0x00 0x00' self.log.debug('Virtual media share type to NFS.') ipmitool.send_raw(task, cmd) except Exception as err: self.log.warning( 'Exception when setting virtual media service type NFS: %s' % str(err)) raise err
def _clear_ris_configuration(self, task): # Clear RIS configuration try: cmd = '0x32 0x9f 0x01 0x0d' self.log.debug('Clear RIS configuration.') ipmitool.send_raw(task, cmd) except Exception as err: self.log.warning( 'Exception when clearing RIS NFS configuration: %s' % str(err)) return False return True
def _set_image_name(self, image_filename, task): try: cmd = RAW_SET_IMG_NAME % (self.hex_convert(image_filename, True, 64)) self.log.debug('Setting virtual media image: %s' % image_filename) ipmitool.send_raw(task, cmd) except Exception as err: self.log.debug('Exception when setting virtual media image: %s' % str(err)) return False return True
def _get_nm_address(task): """Get Intel Node Manager target channel and address. :param task: a TaskManager instance. :raises: IPMIFailure if Intel Node Manager is not detected on a node or if an error happens during detection. :returns: a tuple with IPMI channel and address of Intel Node Manager. """ node = task.node driver_internal_info = node.driver_internal_info def _save_to_node(channel, address): driver_internal_info['intel_nm_channel'] = channel driver_internal_info['intel_nm_address'] = address node.driver_internal_info = driver_internal_info node.save() channel = driver_internal_info.get('intel_nm_channel') address = driver_internal_info.get('intel_nm_address') if channel and address: return channel, address if channel is False and address is False: raise exception.IPMIFailure(_('Driver data indicates that Intel ' 'Node Manager detection failed.')) LOG.info(_LI('Start detection of Intel Node Manager on node %s'), node.uuid) sdr_filename = os.path.join(CONF.tempdir, node.uuid + '.sdr') res = None try: ipmitool.dump_sdr(task, sdr_filename) res = nm_commands.parse_slave_and_channel(sdr_filename) finally: ironic_utils.unlink_without_raise(sdr_filename) if res is None: _save_to_node(False, False) raise exception.IPMIFailure(_('Intel Node Manager is not detected.')) address, channel = res LOG.debug('Intel Node Manager sensors present in SDR on node %(node)s, ' 'channel %(channel)s address %(address)s.', {'node': node.uuid, 'channel': channel, 'address': address}) # SDR can contain wrong info, try simple command node.driver_info['ipmi_bridging'] = 'single' node.driver_info['ipmi_target_channel'] = channel node.driver_info['ipmi_target_address'] = address try: ipmitool.send_raw(task, _command_to_string(nm_commands.get_version(None))) _save_to_node(channel, address) return channel, address except exception.IPMIFailure: _save_to_node(False, False) raise exception.IPMIFailure(_('Intel Node Manager sensors record ' 'present in SDR but Node Manager is not ' 'responding.'))
def _set_nfs_server_ip(self, driver_info, task): try: cmd = '0x32 0x9f 0x01 0x02 0x00 %s' % (self.hex_convert( driver_info['provisioning_server'], True, 63)) self.log.debug('Virtual media server "%s"' % driver_info['provisioning_server']) ipmitool.send_raw(task, cmd) except Exception as err: self.log.warning( 'Exception when setting virtual media server: %s' % str(err)) raise err
def _clear_ris_configuration(self, task): # Clear Remote Image Service configuration try: cmd = RAW_CLEAR_RIS_CONFIG self.log.debug('Clear Remote Image Service configuration.') ipmitool.send_raw(task, cmd) except Exception as err: self.log.warning( 'Exception when clearing RIS NFS configuration: %s' % str(err)) return False return True
def _set_nfs_root_path(self, driver_info, task): try: self.log.debug('Virtual media path to "%s"' % self.remote_share) # set progress bit (hmm. seems to return error if it is already set.. So should check..) # Welp there is no way checking this. As workaround clearing it first ( does not seem to # return error even if alreay cleared). # clear progress bit cmd = '0x32 0x9f 0x01 0x01 0x00 0x00' ipmitool.send_raw(task, cmd) # set progress bit cmd = '0x32 0x9f 0x01 0x01 0x00 0x01' ipmitool.send_raw(task, cmd) time.sleep(2) cmd = '0x32 0x9f 0x01 0x01 0x01 %s' % (self.hex_convert( self.remote_share, True, 64)) ipmitool.send_raw(task, cmd) time.sleep(2) # clear progress bit cmd = '0x32 0x9f 0x01 0x01 0x00 0x00' ipmitool.send_raw(task, cmd) except Exception as err: self.log.warning('Exception when setting virtual media path: %s' % str(err)) return False
def set_boot_device(self, task): try: #BMC boot flag valid bit clearing 1f -> all bit set #P 420 of ipmi spec # https://www.intel.com/content/www/us/en/servers/ipmi/ipmi-second-gen-interface-spec-v2-rev1-1.html cmd = '0x00 0x08 0x03 0x1f' ipmitool.send_raw(task, cmd) self.log.info('Disable timeout for booting') except Exception as err: self.log.warning('Failed to disable booting options: %s', str(err)) #For time being lets do the boot order with ipmitool since, well dell doesn't provide open support #for this. manager_utils.node_set_boot_device(task, boot_devices.CDROM, persistent=False)
def set_boot_device(self, task, device, persistent=False): """Set the boot device for a node. Set the boot device to use on next reboot of the node. :param task: A task from TaskManager. :param device: The boot device, one of the supported devices listed in :mod:`ironic.common.boot_devices`. :param persistent: Boolean value. True if the boot device will persist to all future boots, False if not. Default: False. :raises: InvalidParameterValue if an invalid boot device is specified. :raises: MissingParameterValue if a required parameter is missing. :raises: IPMIFailure on an error from ipmitool. """ if device not in self.get_supported_boot_devices(task): raise exception.InvalidParameterValue(_( "Invalid boot device %s specified.") % device) uefi_mode = ( driver_utils.get_node_capability(task.node, 'boot_mode') == 'uefi') # disable 60 secs timer timeout_disable = "0x00 0x08 0x03 0x08" ipmitool.send_raw(task, timeout_disable) # note(naohirot): # Set System Boot Options : ipmi cmd '0x08', bootparam '0x05' # # $ ipmitool raw 0x00 0x08 0x05 data1 data2 0x00 0x00 0x00 # # data1 : '0xe0' persistent + uefi # '0xc0' persistent + bios # '0xa0' next only + uefi # '0x80' next only + bios # data2 : boot device defined in the dict _BOOTPARAM5_DATA2 bootparam5 = '0x00 0x08 0x05 %s %s 0x00 0x00 0x00' if persistent: data1 = '0xe0' if uefi_mode else '0xc0' else: data1 = '0xa0' if uefi_mode else '0x80' data2 = _BOOTPARAM5_DATA2[device] cmd8 = bootparam5 % (data1, data2) ipmitool.send_raw(task, cmd8)
def _execute_nm_command(task, data, command_func, parse_func=None): """Execute Intel Node Manager command via send_raw(). :param task: a TaskManager instance. :param data: a dict with data passed to vendor's method. :param command_func: a function that returns raw command bytes. :param parse_func: a function that parses returned raw bytes. :raises: IPMIFailure if Intel Node Manager is not detected on a node or if an error happens during command execution. :returns: a dict with parsed output or None if command does not return user's info. """ try: channel, address = _get_nm_address(task) except exception.IPMIFailure as e: with excutils.save_and_reraise_exception(): LOG.exception(_LE('Can not obtain Intel Node Manager address for ' 'node %(node)s: %(err)s'), {'node': task.node.uuid, 'err': six.text_type(e)}) driver_info = task.node.driver_info driver_info['ipmi_bridging'] = 'single' driver_info['ipmi_target_channel'] = channel driver_info['ipmi_target_address'] = address cmd = _command_to_string(command_func(data)) out = ipmitool.send_raw(task, cmd)[0] if parse_func: try: return parse_func(out.split()) except exception.IPMIFailure as e: with excutils.save_and_reraise_exception(): LOG.exception(_LE('Error in returned data for node %(node)s: ' '%(err)s'), {'node': task.node.uuid, 'err': six.text_type(e)})
def _get_virtual_media_device_count(self, task, devicetype): try: _num_inst = 0 # Get num of enabled devices if devicetype == 'CD': _devparam = '0x04' self.log.debug('Get virtual CD count') elif devicetype == 'FD': _devparam = '0x05' self.log.debug('Get virtual FD count') elif devicetype == 'HD': _devparam = '0x06' self.log.debug('Get virtual HD count') else: self.log.warning('Unknown device type "%s"' % devicetype) return _num_inst cmd = '0x32 0xca %s' % _devparam out, err = ipmitool.send_raw(task, cmd) _num_inst = int(out.strip()) self.log.debug('Number of enabled %s devices is %d' % (devicetype, _num_inst)) return _num_inst except Exception as err: # Drive might not be mounted to start with self.log.debug( 'Exception when getting number of enabled %s devices. error: %s' % (devicetype, str(err)))
def _execute_nm_command(task, data, command_func, parse_func=None): """Execute Intel Node Manager command via send_raw(). :param task: a TaskManager instance. :param data: a dict with data passed to vendor's method. :param command_func: a function that returns raw command bytes. :param parse_func: a function that parses returned raw bytes. :raises: IPMIFailure if Intel Node Manager is not detected on a node or if an error happens during command execution. :returns: a dict with parsed output or None if command does not return user's info. """ try: channel, address = _get_nm_address(task) except exception.IPMIFailure as e: with excutils.save_and_reraise_exception(): LOG.exception('Can not obtain Intel Node Manager address for ' 'node %(node)s: %(err)s', {'node': task.node.uuid, 'err': six.text_type(e)}) driver_info = task.node.driver_info driver_info['ipmi_bridging'] = 'single' driver_info['ipmi_target_channel'] = channel driver_info['ipmi_target_address'] = address cmd = _command_to_string(command_func(data)) out = ipmitool.send_raw(task, cmd)[0] if parse_func: try: return parse_func(out.split()) except exception.IPMIFailure as e: with excutils.save_and_reraise_exception(): LOG.exception('Error in returned data for node %(node)s: ' '%(err)s', {'node': task.node.uuid, 'err': six.text_type(e)})
def attach_virtual_cd(self, image_filename, driver_info, task): # Stop virtual device and Clear NFS configuration ipmitool.send_raw(task, '0x3c 0x0') # Set NFS Configurations # NFS server IP ipmitool.send_raw(task, '0x3c 0x01 0x00 %s 0x00' %(self.hex_convert(driver_info['provisioning_server']))) # Set NFS Mount Root path ipmitool.send_raw(task, '0x3c 0x01 0x01 %s 0x00' %(self.hex_convert(self.remote_share))) # Set Image Name ipmitool.send_raw(task, '0x3c 0x01 0x02 %s 0x00' %(self.hex_convert(image_filename))) # Start NFS Service ipmitool.send_raw(task, '0x3c 0x02 0x01') time.sleep(1) return self.check_and_wait_for_cd_mounting(image_filename, task, driver_info)
def get_disk_attachment_status(self, task): # Check NFS Service Status try: out, err = ipmitool.send_raw(task, '0x32 0xd8 0x06 0x01 0x01 0x00') _image_name = str(bytearray.fromhex(out.replace('\n', '').strip())) return 'mounted' except Exception: return 'nfserror'
def get_disk_attachment_status(self, task): # Check NFS Service Status try: cmd = RAW_CHECK_NFS_SERVICE_STATUS out, err = ipmitool.send_raw(task, cmd) _image_name = str(bytearray.fromhex(out.replace('\n', '').strip())) return 'mounted' except Exception: return 'nfserror'
def set_boot_device(self, task, device, persistent=False): """Set the boot device for a node. Set the boot device to use on next reboot of the node. :param task: A task from TaskManager. :param device: The boot device, one of the supported devices listed in :mod:`ironic.common.boot_devices`. :param persistent: Boolean value. True if the boot device will persist to all future boots, False if not. Default: False. :raises: InvalidParameterValue if an invalid boot device is specified. :raises: MissingParameterValue if a required parameter is missing. :raises: IPMIFailure on an error from ipmitool. """ if driver_utils.get_node_capability(task.node, 'boot_mode') == 'uefi': if device not in self.get_supported_boot_devices(): raise exception.InvalidParameterValue(_( "Invalid boot device %s specified.") % device) timeout_disable = "0x00 0x08 0x03 0x08" ipmitool.send_raw(task, timeout_disable) # note(naohirot): As of ipmitool version 1.8.13, # in case of chassis command, the efiboot option doesn't # get set with persistent at the same time. # $ ipmitool chassis bootdev pxe options=efiboot,persistent # In case of raw command, however, both can be set at the # same time. # $ ipmitool raw 0x00 0x08 0x05 0xe0 0x04 0x00 0x00 0x00 # data1^^ ^^data2 # ipmi cmd '0x08' : Set System Boot Options # data1 '0xe0' : persistent and uefi # data1 '0xa0' : next boot only and uefi # data1 = '0xe0' if persistent else '0xa0' bootparam5 = '0x00 0x08 0x05 %s %s 0x00 0x00 0x00' cmd08 = bootparam5 % (data1, _BOOTPARAM5_DATA2[device]) ipmitool.send_raw(task, cmd08) else: super(IRMCManagement, self).set_boot_device( task, device, persistent)
def set_boot_device(self, task, device, persistent=False): """Set the boot device for a node. Set the boot device to use on next reboot of the node. :param task: A task from TaskManager. :param device: The boot device, one of the supported devices listed in :mod:`ironic.common.boot_devices`. :param persistent: Boolean value. True if the boot device will persist to all future boots, False if not. Default: False. :raises: InvalidParameterValue if an invalid boot device is specified. :raises: MissingParameterValue if a required parameter is missing. :raises: IPMIFailure on an error from ipmitool. """ if driver_utils.get_node_capability(task.node, 'boot_mode') == 'uefi': if device not in self.get_supported_boot_devices(task): raise exception.InvalidParameterValue( _("Invalid boot device %s specified.") % device) timeout_disable = "0x00 0x08 0x03 0x08" ipmitool.send_raw(task, timeout_disable) # note(naohirot): As of ipmitool version 1.8.13, # in case of chassis command, the efiboot option doesn't # get set with persistent at the same time. # $ ipmitool chassis bootdev pxe options=efiboot,persistent # In case of raw command, however, both can be set at the # same time. # $ ipmitool raw 0x00 0x08 0x05 0xe0 0x04 0x00 0x00 0x00 # data1^^ ^^data2 # ipmi cmd '0x08' : Set System Boot Options # data1 '0xe0' : persistent and uefi # data1 '0xa0' : next boot only and uefi # data1 = '0xe0' if persistent else '0xa0' bootparam5 = '0x00 0x08 0x05 %s %s 0x00 0x00 0x00' cmd08 = bootparam5 % (data1, _BOOTPARAM5_DATA2[device]) ipmitool.send_raw(task, cmd08) else: super(IRMCManagement, self).set_boot_device(task, device, persistent)
def configure_intel_speedselect(self, task, **kwargs): config = kwargs.get('intel_speedselect_config') socket_count = kwargs.get('socket_count', 1) self._validate_input(config, socket_count) LOG.debug("Going to set Intel SST-PP configuration level %(config)s " "for node %(node)s with socket count %(socket)s", {"config": config, "node": task.node.uuid, "socket": socket_count}) iss_conf = "0x2c 0x41 0x04 0x00 0x0%s %s" for socket in range(socket_count): hexa_code = iss_conf % (socket, config) try: ipmitool.send_raw(task, hexa_code) except exception.IPMIFailure as e: msg = (_("Failed to set Intel SST-PP configuration level " "%(cfg)s on socket number %(skt)s due to " "reason %(exc)s.") % {"cfg": config, "skt": socket, "exc": e}) LOG.error(msg) raise exception.IPMIFailure(message=msg)
def get_disk_attachment_status(self, task): # Check NFS Service Status (out, err) = ipmitool.send_raw(task, '0x3c 0x03') self.log.debug("get_disk_attachment_status: NFS service status: error:%r, output:%r" %(err, out)) if out == ' 00\n': return 'mounted' elif out == ' 64\n': return 'mounting' elif out == ' 20\n': return 'nfserror' else: return 'dismounted'
def _set_virtual_media_device_count(self, task, devicetype, devicecount): # Chapter 46.2 page 181 if not 0 <= devicecount <= 4: self.log.warning('Number of devices must be in range 0 to 4') return False if devicetype == 'CD': _devparam = '0x04' self.log.debug('Setting virtual CD count to %d' % devicecount) elif devicetype == 'HD': _devparam = '0x06' self.log.debug('Setting virtual HD count to %d' % devicecount) else: self.log.warning( '_set_virtual_media_device_count: Unknown device type "%s"' % devicetype) return False try: cmd = '0x32 0xcb %s 0x%s' % (_devparam, str(devicecount)) ipmitool.send_raw(task, cmd) _conf_device_num = self._get_virtual_media_device_count( task, devicetype) _tries = 4 while _conf_device_num != devicecount and _tries > 0: self.log.debug('Virtual %s count is %d expecting %d' % (devicetype, _conf_device_num, devicecount)) time.sleep(5) _conf_device_num = self._get_virtual_media_device_count( task, devicetype) _tries = _tries - 1 except Exception as err: self.log.warning( 'Exception when setting virtual media device count, error: %s' % str(err)) return False return True
def _get_mounted_image_count(self, task): count = 0 try: cmd = '0x32 0xd8 0x00 0x01' out, err = ipmitool.send_raw(task, cmd) out = out.strip() data = out[3:5] count = int(data, 16) self.log.debug('Available image count: %d' % count) except Exception as err: self.log.debug('Exception when trying to get the image count: %s' % str(err)) return count
def _set_virtual_media_device_count(self, task, devicetype, devicecount): if not 0 <= devicecount <= 4: self.log.warning('Number of devices must be in range 0 to 4') return False if devicetype == 'CD': _devparam = VMEDIA_DEVICE_TYPE_CD self.log.debug('Setting virtual CD count to %d' % devicecount) elif devicetype == 'HD': _devparam = VMEDIA_DEVICE_TYPE_HD self.log.debug('Setting virtual HD count to %d' % devicecount) else: self.log.warning( '_set_virtual_media_device_count: Unknown device type "%s"' % devicetype) return False try: cmd = RAW_SET_VMEDIA_DEVICE_COUNT % (_devparam, hex(devicecount)) ipmitool.send_raw(task, cmd) _conf_device_num = self._get_virtual_media_device_count( task, devicetype) _tries = 40 while _conf_device_num != devicecount and _tries > 0: self.log.debug('Virtual %s count is %d expecting %d' % (devicetype, _conf_device_num, devicecount)) time.sleep(5) _conf_device_num = self._get_virtual_media_device_count( task, devicetype) _tries = _tries - 1 except Exception as err: self.log.warning( 'Exception when setting virtual media device count, error: %s' % str(err)) return False return True