diff --git a/tripleoclient/tests/fakes.py b/tripleoclient/tests/fakes.py index f1159b4b6..a3dafe621 100644 --- a/tripleoclient/tests/fakes.py +++ b/tripleoclient/tests/fakes.py @@ -84,24 +84,26 @@ class FakeFile(FakeHandle): self.contents = None -class FakeWebSocket(FakeHandle): - - def wait_for_messages(self, timeout=None): - yield { - 'execution_id': 'IDID', - 'status': 'SUCCESS', - } - - class FakeClientWrapper(object): def __init__(self): - self.ws = FakeWebSocket() - self.object_store = FakeObjectClient() self._instance = mock.Mock() + self.object_store = FakeObjectClient() + self._mock_websocket = mock.Mock() + self._mock_websocket.__enter__ = mock.Mock( + return_value=self._mock_websocket) + # Return False to avoid silencing exceptions + self._mock_websocket.__exit__ = mock.Mock(return_value=False) + self._mock_websocket.wait_for_messages = mock.Mock( + return_value=iter([{ + "status": "SUCCESS", + "message": "Success", + "execution_id": "IDID" + }]) + ) def messaging_websocket(self): - return self.ws + return self._mock_websocket class FakeRunnerConfig(object): @@ -169,7 +171,8 @@ class FakePlaybookExecution(utils.TestCommand): self.app.client_manager.image = mock.Mock() self.app.client_manager.network = mock.Mock() tc = self.app.client_manager.tripleoclient = FakeClientWrapper() - self.app.client_manager.workflow_engine = mock.Mock() + self.tripleoclient = mock.Mock() + self.workflow = self.app.client_manager.workflow_engine = mock.Mock() stack = self.app.client_manager.orchestration = mock.Mock() stack.stacks.get.return_value = FakeStackObject tc.create_mistral_context = plugin.ClientWrapper( @@ -177,10 +180,9 @@ class FakePlaybookExecution(utils.TestCommand): ).create_mistral_context # NOTE(cloudnull): When mistral is gone this should be removed. - workflow = execution = mock.Mock() - execution.id = "IDID" - workflow.executions.create.return_value = execution - self.app.client_manager.workflow_engine = workflow + self.execution = mock.Mock() + self.execution.id = "IDID" + self.workflow.executions.create.return_value = self.execution config_mock = mock.patch( 'tripleo_common.actions.config.GetOvercloudConfig', @@ -207,6 +209,14 @@ class FakePlaybookExecution(utils.TestCommand): get_key.return_value = 'keyfile-path' self.addCleanup(get_key.stop) + self.register_or_update = mock.patch( + 'tripleo_common.actions.baremetal.RegisterOrUpdateNodes.run', + autospec=True, + return_value=[mock.Mock(uuid='MOCK_NODE_UUID')] + ) + self.register_or_update.start() + self.addCleanup(self.register_or_update.stop) + if ansible_mock: get_stack = mock.patch('tripleoclient.utils.get_stack') get_stack.start() diff --git a/tripleoclient/tests/v1/overcloud_node/fakes.py b/tripleoclient/tests/v1/overcloud_node/fakes.py index 030ab89d3..21baff532 100644 --- a/tripleoclient/tests/v1/overcloud_node/fakes.py +++ b/tripleoclient/tests/v1/overcloud_node/fakes.py @@ -13,46 +13,16 @@ # under the License. # -import mock - -from osc_lib.tests import utils - -from tripleoclient import plugin from tripleoclient.tests import fakes -class FakeClientWrapper(object): - - def __init__(self): - self._instance = mock.Mock() - self._mock_websocket = mock.Mock() - self._mock_websocket.__enter__ = mock.Mock( - return_value=self._mock_websocket) - # Return False to avoid silencing exceptions - self._mock_websocket.__exit__ = mock.Mock(return_value=False) - - def messaging_websocket(self): - return self._mock_websocket - - -class TestDeleteNode(utils.TestCommand): +class TestDeleteNode(fakes.FakePlaybookExecution): def setUp(self): super(TestDeleteNode, self).setUp() - self.app.client_manager.auth_ref = mock.Mock(auth_token="TOKEN") - self.app.client_manager.orchestration = mock.Mock() - self.app.client_manager.tripleoclient = FakeClientWrapper() - -class TestOvercloudNode(utils.TestCommand): +class TestOvercloudNode(fakes.FakePlaybookExecution): def setUp(self): super(TestOvercloudNode, self).setUp() - - self.app.client_manager.baremetal = mock.Mock() - self.app.client_manager.workflow_engine = mock.Mock() - tc = self.app.client_manager.tripleoclient = FakeClientWrapper() - tc.create_mistral_context = plugin.ClientWrapper( - instance=fakes.FakeInstanceData - ).create_mistral_context diff --git a/tripleoclient/tests/v1/overcloud_node/test_overcloud_node.py b/tripleoclient/tests/v1/overcloud_node/test_overcloud_node.py index 79511e04f..8bd82e5a1 100644 --- a/tripleoclient/tests/v1/overcloud_node/test_overcloud_node.py +++ b/tripleoclient/tests/v1/overcloud_node/test_overcloud_node.py @@ -15,21 +15,23 @@ import collections import copy +import fixtures import json import mock import os import tempfile -import fixtures from osc_lib import exceptions as oscexc from osc_lib.tests import utils as test_utils import yaml +from tripleoclient import constants from tripleoclient import exceptions from tripleoclient import plugin from tripleoclient.tests import fakes as ooofakes from tripleoclient.tests.v1.overcloud_node import fakes from tripleoclient.v1 import overcloud_node +from tripleoclient.v2 import overcloud_node as overcloud_node_v2 class TestDeleteNode(fakes.TestDeleteNode): @@ -45,31 +47,7 @@ class TestDeleteNode(fakes.TestDeleteNode): self.websocket = mock.Mock() self.websocket.__enter__ = lambda s: self.websocket self.websocket.__exit__ = lambda s, *exc: None - self.tripleoclient = mock.Mock() self.tripleoclient.messaging_websocket.return_value = self.websocket - tc = self.app.client_manager.tripleoclient = self.tripleoclient - tc.create_mistral_context = plugin.ClientWrapper( - instance=ooofakes.FakeInstanceData - ).create_mistral_context - self.gcn = mock.patch( - 'tripleo_common.actions.config.DownloadConfigAction', - autospec=True - ) - self.gcn.start() - self.addCleanup(self.gcn.stop) - self.ansible = mock.patch( - 'tripleo_common.actions.ansible.AnsibleGenerateInventoryAction', - autospec=True - ) - self.ansible.start() - self.addCleanup(self.ansible.stop) - config_mock = mock.patch( - 'tripleo_common.actions.config.GetOvercloudConfig', - autospec=True - ) - config_mock.start() - self.addCleanup(config_mock.stop) - self.workflow = self.app.client_manager.workflow_engine self.stack_name = self.app.client_manager.orchestration.stacks.get stack = self.stack_name.return_value = mock.Mock( @@ -95,6 +73,7 @@ class TestDeleteNode(fakes.TestDeleteNode): wait_stack.start() wait_stack.return_value = None self.addCleanup(wait_stack.stop) + self.app.client_manager.compute.servers.get.return_value = None # TODO(someone): This test does not pass with autospec=True, it should # probably be fixed so that it can pass with that. @@ -125,24 +104,24 @@ class TestDeleteNode(fakes.TestDeleteNode): self.cmd.take_action, parsed_args) - def test_node_wrong_stack(self): + @mock.patch('tripleoclient.utils.run_ansible_playbook', + autospec=True, + side_effect=exceptions.InvalidConfiguration) + def test_node_wrong_stack(self, mock_playbook): argslist = ['instance1', '--templates', '--stack', 'overcast', '--yes'] verifylist = [ ('stack', 'overcast'), ('nodes', ['instance1', ]) ] - parsed_args = self.check_parser(self.cmd, argslist, verifylist) - self.stack_name.return_value = None + parsed_args = self.check_parser(self.cmd, argslist, verifylist) + self.assertRaises(exceptions.InvalidConfiguration, self.cmd.take_action, parsed_args) - # Verify - self.workflow.executions.create.assert_not_called() - @mock.patch('tripleoclient.utils.run_ansible_playbook', autospec=True) def test_node_delete_without_stack(self, mock_playbook): @@ -461,116 +440,6 @@ class TestProvideNode(fakes.TestOvercloudNode): self.cmd, argslist, verifylist) -class TestIntrospectNode(fakes.TestOvercloudNode): - - def setUp(self): - super(TestIntrospectNode, self).setUp() - - self.workflow = self.app.client_manager.workflow_engine - execution = mock.Mock() - execution.id = "IDID" - self.workflow.executions.create.return_value = execution - client = self.app.client_manager.tripleoclient - self.websocket = client.messaging_websocket() - - # Get the command object to test - self.cmd = overcloud_node.IntrospectNode(self.app, None) - - def _check_introspect_all_manageable(self, parsed_args, provide=False): - self.websocket.wait_for_messages.return_value = iter([{ - "status": "SUCCESS", - "message": "Success", - "introspected_nodes": {}, - "execution_id": "IDID" - }] * 2) - - self.cmd.take_action(parsed_args) - - call_list = [mock.call( - 'tripleo.baremetal.v1.introspect_manageable_nodes', - workflow_input={'run_validations': False, 'concurrency': 20} - )] - - if provide: - call_list.append(mock.call( - 'tripleo.baremetal.v1.provide_manageable_nodes', - workflow_input={} - )) - - self.workflow.executions.create.assert_has_calls(call_list) - self.assertEqual(self.workflow.executions.create.call_count, - 2 if provide else 1) - - def _check_introspect_nodes(self, parsed_args, nodes, provide=False): - self.websocket.wait_for_messages.return_value = [{ - "status": "SUCCESS", - "message": "Success", - "execution_id": "IDID", - }] - - self.cmd.take_action(parsed_args) - - call_list = [mock.call( - 'tripleo.baremetal.v1.introspect', workflow_input={ - 'node_uuids': nodes, - 'run_validations': False, - 'concurrency': 20} - )] - - if provide: - call_list.append(mock.call( - 'tripleo.baremetal.v1.provide', workflow_input={ - 'node_uuids': nodes} - )) - - self.workflow.executions.create.assert_has_calls(call_list) - self.assertEqual(self.workflow.executions.create.call_count, - 2 if provide else 1) - - def test_introspect_all_manageable_nodes_without_provide(self): - parsed_args = self.check_parser(self.cmd, - ['--all-manageable'], - [('all_manageable', True)]) - self._check_introspect_all_manageable(parsed_args, provide=False) - - def test_introspect_all_manageable_nodes_with_provide(self): - parsed_args = self.check_parser(self.cmd, - ['--all-manageable', '--provide'], - [('all_manageable', True), - ('provide', True)]) - self._check_introspect_all_manageable(parsed_args, provide=True) - - def test_introspect_nodes_without_provide(self): - nodes = ['node_uuid1', 'node_uuid2'] - parsed_args = self.check_parser(self.cmd, - nodes, - [('node_uuids', nodes)]) - self._check_introspect_nodes(parsed_args, nodes, provide=False) - - def test_introspect_nodes_with_provide(self): - nodes = ['node_uuid1', 'node_uuid2'] - argslist = nodes + ['--provide'] - - parsed_args = self.check_parser(self.cmd, - argslist, - [('node_uuids', nodes), - ('provide', True)]) - self._check_introspect_nodes(parsed_args, nodes, provide=True) - - def test_introspect_no_node_or_flag_specified(self): - self.assertRaises(test_utils.ParserException, - self.check_parser, - self.cmd, [], []) - - def test_introspect_uuids_and_all_both_specified(self): - argslist = ['node_id1', 'node_id2', '--all-manageable'] - verifylist = [('node_uuids', ['node_id1', 'node_id2']), - ('all_manageable', True)] - self.assertRaises(test_utils.ParserException, - self.check_parser, - self.cmd, argslist, verifylist) - - class TestCleanNode(fakes.TestOvercloudNode): def setUp(self): @@ -666,156 +535,6 @@ class TestCleanNode(fakes.TestOvercloudNode): self._check_clean_nodes(parsed_args, nodes, provide=True) -class TestImportNode(fakes.TestOvercloudNode): - - def setUp(self): - super(TestImportNode, self).setUp() - - self.nodes_list = [{ - "pm_user": "stack", - "pm_addr": "192.168.122.1", - "pm_password": "KEY1", - "pm_type": "pxe_ssh", - "mac": [ - "00:0b:d0:69:7e:59" - ], - }, { - "pm_user": "stack", - "pm_addr": "192.168.122.2", - "pm_password": "KEY2", - "pm_type": "pxe_ssh", - "mac": [ - "00:0b:d0:69:7e:58" - ] - }] - self.json_file = tempfile.NamedTemporaryFile( - mode='w', delete=False, suffix='.json') - json.dump(self.nodes_list, self.json_file) - self.json_file.close() - self.addCleanup(os.unlink, self.json_file.name) - - self.workflow = self.app.client_manager.workflow_engine - execution = mock.Mock() - execution.id = "IDID" - self.workflow.executions.create.return_value = execution - client = self.app.client_manager.tripleoclient - self.websocket = client.messaging_websocket() - - # Get the command object to test - self.cmd = overcloud_node.ImportNode(self.app, None) - - image = collections.namedtuple('image', ['id', 'name']) - self.app.client_manager.image = mock.Mock() - self.app.client_manager.image.images.list.return_value = [ - image(id=3, name='overcloud-full'), - ] - - self.http_boot = '/var/lib/ironic/httpboot' - - self.useFixture(fixtures.MockPatch( - 'os.path.exists', autospec=True, - side_effect=lambda path: path in [os.path.join(self.http_boot, i) - for i in ('agent.kernel', - 'agent.ramdisk')])) - - def _check_workflow_call(self, parsed_args, introspect=False, - provide=False, local=None, no_deploy_image=False): - self.websocket.wait_for_messages.return_value = [{ - "status": "SUCCESS", - "message": "Success", - "registered_nodes": [{ - "uuid": "MOCK_NODE_UUID" - }], - "execution_id": "IDID" - }] - - self.cmd.take_action(parsed_args) - - nodes_list = copy.deepcopy(self.nodes_list) - if not no_deploy_image: - for node in nodes_list: - node.update({ - 'kernel_id': 'file://%s/agent.kernel' % self.http_boot, - 'ramdisk_id': 'file://%s/agent.ramdisk' % self.http_boot, - }) - - call_count = 1 - call_list = [mock.call( - 'tripleo.baremetal.v1.register_or_update', workflow_input={ - 'nodes_json': nodes_list, - 'instance_boot_option': ('local' if local is True else - 'netboot' if local is False else None) - } - )] - - if introspect: - call_count += 1 - call_list.append(mock.call( - 'tripleo.baremetal.v1.introspect', workflow_input={ - 'node_uuids': ['MOCK_NODE_UUID'], - 'run_validations': False, - 'concurrency': 20} - )) - - if provide: - call_count += 1 - call_list.append(mock.call( - 'tripleo.baremetal.v1.provide', workflow_input={ - 'node_uuids': ['MOCK_NODE_UUID'] - } - )) - - self.workflow.executions.create.assert_has_calls(call_list) - self.assertEqual(self.workflow.executions.create.call_count, - call_count) - - def test_import_only(self): - argslist = [self.json_file.name] - verifylist = [('introspect', False), - ('provide', False)] - - parsed_args = self.check_parser(self.cmd, argslist, verifylist) - self._check_workflow_call(parsed_args) - - def test_import_and_introspect(self): - argslist = [self.json_file.name, '--introspect'] - verifylist = [('introspect', True), - ('provide', False)] - - parsed_args = self.check_parser(self.cmd, argslist, verifylist) - self._check_workflow_call(parsed_args, introspect=True) - - def test_import_and_provide(self): - argslist = [self.json_file.name, '--provide'] - verifylist = [('introspect', False), - ('provide', True)] - - parsed_args = self.check_parser(self.cmd, argslist, verifylist) - self._check_workflow_call(parsed_args, provide=True) - - def test_import_and_introspect_and_provide(self): - argslist = [self.json_file.name, '--introspect', '--provide'] - verifylist = [('introspect', True), - ('provide', True)] - - parsed_args = self.check_parser(self.cmd, argslist, verifylist) - self._check_workflow_call(parsed_args, introspect=True, provide=True) - - def test_import_with_netboot(self): - arglist = [self.json_file.name, '--instance-boot-option', 'netboot'] - verifylist = [('instance_boot_option', 'netboot')] - - parsed_args = self.check_parser(self.cmd, arglist, verifylist) - self._check_workflow_call(parsed_args, local=False) - - def test_import_with_no_deployed_image(self): - arglist = [self.json_file.name, '--no-deploy-image'] - verifylist = [('no_deploy_image', True)] - - parsed_args = self.check_parser(self.cmd, arglist, verifylist) - self._check_workflow_call(parsed_args, no_deploy_image=True) - - class TestImportNodeMultiArch(fakes.TestOvercloudNode): def setUp(self): @@ -863,7 +582,7 @@ class TestImportNodeMultiArch(fakes.TestOvercloudNode): self.websocket = client.messaging_websocket() # Get the command object to test - self.cmd = overcloud_node.ImportNode(self.app, None) + self.cmd = overcloud_node_v2.ImportNode(self.app, None) image = collections.namedtuple('image', ['id', 'name']) self.app.client_manager.image = mock.Mock() @@ -894,7 +613,9 @@ class TestImportNodeMultiArch(fakes.TestOvercloudNode): "execution_id": "IDID" }] - self.cmd.take_action(parsed_args) + with mock.patch('tripleoclient.utils.run_ansible_playbook', + autospec=True): + self.cmd.take_action(parsed_args) nodes_list = copy.deepcopy(self.nodes_list) if not no_deploy_image: @@ -911,14 +632,8 @@ class TestImportNodeMultiArch(fakes.TestOvercloudNode): nodes_list[2]['ramdisk_id'] = ( 'file://%s/SNB-x86_64/agent.ramdisk' % self.http_boot) - call_count = 1 - call_list = [mock.call( - 'tripleo.baremetal.v1.register_or_update', workflow_input={ - 'nodes_json': nodes_list, - 'instance_boot_option': ('local' if local is True else - 'netboot' if local is False else None) - } - )] + call_count = 0 + call_list = [] if introspect: call_count += 1 @@ -949,13 +664,26 @@ class TestImportNodeMultiArch(fakes.TestOvercloudNode): parsed_args = self.check_parser(self.cmd, argslist, verifylist) self._check_workflow_call(parsed_args) - def test_import_and_introspect(self): - argslist = [self.json_file.name, '--introspect'] - verifylist = [('introspect', True), - ('provide', False)] - - parsed_args = self.check_parser(self.cmd, argslist, verifylist) - self._check_workflow_call(parsed_args, introspect=True) + @mock.patch('tripleoclient.utils.run_ansible_playbook', + autospec=True) + def test_import_and_introspect(self, mock_playbook): + parsed_args = self.check_parser(self.cmd, + [self.json_file.name, + '--introspect'], + [('introspect', True), + ('provide', False)]) + self.cmd.take_action(parsed_args) + mock_playbook.assert_called_once_with( + workdir=mock.ANY, + playbook=mock.ANY, + inventory=mock.ANY, + playbook_dir=constants.ANSIBLE_TRIPLEO_PLAYBOOKS, + extra_vars={ + 'node_uuids': ['MOCK_NODE_UUID'], + 'run_validations': False, + 'concurrency': 20 + } + ) def test_import_and_provide(self): argslist = [self.json_file.name, '--provide'] @@ -965,13 +693,27 @@ class TestImportNodeMultiArch(fakes.TestOvercloudNode): parsed_args = self.check_parser(self.cmd, argslist, verifylist) self._check_workflow_call(parsed_args, provide=True) - def test_import_and_introspect_and_provide(self): - argslist = [self.json_file.name, '--introspect', '--provide'] - verifylist = [('introspect', True), - ('provide', True)] - - parsed_args = self.check_parser(self.cmd, argslist, verifylist) - self._check_workflow_call(parsed_args, introspect=True, provide=True) + @mock.patch('tripleoclient.utils.run_ansible_playbook', + autospec=True) + def test_import_and_introspect_and_provide(self, mock_playbook): + parsed_args = self.check_parser(self.cmd, + [self.json_file.name, + '--introspect', + '--provide'], + [('introspect', True), + ('provide', True)]) + self.cmd.take_action(parsed_args) + mock_playbook.assert_called_once_with( + workdir=mock.ANY, + playbook=mock.ANY, + inventory=mock.ANY, + playbook_dir=constants.ANSIBLE_TRIPLEO_PLAYBOOKS, + extra_vars={ + 'node_uuids': ['MOCK_NODE_UUID'], + 'run_validations': False, + 'concurrency': 20 + } + ) def test_import_with_netboot(self): arglist = [self.json_file.name, '--instance-boot-option', 'netboot'] @@ -1193,12 +935,6 @@ class TestDiscoverNode(fakes.TestOvercloudNode): ) self.gcn.start() self.addCleanup(self.gcn.stop) - self.roun = mock.patch( - 'tripleo_common.actions.baremetal.RegisterOrUpdateNodes', - autospec=True - ) - self.roun.start() - self.addCleanup(self.roun.stop) self.websocket.wait_for_messages.return_value = [{ "status": "SUCCESS", @@ -1252,11 +988,11 @@ class TestDiscoverNode(fakes.TestOvercloudNode): workflows_calls = [ mock.call('tripleo.baremetal.v1.introspect', - workflow_input={'node_uuids': [], + workflow_input={'node_uuids': ['MOCK_NODE_UUID'], 'run_validations': True, 'concurrency': 10}), mock.call('tripleo.baremetal.v1.provide', - workflow_input={'node_uuids': []} + workflow_input={'node_uuids': ['MOCK_NODE_UUID']} ) ] self.workflow.executions.create.assert_has_calls(workflows_calls) diff --git a/tripleoclient/tests/v2/overcloud_node/fakes.py b/tripleoclient/tests/v2/overcloud_node/fakes.py index d3678f7a7..21baff532 100644 --- a/tripleoclient/tests/v2/overcloud_node/fakes.py +++ b/tripleoclient/tests/v2/overcloud_node/fakes.py @@ -13,39 +13,16 @@ # under the License. # -import mock -from osc_lib.tests import utils +from tripleoclient.tests import fakes -class FakeClientWrapper(object): - - def __init__(self): - self._instance = mock.Mock() - self._mock_websocket = mock.Mock() - self._mock_websocket.__enter__ = mock.Mock( - return_value=self._mock_websocket) - # Return False to avoid silencing exceptions - self._mock_websocket.__exit__ = mock.Mock(return_value=False) - - def messaging_websocket(self): - return self._mock_websocket - - -class TestDeleteNode(utils.TestCommand): +class TestDeleteNode(fakes.FakePlaybookExecution): def setUp(self): super(TestDeleteNode, self).setUp() - self.app.client_manager.auth_ref = mock.Mock(auth_token="TOKEN") - self.app.client_manager.orchestration = mock.Mock() - self.app.client_manager.tripleoclient = FakeClientWrapper() - -class TestOvercloudNode(utils.TestCommand): +class TestOvercloudNode(fakes.FakePlaybookExecution): def setUp(self): super(TestOvercloudNode, self).setUp() - - self.app.client_manager.baremetal = mock.Mock() - self.app.client_manager.workflow_engine = mock.Mock() - self.app.client_manager.tripleoclient = FakeClientWrapper() diff --git a/tripleoclient/tests/v2/overcloud_node/test_overcloud_node.py b/tripleoclient/tests/v2/overcloud_node/test_overcloud_node.py index 9f2541011..8524e7372 100644 --- a/tripleoclient/tests/v2/overcloud_node/test_overcloud_node.py +++ b/tripleoclient/tests/v2/overcloud_node/test_overcloud_node.py @@ -297,3 +297,54 @@ class TestIntrospectNode(fakes.TestOvercloudNode): self.assertRaises(test_utils.ParserException, self.check_parser, self.cmd, argslist, verifylist) + + def _check_introspect_all_manageable(self, parsed_args, provide=False): + self.websocket.wait_for_messages.return_value = iter([{ + "status": "SUCCESS", + "message": "Success", + "introspected_nodes": {}, + "execution_id": "IDID" + }] * 2) + + self.cmd.take_action(parsed_args) + + call_list = [mock.call( + 'tripleo.baremetal.v1.introspect_manageable_nodes', + workflow_input={'run_validations': False, 'concurrency': 20} + )] + + if provide: + call_list.append(mock.call( + 'tripleo.baremetal.v1.provide_manageable_nodes', + workflow_input={} + )) + + self.workflow.executions.create.assert_has_calls(call_list) + self.assertEqual(self.workflow.executions.create.call_count, + 2 if provide else 1) + + def _check_introspect_nodes(self, parsed_args, nodes, provide=False): + self.websocket.wait_for_messages.return_value = [{ + "status": "SUCCESS", + "message": "Success", + "execution_id": "IDID", + }] + + self.cmd.take_action(parsed_args) + + call_list = [mock.call( + 'tripleo.baremetal.v1.introspect', workflow_input={ + 'node_uuids': nodes, + 'run_validations': False, + 'concurrency': 20} + )] + + if provide: + call_list.append(mock.call( + 'tripleo.baremetal.v1.provide', workflow_input={ + 'node_uuids': nodes} + )) + + self.workflow.executions.create.assert_has_calls(call_list) + self.assertEqual(self.workflow.executions.create.call_count, + 2 if provide else 1) diff --git a/tripleoclient/tests/workflows/test_baremetal.py b/tripleoclient/tests/workflows/test_baremetal.py index d9b47f06c..c75ef86fc 100644 --- a/tripleoclient/tests/workflows/test_baremetal.py +++ b/tripleoclient/tests/workflows/test_baremetal.py @@ -14,13 +14,12 @@ import mock -from osc_lib.tests import utils - from tripleoclient import exceptions +from tripleoclient.tests import fakes from tripleoclient.workflows import baremetal -class TestBaremetalWorkflows(utils.TestCommand): +class TestBaremetalWorkflows(fakes.FakePlaybookExecution): def setUp(self): super(TestBaremetalWorkflows, self).setUp() @@ -49,44 +48,11 @@ class TestBaremetalWorkflows(utils.TestCommand): }]) def test_register_or_update_success(self): - - self.websocket.wait_for_messages.return_value = self.message_success - self.assertEqual(baremetal.register_or_update( self.app.client_manager, nodes_json=[], - kernel_name="kernel", - ramdisk_name="ramdisk" - ), []) - - self.workflow.executions.create.assert_called_once_with( - 'tripleo.baremetal.v1.register_or_update', - workflow_input={ - 'kernel_name': 'kernel', - 'nodes_json': [], - 'ramdisk_name': 'ramdisk' - }) - - def test_register_or_update_error(self): - - self.websocket.wait_for_messages.return_value = self.message_failed - - self.assertRaises( - exceptions.RegisterOrUpdateError, - baremetal.register_or_update, - self.app.client_manager, - nodes_json=[], - kernel_name="kernel", - ramdisk_name="ramdisk" - ) - - self.workflow.executions.create.assert_called_once_with( - 'tripleo.baremetal.v1.register_or_update', - workflow_input={ - 'kernel_name': 'kernel', - 'nodes_json': [], - 'ramdisk_name': 'ramdisk' - }) + instance_boot_option='local' + ), [mock.ANY]) def test_provide_success(self): diff --git a/tripleoclient/v1/overcloud_node.py b/tripleoclient/v1/overcloud_node.py index 6166df678..1bafbba34 100644 --- a/tripleoclient/v1/overcloud_node.py +++ b/tripleoclient/v1/overcloud_node.py @@ -13,10 +13,8 @@ # under the License. # -import argparse import collections import logging -import os import sys from cliff.formatters import table @@ -286,148 +284,6 @@ class CleanNode(command.Command): baremetal.provide_manageable_nodes(self.app.client_manager) -class IntrospectNode(command.Command): - """Introspect specified nodes or all nodes in 'manageable' state.""" - - log = logging.getLogger(__name__ + ".IntrospectNode") - - def get_parser(self, prog_name): - parser = super(IntrospectNode, self).get_parser(prog_name) - group = parser.add_mutually_exclusive_group(required=True) - group.add_argument('node_uuids', - nargs="*", - metavar="", - default=[], - help=_('Baremetal Node UUIDs for the node(s) to be ' - 'introspected')) - group.add_argument("--all-manageable", - action='store_true', - help=_("Introspect all nodes currently in " - "'manageable' state")) - parser.add_argument('--provide', - action='store_true', - help=_('Provide (make available) the nodes once ' - 'introspected')) - parser.add_argument('--run-validations', action='store_true', - default=False, - help=_('Run the pre-deployment validations. These ' - 'external validations are from the TripleO ' - 'Validations project.')) - parser.add_argument('--concurrency', type=int, - default=20, - help=_('Maximum number of nodes to introspect at ' - 'once.')) - return parser - - def take_action(self, parsed_args): - self.log.debug("take_action(%s)" % parsed_args) - - nodes = parsed_args.node_uuids - - if nodes: - baremetal.introspect(self.app.client_manager, - node_uuids=nodes, - run_validations=parsed_args.run_validations, - concurrency=parsed_args.concurrency - ) - else: - baremetal.introspect_manageable_nodes( - self.app.client_manager, - run_validations=parsed_args.run_validations, - concurrency=parsed_args.concurrency - ) - - if parsed_args.provide: - if nodes: - baremetal.provide(self.app.client_manager, - node_uuids=nodes, - ) - else: - baremetal.provide_manageable_nodes(self.app.client_manager) - - -class ImportNode(command.Command): - """Import baremetal nodes from a JSON, YAML or CSV file. - - The node status will be set to 'manageable' by default. - """ - - log = logging.getLogger(__name__ + ".ImportNode") - - def get_parser(self, prog_name): - parser = super(ImportNode, self).get_parser(prog_name) - parser.add_argument('--introspect', - action='store_true', - help=_('Introspect the imported nodes')) - parser.add_argument('--run-validations', action='store_true', - default=False, - help=_('Run the pre-deployment validations. These ' - 'external validations are from the TripleO ' - 'Validations project.')) - parser.add_argument('--validate-only', action='store_true', - default=False, - help=_('Validate the env_file and then exit ' - 'without actually importing the nodes.')) - parser.add_argument('--provide', - action='store_true', - help=_('Provide (make available) the nodes')) - parser.add_argument('--no-deploy-image', action='store_true', - help=_('Skip setting the deploy kernel and ' - 'ramdisk.')) - parser.add_argument('--instance-boot-option', - choices=['local', 'netboot'], default=None, - help=_('Whether to set instances for booting from ' - 'local hard drive (local) or network ' - '(netboot).')) - parser.add_argument("--http-boot", - default=os.environ.get( - 'HTTP_BOOT', - constants.IRONIC_HTTP_BOOT_BIND_MOUNT), - help=_("Root directory for the ironic-python-agent" - " image")) - parser.add_argument('--concurrency', type=int, - default=20, - help=_('Maximum number of nodes to introspect at ' - 'once.')) - parser.add_argument('env_file', type=argparse.FileType('r')) - return parser - - def take_action(self, parsed_args): - self.log.debug("take_action(%s)" % parsed_args) - - nodes_config = oooutils.parse_env_file(parsed_args.env_file) - parsed_args.env_file.close() - - if parsed_args.validate_only: - return baremetal.validate_nodes(self.app.client_manager, - nodes_json=nodes_config) - - # Look for *specific* deploy images and update the node data if - # one is found. - if not parsed_args.no_deploy_image: - oooutils.update_nodes_deploy_data(nodes_config, - http_boot=parsed_args.http_boot) - nodes = baremetal.register_or_update( - self.app.client_manager, - nodes_json=nodes_config, - instance_boot_option=parsed_args.instance_boot_option - ) - - nodes_uuids = [node['uuid'] for node in nodes] - - if parsed_args.introspect: - baremetal.introspect(self.app.client_manager, - node_uuids=nodes_uuids, - run_validations=parsed_args.run_validations, - concurrency=parsed_args.concurrency - ) - - if parsed_args.provide: - baremetal.provide(self.app.client_manager, - node_uuids=nodes_uuids, - ) - - class ConfigureNode(command.Command): """Configure Node boot options.""" @@ -578,7 +434,7 @@ class DiscoverNode(command.Command): **kwargs ) - nodes_uuids = [node['uuid'] for node in nodes] + nodes_uuids = [node.uuid for node in nodes] if parsed_args.introspect: baremetal.introspect(self.app.client_manager, diff --git a/tripleoclient/v2/overcloud_node.py b/tripleoclient/v2/overcloud_node.py index 01b3b2fac..8afbf6a87 100644 --- a/tripleoclient/v2/overcloud_node.py +++ b/tripleoclient/v2/overcloud_node.py @@ -102,7 +102,7 @@ class ImportNode(command.Command): instance_boot_option=parsed_args.instance_boot_option ) - nodes_uuids = [node['uuid'] for node in nodes] + nodes_uuids = [node.uuid for node in nodes] if parsed_args.introspect: extra_vars = { diff --git a/tripleoclient/workflows/baremetal.py b/tripleoclient/workflows/baremetal.py index 07159440a..9e1aee905 100644 --- a/tripleoclient/workflows/baremetal.py +++ b/tripleoclient/workflows/baremetal.py @@ -44,34 +44,53 @@ def validate_nodes(clients, nodes_json): raise exceptions.RegisterOrUpdateError(validated_nodes) -def register_or_update(clients, **workflow_input): +def register_or_update(clients, nodes_json, kernel_name=None, + ramdisk_name=None, instance_boot_option=None): """Node Registration or Update - Run the tripleo.baremetal.v1.register_or_update Mistral workflow. + :param clients: Application client object. + :type clients: Object + + :param nodes_json: + :type nodes_json: Object + + :param kernel_name: Kernel to use + :type kernel_name: String + + :param ramdisk_name: RAMDISK to use + :type ramdisk_name: String + + :param instance_boot_option: Whether to set instances for booting from + local hard drive (local) or network + (netboot). + :type instance_boot_option: String + + :returns: List """ - workflow_client = clients.workflow_engine - tripleoclients = clients.tripleoclient + context = clients.tripleoclient.create_mistral_context() + nodes = baremetal.RegisterOrUpdateNodes( + nodes_json=nodes_json, + ramdisk_name=ramdisk_name, + kernel_name=kernel_name, + instance_boot_option=instance_boot_option + ) - with tripleoclients.messaging_websocket() as ws: - execution = base.start_workflow( - workflow_client, - 'tripleo.baremetal.v1.register_or_update', - workflow_input=workflow_input - ) - - for payload in base.wait_for_messages(workflow_client, ws, execution): - if 'message' in payload: - print(payload['message']) - - if payload['status'] == 'SUCCESS': - registered_nodes = payload['registered_nodes'] - for nd in registered_nodes: - print('Successfully registered node UUID %s' % nd['uuid']) - return registered_nodes + registered_nodes = nodes.run(context=context) + if not isinstance(registered_nodes, list): + raise exceptions.RegisterOrUpdateError(registered_nodes) else: - raise exceptions.RegisterOrUpdateError( - 'Exception registering nodes: {}'.format(payload['message'])) + for node in registered_nodes: + if node.provision_state == 'enroll': + clients.baremetal.node.set_provision_state( + node_uuid=node.uuid, + state='manage' + ) + print('Successfully registered node UUID {}'.format(node.uuid)) + else: + print('Node UUID {} is already registered'.format(node.uuid)) + + return registered_nodes def _format_errors(payload): @@ -363,18 +382,13 @@ def discover_and_enroll(clients, ip_addresses, credentials, kernel_name, ) print('Successfully probed node IP {}'.format(node['ip'])) - register_or_update = baremetal.RegisterOrUpdateNodes( + return register_or_update( + clients=clients, nodes_json=probed_nodes, instance_boot_option=instance_boot_option, kernel_name=kernel_name, ramdisk_name=ramdisk_name ) - registered_nodes = list() - for node in register_or_update.run(context=context): - print('Successfully registered node UUID {}'.format(node['uuid'])) - registered_nodes.append(node) - else: - return registered_nodes def clean_nodes(clients, **workflow_input): diff --git a/tripleoclient/workflows/deployment.py b/tripleoclient/workflows/deployment.py index 7a54e910a..6a55e3ff2 100644 --- a/tripleoclient/workflows/deployment.py +++ b/tripleoclient/workflows/deployment.py @@ -59,12 +59,11 @@ def deploy(log, clients, **workflow_input): message = payload.get('message') if message and status == "RUNNING": print(message) - - if payload['status'] != "SUCCESS": - log.info(pprint.pformat(payload)) - print(payload['message']) - raise ValueError("Unexpected status %s for %s" - % (payload['status'], wf_name)) + elif payload['status'] != "SUCCESS": + log.info(pprint.pformat(payload)) + print(payload['message']) + raise ValueError("Unexpected status %s for %s" + % (payload['status'], wf_name)) def deploy_and_wait(log, clients, stack, plan_name, verbose_level,