Select Roles Workflow

This patch adds a workflow that takes a list of role names as
input and populates roles_data.yaml in container in Swift with
respective roles from 'roles directory'.

Change-Id: I6c2a0d120d3e362df1ce1b701597d062783a48a4
Implements: blueprint tripleo-common-select-roles-workflow
This commit is contained in:
Ryan Brady 2017-12-15 09:21:43 -05:00
parent a9e26a8d77
commit f70830b425
5 changed files with 151 additions and 35 deletions

View File

@ -0,0 +1,6 @@
---
features:
- |
Adds a workflow that takes a list of role names as input and populates
roles_data.yaml in deployment plan with respective roles from
the '/roles directory'.

View File

@ -113,6 +113,7 @@ mistral.actions =
tripleo.plan.update_from_dir = tripleo_common.actions.plan:UpdatePlanFromDirAction
tripleo.plan.update_networks = tripleo_common.actions.plan:UpdateNetworksAction
tripleo.plan.update_plan_environment = tripleo_common.actions.plan:UpdatePlanEnvironmentAction
tripleo.plan.gather_roles = tripleo_common.actions.plan:GatherRolesAction
tripleo.plan.update_roles = tripleo_common.actions.plan:UpdateRolesAction
tripleo.plan.validate_roles = tripleo_common.actions.plan:ValidateRolesDataAction
tripleo.logging_to_swift.format_messages = tripleo_common.actions.logging_to_swift:FormatMessagesAction

View File

@ -434,3 +434,32 @@ class UpdateRolesAction(base.TripleOAction):
save_roles = sorted(role_data_to_save, key=itemgetter('name'),
reverse=True)
return actions.Result(data={'roles': save_roles})
class GatherRolesAction(actions.Action):
"""Gather role definitions
Check each role name from the input, check if it exists in
roles_data.yaml, if yes, use that role definition, if not, get the
role definition from roles directory. Return the gathered role
definitions.
"""
def __init__(self, role_names, current_roles, available_roles):
super(GatherRolesAction, self).__init__()
self.role_names = role_names
self.current_roles = current_roles
self.available_roles = available_roles
def run(self, context):
err_msgs = []
# merge the two lists of dicts in the proper order. last in wins, so
# a current role shall be favored over an available role.
gathered_roles = [role for role in {
x['name']: x for x in self.available_roles + self.current_roles
}.values() if role['name'] in self.role_names]
if err_msgs:
return actions.Result(error="/n".join(err_msgs))
return actions.Result(data={'gathered_roles': gathered_roles})

View File

