mirror of
https://github.com/saltstack/salt.git
synced 2025-04-16 17:50:20 +00:00
454 lines
16 KiB
Python
454 lines
16 KiB
Python
import pytest
|
|
import salt.defaults.exitcodes
|
|
|
|
pytestmark = [
|
|
pytest.mark.slow_test,
|
|
pytest.mark.windows_whitelisted,
|
|
]
|
|
|
|
|
|
@pytest.fixture(scope="module")
|
|
def pillar_tree(base_env_pillar_tree_root_dir, salt_minion, salt_sub_minion, salt_cli):
|
|
top_file = """
|
|
base:
|
|
'{}':
|
|
- basic
|
|
'{}':
|
|
- basic
|
|
- sub
|
|
""".format(
|
|
salt_minion.id, salt_sub_minion.id
|
|
)
|
|
basic_pillar_file = """
|
|
monty: python
|
|
os: {{ grains['os'] }}
|
|
{% if grains['os'] == 'Fedora' %}
|
|
class: redhat
|
|
{% else %}
|
|
class: other
|
|
{% endif %}
|
|
|
|
knights:
|
|
- Lancelot
|
|
- Galahad
|
|
- Bedevere
|
|
- Robin
|
|
|
|
level1:
|
|
level2: foo
|
|
|
|
companions:
|
|
three:
|
|
- liz
|
|
- jo
|
|
- sarah jane
|
|
"""
|
|
sub_pillar_file = """
|
|
sub: {}
|
|
""".format(
|
|
salt_sub_minion.id
|
|
)
|
|
top_tempfile = pytest.helpers.temp_file(
|
|
"top.sls", top_file, base_env_pillar_tree_root_dir
|
|
)
|
|
basic_tempfile = pytest.helpers.temp_file(
|
|
"basic.sls", basic_pillar_file, base_env_pillar_tree_root_dir
|
|
)
|
|
sub_tempfile = pytest.helpers.temp_file(
|
|
"sub.sls", sub_pillar_file, base_env_pillar_tree_root_dir
|
|
)
|
|
try:
|
|
with top_tempfile, basic_tempfile, sub_tempfile:
|
|
ret = salt_cli.run("saltutil.refresh_pillar", wait=True, minion_tgt="*")
|
|
assert ret.exitcode == 0
|
|
assert salt_minion.id in ret.json
|
|
assert ret.json[salt_minion.id] is True
|
|
assert salt_sub_minion.id in ret.json
|
|
assert ret.json[salt_sub_minion.id] is True
|
|
yield
|
|
finally:
|
|
# Refresh pillar again to cleaup the temp pillar
|
|
ret = salt_cli.run("saltutil.refresh_pillar", wait=True, minion_tgt="*")
|
|
assert ret.exitcode == 0
|
|
assert salt_minion.id in ret.json
|
|
assert ret.json[salt_minion.id] is True
|
|
assert salt_sub_minion.id in ret.json
|
|
assert ret.json[salt_sub_minion.id] is True
|
|
|
|
|
|
def test_list(salt_cli, salt_minion, salt_sub_minion):
|
|
"""
|
|
test salt -L matcher
|
|
"""
|
|
ret = salt_cli.run("-L", "test.ping", minion_tgt=salt_minion.id)
|
|
assert ret.exitcode == 0
|
|
assert ret.json is True
|
|
assert salt_minion.id in ret.stdout
|
|
assert salt_sub_minion.id not in ret.stdout
|
|
ret = salt_cli.run(
|
|
"-L", "test.ping", minion_tgt="{},{}".format(salt_minion.id, salt_sub_minion.id)
|
|
)
|
|
assert ret.exitcode == 0
|
|
assert salt_minion.id in ret.json
|
|
assert salt_sub_minion.id in ret.json
|
|
|
|
|
|
def test_compound_min_with_grain(salt_cli, salt_minion, salt_sub_minion):
|
|
"""
|
|
test salt compound matcher
|
|
"""
|
|
ret = salt_cli.run("-C", "test.ping", minion_tgt="min* and G@test_grain:cheese")
|
|
assert ret.exitcode == 0
|
|
assert salt_minion.id in ret.json
|
|
assert salt_sub_minion.id not in ret.json
|
|
|
|
|
|
def test_compound_and_not_grain(salt_cli, salt_minion, salt_sub_minion):
|
|
ret = salt_cli.run("-C", "test.ping", minion_tgt="min* and not G@test_grain:foo")
|
|
assert ret.exitcode == 0
|
|
assert salt_minion.id in ret.json
|
|
assert salt_sub_minion.id not in ret.json
|
|
|
|
|
|
def test_compound_not_grain(salt_cli, salt_minion, salt_sub_minion):
|
|
ret = salt_cli.run("-C", "test.ping", minion_tgt="min* not G@test_grain:foo")
|
|
assert ret.exitcode == 0
|
|
assert salt_minion.id in ret.json
|
|
assert salt_sub_minion.id not in ret.json
|
|
|
|
|
|
def test_compound_pcre_grain_and_grain(salt_cli, salt_minion, salt_sub_minion):
|
|
match = "P@test_grain:^cheese$ and * and G@test_grain:cheese"
|
|
ret = salt_cli.run("-C", "test.ping", minion_tgt=match)
|
|
assert salt_minion.id in ret.json
|
|
assert salt_sub_minion.id not in ret.json
|
|
|
|
|
|
def test_compound_list_and_pcre_minion(salt_cli, salt_minion, salt_sub_minion):
|
|
match = "L@{} and E@.*".format(salt_sub_minion.id)
|
|
ret = salt_cli.run("-C", "test.ping", minion_tgt=match)
|
|
assert salt_sub_minion.id in ret.json
|
|
assert salt_minion.id not in ret.json
|
|
|
|
|
|
def test_compound_not_sub_minion(salt_cli, salt_minion, salt_sub_minion):
|
|
ret = salt_cli.run(
|
|
"-C", "test.ping", minion_tgt="not {}".format(salt_sub_minion.id)
|
|
)
|
|
assert ret.exitcode == 0
|
|
assert salt_minion.id in ret.json
|
|
assert salt_sub_minion.id not in ret.json
|
|
|
|
|
|
def test_compound_all_and_not_grains(salt_cli, salt_minion, salt_sub_minion):
|
|
ret = salt_cli.run(
|
|
"-C", "test.ping", minion_tgt="* and ( not G@test_grain:cheese )"
|
|
)
|
|
assert ret.exitcode == 0
|
|
assert salt_minion.id not in ret.json
|
|
assert salt_sub_minion.id in ret.json
|
|
|
|
|
|
def test_compound_grain_regex(salt_cli, salt_minion, salt_sub_minion):
|
|
ret = salt_cli.run("-C", "test.ping", minion_tgt="G%@planets%merc*")
|
|
assert ret.exitcode == 0
|
|
assert salt_minion.id in ret.json
|
|
assert salt_sub_minion.id not in ret.json
|
|
|
|
|
|
def test_coumpound_pcre_grain_regex(salt_cli, salt_minion, salt_sub_minion):
|
|
ret = salt_cli.run("-C", "test.ping", minion_tgt="P%@planets%^(mercury|saturn)$")
|
|
assert ret.exitcode == 0
|
|
assert salt_minion.id in ret.json
|
|
assert salt_sub_minion.id in ret.json
|
|
|
|
|
|
def test_compound_pillar(salt_cli, salt_minion, salt_sub_minion, pillar_tree):
|
|
# FYI, This test was previously being skipped because it was unreliable
|
|
ret = salt_cli.run("-C", "test.ping", minion_tgt="I%@companions%three%sarah*")
|
|
assert ret.exitcode == 0
|
|
assert salt_minion.id in ret.json
|
|
assert salt_sub_minion.id in ret.json
|
|
|
|
|
|
def test_compound_pillar_pcre(salt_cli, salt_minion, salt_sub_minion, pillar_tree):
|
|
# FYI, This test was previously being skipped because it was unreliable
|
|
ret = salt_cli.run("-C", "test.ping", minion_tgt="J%@knights%^(Lancelot|Galahad)$")
|
|
assert ret.exitcode == 0
|
|
assert salt_minion.id in ret.json
|
|
assert salt_sub_minion.id in ret.json
|
|
|
|
|
|
def test_compound_nodegroup(salt_cli, salt_minion, salt_sub_minion):
|
|
ret = salt_cli.run("-C", "test.ping", minion_tgt="N@multiline_nodegroup")
|
|
assert ret.exitcode == 0
|
|
assert salt_minion.id in ret.json
|
|
assert salt_sub_minion.id in ret.json
|
|
target = "N@multiline_nodegroup not {}".format(salt_sub_minion.id)
|
|
ret = salt_cli.run("-C", "test.ping", minion_tgt=target)
|
|
assert ret.exitcode == 0
|
|
assert salt_minion.id in ret.json
|
|
assert salt_sub_minion.id not in ret.json
|
|
target = "N@multiline_nodegroup not @fakenodegroup not {}".format(
|
|
salt_sub_minion.id
|
|
)
|
|
ret = salt_cli.run("-C", "test.ping", minion_tgt=target)
|
|
assert ret.exitcode == 0
|
|
assert salt_minion.id in ret.json
|
|
assert salt_sub_minion.id not in ret.json
|
|
|
|
|
|
def test_nodegroup(salt_cli, salt_minion, salt_sub_minion):
|
|
"""
|
|
test salt nodegroup matcher
|
|
"""
|
|
ret = salt_cli.run("-N", "test.ping", minion_tgt="min")
|
|
assert ret.exitcode == 0
|
|
assert salt_minion.id in ret.json
|
|
assert salt_sub_minion.id not in ret.json
|
|
ret = salt_cli.run("-N", "test.ping", minion_tgt="sub_min")
|
|
assert ret.exitcode == 0
|
|
assert salt_minion.id not in ret.json
|
|
assert salt_sub_minion.id in ret.json
|
|
ret = salt_cli.run("-N", "test.ping", minion_tgt="mins")
|
|
assert ret.exitcode == 0
|
|
assert salt_minion.id in ret.json
|
|
assert salt_sub_minion.id in ret.json
|
|
ret = salt_cli.run("-N", "test.ping", minion_tgt="unknown_nodegroup")
|
|
assert ret.exitcode == 0
|
|
assert not ret.json
|
|
ret = salt_cli.run("-N", "test.ping", minion_tgt="redundant_minions")
|
|
assert ret.exitcode == 0
|
|
assert salt_minion.id in ret.json
|
|
assert salt_sub_minion.id in ret.json
|
|
ret = salt_cli.run("-N", "test.ping", minion_tgt="nodegroup_loop_a")
|
|
assert ret.exitcode == 2 # No minions matched
|
|
ret = salt_cli.run("-N", "test.ping", minion_tgt="multiline_nodegroup")
|
|
assert ret.exitcode == 0
|
|
assert salt_minion.id in ret.json
|
|
assert salt_sub_minion.id in ret.json
|
|
|
|
|
|
def test_nodegroup_list(salt_cli, salt_minion, salt_sub_minion):
|
|
ret = salt_cli.run("-N", "test.ping", minion_tgt="list_group")
|
|
assert ret.exitcode == 0
|
|
assert salt_minion.id in ret.json
|
|
assert salt_sub_minion.id in ret.json
|
|
|
|
ret = salt_cli.run("-N", "test.ping", minion_tgt="list_group2")
|
|
assert ret.exitcode == 0
|
|
assert salt_minion.id in ret.json
|
|
assert salt_sub_minion.id in ret.json
|
|
|
|
ret = salt_cli.run("-N", "test.ping", minion_tgt="one_list_group")
|
|
assert ret.exitcode == 0
|
|
assert salt_minion.id in ret.json
|
|
assert salt_sub_minion.id not in ret.json
|
|
|
|
ret = salt_cli.run("-N", "test.ping", minion_tgt="one_minion_list")
|
|
assert ret.exitcode == 0
|
|
assert salt_minion.id in ret.json
|
|
assert salt_sub_minion.id not in ret.json
|
|
|
|
|
|
def test_glob(salt_cli, salt_minion, salt_sub_minion):
|
|
"""
|
|
test salt glob matcher
|
|
"""
|
|
ret = salt_cli.run("test.ping", minion_tgt=salt_minion.id)
|
|
assert ret.exitcode == 0
|
|
assert ret.json is True
|
|
assert salt_minion.id in ret.stdout
|
|
assert salt_sub_minion.id not in ret.stdout
|
|
ret = salt_cli.run("test.ping", minion_tgt="*")
|
|
assert ret.exitcode == 0
|
|
assert salt_minion.id in ret.json
|
|
assert salt_sub_minion.id in ret.json
|
|
|
|
|
|
def test_regex(salt_cli, salt_minion, salt_sub_minion):
|
|
"""
|
|
test salt regex matcher
|
|
"""
|
|
ret = salt_cli.run("-E", "test.ping", minion_tgt="^{}$".format(salt_minion.id))
|
|
assert ret.exitcode == 0
|
|
assert salt_minion.id in ret.json
|
|
assert salt_sub_minion.id not in ret.json
|
|
ret = salt_cli.run("-E", "test.ping", minion_tgt=".*")
|
|
assert ret.exitcode == 0
|
|
assert salt_minion.id in ret.json
|
|
assert salt_sub_minion.id in ret.json
|
|
|
|
|
|
def test_grain(salt_cli, salt_master, salt_minion, salt_sub_minion):
|
|
"""
|
|
test salt grain matcher
|
|
"""
|
|
# Sync grains
|
|
ret = salt_cli.run("saltutil.sync_grains", minion_tgt="*")
|
|
assert ret.exitcode == 0
|
|
# First-level grain (string value)
|
|
ret = salt_cli.run("-G", "test.ping", minion_tgt="test_grain:cheese")
|
|
assert ret.exitcode == 0
|
|
assert salt_minion.id in ret.json
|
|
assert salt_sub_minion.id not in ret.json
|
|
ret = salt_cli.run("-G", "test.ping", minion_tgt="test_grain:spam")
|
|
assert ret.exitcode == 0
|
|
assert salt_sub_minion.id in ret.json
|
|
assert salt_minion.id not in ret.json
|
|
# Custom grain
|
|
ret = salt_cli.run("-G", "test.ping", minion_tgt="match:maker")
|
|
assert ret.exitcode == 0
|
|
assert salt_minion.id in ret.json
|
|
assert salt_sub_minion.id in ret.json
|
|
# First-level grain (list member)
|
|
ret = salt_cli.run("-G", "test.ping", minion_tgt="planets:earth")
|
|
assert ret.exitcode == 0
|
|
assert salt_minion.id in ret.json
|
|
assert salt_sub_minion.id not in ret.json
|
|
ret = salt_cli.run("-G", "test.ping", minion_tgt="planets:saturn")
|
|
assert ret.exitcode == 0
|
|
assert salt_sub_minion.id in ret.json
|
|
assert salt_minion.id not in ret.json
|
|
ret = salt_cli.run("-G", "test.ping", minion_tgt="planets:pluto")
|
|
assert ret.exitcode == 2 # No match
|
|
# Nested grain (string value)
|
|
ret = salt_cli.run("-G", "test.ping", minion_tgt="level1:level2:foo")
|
|
assert ret.exitcode == 0
|
|
assert salt_minion.id in ret.json
|
|
assert salt_sub_minion.id not in ret.json
|
|
ret = salt_cli.run("-G", "test.ping", minion_tgt="level1:level2:bar")
|
|
assert ret.exitcode == 0
|
|
assert salt_sub_minion.id in ret.json
|
|
assert salt_minion.id not in ret.json
|
|
# Nested grain (list member)
|
|
ret = salt_cli.run("-G", "test.ping", minion_tgt="companions:one:ian")
|
|
assert ret.exitcode == 0
|
|
assert salt_minion.id in ret.json
|
|
assert salt_sub_minion.id not in ret.json
|
|
ret = salt_cli.run("-G", "test.ping", minion_tgt="companions:two:jamie")
|
|
assert ret.exitcode == 0
|
|
assert salt_sub_minion.id in ret.json
|
|
assert salt_minion.id not in ret.json
|
|
# Test for issue: https://github.com/saltstack/salt/issues/19651
|
|
ret = salt_cli.run("-G", "test.ping", minion_tgt="companions:*:susan")
|
|
assert ret.exitcode == 0
|
|
assert salt_minion.id in ret.json
|
|
assert salt_sub_minion.id not in ret.json
|
|
# Test to ensure wildcard at end works correctly
|
|
ret = salt_cli.run("-G", "test.ping", minion_tgt="companions:one:*")
|
|
assert ret.exitcode == 0
|
|
assert salt_minion.id in ret.json
|
|
assert salt_sub_minion.id not in ret.json
|
|
# Test to ensure multiple wildcards works correctly
|
|
ret = salt_cli.run("-G", "test.ping", minion_tgt="companions:*:*")
|
|
assert ret.exitcode == 0
|
|
assert salt_minion.id in ret.json
|
|
assert salt_sub_minion.id in ret.json
|
|
|
|
|
|
def test_regrain(salt_cli, salt_minion, salt_sub_minion):
|
|
"""
|
|
test salt grain matcher
|
|
"""
|
|
ret = salt_cli.run("--grain-pcre", "test.ping", minion_tgt="test_grain:^cheese$")
|
|
assert ret.exitcode == 0
|
|
assert salt_minion.id in ret.json
|
|
assert salt_sub_minion.id not in ret.json
|
|
ret = salt_cli.run("--grain-pcre", "test.ping", minion_tgt="test_grain:.*am$")
|
|
assert ret.exitcode == 0
|
|
assert salt_sub_minion.id in ret.json
|
|
assert salt_minion.id not in ret.json
|
|
|
|
|
|
def test_pillar(salt_cli, salt_minion, salt_sub_minion, pillar_tree):
|
|
"""
|
|
test pillar matcher
|
|
"""
|
|
# First-level pillar (string value)
|
|
ret = salt_cli.run("-I", "test.ping", minion_tgt="monty:python")
|
|
assert ret.exitcode == 0
|
|
assert salt_minion.id in ret.json
|
|
assert salt_sub_minion.id in ret.json
|
|
# First-level pillar (string value, only in sub_minion)
|
|
ret = salt_cli.run(
|
|
"-I", "test.ping", minion_tgt="sub:{}".format(salt_sub_minion.id)
|
|
)
|
|
assert ret.exitcode == 0
|
|
assert salt_sub_minion.id in ret.json
|
|
assert salt_minion.id not in ret.json
|
|
# First-level pillar (list member)
|
|
ret = salt_cli.run("-I", "test.ping", minion_tgt="knights:Bedevere")
|
|
assert ret.exitcode == 0
|
|
assert salt_minion.id in ret.json
|
|
assert salt_sub_minion.id in ret.json
|
|
# Nested pillar (string value)
|
|
ret = salt_cli.run("-I", "test.ping", minion_tgt="level1:level2:foo")
|
|
assert ret.exitcode == 0
|
|
assert salt_minion.id in ret.json
|
|
assert salt_sub_minion.id in ret.json
|
|
# Nested pillar (list member)
|
|
ret = salt_cli.run("-I", "test.ping", minion_tgt="companions:three:sarah jane")
|
|
assert ret.exitcode == 0
|
|
assert salt_minion.id in ret.json
|
|
assert salt_sub_minion.id in ret.json
|
|
|
|
|
|
def test_repillar(salt_cli, salt_minion, salt_sub_minion, pillar_tree):
|
|
"""
|
|
test salt pillar PCRE matcher
|
|
"""
|
|
ret = salt_cli.run("-J", "test.ping", minion_tgt="monty:^(python|hall)$")
|
|
assert ret.exitcode == 0
|
|
assert salt_minion.id in ret.json
|
|
assert salt_sub_minion.id in ret.json
|
|
ret = salt_cli.run(
|
|
"--pillar-pcre", "test.ping", minion_tgt="knights:^(Robin|Lancelot)$"
|
|
)
|
|
assert ret.exitcode == 0
|
|
assert salt_minion.id in ret.json
|
|
assert salt_sub_minion.id in ret.json
|
|
|
|
|
|
def test_ipcidr(salt_cli, salt_minion, salt_sub_minion):
|
|
ret = salt_cli.run("network.subnets", minion_tgt=salt_minion.id)
|
|
assert ret.exitcode == 0
|
|
assert ret.json
|
|
|
|
# We're just after the first defined subnet from 'minion'
|
|
subnet = ret.json[0]
|
|
|
|
ret = salt_cli.run("-S", "test.ping", minion_tgt=subnet)
|
|
assert ret.exitcode == 0
|
|
assert salt_minion.id in ret.json
|
|
assert salt_sub_minion.id in ret.json
|
|
|
|
|
|
def test_static(salt_cli, salt_minion, salt_sub_minion):
|
|
"""
|
|
test salt static call
|
|
"""
|
|
ret = salt_cli.run("test.ping", "--static", minion_tgt=salt_minion.id)
|
|
assert ret.exitcode == 0
|
|
assert ret.json is True
|
|
assert salt_minion.id in ret.stdout
|
|
|
|
|
|
def test_salt_documentation(salt_cli, salt_minion):
|
|
"""
|
|
Test to see if we're supporting --doc
|
|
"""
|
|
ret = salt_cli.run("-d", "test", minion_tgt=salt_minion.id)
|
|
assert ret.exitcode == 0
|
|
assert "test.ping" in ret.json
|
|
|
|
|
|
def test_salt_documentation_too_many_arguments(salt_cli, salt_minion):
|
|
"""
|
|
Test to see if passing additional arguments shows an error
|
|
"""
|
|
ret = salt_cli.run(
|
|
"-d", "salt", "ldap.search", "filter=ou=People", minion_tgt=salt_cli.id
|
|
)
|
|
assert ret.exitcode == salt.defaults.exitcodes.EX_USAGE
|
|
assert "You can only get documentation for one method at one time" in ret.stderr
|