summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorAlexander Tivelkov <ativelkov@mirantis.com>2016-08-01 14:04:35 +0300
committerKirill Zaitsev <kzaitsev@mirantis.com>2016-08-06 10:25:58 +0000
commit56605d2740a4088631117cd44276f2b13c2a2a07 (patch)
treeb7f8a1f7b37519d0dba5bdbe9f0e8178483ccb96
parent3234f25bee9e6d62f109a12c237902657c41fa5e (diff)
Support for multi-class yamls in client0.8.6
MuranoClient needs to analyse package classes (names and inheritance chains) to properly add packages to Glare. This requires it to properly resolve class names in the appropriate namespaces. Since Mitaka Murano supports multi-class yamls, i.e. yaml files containing multiple MuranoPL classes in a single yaml file using it multi-document format. Optionally this allows to reuse a single namespace definition for multiple classes defined in the same file. Client was not aware of this feature, always loading classes as single-document yamls. It was also always using the current-class namespace definitions, thus likely to fail if the shared namespace definition is in use. This has been addressed. Closes-bug: #1608440 Change-Id: Ibd08454f71e0266c76a2ac517b441df97311d8b9 (cherry picked from commit 98adda6a46fd5d2032077758de1d72cefe4ef55c)
Notes
Notes (review): Verified+1: Murano CI Code-Review+2: Kirill Zaitsev <kzaitsev@mirantis.com> Workflow+1: Serg Melikyan <smelikyan@mirantis.com> Code-Review+2: Serg Melikyan <smelikyan@mirantis.com> Verified+2: Jenkins Submitted-by: Jenkins Submitted-at: Mon, 08 Aug 2016 18:06:37 +0000 Reviewed-on: https://review.openstack.org/352015 Project: openstack/python-muranoclient Branch: refs/heads/stable/mitaka
-rw-r--r--muranoclient/common/utils.py55
-rw-r--r--muranoclient/v1/artifact_packages.py38
-rw-r--r--releasenotes/notes/multi-class-yamls-support-914b3d155324214f.yaml4
3 files changed, 61 insertions, 36 deletions
diff --git a/muranoclient/common/utils.py b/muranoclient/common/utils.py
index 9ba9d7f..de2ea15 100644
--- a/muranoclient/common/utils.py
+++ b/muranoclient/common/utils.py
@@ -354,17 +354,37 @@ class Package(FileWrapperMixin):
354 return [] 354 return []
355 355
356 @property 356 @property
357 def resolvers(self):
358 if not hasattr(self, '_resolvers'):
359 self.classes
360 return self._resolvers
361
362 @property
357 def classes(self): 363 def classes(self):
358 if not hasattr(self, '_classes'): 364 if not hasattr(self, '_classes'):
359 self._classes = {} 365 self._classes = {}
366 self._resolvers = {}
360 for class_name, class_file in six.iteritems( 367 for class_name, class_file in six.iteritems(
361 self.manifest.get('Classes', {})): 368 self.manifest.get('Classes', {})):
362 filename = "Classes/%s" % class_file 369 filename = "Classes/%s" % class_file
363 if filename not in self.contents.namelist(): 370 if filename not in self.contents.namelist():
364 continue 371 continue
365 klass = yaml.load(self.contents.open(filename), 372 klass_list = yaml.load_all(self.contents.open(filename),
366 DummyYaqlYamlLoader) 373 DummyYaqlYamlLoader)
367 self._classes[class_name] = klass 374 if not klass_list:
375 raise ValueError('No classes defined in file')
376 resolver = None
377 for klass in klass_list:
378 ns = klass.get('Namespaces')
379 if ns:
380 resolver = NamespaceResolver(ns)
381 name = klass.get('Name')
382 if name and resolver:
383 name = resolver.resolve_name(name)
384 if name == class_name:
385 self._classes[class_name] = klass
386 self._resolvers[class_name] = resolver
387 break
368 return self._classes 388 return self._classes
369 389
370 @property 390 @property
@@ -669,3 +689,32 @@ def traverse_and_replace(obj,
669 _maybe_replace(obj, key, value) 689 _maybe_replace(obj, key, value)
670 else: 690 else:
671 _maybe_replace(obj, key, value) 691 _maybe_replace(obj, key, value)
692
693
694class NamespaceResolver(object):
695 """Copied from main murano repo
696
697 original at murano/dsl/namespace_resolver.py
698 """
699
700 def __init__(self, namespaces):
701 self._namespaces = namespaces
702 self._namespaces[''] = ''
703
704 def resolve_name(self, name, relative=None):
705 if name is None:
706 raise ValueError()
707 if name and name.startswith(':'):
708 return name[1:]
709 if ':' in name:
710 parts = name.split(':')
711 if len(parts) != 2 or not parts[1]:
712 raise NameError('Incorrectly formatted name ' + name)
713 if parts[0] not in self._namespaces:
714 raise KeyError('Unknown namespace prefix ' + parts[0])
715 return '.'.join((self._namespaces[parts[0]], parts[1]))
716 if not relative and '=' in self._namespaces and '.' not in name:
717 return '.'.join((self._namespaces['='], name))
718 if relative and '.' not in name:
719 return '.'.join((relative, name))
720 return name
diff --git a/muranoclient/v1/artifact_packages.py b/muranoclient/v1/artifact_packages.py
index 7b082ab..286819e 100644
--- a/muranoclient/v1/artifact_packages.py
+++ b/muranoclient/v1/artifact_packages.py
@@ -52,7 +52,8 @@ class ArtifactRepo(object):
52 for k, v in six.iteritems(kwargs): 52 for k, v in six.iteritems(kwargs):
53 package_draft[k] = v 53 package_draft[k] = v
54 54
55 inherits = self._get_local_inheritance(package.classes) 55 inherits = self._get_local_inheritance(package.classes,
56 package.resolvers)
56 57
57 package_draft['inherits'] = inherits 58 package_draft['inherits'] = inherits
58 59
@@ -90,16 +91,16 @@ class ArtifactRepo(object):
90 return self.client.artifacts.get(app_id) 91 return self.client.artifacts.get(app_id)
91 92
92 @staticmethod 93 @staticmethod
93 def _get_local_inheritance(classes): 94 def _get_local_inheritance(classes, resolvers):
94 result = {} 95 result = {}
95 for class_name, klass in six.iteritems(classes): 96 for class_name, klass in six.iteritems(classes):
96 if 'Extends' not in klass: 97 if 'Extends' not in klass:
97 continue 98 continue
98 ns = klass.get('Namespaces') 99 ns = klass.get('Namespaces')
99 if ns: 100 if ns:
100 resolver = NamespaceResolver(ns) 101 resolver = utils.NamespaceResolver(ns)
101 else: 102 else:
102 resolver = None 103 resolver = resolvers.get(class_name)
103 104
104 if isinstance(klass['Extends'], list): 105 if isinstance(klass['Extends'], list):
105 bases = klass['Extends'] 106 bases = klass['Extends']
@@ -337,32 +338,3 @@ class PackageWrapper(object):
337 {'pkg_name': self.name, 338 {'pkg_name': self.name,
338 'attrs': ", ".join(missing_keys)}) 339 'attrs': ", ".join(missing_keys)})
339 return {key: getattr(self, key) for key in keys} 340 return {key: getattr(self, key) for key in keys}
340
341
342class NamespaceResolver(object):
343 """Copied from main murano repo
344
345 original at murano/dsl/namespace_resolver.py
346 """
347
348 def __init__(self, namespaces):
349 self._namespaces = namespaces
350 self._namespaces[''] = ''
351
352 def resolve_name(self, name, relative=None):
353 if name is None:
354 raise ValueError()
355 if name and name.startswith(':'):
356 return name[1:]
357 if ':' in name:
358 parts = name.split(':')
359 if len(parts) != 2 or not parts[1]:
360 raise NameError('Incorrectly formatted name ' + name)
361 if parts[0] not in self._namespaces:
362 raise KeyError('Unknown namespace prefix ' + parts[0])
363 return '.'.join((self._namespaces[parts[0]], parts[1]))
364 if not relative and '=' in self._namespaces and '.' not in name:
365 return '.'.join((self._namespaces['='], name))
366 if relative and '.' not in name:
367 return '.'.join((relative, name))
368 return name
diff --git a/releasenotes/notes/multi-class-yamls-support-914b3d155324214f.yaml b/releasenotes/notes/multi-class-yamls-support-914b3d155324214f.yaml
new file mode 100644
index 0000000..1d26c2f
--- /dev/null
+++ b/releasenotes/notes/multi-class-yamls-support-914b3d155324214f.yaml
@@ -0,0 +1,4 @@
1---
2fixes:
3 - Fixed a bug when a package containing multi-class yamls could not be added
4 to glare-based catalog.