Removing left v1 related stuff (resources, DSL specs)

Change-Id: Ie85296368e326cfad1da1dfb99e84e24107051e2
This commit is contained in:
Renat Akhmerov 2015-04-08 13:45:57 +06:00
parent f74541085d
commit 3544888543
42 changed files with 80 additions and 1584 deletions

View File

@ -21,7 +21,6 @@ from mistral.actions import action_factory
from mistral.actions import generator_factory from mistral.actions import generator_factory
from mistral.db.v2 import api as db_api from mistral.db.v2 import api as db_api
from mistral import exceptions as exc from mistral import exceptions as exc
from mistral import expressions as expr
from mistral.openstack.common import log as logging from mistral.openstack.common import log as logging
from mistral.services import actions from mistral.services import actions
from mistral import utils from mistral import utils
@ -168,42 +167,3 @@ def _has_argument(action, attributes, argument_name):
def has_action_context(action, attributes): def has_action_context(action, attributes):
return _has_argument(action, attributes, _ACTION_CTX_PARAM) return _has_argument(action, attributes, _ACTION_CTX_PARAM)
def resolve_adhoc_action_name(workbook, action_name):
action_spec = workbook.get_action(action_name)
if not action_spec:
msg = ('Ad-hoc action class is not registered '
'[workbook=%s, action=%s, action_spec=%s]' %
(workbook, action_name, action_spec))
raise exc.ActionException(msg)
base_cls = get_action_class(action_spec.clazz)
if not base_cls:
msg = ('Ad-hoc action base class is not registered '
'[workbook=%s, action=%s, base_class=%s]' %
(workbook, action_name, base_cls))
raise exc.ActionException(msg)
return action_spec.clazz
def convert_adhoc_action_params(workbook, action_name, params):
base_params = workbook.get_action(action_name).base_parameters
if not base_params:
return {}
return expr.evaluate_recursively(base_params, params)
def convert_adhoc_action_result(workbook, action_name, result):
transformer = workbook.get_action(action_name).output
if not transformer:
return result
# Use base action result as a context for evaluating expressions.
return expr.evaluate_recursively(transformer, result)

View File

@ -1,53 +0,0 @@
Namespaces:
MyRest:
class: std.mistral_http
base-parameters:
method: GET
headers:
X-Auth-Token: <% $.auth_token %>
actions:
async-action:
base-parameters:
url: http://some_host/service/action/execute
headers:
Content-Type: 'application/json'
parameters:
- input1
- input2
output:
Workflow:
tasks:
start-task:
action: MyRest.async-action
parameters:
input1: foo
input2: bar
on-success:
task-one
on-error:
- task-three
- task-four
on-finish:
task-two
task-one:
action: MyRest.async-action
on-success: task-two
task-two:
action: MyRest.async-action
task-three:
action: MyRest.async-action
task-four:
action: MyRest.async-action
Triggers:
my-cron:
type: periodic
tasks: start-task
parameters:
cron-pattern: "* * * * *"

View File

@ -1,7 +0,0 @@
Workflow:
tasks:
task1:
action: std.http
parameters:
method: GET
url: http://some_url

View File

@ -1,26 +0,0 @@
Namespaces:
MyRest:
class: std.mistral_http
base-parameters:
method: GET
headers:
X-Auth-Token: <% $.auth_token %>
actions:
create-vm:
base-parameters:
url: http://some_host/service/action/execute
headers:
Content-Type: 'application/json'
parameters:
- image_id
- flavor_id
output:
Workflow:
tasks:
create-vms:
action: MyRest.create-vm
parameters:
image_id: 1234
flavor_id: 42

View File

@ -1,17 +0,0 @@
Namespaces:
Nova:
actions:
create-vm:
class: std.http
base-parameters:
url: http://path_to_nova/url_for_create
output:
vm_id: <% $.base_output.server_id %>
Workflow:
tasks:
std_http_task:
action: std.http
parameters:
method: GET
url: http://some_url

View File

@ -1,20 +0,0 @@
Namespaces:
MyActions:
actions:
concat:
class: std.echo
base-parameters:
output: '<% $.left %> <% $.right %>'
parameters:
- left
- right
output:
string: <% $.output %>
Workflow:
tasks:
build_name:
action: MyActions.concat
parameters:
left: Stormin
right: Stanley

View File

@ -1,34 +0,0 @@
Namespaces:
MyActions:
actions:
concat:
class: std.echo
base-parameters:
output: '<% $.left %> <% $.right %>'
parameters:
- left
- right
output:
string: <% $.output %>
start:
class: std.echo
base-parameters:
output: 'Starting...'
output:
info: <% $.output %>
Workflow:
tasks:
startup:
action: MyActions.start
build_name:
action: MyActions.concat
parameters:
left: Stormin
right: Stanley
greet:
requires: [startup, build_name]
action: MyActions.concat
parameters:
left: Greetings
right: <% $.string %>

View File

