diff --git a/.github/actions/run-tests/action.yaml b/.github/actions/run-tests/action.yaml index 8944a46..1844275 100644 --- a/.github/actions/run-tests/action.yaml +++ b/.github/actions/run-tests/action.yaml @@ -24,13 +24,16 @@ runs: - name: Run sanity test shell: bash run: pushd ~/.ansible/collections/ansible_collections/dynatrace/oneagent && ansible-test sanity && popd + - name: Prepare component tests + id: prepare-component-tests + shell: bash + run: python -m virtualenv venv && source venv/bin/activate && cd roles/oneagent/tests/component && + pip install -r resources/requirements.txt - name: Run component tests id: component-tests shell: bash - run: python -m virtualenv venv && source venv/bin/activate && cd roles/oneagent/tests/component && - pip install -r resources/requirements.txt && python run.py --linux_x86=localhost + run: python run.py --linux_x86=localhost - name: Upload logs - if: failure() && steps.component-tests.outcome == 'failure' uses: actions/upload-artifact@v4 with: name: component-tests-${{ github.sha }} diff --git a/.github/workflows/build-and-test.yaml b/.github/workflows/build-and-test.yaml index dfb4308..2d096d5 100644 --- a/.github/workflows/build-and-test.yaml +++ b/.github/workflows/build-and-test.yaml @@ -35,7 +35,5 @@ jobs: uses: ./.github/actions/setup-build-environment - name: Build the collection uses: ./.github/actions/build-collection - - name: Debug - run: ls -alR - name: Run tests uses: ./.github/actions/run-tests diff --git a/.gitignore b/.gitignore index 47aeaee..001bb20 100644 --- a/.gitignore +++ b/.gitignore @@ -1,2 +1,2 @@ dynatrace-oneagent-* -.idea/ \ No newline at end of file +**/.idea/ \ No newline at end of file diff --git a/README.md b/README.md index 41e1099..cf87ef4 100644 --- a/README.md +++ b/README.md @@ -5,7 +5,7 @@ In its current state, the collection consists of a single role that deploys Dyna ### General * Ansible >= 2.15.0 ### Windows -* pywinrm >= 0.4.3 +* pywinrm >= 0.4.1 ## Setup `pip install -r requirements.txt` diff --git a/roles/oneagent/README.md b/roles/oneagent/README.md index d05bf75..830fc38 100644 --- a/roles/oneagent/README.md +++ b/roles/oneagent/README.md @@ -40,7 +40,7 @@ For full list of suitable parameters, see [OneAgent configuration via command-li The following variables are available in `defaults/main/` and can be overridden: | Name | Default | Description -|------|-|- +|-|-|- | `oneagent_environment_url` | `-` | The URL of the target Dynatrace environment (see [Direct download from your environment](#direct-download-from-your-environment)). | `oneagent_paas_token` | `-` | The [PaaS Token] retrieved from the "Deploy Dynatrace" installer page. | `oneagent_local_installer` | `-` | The Path to OneAgent installer stored on the main node. @@ -53,7 +53,7 @@ The following variables are available in `defaults/main/` and can be overridden: | `oneagent_package_state` | `present` | OneAgent package state; use `present` or `latest` to make sure it's installed, or `absent` in order to uninstall. | `oneagent_reboot_host` | `false` | Reboot the secondary machine after OneAgent installation | `oneagent_validate_certs` | `true` | If set to `false`, allows to download OneAgent from a server with insecure SSL certificate (expired, self-signed, etc). -| `oneagent_verify_signature` | `true` | Allows to skip verifying the installer's signature on UNIX platforms +| `oneagent_verify_signature` | `true` | Verifies installer's signature (available only on AIX/Linux platforms) | `oneagent_reboot_timeout` | `3600` | Set the timeout for rebooting secondary machine in seconds For more information, see customize OneAgent installation documentation for [Linux], [Windows], and [AIX]. diff --git a/roles/oneagent/tasks/gather-info/gather-info.yml b/roles/oneagent/tasks/gather-info/gather-info.yml index 640a72f..6816a89 100644 --- a/roles/oneagent/tasks/gather-info/gather-info.yml +++ b/roles/oneagent/tasks/gather-info/gather-info.yml @@ -1,6 +1,7 @@ --- - name: Gather installers info ansible.builtin.include_tasks: tasks/gather-info/gather-info-{{ oneagent_system_family }}.yml + - name: Compare versions of installed OneAgent and uploaded installer ansible.builtin.set_fact: _oneagent_is_installation_possible: "{{ _oneagent_installed_agent_version.stdout | default('') < _oneagent_new_agent_version.stdout }}" diff --git a/roles/oneagent/tasks/provide-installer/signature-unix.yml b/roles/oneagent/tasks/provide-installer/signature-unix.yml index b3bcb52..79660fa 100644 --- a/roles/oneagent/tasks/provide-installer/signature-unix.yml +++ b/roles/oneagent/tasks/provide-installer/signature-unix.yml @@ -21,7 +21,7 @@ - name: Validate installer signature ansible.builtin.shell: > - ( printf "%s\n" "{{ oneagent_certificate_verification_header }}"; + ( printf '%s\n' '{{ oneagent_certificate_verification_header }}'; printf '\n\n----SIGNED-INSTALLER\n'; cat "{{ oneagent_installer_path }}" ) | openssl cms -verify -CAfile "{{ oneagent_ca_cert_dest_path }}" > /dev/null no_log: true diff --git a/roles/oneagent/tests/component/resources/installers/Dynatrace-OneAgent-Linux.sh b/roles/oneagent/tests/component/resources/installers/Dynatrace-OneAgent-Linux.sh index bd3d8d1..ab4e41b 100644 --- a/roles/oneagent/tests/component/resources/installers/Dynatrace-OneAgent-Linux.sh +++ b/roles/oneagent/tests/component/resources/installers/Dynatrace-OneAgent-Linux.sh @@ -25,7 +25,7 @@ parseParams() { while [ $# -gt 0 ]; do local param="${1}" if [ "${param}" = "--version" ]; then - printf "%s" "${INSTALLER_VERSION}" + printf "%s\n" "${INSTALLER_VERSION}" exit 0 elif [ "${param}" = "INSTALL_PATH" ]; then INSTALL_DIR="$(printf "%s" "${param}" | cut -d "=" -f "2-")" @@ -68,6 +68,7 @@ main() { deployOneagentCtl deployUninstallScript applyConfig + exit 0 } ################## diff --git a/roles/oneagent/tests/component/resources/installers/certificate.pem b/roles/oneagent/tests/component/resources/installers/certificate.pem new file mode 100644 index 0000000..fdb456a --- /dev/null +++ b/roles/oneagent/tests/component/resources/installers/certificate.pem @@ -0,0 +1,31 @@ +-----BEGIN CERTIFICATE----- +MIIFazCCA1OgAwIBAgIUYkKTxzGlL9GbWs+0yUpApwdKNq4wDQYJKoZIhvcNAQEL +BQAwRTELMAkGA1UEBhMCQVUxEzARBgNVBAgMClNvbWUtU3RhdGUxITAfBgNVBAoM +GEludGVybmV0IFdpZGdpdHMgUHR5IEx0ZDAeFw0yNDA5MjAwNzAxMzZaFw0yNTA5 +MjAwNzAxMzZaMEUxCzAJBgNVBAYTAkFVMRMwEQYDVQQIDApTb21lLVN0YXRlMSEw +HwYDVQQKDBhJbnRlcm5ldCBXaWRnaXRzIFB0eSBMdGQwggIiMA0GCSqGSIb3DQEB +AQUAA4ICDwAwggIKAoICAQC9mTJgc7MYM/KjZ90iF/omZEd1VCnj/nubAKkVSMdO +XAaYHRAszNUZh11fJ9wJEoY5CgeAQxWcy2YAh9Sb8MU/FmO7erXuK1h+315DI2Ao +owxQjb3rL7+mfD9EKZon9RJuMdzwBhZhNpATa+RXbI5IsJJLGW8sWH8k+/XXmpBj +qjVOpY8BYjU6wEFrTo+vvu17CyGnYFcX/LssgggBTCSV7bLWAuCML/Si2MwSz6Yn +s4jf0Av8cUpoQXbFF8Rh+ejtgDIBwydUD6MOtrnX0DClKdDe+A/GDNK79g4rfnOC +FV4VKIDaJ92GrRf03xCgxappQmFtpx00I9oNDUSQYE6LxVwYg56TGhoFeNoV0nBA +FIoWOyVxSFpS4FXkhOAstHholMYjvE2QwUfO4dFPqVD8cgRlB/rstP1guhFIxrRH +KhD3Quj5c48EoC///mgHuc6BLj/16H3z3GpZFPexXFFxZEVvhgoZRGonLjOCpz8k +wOQki96o2IZnejU/i/oYbmBBwMT2aw2X+O/UW6cD9UBPjxzkxHbK0NACnMFkVt8U +8RpILZ4kFWNZU7ANN3E0rTSXyUi5zDUuRefLlsuqxAFSKNKiYe65RJSjERbFqq1M ++FLatD7ms8Ax97WVIPOwvGD7swx6vVAW2kh2pkPC1GTrbl/0bHCRZBiXfEc1PqvU +bwIDAQABo1MwUTAdBgNVHQ4EFgQUGBHNBHCjqqwYLL3HZ7GLl8HEWJQwHwYDVR0j +BBgwFoAUGBHNBHCjqqwYLL3HZ7GLl8HEWJQwDwYDVR0TAQH/BAUwAwEB/zANBgkq +hkiG9w0BAQsFAAOCAgEAQsj9+T73gWKIdG863tXdWQfcyT4sqO8ot7PVtVKJf130 +37Dm/9Ic3m+1CHon2TCClgOF75OT5GpVXVumfqlgqP70u15SsZBGAKFJSnBtOMrV +0iIP6fAp9KYnsigrtamzA7WLa8EL3sDIEwJ7e1OPgamG4VxWf01d/rPA8z1lPfij +gRzMKtX6rpioNQZP+48ovVTBgXIQRnVfqByfk40zyqjQOwML20VL6ERwnw9LFejF +RjUopihGZsSwL4O0l2hC97wGGJ2BXvwfGGziczaBHLIJcsaViaPH1jHX5FaxhfOk +YIoUm/0U5dUKIRNz1t0ooGXKo2RGf3328xPdMeRNXbQRK49SL4rgGqM8+W6hkEok +gXSAOXdJLZNB/h7juJGKGXJ+VQZcWrEGz5gNL1CeIBbmcY49p1k8HHkt0zfgJhkP +XKpwuBrRgN3N2FuTYm0yTl5hlAy6P8Ryu+sZbjZd6dL8BqjkyY5sIt2Xh7UUvkVd +tvg3xDICBh8qRAW51ExWMwajasK2aeWaI+xUg+MiAzWmDNc7ToTuxF7vJtTT3jk2 +HGsVTnJTF3YxdD+9VbUX86meF649LNGK1+Wl9EDxY3Rg/uBxA8T3vbhWeC3djg79 +LT+WQqRE6l4E7mNeb/vIPddt4nP8SvPmy+3ilLYPb6A2kwpItY1oVbsMPmo0NpU= +-----END CERTIFICATE----- diff --git a/roles/oneagent/tests/component/resources/installers/private.key b/roles/oneagent/tests/component/resources/installers/private.key new file mode 100644 index 0000000..0471f3d --- /dev/null +++ b/roles/oneagent/tests/component/resources/installers/private.key @@ -0,0 +1,52 @@ +-----BEGIN PRIVATE KEY----- +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 +3xG8cvNVEwspZX75ptSaJV5PImJRRg== +-----END PRIVATE KEY----- diff --git a/roles/oneagent/tests/component/run.py b/roles/oneagent/tests/component/run.py index 3db5f3c..a4c79ec 100644 --- a/roles/oneagent/tests/component/run.py +++ b/roles/oneagent/tests/component/run.py @@ -10,6 +10,7 @@ from pathlib import Path from typing import Any from scripts.util.test_data_types import DeploymentPlatform +from scripts.util.constants.common_constants import SIGNATURE_FILE_NAME USER_KEY = "user" PASS_KEY = "password" @@ -17,10 +18,12 @@ BASE_DIR = Path(__file__).resolve().parent TEST_DIR = BASE_DIR / "test_dir" LOG_DIR = TEST_DIR / "logs" -INSTALLERS_DIR = TEST_DIR / "installers" +INSTALLERS_DEST_DIR = TEST_DIR / "installers" +INSTALLERS_RESOURCE_DIR = BASE_DIR / "resources" / "installers" TEST_VARS = {"PYTHONPATH": "scripts/"} + class ServerWrapper(object): def __init__(self, proc: subprocess.Popen): self.proc = proc @@ -30,7 +33,7 @@ def __enter__(self): def __exit__(self, exc_type, exc_val, exc_tb): self.proc.terminate() - save_log(self.proc.stdout, LOG_DIR / "server.log") + save_file(self.proc.stdout, LOG_DIR / "server.log") def get_env_vars() -> dict[str, str]: @@ -40,10 +43,9 @@ def get_env_vars() -> dict[str, str]: return env_vars -def save_log(out, log_path: Path) -> None: - with log_path.open("w") as log: - for line in out: - log.write(line) +def save_file(data: list[str], path: Path) -> None: + with path.open("w") as log: + log.writelines(data) def get_test_args(args: dict[str, Any]) -> list[str]: @@ -59,7 +61,7 @@ def run_test(test: str, test_args: list[str]) -> bool: logging.info(f"Test: {test_name}") proc = subprocess.run(["pytest", test] + test_args, env=get_env_vars(), encoding="utf-8", stdout=subprocess.PIPE, stderr=subprocess.STDOUT) - save_log(proc.stdout, LOG_DIR / f"{test_name}.log") + save_file(proc.stdout, LOG_DIR / f"{test_name}.log") success = proc.returncode == 0 logging.info("PASSED" if success else "FAILED") return success @@ -95,36 +97,55 @@ def replace_tag(source: list[str], old: str, new: str) -> list[str]: return [line.replace(old, new) for line in source] -def prepare_installers() -> None: - logging.info("Preparing installers...") +def sign_installer(installer: list[str]) -> list[str]: + cmd = ["openssl", "cms", "-sign", + "-signer", f"{INSTALLERS_RESOURCE_DIR / SIGNATURE_FILE_NAME}", + "-inkey", f"{INSTALLERS_RESOURCE_DIR / "private.key"}"] - oneagentctl_bin_name = "oneagentctl.sh" - uninstall_script_name = "uninstall.sh" - installer_partial_name = "Dynatrace-OneAgent-Linux" + proc = subprocess.run(cmd, input=f"{''.join(installer)}", encoding="utf-8", stdout=subprocess.PIPE, stderr=subprocess.STDOUT) + if proc.returncode != 0: + logging.error(f"Failed to sign installer: {proc.stdout}") + sys.exit(1) - version_tag = "##VERSION##" - uninstall_code_tag = "##UNINSTALL_CODE##" - oneagentctl_code_tag = "##ONEAGENTCTL_CODE##" + signed_installer = proc.stdout.splitlines() + delimiter = next(l for l in signed_installer if l.startswith("----")) + index = signed_installer.index(delimiter) + signed_installer = signed_installer[index + 1:] - resource_dir = BASE_DIR / "resources" / "installers" + custom_delimiter = "----SIGNED_INSTALLER" + return [ f"{l}\n" if not l.startswith(delimiter) else f"{l.replace(delimiter, custom_delimiter)}\n" for l in signed_installer] - uninstall_template = get_file_content(resource_dir / uninstall_script_name) + +def prepare_installers() -> None: + logging.info("Preparing installers...") + + uninstall_template = get_file_content(INSTALLERS_RESOURCE_DIR / "uninstall.sh") uninstall_code = replace_tag(uninstall_template, "$", r"\$") - oneagentctl_template = get_file_content(resource_dir / oneagentctl_bin_name) + oneagentctl_template = get_file_content(INSTALLERS_RESOURCE_DIR / "oneagentctl.sh") oneagentctl_code = replace_tag(oneagentctl_template, "$", r"\$") - installer_template = get_file_content(resource_dir / f"{installer_partial_name}.sh") - installer_template = replace_tag(installer_template, uninstall_code_tag, "".join(uninstall_code)) - installer_template = replace_tag(installer_template, oneagentctl_code_tag, "".join(oneagentctl_code)) + installer_partial_name = "Dynatrace-OneAgent-Linux" + installer_template = get_file_content(INSTALLERS_RESOURCE_DIR / f"{installer_partial_name}.sh") + installer_template = replace_tag(installer_template, "##UNINSTALL_CODE##", "".join(uninstall_code)) + installer_template = replace_tag(installer_template, "##ONEAGENTCTL_CODE##", "".join(oneagentctl_code)) timestamp = '{:%Y%m%d-%H%M%S}'.format(datetime.now()) # Minimal supported version is 1.199 for version in ["1.199.0", "1.300.0"]: full_version = f"{version}.{timestamp}" - installer_code = replace_tag(installer_template, version_tag, full_version) - with open(INSTALLERS_DIR / f"{installer_partial_name}-{full_version}.sh", "w") as f: - f.writelines(installer_code) + installer_code = replace_tag(installer_template, "##VERSION##", full_version) + installer_code = sign_installer(installer_code) + + save_file(installer_code, INSTALLERS_DEST_DIR / f"{installer_partial_name}-{full_version}.sh") + + +def assign_localhost_to_ca_provider() -> None: + with open("/etc/hosts", "a+") as f: + if any(SIGNATURE_FILE_NAME in line for line in f.read()): + return + f.write("\n# For orchestration tests purposes\n") + f.write(f"127.0.0.1\t{SIGNATURE_FILE_NAME}\n") def prepare_environment() -> None: @@ -132,9 +153,12 @@ def prepare_environment() -> None: format="%(asctime)s [server] %(levelname)s: %(message)s", datefmt="%H:%M:%S", level=logging.INFO ) shutil.rmtree(TEST_DIR, ignore_errors=True) - os.makedirs(INSTALLERS_DIR, exist_ok=True) + os.makedirs(INSTALLERS_DEST_DIR, exist_ok=True) os.makedirs(LOG_DIR, exist_ok=True) + shutil.copyfile(INSTALLERS_RESOURCE_DIR / SIGNATURE_FILE_NAME, INSTALLERS_DEST_DIR / SIGNATURE_FILE_NAME) + prepare_installers() + assign_localhost_to_ca_provider() def parse_args() -> dict[str, Any]: diff --git a/roles/oneagent/tests/component/scripts/server/server.py b/roles/oneagent/tests/component/scripts/server/server.py index 64babd0..765d2f5 100644 --- a/roles/oneagent/tests/component/scripts/server/server.py +++ b/roles/oneagent/tests/component/scripts/server/server.py @@ -6,7 +6,7 @@ from flask import Blueprint, Flask, request, send_file from util.common_utils import get_installers -from util.constants.common_constants import HOST_SERVER_PORT +from util.constants.common_constants import HOST_SERVER_PORT, INSTALLERS_DIRECTORY, SIGNATURE_FILE_NAME APPLICATION_ROOT = "/api/v1/deployment/installer/agent" @@ -30,6 +30,14 @@ def get_installer(system: str, arch: str, version: str) -> TransferResult: return msg, HTTPStatus.NOT_FOUND +@bp.route(f"/{SIGNATURE_FILE_NAME}") +def get_ca_certificate() -> TransferResult: + cert_file = INSTALLERS_DIRECTORY / SIGNATURE_FILE_NAME + if not cert_file.exists(): + return f"{cert_file} not found", HTTPStatus.NOT_FOUND + return send_file(cert_file) + + @bp.route("//default/latest") def get_latest_agent(system) -> TransferResult: return get_installer(system, request.args["arch"], "latest") diff --git a/roles/oneagent/tests/component/scripts/technology/config.py b/roles/oneagent/tests/component/scripts/technology/config.py index d77be50..009e6ca 100644 --- a/roles/oneagent/tests/component/scripts/technology/config.py +++ b/roles/oneagent/tests/component/scripts/technology/config.py @@ -2,17 +2,17 @@ from typing import Any from technology.constants import ( - PLAYBOOK_TEMPLATE_FILE_NAME, - HOSTS_TEMPLATE_FILE_NAME, - ANSIBLE_USER_KEY, ANSIBLE_CONNECTION_KEY, + ANSIBLE_PASS_KEY, ANSIBLE_RESOURCE_DIR, - COLLECTION_DIR, + ANSIBLE_USER_KEY, COLLECTION_NAME, - PLAYBOOK_FILE, - INVENTORY_FILE, CREDENTIALS_FILE_NAME, - ANSIBLE_PASS_KEY, + HOSTS_TEMPLATE_FILE_NAME, + INSTALLED_COLLECTIONS_DIR, + INVENTORY_FILE, + PLAYBOOK_FILE, + PLAYBOOK_TEMPLATE_FILE_NAME, ) from technology.deployment_config import DeploymentConfig from util.common_utils import read_yaml_file, write_yaml_file @@ -20,6 +20,10 @@ from util.test_data_types import DeploymentPlatform, PlatformCollection +def _prepare_collection() -> None: + shutil.rmtree(TEST_DIRECTORY / "collections", ignore_errors=True) + shutil.copytree(INSTALLED_COLLECTIONS_DIR, TEST_DIRECTORY / "collections") + def _prepare_playbook_file() -> None: shutil.copy( str(ANSIBLE_RESOURCE_DIR / PLAYBOOK_TEMPLATE_FILE_NAME), str(TEST_DIRECTORY / PLAYBOOK_TEMPLATE_FILE_NAME) @@ -80,6 +84,7 @@ def prepare_test_environment(self) -> None: _prepare_playbook_file() _prepare_inventory_file(self.user, self.platforms) _prepare_credentials_file(self.user, self.password) + _prepare_collection() def set_common_parameter(self, key: str, value: Any) -> None: data = read_yaml_file(PLAYBOOK_FILE) diff --git a/roles/oneagent/tests/component/scripts/technology/constants.py b/roles/oneagent/tests/component/scripts/technology/constants.py index d0afcea..dcab805 100644 --- a/roles/oneagent/tests/component/scripts/technology/constants.py +++ b/roles/oneagent/tests/component/scripts/technology/constants.py @@ -23,8 +23,12 @@ PLAYBOOK_TEMPLATE_FILE_NAME = "oneagent.yml" ANSIBLE_RESOURCE_DIR = RESOURCES_DIRECTORY / "ansible" -COLLECTION_DIR = Path().home() / ".ansible" / "collections" / "ansible_collections" / COLLECTION_NAMESPACE -ROLE_DIR = COLLECTION_DIR / COLLECTION_NAME / "roles" / ROLE_NAME +# As tests needs to be run as root and the default install location for collection is non-root based, +# we need to get the script's user home dir to access installed collection. +# Parents[-3] for __file__ will return "/home/" +INSTALLED_COLLECTIONS_DIR = Path(__file__).parents[-3] / ".ansible" / "collections" +NAMESPACE_DIR = INSTALLED_COLLECTIONS_DIR / "ansible_collections" / COLLECTION_NAMESPACE +ROLE_DIR = NAMESPACE_DIR / COLLECTION_NAME / "roles" / ROLE_NAME PLAYBOOK_FILE = TEST_DIRECTORY / PLAYBOOK_TEMPLATE_FILE_NAME INVENTORY_FILE = TEST_DIRECTORY / HOSTS_TEMPLATE_FILE_NAME diff --git a/roles/oneagent/tests/component/scripts/technology/deployment_runner.py b/roles/oneagent/tests/component/scripts/technology/deployment_runner.py index 9020347..14ec4cc 100644 --- a/roles/oneagent/tests/component/scripts/technology/deployment_runner.py +++ b/roles/oneagent/tests/component/scripts/technology/deployment_runner.py @@ -6,4 +6,5 @@ class DeploymentRunner: @abstractmethod def run_deployment(self) -> DeploymentResult: - pass + raise NotImplementedError + diff --git a/roles/oneagent/tests/component/scripts/tests/test_resilience.py b/roles/oneagent/tests/component/scripts/tests/test_resilience.py index c8fea66..4825c83 100644 --- a/roles/oneagent/tests/component/scripts/tests/test_resilience.py +++ b/roles/oneagent/tests/component/scripts/tests/test_resilience.py @@ -88,9 +88,9 @@ def test_missing_local_installer(_error_messages, runner, configurator, constant @enable_for_system_family(family="unix") def test_directories_contain_spaces(_error_messages, runner, configurator, constants): - logging.info("Running directories contain spaces test") - logging.debug("Space in directory path - INSTALL_PATH scenario") + logging.info("Running directories contain spaces test") + logging.info(type(enable_for_system_family)) set_installer_download_params(configurator) installer_args = ["INSTALL_PATH=/path with spaces"] configurator.set_common_parameter(configurator.INSTALLER_ARGS_KEY, installer_args) diff --git a/roles/oneagent/tests/component/scripts/util/constants/common_constants.py b/roles/oneagent/tests/component/scripts/util/constants/common_constants.py index f079e7a..e4bb099 100644 --- a/roles/oneagent/tests/component/scripts/util/constants/common_constants.py +++ b/roles/oneagent/tests/component/scripts/util/constants/common_constants.py @@ -1,6 +1,6 @@ from pathlib import Path -# is cwd() correct? +# TODO: is cwd() correct? COMPONENT_TEST_BASE = Path().cwd() / "test_dir" TEST_DIRECTORY = COMPONENT_TEST_BASE / "working_dir" RESOURCES_DIRECTORY = Path().cwd() / "resources" diff --git a/roles/oneagent/vars/aix.yml b/roles/oneagent/vars/aix.yml index cdb9b15..1956b78 100644 --- a/roles/oneagent/vars/aix.yml +++ b/roles/oneagent/vars/aix.yml @@ -8,8 +8,8 @@ oneagent_available_arch: ["{{ oneagent_default_arch }}"] oneagent_download_arch: "{{ oneagent_installer_arch | default(oneagent_default_arch, true) }}" oneagent_install_path: >- - "{{ oneagent_passed_install_args | select('regex', 'INSTALL_PATH') | first - | default(oneagent_default_install_dir) | regex_replace('INSTALL_PATH=(.*)', '\\1') }}" + {{ oneagent_passed_install_args | select('regex', 'INSTALL_PATH') | first + | default(oneagent_default_install_dir) | regex_replace('INSTALL_PATH=(.*)', '\\1') }} oneagent_download_path: "{{ oneagent_download_dir | default(oneagent_default_download_dir, true) }}" oneagent_installer_path: "{{ oneagent_download_path }}/Dynatrace-OneAgent-AIX-{{ oneagent_version }}.sh" oneagent_ctl_bin_path: "{{ oneagent_install_path }}/agent/tools/oneagentctl" @@ -20,8 +20,6 @@ oneagent_uninstall_cmd: sh {{ oneagent_install_path }}/agent/uninstall.sh oneagent_ca_cert_src_path: files/dt-root.cert.pem oneagent_ca_cert_dest_path: "{{ oneagent_download_path }}/dt-root.cert.pem" oneagent_ca_cert_download_url: https://ca.dynatrace.com/dt-root.cert.pem -oneagent_certificate_verification_header: >- - "Content-Type: multipart/signed; protocol=\"application/x-pkcs7-signature\"; micalg=\"sha-256\"; boundary=\"--SIGNED-INSTALLER\"" - - +oneagent_certificate_verification_header: > + Content-Type: multipart/signed; protocol="application/x-pkcs7-signature"; micalg="sha-256"; boundary="--SIGNED-INSTALLER" oneagent_service_name: oneagent diff --git a/roles/oneagent/vars/linux.yml b/roles/oneagent/vars/linux.yml index 61aeb5c..bfc8117 100644 --- a/roles/oneagent/vars/linux.yml +++ b/roles/oneagent/vars/linux.yml @@ -8,8 +8,8 @@ oneagent_available_arch: ["{{ oneagent_default_arch }}", "ppcle", "s390", "arm"] oneagent_download_arch: "{{ oneagent_installer_arch | default(oneagent_default_arch, true) }}" oneagent_install_path: >- - "{{ oneagent_passed_install_args | select('regex', 'INSTALL_PATH') | first - | default(oneagent_default_install_dir) | regex_replace('INSTALL_PATH=(.*)', '\\1') }}" + {{ oneagent_passed_install_args | select('regex', 'INSTALL_PATH') | first + | default(oneagent_default_install_dir) | regex_replace('INSTALL_PATH=(.*)', '\1') }} oneagent_download_path: "{{ oneagent_download_dir | default(oneagent_default_download_dir, true) }}" oneagent_installer_arch_name: "{{ (oneagent_download_arch == oneagent_default_arch) | ternary('', oneagent_download_arch + '-') }}" oneagent_installer_path: "{{ oneagent_download_path }}/Dynatrace-OneAgent-Linux-{{ oneagent_installer_arch_name }}{{ oneagent_version }}.sh" @@ -21,6 +21,6 @@ oneagent_uninstall_cmd: sh {{ oneagent_install_path }}/agent/uninstall.sh oneagent_ca_cert_src_path: files/dt-root.cert.pem oneagent_ca_cert_dest_path: "{{ oneagent_download_path }}/dt-root.cert.pem" oneagent_ca_cert_download_url: https://ca.dynatrace.com/dt-root.cert.pem -oneagent_certificate_verification_header: >- - "Content-Type: multipart/signed; protocol=\"application/x-pkcs7-signature\"; micalg=\"sha-256\"; boundary=\"--SIGNED-INSTALLER\"" +oneagent_certificate_verification_header: > + Content-Type: multipart/signed; protocol="application/x-pkcs7-signature"; micalg="sha-256"; boundary="--SIGNED-INSTALLER" oneagent_service_name: oneagent diff --git a/roles/oneagent/vars/main.yml b/roles/oneagent/vars/main.yml index 2d575dc..a850179 100644 --- a/roles/oneagent/vars/main.yml +++ b/roles/oneagent/vars/main.yml @@ -10,8 +10,8 @@ oneagent_system_family: "{{ oneagent_system_is_windows | ternary('windows', 'uni oneagent_is_operation_uninstall: "{{ oneagent_package_state == 'absent' }}" oneagent_is_operation_configuration: >- - "{{ not oneagent_is_operation_uninstall and oneagent_environment_url | length == 0 and - oneagent_paas_token | length == 0 and oneagent_local_installer | length == 0 }}" + {{ not oneagent_is_operation_uninstall and oneagent_environment_url | length == 0 and + oneagent_paas_token | length == 0 and oneagent_local_installer | length == 0 }} oneagent_is_operation_installation: "{{ not (oneagent_is_operation_uninstall or oneagent_is_operation_configuration | bool) }}" oneagent_passed_install_args: "{{ (oneagent_install_args + oneagent_platform_install_args) | unique(case_sensitive=False) }}" diff --git a/roles/oneagent/vars/win32nt.yml b/roles/oneagent/vars/win32nt.yml index f14556b..1032877 100644 --- a/roles/oneagent/vars/win32nt.yml +++ b/roles/oneagent/vars/win32nt.yml @@ -8,8 +8,8 @@ oneagent_available_arch: ["{{ oneagent_default_arch }}"] oneagent_download_arch: "{{ oneagent_installer_arch | default(oneagent_default_arch, true) }}" oneagent_install_path: >- - "{{ oneagent_passed_install_args | select('regex', 'INSTALL_PATH') | first - | default(oneagent_default_install_dir) | regex_replace('INSTALL_PATH=(.*)', '\\1') }}" + {{ oneagent_passed_install_args | select('regex', 'INSTALL_PATH') | first + | default(oneagent_default_install_dir) | regex_replace('INSTALL_PATH=(.*)', '\\1') }} oneagent_ctl_bin_path: "{{ oneagent_install_path }}\\agent\\tools\\oneagentctl.exe" oneagent_download_path: "{{ oneagent_download_dir | default(oneagent_default_download_dir, true) }}" oneagent_installer_path: "{{ oneagent_download_path }}\\Dynatrace-OneAgent-Windows-{{ oneagent_version }}.exe"