diff --git a/muranoapi/api/v1/schemas.py b/muranoapi/api/v1/schemas.py index 559994375..cba82b1e4 100644 --- a/muranoapi/api/v1/schemas.py +++ b/muranoapi/api/v1/schemas.py @@ -21,5 +21,5 @@ ENV_SCHEMA = { "id": {"type": "string"}, "name": {"type": "string"} }, - "required": ["id"] + "required": ["id", "name"] } diff --git a/muranoapi/api/v1/services.py b/muranoapi/api/v1/services.py index 9b2476f5c..e8566d04c 100644 --- a/muranoapi/api/v1/services.py +++ b/muranoapi/api/v1/services.py @@ -55,7 +55,7 @@ class Controller(object): @utils.verify_session @normalize_path def post(self, request, environment_id, path, body): - log.debug(_('Services:Post '.format(environment_id, body, path))) post_data = CoreServices.post_data @@ -69,7 +69,7 @@ class Controller(object): @utils.verify_session @normalize_path def put(self, request, environment_id, path, body): - log.debug(_('Services:Put '.format(environment_id, body, path))) put_data = CoreServices.put_data diff --git a/muranoapi/common/utils.py b/muranoapi/common/utils.py index 59724115d..572af9fe4 100644 --- a/muranoapi/common/utils.py +++ b/muranoapi/common/utils.py @@ -12,12 +12,12 @@ # License for the specific language governing permissions and limitations # under the License. -import eventlet -from jsonschema import validate -from muranoapi.common.uuidutils import generate_uuid -import types from collections import deque from functools import wraps + +import eventlet +from jsonschema import validate +import types from muranoapi.openstack.common import log as logging @@ -101,6 +101,18 @@ class TraverseHelper(object): node = TraverseHelper.get(path, source) node.append(value) + @staticmethod + def extend(path, value, source): + """ + Extend list by appending elements from the iterable. + + :param path: string with path to desired value + :param value: value + :param source: List + """ + node = TraverseHelper.get(path, source) + node.extend(value) + @staticmethod def remove(path, source): """ @@ -125,17 +137,6 @@ class TraverseHelper(object): raise ValueError('Source object or path is malformed') -def auto_id(value): - if isinstance(value, types.DictionaryType): - value['id'] = generate_uuid() - for k, v in value.iteritems(): - value[k] = auto_id(v) - if isinstance(value, types.ListType): - for item in value: - auto_id(item) - return value - - def build_entity_map(value): def build_entity_map_recursive(value, id_map): if isinstance(value, types.DictionaryType): diff --git a/muranoapi/db/services/core_services.py b/muranoapi/db/services/core_services.py index 71bb629e1..50d13899e 100644 --- a/muranoapi/db/services/core_services.py +++ b/muranoapi/db/services/core_services.py @@ -12,9 +12,10 @@ # License for the specific language governing permissions and limitations # under the License. -from muranoapi.common.utils import TraverseHelper, auto_id +from muranoapi.common.utils import TraverseHelper from muranoapi.db.services.environments import EnvironmentServices from muranoapi.openstack.common import timeutils +import types class CoreServices(object): @@ -66,16 +67,12 @@ class CoreServices(object): if not 'services' in env_description: env_description['services'] = [] - data = auto_id(data) - if path == '/services': - data['created'] = str(timeutils.utcnow()) - data['updated'] = str(timeutils.utcnow()) + if isinstance(data, types.ListType): + TraverseHelper.extend(path, data, env_description) + else: + TraverseHelper.insert(path, data, env_description) - for idx, unit in enumerate(data['units']): - unit['name'] = data['name'] + '_instance_' + str(idx) - - TraverseHelper.insert(path, data, env_description) save_description(session_id, env_description) return data diff --git a/muranoapi/db/services/environments.py b/muranoapi/db/services/environments.py index 942b09b65..172630ecd 100644 --- a/muranoapi/db/services/environments.py +++ b/muranoapi/db/services/environments.py @@ -16,9 +16,11 @@ from collections import namedtuple from jsonschema import validate from muranoapi.api.v1.schemas import ENV_SCHEMA from muranoapi.common import config +from muranoapi.common.uuidutils import generate_uuid from muranoapi.db.models import Session, Environment from muranoapi.db.services.sessions import SessionServices, SessionState from muranoapi.db.session import get_session +from muranoapi.openstack.common import timeutils from muranocommon.messaging import MqClient, Message @@ -175,6 +177,37 @@ class EnvironmentServices(object): unit = get_session() session = unit.query(Session).get(session_id) + EnvironmentServices.normalize(environment) validate(environment, ENV_SCHEMA) session.description = environment session.save(unit) + + @staticmethod + def normalize(environment): + if 'id' not in environment: + environment['id'] = generate_uuid() + + if 'services' not in environment: + return + + for service in environment['services']: + if 'id' not in service: + service['id'] = generate_uuid() + + if 'created' not in service: + service['created'] = str(timeutils.utcnow()) + + if 'updated' not in service: + service['updated'] = str(timeutils.utcnow()) + + if 'units' not in service: + continue + + for idx, unit in enumerate(service['units']): + if 'id' not in unit: + unit['id'] = generate_uuid() + + if 'name' not in unit: + unit['name'] = '{srv_name}_instance_{number}'.format( + srv_name=service['name'], number=idx + ) diff --git a/muranoapi/db/services/sessions.py b/muranoapi/db/services/sessions.py index 1a73b32ed..2face7f82 100644 --- a/muranoapi/db/services/sessions.py +++ b/muranoapi/db/services/sessions.py @@ -16,6 +16,7 @@ from collections import namedtuple from muranoapi.common import config from muranoapi.db.models import Session, Environment, Deployment, Status from muranoapi.db.session import get_session +from muranocommon.helpers.token_sanitizer import TokenSanitizer from muranocommon.messaging import MqClient, Message @@ -26,6 +27,11 @@ SessionState = namedtuple('SessionState', ['open', 'deploying', 'deployed'])( ) +def secure_description(description): + sanitizer = TokenSanitizer() + return sanitizer.sanitize(description) + + class SessionServices(object): @staticmethod def get_sessions(environment_id, state=None): @@ -125,9 +131,7 @@ class SessionServices(object): session.state = SessionState.deploying deployment = Deployment() deployment.environment_id = environment['id'] - deployment.description = dict(session.description) - if 'token' in deployment.description: - del deployment.description['token'] + deployment.description = secure_description(dict(session.description)) status = Status() status.text = "Deployment scheduled" status.level = "info" diff --git a/muranoapi/tests/common/traverse_helper_tests.py b/muranoapi/tests/common/traverse_helper_tests.py index f03757d35..1d078ed32 100644 --- a/muranoapi/tests/common/traverse_helper_tests.py +++ b/muranoapi/tests/common/traverse_helper_tests.py @@ -88,6 +88,18 @@ class TraverseHelperTests(unittest.TestCase): value = TraverseHelper.get('/obj/attr', source) self.assertListEqual(value, [1, 2, 3, 4]) + def test_extending_list_with_list(self): + source = {'attr': [1, 2, 3]} + TraverseHelper.extend('/attr', [4, 5], source) + value = TraverseHelper.get('/attr', source) + self.assertListEqual(value, [1, 2, 3, 4, 5]) + + def test_nested_extending_list_with_list(self): + source = {'obj': {'attr': [1, 2, 3]}} + TraverseHelper.extend('/obj/attr', [4, 5], source) + value = TraverseHelper.get('/obj/attr', source) + self.assertListEqual(value, [1, 2, 3, 4, 5]) + def test_attribute_remove_from_dict(self): source = {'attr1': False, 'attr2': True} TraverseHelper.remove('/attr1', source) diff --git a/muranoapi/tests/common/utils_tests.py b/muranoapi/tests/common/utils_tests.py deleted file mode 100644 index c99e19c5a..000000000 --- a/muranoapi/tests/common/utils_tests.py +++ /dev/null @@ -1,38 +0,0 @@ -# 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 unittest2 as unittest -from muranoapi.common.utils import auto_id - - -class AutoIdTests(unittest.TestCase): - def test_simple_dict(self): - source = {"attr": True} - value = auto_id(source) - self.assertIn('id', value) - - def test_nested_lists(self): - source = {"attr": True, "obj": {"attr": False}} - value = auto_id(source) - self.assertIn('id', value) - - def test_list_with_ints(self): - source = [0, 1, 2, 3] - value = auto_id(source) - self.assertListEqual(value, source) - - def test_list_with_dicts(self): - source = [{"attr": True}, {"attr": False}] - value = auto_id(source) - for item in value: - self.assertIn('id', item) diff --git a/requirements.txt b/requirements.txt index 1b4acfc55..2bbe8f638 100644 --- a/requirements.txt +++ b/requirements.txt @@ -31,4 +31,4 @@ passlib jsonschema==2.0.0 python-keystoneclient>=0.2.0 oslo.config -http://github.com/sergmelikyan/murano-common/releases/download/0.2.1/muranocommon-0.2.1.tar.gz#egg=muranocommon-0.2.1 \ No newline at end of file +http://tarballs.openstack.org/murano-common/murano-common-release-0.2.tar.gz#egg=muranocommon-dev \ No newline at end of file diff --git a/setup.cfg b/setup.cfg index ee8f39de3..cc01c2625 100644 --- a/setup.cfg +++ b/setup.cfg @@ -15,6 +15,7 @@ [metadata] name = muranoapi +version = 0.2 summary = Murano API description-file = README.rst @@ -65,4 +66,4 @@ input_file = muranoapi/locale/muranoapi.pot [extract_messages] keywords = _ gettext ngettext l_ lazy_gettext mapping_file = babel.cfg -output_file = muranoapi/locale/muranoapi.pot \ No newline at end of file +output_file = muranoapi/locale/muranoapi.pot