@ -1,62 +0,0 @@
Namespaces:
MyService:
# These ad-hoc actions based on std.echo have parameters only for test
# purposes. In practice, it's more convenient just to use std.echo and
# specify parameter 'output'.
actions:
concat:
class: std.echo
base-parameters:
output: '<% $.left %> <% $.right %>'
parameters:
- left
- right
output:
string: <% $ %>
Workflow:
# context = {
# 'person': {
# 'first_name': 'John',
# 'last_name': 'Doe',
# 'address': {
# 'street': '124352 Broadway Street',
# 'city': 'Gloomington',
# 'country': 'USA'
# }
# }
# }
tasks:
build_full_name:
action: MyService.concat
parameters:
left: <% $.person.first_name %>
right: <% $.person.last_name %>
publish:
full_name: <% $.string %>
build_greeting:
requires: [build_full_name]
action: MyService.concat
parameters:
left: Dear
right: <% $.full_name %>
publish:
greeting: <% $.string %>
build_address:
requires: [build_full_name]
action: MyService.concat
parameters:
left: To
right: <% $.full_name %>
publish:
address: <% $.string %>
send_greeting:
requires: [build_address, build_greeting]
action: MyService.concat
parameters:
left: '<% $.address %>.'
right: '<% $.greeting %>,..'

View File

@ -1,67 +0,0 @@
Namespaces:
MyService:
# These ad-hoc actions based on std.echo have parameters only for test
# purposes. In practice, it's more convenient just to use std.echo and
# specify parameter 'output'.
actions:
build_full_name:
class: std.echo
base-parameters:
output: '<% $.first_name %> <% $.last_name %>'
parameters:
- first_name
- last_name
output:
full_name: <% $ %>
build_greeting:
class: std.echo
base-parameters:
output: Cheers!
output:
greeting: <% $ %>
send_greeting:
class: std.echo
base-parameters:
output: True
parameters:
- f_name
- greet_msg
output:
greeting_sent: <% $ %>
Workflow:
# context = {
# 'person': {
# 'first_name': 'John',
# 'last_name': 'Doe',
# 'address': {
# 'street': '124352 Broadway Street',
# 'city': 'Gloomington',
# 'country': 'USA'
# }
# }
# }
tasks:
build_full_name:
action: MyService.build_full_name
parameters:
first_name: <% $.person.first_name %>
last_name: <% $.person.last_name %>
publish:
f_name: <% $.full_name %>
build_greeting:
requires: [build_full_name]
action: MyService.build_greeting
publish:
greet_msg: <% $.greeting %>
send_greeting:
requires: [build_full_name, build_greeting]
action: MyService.send_greeting
parameters:
f_name: <% $.f_name %>
greet_msg: <% $.greet_msg %>

View File

@ -1,72 +0,0 @@
Namespaces:
MyService:
# These ad-hoc actions based on std.echo have parameters only for test
# purposes. In practice, it's more convenient just to use std.echo and
# specify parameter 'output'.
actions:
build_full_name:
class: std.echo
base-parameters:
output: '<% $.first_name %> <% $.last_name %>'
parameters:
- first_name
- last_name
output:
full_name: <% $ %>
build_greeting:
class: std.echo
base-parameters:
output: 'Hello, <% $.full_name %>!'
parameters:
- full_name
output:
greeting: <% $ %>
send_greeting:
class: std.echo
base-parameters:
output: True
parameters:
- greeting
output:
greeting_sent: <% $ %>
Workflow:
# context = {
# 'person': {
# 'first_name': 'John',
# 'last_name': 'Doe',
# 'address': {
# 'street': '124352 Broadway Street',
# 'city': 'Gloomington',
# 'country': 'USA'
# }
# }
# }
tasks:
build_full_name:
action: MyService.build_full_name
parameters:
first_name: <% $.person.first_name %>
last_name: <% $.person.last_name %>
publish:
f_name: <% $.full_name %>
on-success: build_greeting
build_greeting:
action: MyService.build_greeting
parameters:
full_name: <% $.f_name %>
publish:
greet_msg: <% $.greeting %>
on-success: send_greeting
send_greeting:
action: MyService.send_greeting
parameters:
greeting: <% $.task.build_greeting.greeting %>
publish:
sent: <% $.greeting_sent %>

View File

@ -1,53 +0,0 @@
Namespaces:
MyService:
actions:
# These ad-hoc actions based on std.echo have parameters only for test
# purposes. In practice, it's more convenient just to use std.echo and
# specify parameter 'output'.
build_full_name:
class: std.echo
base-parameters:
output: '<% $.first_name %> <% $.last_name %>'
parameters:
- first_name
- last_name
output:
full_name: <% $ %>
build_greeting:
class: std.echo
base-parameters:
output: 'Hello, <% $.full_name %>!'
parameters:
- full_name
output:
greeting: <% $ %>
Workflow:
# context = {
# 'person': {
# 'first_name': 'John',
# 'last_name': 'Doe',
# 'address': {
# 'street': '124352 Broadway Street',
# 'city': 'Gloomington',
# 'country': 'USA'
# }
# }
# }
tasks:
build_full_name:
action: MyService.build_full_name
parameters:
first_name: <% $.person.first_name %>
last_name: <% $.person.last_name %>
publish:
f_name: <% $.full_name %>
build_greeting:
requires: [build_full_name]
action: MyService.build_greeting
parameters:
full_name: <% $.f_name %>

