Add support for plugin actions
implements blueprint mistral-pluggable-task-actions Change-Id: If12a0c6835edcabd33027555501dea4f473fc1f5
This commit is contained in:
parent
1ceb4b1e8a
commit
ebf225553d
49
doc/source/writing_a_plugin_action.rst
Normal file
49
doc/source/writing_a_plugin_action.rst
Normal file
@ -0,0 +1,49 @@
|
||||
How to write an Action Plugin
|
||||
=============================
|
||||
|
||||
1. Write a class based on mistral.actions.base.Actions
|
||||
::
|
||||
|
||||
from mistral.actions import base
|
||||
|
||||
class RunnerAction(base.Action):
|
||||
def __init__(self, param):
|
||||
# store the incomming params
|
||||
self.param = param
|
||||
|
||||
def run(self):
|
||||
# return your results here
|
||||
return {'status': 0}
|
||||
|
||||
2. Publish the class in a namespace
|
||||
(in your setup.cfg)
|
||||
|
||||
::
|
||||
|
||||
[entry_points]
|
||||
myproject.plugins.example =
|
||||
runner = solum.mistral_plugins.somefile:RunnerAction
|
||||
|
||||
3. Add the namespace into /etc/mistral/mistral.conf
|
||||
(don't overwrite "mistral.plugins.std")
|
||||
|
||||
::
|
||||
|
||||
action_plugins = mistral.plugins.std,myproject.plugins.example
|
||||
|
||||
4. Use your plugin
|
||||
|
||||
Note on naming the plugin.
|
||||
|
||||
* The namespace is "myproject.plugins.example"
|
||||
* The class is named "runner"
|
||||
* Now you can call the action "example.runner"
|
||||
|
||||
::
|
||||
|
||||
Workflow:
|
||||
tasks:
|
||||
myaction:
|
||||
action: example.runner
|
||||
parameters:
|
||||
param: avalue_to_pass_in
|
@ -30,6 +30,10 @@ rabbit_password = guest
|
||||
# Example: server=api,engine
|
||||
#server=all
|
||||
|
||||
# List of python module namespaces to search for plug-ins.
|
||||
# See: doc/source/writing_a_plugin_action.rst on how to write a plugin.
|
||||
action_plugins = mistral.actions.std
|
||||
|
||||
[api]
|
||||
# Host and port to bind the API server to
|
||||
host = 0.0.0.0
|
||||
|
@ -15,6 +15,7 @@
|
||||
# limitations under the License.
|
||||
|
||||
import inspect
|
||||
from oslo.config import cfg
|
||||
|
||||
from mistral.actions import base
|
||||
from mistral.actions import std_actions
|
||||
@ -26,36 +27,29 @@ from mistral.openstack.common import log as logging
|
||||
LOG = logging.getLogger(__name__)
|
||||
|
||||
_ACTION_CTX_PARAM = 'action_context'
|
||||
_STD_NAMESPACE = "std"
|
||||
|
||||
_NAMESPACES = {}
|
||||
|
||||
|
||||
def _find_or_create_namespace(name):
|
||||
def _find_or_create_namespace(full_name):
|
||||
name = full_name.split('.')[-1]
|
||||
ns = _NAMESPACES.get(name)
|
||||
|
||||
if not ns:
|
||||
ns = base.Namespace(name)
|
||||
ns = base.Namespace(full_name)
|
||||
_NAMESPACES[name] = ns
|
||||
|
||||
return ns
|
||||
|
||||
|
||||
def register_action_class(namespace_name, action_name, action_cls):
|
||||
_find_or_create_namespace(namespace_name).add(action_name, action_cls)
|
||||
|
||||
|
||||
def get_registered_namespaces():
|
||||
return _NAMESPACES.copy()
|
||||
|
||||
|
||||
def _register_standard_action_classes():
|
||||
register_action_class(_STD_NAMESPACE, "echo", std_actions.EchoAction)
|
||||
register_action_class(_STD_NAMESPACE, "http", std_actions.HTTPAction)
|
||||
register_action_class(_STD_NAMESPACE,
|
||||
"mistral_http", std_actions.MistralHTTPAction)
|
||||
register_action_class(_STD_NAMESPACE, "ssh", std_actions.SSHAction)
|
||||
register_action_class(_STD_NAMESPACE, "email", std_actions.SendEmailAction)
|
||||
def _register_action_classes():
|
||||
cfg.CONF.import_opt('action_plugins', 'mistral.config')
|
||||
for py_ns in cfg.CONF.action_plugins:
|
||||
ns = _find_or_create_namespace(py_ns)
|
||||
ns.log()
|
||||
|
||||
|
||||
def get_action_class(action_full_name):
|
||||
@ -160,5 +154,5 @@ def create_action(db_task):
|
||||
(db_task, e))
|
||||
|
||||
|
||||
# Registering standard actions on module load.
|
||||
_register_standard_action_classes()
|
||||
# Registering actions on module load.
|
||||
_register_action_classes()
|
||||
|
@ -15,9 +15,9 @@
|
||||
# limitations under the License.
|
||||
|
||||
import abc
|
||||
from stevedore import extension
|
||||
|
||||
from mistral.openstack.common import log as logging
|
||||
from mistral import exceptions as exc
|
||||
|
||||
LOG = logging.getLogger(__name__)
|
||||
|
||||
@ -86,24 +86,26 @@ class Action(object):
|
||||
class Namespace(object):
|
||||
"""Action namespace."""
|
||||
|
||||
def __init__(self, name):
|
||||
self.name = name
|
||||
self.action_classes = {} # action name -> action class
|
||||
|
||||
def add(self, action_name, action_cls):
|
||||
if action_name in self.action_classes:
|
||||
raise exc.ActionRegistrationException(
|
||||
"Action is already associated with namespace "
|
||||
"[action_cls=%s, namespace=%s" %
|
||||
(action_cls, self))
|
||||
|
||||
self.action_classes[action_name] = action_cls
|
||||
def __init__(self, namespace):
|
||||
self.name = namespace.split('.')[-1]
|
||||
self.mgr = extension.ExtensionManager(
|
||||
namespace=namespace,
|
||||
invoke_on_load=False)
|
||||
|
||||
def contains_action_name(self, name):
|
||||
return name in self.action_classes
|
||||
return name in self.mgr.names()
|
||||
|
||||
def get_action_class(self, name):
|
||||
return self.action_classes.get(name)
|
||||
# ExtensionManager has no "get"
|
||||
if self.contains_action_name(name):
|
||||
return self.mgr[name].plugin
|
||||
else:
|
||||
return None
|
||||
|
||||
def __len__(self):
|
||||
return len(self.action_classes)
|
||||
# ExtensionManager has no len()
|
||||
return len(self.mgr.names())
|
||||
|
||||
def log(self):
|
||||
for ext in self.mgr:
|
||||
LOG.debug('%s:%s' % (self.name, ext.name))
|
||||
|
@ -94,6 +94,11 @@ launch_opt = cfg.ListOpt(
|
||||
'api, engine, and executor.'
|
||||
)
|
||||
|
||||
action_plugins_opt = cfg.ListOpt(
|
||||
'action_plugins',
|
||||
default=['mistral.actions.std'],
|
||||
help='List of namespaces to search for plug-ins.')
|
||||
|
||||
|
||||
wf_trace_log_name_opt = cfg.StrOpt('workflow_trace_log_name',
|
||||
default='workflow_trace',
|
||||
@ -110,6 +115,7 @@ CONF.register_opts(db_opts, group='database')
|
||||
CONF.register_opts(rabbit_opts, group='rabbit')
|
||||
CONF.register_opts(executor_opts, group='executor')
|
||||
CONF.register_opt(wf_trace_log_name_opt)
|
||||
CONF.register_opt(action_plugins_opt)
|
||||
|
||||
CONF.register_cli_opt(use_debugger)
|
||||
CONF.register_cli_opt(launch_opt)
|
||||
|
@ -15,4 +15,5 @@ python-keystoneclient>=0.7.0
|
||||
networkx>=1.8
|
||||
six>=1.6.0
|
||||
SQLAlchemy>=0.7.8,<=0.9.99
|
||||
stevedore>=0.14
|
||||
yaql==0.2.1 # This is not in global requirements
|
||||
|
@ -30,3 +30,10 @@ mistral.engine.drivers =
|
||||
|
||||
mistral.executor.drivers =
|
||||
default = mistral.engine.drivers.default.executor:DefaultExecutor
|
||||
|
||||
mistral.actions.std =
|
||||
echo = mistral.actions.std_actions:EchoAction
|
||||
http = mistral.actions.std_actions:HTTPAction
|
||||
mistral_http = mistral.actions.std_actions:MistralHTTPAction
|
||||
ssh = mistral.actions.std_actions:SSHAction
|
||||
email = mistral.actions.std_actions:SendEmailAction
|
||||
|
Loading…
x
Reference in New Issue
Block a user