From 904cb248e46c05708547f3593406202ce20e6f1c Mon Sep 17 00:00:00 2001 From: Stan Lagun Date: Wed, 13 Jul 2016 22:47:27 -0700 Subject: [PATCH] Fix used package versions for stable inheritance When an object from an object model is deserialized on subsequent deployment it's version is usually fixed in the object model. However the version of base classes for that object is not as long as it meets to the class requirements. Thus slightly different version might be used on each deployment that does satisfies the requirements but may have different internal state representation. To solve this a list of all package versions that are in use by the object model is written to the hidden section of the object model. On the subsequent load package loader will prefer versions in the list over newer versions available in the catalog at that time Change-Id: I17087c0045210d28b87aba4d50c329f688df3954 Closes-Bug: #1602839 --- murano/common/engine.py | 5 ++ murano/dsl/package_loader.py | 12 +++ murano/engine/package_loader.py | 74 ++++++++++++++++++- .../dsl/foundation/test_package_loader.py | 9 +++ .../tests/unit/policy/test_congress_rules.py | 9 +++ 5 files changed, 107 insertions(+), 2 deletions(-) diff --git a/murano/common/engine.py b/murano/common/engine.py index 09c18d99..14bc91fd 100644 --- a/murano/common/engine.py +++ b/murano/common/engine.py @@ -180,7 +180,11 @@ class TaskExecutor(object): return self.exception_result(e, None, '') with package_loader.CombinedPackageLoader(self._session) as pkg_loader: + pkg_loader.import_fixation_table( + self._session.system_attributes.get('Packages', {})) result = self._execute(pkg_loader) + self._session.system_attributes[ + 'Packages'] = pkg_loader.export_fixation_table() self._model['SystemData'] = self._session.system_attributes result['model'] = self._model @@ -248,6 +252,7 @@ class TaskExecutor(object): except Exception as e: return self.exception_result(e, None, '') + pkg_loader.compact_fixation_table() return { 'action': { 'result': action_result, diff --git a/murano/dsl/package_loader.py b/murano/dsl/package_loader.py index 69d8db44..defa43d7 100644 --- a/murano/dsl/package_loader.py +++ b/murano/dsl/package_loader.py @@ -30,3 +30,15 @@ class MuranoPackageLoader(object): @abc.abstractmethod def register_package(self, package): pass + + @abc.abstractmethod + def import_fixation_table(self, fixations): + pass + + @abc.abstractmethod + def export_fixation_table(self): + pass + + @abc.abstractmethod + def compact_fixation_table(self): + pass diff --git a/murano/engine/package_loader.py b/murano/engine/package_loader.py index ae4b1099..709bd4fb 100644 --- a/murano/engine/package_loader.py +++ b/murano/engine/package_loader.py @@ -66,6 +66,8 @@ class ApiPackageLoader(package_loader.MuranoPackageLoader): self._mem_locks = [] self._ipc_locks = [] self._downloaded = [] + self._fixations = collections.defaultdict(set) + self._new_fixations = collections.defaultdict(set) def _get_glare_client(self): glare_settings = CONF.glare @@ -140,6 +142,11 @@ class ApiPackageLoader(package_loader.MuranoPackageLoader): self._get_package_by_definition(package_definition)) def load_package(self, package_name, version_spec): + fixed_versions = self._fixations[package_name] + version = version_spec.select(fixed_versions) + if version: + version_spec = helpers.parse_version_spec(version) + packages = self._package_cache.get(package_name) if packages: version = version_spec.select(six.iterkeys(packages)) @@ -157,8 +164,10 @@ class ApiPackageLoader(package_loader.MuranoPackageLoader): six.reraise(exceptions.NoPackageFound(package_name), None, exc_info[2]) else: - return self._to_dsl_package( - self._get_package_by_definition(package_definition)) + package = self._get_package_by_definition(package_definition) + self._fixations[package_name].add(package.version) + self._new_fixations[package_name].add(package.version) + return self._to_dsl_package(package) def register_package(self, package): for name in package.classes: @@ -402,6 +411,15 @@ class ApiPackageLoader(package_loader.MuranoPackageLoader): self._mem_locks.append(mem_lock) self._ipc_locks.append(ipc_lock) + def import_fixation_table(self, fixations): + self._fixations = deserialize_package_fixations(fixations) + + def export_fixation_table(self): + return serialize_package_fixations(self._fixations) + + def compact_fixation_table(self): + self._fixations = self._new_fixations.copy() + def cleanup(self): """Cleans up any lock we had acquired and removes any stale packages""" @@ -430,6 +448,8 @@ class DirectoryPackageLoader(package_loader.MuranoPackageLoader): self._packages_by_name = {} self._loaded_packages = set() self._root_loader = root_loader or self + self._fixations = collections.defaultdict(set) + self._new_fixations = collections.defaultdict(set) self._build_index() def _build_index(self): @@ -453,6 +473,15 @@ class DirectoryPackageLoader(package_loader.MuranoPackageLoader): continue LOG.info(_LI('Loaded package from path {0}').format(folder)) + def import_fixation_table(self, fixations): + self._fixations = deserialize_package_fixations(fixations) + + def export_fixation_table(self): + return serialize_package_fixations(self._fixations) + + def compact_fixation_table(self): + self._fixations = self._new_fixations.copy() + def load_class_package(self, class_name, version_spec): packages = self._packages_by_class.get(class_name) if not packages: @@ -463,12 +492,18 @@ class DirectoryPackageLoader(package_loader.MuranoPackageLoader): return packages[version] def load_package(self, package_name, version_spec): + fixed_versions = self._fixations[package_name] + version = version_spec.select(fixed_versions) + if version: + version_spec = helpers.parse_version_spec(version) packages = self._packages_by_name.get(package_name) if not packages: raise exceptions.NoPackageFound(package_name) version = version_spec.select(six.iterkeys(packages)) if not version: raise exceptions.NoPackageFound(package_name) + self._fixations[package_name].add(version) + self._new_fixations[package_name].add(version) return packages[version] def register_package(self, package): @@ -543,6 +578,26 @@ class CombinedPackageLoader(package_loader.MuranoPackageLoader): def register_package(self, package): self.api_loader.register_package(package) + def export_fixation_table(self): + result = deserialize_package_fixations( + self.api_loader.export_fixation_table()) + for loader in self.directory_loaders: + fixations = deserialize_package_fixations( + loader.export_fixation_table()) + for key, value in six.iteritems(fixations): + result[key].update(value) + return serialize_package_fixations(result) + + def import_fixation_table(self, fixations): + self.api_loader.import_fixation_table(fixations) + for loader in self.directory_loaders: + loader.import_fixation_table(fixations) + + def compact_fixation_table(self): + self.api_loader.compact_fixation_table() + for loader in self.directory_loaders: + loader.compact_fixation_table() + def __enter__(self): return self @@ -568,3 +623,18 @@ def _with_to_generator(context_obj): with context_obj as obj: yield obj yield + + +def deserialize_package_fixations(fixations): + result = collections.defaultdict(set) + for name, versions in six.iteritems(fixations): + for version in versions: + result[name].add(helpers.parse_version(version)) + return result + + +def serialize_package_fixations(fixations): + return { + name: list(str(v) for v in versions) + for name, versions in six.iteritems(fixations) + } diff --git a/murano/tests/unit/dsl/foundation/test_package_loader.py b/murano/tests/unit/dsl/foundation/test_package_loader.py index 7ee9f2fd..67dfcf75 100644 --- a/murano/tests/unit/dsl/foundation/test_package_loader.py +++ b/murano/tests/unit/dsl/foundation/test_package_loader.py @@ -77,6 +77,15 @@ class TestPackageLoader(package_loader.MuranoPackageLoader): else: raise KeyError(class_name) + def export_fixation_table(self): + return {} + + def import_fixation_table(self, fixations): + pass + + def compact_fixation_table(self): + pass + def _build_index(self, directory): yamls = [ os.path.join(dirpath, f) diff --git a/murano/tests/unit/policy/test_congress_rules.py b/murano/tests/unit/policy/test_congress_rules.py index 7e9ef773..30005fc7 100644 --- a/murano/tests/unit/policy/test_congress_rules.py +++ b/murano/tests/unit/policy/test_congress_rules.py @@ -57,6 +57,15 @@ class MockPackageLoader(package_loader.MuranoPackageLoader): def load_package(self, package_name, version_spec): return self._package + def export_fixation_table(self): + pass + + def import_fixation_table(self, fixations): + pass + + def compact_fixation_table(self): + pass + class MockPackage(object): def __init__(self, classes):