Merge pull request #61 from salt-formulas/bump-156
Bump 156
diff --git a/README-extentions.rst b/README-extentions.rst
index ec10e48..2bc4816 100644
--- a/README-extentions.rst
+++ b/README-extentions.rst
@@ -228,7 +228,7 @@
parameters:
y: 1
-
+
The parameter ``a`` only depends on the parameter ``y`` through the reference set in class2. The fact that the parameter ``x`` referenced
in class1 is not defined does not affect the final value of the parameter ``a``. For such overwritten missing references by default a warning is
printed but no error is raised, providing the final value of the parameter being evaluated is a scalar. If the final value is a dictionary or list
@@ -507,3 +507,34 @@
The above exports and parameter definitions could be put into a separate class and then included by nodes which require
access to the database and included by the database server as well.
+
+
+Compose node name
+---------------------------
+
+Nodes can be defined in subdirectories. However, node names (filename) must be unique across all subdirectories.
+
+For example, the following file structure is invalid:
+
+.. code-block:: yaml
+
+ inventory/nodes/prod/mysql.yml
+ inventory/nodes/staging/mysql.yml
+
+With setting:
+
+.. code-block:: yaml
+
+ compose_node_name: True # default False
+
+This adds the subfolder to the node name and the structure above can then be used. It generates the following reclass objects:
+
+.. code-block:: yaml
+
+ nodes:
+ prod.mysql:
+ ...
+ staging.mysql:
+ ...
+
+If the subfolder path starts with the underscore character ``_``, then the subfolder path is NOT added to the node name.
diff --git a/reclass/__init__.py b/reclass/__init__.py
index 3739b5e..2167a30 100644
--- a/reclass/__init__.py
+++ b/reclass/__init__.py
@@ -15,9 +15,9 @@
from .storage.loader import StorageBackendLoader
from .storage.memcache_proxy import MemcacheProxy
-def get_storage(storage_type, nodes_uri, classes_uri, **kwargs):
+def get_storage(storage_type, nodes_uri, classes_uri, compose_node_name, **kwargs):
storage_class = StorageBackendLoader(storage_type).load()
- return MemcacheProxy(storage_class(nodes_uri, classes_uri, **kwargs))
+ return MemcacheProxy(storage_class(nodes_uri, classes_uri, compose_node_name, **kwargs))
def get_path_mangler(storage_type,**kwargs):
return StorageBackendLoader(storage_type).path_mangler()
diff --git a/reclass/adapters/ansible.py b/reclass/adapters/ansible.py
index abf7df2..be67198 100755
--- a/reclass/adapters/ansible.py
+++ b/reclass/adapters/ansible.py
@@ -66,7 +66,10 @@
add_options_cb=add_ansible_options_group,
defaults=defaults)
- storage = get_storage(options.storage_type, options.nodes_uri, options.classes_uri)
+ storage = get_storage(options.storage_type,
+ options.nodes_uri,
+ options.classes_uri,
+ options.compose_node_name)
class_mappings = defaults.get('class_mappings')
defaults.update(vars(options))
settings = Settings(defaults)
diff --git a/reclass/adapters/salt.py b/reclass/adapters/salt.py
index ce4e792..523b0c4 100755
--- a/reclass/adapters/salt.py
+++ b/reclass/adapters/salt.py
@@ -31,11 +31,12 @@
classes_uri=OPT_CLASSES_URI,
class_mappings=None,
propagate_pillar_data_to_reclass=False,
+ compose_node_name=OPT_COMPOSE_NODE_NAME,
**kwargs):
path_mangler = get_path_mangler(storage_type)
nodes_uri, classes_uri = path_mangler(inventory_base_uri, nodes_uri, classes_uri)
- storage = get_storage(storage_type, nodes_uri, classes_uri)
+ storage = get_storage(storage_type, nodes_uri, classes_uri, compose_node_name)
input_data = None
if propagate_pillar_data_to_reclass:
input_data = pillar
@@ -54,11 +55,12 @@
def top(minion_id, storage_type=OPT_STORAGE_TYPE,
inventory_base_uri=OPT_INVENTORY_BASE_URI, nodes_uri=OPT_NODES_URI,
- classes_uri=OPT_CLASSES_URI, class_mappings=None, **kwargs):
+ classes_uri=OPT_CLASSES_URI, class_mappings=None, compose_node_name=OPT_COMPOSE_NODE_NAME,
+ **kwargs):
path_mangler = get_path_mangler(storage_type)
nodes_uri, classes_uri = path_mangler(inventory_base_uri, nodes_uri, classes_uri)
- storage = get_storage(storage_type, nodes_uri, classes_uri)
+ storage = get_storage(storage_type, nodes_uri, classes_uri, compose_node_name)
settings = Settings(kwargs)
reclass = Core(storage, class_mappings, settings, input_data=None)
diff --git a/reclass/cli.py b/reclass/cli.py
index 44694c5..38bd5fc 100644
--- a/reclass/cli.py
+++ b/reclass/cli.py
@@ -31,7 +31,10 @@
defaults.update(find_and_read_configfile())
options = get_options(RECLASS_NAME, VERSION, DESCRIPTION, defaults=defaults)
- storage = get_storage(options.storage_type, options.nodes_uri, options.classes_uri)
+ storage = get_storage(options.storage_type,
+ options.nodes_uri,
+ options.classes_uri,
+ options.compose_node_name)
class_mappings = defaults.get('class_mappings')
defaults.update(vars(options))
settings = Settings(defaults)
diff --git a/reclass/config.py b/reclass/config.py
index 1a6ba81..d24f7fd 100644
--- a/reclass/config.py
+++ b/reclass/config.py
@@ -36,6 +36,9 @@
ret.add_option('-z', '--ignore-class-notfound', dest='ignore_class_notfound',
default=defaults.get('ignore_class_notfound', OPT_IGNORE_CLASS_NOTFOUND),
help='decision for not found classes [%default]')
+ ret.add_option('-a', '--compose-node-name', dest='compose_node_name', action="store_true",
+ default=defaults.get('compose_node_name', OPT_COMPOSE_NODE_NAME),
+ help='Add subdir when generating node names. [%default]')
ret.add_option('-x', '--ignore-class-notfound-regexp', dest='ignore_class_notfound_regexp',
default=defaults.get('ignore_class_notfound_regexp', OPT_IGNORE_CLASS_NOTFOUND_REGEXP),
help='regexp for not found classes [%default]')
diff --git a/reclass/defaults.py b/reclass/defaults.py
index 1e50c0e..f240f3f 100644
--- a/reclass/defaults.py
+++ b/reclass/defaults.py
@@ -21,6 +21,7 @@
OPT_CLASSES_URI = 'classes'
OPT_PRETTY_PRINT = True
OPT_GROUP_ERRORS = True
+OPT_COMPOSE_NODE_NAME = False
OPT_NO_REFS = False
OPT_OUTPUT = 'yaml'
diff --git a/reclass/settings.py b/reclass/settings.py
index 51c518f..3e223cc 100644
--- a/reclass/settings.py
+++ b/reclass/settings.py
@@ -32,6 +32,7 @@
self.reference_sentinels = options.get('reference_sentinels', REFERENCE_SENTINELS)
self.ignore_class_notfound = options.get('ignore_class_notfound', OPT_IGNORE_CLASS_NOTFOUND)
self.strict_constant_parameters = options.get('strict_constant_parameters', OPT_STRICT_CONSTANT_PARAMETERS)
+ self.compose_node_name = options.get('compose_node_name', OPT_COMPOSE_NODE_NAME)
self.ignore_class_notfound_regexp = options.get('ignore_class_notfound_regexp', OPT_IGNORE_CLASS_NOTFOUND_REGEXP)
if isinstance(self.ignore_class_notfound_regexp, string_types):
@@ -65,7 +66,8 @@
and self.ignore_class_notfound == other.ignore_class_notfound \
and self.ignore_class_notfound_regexp == other.ignore_class_notfound_regexp \
and self.ignore_class_notfound_warning == other.ignore_class_notfound_warning \
- and self.strict_constant_parameters == other.strict_constant_parameters
+ and self.strict_constant_parameters == other.strict_constant_parameters \
+ and self.compose_node_name == other.compose_node_name
def __copy__(self):
cls = self.__class__
diff --git a/reclass/storage/common.py b/reclass/storage/common.py
index 7de71d0..13db7ec 100644
--- a/reclass/storage/common.py
+++ b/reclass/storage/common.py
@@ -14,6 +14,17 @@
return relpath, name
@staticmethod
+ def composed_nodes(relpath, name):
+ if relpath == '.' or relpath == '':
+ # './' is converted to None
+ return None, name
+ parts = relpath.split(os.path.sep)
+ if parts[0].startswith("_"):
+ return relpath, name
+ parts.append(name)
+ return relpath, '.'.join(parts)
+
+ @staticmethod
def classes(relpath, name):
if relpath == '.' or relpath == '':
# './' is converted to None
diff --git a/reclass/storage/yaml_fs/__init__.py b/reclass/storage/yaml_fs/__init__.py
index a102f31..7ed3fe4 100644
--- a/reclass/storage/yaml_fs/__init__.py
+++ b/reclass/storage/yaml_fs/__init__.py
@@ -55,12 +55,16 @@
class ExternalNodeStorage(NodeStorageBase):
- def __init__(self, nodes_uri, classes_uri):
+ def __init__(self, nodes_uri, classes_uri, compose_node_name):
super(ExternalNodeStorage, self).__init__(STORAGE_NAME)
if nodes_uri is not None:
self._nodes_uri = nodes_uri
- self._nodes = self._enumerate_inventory(nodes_uri, NameMangler.nodes)
+ if compose_node_name:
+ self._nodes = self._enumerate_inventory(nodes_uri, NameMangler.composed_nodes)
+ else:
+ self._nodes = self._enumerate_inventory(nodes_uri, NameMangler.nodes)
+
if classes_uri is not None:
self._classes_uri = classes_uri
diff --git a/reclass/tests/test_core.py b/reclass/tests/test_core.py
index 679d6ca..047bf24 100644
--- a/reclass/tests/test_core.py
+++ b/reclass/tests/test_core.py
@@ -27,8 +27,8 @@
inventory_uri = os.path.dirname(os.path.abspath(__file__)) + '/data/' + dataset
path_mangler = get_path_mangler('yaml_fs')
nodes_uri, classes_uri = path_mangler(inventory_uri, 'nodes', 'classes')
- storage = get_storage('yaml_fs', nodes_uri, classes_uri)
settings = Settings(opts)
+ storage = get_storage('yaml_fs', nodes_uri, classes_uri, settings.compose_node_name)
return Core(storage, None, settings)
def test_type_conversion(self):