123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176 |
- import shutil
- import textwrap
- import time
- import attr
- import pytest
- @attr.s
- class BlackoutPillar:
- pillar_state_tree = attr.ib(repr=False)
- salt_cli = attr.ib(repr=False)
- top_file = attr.ib(init=False)
- minion_1_id = attr.ib(repr=False)
- minion_1_pillar = attr.ib(init=False)
- minion_2_id = attr.ib(repr=False)
- minion_2_pillar = attr.ib(init=False)
- in_blackout = attr.ib(default=False)
- def __attrs_post_init__(self):
- self.top_file = self.pillar_state_tree / "top.sls"
- top_file_contents = textwrap.dedent(
- """\
- base:
- {}:
- - minion-1-pillar
- {}:
- - minion-2-pillar
- """.format(
- self.minion_1_id, self.minion_2_id
- )
- )
- self.top_file.write_text(top_file_contents)
- self.minion_1_pillar = self.pillar_state_tree / "minion-1-pillar.sls"
- self.minion_2_pillar = self.pillar_state_tree / "minion-2-pillar.sls"
- self.minion_1_pillar.write_text("minion_blackout: false")
- self.minion_2_pillar.write_text("minion_blackout: false")
- self.refresh_pillar()
- def enter_blackout(self, pillar_contents=None):
- if pillar_contents is None:
- pillar_contents = "minion_blackout: false"
- if pillar_contents.startswith("\n"):
- pillar_contents = pillar_contents[1:]
- pillar_contents = textwrap.dedent(pillar_contents)
- self.minion_1_pillar.write_text(pillar_contents)
- self.refresh_pillar(exiting_blackout=False)
- self.in_blackout = True
- return self.__enter__()
- def exit_blackout(self):
- if self.in_blackout:
- self.minion_1_pillar.write_text("minion_blackout: false")
- self.refresh_pillar(exiting_blackout=True)
- self.in_blackout = False
- def refresh_pillar(self, timeout=60, sleep=0.5, exiting_blackout=None):
- ret = self.salt_cli.run("saltutil.refresh_pillar", wait=True, minion_tgt="*")
- assert ret.exitcode == 0
- assert self.minion_1_id in ret.json
- assert self.minion_2_id in ret.json
- stop_at = time.time() + timeout
- while True:
- if time.time() > stop_at:
- if exiting_blackout is True:
- pytest.fail(
- "Minion did not exit blackout mode after {} seconds".format(
- timeout
- )
- )
- elif exiting_blackout is False:
- pytest.fail(
- "Minion did not enter blackout mode after {} seconds".format(
- timeout
- )
- )
- else:
- pytest.fail(
- "Minion did not refresh pillar after {} seconds".format(timeout)
- )
- time.sleep(sleep)
- ret = self.salt_cli.run("pillar.get", "minion_blackout", minion_tgt="*")
- if not ret.json:
- # Something is wrong here. Try again
- continue
- assert self.minion_1_id in ret.json
- assert self.minion_2_id in ret.json
- if ret.json[self.minion_1_id] == "" or ret.json[self.minion_2_id] == "":
- # Pillar not found
- continue
- # Minion 2 must NEVER enter blackout
- assert ret.json[self.minion_2_id] is False
- if exiting_blackout is True and ret.json[self.minion_1_id] is not False:
- continue
- elif (
- exiting_blackout is False
- and "Minion in blackout mode" not in ret.json[self.minion_1_id]
- ):
- continue
- # We got the pillar we're after, break out of the loop
- break
- def __enter__(self):
- return self
- def __exit__(self, *args):
- self.exit_blackout()
- @pytest.fixture(scope="package")
- def pillar_state_tree(tmp_path_factory):
- _pillar_state_tree = tmp_path_factory.mktemp("pillar")
- try:
- yield _pillar_state_tree
- finally:
- shutil.rmtree(str(_pillar_state_tree), ignore_errors=True)
- @pytest.fixture(scope="package")
- def salt_master(salt_factories, pillar_state_tree):
- config_defaults = {
- "pillar_roots": {"base": [str(pillar_state_tree)]},
- "open_mode": True,
- }
- factory = salt_factories.get_salt_master_daemon(
- "blackout-master",
- config_defaults=config_defaults,
- extra_cli_arguments_after_first_start_failure=["--log-level=debug"],
- )
- with factory.started():
- yield factory
- @pytest.fixture(scope="package")
- def salt_minion_1(salt_master):
- factory = salt_master.get_salt_minion_daemon(
- "blackout-minion-1", config_defaults={"open_mode": True}
- )
- with factory.started():
- yield factory
- @pytest.fixture(scope="package")
- def salt_minion_2(salt_master):
- factory = salt_master.get_salt_minion_daemon(
- "blackout-minion-2", config_defaults={"open_mode": True}
- )
- with factory.started():
- yield factory
- @pytest.fixture(scope="package")
- def salt_cli(salt_master):
- return salt_master.get_salt_cli()
- @pytest.fixture(scope="package")
- def blackout_pillar(salt_cli, pillar_state_tree, salt_minion_1, salt_minion_2):
- return BlackoutPillar(
- pillar_state_tree=pillar_state_tree,
- salt_cli=salt_cli,
- minion_1_id=salt_minion_1.id,
- minion_2_id=salt_minion_2.id,
- )
- @pytest.fixture
- def blackout(blackout_pillar):
- try:
- yield blackout_pillar
- finally:
- blackout_pillar.exit_blackout()
|