Description
Experpt from Neon release notes and docs: https://docs.saltstack.com/en/develop/topics/releases/neon.html
https://docs.saltstack.com/en/develop/ref/modules/all/salt.modules.saltcheck.html
Saltcheck provides unittest like functionality requiring only the knowledge of salt module execution and yaml. Saltcheck uses salt modules to return data, then runs an assertion against that return. This allows for testing with all the features included in salt modules.
tst
files are run through the salt rendering system, enabling tests to be written in yaml (or renderer of choice), and include jinja, as well as the usual grain and pillar information.
saltcheck
can be used for formula tests as part of a CI pipeline and can also be run on machines in your environment as part of a QA validation step. Personally, I see a lot of benefit to including saltcheck-tests directories in upstream formulas, as it allows for instant testing capability without other dependencies and using a state-like yaml syntax which understands pillars. For example, validating that 100 users (defined in a pillar) are properly provisioned is trivial and clear in saltcheck, while writing the same in inspec would require duplication of the salt pillar data as well as needing inspec and its dependencies which might not be appropriate in a production environment.
Example file system layout:
/srv/salt/apache/
init.sls
config.sls
saltcheck-tests/
init.tst
config.tst
deployment_validation.tst
Tests can be run for each state by name, for all apache/saltcheck/*.tst files, or for all states assigned to the minion in top.sls. Tests may also be created with no associated state. These tests will be run through the use of saltcheck.run_state_tests, but will not be automatically run by saltcheck.run_highstate_tests.
salt '*' saltcheck.run_state_tests apache,apache.config
salt '*' saltcheck.run_state_tests apache check_all=True
salt '*' saltcheck.run_highstate_tests
salt '*' saltcheck.run_state_tests apache.deployment_validation
Verify package installed:
verify_vim:
module_and_function: pkg.version
args:
- vim
assertion: assertNotEmpty
Ensure latest package installed:
{% for package in ["apache2", "openssh"] %}
{# or another example #}
{# for package in salt['pillar.get']("packages") #}
jinja_test_{{ package }}_latest:
module_and_function: pkg.upgrade_available
args:
- {{ package }}
assertion: assertFalse
{% endfor %}
Ensure python can load boto and boto3 libraries:
common/saltcheck-tests/init.tst
boto-installed:
module_and_function: cmd.run
args:
- python -c 'import pkgutil; print(1 if pkgutil.find_loader("boto") else 0)'
assertion: assertNotEqual
expected-return: 0
boto3-installed:
module_and_function: cmd.run
args:
- python -c 'import pkgutil; print(1 if pkgutil.find_loader("boto3") else 0)'
assertion: assertEqual
expected-return: 1
Test that all users exist and have the expected ssh keys. Might be appropriate for the users formula, for example.
users/saltcheck-tests/init.tst
{% for usr,data in salt['pillar.get']('users').items() %}
validate_user_{{ usr }}:
module_and_function: user.info
assertion_section: shell
args:
- {{ usr }}
assertion: assertEqual
expected-return: /bin/bash
{%- if 'key' in data %}
check_ssh_key_{{ usr }}:
module_and_function: ssh.check_key
args:
- {{ usr }}
- {{ data.key }}
- ssh-rsa
- ''
- ''
assertion: assertEqual
expected-return: exists
{%- endif %}
{% endfor %}
I'd envision having basic tests like pkg.version
is notNull
, service.status
is True
, and maybe a file.contains
is True
live in most formulas. Since salt already has the map.jina and pkg manager abstractions, these tests can easily be upstreamed allowing for everyone's use.