From 285e7ef962604e33f5d5305863c4af266389d401 Mon Sep 17 00:00:00 2001 From: Jay Dobies Date: Tue, 17 Mar 2015 16:34:10 -0400 Subject: [PATCH] Add relative_path metadata to a stored file This field is optional and can be used to carry information on the directory structure expected for role templates. Change-Id: Ic68ac09196de7604466a45f2dd929544597c1b9f --- .../versions/003_add_relative_path.py | 24 +++++++++++++++++++ tuskar/db/sqlalchemy/models.py | 3 +++ tuskar/manager/models.py | 4 +++- tuskar/manager/name_utils.py | 12 ++++++++-- tuskar/manager/plan.py | 11 +++++---- tuskar/storage/models.py | 3 ++- tuskar/tests/manager/test_name_utils.py | 6 ++++- tuskar/tests/manager/test_plan.py | 4 ++-- 8 files changed, 56 insertions(+), 11 deletions(-) create mode 100644 tuskar/db/sqlalchemy/migrate_repo/versions/003_add_relative_path.py diff --git a/tuskar/db/sqlalchemy/migrate_repo/versions/003_add_relative_path.py b/tuskar/db/sqlalchemy/migrate_repo/versions/003_add_relative_path.py new file mode 100644 index 00000000..3464cc42 --- /dev/null +++ b/tuskar/db/sqlalchemy/migrate_repo/versions/003_add_relative_path.py @@ -0,0 +1,24 @@ +# 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 oslo.db.sqlalchemy import utils +from sqlalchemy import Column, String + + +def upgrade(migrate_engine): + stored_file = utils.get_table(migrate_engine, 'stored_file') + relative_path = Column('relative_path', String(256), nullable=True) + stored_file.create_column(relative_path) + + +def downgrade(migrate_engine): + raise NotImplementedError('Downgrade is unsupported.') diff --git a/tuskar/db/sqlalchemy/models.py b/tuskar/db/sqlalchemy/models.py index e212c365..d3b48fb3 100644 --- a/tuskar/db/sqlalchemy/models.py +++ b/tuskar/db/sqlalchemy/models.py @@ -234,5 +234,8 @@ class StoredFile(Base): #: Names provide a short human readable description of a file. name = Column(String(length=64), nullable=True) + #: Relative path to which the file belongs + relative_path = Column(String(length=256), nullable=True) + #: Versions are an automatic incrementing count. version = Column(Integer(), nullable=True) diff --git a/tuskar/manager/models.py b/tuskar/manager/models.py index 8f701cb4..7305a478 100644 --- a/tuskar/manager/models.py +++ b/tuskar/manager/models.py @@ -13,7 +13,8 @@ class Role(object): - def __init__(self, uuid, name, version, description, template): + def __init__(self, uuid, name, version, description, template, + relative_path=None): super(Role, self).__init__() self.uuid = uuid @@ -21,6 +22,7 @@ class Role(object): self.version = version self.description = description self.template = template + self.relative_path = relative_path class DeploymentPlan(object): diff --git a/tuskar/manager/name_utils.py b/tuskar/manager/name_utils.py index 91d08653..5aa33cfd 100644 --- a/tuskar/manager/name_utils.py +++ b/tuskar/manager/name_utils.py @@ -20,6 +20,8 @@ such as: resource """ +import os + def generate_role_namespace(role_name, role_version): """Creates a unique namespace for the given role name and version. @@ -44,16 +46,22 @@ def parse_role_namespace(role_namespace): return role_namespace.rsplit('-', 1) -def role_template_filename(role_name, role_version): +def role_template_filename(role_name, role_version, role_relative_path): """Generates the filename a role's template should be stored in when creating the deployment plan's Heat files. :type role_name: str :type role_version: str + :type role_relative_path: str or None :rtype: str """ namespace = generate_role_namespace(role_name, role_version) - return 'provider-%s.yaml' % namespace + + filename = 'provider-%s.yaml' % namespace + if role_relative_path: + filename = os.path.join(role_relative_path, filename) + + return filename def master_template_filename(plan_name): diff --git a/tuskar/manager/plan.py b/tuskar/manager/plan.py index 4f131a9a..9083e28d 100644 --- a/tuskar/manager/plan.py +++ b/tuskar/manager/plan.py @@ -151,8 +151,9 @@ class PlansManager(object): # Use the combination logic to perform the addition. role_namespace = name_utils.generate_role_namespace(db_role.name, db_role.version) - template_filename = name_utils.role_template_filename(db_role.name, - db_role.version) + template_filename = ( + name_utils.role_template_filename(db_role.name, db_role.version, + db_role.relative_path)) deployment_plan.add_template(role_namespace, role_template, template_filename, override_properties=special_properties) @@ -375,7 +376,8 @@ class PlansManager(object): for role in plan_roles: contents = composer.compose_template(role.template) filename = name_utils.role_template_filename(role.name, - role.version) + role.version, + role.relative_path) files_dict[filename] = contents def _add_template_extra_data_for(templates, template_store): @@ -423,7 +425,8 @@ class PlansManager(object): # Convert to the Tuskar domain model. tuskar_role = models.Role(db_role.uuid, name, version, - role.description, role) + role.description, role, + relative_path=db_role.relative_path) return tuskar_role reg_mapping = self.registry_mapping_store.list() diff --git a/tuskar/storage/models.py b/tuskar/storage/models.py index cacbbd07..bcdf056a 100644 --- a/tuskar/storage/models.py +++ b/tuskar/storage/models.py @@ -21,7 +21,7 @@ class StoredFile(object): """ def __init__(self, uuid, contents, store, name=None, created_at=None, - updated_at=None, version=None): + updated_at=None, version=None, relative_path=None): """The constructor requires uuid, contents and store which are the common attributes in all drivers. @@ -56,6 +56,7 @@ class StoredFile(object): self.created_at = created_at self.updated_at = updated_at self.version = version + self.relative_path = relative_path def __eq__(self, other): return (isinstance(other, self.__class__) diff --git a/tuskar/tests/manager/test_name_utils.py b/tuskar/tests/manager/test_name_utils.py index b343ccd4..017cb4d2 100644 --- a/tuskar/tests/manager/test_name_utils.py +++ b/tuskar/tests/manager/test_name_utils.py @@ -32,9 +32,13 @@ class NameUtilsTestCases(unittest.TestCase): self.assertEqual('v1', version) def test_role_template_filename(self): - filename = name_utils.role_template_filename('r1', 'v1') + filename = name_utils.role_template_filename('r1', 'v1', None) self.assertEqual('provider-r1-v1.yaml', filename) + def test_role_template_filename_with_relative_path(self): + filename = name_utils.role_template_filename('r1', 'v1', 'l1') + self.assertEqual('l1/provider-r1-v1.yaml', filename) + def test_master_template_filename(self): filename = name_utils.master_template_filename('p1') self.assertEqual('p1-template.yaml', filename) diff --git a/tuskar/tests/manager/test_plan.py b/tuskar/tests/manager/test_plan.py index 537bd395..b50ade51 100644 --- a/tuskar/tests/manager/test_plan.py +++ b/tuskar/tests/manager/test_plan.py @@ -395,7 +395,7 @@ class PlansManagerTestCase(TestCase): parsed_env = parser.parse_environment(templates['environment.yaml']) self.assertEqual(1, len(parsed_env.registry_entries)) - role_filename = name_utils.role_template_filename('r1', '1') + role_filename = name_utils.role_template_filename('r1', '1', None) self.assertTrue(role_filename in templates) parsed_role = parser.parse_template(templates[role_filename]) self.assertEqual(parsed_role.description, 'Test provider resource foo') @@ -428,7 +428,7 @@ class PlansManagerTestCase(TestCase): parsed_env = parser.parse_environment(templates['environment.yaml']) self.assertEqual(2, len(parsed_env.registry_entries)) - role_filename = name_utils.role_template_filename('r1', '1') + role_filename = name_utils.role_template_filename('r1', '1', None) self.assertTrue(role_filename in templates) parsed_role = parser.parse_template(templates[role_filename]) self.assertEqual(parsed_role.description, 'Test provider resource foo')