Add new interface to run arbitrary playbooks from a plan

This change is the first step to providing a path to remove the mistral
"derived_params" workflows. Deployers will now be able to execute playbooks
from within a given plan by passing in the `playbook_parameters` key which
contains a dictionary of playbook file paths, and all options applied to a
given playbook.

Story: 2007419
Task: 39118

Change-Id: I26ea1c01e17513d001e311d68fd239d3ba8c8a0d
Signed-off-by: Kevin Carter <kecarter@redhat.com>
This commit is contained in:
Kevin Carter 2020-03-20 13:53:24 -05:00 committed by Kevin Carter (cloudnull)
parent 337820e800
commit 0464bdc17f
3 changed files with 145 additions and 1 deletions

View File

@ -0,0 +1,26 @@
---
features:
- |
A new interface has been created allowing deployers to run arbitrary
playbooks which are defined within a deployment plan. This interface is
being created to replace the existing Mistral interface, which is largely
used for HCI and NFV use cases. The interface will now process playbooks
when they're defined within a plan under the `playbook_parameters` key.
Playbook entries can be defined with, and without the base path. If no base
path is defined within the entry, the interface will fall back to the
constant tripleo playbook path, `/usr/share/ansible/tripleo-playbooks`.
Options fined within a playbook entry will be passed into the playbook at
runtime using extra-vars.
* Interface usage example
.. code-block:: yaml
playbook_parameters:
sample-playbook-0.yaml:
x: 1
y: a
/path/to/sample-playbook-1.yaml:
x: a
y: 1

View File

@ -119,6 +119,86 @@ class TestParameterWorkflows(utils.TestCommand):
'user_inputs': {
'num_phy_cores_per_numa_node_for_pmd': 2}})
@mock.patch('yaml.safe_load')
@mock.patch("six.moves.builtins.open")
@mock.patch('tripleoclient.utils.run_ansible_playbook', autospec=True)
@mock.patch('tripleoclient.utils.get_tripleo_ansible_inventory',
autospec=True)
def test_invoke_plan_env_workflows_single_playbook(self,
mock_inventory,
mock_playbook,
mock_open,
mock_safe_load):
plan_env_data = {
'name': 'overcloud',
'playbook_parameters': {
'sample-playbook-1.yaml': {
'num_phy_cores_per_numa_node_for_pmd': 2
}
}
}
mock_safe_load.return_value = plan_env_data
parameters.invoke_plan_env_workflows(
self.app.client_manager,
'overcloud',
'the-plan-environment.yaml'
)
calls = [
mock.call(
playbook='sample-playbook-1.yaml',
inventory=mock.ANY,
workdir=mock.ANY,
playbook_dir=mock.ANY,
extra_vars={'num_phy_cores_per_numa_node_for_pmd': 2}
)
]
mock_playbook.assert_has_calls(calls, any_order=True)
@mock.patch('yaml.safe_load')
@mock.patch("six.moves.builtins.open")
@mock.patch('tripleoclient.utils.run_ansible_playbook', autospec=True)
@mock.patch('tripleoclient.utils.get_tripleo_ansible_inventory',
autospec=True)
def test_invoke_plan_env_workflows_multi_playbook(self,
mock_inventory,
mock_playbook,
mock_open,
mock_safe_load):
plan_env_data = {
'name': 'overcloud',
'playbook_parameters': {
'sample-playbook-1.yaml': {
'num_phy_cores_per_numa_node_for_pmd': 2
},
'/playbook/dir-1/sample-playbook-2.yaml': {
'some_opt': 0
}
}
}
mock_safe_load.return_value = plan_env_data
parameters.invoke_plan_env_workflows(
self.app.client_manager,
'overcloud',
'the-plan-environment.yaml'
)
calls = [
mock.call(
playbook='sample-playbook-1.yaml',
inventory=mock.ANY,
workdir=mock.ANY,
playbook_dir=mock.ANY,
extra_vars={'num_phy_cores_per_numa_node_for_pmd': 2}
),
mock.call(
playbook='sample-playbook-2.yaml',
inventory=mock.ANY,
workdir=mock.ANY,
playbook_dir='/playbook/dir-1',
extra_vars={'some_opt': 0}
)
]
mock_playbook.assert_has_calls(calls, any_order=True)
@mock.patch('yaml.safe_load')
@mock.patch("six.moves.builtins.open")
def test_invoke_plan_env_workflow_failed(self, mock_open,

View File

@ -11,13 +11,16 @@
# under the License.
import logging
import os
import re
import yaml
from tripleo_common.actions import parameters
from tripleoclient.constants import ANSIBLE_TRIPLEO_PLAYBOOKS
from tripleoclient.constants import UNUSED_PARAMETER_EXCLUDES_RE
from tripleoclient import exceptions
from tripleoclient import utils
from tripleoclient.workflows import base
from tripleoclient.workflows import roles
@ -40,7 +43,42 @@ def invoke_plan_env_workflows(clients, stack_name, plan_env_file):
raise exceptions.PlanEnvWorkflowError('File (%s) is not found: '
'%s' % (plan_env_file, exc))
if plan_env_data and "workflow_parameters" in plan_env_data:
if plan_env_data and "playbook_parameters" in plan_env_data:
static_inventory = utils.get_tripleo_ansible_inventory(
ssh_user='heat-admin',
stack=stack_name,
undercloud_connection='local',
return_inventory_file_path=True
)
with utils.TempDirs() as tmp:
for pb, pb_vars in plan_env_data["playbook_parameters"].items():
print('Invoking playbook ({}) specified in plan-environment'
' file'.format(pb))
LOG.debug(
'Running playbook "{}" with the'
' following options {}.'.format(
pb,
pb_vars
)
)
playbook_dir = os.path.dirname(pb)
if not playbook_dir:
playbook_dir = ANSIBLE_TRIPLEO_PLAYBOOKS
utils.run_ansible_playbook(
playbook=os.path.basename(pb),
inventory=static_inventory,
workdir=tmp,
playbook_dir=playbook_dir,
extra_vars=pb_vars
)
# NOTE(cloudnull): Remove this when mistral is gone.
elif plan_env_data and "workflow_parameters" in plan_env_data:
LOG.warning(
'The workflow_parameters interface is deprecated, begin using'
' playbook_parameters instead.'
)
for wf_name, wf_inputs in plan_env_data["workflow_parameters"].items():
print('Invoking workflow (%s) specified in plan-environment '
'file' % wf_name)