From 7d716311df96d226f0b9a47d245ea07cbd565012 Mon Sep 17 00:00:00 2001 From: Nikolay Mahotkin Date: Wed, 11 Dec 2013 16:41:58 +0400 Subject: [PATCH] Add DSL parser * DSL parser * Unit tests Change-Id: I3e56ad7125233ecdafd41036d8b717fb95e2955c --- mistral/dsl.py | 53 ++++++++++++++++++ mistral/tests/resources/test_rest.yaml | 76 ++++++++++++++++++++++++++ mistral/tests/unit/test_parser.py | 54 ++++++++++++++++++ mistral/version.py | 2 +- 4 files changed, 184 insertions(+), 1 deletion(-) create mode 100644 mistral/dsl.py create mode 100644 mistral/tests/resources/test_rest.yaml create mode 100644 mistral/tests/unit/test_parser.py diff --git a/mistral/dsl.py b/mistral/dsl.py new file mode 100644 index 000000000..ad6c16f5e --- /dev/null +++ b/mistral/dsl.py @@ -0,0 +1,53 @@ +# Copyright (c) 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. + +import yaml +from yaml import error + + +class Parser(object): + """Mistral DSL parser. + + Loads a workbook definition in YAML format as described in Mistral DSL + specification and provides various methods to access DSL entities like + tasks and actions in a form of dictionary. + """ + def __init__(self, workbook_definition): + try: + self.doc = yaml.safe_load(workbook_definition) + except error.YAMLError as exc: + raise RuntimeError("Definition could not be parsed: %s\n" + % exc.message) + + def get_service(self): + return self.doc["Service"] + + def get_events(self): + events_from_doc = self.doc["Workflow"]["events"] + events = [] + for name in events_from_doc: + event_dict = {'name': name} + event_dict.update(events_from_doc[name]) + events.append(event_dict) + return events + + def get_tasks(self): + return self.doc["Workflow"]["tasks"] + + def get_service_name(self): + return self.doc['Service']['name'] + + def get_event_task_name(self, event_name): + return self.doc["Workflow"]["events"][event_name]['tasks'] diff --git a/mistral/tests/resources/test_rest.yaml b/mistral/tests/resources/test_rest.yaml new file mode 100644 index 000000000..ab5a7883b --- /dev/null +++ b/mistral/tests/resources/test_rest.yaml @@ -0,0 +1,76 @@ +Service: + name: MyRest + type: REST_API + parameters: + baseUrl: http://some_host + actions: + create-vm: + parameters: + url: /service/action/execute + method: GET + task-parameters: + flavor_id: + optional: false + image_id: + optional: false + backup-vm: + parameters: + url: url_for_backup + method: GET + task-parameters: + server_id: + optional: false + attach-volume: + parameters: + url: url_for_attach + method: GET + task-parameters: + size: + optional: false + mnt_path: + optional: false + format-volume: + parameters: + url: url_for_format + method: GET + task-parameters: + volume_id: + optional: false + server_id: + optional: false + + +Workflow: + tasks: + create-vms: + action: MyRest:create-vm + parameters: + image_id: 1234 + flavor_id: 42 + + attach-volumes: + action: Nova:attach-volume + parameters: + size: + optional: false + mnt_path: + optional: false + dependsOn: [create-vms] + format-volumes: + action: Nova:format-volume + parameters: + server_id: + optional: false + dependsOn: [attach-volumes] + backup-vms: + action: Nova:backup-vm + parameters: + server_id: + optional: false + dependsOn: [create-vms] + events: + create-vms: + type: periodic + tasks: create-vms + parameters: + cron-pattern: "* * * * *" \ No newline at end of file diff --git a/mistral/tests/unit/test_parser.py b/mistral/tests/unit/test_parser.py new file mode 100644 index 000000000..4609bd55b --- /dev/null +++ b/mistral/tests/unit/test_parser.py @@ -0,0 +1,54 @@ +# Copyright (c) 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. + +import pkg_resources as pkg +import unittest2 + +from mistral import dsl +from mistral import version + + +class DSLParserTest(unittest2.TestCase): + def setUp(self): + doc = open(pkg.resource_filename( + version.version_info.package, + "tests/resources/test_rest.yaml")).read() + self.dsl = dsl.Parser(doc) + + def test_service(self): + service = self.dsl.get_service() + self.assertEqual(service["name"], "MyRest") + self.assertEqual(service["type"], "REST_API") + self.assertIn("baseUrl", service["parameters"]) + + def test_events(self): + events = self.dsl.get_events() + self.assertIn("create-vms", events[0]['name']) + + def test_tasks(self): + tasks = self.dsl.get_tasks() + self.assertIn("create-vms", tasks) + self.assertIn("parameters", tasks["create-vms"]) + self.assertEqual(tasks["backup-vms"]["action"], + "Nova:backup-vm") + + def test_broken_definition(self): + broken_yaml = """ + Workflow: + [tasks: + create-vms/: + + """ + self.assertRaises(RuntimeError, dsl.Parser, broken_yaml) diff --git a/mistral/version.py b/mistral/version.py index 1cafedb7f..9d17c607b 100644 --- a/mistral/version.py +++ b/mistral/version.py @@ -15,5 +15,5 @@ from pbr import version -version_info = version.VersionInfo('Mistral') +version_info = version.VersionInfo('mistral') version_string = version_info.version_string