View File

@ -1,56 +0,0 @@
Namespaces:
MyService:
# These ad-hoc actions based on std.echo have parameters only for test
# purposes. In practice, it's more convenient just to use std.echo and
# specify parameter 'output'.
actions:
build_full_name:
class: std.echo
base-parameters:
output: '<% $.first_name %> <% $.last_name %>'
parameters:
- first_name
- last_name
output:
full_name: <% $ %>
build_greeting:
class: std.echo
base-parameters:
output: 'Hello, <% $.full_name %>!'
parameters:
- full_name
output:
greeting:
greet_message: <% $ %>
Workflow:
# context = {
# 'person': {
# 'first_name': 'John',
# 'last_name': 'Doe',
# 'address': {
# 'street': '124352 Broadway Street',
# 'city': 'Gloomington',
# 'country': 'USA'
# }
# }
# }
tasks:
build_full_name:
action: MyService.build_full_name
parameters:
first_name: <% $.person.first_name %>
last_name: <% $.person.last_name %>
publish:
f_name: <% $.full_name %>
on-success: build_greeting
build_greeting:
action: MyService.build_greeting
parameters:
full_name: <% $.f_name %>
publish:
greet_msg: <% $.greeting %>

View File

@ -1,4 +0,0 @@
Workflow:
tasks:
glance_image_list:
action: glance.images_list

View File

@ -1,15 +0,0 @@
Workflow:
tasks:
image_list:
action: glance.images_list
publish:
image_id: <% $[0].id %>
on-success: image_get
image_get:
action: glance.images_get
parameters:
image_id: <% $.image_id %>
publish:
image_id: <% $.id %>
image_name: <% $.name %>

View File

@ -1,4 +0,0 @@
Workflow:
tasks:
heat_stack_list:
action: heat.stacks_list

View File

@ -1,4 +0,0 @@
Workflow:
tasks:
keystone_user_list:
action: keystone.users_list

View File

@ -1,6 +0,0 @@
Workflow:
tasks:
get_some_endpoint:
action: keystone.service_catalog_get_data
publish:
endpoint_url: <% $[0].endpoints[0].url %>

View File

@ -1,7 +0,0 @@
Workflow:
tasks:
nova_server_findall:
action: nova.servers_findall
parameters:
status: ACTIVE
tenant_id: 8e44eb2ce32

View File

@ -1,31 +0,0 @@
Workflow:
tasks:
server_create:
action: nova.servers_create
parameters:
name: <% $.server_name %>
image: <% $.image_ref %>
flavor: <% $.flavor_ref %>
publish:
server_id: <% $.id %>
on-success: check_server_exists
check_server_exists:
action: nova.servers_get
parameters:
server: <% $.server_id %>
publish:
server_exists: True
on-success:
wait_instance
wait_instance:
action: nova.servers_find
retry:
delay: 5
count: 15
parameters:
id: <% $.server_id %>
status: 'ACTIVE'
publish:
instance_id: <% $.id %>

View File

@ -1,4 +0,0 @@
Workflow:
tasks:
neutron_list_networks:
action: neutron.list_networks

View File

@ -1,20 +0,0 @@
Namespaces:
MyService:
actions:
some-action:
class: std.mistral_http
base-parameters:
url: http://path_to_service/action_url
method: GET
output:
output: <% $ %>
Workflow:
tasks:
delay_retry_task:
action: MyService.some-action
retry:
count: 2
delay: 0.1
publish:
rt_output: output

View File

@ -1,19 +0,0 @@
Namespaces:
MyService:
actions:
some-action:
class: std.mistral_http
base-parameters:
url: http://path_to_service/action_url
method: GET
output:
output: <% $ %>
Workflow:
tasks:
retry_task:
action: MyService.some-action
retry:
count: 5
publish:
rt_output: <% $.output %>

View File

@ -1,18 +0,0 @@
Namespaces:
MyService:
actions:
sync-action:
class: std.echo
base-parameters:
output: Cheers!
output:
greeting: <% $ %>
Workflow:
tasks:
sync-task:
action: MyService.sync-action
retry:
count: 5
publish:
st_output: <% $.greeting %>

View File

@ -1,26 +0,0 @@
Namespaces:
MyService:
actions:
some-action:
class: std.mistral_http
base-parameters:
url: http://path_to_service/action_url
method: GET
output:
output: <% $ %>
Workflow:
tasks:
no_retry_task:
action: MyService.some-action
publish:
n_rt_output: <% $.output %>
on-success: delay_retry_task
delay_retry_task:
action: MyService.some-action
retry:
count: 2
delay: 0.1
publish:
rt_output: output