@ -273,7 +273,6 @@ class DeletePlanActionTest(base.TestCase):
swift = mock.MagicMock()
swift.get_account.return_value = ({}, [
{'name': self.container_name},
{'name': "%s-swift-rings" % self.container_name},
{'name': 'test'},
])
swift.get_container.return_value = (
@ -305,39 +304,7 @@ class DeletePlanActionTest(base.TestCase):
swift.delete_object.assert_has_calls(
mock_calls, any_order=True)
mock_calls = [
mock.call(self.container_name),
mock.call("%s-swift-rings" % self.container_name)
]
self.assertEqual(2, swift.delete_container.call_count)
swift.delete_container.assert_has_calls(mock_calls)
@mock.patch('tripleo_common.actions.base.TripleOAction.get_object_client')
@mock.patch(
'tripleo_common.actions.base.TripleOAction.get_orchestration_client')
def test_run_no_containers(
self, get_orchestration_client, get_obj_client_mock):
# setup swift
swift = mock.MagicMock()
# There are no swift containers because they were either accidentally
# removed or not created.
swift.get_account.return_value = ({}, [])
get_obj_client_mock.return_value = swift
# setup heat
heat = mock.MagicMock()
heat.stacks.get = mock.Mock(
side_effect=heatexceptions.HTTPNotFound)
get_orchestration_client.return_value = heat
action = plan.DeletePlanAction(self.container_name)
action.run(self.ctx)
# The operation was successfully finished and we didn't try to remove
# nonexistent containers.
self.assertEqual(0, swift.delete_container.call_count)
swift.delete_container.assert_called_with(self.container_name)
class ListRolesActionTest(base.TestCase):
@ -603,3 +570,23 @@ class UpdateRolesActionTest(base.TestCase):
result = action.run(self.ctx)
self.assertEqual(result.data, {'roles': [UPDATED_ROLE_OBJ, ]})
class GatherRolesActionTest(base.TestCase):
def setUp(self):
super(GatherRolesActionTest, self).setUp()
self.container = 'overcloud'
self.ctx = mock.MagicMock()
self.current_roles = [SAMPLE_ROLE_OBJ, SAMPLE_ROLE_2_OBJ]
self.available_role = SAMPLE_ROLE_OBJ.copy()
self.available_role['name'] = 'test'
def test_roles_gathered(self):
action = plan.GatherRolesAction(['sample', 'test'], self.current_roles,
[self.available_role])
result = action.run(self.ctx)
# assert that a role was loaded from self.current_roles
self.assertTrue(result.data['gathered_roles'],
[SAMPLE_ROLE_OBJ, self.available_role])

View File

@ -1289,4 +1289,97 @@ workflows:
execution: <% execution() %>
updated_roles: <% $.get('updated_roles', []) %>
on-success:
- fail: <% $.get('status') = "FAILED" %>
- fail: <% $.get('status') = "FAILED" %>
select_roles:
description: >
takes a list of role names as input and populates roles_data.yaml in
container in Swift with respective roles from 'roles directory'
input:
- container
- role_names
- roles_data_file: 'roles_data.yaml'
- replace_all: true
- queue_name: tripleo
tags:
- tripleo-common-managed
tasks:
get_available_roles:
workflow: list_available_roles
input:
container: <% $.container %>
queue_name: <% $.queue_name %>
publish:
available_roles: <% task().result.available_roles %>
on-success: get_current_roles
on-error: notify_zaqar
publish-on-error:
status: FAILED
message: <% task().result %>
get_current_roles:
workflow: list_roles
input:
container: <% $.container %>
roles_data_file: <% $.roles_data_file %>
queue_name: <% $.queue_name %>
publish:
current_roles: <% task().result.roles_data %>
on-success: gather_roles
on-error: notify_zaqar
publish-on-error:
status: FAILED
message: <% task().result %>
gather_roles:
description: >
for each role name from the input, check if it exists in
roles_data.yaml, if yes, use that role definition, if not, get the
role definition from roles directory. Use the gathered roles
definitions as input to updateRolesWorkflow - this ensures
configuration of the roles which are already in roles_data.yaml
will not get overridden by data from roles directory
action: tripleo.plan.gather_roles
input:
role_names: <% $.role_names %>
current_roles: <% $.current_roles %>
available_roles: <% $.available_roles %>
publish:
gathered_roles: <% task().result.gathered_roles %>
on-success: call_update_roles_workflow
on-error: notify_zaqar
publish-on-error:
status: FAILED
message: <% task().result %>
call_update_roles_workflow:
workflow: update_roles
input:
container: <% $.container %>
roles: <% $.gathered_roles %>
roles_data_file: <% $.roles_data_file %>
replace_all: <% $.replace_all %>
queue_name: <% $.queue_name %>
on-complete: notify_zaqar
publish:
selected_roles: <% task().result.updated_roles %>
status: SUCCESS
publish-on-error:
status: FAILED
message: <% task().result %>
notify_zaqar:
action: zaqar.queue_post
input:
queue_name: <% $.queue_name %>
messages:
body:
type: tripleo.plan_management.v1.select_roles
payload:
status: <% $.status %>
message: <% $.get('message', '') %>
execution: <% execution() %>
selected_roles: <% $.get('selected_roles', []) %>
on-success:
- fail: <% $.get('status') = "FAILED" %>