Make OpenStack related data available in actions

* Make OpenStack related data accessible via context in action DSL
   without explicitly defining parameters such as auth_token and project_id
 * Make Openstack data accessible via action_context parameter
   for new Actions
 * Unit tests

Implements blueprint: mistral-openstack-data-accessible-by-default

Change-Id: I9b6802d90c0ac17e0494d2025897ce5cdd02f4ee
This commit is contained in:
Nikolay Mahotkin
2014-06-18 17:31:38 +04:00
committed by Renat Akhmerov
parent f814baae8c
commit e50d1eaa9f
7 changed files with 86 additions and 20 deletions

View File

@@ -4,10 +4,10 @@ Namespaces:
actions:
create-vm:
base-parameters:
url: '{$.nova_url}/{$.project_id}/servers'
url: '{$.nova_url}/{$.openstack.project_id}/servers'
method: POST
headers:
X-Auth-Token: $.auth_token
X-Auth-Token: $.openstack.auth_token
Content-Type: application/json
body:
server:
@@ -26,7 +26,5 @@ Workflow:
image_id: $.image_id
flavor_id: $.flavor_id
nova_url: $.nova_url
project_id: $.project_id
auth_token: $.auth_token
publish:
vm_id: vm_id
vm_id: $.vm_id

View File

