|
Packit Service |
a166ed |
#!/usr/bin/env python
|
|
Packit Service |
a166ed |
|
|
Packit Service |
a166ed |
# Authors:
|
|
Packit Service |
a166ed |
# Sergio Oliveira Campos <seocam@redhat.com>
|
|
Packit Service |
a166ed |
#
|
|
Packit Service |
a166ed |
# Copyright (C) 2020 Red Hat
|
|
Packit Service |
a166ed |
# see file 'COPYING' for use and warranty information
|
|
Packit Service |
a166ed |
#
|
|
Packit Service |
a166ed |
# This program is free software; you can redistribute it and/or modify
|
|
Packit Service |
a166ed |
# it under the terms of the GNU General Public License as published by
|
|
Packit Service |
a166ed |
# the Free Software Foundation, either version 3 of the License, or
|
|
Packit Service |
a166ed |
# (at your option) any later version.
|
|
Packit Service |
a166ed |
#
|
|
Packit Service |
a166ed |
# This program is distributed in the hope that it will be useful,
|
|
Packit Service |
a166ed |
# but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
Packit Service |
a166ed |
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
|
Packit Service |
a166ed |
# GNU General Public License for more details.
|
|
Packit Service |
a166ed |
#
|
|
Packit Service |
a166ed |
# You should have received a copy of the GNU General Public License
|
|
Packit Service |
a166ed |
# along with this program. If not, see <http://www.gnu.org/licenses/>.
|
|
Packit Service |
a166ed |
|
|
Packit Service |
a166ed |
import os
|
|
Packit Service |
a166ed |
import pytest
|
|
Packit Service |
a166ed |
import subprocess
|
|
Packit Service |
a166ed |
import tempfile
|
|
Packit Service |
a166ed |
import testinfra
|
|
Packit Service |
a166ed |
|
|
Packit Service |
a166ed |
from unittest import TestCase
|
|
Packit Service |
a166ed |
|
|
Packit Service |
a166ed |
|
|
Packit Service |
a166ed |
SCRIPT_DIR = os.path.dirname(os.path.abspath(__file__))
|
|
Packit Service |
a166ed |
|
|
Packit Service |
a166ed |
|
|
Packit Service |
a166ed |
def is_docker_env():
|
|
Packit Service |
a166ed |
if os.getenv("RUN_TESTS_IN_DOCKER", "0") == "0":
|
|
Packit Service |
a166ed |
return False
|
|
Packit Service |
a166ed |
return True
|
|
Packit Service |
a166ed |
|
|
Packit Service |
a166ed |
|
|
Packit Service |
a166ed |
def get_ssh_password():
|
|
Packit Service |
a166ed |
return os.getenv("IPA_SSH_PASSWORD")
|
|
Packit Service |
a166ed |
|
|
Packit Service |
a166ed |
|
|
Packit Service |
a166ed |
def get_server_host():
|
|
Packit Service |
a166ed |
return os.getenv("IPA_SERVER_HOST")
|
|
Packit Service |
a166ed |
|
|
Packit Service |
a166ed |
|
|
Packit Service |
a166ed |
def get_inventory_content():
|
|
Packit Service |
a166ed |
"""Create the content of an inventory file for a test run."""
|
|
Packit Service |
a166ed |
ipa_server_host = get_server_host()
|
|
Packit Service |
a166ed |
|
|
Packit Service |
a166ed |
if is_docker_env():
|
|
Packit Service |
a166ed |
ipa_server_host += " ansible_connection=docker"
|
|
Packit Service |
a166ed |
|
|
Packit Service |
a166ed |
sshpass = get_ssh_password()
|
|
Packit Service |
a166ed |
if sshpass:
|
|
Packit Service |
a166ed |
ipa_server_host += " ansible_ssh_pass=%s" % sshpass
|
|
Packit Service |
a166ed |
|
|
Packit Service |
a166ed |
lines = [
|
|
Packit Service |
a166ed |
"[ipaserver]",
|
|
Packit Service |
a166ed |
ipa_server_host,
|
|
Packit Service |
a166ed |
"[ipaserver:vars]",
|
|
Packit Service |
a166ed |
"ipaserver_domain=test.local",
|
|
Packit Service |
a166ed |
"ipaserver_realm=TEST.LOCAL",
|
|
Packit Service |
a166ed |
]
|
|
Packit Service |
a166ed |
return "\n".join(lines).encode("utf8")
|
|
Packit Service |
a166ed |
|
|
Packit Service |
a166ed |
|
|
Packit Service |
a166ed |
def get_test_name_from_playbook_path(playbook):
|
|
Packit Service |
a166ed |
"""
|
|
Packit Service |
a166ed |
Create a test name based of a playbook path.
|
|
Packit Service |
a166ed |
|
|
Packit Service |
a166ed |
For example:
|
|
Packit Service |
a166ed |
Input: /home/johndoe/ansible-freeipa/tests/dnszone/test_dnszone_mod.yml
|
|
Packit Service |
a166ed |
Output: dnszone_test_dnszone_mod
|
|
Packit Service |
a166ed |
"""
|
|
Packit Service |
a166ed |
playbook_abspath = os.path.abspath(playbook)
|
|
Packit Service |
a166ed |
playbook_rel_to_tests_dir = playbook_abspath.replace(SCRIPT_DIR, "")
|
|
Packit Service |
a166ed |
playbook_slug = playbook_rel_to_tests_dir.strip("/").replace("/", "_")
|
|
Packit Service |
a166ed |
return os.path.splitext(playbook_slug)[0]
|
|
Packit Service |
a166ed |
|
|
Packit Service |
a166ed |
|
|
Packit Service |
a166ed |
def write_logs(result, test_name):
|
|
Packit Service |
a166ed |
"""Write logs of a ansible run logs to `test/logs/`."""
|
|
Packit Service |
a166ed |
log_dir = os.path.join(SCRIPT_DIR, "logs")
|
|
Packit Service |
a166ed |
if not os.path.exists(log_dir):
|
|
Packit Service |
a166ed |
os.makedirs(log_dir)
|
|
Packit Service |
a166ed |
|
|
Packit Service |
a166ed |
# Write stdout log for test
|
|
Packit Service |
a166ed |
log_path = os.path.join(log_dir, "ansible_" + test_name + ".log")
|
|
Packit Service |
a166ed |
with open(log_path, "w") as log_file:
|
|
Packit Service |
a166ed |
log_file.write(result.stdout.decode("utf-8"))
|
|
Packit Service |
a166ed |
|
|
Packit Service |
a166ed |
# Write stderr log for test
|
|
Packit Service |
a166ed |
error_log_path = os.path.join(log_dir, test_name + "-error.log")
|
|
Packit Service |
a166ed |
with open(error_log_path, "w") as log_file:
|
|
Packit Service |
a166ed |
log_file.write(result.stderr.decode("utf-8"))
|
|
Packit Service |
a166ed |
|
|
Packit Service |
a166ed |
|
|
Packit Service |
a166ed |
def _run_playbook(playbook):
|
|
Packit Service |
a166ed |
"""
|
|
Packit Service |
a166ed |
Create a inventory using a temporary file and run ansible using it.
|
|
Packit Service |
a166ed |
|
|
Packit Service |
a166ed |
The logs of the run will be placed in `tests/logs/`.
|
|
Packit Service |
a166ed |
"""
|
|
Packit Service |
a166ed |
with tempfile.NamedTemporaryFile() as inventory_file:
|
|
Packit Service |
a166ed |
inventory_file.write(get_inventory_content())
|
|
Packit Service |
a166ed |
inventory_file.flush()
|
|
Packit Service |
a166ed |
cmd = [
|
|
Packit Service |
a166ed |
"ansible-playbook",
|
|
Packit Service |
a166ed |
"-i",
|
|
Packit Service |
a166ed |
inventory_file.name,
|
|
Packit Service |
a166ed |
playbook,
|
|
Packit Service |
a166ed |
]
|
|
Packit Service |
a166ed |
process = subprocess.run(
|
|
Packit Service |
a166ed |
cmd, cwd=SCRIPT_DIR, stdout=subprocess.PIPE, stderr=subprocess.PIPE
|
|
Packit Service |
a166ed |
)
|
|
Packit Service |
a166ed |
test_name = get_test_name_from_playbook_path(playbook)
|
|
Packit Service |
a166ed |
write_logs(process, test_name)
|
|
Packit Service |
a166ed |
|
|
Packit Service |
a166ed |
return process
|
|
Packit Service |
a166ed |
|
|
Packit Service |
a166ed |
|
|
Packit Service |
a166ed |
def run_playbook(playbook, allow_failures=False):
|
|
Packit Service |
a166ed |
"""
|
|
Packit Service |
a166ed |
Run an Ansible playbook and assert the return code.
|
|
Packit Service |
a166ed |
|
|
Packit Service |
a166ed |
Call ansible (using _run_playbook function) and assert the result of
|
|
Packit Service |
a166ed |
the execution.
|
|
Packit Service |
a166ed |
|
|
Packit Service |
a166ed |
In case of failure the tail of the error message will be displayed
|
|
Packit Service |
a166ed |
as an assertion message.
|
|
Packit Service |
a166ed |
|
|
Packit Service |
a166ed |
The full log of the execution will be available in the directory
|
|
Packit Service |
a166ed |
`tests/logs/`.
|
|
Packit Service |
a166ed |
"""
|
|
Packit Service |
a166ed |
result = _run_playbook(playbook)
|
|
Packit Service |
a166ed |
|
|
Packit Service |
a166ed |
if allow_failures:
|
|
Packit Service |
a166ed |
return result
|
|
Packit Service |
a166ed |
|
|
Packit Service |
a166ed |
status_code_msg = "ansible-playbook return code: {}".format(
|
|
Packit Service |
a166ed |
result.returncode
|
|
Packit Service |
a166ed |
)
|
|
Packit Service |
a166ed |
assert_msg = "\n".join(
|
|
Packit Service |
a166ed |
[
|
|
Packit Service |
a166ed |
"",
|
|
Packit Service |
a166ed |
"-" * 30 + " Captured stdout " + "-" * 30,
|
|
Packit Service |
a166ed |
result.stdout.decode("utf8"),
|
|
Packit Service |
a166ed |
"-" * 30 + " Captured stderr " + "-" * 30,
|
|
Packit Service |
a166ed |
result.stderr.decode("utf8"),
|
|
Packit Service |
a166ed |
"-" * 30 + " Playbook Return Code " + "-" * 30,
|
|
Packit Service |
a166ed |
status_code_msg,
|
|
Packit Service |
a166ed |
]
|
|
Packit Service |
a166ed |
)
|
|
Packit Service |
a166ed |
|
|
Packit Service |
a166ed |
# Need to get the last bytes of msg otherwise Azure
|
|
Packit Service |
a166ed |
# will cut it out.
|
|
Packit Service |
a166ed |
assert result.returncode == 0, assert_msg[-2500:]
|
|
Packit Service |
a166ed |
|
|
Packit Service |
a166ed |
return result
|
|
Packit Service |
a166ed |
|
|
Packit Service |
a166ed |
|
|
Packit Service |
a166ed |
def list_test_yaml(dir_path):
|
|
Packit Service |
a166ed |
"""
|
|
Packit Service |
a166ed |
List the test playbooks inside a given directory.
|
|
Packit Service |
a166ed |
|
|
Packit Service |
a166ed |
A test playbook is any file inside the directory which the name starts with
|
|
Packit Service |
a166ed |
`test_` and the extension is `.yml`.
|
|
Packit Service |
a166ed |
"""
|
|
Packit Service |
a166ed |
yamls = []
|
|
Packit Service |
6e1210 |
for root, _dirs, files in os.walk(dir_path):
|
|
Packit Service |
a166ed |
for yaml_name in files:
|
|
Packit Service |
a166ed |
if yaml_name.startswith("test_") and yaml_name.endswith(".yml"):
|
|
Packit Service |
a166ed |
test_yaml_path = os.path.join(root, yaml_name)
|
|
Packit Service |
a166ed |
yamls.append(
|
|
Packit Service |
a166ed |
{
|
|
Packit Service |
a166ed |
"path": test_yaml_path,
|
|
Packit Service |
a166ed |
"name": yaml_name.split(".")[0],
|
|
Packit Service |
a166ed |
}
|
|
Packit Service |
a166ed |
)
|
|
Packit Service |
a166ed |
return yamls
|
|
Packit Service |
a166ed |
|
|
Packit Service |
a166ed |
|
|
Packit Service |
a166ed |
def get_test_playbooks():
|
|
Packit Service |
a166ed |
"""
|
|
Packit Service |
a166ed |
Get playbook tests grouped by first level directory.
|
|
Packit Service |
a166ed |
|
|
Packit Service |
a166ed |
This function visits the first level of directories inside `tests/` and
|
|
Packit Service |
a166ed |
look for ansible playbooks on them.
|
|
Packit Service |
a166ed |
|
|
Packit Service |
a166ed |
Returns a dict with the directories found in `tests/` as key and a
|
|
Packit Service |
a166ed |
list of test playbook files inside of it.
|
|
Packit Service |
a166ed |
|
|
Packit Service |
a166ed |
A test playbook is any file inside the directory which the name starts with
|
|
Packit Service |
a166ed |
`test_` and the extension is `.yml`.
|
|
Packit Service |
a166ed |
"""
|
|
Packit Service |
a166ed |
test_dirs = os.listdir(SCRIPT_DIR)
|
|
Packit Service |
a166ed |
groups = {}
|
|
Packit Service |
a166ed |
for test_group_dir in sorted(test_dirs):
|
|
Packit Service |
a166ed |
group_dir_path = os.path.join(SCRIPT_DIR, test_group_dir)
|
|
Packit Service |
a166ed |
if not os.path.isdir(group_dir_path):
|
|
Packit Service |
a166ed |
continue
|
|
Packit Service |
a166ed |
yamls = list_test_yaml(group_dir_path)
|
|
Packit Service |
a166ed |
if yamls:
|
|
Packit Service |
a166ed |
groups[test_group_dir] = yamls
|
|
Packit Service |
a166ed |
return groups
|
|
Packit Service |
a166ed |
|
|
Packit Service |
a166ed |
|
|
Packit Service |
a166ed |
def kinit_admin(host, admin="admin", password="SomeADMINpassword"):
|
|
Packit Service |
a166ed |
return host.run_test("kinit " + admin + "<<< " + password)
|
|
Packit Service |
a166ed |
|
|
Packit Service |
a166ed |
|
|
Packit Service |
a166ed |
def kdestroy(host):
|
|
Packit Service |
a166ed |
return host.run_test("kdestroy -A")
|
|
Packit Service |
a166ed |
|
|
Packit Service |
a166ed |
|
|
Packit Service |
a166ed |
class AnsibleFreeIPATestCase(TestCase):
|
|
Packit Service |
a166ed |
def setUp(self):
|
|
Packit Service |
a166ed |
if is_docker_env():
|
|
Packit Service |
a166ed |
protocol = "docker://"
|
|
Packit Service |
a166ed |
user = ""
|
|
Packit Service |
a166ed |
ssh_identity_file = None
|
|
Packit Service |
a166ed |
else:
|
|
Packit Service |
a166ed |
protocol = "ssh://"
|
|
Packit Service |
a166ed |
|
|
Packit Service |
a166ed |
password = get_ssh_password() or ""
|
|
Packit Service |
a166ed |
if password:
|
|
Packit Service |
a166ed |
password = ":" + password
|
|
Packit Service |
a166ed |
|
|
Packit Service |
a166ed |
current_user = os.getenv("USER")
|
|
Packit Service |
a166ed |
ansible_user = os.getenv("ANSIBLE_REMOTE_USER", current_user)
|
|
Packit Service |
a166ed |
user = ansible_user + password + "@"
|
|
Packit Service |
a166ed |
ssh_identity_file = os.getenv("ANSIBLE_PRIVATE_KEY_FILE", None)
|
|
Packit Service |
a166ed |
|
|
Packit Service |
a166ed |
host_connection_info = protocol + user + get_server_host()
|
|
Packit Service |
a166ed |
self.master = testinfra.get_host(
|
|
Packit Service |
a166ed |
host_connection_info, ssh_identity_file=ssh_identity_file,
|
|
Packit Service |
a166ed |
)
|
|
Packit Service |
a166ed |
|
|
Packit Service |
a166ed |
def run_playbook(self, playbook, allow_failures=False):
|
|
Packit Service |
a166ed |
return run_playbook(playbook, allow_failures)
|
|
Packit Service |
a166ed |
|
|
Packit Service |
a166ed |
def run_playbook_with_exp_msg(self, playbook, expected_msg):
|
|
Packit Service |
a166ed |
result = self.run_playbook(playbook, allow_failures=True)
|
|
Packit Service |
a166ed |
assert (
|
|
Packit Service |
a166ed |
expected_msg in result.stdout.decode("utf8")
|
|
Packit Service |
a166ed |
or
|
|
Packit Service |
a166ed |
expected_msg in result.stderr.decode("utf8")
|
|
Packit Service |
a166ed |
)
|
|
Packit Service |
a166ed |
|
|
Packit Service |
a166ed |
def check_details(self, expected_output, cmd, extra_cmds=None):
|
|
Packit Service |
a166ed |
cmd = "ipa " + cmd
|
|
Packit Service |
a166ed |
if extra_cmds:
|
|
Packit Service |
a166ed |
cmd += " " + " ".join(extra_cmds)
|
|
Packit Service |
a166ed |
kinit_admin(self.master)
|
|
Packit Service |
a166ed |
res = self.master.run(cmd)
|
|
Packit Service |
a166ed |
if res.rc != 0:
|
|
Packit Service |
a166ed |
for output in expected_output:
|
|
Packit Service |
a166ed |
assert output in res.stderr
|
|
Packit Service |
a166ed |
else:
|
|
Packit Service |
a166ed |
for output in expected_output:
|
|
Packit Service |
a166ed |
assert output in res.stdout
|
|
Packit Service |
a166ed |
kdestroy(self.master)
|
|
Packit Service |
a166ed |
|
|
Packit Service |
a166ed |
def check_notexists(self, members, cmd, extra_cmds=None):
|
|
Packit Service |
a166ed |
cmd = "ipa " + cmd
|
|
Packit Service |
a166ed |
if extra_cmds:
|
|
Packit Service |
a166ed |
cmd += " " + " ".join(extra_cmds)
|
|
Packit Service |
a166ed |
kinit_admin(self.master)
|
|
Packit Service |
a166ed |
res = self.master.run(cmd)
|
|
Packit Service |
a166ed |
for member in members:
|
|
Packit Service |
a166ed |
assert member not in res.stdout
|
|
Packit Service |
a166ed |
kdestroy(self.master)
|
|
Packit Service |
a166ed |
|
|
Packit Service |
a166ed |
def mark_xfail_using_ansible_freeipa_version(self, version, reason):
|
|
Packit Service |
a166ed |
package = self.master.package("ansible-freeipa")
|
|
Packit Service |
a166ed |
|
|
Packit Service |
a166ed |
if not package.is_installed:
|
|
Packit Service |
a166ed |
return
|
|
Packit Service |
a166ed |
|
|
Packit Service |
a166ed |
if package.version == version:
|
|
Packit Service |
a166ed |
pytest.xfail(reason)
|