From 227ce3fc90e5b07d7902ee6299e65b2c2ba9cf9b Mon Sep 17 00:00:00 2001 From: Carlos Camacho Date: Wed, 21 Nov 2018 00:05:14 +0100 Subject: [PATCH] Get the stack name if possible before running the validations group If we run the group validations in the Undercloud and we do not specify the stack name, this will fail if the Overcloud stack is not called 'overcloud'. In this case we try to fetch the stack name and we compare it with the swift containers to match the deployment plan name if there is a match, then we know the stack name. Change-Id: Ib2e27b1b43f573385c089e57bd2290daac49d814 Closes-Bug: 1806684 Resolves: rhbz#1573120 --- instack_undercloud/tests/test_undercloud.py | 107 +++++++++++++++++++- instack_undercloud/undercloud.py | 55 ++++++++-- 2 files changed, 149 insertions(+), 13 deletions(-) diff --git a/instack_undercloud/tests/test_undercloud.py b/instack_undercloud/tests/test_undercloud.py index 2071de2d7..9448e5d30 100644 --- a/instack_undercloud/tests/test_undercloud.py +++ b/instack_undercloud/tests/test_undercloud.py @@ -999,7 +999,12 @@ class TestPostConfig(BaseTestCase): @mock.patch('instack_undercloud.undercloud._get_auth_values') @mock.patch('instack_undercloud.undercloud._get_session') @mock.patch('mistralclient.api.client.client', autospec=True) - def test_run_validation_groups_success(self, mock_mistral_client, + @mock.patch('swiftclient.client.Connection', autospec=True) + @mock.patch('os_client_config.make_client') + def test_run_validation_groups_success(self, + mock_make_client, + mock_swift_client, + mock_mistral_client, mock_get_session, mock_auth_values): mock_mistral = mock.Mock() @@ -1007,19 +1012,76 @@ class TestPostConfig(BaseTestCase): mock_mistral.environments.list.return_value = [] mock_mistral.executions.get.return_value = mock.Mock(state="SUCCESS") mock_get_session.return_value = mock.MagicMock() + + mock_auth_values.return_value = ('aturing', '3nigma', 'hut8', + 'http://bletchley:5000/') + + mock_instance_swift = mock.Mock() + mock_instance_swift.get_account.return_value = [None, + [{'name': 'hut8'}, + {'name': 'mystack'}]] + mock_swift_client.return_value = mock_instance_swift + + mock_heat = mock.Mock() + aux_stack = {} + aux_stack['stack_name'] = "mystack" + mock_heat.stacks.list.return_value = [aux_stack] + mock_make_client.return_value = mock_heat + undercloud._run_validation_groups(["post-upgrade"]) mock_mistral.executions.create.assert_called_once_with( 'tripleo.validations.v1.run_groups', workflow_input={ 'group_names': ['post-upgrade'], + 'plan': 'mystack', } ) + @mock.patch('instack_undercloud.undercloud._get_auth_values') + @mock.patch('instack_undercloud.undercloud._get_session') + @mock.patch('mistralclient.api.client.client', autospec=True) + @mock.patch('swiftclient.client.Connection', autospec=True) + @mock.patch('os_client_config.make_client') + def test_run_validation_groups_no_overcloud(self, + mock_make_client, + mock_swift_client, + mock_mistral_client, + mock_get_session, + mock_auth_values): + mock_mistral = mock.Mock() + mock_mistral_client.return_value = mock_mistral + mock_mistral.environments.list.return_value = [] + mock_mistral.executions.get.return_value = mock.Mock(state="SUCCESS") + mock_get_session.return_value = mock.MagicMock() + + mock_auth_values.return_value = ('aturing', '3nigma', 'hut8', + 'http://bletchley:5000/') + + mock_instance_swift = mock.Mock() + mock_instance_swift.get_account.return_value = [None, + [{'name': 'hut8'}, + {'name': 'mystack'}]] + mock_swift_client.return_value = mock_instance_swift + + mock_heat = mock.Mock() + aux_stack = {} + aux_stack['stack_name'] = "mystackooo" + mock_heat.stacks.list.return_value = [aux_stack] + mock_make_client.return_value = mock_heat + + undercloud._run_validation_groups(["post-upgrade"]) + mock_mistral.executions.create.assert_not_called() + @mock.patch('instack_undercloud.undercloud._get_auth_values') @mock.patch('instack_undercloud.undercloud._get_session') @mock.patch('mistralclient.api.client.client', autospec=True) @mock.patch('time.strptime') - def test_run_validation_groups_fail(self, mock_strptime, + @mock.patch('swiftclient.client.Connection', autospec=True) + @mock.patch('os_client_config.make_client') + def test_run_validation_groups_fail(self, + mock_make_client, + mock_swift_client, + mock_strptime, mock_mistral_client, mock_get_session, mock_auth_values): mock_mistral = mock.Mock() @@ -1029,6 +1091,22 @@ class TestPostConfig(BaseTestCase): mock_mistral.executions.get_output.return_value = "ERROR!" mock_mistral.executions.get.id = "1234" mock_mistral.action_executions.list.return_value = [] + + mock_auth_values.return_value = ('aturing', '3nigma', 'hut8', + 'http://bletchley:5000/') + + mock_instance_swift = mock.Mock() + mock_instance_swift.get_account.return_value = [None, + [{'name': 'hut8'}, + {'name': 'mystack'}]] + mock_swift_client.return_value = mock_instance_swift + + mock_heat = mock.Mock() + aux_stack = {} + aux_stack['stack_name'] = "mystack" + mock_heat.stacks.list.return_value = [aux_stack] + mock_make_client.return_value = mock_heat + mock_strptime.return_value = time.mktime(time.localtime()) mock_get_session.return_value = mock.MagicMock() self.assertRaises( @@ -1039,7 +1117,12 @@ class TestPostConfig(BaseTestCase): @mock.patch('instack_undercloud.undercloud._get_session') @mock.patch('mistralclient.api.client.client', autospec=True) @mock.patch('time.strptime') - def test_run_validation_groups_timeout(self, mock_strptime, + @mock.patch('swiftclient.client.Connection', autospec=True) + @mock.patch('os_client_config.make_client') + def test_run_validation_groups_timeout(self, + mock_make_client, + mock_swift_client, + mock_strptime, mock_mistral_client, mock_get_session, mock_auth_values): mock_mistral = mock.Mock() @@ -1047,7 +1130,23 @@ class TestPostConfig(BaseTestCase): mock_mistral.environments.list.return_value = [] mock_mistral.executions.get.id = "1234" mock_mistral.action_executions.list.return_value = [] - mock_get_session.return_value = mock.MagicMock() + mock_instance_swift = mock.Mock() + + mock_auth_values.return_value = ('aturing', '3nigma', 'hut8', + 'http://bletchley:5000/') + + mock_instance_swift = mock.Mock() + mock_instance_swift.get_account.return_value = [None, + [{'name': 'hut8'}, + {'name': 'mystack'}]] + mock_swift_client.return_value = mock_instance_swift + + mock_heat = mock.Mock() + aux_stack = {} + aux_stack['stack_name'] = "mystack" + mock_heat.stacks.list.return_value = [aux_stack] + mock_make_client.return_value = mock_heat + mock_time = mock.MagicMock() mock_time.return_value = time.mktime(time.localtime()) mock_strptime.return_value = time.mktime(time.localtime()) diff --git a/instack_undercloud/undercloud.py b/instack_undercloud/undercloud.py index 8c9895dd5..af825eedd 100644 --- a/instack_undercloud/undercloud.py +++ b/instack_undercloud/undercloud.py @@ -1846,15 +1846,52 @@ def _run_validation_groups(groups=[], mistral_url='', timeout=540, fail_on_error=False): sess = _get_session() mistral = mistralclient.client(mistral_url=mistral_url, session=sess) - LOG.info('Starting and waiting for validation groups %s ', groups) - execution = mistral.executions.create( - 'tripleo.validations.v1.run_groups', - workflow_input={'group_names': groups} - ) - fail_message = ("error running the validation groups %s " % groups) - timeout_at = time.time() + timeout - _wait_for_mistral_execution(timeout_at, mistral, execution, fail_message, - fail_on_error) + + # Here we fetch all the containers names from swift, we should have + # a container called with the same name as the deployment plan. + swift_client = swiftclient.Connection(session=sess) + swift = swift_client.get_account()[1] + plans = [container["name"] for container in swift] + user, password, project, auth_url = _get_auth_values() + heat = os_client_config.make_client('orchestration', + auth_url=auth_url, + username=user, + password=password, + project_name=project, + project_domain_name='Default', + user_domain_name='Default') + + # Here we get all the stack names, we should have only one. + stack_names_list = [stack['stack_name'] for stack in heat.stacks.list()] + + # We calculate the interception of the two previous list, the + # result should be only one value in case the Overcloud exists. + existing_stack = list(set(plans) & set(stack_names_list)) + + # We can not run the validations if we do not have the Overcloud deployed + # We are running a group validation and if the validation runs in both + # the Undercloud and Overcloud nodes is mandatory to define the Overcloud + # stack name. For example there are validations in the post-upgrade group + # that will run in both the Undercloud and Overcloud making this mistral + # execution fail. + + if existing_stack: + LOG.info('Starting and waiting for validation groups %s ', groups) + + execution = mistral.executions.create( + 'tripleo.validations.v1.run_groups', + workflow_input={'group_names': groups, 'plan': existing_stack[0]} + ) + + fail_message = ("error running the validation groups %s " % groups) + timeout_at = time.time() + timeout + _wait_for_mistral_execution(timeout_at, + mistral, + execution, + fail_message, + fail_on_error) + else: + LOG.info('We can not run validations if the Overcloud is not deployed') def _create_default_plan(mistral, plans, timeout=360):