Optionally propagate pillar data from Salt to reclass
Optionally, data from pillars that run before the reclass ``ext_pillar``
(i.e. Salt's builtin ``pillar_roots``, as well as other ``ext_pillar``
modules listed before the ``reclass_adapter``) can be made available to
reclass. Please use this with caution as referencing data from Salt in
the inventory will make it harder or impossible to run |reclass| in
other environments. This feature is therefore turned off by default and
must be explicitly enabled in the Salt master configuration file, like
this:
reclass: &reclass
[…]
propagate_pillar_data_to_reclass: True
Signed-off-by: martin f. krafft <madduck@madduck.net>
diff --git a/doc/source/changelog.rst b/doc/source/changelog.rst
index 25bda17..9f91569 100644
--- a/doc/source/changelog.rst
+++ b/doc/source/changelog.rst
@@ -5,6 +5,8 @@
========= ========== ========================================================
Version Date Changes
========= ========== ========================================================
+ * Salt: pillar data from previous pillars are now
+ available to reclass parameter interpolation
* yaml_fs: classes may be defined in subdirectories
(closes: #12, #19, #20)
* Migrate Salt adapter to new core API (closes: #18)
diff --git a/doc/source/salt.rst b/doc/source/salt.rst
index f0cc733..a5f9a73 100644
--- a/doc/source/salt.rst
+++ b/doc/source/salt.rst
@@ -178,9 +178,9 @@
Similarly, all parameters that are collected and merged eventually end up in
the pillar data of a specific node.
-However, the pillar data of a node include all the information about classes
-and applications, so you could theoretically use them to target your Salt
-calls at groups of nodes defined in the |reclass| inventory, e.g.
+The pillar data of a node include all the information about classes and
+applications, so you could theoretically use them to target your Salt calls at
+groups of nodes defined in the |reclass| inventory, e.g.
::
@@ -189,5 +189,17 @@
Unfortunately, this does not work yet, please stay tuned, and let me know
if you figure out a way. `Salt issue #5787`_ is also of relevance.
+Optionally, data from pillars that run before the |reclass| ``ext_pillar``
+(i.e. Salt's builtin ``pillar_roots``, as well as other ``ext_pillar`` modules
+listed before the ``reclass_adapter``) can be made available to |reclass|.
+Please use this with caution as referencing data from Salt in the inventory
+will make it harder or impossible to run |reclass| in other environments. This
+feature is therefore turned off by default and must be explicitly enabled in
+the Salt master configuration file, like this::
+
+ reclass: &reclass
+ […]
+ propagate_pillar_data_to_reclass: True
+
.. include:: substs.inc
.. include:: extrefs.inc
diff --git a/reclass/adapters/salt.py b/reclass/adapters/salt.py
index dfffc6e..1b45823 100755
--- a/reclass/adapters/salt.py
+++ b/reclass/adapters/salt.py
@@ -23,13 +23,17 @@
inventory_base_uri=OPT_INVENTORY_BASE_URI,
nodes_uri=OPT_NODES_URI,
classes_uri=OPT_CLASSES_URI,
- class_mappings=None):
+ class_mappings=None,
+ propagate_pillar_data_to_reclass=False):
nodes_uri, classes_uri = path_mangler(inventory_base_uri,
nodes_uri, classes_uri)
storage = get_storage(storage_type, nodes_uri, classes_uri,
default_environment='base')
- reclass = Core(storage, class_mappings)
+ input_data = None
+ if propagate_pillar_data_to_reclass:
+ input_data = pillar
+ reclass = Core(storage, class_mappings, input_data=input_data)
data = reclass.nodeinfo(minion_id)
params = data.get('parameters', {})
@@ -50,7 +54,7 @@
nodes_uri, classes_uri)
storage = get_storage(storage_type, nodes_uri, classes_uri,
default_environment='base')
- reclass = Core(storage, class_mappings)
+ reclass = Core(storage, class_mappings, input_data=None)
# if the minion_id is not None, then return just the applications for the
# specific minion, otherwise return the entire top data (which we need for
diff --git a/reclass/core.py b/reclass/core.py
index f65fb82..76bd0a8 100644
--- a/reclass/core.py
+++ b/reclass/core.py
@@ -13,14 +13,15 @@
#import sys
import fnmatch
import shlex
-from reclass.datatypes import Entity, Classes
+from reclass.datatypes import Entity, Classes, Parameters
from reclass.errors import MappingFormatError, ClassNotFound
class Core(object):
- def __init__(self, storage, class_mappings):
+ def __init__(self, storage, class_mappings, input_data=None):
self._storage = storage
self._class_mappings = class_mappings
+ self._input_data = input_data
@staticmethod
def _get_timestamp():
@@ -53,9 +54,9 @@
key = '/{0}/'.format(key)
return key, list(lexer)
- def _populate_with_class_mappings(self, nodename):
+ def _get_class_mappings_entity(self, nodename):
if not self._class_mappings:
- return Entity(name='empty')
+ return Entity(name='empty (class mappings)')
c = Classes()
for mapping in self._class_mappings:
matched = False
@@ -74,6 +75,12 @@
return Entity(classes=c,
name='class mappings for node {0}'.format(nodename))
+ def _get_input_data_entity(self):
+ if not self._input_data:
+ return Entity(name='empty (input data)')
+ p = Parameters(self._input_data)
+ return Entity(parameters=p, name='input data')
+
def _recurse_entity(self, entity, merge_base=None, seen=None, nodename=None):
if seen is None:
seen = {}
@@ -104,7 +111,9 @@
def _nodeinfo(self, nodename):
node_entity = self._storage.get_node(nodename)
- base_entity = self._populate_with_class_mappings(node_entity.name)
+ base_entity = Entity(name='base')
+ base_entity.merge(self._get_class_mappings_entity(node_entity.name))
+ base_entity.merge(self._get_input_data_entity())
seen = {}
merge_base = self._recurse_entity(base_entity, seen=seen,
nodename=base_entity.name)