First commit of working minion and master connection in docker containers using an old salt version

This commit is contained in:
MKLeb 2022-12-05 19:45:45 -05:00 committed by Megan Wilhite
parent 3b347fc27d
commit 07e217d516
3 changed files with 324 additions and 0 deletions

View file

@ -0,0 +1,116 @@
"""
Salt performance tests
"""
import logging
import shutil
import pytest
from saltfactories.daemons.container import Container
import salt.utils.path
from tests.support.sminion import create_sminion
docker = pytest.importorskip("docker")
# pylint: disable=3rd-party-module-not-gated,no-name-in-module
from docker.errors import DockerException # isort:skip
# pylint: enable=3rd-party-module-not-gated,no-name-in-module
pytestmark = [
pytest.mark.slow_test,
pytest.mark.skip_if_binaries_missing("docker"),
]
log = logging.getLogger(__name__)
@pytest.fixture(scope="session")
def docker_client():
if docker is None:
pytest.skip("The docker python library is not available")
if salt.utils.path.which("docker") is None:
pytest.skip("The docker binary is not available")
try:
client = docker.from_env()
connectable = Container.client_connectable(client)
if connectable is not True: # pragma: no cover
pytest.skip(connectable)
return client
except DockerException:
pytest.skip("Failed to get a connection to docker running on the system")
@pytest.fixture(scope="session")
def network():
return "salt-performance"
@pytest.fixture(scope="session")
def host_docker_network_ip_address(network):
sminion = create_sminion()
network_name = network
network_subnet = "10.0.20.0/24"
network_gateway = "10.0.20.1"
try:
ret = sminion.states.docker_network.present(
network_name,
driver="bridge",
ipam_pools=[{"subnet": network_subnet, "gateway": network_gateway}],
)
assert isinstance(ret, dict), ret
assert ret["result"], "Failed to create docker network: {}".format(ret)
yield network_gateway
finally:
sminion.states.docker_network.absent(network_name)
@pytest.fixture(scope="session")
def salt_factories_config(salt_factories_config, host_docker_network_ip_address):
"""
Return a dictionary with the keyworkd arguments for FactoriesManager
"""
config = salt_factories_config.copy()
config["log_server_host"] = host_docker_network_ip_address
return config
@pytest.fixture(scope="package")
def integration_files_dir(tmp_path_factory):
"""
Fixture which returns the salt integration files directory path.
Creates the directory if it does not yet exist.
"""
dirname = tmp_path_factory.mktemp("integration-files")
try:
yield dirname
finally:
shutil.rmtree(str(dirname), ignore_errors=True)
@pytest.fixture(scope="package")
def state_tree(integration_files_dir):
"""
Fixture which returns the salt state tree root directory path.
Creates the directory if it does not yet exist.
"""
dirname = integration_files_dir / "state-tree"
dirname.mkdir(exist_ok=True)
return dirname
@pytest.fixture(scope="package")
def pillar_tree(integration_files_dir):
"""
Fixture which returns the salt pillar tree root directory path.
Creates the directory if it does not yet exist.
"""
dirname = integration_files_dir / "pillar-tree"
dirname.mkdir(exist_ok=True)
return dirname
@pytest.fixture
def salt_cli(salt_master):
return salt_master.salt_cli()

View file

