def _test__do_next_deploy_step_last_step_done(self, mock_execute, mock_console, console_enabled=False, console_error=False): # Resume where last_step is the last deploy step that was executed driver_internal_info = {'deploy_step_index': 1, 'deploy_steps': self.deploy_steps} self._start_service() node = obj_utils.create_test_node( self.context, driver='fake-hardware', provision_state=states.DEPLOYWAIT, target_provision_state=states.ACTIVE, driver_internal_info=driver_internal_info, deploy_step=self.deploy_steps[1], console_enabled=console_enabled) mock_execute.return_value = None if console_error: mock_console.side_effect = exception.ConsoleError() task = task_manager.TaskManager(self.context, node.uuid) task.process_event('resume') deployments.do_next_deploy_step(task, None, self.service.conductor.id) node.refresh() # Deploying should be complete without calling additional steps self.assertEqual(states.ACTIVE, node.provision_state) self.assertEqual(states.NOSTATE, node.target_provision_state) self.assertEqual({}, node.deploy_step) self.assertNotIn('deploy_step_index', node.driver_internal_info) self.assertIsNone(node.driver_internal_info['deploy_steps']) self.assertFalse(mock_execute.called) if console_enabled: mock_console.assert_called_once_with(mock.ANY, task) else: self.assertFalse(mock_console.called)
def _stop_console(node_uuid): """Close the serial console for a node Kills the console process and deletes the PID file. :param node_uuid: the UUID of the node :raises: NoConsolePid if no console PID was found :raises: ConsoleError if unable to stop the console process """ try: console_pid = _get_console_pid(node_uuid) os.kill(console_pid, signal.SIGTERM) except OSError as exc: if exc.errno != errno.ESRCH: msg = (_("Could not stop the console for node '%(node)s'. " "Reason: %(err)s.") % { 'node': node_uuid, 'err': exc }) raise exception.ConsoleError(message=msg) else: LOG.warning( _LW("Console process for node %s is not running " "but pid file exists."), node_uuid) finally: ironic_utils.unlink_without_raise(_get_console_pid_file(node_uuid))
def test_start_console_fail_nodir(self, mock_exec): mock_exec.side_effect = exception.ConsoleError() with task_manager.acquire(self.context, self.node.uuid) as task: self.assertRaises(exception.ConsoleError, self.driver.console.start_console, task) mock_exec.assert_called_once_with(self.node.uuid, mock.ANY, mock.ANY)
def test_stop_console_fail(self, mock_stop): mock_stop.side_effect = iter([exception.ConsoleError()]) with task_manager.acquire(self.context, self.node.uuid) as task: self.assertRaises(exception.ConsoleError, self.driver.console.stop_console, task) mock_stop.assert_called_once_with(self.node.uuid)
def test_start_socat_console_fail_nopiddir(self, mock_stop, mock_dir_exists, mock_popen): mock_dir_exists.side_effect = exception.ConsoleError(message='fail') self.assertRaises(exception.ConsoleError, console_utils.start_socat_console, self.info['uuid'], self.info['port'], 'ls&') mock_stop.assert_called_once_with(self.info['uuid']) mock_dir_exists.assert_called_once_with() self.assertEqual(0, mock_popen.call_count)
def test_start_shellinabox_console_fail_nopiddir(self, mock_stop, mock_dir_exists, mock_popen): mock_dir_exists.side_effect = exception.ConsoleError(message='fail') mock_popen.return_value.poll.return_value = 0 self.assertRaises(exception.ConsoleError, console_utils.start_shellinabox_console, self.info['uuid'], self.info['port'], 'ls&') mock_stop.assert_called_once_with(self.info['uuid']) mock_dir_exists.assert_called_once_with() self.assertFalse(mock_popen.called)
def _stop_console(node_uuid): """Close the serial console for a node Kills the console process and deletes the PID file. :param node_uuid: the UUID of the node :raises: NoConsolePid if no console PID was found :raises: ConsoleError if unable to stop the console process """ try: console_pid = _get_console_pid(node_uuid) os.kill(console_pid, signal.SIGTERM) # make sure the process gets killed hard if required attempt = 0 max_attempts = CONF.console.kill_timeout // 0.2 while attempt < max_attempts: if psutil.pid_exists(console_pid): if attempt == max_attempts - 1: os.kill(console_pid, signal.SIGKILL) LOG.debug( "Waiting for the console process with PID %(pid)s " "to exit. Node: %(node)s.", { 'pid': console_pid, 'node': node_uuid }) time.sleep(0.2) attempt += 1 else: break except OSError as exc: if exc.errno != errno.ESRCH: msg = (_("Could not stop the console for node '%(node)s'. " "Reason: %(err)s.") % { 'node': node_uuid, 'err': exc }) raise exception.ConsoleError(message=msg) else: LOG.warning( "Console process for node %s is not running " "but pid file exists.", node_uuid) finally: ironic_utils.unlink_without_raise(_get_console_pid_file(node_uuid))
def stop_shellinabox_console(node_uuid): """Close the serial console for a node. :param node_uuid: the UUID of the node :raises: ConsoleError if unable to stop the console process """ try: _stop_console(node_uuid) except exception.NoConsolePid: LOG.warning(_LW("No console pid found for node %s while trying to " "stop shellinabox console."), node_uuid) except processutils.ProcessExecutionError as exc: msg = (_("Could not stop the console for node '%(node)s'. " "Reason: %(err)s.") % {'node': node_uuid, 'err': exc}) raise exception.ConsoleError(message=msg)
def _ensure_console_pid_dir_exists(): """Ensure that the console PID directory exists Checks that the directory for the console PID file exists and if not, creates it. :raises: ConsoleError if the directory doesn't exist and cannot be created """ dir = _get_console_pid_dir() if not os.path.exists(dir): try: os.makedirs(dir) except OSError as exc: msg = (_("Cannot create directory '%(path)s' for console PID file." " Reason: %(reason)s.") % {'path': dir, 'reason': exc}) LOG.error(msg) raise exception.ConsoleError(message=msg)
def stop_ics_console(node_uuid): """Close the serial console for a node (ironic console server). :param node_uuid: the UUID of the node :raises: ConsoleError if unable to disable the console service """ try: _send_signal(node_uuid, 'USR2') except exception.NoConsolePid: LOG.warning( _LW("No console pid found for node %s while trying to " "disable the console service."), node_uuid) except processutils.ProcessExecutionError as exc: msg = (_("Could not disable the console service for node " "'%(node)s'. Reason: %(err)s.") % { 'node': node_uuid, 'err': exc }) raise exception.ConsoleError(message=msg)
def stop_ics_console_log(node_uuid): """Stop console logging of a node with ironic console server. :param node_uuid: the UUID of the node :raises: ConsoleError if unable to stop the console process """ try: _stop_console(node_uuid) except exception.NoConsolePid: LOG.warning( _LW("No console pid found for node %s while trying to " "stop the console server."), node_uuid) except processutils.ProcessExecutionError as exc: msg = (_("Could not stop the console for node '%(node)s'. " "Reason: %(err)s.") % { 'node': node_uuid, 'err': exc }) raise exception.ConsoleError(message=msg)
def clear_ics_console_log(node_uuid): """Clear the content of a console log (ironic console server). :param node_uuid: the uuid for the node. :raises: ConsoleError if unable to clear the console log """ try: ironic_utils.unlink_without_raise(_get_console_log_file(node_uuid)) _send_signal(node_uuid, 'HUP') except exception.NoConsolePid: LOG.warning( _LW("No console pid found for node %s while trying to " "enable the console service."), node_uuid) except processutils.ProcessExecutionError as exc: msg = (_("Could not enable the console service for node " "'%(node)s'. Reason: %(err)s.") % { 'node': node_uuid, 'err': exc }) raise exception.ConsoleError(message=msg)