@@ -72,15 +72,20 @@ def get_action_class(action_full_name):
return ns.get_action_class(arr[1])
def _get_action_context(db_task):
return {
def _get_action_context(db_task, openstack_context):
result = {
'workbook_name': db_task['workbook_name'],
'execution_id': db_task['execution_id'],
'task_id': db_task['id'],
'task_name': db_task['name'],
'task_tags': db_task['tags']
'task_tags': db_task['tags'],
}
if openstack_context:
result.update({'openstack': openstack_context})
return result
def _has_action_context_param(action_cls):
arg_spec = inspect.getargspec(action_cls.__init__)
@@ -88,7 +93,7 @@ def _has_action_context_param(action_cls):
return _ACTION_CTX_PARAM in arg_spec.args
def _create_adhoc_action(db_task):
def _create_adhoc_action(db_task, openstack_context):
task_spec = tasks.TaskSpec(db_task['task_spec'])
full_action_name = task_spec.get_full_action_name()
@@ -108,7 +113,7 @@ def _create_adhoc_action(db_task):
action_context = None
if _has_action_context_param(base_cls):
action_context = _get_action_context(db_task)
action_context = _get_action_context(db_task, openstack_context)
if not base_cls:
msg = 'Ad-hoc action base class is not registered ' \
@@ -130,10 +135,14 @@ def create_action(db_task):
action_cls = get_action_class(full_action_name)
openstack_ctx = db_task['in_context'].get('openstack')
if not action_cls:
# If action is not found in registered actions try to find ad-hoc
# action definition.
action = _create_adhoc_action(db_task)
if openstack_ctx is not None:
db_task['parameters'].update({'openstack': openstack_ctx})
action = _create_adhoc_action(db_task, openstack_ctx)
if action:
return action
@@ -145,7 +154,8 @@ def create_action(db_task):
action_params = db_task['parameters'] or {}
if _has_action_context_param(action_cls):
action_params[_ACTION_CTX_PARAM] = _get_action_context(db_task)
action_params[_ACTION_CTX_PARAM] = _get_action_context(db_task,
openstack_ctx)
try:
return action_cls(**action_params)

View File

@@ -278,7 +278,7 @@ class Engine(object):
def _add_variables_to_data_flow_context(cls, context, execution):
db_workbook = db_api.workbook_get(execution['workbook_name'])
data_flow.add_token_to_context(context, db_workbook)
data_flow.add_openstack_data_to_context(context, db_workbook)
data_flow.add_execution_to_context(context, execution)
@classmethod

View File

@@ -82,14 +82,14 @@ def get_outbound_context(task, output=None):
return out_context
def add_token_to_context(context, db_workbook):
def add_openstack_data_to_context(context, db_workbook):
if context is None:
context = {}
if CONF.pecan.auth_enable:
workbook_ctx = trusts.create_context(db_workbook)
if workbook_ctx:
context.update(workbook_ctx.to_dict())
context.update({'openstack': workbook_ctx.to_dict()})
return context

View File

@@ -19,6 +19,7 @@ import json
from mistral.actions import action_factory as a_f
from mistral.actions import std_actions as std
from mistral.engine import data_flow
from mistral import exceptions
from mistral.openstack.common import log as logging
from mistral.tests import base
@@ -35,6 +36,7 @@ DB_TASK = {
'workbook_name': 'my_workbook',
'execution_id': '123',
'id': '123',
'in_context': {},
'tags': ['deployment', 'test'],
'parameters': {
'url': 'http://some.url',
@@ -76,6 +78,7 @@ DB_TASK_ADHOC = {
'workbook_name': 'my_workbook',
'execution_id': '123',
'id': '123',
'in_context': {},
'tags': ['deployment', 'test'],
'parameters': {
'first': 'Tango',
@@ -156,6 +159,59 @@ class ActionFactoryTest(base.BaseTest):
self.assertEqual(db_task['id'],
headers['Mistral-Task-Id'])
def test_create_adhoc_action_with_openstack_context(self):
db_task = copy.copy(DB_TASK_ADHOC)
db_task['action_spec']['output'] = {'res': '{$}'}
db_task['in_context'].update({
'openstack': {
'auth_token': '123',
'project_id': '321'
}
})
base_parameters = db_task['action_spec']['base-parameters']
base_parameters['output'] = ("{$.openstack.auth_token}"
"{$.openstack.project_id}")
action = a_f.create_action(db_task)
self.assertEqual({'res': "123321"}, action.run())
def test_create_adhoc_action_no_openstack_context(self):
db_task = copy.copy(DB_TASK_ADHOC)
db_task['action_spec']['output'] = {'res': '{$}'}
db_task['in_context'].update({
'openstack': None
})
base_parameters = db_task['action_spec']['base-parameters']
base_parameters['output'] = "$.openstack.auth_token"
action = a_f.create_action(db_task)
self.assertEqual({'res': "$.openstack.auth_token"}, action.run())
def test_create_no_adhoc_action_with_openstack_context(self):
db_task = copy.copy(DB_TASK)
db_task['task_spec']['action'] = 'std.http'
db_task['in_context'].update({
'openstack': {
'auth_token': '123',
'project_id': '321'
}
})
## In case of no-adhoc action we should evaluate task parameters
## to see what we need.
task_spec = db_task['task_spec']
task_spec['parameters'] = {
'url': "http://some/{$.openstack.project_id}/servers",
}
db_task['parameters'] = data_flow.evaluate_task_parameters(
db_task, db_task['in_context'])
action = a_f.create_action(db_task)
self.assertEqual("http://some/321/servers", action.url)
def test_get_ssh_action(self):
db_task = copy.copy(DB_TASK)
db_task['task_spec'] = {
@@ -181,7 +237,7 @@ class ActionFactoryTest(base.BaseTest):
self.assertEqual("10.0.0.1", action.host)
def test_adhoc_echo_action(self):
db_task = DB_TASK_ADHOC.copy()
db_task = copy.copy(DB_TASK_ADHOC)
action_spec = db_task['action_spec']
# With dic-like output formatter.

View File

@@ -76,6 +76,8 @@ SAMPLE_TASK = {
},
'namespace': 'MyRest'
},
'in_context': {},
'parameters': {},
'task_spec': {
'action': 'MyRest.my-action',
'name': TASK_NAME},

View File

@@ -447,11 +447,11 @@ class DataFlowTest(base.EngineTestCase):
task = self._assert_single_item(tasks, name=task_name)
context = task['in_context']
openstack_context = task['in_context']['openstack']
self.assertIn("auth_token", context)
self.assertEqual(TOKEN, context['auth_token'])
self.assertEqual(USER_ID, context["user_id"])
self.assertIn("auth_token", openstack_context)
self.assertEqual(TOKEN, openstack_context['auth_token'])
self.assertEqual(USER_ID, openstack_context["user_id"])
self.engine.convey_task_result(task['id'], states.SUCCESS, {})