def set_boot_mode(self, task, mode): """Set the boot mode for a node. Set the boot mode to use on next reboot of the node. :param task: A task from TaskManager. :param mode: The boot mode, one of :mod:`ironic.common.boot_modes`. :raises: InvalidParameterValue on malformed parameter(s) :raises: MissingParameterValue on missing parameter(s) :raises: IBMCConnectionError when it fails to connect to iBMC :raises: IBMCError on an error from the iBMC """ self.validate(task) system = utils.get_system(task.node) boot_device = system.boot.get('target') if not boot_device: error_msg = (_('Cannot change boot mode on node %(node)s ' 'because its boot device is not set.') % { 'node': task.node.uuid }) LOG.error(error_msg) raise exception.IBMCError(error_msg) boot_override = system.boot.get('enabled') if not boot_override: error_msg = (_('Cannot change boot mode on node %(node)s ' 'because its boot source override is not set.') % { 'node': task.node.uuid }) LOG.error(error_msg) raise exception.IBMCError(error_msg) try: system.set_system_boot_source( boot_device, enabled=boot_override, mode=mappings.BOOT_MODE_MAP_REV[mode]) except requests.exceptions.RequestException as e: error_msg = (_('Setting boot mode to %(mode)s ' 'failed for node %(node)s. Error : %(error)s') % { 'node': task.node.uuid, 'mode': mode, 'error': e }) LOG.error(error_msg) raise exception.IBMCError(error=error_msg)
def wrapper(*args, **kwargs): # NOTE(dtantsur): this code could be written simpler, but then unit # testing decorated functions is pretty hard, as we usually pass a # Mock object instead of TaskManager there. if len(args) > 1: is_task_mgr = isinstance(args[1], task_manager.TaskManager) task = args[1] if is_task_mgr else args[0] else: task = args[0] node = task.node try: return f(*args, **kwargs) except ibmc_error.IBMCConnectionError as e: error = (_('Failed to connect to iBMC for node %(node)s, ' 'Error: %(error)s') % { 'node': node.uuid, 'error': e }) LOG.error(error) raise exception.IBMCConnectionError(node=node.uuid, error=error) except ibmc_error.IBMCClientError as e: error = (_('Failed to %(action)s for node %(node)s, ' 'Error %(error)s') % { 'node': node.uuid, 'action': action, 'error': e }) LOG.error(error) raise exception.IBMCError(node=node.uuid, error=error)
def set_boot_device(self, task, device, persistent=False): """Set the boot device for a node. :param task: A task from TaskManager. :param device: The boot device, one of :mod:`ironic.common.boot_device`. :param persistent: Boolean value. True if the boot device will persist to all future boots, False if not. Default: False. :raises: InvalidParameterValue on malformed parameter(s) :raises: MissingParameterValue on missing parameter(s) :raises: IBMCConnectionError when it fails to connect to iBMC :raises: IBMCError on an error from the iBMC """ self.validate(task) system = utils.get_system(task.node) try: system.set_system_boot_source( mappings.BOOT_DEVICE_MAP_REV[device], enabled=mappings.BOOT_DEVICE_PERSISTENT_MAP_REV[persistent]) except requests.exceptions.RequestException as e: error_msg = (_('IBMC set boot device failed for node ' '%(node)s. Error: %(error)s') % { 'node': task.node.uuid, 'error': e }) LOG.error(error_msg) raise exception.IBMCError(error=error_msg)
def set_power_state(self, task, power_state, timeout=None): """Set the power state of the task's node. :param task: A TaskManager instance containing the node to act on. :param power_state: Any power state from :mod:`ironic.common.states`. :param timeout: Time to wait for the node to reach the requested state. :raises: InvalidParameterValue on malformed parameter(s) :raises: MissingParameterValue if a required parameter is missing. :raises: IBMCConnectionError when it fails to connect to iBMC :raises: IBMCError on an error from the iBMC """ self.validate(task) system = utils.get_system(task.node) try: system.reset_system( mappings.SET_POWER_STATE_MAP_REV.get(power_state)) except requests.exceptions.RequestException as e: error_msg = (_('IBMC set power state failed for node ' '%(node)s. Error: %(error)s') % { 'node': task.node.uuid, 'error': e }) LOG.error(error_msg) raise exception.IBMCError(error=error_msg) target_state = TARGET_STATE_MAP.get(power_state, power_state) cond_utils.node_wait_for_power_state(task, target_state, timeout=timeout)
def _load_from_json(json, path, ignore_missing=False): """Load field from json. :param json: JSON object. :param path: Field path, string or string array. For example 'Systems' will get field value from json.get('Systems'), ['Systems', 'data'] will get field value from json.get('Systems').get('data') :param ignore_missing: Ignore missing attribute :raises IBMCError: When no such attribute exists. :returns: Field value """ if isinstance(path, six.string_types): path = [path] name = path[-1] body = json for path_item in path[:-1]: body = body.get(path_item) or {} if name not in body: if not ignore_missing: err_msg = _('Missing attribute %s, json: %s' % ('/'.join(path), json)) raise exception.IBMCError(error=err_msg) else: return None return body[name]
def reboot(self, task, timeout=None): """Perform a hard reboot of the task's node. :param task: A TaskManager instance containing the node to act on. :param timeout: Time to wait for the node to become powered on. :raises: InvalidParameterValue on malformed parameter(s) :raises: MissingParameterValue if a required parameter is missing. :raises: IBMCConnectionError when it fails to connect to iBMC :raises: IBMCError on an error from the iBMC """ self.validate(task) system = utils.get_system(task.node) current_power_state = (mappings.GET_POWER_STATE_MAP.get( system.power_state)) try: if current_power_state == states.POWER_ON: system.reset_system( mappings.SET_POWER_STATE_MAP_REV.get(states.REBOOT)) else: system.reset_system( mappings.SET_POWER_STATE_MAP_REV.get(states.POWER_ON)) except requests.exceptions.RequestException as e: error_msg = (_('IBMC reboot failed for node %(node)s. ' 'Error: %(error)s') % { 'node': task.node.uuid, 'error': e }) LOG.error(error_msg) raise exception.IBMCError(error=error_msg) cond_utils.node_wait_for_power_state(task, states.POWER_ON, timeout=timeout)
def __init__(self, conn, id, address, systems_path): """A class representing iBMC System object. :param conn: IBMCConnector :param id: IBMC System identifier. If None, use first system. :param address: IBMC address :param systems_path: IBMC Systems path """ self._conn = conn self._address = address self._systems_path = systems_path self._real_id = None self._json = None self._boot = None self._reset_path = None self._power_state = None self._bios_path = None if not id: r = self._conn.make_req('GET', self._systems_url()) systems = _load_from_json(r.json(), 'Members') if not systems: raise exception.IBMCError(error='No system available') self._real_id = _load_from_json(systems[0], '@odata.id') else: self._real_id = id self.get()
def _get_resource_etag(self, url): r = self.make_req('GET', url) etag = r.headers.get('Etag') or r.headers.get('etag') if not etag: msg = 'Can not get resource[%s] etag' % url raise exception.IBMCError(msg) return etag
def _get_system(): try: with SessionCache(driver_info) as conn: return conn.get_system(system_id) except requests.exceptions.RequestException as e: if (e.response is not None and e.response.status_code and e.response.status_code == 404): # If it is a resource not found error, then log about # the error, and re-raise a not-to-retry error LOG.error( 'The iBMC System "%(system)s" was not found for ' 'node %(node)s. Error %(error)s', { 'system': system_id, 'node': node.uuid, 'error': e }) raise exception.IBMCError(error=e) else: # Every other exceptions raise from requests lib, # we need to retry the request LOG.warning( 'For node %(node)s, got a connection error from ' 'iBMC at address "%(address)s" when fetching ' 'System "%(system)s". Error: %(error)s', { 'system': system_id, 'address': address, 'node': node.uuid, 'error': e }) raise exception.IBMCConnectionError(node=node.uuid, error=e)
def set_boot_mode(self, task, mode): """Set the boot mode for a node. Set the boot mode to use on next reboot of the node. :param task: A task from TaskManager. :param mode: The boot mode, one of :mod:`ironic.common.boot_modes`. :raises: InvalidParameterValue on malformed parameter(s) :raises: MissingParameterValue on missing parameter(s) :raises: IBMCConnectionError when it fails to connect to iBMC :raises: IBMCError when iBMC responses an error information """ ibmc = utils.parse_driver_info(task.node) with ibmc_client.connect(**ibmc) as conn: system = conn.system.get() boot_source_override = system.boot_source_override boot_device = boot_source_override.target boot_override = boot_source_override.enabled # Copied from redfish driver # TODO(Qianbiao.NG) what if boot device is "NONE"? if not boot_device: error_msg = (_('Cannot change boot mode on node %(node)s ' 'because its boot device is not set.') % { 'node': task.node.uuid }) LOG.error(error_msg) raise exception.IBMCError(error_msg) # TODO(Qianbiao.NG) what if boot override is "disabled"? if not boot_override: i18n = _('Cannot change boot mode on node %(node)s ' 'because its boot source override is not set.') error_msg = i18n % {'node': task.node.uuid} LOG.error(error_msg) raise exception.IBMCError(error_msg) boot_mode = mappings.SET_BOOT_MODE_MAP[mode] conn.system.set_boot_source(boot_device, enabled=boot_override, mode=boot_mode)
def _make_req(self, method, url, json=None, headers=None): # If method is PATCH or PUT, get resource's etag first if method.lower() in ['patch', 'put']: etag = self._get_resource_etag(url) headers = headers or {} headers.update({'If-Match': etag}) LOG.info('IBMC request: %(method)s, %(url)s', { 'method': method, 'url': url, }) req = requests.Request(method, url, json=json, headers=headers) prepped = self._session.prepare_request(req) try: r = self._session.send(prepped, timeout=self._DEFAULT_TIMEOUT) r.raise_for_status() return r except requests.exceptions.RequestException as e: if (e.response is not None and e.response.status_code and e.response.status_code >= 500): # If it's server error, then log about the error, # and re-raise a not-to-retry error msg = ('IBMC server error: method: [%s], url: [%s], %s' % (method, url, e.response.text)) raise exception.IBMCError(error=msg) else: try: ext_info = _load_from_json( e.response.json(), ['error', '@Message.ExtendedInfo'], ignore_missing=True) reason = (ext_info[0].get('Message') if len(ext_info) else ext_info) except Exception: reason = '' # Simply log about the exception, and re-raise to the # outer try-catch, let it determine whether to retry # the request msg = ('IBMC request error: method: [%s], url: [%s], ' 'body: %s, headers: %s, reason: %s' % (method, url, json, headers, reason)) LOG.error(msg) raise e
def boot_up_seq(self, task, **kwargs): """List boot type order of the node. :param task: A TaskManager instance containing the node to act on. :param kwargs: Not used. :raises: InvalidParameterValue if kwargs does not contain 'method'. :raises: MissingParameterValue :returns: A dictionary, containing node boot up sequence, in ascending order. """ self.validate(task) system = utils.get_system(task.node) try: boot_seq = system.boot_sequence return {'boot_up_sequence': boot_seq} except requests.exceptions.RequestException as e: error_msg = (_('IBMC get bootup sequence failed ' 'for node %(node)s. Error: %(error)s') % {'node': task.node.uuid, 'error': e}) LOG.error(error_msg) raise exception.IBMCError(error=error_msg)
def inject_nmi(self, task): """Inject NMI, Non Maskable Interrupt. Inject NMI (Non Maskable Interrupt) for a node immediately. :param task: A TaskManager instance containing the node to act on. :raises: InvalidParameterValue on malformed parameter(s) :raises: MissingParameterValue on missing parameter(s) :raises: IBMCConnectionError when it fails to connect to iBMC :raises: IBMCError on an error from the Sushy library """ self.validate(task) system = utils.get_system(task.node) try: system.reset_system(constants.RESET_NMI) except requests.exceptions.RequestException as e: error_msg = (_('IBMC inject NMI failed for node %(node)s. ' 'Error: %(error)s') % { 'node': task.node.uuid, 'error': e }) LOG.error(error_msg) raise exception.IBMCError(error=error_msg)