Skip to content

Commit

Permalink
salt: Add execution module to retrieve value from map.jinja
Browse files Browse the repository at this point in the history
In salt we have a function `jinja.load_map` that retrieve a specific
value from a map.jinja (same as what we do in salt SLS) but this
function does not support saltenv
Add a new function to retrieve information from `map.jinja` in MetalK8s
context, so hardcoded map.jinja path and retrieving saltenv from version
stored in the pillar
Sees: saltstack/salt#59300
  • Loading branch information
TeddyAndrieux committed Jan 18, 2021
1 parent 7944925 commit f171f58
Show file tree
Hide file tree
Showing 2 changed files with 108 additions and 1 deletion.
58 changes: 58 additions & 0 deletions salt/_modules/metalk8s.py
Original file line number Diff line number Diff line change
Expand Up @@ -10,10 +10,13 @@
import six
import socket
import tempfile
import textwrap
import time

from salt.pillar import get_pillar
from salt.exceptions import CommandExecutionError
import salt.loader
import salt.template
import salt.utils.args
import salt.utils.files
from salt.utils.hashutils import get_hash
Expand Down Expand Up @@ -557,3 +560,58 @@ def _clean_tmp(sfn):
if source_filename:
_clean_tmp(source_filename)
return ret


def get_from_map(value, saltenv=None):
"""Get a value from map.jinja so that we have an up to date value
computed from defaults.yaml and pillar.
Basically the same as a `jinja.map_load` but with support for saltenv and
also hardcoded path to MetalK8s map.jinja.
Also add logic to retrieve the saltenv using version in the pillar.
Arguments:
value (str): Name of the value to retrieve
CLI Example:
.. code-block:: bash
# Retrieve `metalk8s` merge between defaults.yaml and pillar using
# current node version as saltenv
salt '*' metalk8s.get_from_map metalk8s
# Retrieve `metalk8s` from a specific saltenv
salt '*' metalk8s.get_from_map meltak8s saltenv=my-salt-env
"""
path = "metalk8s/map.jinja"
if not saltenv:
current_version = __pillar__.get('metalk8s', {}).get('nodes', {}).get(
__grains__['id'], {}).get('version')
if not current_version:
log.warning(
'Unable to retrieve current running version, fallback on "base"'
)
saltenv = 'base'
else:
saltenv = "metalk8s-{}".format(current_version)

tmplstr = textwrap.dedent(
"""\
{{% from "{path}" import {value} with context %}}
{{{{ {value} | tojson }}}}
""".format(
path=path, value=value
)
)
return salt.template.compile_template(
":string:",
salt.loader.render(__opts__, __salt__),
__opts__["renderer"],
__opts__["renderer_blacklist"],
__opts__["renderer_whitelist"],
input_data=tmplstr,
saltenv=saltenv
)
51 changes: 50 additions & 1 deletion salt/tests/unit/modules/test_metalk8s.py
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,8 @@

from parameterized import param, parameterized
from salt.exceptions import CommandExecutionError
import salt.renderers.jinja
import salt.renderers.yaml
import salt.utils.files
import yaml

Expand Down Expand Up @@ -41,7 +43,13 @@ class Metalk8sTestCase(TestCase, mixins.LoaderModuleMockMixin):
loader_module_globals = {
"__grains__": {
"id": "my_node_1"
}
},
"__opts__": {
"renderer": "jinja|yaml",
"renderer_blacklist": [],
"renderer_whitelist": []
},
"__salt__": {}
}

def test_virtual(self):
Expand Down Expand Up @@ -469,3 +477,44 @@ def _get_diff(*_a, **_k):
self.assertEqual(remove_mock.call_count, 0)
else:
self.assertEqual(remove_mock.call_count, 1)

@parameterized.expand([
param(),
param(saltenv='my-salt-env', expected_saltenv='my-salt-env'),
param(node_version='1.2.3', expected_saltenv='metalk8s-1.2.3'),
param(node_version=None, expected_saltenv='base')
])
def test_get_from_map(self, saltenv=None, expected_saltenv="base",
node_version=None):
"""
Tests the return of `get_from_map` function
"""
# NOTE: The goal is not to test the `compile_template` function from
# salt so just ignore the return of the function but check that we
# give the right arguments
expected_args = {
'input_data': '{% from "metalk8s/map.jinja" import my-key with context %}\n{{ my-key | tojson }}\n',
'saltenv': expected_saltenv
}
pillar_content = {}
if node_version:
pillar_content = {
'metalk8s': {
'nodes': {
'my_node_1': {
'version': node_version
}
}
}
}

compile_template_mock = MagicMock()
with patch.dict(metalk8s.__pillar__, pillar_content), \
patch('salt.loader.render', MagicMock()), \
patch("salt.template.compile_template", compile_template_mock):
metalk8s.get_from_map('my-key', saltenv=saltenv)
compile_template_mock.assert_called_once()
self.assertDictContainsSubset(
expected_args,
compile_template_mock.call_args[1]
)

0 comments on commit f171f58

Please # to comment.