Remove mistral when running the register_or_update workflow
This change removes all of mistral from the register_or_update workflow by calling the required functions directly. Story: 2007212 Task: 38442 Closes-Bug: #1866637 Change-Id: Ie85adc64cd4fcec469d6979a424d8f01b00f34f2 Signed-off-by: Kevin Carter <kecarter@redhat.com>
This commit is contained in:
parent
ed75570496
commit
ad9c7a7504
|
@ -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()
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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)
|
||||
|
|
|
@ -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()
|
||||
|
|
|
@ -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)
|
||||
|
|
|
@ -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):
|
||||
|
||||
|
|
|
@ -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="<node_uuid>",
|
||||
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,
|
||||
|
|
|
@ -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 = {
|
||||
|
|
|
@ -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):
|
||||
|
|
|
@ -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,
|
||||
|
|
Loading…
Reference in New Issue