def update_firmware(self, task, firmware_images): """Updates the firmware on the node. :param task: a TaskManager instance containing the node to act on. :param firmware_images: A list of firmware images are to apply. :returns: None if it is completed. :raises: RedfishError on an error from the Sushy library. """ node = task.node LOG.debug( 'Updating firmware on node %(node_uuid)s with firmware ' '%(firmware_images)s', { 'node_uuid': node.uuid, 'firmware_images': firmware_images }) update_service = redfish_utils.get_update_service(task.node) # The cleaning infrastructure has an exclusive lock on the node, so # there is no need to get one here. self._apply_firmware_update(node, update_service, firmware_images) # set_async_step_flags calls node.save() deploy_utils.set_async_step_flags(node, reboot=True, skip_current_step=True, polling=True) manager_utils.node_power_action(task, states.REBOOT) return deploy_utils.get_async_step_return_state(task.node)
def test_get_update_service(self): redfish_utils._get_connection = mock.Mock() mock_update_service = mock.Mock() redfish_utils._get_connection.return_value = mock_update_service result = redfish_utils.get_update_service(self.node) self.assertEqual(mock_update_service, result)
def _check_node_firmware_update(self, task): """Check the progress of running firmware update on a node.""" node = task.node firmware_updates = node.driver_internal_info['firmware_updates'] current_update = firmware_updates[0] try: update_service = redfish_utils.get_update_service(node) except exception.RedfishConnectionError as e: # If the BMC firmware is being updated, the BMC will be # unavailable for some amount of time. LOG.warning( 'Unable to communicate with firmware update service ' 'on node %(node)s. Will try again on the next poll. ' 'Error: %(error)s', { 'node': node.uuid, 'error': e }) return wait_start_time = current_update.get('wait_start_time') if wait_start_time: wait_start = timeutils.parse_isotime(wait_start_time) elapsed_time = timeutils.utcnow(True) - wait_start if elapsed_time.seconds >= current_update['wait']: LOG.debug( 'Finished waiting after firmware update ' '%(firmware_image)s on node %(node)s. ' 'Elapsed time: %(seconds)s seconds', { 'firmware_image': current_update['url'], 'node': node.uuid, 'seconds': elapsed_time.seconds }) current_update.pop('wait', None) current_update.pop('wait_start_time', None) task.upgrade_lock() self._continue_firmware_updates(task, update_service, firmware_updates) else: LOG.debug( 'Continuing to wait after firmware update ' '%(firmware_image)s on node %(node)s. ' 'Elapsed time: %(seconds)s seconds', { 'firmware_image': current_update['url'], 'node': node.uuid, 'seconds': elapsed_time.seconds }) return try: task_monitor = update_service.get_task_monitor( current_update['task_monitor']) except sushy.exceptions.ResourceNotFoundError: # The BMC deleted the Task before we could query it LOG.warning( 'Firmware update completed for node %(node)s, ' 'firmware %(firmware_image)s, but success of the ' 'update is unknown. Assuming update was successful.', { 'node': node.uuid, 'firmware_image': current_update['url'] }) task.upgrade_lock() self._continue_firmware_updates(task, update_service, firmware_updates) return if not task_monitor.is_processing: # The last response does not necessarily contain a Task, # so get it sushy_task = task_monitor.get_task() # Only parse the messages if the BMC did not return parsed # messages messages = [] if not sushy_task.messages[0].message: sushy_task.parse_messages() messages = [m.message for m in sushy_task.messages] if (sushy_task.task_state == sushy.TASK_STATE_COMPLETED and sushy_task.task_status in [sushy.HEALTH_OK, sushy.HEALTH_WARNING]): LOG.info( 'Firmware update succeeded for node %(node)s, ' 'firmware %(firmware_image)s: %(messages)s', { 'node': node.uuid, 'firmware_image': current_update['url'], 'messages': ", ".join(messages) }) task.upgrade_lock() self._continue_firmware_updates(task, update_service, firmware_updates) else: error_msg = (_('Firmware update failed for node %(node)s, ' 'firmware %(firmware_image)s. ' 'Error: %(errors)s') % { 'node': node.uuid, 'firmware_image': current_update['url'], 'errors': ", ".join(messages) }) LOG.error(error_msg) task.upgrade_lock() self._clear_firmware_updates(node) manager_utils.cleaning_error_handler(task, error_msg) else: LOG.debug( 'Firmware update in progress for node %(node)s, ' 'firmware %(firmware_image)s.', { 'node': node.uuid, 'firmware_image': current_update['url'] })