View File

@ -1,63 +0,0 @@
Namespaces:
Nova:
class: std.mistral_http
base-parameters:
method: GET
headers:
X-Auth-Token: <% $.auth_token %>
actions:
create-vm:
base-parameters:
url: http://some_host/service/action/execute
headers:
Content-Type: 'application/json'
parameters:
- image_id
- flavor_id
Echo:
actions:
concat:
class: std.echo
base-parameters:
output: '<% $.left %> <% $.right %>'
parameters:
- left
- right
output:
string: <% $ %>
Workflow:
tasks:
task1:
action: Nova.create-vm
parameters:
image_id: 1234
flavor_id: 42
on-error: task2
task2:
action: Echo.concat
parameters:
left: workflow
right: is
publish:
result2: <% $.string %>
on-finish: task3
task3:
action: Nova.create-vm
parameters:
image_id: 1234
flavor_id: 42
on-finish: task4
task4:
action: Echo.concat
parameters:
left: <% $.result2 %>
right: complete!
publish:
result4: <% $.string %>

View File

@ -1,40 +0,0 @@
Namespaces:
MyService:
actions:
concat:
class: std.echo
base-parameters:
output: '<% $.left %> <% $.right %>'
parameters:
- left
- right
output:
string: <% $ %>
Workflow:
tasks:
task1:
action: MyService.concat
parameters:
left: workflow
right: is
publish:
result1: <% $.string %>
task2:
requires: [task1]
action: MyService.concat
parameters:
left: <% $.result1 %>
right: complete
publish:
result2: <% $.string %>
on-success: task3
task3:
action: MyService.concat
parameters:
left: <% $.result2 %>
right: '!'
publish:
result3: <% $.string %>

View File

@ -1,29 +0,0 @@
Workflow:
tasks:
task:
requires: [atask, pretask]
action: std.echo
parameters:
output: some
btask:
requires: [ztask]
action: std.echo
parameters:
output: some
ztask:
action: std.echo
parameters:
output: some
atask:
action: std.echo
parameters:
output: some
ctask:
action: std.echo
parameters:
output: some
pretask:
requires: [btask, ztask]
action: std.echo
parameters:
output: some

View File

@ -1,101 +0,0 @@
Namespaces:
MyRest:
class: std.mistral_http
base-parameters:
method: GET
headers:
X-Auth-Token: $.auth_token
actions:
create-vm:
base-parameters:
url: http://some_host/service/action/execute
headers:
Content-Type: 'application/json'
parameters:
- image_id
- flavor_id
output:
backup-vm:
base-parameters:
url: http://some_host/url_for_backup
parameters:
- server_id
attach-volume:
base-parameters:
url: /url_for_attach
parameters:
- size
- mnt_path
format-volume:
base-parameters:
url: /url_for_format
parameters:
- server_id
Nova:
actions:
create-vm:
class: std.http
base-parameters:
url: http://path_to_nova/url_for_create
parameters:
- image_id
- flavor_id
output:
vm_id: $.base_output.server_id
Workflow:
tasks:
create-vms:
action: MyRest.create-vm
parameters:
image_id: 1234
flavor_id: 42
attach-volumes:
requires: [create-vms]
action: MyRest.attach-volume
parameters:
size:
mnt_path:
format-volumes:
requires: [attach-volumes]
action: MyRest.format-volume
parameters:
server_id:
backup-vms:
requires: [create-vms]
action: MyRest.backup-vm
parameters:
server_id:
create-vm-nova:
action: Nova.create-vm
parameters:
image_id: 1234
flavor_id: 2
test_subsequent:
action: MyRest.backup-vm
parameters:
server_id: 1
on-success:
attach-volumes
on-error:
- backup-vms: $.status != 'OK'
- attach-volumes
on-finish:
create-vms
Triggers:
create-vms:
type: periodic
tasks: create-vms
parameters:
cron-pattern: "* * * * *"

View File

@ -4,8 +4,9 @@ Namespaces:
hello: hello:
class: std.echo class: std.echo
base-parameters: base-parameters:
output: Hello! output: Hello!
Workflow: Workflow:
tasks: tasks:
hello: hello:
action: Greetings.hello action: Greetings.hello

View File