@ -0,0 +1,208 @@
import time
import pytest
from pytestshellutils.utils import ports
from saltfactories.daemons import master
from saltfactories.daemons.container import SaltDaemon, SaltMinion
from saltfactories.utils import random_string
class ContainerMaster(SaltDaemon, master.SaltMaster):
"""
Containerized salt master that has no check events
"""
def get_display_name(self):
return master.SaltMaster.get_display_name(self)
def get_check_events(self):
return []
class ContainerMinion(SaltMinion):
"""
Containerized salt minion that has no check events
"""
def get_check_events(self):
return []
@pytest.fixture(scope="session")
def compat_salt_version():
return "3004"
@pytest.fixture(scope="session")
def master_id(compat_salt_version):
return random_string(
"master-performance-{}-".format(compat_salt_version), uppercase=False
)
@pytest.fixture(scope="package")
def container_master(
request,
salt_factories,
host_docker_network_ip_address,
network,
state_tree,
pillar_tree,
compat_salt_version,
docker_client,
master_id,
):
root_dir = salt_factories.get_root_dir_for_daemon(master_id)
conf_dir = root_dir / "conf"
conf_dir.mkdir(exist_ok=True)
config_defaults = {
"root_dir": str(root_dir),
"transport": request.config.getoption("--transport"),
"user": False,
}
publish_port = ports.get_unused_localhost_port()
ret_port = ports.get_unused_localhost_port()
config_overrides = {
"interface": "0.0.0.0",
"publish_port": publish_port,
"ret_port": ret_port,
"log_level_logfile": "quiet",
"pytest-master": {
"log": {"host": host_docker_network_ip_address},
},
}
config_overrides.update(
{
"file_roots": {"base": [str(state_tree)]},
"pillar_roots": {"base": [str(pillar_tree)]},
}
)
factory = salt_factories.salt_master_daemon(
master_id,
defaults=config_defaults,
overrides=config_overrides,
factory_class=ContainerMaster,
image="ghcr.io/saltstack/salt-ci-containers/salt:{}".format(
compat_salt_version
),
base_script_args=["--log-level=debug"],
container_run_kwargs={
# "ports": {
# f"{publish_port}/tcp": publish_port,
# f"{ret_port}/tcp": ret_port,
# },
"network": network,
"hostname": master_id,
},
docker_client=docker_client,
name=master_id,
start_timeout=120,
max_start_attempts=1,
skip_if_docker_client_not_connectable=True,
)
with factory.started():
yield factory
@pytest.fixture
def salt_cli(container_master):
return container_master.salt_cli()
@pytest.fixture
def salt_key_cli(container_master):
return container_master.salt_key_cli()
@pytest.fixture
def salt_run_cli(container_master):
return container_master.salt_run_cli()
@pytest.fixture()
def minion_id(compat_salt_version):
return random_string(
"minion-performance-{}-".format(compat_salt_version),
uppercase=False,
)
@pytest.mark.skip_if_binaries_missing("docker")
@pytest.fixture()
def container_minion(
minion_id,
container_master,
docker_client,
compat_salt_version,
host_docker_network_ip_address,
network,
master_id,
):
config_overrides = {
"master": master_id,
"user": False,
"pytest-minion": {"log": {"host": host_docker_network_ip_address}},
}
factory = container_master.salt_minion_daemon(
minion_id,
overrides=config_overrides,
factory_class=ContainerMinion,
# SaltMinion kwargs
name=minion_id,
image="ghcr.io/saltstack/salt-ci-containers/salt:{}".format(
compat_salt_version
),
docker_client=docker_client,
start_timeout=120,
pull_before_start=False,
skip_if_docker_client_not_connectable=True,
container_run_kwargs={
"network": network,
"hostname": minion_id,
},
max_start_attempts=1,
)
factory.after_terminate(
pytest.helpers.remove_stale_minion_key, container_master, factory.id
)
with factory.started():
yield factory
def _wait_for_stdout(expected, func, *args, timeout=120, **kwargs):
start = time.time()
while time.time() < start + timeout:
ret = func(*args, **kwargs)
if ret and ret.stdout and expected in ret.stdout:
break
time.sleep(1)
else:
pytest.skip("Skipping test, one or more daemons failed to start")
def test_performance(
salt_cli,
container_minion,
salt_run_cli,
salt_key_cli,
compat_salt_version,
container_master,
):
_wait_for_stdout(
compat_salt_version,
container_master.run,
*salt_run_cli.cmdline("--versions-report")
)
salt_key_cmd = [
comp
for comp in salt_key_cli.cmdline("-Ay")
if not comp.startswith("--log-level")
]
_wait_for_stdout(container_minion.id, container_master.run, *salt_key_cmd)
versions_ret = container_master.run(
*salt_cli.cmdline("test.versions", minion_tgt=container_minion.id)
)
assert compat_salt_version in versions_ret.stdout