def test_node_power_action_power_soft_reboot_timeout(self): """Test for soft reboot a node.""" node = obj_utils.create_test_node(self.context, uuid=uuidutils.generate_uuid(), driver='fake_soft_power', power_state=states.POWER_ON) task = task_manager.TaskManager(self.context, node.uuid) with mock.patch.object(self.driver.power, 'get_power_state') as get_power_mock: get_power_mock.return_value = states.POWER_ON conductor_utils.node_power_action(task, states.SOFT_REBOOT, timeout=2) node.refresh() get_power_mock.assert_called_once_with(mock.ANY) self.assertEqual(states.POWER_ON, node['power_state']) self.assertIsNone(node['target_power_state']) self.assertIsNone(node['last_error'])
def test_upgrade_lock( self, get_voltgt_mock, get_volconn_mock, get_portgroups_mock, get_ports_mock, build_driver_mock, reserve_mock, release_mock, node_get_mock): node_get_mock.return_value = self.node reserve_mock.return_value = self.node with task_manager.TaskManager(self.context, 'fake-node-id', shared=True, purpose='ham') as task: self.assertEqual(self.context, task.context) self.assertEqual(self.node, task.node) self.assertEqual(get_ports_mock.return_value, task.ports) self.assertEqual(get_portgroups_mock.return_value, task.portgroups) self.assertEqual(get_volconn_mock.return_value, task.volume_connectors) self.assertEqual(get_voltgt_mock.return_value, task.volume_targets) self.assertEqual(build_driver_mock.return_value, task.driver) self.assertTrue(task.shared) self.assertFalse(reserve_mock.called) task.upgrade_lock() self.assertFalse(task.shared) self.assertEqual('ham', task._purpose) # second upgrade does nothing except changes the purpose task.upgrade_lock(purpose='spam') self.assertFalse(task.shared) self.assertEqual('spam', task._purpose) build_driver_mock.assert_called_once_with(mock.ANY, driver_name=None) # make sure reserve() was called only once reserve_mock.assert_called_once_with(self.context, self.host, 'fake-node-id') release_mock.assert_called_once_with(self.context, self.host, self.node.id) node_get_mock.assert_called_once_with(self.context, 'fake-node-id') get_ports_mock.assert_called_once_with(self.context, self.node.id) get_portgroups_mock.assert_called_once_with(self.context, self.node.id) get_volconn_mock.assert_called_once_with(self.context, self.node.id) get_voltgt_mock.assert_called_once_with(self.context, self.node.id)
def test_excl_lock_with_driver( self, get_portgroups_mock, get_ports_mock, build_driver_mock, reserve_mock, release_mock, node_get_mock): reserve_mock.return_value = self.node with task_manager.TaskManager(self.context, 'fake-node-id', driver_name='fake-driver') as task: self.assertEqual(self.context, task.context) self.assertEqual(self.node, task.node) self.assertEqual(get_ports_mock.return_value, task.ports) self.assertEqual(get_portgroups_mock.return_value, task.portgroups) self.assertEqual(build_driver_mock.return_value, task.driver) self.assertFalse(task.shared) build_driver_mock.assert_called_once_with( task, driver_name='fake-driver') reserve_mock.assert_called_once_with(self.context, self.host, 'fake-node-id') get_ports_mock.assert_called_once_with(self.context, self.node.id) get_portgroups_mock.assert_called_once_with(self.context, self.node.id) release_mock.assert_called_once_with(self.context, self.host, self.node.id) self.assertFalse(node_get_mock.called)
def test__do_node_deploy_unexpected_prepare_error(self, mock_prepare, mock_deploy): self._start_service() # test when driver.deploy.prepare raises an exception mock_prepare.side_effect = RuntimeError('test') node = obj_utils.create_test_node(self.context, driver='fake-hardware', provision_state=states.DEPLOYING, target_provision_state=states.ACTIVE) task = task_manager.TaskManager(self.context, node.uuid) self.assertRaises(RuntimeError, deployments.do_node_deploy, task, self.service.conductor.id) node.refresh() self.assertEqual(states.DEPLOYFAIL, node.provision_state) # NOTE(tenbrae): failing a deploy does not clear the target state # any longer. Instead, it is cleared when the instance # is deleted. self.assertEqual(states.ACTIVE, node.target_provision_state) self.assertIsNotNone(node.last_error) self.assertTrue(mock_prepare.called) self.assertFalse(mock_deploy.called)
def test__do_next_deploy_step_async(self, mock_execute): driver_internal_info = {'deploy_step_index': None, 'deploy_steps': self.deploy_steps} self._start_service() node = obj_utils.create_test_node( self.context, driver='fake-hardware', driver_internal_info=driver_internal_info, deploy_step={}) mock_execute.return_value = states.DEPLOYWAIT expected_first_step = node.driver_internal_info['deploy_steps'][0] task = task_manager.TaskManager(self.context, node.uuid) task.process_event('deploy') deployments.do_next_deploy_step(task, 0) node.refresh() self.assertEqual(states.DEPLOYWAIT, node.provision_state) self.assertEqual(states.ACTIVE, node.target_provision_state) self.assertEqual(expected_first_step, node.deploy_step) self.assertEqual(0, node.driver_internal_info['deploy_step_index']) mock_execute.assert_called_once_with(mock.ANY, task, self.deploy_steps[0])
def test_node_power_action_failed_getting_state(self): """Test for exception when we can't get the current power state.""" node = obj_utils.create_test_node(self.context, uuid=uuidutils.generate_uuid(), driver='fake', power_state=states.POWER_ON) task = task_manager.TaskManager(self.context, node.uuid) with mock.patch.object(self.driver.power, 'get_power_state') as get_power_state_mock: get_power_state_mock.side_effect = ( exception.InvalidParameterValue('failed getting power state')) self.assertRaises(exception.InvalidParameterValue, conductor_utils.node_power_action, task, states.POWER_ON) node.refresh() get_power_state_mock.assert_called_once_with(mock.ANY) self.assertEqual(states.POWER_ON, node['power_state']) self.assertIsNone(node['target_power_state']) self.assertIsNotNone(node['last_error'])
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 test_node_power_action_already_being_processed(self): """Test node power action after aborted power action. The target_power_state is expected to be None so it isn't checked in the code. This is what happens if it is not None. (Eg, if a conductor had died during a previous power-off attempt and left the target_power_state set to states.POWER_OFF, and the user is attempting to power-off again.) """ node = obj_utils.create_test_node(self.context, uuid=uuidutils.generate_uuid(), driver='fake', power_state=states.POWER_ON, target_power_state=states.POWER_OFF) task = task_manager.TaskManager(self.context, node.uuid) conductor_utils.node_power_action(task, states.POWER_OFF) node.refresh() self.assertEqual(states.POWER_OFF, node['power_state']) self.assertEqual(states.NOSTATE, node['target_power_state']) self.assertIsNone(node['last_error'])
def test_node_power_action_power_on_notify(self, mock_notif): """Test node_power_action to power on node and send notification.""" self.config(notification_level='info') self.config(host='my-host') # Required for exception handling mock_notif.__name__ = 'NodeSetPowerStateNotification' node = obj_utils.create_test_node(self.context, uuid=uuidutils.generate_uuid(), driver='fake', power_state=states.POWER_OFF) task = task_manager.TaskManager(self.context, node.uuid) with mock.patch.object(self.driver.power, 'get_power_state') as get_power_mock: get_power_mock.return_value = states.POWER_OFF conductor_utils.node_power_action(task, states.POWER_ON) node.refresh() get_power_mock.assert_called_once_with(mock.ANY) self.assertEqual(states.POWER_ON, node.power_state) self.assertIsNone(node.target_power_state) self.assertIsNone(node.last_error) # 2 notifications should be sent: 1 .start and 1 .end self.assertEqual(2, mock_notif.call_count) self.assertEqual(2, mock_notif.return_value.emit.call_count) first_notif_args = mock_notif.call_args_list[0][1] second_notif_args = mock_notif.call_args_list[1][1] self.assertNotificationEqual(first_notif_args, 'ironic-conductor', CONF.host, 'baremetal.node.power_set.start', obj_fields.NotificationLevel.INFO) self.assertNotificationEqual(second_notif_args, 'ironic-conductor', CONF.host, 'baremetal.node.power_set.end', obj_fields.NotificationLevel.INFO)
def _check_deploy_timeouts(self, context): if not CONF.conductor.deploy_callback_timeout: return filters = {'reserved': False, 'maintenance': False} columns = ['uuid', 'driver', 'provision_state', 'provision_updated_at'] node_list = self.dbapi.get_nodeinfo_list(columns=columns, filters=filters) for (node_uuid, driver, state, update_time) in node_list: mapped_hosts = self.driver_rings[driver].get_hosts(node_uuid) if self.host not in mapped_hosts: continue if state == states.DEPLOYWAIT: limit = (timeutils.utcnow() - datetime.timedelta( seconds=CONF.conductor.deploy_callback_timeout)) if timeutils.normalize_time(update_time) <= limit: try: task = task_manager.TaskManager(context, node_uuid) except (exception.NodeLocked, exception.NodeNotFound): continue node = task.node node.provision_state = states.DEPLOYFAIL node.target_provision_state = states.NOSTATE msg = (_('Timeout reached when waiting callback for ' 'node %s') % node_uuid) node.last_error = msg LOG.error(msg) node.save(task.context) try: thread = self._spawn_worker( utils.cleanup_after_timeout, task) thread.link(lambda t: task.release_resources()) except exception.NoFreeConductorWorker: task.release_resources()
def test_start_deploy(self, mock_iwdi, mock_validate_traits, mock_validate_templates, mock_deploy_validate, mock_power_validate, mock_process_event): self._start_service() mock_iwdi.return_value = False node = obj_utils.create_test_node(self.context, driver='fake-hardware', provision_state=states.AVAILABLE, target_provision_state=states.ACTIVE) task = task_manager.TaskManager(self.context, node.uuid) deployments.start_deploy(task, self.service, configdrive=None, event='deploy') node.refresh() self.assertTrue(mock_iwdi.called) mock_power_validate.assert_called_once_with(task.driver.power, task) mock_deploy_validate.assert_called_once_with(task.driver.deploy, task) mock_validate_traits.assert_called_once_with(task.node) mock_validate_templates.assert_called_once_with( task, skip_missing=True) mock_process_event.assert_called_with( mock.ANY, 'deploy', call_args=( deployments.do_node_deploy, task, 1, None), callback=mock.ANY, err_handler=mock.ANY)
def test__do_node_deploy_configdrive_db_error(self, mock_prepare): self._start_service() node = obj_utils.create_test_node(self.context, driver='fake-hardware', provision_state=states.DEPLOYING, target_provision_state=states.ACTIVE) task = task_manager.TaskManager(self.context, node.uuid) task.node.save() expected_instance_info = dict(node.instance_info) with mock.patch.object(dbapi.IMPL, 'update_node', autospec=True) as mock_db: db_node = self.dbapi.get_node_by_uuid(node.uuid) mock_db.side_effect = [db_exception.DBDataError('DB error'), db_node, db_node, db_node] self.assertRaises(db_exception.DBDataError, deployments.do_node_deploy, task, self.service.conductor.id, configdrive=b'fake config drive') expected_instance_info.update(configdrive=b'fake config drive') expected_calls = [ mock.call(node.uuid, {'version': mock.ANY, 'instance_info': expected_instance_info, 'driver_internal_info': mock.ANY}), mock.call(node.uuid, {'version': mock.ANY, 'last_error': mock.ANY}), mock.call(node.uuid, {'version': mock.ANY, 'deploy_step': {}, 'driver_internal_info': mock.ANY}), mock.call(node.uuid, {'version': mock.ANY, 'provision_state': states.DEPLOYFAIL, 'target_provision_state': states.ACTIVE}), ] self.assertEqual(expected_calls, mock_db.mock_calls) self.assertFalse(mock_prepare.called)
def _test__do_node_deploy_ok(self, mock_store, configdrive=None, expected_configdrive=None, fast_track=False): if fast_track: self.config(fast_track=True, group='deploy') expected_configdrive = expected_configdrive or configdrive self._start_service() with mock.patch.object(fake.FakeDeploy, 'deploy', autospec=True) as mock_deploy: mock_deploy.return_value = None self.node = obj_utils.create_test_node( self.context, driver='fake-hardware', name=None, provision_state=states.DEPLOYING, target_provision_state=states.ACTIVE, driver_internal_info={'agent_url': 'url', 'agent_secret_token': 'token'}) task = task_manager.TaskManager(self.context, self.node.uuid) deployments.do_node_deploy(task, self.service.conductor.id, configdrive=configdrive) self.node.refresh() self.assertEqual(states.ACTIVE, self.node.provision_state) self.assertEqual(states.NOSTATE, self.node.target_provision_state) self.assertIsNone(self.node.last_error) mock_deploy.assert_called_once_with(mock.ANY, mock.ANY) if configdrive: mock_store.assert_called_once_with(task.node, expected_configdrive) else: self.assertFalse(mock_store.called) self.assertEqual( fast_track, bool(task.node.driver_internal_info.get('agent_url'))) self.assertEqual( fast_track, bool(task.node.driver_internal_info.get('agent_secret_token'))) self.assertEqual(self.service.conductor.id, task.node.conductor_affinity)
def test__do_next_deploy_step_fast_track(self, mock_execute): self.config(fast_track=True, group='deploy') # Run all steps from start to finish (all synchronous) driver_internal_info = { 'deploy_step_index': None, 'deploy_steps': self.deploy_steps, 'agent_url': 'url', 'agent_secret_token': 'token' } self._start_service() node = obj_utils.create_test_node( self.context, driver='fake-hardware', driver_internal_info=driver_internal_info, deploy_step={}) mock_execute.return_value = None task = task_manager.TaskManager(self.context, node.uuid) task.process_event('deploy') deployments.do_next_deploy_step(task, 1, self.service.conductor.id) # Deploying should be complete node.refresh() 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']) mock_execute.assert_has_calls = [ mock.call(self.deploy_steps[0]), mock.call(self.deploy_steps[1]) ] self.assertEqual('url', node.driver_internal_info['agent_url']) self.assertEqual('token', node.driver_internal_info['agent_secret_token'])
def test_node_power_action_invalid_driver_info(self): """Test if an exception is thrown when the driver validation fails. """ ndict = utils.get_test_node(uuid=cmn_utils.generate_uuid(), driver='fake', power_state=states.POWER_ON) node = self.dbapi.create_node(ndict) task = task_manager.TaskManager(self.context, node.uuid) with mock.patch.object(self.driver.power, 'validate') \ as validate_mock: validate_mock.side_effect = exception.InvalidParameterValue( 'wrong power driver info') self.assertRaises(exception.InvalidParameterValue, conductor_utils.node_power_action, task, task.node, states.POWER_ON) node.refresh(self.context) validate_mock.assert_called_once_with(mock.ANY, mock.ANY) self.assertEqual(states.POWER_ON, node['power_state']) self.assertIsNone(node['target_power_state']) self.assertIsNotNone(node['last_error'])
def test_task_manager_gets_node(self): node_uuid = self.uuids[0] task = task_manager.TaskManager(self.context, node_uuid) self.assertEqual(node_uuid, task.node.uuid)
def _test_it(): with task_manager.TaskManager(self.context, 'node-id') as task: task.set_spawn_error_hook(on_error_handler, 'fake-argument') task.spawn_after(spawn_mock, 1, 2, foo='bar', cat='meow') task.release_resources = task_release_mock
def _test_it(): with task_manager.TaskManager(self.context, 'node-id') as task: task.spawn_after(spawn_mock, 1, 2, foo='bar', cat='meow') task._thread_release_resources = thr_release_mock task.release_resources = task_release_mock
def _test_it(): with task_manager.TaskManager(self.context, 'node-id') as task: task.spawn_after(spawn_mock, 1, 2, foo='bar', cat='meow') task.release_resources = task_release_mock raise exception.IronicException('foo')
def test_excl_nested_acquire(self, get_voltgt_mock, get_volconn_mock, get_portgroups_mock, get_ports_mock, build_driver_mock, reserve_mock, release_mock, node_get_mock): node2 = obj_utils.create_test_node(self.context, uuid=uuidutils.generate_uuid(), driver='fake-hardware') reserve_mock.return_value = self.node get_ports_mock.return_value = mock.sentinel.ports1 get_portgroups_mock.return_value = mock.sentinel.portgroups1 get_volconn_mock.return_value = mock.sentinel.volconn1 get_voltgt_mock.return_value = mock.sentinel.voltgt1 build_driver_mock.return_value = mock.sentinel.driver1 with task_manager.TaskManager(self.context, 'node-id1') as task: reserve_mock.return_value = node2 get_ports_mock.return_value = mock.sentinel.ports2 get_portgroups_mock.return_value = mock.sentinel.portgroups2 get_volconn_mock.return_value = mock.sentinel.volconn2 get_voltgt_mock.return_value = mock.sentinel.voltgt2 build_driver_mock.return_value = mock.sentinel.driver2 with task_manager.TaskManager(self.context, 'node-id2') as task2: self.assertEqual(self.context, task.context) self.assertEqual(self.node, task.node) self.assertEqual(mock.sentinel.ports1, task.ports) self.assertEqual(mock.sentinel.portgroups1, task.portgroups) self.assertEqual(mock.sentinel.volconn1, task.volume_connectors) self.assertEqual(mock.sentinel.voltgt1, task.volume_targets) self.assertEqual(mock.sentinel.driver1, task.driver) self.assertFalse(task.shared) self.assertEqual(self.context, task2.context) self.assertEqual(node2, task2.node) self.assertEqual(mock.sentinel.ports2, task2.ports) self.assertEqual(mock.sentinel.portgroups2, task2.portgroups) self.assertEqual(mock.sentinel.volconn2, task2.volume_connectors) self.assertEqual(mock.sentinel.voltgt2, task2.volume_targets) self.assertEqual(mock.sentinel.driver2, task2.driver) self.assertFalse(task2.shared) self.assertEqual( [mock.call(task), mock.call(task2)], build_driver_mock.call_args_list) self.assertEqual([ mock.call(self.context, 'node-id1'), mock.call(self.context, 'node-id2') ], node_get_mock.call_args_list) self.assertEqual([ mock.call(self.context, self.host, 'node-id1'), mock.call(self.context, self.host, 'node-id2') ], reserve_mock.call_args_list) self.assertEqual([ mock.call(self.context, self.node.id), mock.call(self.context, node2.id) ], get_ports_mock.call_args_list) # release should be in reverse order self.assertEqual([ mock.call(self.context, self.host, node2.id), mock.call(self.context, self.host, self.node.id) ], release_mock.call_args_list)