Skip to content

Commit

Permalink
feat: Inventory for variable values
Browse files Browse the repository at this point in the history
This CL adds an experimental inventory area in the pillar data, which is
not return in the result and can easily access with a minion lookup
scope. It can be used for minion-specific variables that are used in
more generic shared roles/other pillar files.
  • Loading branch information
jgraichen committed Nov 23, 2022
1 parent 50e910b commit 8bee0d0
Show file tree
Hide file tree
Showing 4 changed files with 104 additions and 0 deletions.
1 change: 1 addition & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,7 @@ and this project adheres to [Semantic Versioning](http://semver.org/spec/v2.0.0.
### Added

- Raise error from yamlet renderer when an included file does not exist
- Experimental inventory feature

## [1.10.0] - 2022-09-03

Expand Down
42 changes: 42 additions & 0 deletions docs/configuration.md
Original file line number Diff line number Diff line change
Expand Up @@ -108,3 +108,45 @@ The `salt_tower.unstable_enable_saltenv` flag modifies some options passed to th
By setting `salt_tower.unstable_enable_saltenv` to `True`, Salt Tower will pass additional flags to the rendering pipeline, indicating that pillars are rendered. Engines, such as JINJA, will now look up files in `pillar_roots`. This can work well, when you Salt Tower base directory is the same as the pillar root directory.

See issue [#11](https://github.com/jgraichen/salt-tower/issues/11) for more details.

### salt_tower.enable_inventory

**Experimental feature**: Enables the `inventory` mode. All pillar data within the `inventory:` subtree will not be returned in the final result. Instead, an additional context module is passed to templates, easing access to minion-scoped variables.

This _inventory_ can be used to provide specialized, independent variable values to other pillar files such as roles. See the following example:

```yaml title="tower.sls"
base:
- inventory/*
- 'web*'
- role/web
```

```yaml title="inventory/vars.sls"
inventory:
web-0:
ip:
public: 203.0.113.100
nginx:
server_name: example.org
web-1:
ip:
public: 203.0.113.110
nginx:
server_name: example.com
```

```yaml title="role/web.sls"
states:
- nginx
nginx:
config: |
server {
listen {{ inventory.get('ip:public') }}:80;
server_name {{ inventory.get('nginx:server_name') }};
}
```

The inventory can provide custom variables to be used in larger pillar files, or used in multiple roles.
17 changes: 17 additions & 0 deletions salt_tower/pillar/tower.py
Original file line number Diff line number Diff line change
Expand Up @@ -161,6 +161,10 @@ def run(self, top):
else:
self._load_item(base, item)

if __opts__.get("salt_tower.enable_inventory", False):
if "inventory" in self:
del self["inventory"]

def _match_minion(self, tgt):
try:
if hasattr(__grains__, "value"):
Expand Down Expand Up @@ -328,6 +332,9 @@ def _compile( # pylint: disable=too-many-arguments
ctx["tower"] = self
ctx["env"] = self.env

if __opts__.get("salt_tower.enable_inventory", False):
ctx["inventory"] = Inventory(self)

def render(path, context=None, renderer="text"):
if isinstance(context, dict):
context = {**ctx, **context}
Expand Down Expand Up @@ -388,6 +395,16 @@ def render(path, context=None, renderer="text"):
raise err


class Inventory: # pylint: disable=too-few-public-methods
def __init__(self, tower):
self._tower = tower

def get(self, key, minion=None, require=True, **kwargs):
if not minion:
minion = self._tower.minion_id
return self._tower.get(f"inventory:{minion}:{key}", require=require, **kwargs)


class Formatter(string.Formatter):
def __init__(self, tower):
self._tower = tower
Expand Down
44 changes: 44 additions & 0 deletions test/pillar/test_tower.py
Original file line number Diff line number Diff line change
Expand Up @@ -707,3 +707,47 @@ def test_tower_jinja_import_roots(env):
)

assert env.ext_pillar() == {"foo": "pillar_root"}


def test_tower_inventory_disabled(env):
env.setup(
{
"tower.sls": """
base:
- '*':
- inventory.sls
""",
"inventory.sls": """
inventory:
test_master:
key: 1
""",
}
)

assert env.ext_pillar() == {"inventory": {"test_master": {"key": 1}}}


def test_tower_inventory_get(env):
env.opts.update({"salt_tower.enable_inventory": True})

env.setup(
{
"tower.sls": """
base:
- '*':
- inventory.sls
- init.sls
""",
"inventory.sls": """
inventory:
test_master:
foo: 1
""",
"init.sls": """
bar: {{ inventory.get('foo') }}
""",
}
)

assert env.ext_pillar() == {"bar": 1}

0 comments on commit 8bee0d0

Please sign in to comment.