JavaScript action: part 1

* Added new action - std.javascript
 * Use V8 JS engine for now
 * Allow to use any JS engine in future

TODO (next commit):
 * Add guide on how install PyV8
 * Work with data context in JS action

Partially implements blueprint mistral-javascript-action

Change-Id: I5bd940e75f5224d813c9cd865f9411e90bec09c1
This commit is contained in:
Nikolay Mahotkin 2015-01-28 14:18:24 +03:00
parent 8114ed8f2f
commit 50972a9779
5 changed files with 97 additions and 0 deletions

View File

@ -23,6 +23,7 @@ import smtplib
from mistral.actions import base
from mistral import exceptions as exc
from mistral.openstack.common import log as logging
from mistral.utils import javascript
from mistral.utils import ssh_utils
@ -326,3 +327,20 @@ class SSHAction(base.Action):
def test(self):
# TODO(rakhmerov): Implement.
return None
class JavaScriptAction(base.Action):
"""Evaluates given JavaScript.
"""
def __init__(self, script):
self.script = script
def run(self):
try:
return javascript.evaluate(self.script)
except Exception as e:
raise exc.ActionException("JavaScriptAction failed: %s" % str(e))
def test(self):
return self.script

View File

@ -93,6 +93,7 @@ class ActionFactoryTest(base.DbTestCase):
self._assert_single_item(action_list, name="std.http")
self._assert_single_item(action_list, name="std.mistral_http")
self._assert_single_item(action_list, name="std.ssh")
self._assert_single_item(action_list, name="std.javascript")
self._assert_single_item(action_list, name="nova.servers_get")
self._assert_single_item(action_list, name="nova.volumes_delete")
@ -110,6 +111,8 @@ class ActionFactoryTest(base.DbTestCase):
a_m.get_action_class("std.mistral_http"))
self.assertEqual(std.SendEmailAction,
a_m.get_action_class("std.email"))
self.assertEqual(std.JavaScriptAction,
a_m.get_action_class("std.javascript"))
def test_resolve_adhoc_action_name(self):
wb = spec_parser.get_workbook_spec_from_yaml(

View File

@ -0,0 +1,28 @@
# Copyright 2015 - Mirantis, Inc.
#
# Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License.
# You may obtain a copy of the License at
#
# http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS,
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
# See the License for the specific language governing permissions and
# limitations under the License.
import mock
from mistral.actions import std_actions as std
from mistral.tests import base
from mistral.utils import javascript
class JavascriptActionTest(base.BaseTest):
@mock.patch.object(javascript, 'evaluate', mock.Mock(return_value="3"))
def test_js_action(self):
script = "1 + 2"
action = std.JavaScriptAction(script)
self.assertEqual("3", action.run())

View File

@ -0,0 +1,47 @@
# Copyright 2015 - Mirantis, Inc.
#
# Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License.
# You may obtain a copy of the License at
#
# http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS,
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
# See the License for the specific language governing permissions and
# limitations under the License.
import abc
from mistral import exceptions as exc
from mistral.openstack.common import importutils
_PYV8 = importutils.try_import('PyV8')
class JSEvaluator(object):
@classmethod
@abc.abstractmethod
def evaluate(cls, script):
pass
class V8Evaluator(JSEvaluator):
@classmethod
def evaluate(cls, script):
if not _PYV8:
raise exc.MistralException(
"PyV8 module is not available. Please install PyV8."
)
with _PYV8.JSContext() as ctx:
return ctx.eval(script)
# TODO(nmakhotkin) Make it configurable.
EVALUATOR = V8Evaluator
def evaluate(script):
return EVALUATOR.evaluate(script)

View File

@ -48,3 +48,4 @@ mistral.actions =
std.mistral_http = mistral.actions.std_actions:MistralHTTPAction
std.ssh = mistral.actions.std_actions:SSHAction
std.email = mistral.actions.std_actions:SendEmailAction
std.javascript = mistral.actions.std_actions:JavaScriptAction