@ -1,154 +0,0 @@
# -*- coding: utf-8 -*-
#
# Copyright 2014 - 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.
from mistral.actions import std_actions as std
from mistral.openstack.common import log as logging
from mistral.services import action_manager as a_m
from mistral.tests import base
from mistral.workbook import parser as spec_parser
# TODO(rakhmerov): Deprecated. Remove it once engine v1 is gone.
LOG = logging.getLogger(__name__)
DB_TASK = {
'task_spec': {
'name': 'my_task',
'action': 'std.http'
},
'name': 'my_task',
'workbook_name': 'my_workbook',
'execution_id': '123',
'id': '123',
'in_context': {},
'tags': ['deployment', 'test'],
'parameters': {
'url': 'http://some.url',
'params': {
'param1': 'val1',
'param2': 'val2'
},
'method': 'POST',
'headers': {
'content-type': 'text/json'
},
'body': {
'my_object': {
'prop1': 'val1',
'prop2': 'val2'
}
}
}
}
DB_TASK_ADHOC = {
'task_spec': {
'name': 'my_task',
'action': 'my_namespace.my_action'
},
'action_spec': {
'name': 'my_action',
'namespace': 'my_namespace',
'class': 'std.echo',
'base-parameters': {
'output': '<% $.first %> and <% $.second %>'
},
'parameters': ['first', 'second'],
'output': {
'res': '<% $ %>'
}
},
'name': 'my_task',
'workbook_name': 'my_workbook',
'execution_id': '123',
'id': '123',
'in_context': {},
'tags': ['deployment', 'test'],
'parameters': {
'first': 'Tango',
'second': 'Cash'
}
}
class ActionFactoryTest(base.DbTestCase):
def test_register_standard_actions(self):
action_list = a_m.get_registered_actions()
self._assert_single_item(action_list, name="std.echo")
self._assert_single_item(action_list, name="std.email")
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")
self._assert_single_item(action_list, name="keystone.users_list")
self._assert_single_item(action_list, name="keystone.trusts_create")
self._assert_single_item(action_list, name="glance.images_list")
self._assert_single_item(action_list, name="glance.images_delete")
def test_get_action_class(self):
self.assertEqual(std.EchoAction, a_m.get_action_class("std.echo"))
self.assertEqual(std.HTTPAction, a_m.get_action_class("std.http"))
self.assertEqual(std.MistralHTTPAction,
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(
base.get_resource('control_flow/one_sync_task.yaml'))
action_name = 'MyActions.concat'
action = a_m.resolve_adhoc_action_name(wb, action_name)
self.assertEqual('std.echo', action)
def test_convert_adhoc_action_params(self):
wb = spec_parser.get_workbook_spec_from_yaml(
base.get_resource('control_flow/one_sync_task.yaml'))
action_name = 'MyActions.concat'
params = {
'left': 'Stormin',
'right': 'Stanley'
}
parameters = a_m.convert_adhoc_action_params(wb,
action_name,
params)
self.assertEqual({'output': 'Stormin Stanley'}, parameters)
def test_convert_adhoc_action_result(self):
wb = spec_parser.get_workbook_spec_from_yaml(
base.get_resource('control_flow/one_sync_task.yaml'))
action_name = 'MyActions.concat'
result = {'output': 'Stormin Stanley'}
parameters = a_m.convert_adhoc_action_result(wb,
action_name,
result)
self.assertEqual({'string': 'Stormin Stanley'}, parameters)

View File

@ -0,0 +1,60 @@
# -*- coding: utf-8 -*-
#
# Copyright 2014 - 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.
from mistral.actions import std_actions as std
from mistral.openstack.common import log as logging
from mistral.services import action_manager as a_m
from mistral.tests import base
LOG = logging.getLogger(__name__)
class ActionFactoryTest(base.DbTestCase):
def test_register_standard_actions(self):
action_list = a_m.get_registered_actions()
self._assert_single_item(action_list, name="std.echo")
self._assert_single_item(action_list, name="std.email")
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")
self._assert_single_item(action_list, name="keystone.users_list")
self._assert_single_item(action_list, name="keystone.trusts_create")
self._assert_single_item(action_list, name="glance.images_list")
self._assert_single_item(action_list, name="glance.images_delete")
def test_get_action_class(self):
self.assertEqual(std.EchoAction, a_m.get_action_class("std.echo"))
self.assertEqual(std.HTTPAction, a_m.get_action_class("std.http"))
self.assertEqual(
std.MistralHTTPAction,
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")
)

View File

@ -54,7 +54,7 @@ workflows:
RESUME_WORKBOOK_REVERSE = """ RESUME_WORKBOOK_REVERSE = """
--- ---
version: 2.0 version: '2.0'
name: resume_reverse name: resume_reverse

View File

@ -1,112 +0,0 @@
# -*- coding: utf-8 -*-
#
# Copyright 2013 - 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.
from mistral.tests import base
from mistral.workbook import parser
SIMPLE_WORKBOOK = """
Workflow:
tasks:
create-vms:
action: MyRest.create-vm
"""
class DSLv1ModelTest(base.BaseTest):
def setUp(self):
super(DSLv1ModelTest, self).setUp()
# TODO(rakhmerov): Need to have a dedicated resource.
self.doc = base.get_resource("test_rest.yaml")
def test_load_dsl(self):
wb = parser.get_workbook_spec_from_yaml(self.doc)
self.assertEqual(wb.workflow.tasks.items, wb.tasks.items)
self.assertEqual(wb.tasks.get("create-vms").name, "create-vms")
self.assertEqual(4, len(wb.namespaces.get("MyRest").actions))
def test_tasks(self):
wb = parser.get_workbook_spec_from_yaml(self.doc)
self.assertEqual(len(wb.tasks), 6)
attach_volumes = wb.tasks.get("attach-volumes")
self.assertEqual(attach_volumes.get_action_namespace(), "MyRest")
t_parameters = {"image_id": 1234, "flavor_id": 2}
create_vm_nova = wb.tasks.get("create-vm-nova")
self.assertEqual(create_vm_nova.parameters, t_parameters)
attach_requires = {"create-vms": ''}
self.assertEqual(attach_volumes.requires, attach_requires)
subsequent = wb.tasks.get("test_subsequent")
subseq_success = subsequent.get_on_success()
subseq_error = subsequent.get_on_error()
subseq_finish = subsequent.get_on_finish()
self.assertEqual(subseq_success, {"attach-volumes": ''})
self.assertEqual(subseq_error, {"backup-vms": "$.status != 'OK'",
"attach-volumes": ''})
self.assertEqual(subseq_finish, {"create-vms": ''})
def test_actions(self):
wb = parser.get_workbook_spec_from_yaml(self.doc)
actions = wb.namespaces.get("MyRest").actions
self.assertEqual(len(actions), 4)
create_vm = actions.get("create-vm")
base_params = create_vm.base_parameters
self.assertEqual('std.mistral_http', create_vm.clazz)
self.assertIn('method', base_params)
self.assertIn('headers', base_params)
self.assertEqual('$.auth_token',
base_params['headers']['X-Auth-Token'])
self.assertEqual('application/json',
base_params['headers']['Content-Type'])
action = wb.get_action("MyRest.create-vm")
self.assertIsNotNone(action)
self.assertEqual("create-vm", action.name)
self.assertEqual("MyRest", action.namespace)
def test_namespaces(self):
wb = parser.get_workbook_spec_from_yaml(self.doc)
self.assertEqual(len(wb.namespaces), 2)
nova_namespace = wb.namespaces.get("Nova")
self.assertEqual(1, len(nova_namespace.actions))
def test_workbook_without_namespaces(self):
parser.get_workbook_spec_from_yaml(SIMPLE_WORKBOOK)
def test_triggers(self):
wb = parser.get_workbook_spec_from_yaml(self.doc)
self.assertEqual(len(wb.get_triggers()), 1)

View File

@ -1,56 +0,0 @@
# -*- coding: utf-8 -*-
#
# Copyright 2013 - 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.
# TODO(rakhmerov): Can we just extend dsl_specs_v1.py and remove this one?.
SAMPLE_TASK_SPEC = {
'action': 'MyRest:create-vm',
'name': 'create-vms',
'on-success': ["format-volumes", {'task1': 'expression'}, {'task2': ''}],
'on-finish': "attach-volumes",
'on-error': ["task1", "task2"]
}
from mistral.tests import base
from mistral.workbook.v1 import tasks
class GetOnStateTest(base.BaseTest):
def setUp(self):
super(GetOnStateTest, self).setUp()
self.task = tasks.TaskSpec(SAMPLE_TASK_SPEC)
def test_state_finish(self):
on_finish = self.task.get_on_finish()
self.assertIsInstance(on_finish, dict)
self.assertIn("attach-volumes", on_finish)
def test_state_error(self):
on_error = self.task.get_on_error()
self.assertIsInstance(on_error, dict)
self.assertEqual(len(on_error), 2)
self.assertIn("task1", on_error)
def test_state_success(self):
on_success = self.task.get_on_success()
self.assertIsInstance(on_success, dict)
self.assertEqual(len(on_success), 3)
self.assertIn("task1", on_success)
self.assertIsNotNone(on_success["task1"])

View File

@ -17,20 +17,14 @@ import yaml
from yaml import error from yaml import error
from mistral import exceptions as exc from mistral import exceptions as exc
from mistral.workbook.v1 import actions as actions_v1
from mistral.workbook.v1 import namespaces as ns_v1
from mistral.workbook.v1 import tasks as tasks_v1
from mistral.workbook.v1 import workbook as wb_v1
from mistral.workbook.v1 import workflow as wf_v1
from mistral.workbook.v2 import actions as actions_v2 from mistral.workbook.v2 import actions as actions_v2
from mistral.workbook.v2 import tasks as tasks_v2 from mistral.workbook.v2 import tasks as tasks_v2
from mistral.workbook.v2 import workbook as wb_v2 from mistral.workbook.v2 import workbook as wb_v2
from mistral.workbook.v2 import workflows as wf_v2 from mistral.workbook.v2 import workflows as wf_v2
V1_0 = '1.0'
V2_0 = '2.0' V2_0 = '2.0'
ALL_VERSIONS = [V1_0, V2_0] ALL_VERSIONS = [V2_0]
def parse_yaml(text): def parse_yaml(text):
@ -49,8 +43,8 @@ def parse_yaml(text):
def _get_spec_version(spec_dict): def _get_spec_version(spec_dict):
# If version is not specified it will '1.0' by default. # If version is not specified it will '2.0' by default.
ver = V1_0 ver = V2_0
if 'version' in spec_dict: if 'version' in spec_dict:
ver = spec_dict['version'] ver = spec_dict['version']
@ -66,31 +60,22 @@ def _get_spec_version(spec_dict):
def get_workbook_spec(spec_dict): def get_workbook_spec(spec_dict):
if _get_spec_version(spec_dict) == V1_0: if _get_spec_version(spec_dict) == V2_0:
return wb_v1.WorkbookSpec(spec_dict)
else:
return wb_v2.WorkbookSpec(spec_dict) return wb_v2.WorkbookSpec(spec_dict)
return None
def get_workbook_spec_from_yaml(text): def get_workbook_spec_from_yaml(text):
spec_dict = parse_yaml(text) return get_workbook_spec(parse_yaml(text))
return get_workbook_spec(spec_dict)
def get_namespace_spec(spec_dict):
if _get_spec_version(spec_dict) == V1_0:
return ns_v1.NamespaceSpec(spec_dict)
else:
return None
def get_action_spec(spec_dict): def get_action_spec(spec_dict):
if _get_spec_version(spec_dict) == V1_0: if _get_spec_version(spec_dict) == V2_0:
return actions_v1.ActionSpec(spec_dict)
else:
return actions_v2.ActionSpec(spec_dict) return actions_v2.ActionSpec(spec_dict)
return None
def get_action_spec_from_yaml(text, action_name): def get_action_spec_from_yaml(text, action_name):
spec_dict = parse_yaml(text) spec_dict = parse_yaml(text)
@ -105,17 +90,15 @@ def get_action_list_spec(spec_dict):
def get_action_list_spec_from_yaml(text): def get_action_list_spec_from_yaml(text):
spec_dict = parse_yaml(text) return get_action_list_spec(parse_yaml(text))
return get_action_list_spec(spec_dict)
def get_workflow_spec(spec_dict): def get_workflow_spec(spec_dict):
if _get_spec_version(spec_dict) == V1_0: if _get_spec_version(spec_dict) == V2_0:
return wf_v1.WorkflowSpec(spec_dict)
else:
return wf_v2.WorkflowSpec(spec_dict) return wf_v2.WorkflowSpec(spec_dict)
return None
def get_workflow_list_spec(spec_dict): def get_workflow_list_spec(spec_dict):
return wf_v2.WorkflowListSpec(spec_dict) return wf_v2.WorkflowListSpec(spec_dict)
@ -134,9 +117,7 @@ def get_workflow_list_spec_from_yaml(text):
def get_task_spec(spec_dict): def get_task_spec(spec_dict):
if _get_spec_version(spec_dict) == V1_0: if _get_spec_version(spec_dict) == V2_0:
return tasks_v1.TaskSpec(spec_dict)
else:
workflow_type = spec_dict.get('type') workflow_type = spec_dict.get('type')
if workflow_type == 'direct': if workflow_type == 'direct':
@ -146,7 +127,4 @@ def get_task_spec(spec_dict):
else: else:
raise Exception('Unsupported workflow type "%s".' % workflow_type) raise Exception('Unsupported workflow type "%s".' % workflow_type)
return None
def get_trigger_spec(spec_dict):
# TODO(rakhmerov): Implement.
pass

View File

@ -1,47 +0,0 @@
# Copyright 2014 - 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.
from mistral.workbook import base
class ActionSpec(base.BaseSpec):
# See http://json-schema.org
_schema = {
"type": "object",
"properties": {
"version": {"type": "string"},
"name": {"type": "string"},
"class": {"type": "string"},
"namespace": {"type": "string"},
"base-parameters": {"type": "object"},
"parameters": {"type": "array"},
"output": {"type": ["string", "object", "array", "null"]},
},
"required": ["name", "class", "namespace"],
"additionalProperties": False
}
def __init__(self, data):
super(ActionSpec, self).__init__(data)
self.name = data['name']
self.clazz = data['class']
self.namespace = data['namespace']
self.base_parameters = data.get('base-parameters', {})
self.parameters = data.get('parameters', {})
self.output = data.get('output')
class ActionSpecList(base.BaseSpecList):
item_class = ActionSpec

View File

@ -1,68 +0,0 @@
# Copyright 2014 - 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.
from mistral import utils
from mistral.workbook import base
from mistral.workbook.v1 import actions
def merge_base_parameters(action, ns_base_parameters):
if not ns_base_parameters:
return
if 'base-parameters' not in action:
action['base-parameters'] = ns_base_parameters
return
action_base_parameters = action['base-parameters']
utils.merge_dicts(action_base_parameters, ns_base_parameters)
class NamespaceSpec(base.BaseSpec):
# See http://json-schema.org
_schema = {
"type": "object",
"properties": {
"version": {"type": "string"},
"name": {"type": "string"},
"class": {"type": ["string", "null"]},
"base-parameters": {"type": ["object", "null"]},
"actions": {"type": "object"}
},
"required": ["name", "actions"],
"additionalProperties": False
}
def __init__(self, data):
super(NamespaceSpec, self).__init__(data)
self.name = data['name']
self.clazz = data.get('class')
self.base_parameters = data.get('base-parameters')
self.parameters = data.get('parameters')
for _, action in data['actions'].iteritems():
action['namespace'] = self.name
if 'class' not in action:
action['class'] = self.clazz
merge_base_parameters(action, self.base_parameters)
self.actions = actions.ActionSpecList(data['actions'])
class NamespaceSpecList(base.BaseSpecList):
item_class = NamespaceSpec

View File

@ -1,102 +0,0 @@
# Copyright 2014 - 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.
from mistral.workbook import base
class TaskSpec(base.BaseSpec):
# See http://json-schema.org
_schema = {
"type": "object",
"properties": {
"version": {"type": "string"},
"name": {"type": "string"},
"action": {"type": ["string", "null"]},
"parameters": {"type": ["object", "null"]},
"publish": {"type": ["object", "null"]},
"retry": {"type": ["object", "null"]},
"requires": {"type": ["object", "string", "array", "null"]},
"on-finish": {"type": ["string", "array", "null"]},
"on-success": {"type": ["string", "array", "null"]},
"on-error": {"type": ["string", "array", "null"]}
},
"required": ["name", "action"],
"additionalProperties": False
}
def __init__(self, data):
super(TaskSpec, self).__init__(data)
self._prepare(data)
self.requires = data.get('requires')
self.action = data['action']
self.name = data['name']
self.parameters = data.get('parameters', {})
def _prepare(self, task):
if task:
req = task.get("requires", {})
if req and isinstance(req, list):
task["requires"] = dict(zip(req, [''] * len(req)))
elif isinstance(req, dict):
task['requires'] = req
def get_property(self, property_name, default=None):
return self._data.get(property_name, default)
def get_requires(self):
return self._as_dict('requires').keys()
def get_on_error(self):
return self._as_dict("on-error")
def get_on_success(self):
return self._as_dict("on-success")
def get_on_finish(self):
return self._as_dict("on-finish")
def get_action_namespace(self):
return self.action.split('.')[0]
def get_action_name(self):
return self.action.split('.')[1]
def get_full_action_name(self):
return self.action
def is_retry_task(self):
return self.get_property("retry") is not None
def get_retry_parameters(self):
iterations = 0
break_on = None
delay = 0
retry = self.get_property("retry")
if retry:
if "count" in retry:
iterations = retry["count"]
if "break-on" in retry:
break_on = retry["break-on"]
if "delay" in retry:
delay = retry["delay"]
return iterations, break_on, delay
class TaskSpecList(base.BaseSpecList):
item_class = TaskSpec

View File

@ -1,73 +0,0 @@
# Copyright 2014 - 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.
from mistral.workbook import base
from mistral.workbook.v1 import namespaces
from mistral.workbook.v1 import workflow
class WorkbookSpec(base.BaseSpec):
# See http://json-schema.org
_schema = {
"type": "object",
"properties": {
"Namespaces": {"type": "object"},
"Workflow": {"type": "object"},
"Triggers": {"type": "object"}
},
"required": ["Workflow"],
"additionalProperties": False
}
def __init__(self, doc):
super(WorkbookSpec, self).__init__(doc)
self.namespaces = self._spec_property('Namespaces',
namespaces.NamespaceSpecList)
self.workflow = self._spec_property('Workflow', workflow.WorkflowSpec)
self.tasks = self.workflow.tasks
def get_triggers(self):
triggers_from_data = self._data.get("Triggers", None)
if not triggers_from_data:
return []
triggers = []
for name in triggers_from_data:
trigger_dict = {'name': name}
trigger_dict.update(triggers_from_data[name])
triggers.append(trigger_dict)
return triggers
def get_action(self, full_action_name):
if not self.namespaces:
return None
if full_action_name.find(".") == -1:
return {}
ns_name = full_action_name.split('.')[0]
action_name = full_action_name.split('.')[1]
if ns_name in self.namespaces.item_keys():
return self.namespaces[ns_name].actions.get(action_name)
def get_actions(self, namespace_name):
return self.namespaces.get(namespace_name).actions
def get_trigger_task_name(self, trigger_name):
trigger = self._data["Triggers"].get(trigger_name)
return trigger.get('tasks') if trigger else ""

View File

@ -1,33 +0,0 @@
# Copyright 2014 - 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.
from mistral.workbook import base
from mistral.workbook.v1 import tasks
class WorkflowSpec(base.BaseSpec):
# See http://json-schema.org
_schema = {
"type": "object",
"properties": {
"tasks": {"type": "object"},
},
"required": ["tasks"],
"additionalProperties": False
}
def __init__(self, workflow):
super(WorkflowSpec, self).__init__(workflow)
self.tasks = tasks.TaskSpecList(workflow['tasks'])