From 9244349742f6c1e33931dc4927310ef8811a9424 Mon Sep 17 00:00:00 2001 From: Dan Prince Date: Sun, 29 May 2016 22:09:17 -0400 Subject: [PATCH] Use Mistral for baremetal registration Updates the baremetal registration workflows to use Mistral instead of python. Co-Authored-By: Dougal Matthews Co-Authored-By: Ryan Brady Change-Id: Ide8b7753829170f503ef962b4ad4fde388cbb0ba Depends-On: Ifc6bdd273a8e129ea7c4269d00add64e72cd371b Depends-On: I910f50a377bcbc2c23b527953e9df7eee9c938a4 --- requirements.txt | 1 + tripleoclient/exceptions.py | 13 ++ tripleoclient/tests/fakes.py | 2 + tripleoclient/tests/v1/baremetal/fakes.py | 23 ++- .../tests/v1/baremetal/test_baremetal.py | 140 +++++++++--------- tripleoclient/tests/workflows/__init__.py | 0 .../tests/workflows/test_baremetal.py | 121 +++++++++++++++ tripleoclient/v1/baremetal.py | 68 ++++----- tripleoclient/workflows/__init__.py | 0 tripleoclient/workflows/baremetal.py | 70 +++++++++ 10 files changed, 329 insertions(+), 109 deletions(-) create mode 100644 tripleoclient/tests/workflows/__init__.py create mode 100644 tripleoclient/tests/workflows/test_baremetal.py create mode 100644 tripleoclient/workflows/__init__.py create mode 100644 tripleoclient/workflows/baremetal.py diff --git a/requirements.txt b/requirements.txt index e5500aa94..74d279028 100644 --- a/requirements.txt +++ b/requirements.txt @@ -10,6 +10,7 @@ passlib>=1.6 # BSD python-ironic-inspector-client>=1.5.0 # Apache-2.0 python-heatclient>=1.1.0 # Apache-2.0 python-ironicclient>=1.1.0 # Apache-2.0 +python-mistralclient>=2.0.0 # Apache-2.0 python-openstackclient>=2.1.0 # Apache-2.0 six>=1.9.0 # MIT os-cloud-config # Apache-2.0 diff --git a/tripleoclient/exceptions.py b/tripleoclient/exceptions.py index d6d65e33d..95637ce28 100644 --- a/tripleoclient/exceptions.py +++ b/tripleoclient/exceptions.py @@ -31,6 +31,11 @@ class UnknownService(Exception): pass +class WorkflowServiceError(Exception): + """The service type is unknown""" + pass + + class NotFound(Exception): """Resource not found""" pass @@ -54,6 +59,14 @@ class IntrospectionError(RuntimeError): """Introspection failed""" +class RegisterOrUpdateError(WorkflowServiceError): + """Introspection failed""" + + +class NodeProvideError(WorkflowServiceError): + """Node Provide failed.""" + + class StateTransitionFailed(Exception): """Ironic node state transition failed""" diff --git a/tripleoclient/tests/fakes.py b/tripleoclient/tests/fakes.py index 9282cf4e8..534023fb6 100644 --- a/tripleoclient/tests/fakes.py +++ b/tripleoclient/tests/fakes.py @@ -34,6 +34,8 @@ class FakeApp(object): class FakeClientManager(object): def __init__(self): self.identity = None + self.workflow_engine = None + self.tripleoclient = None self.auth_ref = None self.tripleoclient = FakeClientWrapper() diff --git a/tripleoclient/tests/v1/baremetal/fakes.py b/tripleoclient/tests/v1/baremetal/fakes.py index e0af82f6c..b644b6b87 100644 --- a/tripleoclient/tests/v1/baremetal/fakes.py +++ b/tripleoclient/tests/v1/baremetal/fakes.py @@ -13,8 +13,9 @@ # under the License. # -import ironic_inspector_client import mock + +import ironic_inspector_client from openstackclient.tests import utils @@ -90,6 +91,19 @@ class FakeInspectorClient(object): return {uuid: self.states[uuid] for uuid in uuids} +class ClientWrapper(object): + + def __init__(self): + self._instance = None + self._mock_websocket = mock.Mock() + self._mock_websocket.__enter__ = mock.Mock( + return_value=self._mock_websocket) + self._mock_websocket.__exit__ = mock.Mock() + + def messaging_websocket(self, queue_name='tripleo'): + return self._mock_websocket + + class TestBaremetal(utils.TestCommand): def setUp(self): @@ -101,3 +115,10 @@ class TestBaremetal(utils.TestCommand): self.app.client_manager.baremetal_introspection = FakeInspectorClient() self.app.client_manager._region_name = "Arcadia" self.app.client_manager.session = mock.Mock() + self.app.client_manager.workflow_engine = mock.Mock() + self.app.client_manager.tripleoclient = ClientWrapper() + + def tearDown(self): + super(TestBaremetal, self).tearDown() + + mock.patch.stopall() diff --git a/tripleoclient/tests/v1/baremetal/test_baremetal.py b/tripleoclient/tests/v1/baremetal/test_baremetal.py index c4b16bd97..9aa995793 100644 --- a/tripleoclient/tests/v1/baremetal/test_baremetal.py +++ b/tripleoclient/tests/v1/baremetal/test_baremetal.py @@ -339,10 +339,24 @@ pxe_ssh,192.168.122.2,stack,"KEY2",00:0b:d0:69:7e:58""") } ) - self.mock_initial_nodes = { - mock.Mock(uuid="ABCDEFGH", provision_state="enroll"), - mock.Mock(uuid="IJKLMNOP", provision_state="enroll") - } + self.mock_websocket_success = [{ + "status": "SUCCESS", + "registered_nodes": [{ + "uuid": "MOCK_NODE_UUID" + }], + }, { + "status": "SUCCESS" + }] + + self.workflow = self.app.client_manager.workflow_engine + tripleoclient = self.app.client_manager.tripleoclient + websocket = tripleoclient.messaging_websocket() + websocket.wait_for_message.side_effect = self.mock_websocket_success + self.websocket = websocket + + uuid4_patcher = mock.patch('uuid.uuid4', return_value="UUID4") + self.mock_uuid4 = uuid4_patcher.start() + self.addCleanup(self.mock_uuid4.stop) def tearDown(self): @@ -353,25 +367,38 @@ pxe_ssh,192.168.122.2,stack,"KEY2",00:0b:d0:69:7e:58""") os.unlink(self.yaml_file.name) os.unlink(self.instack_yaml.name) - def _check_register_call(self, mock_register_nodes, local=True, **kwargs): + def _check_workflow_call(self, local=True, provide=True, + kernel_name='bm-deploy-kernel', + ramdisk_name='bm-deploy-ramdisk'): nodes_list = copy.deepcopy(self.nodes_list) for node in nodes_list: if local: node['capabilities'] = 'boot_option:local' else: node['capabilities'] = 'boot_option:netboot' - kwargs.setdefault('kernel_name', 'bm-deploy-kernel') - kwargs.setdefault('ramdisk_name', 'bm-deploy-ramdisk') - mock_register_nodes.assert_called_with( - 'http://localhost', nodes_list, - client=self.app.client_manager.baremetal, - keystone_client=None, - glance_client=self.app.client_manager.image, - **kwargs) + call_list = [mock.call( + 'tripleo.baremetal.v1.register_or_update', workflow_input={ + 'kernel_name': kernel_name, + 'nodes_json': nodes_list, + 'queue_name': 'UUID4', + 'ramdisk_name': ramdisk_name} + )] - @mock.patch('tripleo_common.utils.nodes.register_all_nodes', autospec=True) - def test_json_import(self, mock_register_nodes): + if provide: + call_list.append(mock.call( + 'tripleo.baremetal.v1.provide', workflow_input={ + 'node_uuids': ['MOCK_NODE_UUID', ], + 'queue_name': 'UUID4' + } + )) + + self.workflow.executions.create.assert_has_calls(call_list) + + self.assertEqual(self.workflow.executions.create.call_count, + 2 if provide else 1) + + def test_json_import(self): arglist = [self.json_file.name, '--json', '-s', 'http://localhost'] @@ -381,18 +408,12 @@ pxe_ssh,192.168.122.2,stack,"KEY2",00:0b:d0:69:7e:58""") ] parsed_args = self.check_parser(self.cmd, arglist, verifylist) - mock_register_nodes.return_value = self.mock_initial_nodes self.cmd.take_action(parsed_args) - self._check_register_call(mock_register_nodes) - self.assertEqual(sorted([ - ('ABCDEFGH', 'manage'), ('IJKLMNOP', 'manage'), - ('ABCDEFGH', 'provide'), ('IJKLMNOP', 'provide') - ]), sorted(self.baremetal.node.updates)) + self._check_workflow_call() - @mock.patch('tripleo_common.utils.nodes.register_all_nodes', autospec=True) - def test_json_import_initial_state_enroll(self, mock_register_nodes): + def test_json_import_initial_state_enroll(self): arglist = [ self.json_file.name, @@ -407,14 +428,12 @@ pxe_ssh,192.168.122.2,stack,"KEY2",00:0b:d0:69:7e:58""") ] parsed_args = self.check_parser(self.cmd, arglist, verifylist) - mock_register_nodes.return_value = self.mock_initial_nodes self.cmd.take_action(parsed_args) - self._check_register_call(mock_register_nodes) + self._check_workflow_call(provide=False) self.assertEqual([], self.baremetal.node.updates) - @mock.patch('tripleo_common.utils.nodes.register_all_nodes', autospec=True) - def test_available_does_not_require_api_1_11(self, mock_register_nodes): + def test_available_does_not_require_api_1_11(self): arglist = [self.json_file.name, '--json', '-s', 'http://localhost'] verifylist = [ @@ -423,15 +442,9 @@ pxe_ssh,192.168.122.2,stack,"KEY2",00:0b:d0:69:7e:58""") ] self.baremetal.http_client.os_ironic_api_version = '1.6' parsed_args = self.check_parser(self.cmd, arglist, verifylist) - mock_register_nodes.return_value = self.mock_initial_nodes self.cmd.take_action(parsed_args) - self._check_register_call(mock_register_nodes) - - self.assertEqual(sorted([ - ('ABCDEFGH', 'manage'), ('IJKLMNOP', 'manage'), - ('ABCDEFGH', 'provide'), ('IJKLMNOP', 'provide') - ]), sorted(self.baremetal.node.updates)) + self._check_workflow_call() def test_enroll_requires_api_1_11(self): arglist = [ @@ -450,9 +463,9 @@ pxe_ssh,192.168.122.2,stack,"KEY2",00:0b:d0:69:7e:58""") self.assertRaisesRegexp(exceptions.InvalidConfiguration, 'OS_BAREMETAL_API_VERSION', self.cmd.take_action, parsed_args) + self.workflow.executions.create.assert_not_called() - @mock.patch('tripleo_common.utils.nodes.register_all_nodes', autospec=True) - def test_json_import_detect_suffix(self, mock_register_nodes): + def test_json_import_detect_suffix(self): arglist = [self.json_file.name, '-s', 'http://localhost'] @@ -465,10 +478,9 @@ pxe_ssh,192.168.122.2,stack,"KEY2",00:0b:d0:69:7e:58""") self.cmd.take_action(parsed_args) - self._check_register_call(mock_register_nodes) + self._check_workflow_call() - @mock.patch('tripleo_common.utils.nodes.register_all_nodes', autospec=True) - def test_instack_json_import(self, mock_register_nodes): + def test_instack_json_import(self): arglist = [self.instack_json.name, '--json', '-s', 'http://localhost'] @@ -478,18 +490,12 @@ pxe_ssh,192.168.122.2,stack,"KEY2",00:0b:d0:69:7e:58""") ] parsed_args = self.check_parser(self.cmd, arglist, verifylist) - mock_register_nodes.return_value = self.mock_initial_nodes self.cmd.take_action(parsed_args) - self._check_register_call(mock_register_nodes) - self.assertEqual(sorted([ - ('ABCDEFGH', 'manage'), ('IJKLMNOP', 'manage'), - ('ABCDEFGH', 'provide'), ('IJKLMNOP', 'provide') - ]), sorted(self.baremetal.node.updates)) + self._check_workflow_call() - @mock.patch('tripleo_common.utils.nodes.register_all_nodes', autospec=True) - def test_csv_import(self, mock_register_nodes): + def test_csv_import(self): arglist = [self.csv_file.name, '--csv', '-s', 'http://localhost'] @@ -499,14 +505,12 @@ pxe_ssh,192.168.122.2,stack,"KEY2",00:0b:d0:69:7e:58""") ] parsed_args = self.check_parser(self.cmd, arglist, verifylist) - mock_register_nodes.return_value = self.mock_initial_nodes self.cmd.take_action(parsed_args) - self._check_register_call(mock_register_nodes) + self._check_workflow_call() - @mock.patch('tripleo_common.utils.nodes.register_all_nodes', autospec=True) - def test_csv_import_detect_suffix(self, mock_register_nodes): + def test_csv_import_detect_suffix(self): arglist = [self.csv_file.name, '-s', 'http://localhost'] @@ -519,10 +523,9 @@ pxe_ssh,192.168.122.2,stack,"KEY2",00:0b:d0:69:7e:58""") self.cmd.take_action(parsed_args) - self._check_register_call(mock_register_nodes) + self._check_workflow_call() - @mock.patch('tripleo_common.utils.nodes.register_all_nodes', autospec=True) - def test_yaml_import(self, mock_register_nodes): + def test_yaml_import(self): arglist = [self.yaml_file.name, '-s', 'http://localhost'] @@ -535,7 +538,7 @@ pxe_ssh,192.168.122.2,stack,"KEY2",00:0b:d0:69:7e:58""") self.cmd.take_action(parsed_args) - self._check_register_call(mock_register_nodes) + self._check_workflow_call() def test_invalid_import_filetype(self): @@ -552,8 +555,7 @@ pxe_ssh,192.168.122.2,stack,"KEY2",00:0b:d0:69:7e:58""") 'Invalid file extension', self.cmd.take_action, parsed_args) - @mock.patch('tripleo_common.utils.nodes.register_all_nodes', autospec=True) - def test_instack_yaml_import(self, mock_register_nodes): + def test_instack_yaml_import(self): arglist = [self.instack_yaml.name, '-s', 'http://localhost'] @@ -563,18 +565,12 @@ pxe_ssh,192.168.122.2,stack,"KEY2",00:0b:d0:69:7e:58""") ] parsed_args = self.check_parser(self.cmd, arglist, verifylist) - mock_register_nodes.return_value = self.mock_initial_nodes self.cmd.take_action(parsed_args) - self._check_register_call(mock_register_nodes) - self.assertEqual(sorted([ - ('ABCDEFGH', 'manage'), ('IJKLMNOP', 'manage'), - ('ABCDEFGH', 'provide'), ('IJKLMNOP', 'provide') - ]), sorted(self.baremetal.node.updates)) + self._check_workflow_call() - @mock.patch('tripleo_common.utils.nodes.register_all_nodes', autospec=True) - def test_netboot(self, mock_register_nodes): + def test_netboot(self): arglist = [self.json_file.name, '-s', 'http://localhost', '--instance-boot-option', 'netboot'] @@ -587,10 +583,9 @@ pxe_ssh,192.168.122.2,stack,"KEY2",00:0b:d0:69:7e:58""") self.cmd.take_action(parsed_args) - self._check_register_call(mock_register_nodes, local=False) + self._check_workflow_call(local=False) - @mock.patch('tripleo_common.utils.nodes.register_all_nodes', autospec=True) - def test_custom_image(self, mock_register_nodes): + def test_custom_image(self): arglist = [self.json_file.name, '-s', 'http://localhost', '--deploy-kernel', 'k', '--deploy-ramdisk', 'r'] @@ -604,11 +599,9 @@ pxe_ssh,192.168.122.2,stack,"KEY2",00:0b:d0:69:7e:58""") self.cmd.take_action(parsed_args) - self._check_register_call(mock_register_nodes, kernel_name='k', - ramdisk_name='r') + self._check_workflow_call(kernel_name='k', ramdisk_name='r') - @mock.patch('tripleo_common.utils.nodes.register_all_nodes', autospec=True) - def test_no_image(self, mock_register_nodes): + def test_no_image(self): arglist = [self.json_file.name, '-s', 'http://localhost', '--no-deploy-image'] @@ -621,8 +614,7 @@ pxe_ssh,192.168.122.2,stack,"KEY2",00:0b:d0:69:7e:58""") self.cmd.take_action(parsed_args) - self._check_register_call(mock_register_nodes, kernel_name=None, - ramdisk_name=None) + self._check_workflow_call(kernel_name=None, ramdisk_name=None) class TestStartBaremetalIntrospectionBulk(fakes.TestBaremetal): diff --git a/tripleoclient/tests/workflows/__init__.py b/tripleoclient/tests/workflows/__init__.py new file mode 100644 index 000000000..e69de29bb diff --git a/tripleoclient/tests/workflows/test_baremetal.py b/tripleoclient/tests/workflows/test_baremetal.py new file mode 100644 index 000000000..ff756709d --- /dev/null +++ b/tripleoclient/tests/workflows/test_baremetal.py @@ -0,0 +1,121 @@ +# -*- coding: utf-8 -*- + +# Licensed under the Apache License, Version 2.0 (the "License"); you may +# not use this file except in compliance with the License. You may obtain +# a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT +# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the +# License for the specific language governing permissions and limitations +# under the License. + +import mock + +from openstackclient.tests import utils + +from tripleoclient import exceptions +from tripleoclient.workflows import baremetal + + +class TestBaremetalWorkflows(utils.TestCommand): + + def setUp(self): + super(TestBaremetalWorkflows, self).setUp() + + self.app.client_manager.workflow_engine = self.workflow = mock.Mock() + self.tripleoclient = mock.Mock() + self.websocket = mock.Mock() + self.websocket.__enter__ = lambda s: self.websocket + self.websocket.__exit__ = lambda s, *exc: None + self.tripleoclient.messaging_websocket.return_value = self.websocket + self.app.client_manager.tripleoclient = self.tripleoclient + + def test_register_or_update_success(self): + + self.websocket.wait_for_message.return_value = { + "status": "SUCCESS", + "registered_nodes": [], + } + + self.assertEqual(baremetal.register_or_update( + self.app.client_manager, + nodes_json=[], + queue_name="QUEUE_NAME", + 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', + 'queue_name': 'QUEUE_NAME', + 'nodes_json': [], + 'ramdisk_name': 'ramdisk' + }) + + def test_register_or_update_error(self): + + self.websocket.wait_for_message.return_value = { + "status": "FAIL", + "message": "FAILED", + } + + self.assertRaises( + exceptions.RegisterOrUpdateError, + baremetal.register_or_update, + self.app.client_manager, + nodes_json=[], + queue_name="QUEUE_NAME", + 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', + 'queue_name': 'QUEUE_NAME', + 'nodes_json': [], + 'ramdisk_name': 'ramdisk' + }) + + def test_provide_success(self): + + self.websocket.wait_for_message.return_value = { + "status": "SUCCESS", + } + + baremetal.provide(self.app.client_manager, node_uuids=[], + queue_name="QUEUE_NAME") + + self.workflow.executions.create.assert_called_once_with( + 'tripleo.baremetal.v1.provide', + workflow_input={ + 'node_uuids': [], + 'queue_name': "QUEUE_NAME" + }) + + def test_provide_error(self): + + self.websocket.wait_for_message.return_value = { + "status": "FAIL", + "message": "Failed" + } + + self.assertRaises( + exceptions.NodeProvideError, + baremetal.provide, + self.app.client_manager, + node_uuids=[], + queue_name="QUEUE_NAME") + + self.workflow.executions.create.assert_called_once_with( + 'tripleo.baremetal.v1.provide', + workflow_input={ + 'node_uuids': [], + 'queue_name': "QUEUE_NAME" + }) diff --git a/tripleoclient/v1/baremetal.py b/tripleoclient/v1/baremetal.py index ae7f218c7..ec12f40c8 100644 --- a/tripleoclient/v1/baremetal.py +++ b/tripleoclient/v1/baremetal.py @@ -20,6 +20,7 @@ import csv import json import logging import time +import uuid import yaml from cliff import command @@ -28,10 +29,10 @@ import ironic_inspector_client from openstackclient.common import utils as osc_utils from openstackclient.i18n import _ from oslo_utils import units -from tripleo_common.utils import nodes from tripleoclient import exceptions from tripleoclient import utils +from tripleoclient.workflows import baremetal def _csv_to_nodes_dict(nodes_csv): @@ -152,8 +153,7 @@ class ImportBaremetal(command.Command): def get_parser(self, prog_name): parser = super(ImportBaremetal, self).get_parser(prog_name) parser.add_argument('-s', '--service-host', dest='service_host', - help=_('Nova compute service host to register ' - 'nodes with')) + help=_('Deprecated, this argument has no impact.')) parser.add_argument( '--json', dest='json', action='store_true', help=_('Deprecated, now detected via file extension.')) @@ -210,34 +210,34 @@ class ImportBaremetal(command.Command): _("OS_BAREMETAL_API_VERSION must be >=1.11 for use of " "'enroll' provision state; currently %s") % api_version) + # NOTE (dprince) move this to tripleo-common? for node in nodes_config: caps = utils.capabilities_to_dict(node.get('capabilities', {})) caps.setdefault('boot_option', parsed_args.instance_boot_option) node['capabilities'] = utils.dict_to_capabilities(caps) - new_nodes = nodes.register_all_nodes( - parsed_args.service_host, - nodes_config, - client=client, - keystone_client=self.app.client_manager.identity, - glance_client=self.app.client_manager.image, - kernel_name=(parsed_args.deploy_kernel if not - parsed_args.no_deploy_image else None), - ramdisk_name=(parsed_args.deploy_ramdisk if not - parsed_args.no_deploy_image else None)) + queue_name = str(uuid.uuid4()) + + if parsed_args.no_deploy_image: + deploy_kernel = None + deploy_ramdisk = None + else: + deploy_kernel = parsed_args.deploy_kernel + deploy_ramdisk = parsed_args.deploy_ramdisk + + nodes = baremetal.register_or_update( + self.app.client_manager, + nodes_json=nodes_config, + queue_name=queue_name, + kernel_name=deploy_kernel, + ramdisk_name=deploy_ramdisk + ) + + node_uuids = [node['uuid'] for node in nodes] if parsed_args.initial_state == "available": - manageable_node_uuids = list(utils.set_nodes_state( - client, new_nodes, "manage", "manageable", - skipped_states={'manageable', 'available'} - )) - manageable_nodes = [ - n for n in new_nodes if n.uuid in manageable_node_uuids - ] - list(utils.set_nodes_state( - client, manageable_nodes, "provide", "available", - skipped_states={'available'} - )) + baremetal.provide(self.app.client_manager, node_uuids=node_uuids, + queue_name=queue_name) class StartBaremetalIntrospectionBulk(command.Command): @@ -257,9 +257,9 @@ class StartBaremetalIntrospectionBulk(command.Command): self.log.debug("Moving available/enroll nodes to manageable state.") available_nodes = utils.nodes_in_states(client, ("available", "enroll")) - for uuid in utils.set_nodes_state(client, available_nodes, 'manage', - 'manageable'): - self.log.debug("Node {0} has been set to manageable.".format(uuid)) + for uu in utils.set_nodes_state(client, available_nodes, 'manage', + 'manageable'): + self.log.debug("Node {0} has been set to manageable.".format(uu)) manageable_nodes = utils.nodes_in_states(client, ("manageable",)) for node in manageable_nodes: @@ -272,25 +272,25 @@ class StartBaremetalIntrospectionBulk(command.Command): errors = [] successful_node_uuids = set() results = inspector_client.wait_for_finish(node_uuids) - for uuid, status in results.items(): + for uu, status in results.items(): if status['error'] is None: print("Introspection for UUID {0} finished successfully." - .format(uuid)) - successful_node_uuids.add(uuid) + .format(uu)) + successful_node_uuids.add(uu) else: print("Introspection for UUID {0} finished with error: {1}" - .format(uuid, status['error'])) - errors.append("%s: %s" % (uuid, status['error'])) + .format(uu, status['error'])) + errors.append("%s: %s" % (uu, status['error'])) print("Setting manageable nodes to available...") self.log.debug("Moving manageable nodes to available state.") successful_nodes = [n for n in manageable_nodes if n.uuid in successful_node_uuids] - for uuid in utils.set_nodes_state( + for uu in utils.set_nodes_state( client, successful_nodes, 'provide', 'available', skipped_states=("available", "active")): - print("Node {0} has been set to available.".format(uuid)) + print("Node {0} has been set to available.".format(uu)) if errors: raise exceptions.IntrospectionError( diff --git a/tripleoclient/workflows/__init__.py b/tripleoclient/workflows/__init__.py new file mode 100644 index 000000000..e69de29bb diff --git a/tripleoclient/workflows/baremetal.py b/tripleoclient/workflows/baremetal.py new file mode 100644 index 000000000..4b31e8915 --- /dev/null +++ b/tripleoclient/workflows/baremetal.py @@ -0,0 +1,70 @@ +# -*- coding: utf-8 -*- + +# Licensed under the Apache License, Version 2.0 (the "License"); you may +# not use this file except in compliance with the License. You may obtain +# a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT +# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the +# License for the specific language governing permissions and limitations +# under the License. + +from tripleoclient import exceptions + + +def register_or_update(clients, **workflow_input): + """Node Registration or Update + + Run the tripleo.baremetal.v1.register_or_update Mistral workflow. + """ + + workflow_client = clients.workflow_engine + tripleoclients = clients.tripleoclient + queue_name = workflow_input['queue_name'] + + execution = workflow_client.executions.create( + 'tripleo.baremetal.v1.register_or_update', + workflow_input=workflow_input + ) + + with tripleoclients.messaging_websocket(queue_name) as ws: + payload = ws.wait_for_message(execution.id) + + 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 + else: + raise exceptions.RegisterOrUpdateError( + 'Exception registering nodes: {}'.format(payload['message'])) + + +def provide(clients, **workflow_input): + """Provide Baremetal Nodes + + Run the tripleo.baremetal.v1.provide Mistral workflow. + """ + + workflow_client = clients.workflow_engine + tripleoclients = clients.tripleoclient + queue_name = workflow_input['queue_name'] + + execution = workflow_client.executions.create( + 'tripleo.baremetal.v1.provide', + workflow_input={'node_uuids': workflow_input['node_uuids'], + 'queue_name': queue_name} + ) + + with tripleoclients.messaging_websocket(queue_name) as ws: + payload = ws.wait_for_message(execution.id) + + if payload['status'] == 'SUCCESS': + print('Successfully set all nodes to available.') + else: + raise exceptions.NodeProvideError( + 'Failed to set nodes to available state: {}'.format( + payload['message']))