From a4dd11d6d68bfe3d408c49dd33b8cf260f0aa684 Mon Sep 17 00:00:00 2001 From: Jeff Cheng Date: Thu, 1 Apr 2021 13:26:16 -0400 Subject: [PATCH] Support gateway mode for linux installer (#187) --- internal/buildscripts/packaging/fpm/common.sh | 9 +- .../buildscripts/packaging/fpm/deb/build.sh | 3 +- .../buildscripts/packaging/fpm/rpm/build.sh | 3 +- .../packaging/installer/install.sh | 53 +++++- .../packaging/tests/installer_test.py | 156 ++++++++++++++++-- .../packaging/tests/package_test.py | 11 +- 6 files changed, 206 insertions(+), 29 deletions(-) diff --git a/internal/buildscripts/packaging/fpm/common.sh b/internal/buildscripts/packaging/fpm/common.sh index f5b1045b59..8a77bae8ea 100644 --- a/internal/buildscripts/packaging/fpm/common.sh +++ b/internal/buildscripts/packaging/fpm/common.sh @@ -29,8 +29,10 @@ SERVICE_USER="splunk-otel-collector" SERVICE_GROUP="splunk-otel-collector" OTELCOL_INSTALL_PATH="/usr/bin/otelcol" -CONFIG_REPO_PATH="$REPO_DIR/cmd/otelcol/config/collector/agent_config.yaml" -CONFIG_INSTALL_PATH="/etc/otel/collector/agent_config.yaml" +AGENT_CONFIG_REPO_PATH="$REPO_DIR/cmd/otelcol/config/collector/agent_config.yaml" +AGENT_CONFIG_INSTALL_PATH="/etc/otel/collector/agent_config.yaml" +GATEWAY_CONFIG_REPO_PATH="$REPO_DIR/cmd/otelcol/config/collector/gateway_config.yaml" +GATEWAY_CONFIG_INSTALL_PATH="/etc/otel/collector/gateway_config.yaml" SERVICE_REPO_PATH="$FPM_DIR/$SERVICE_NAME.service" SERVICE_INSTALL_PATH="/lib/systemd/system/$SERVICE_NAME.service" @@ -107,7 +109,8 @@ setup_files_and_permissions() { sudo chmod 755 "$buildroot/$OTELCOL_INSTALL_PATH" cp -r "$FPM_DIR/etc" "$buildroot/etc" - cp -f "$CONFIG_REPO_PATH" "$buildroot/$CONFIG_INSTALL_PATH" + cp -f "$AGENT_CONFIG_REPO_PATH" "$buildroot/$AGENT_CONFIG_INSTALL_PATH" + cp -f "$GATEWAY_CONFIG_REPO_PATH" "$buildroot/$GATEWAY_CONFIG_INSTALL_PATH" sudo chown -R $SERVICE_USER:$SERVICE_GROUP "$buildroot/etc/otel" sudo chmod -R 755 "$buildroot/etc/otel" sudo chmod 600 "$buildroot/etc/otel/collector/$SERVICE_NAME.conf.example" diff --git a/internal/buildscripts/packaging/fpm/deb/build.sh b/internal/buildscripts/packaging/fpm/deb/build.sh index 824ecde345..f782cf5aae 100755 --- a/internal/buildscripts/packaging/fpm/deb/build.sh +++ b/internal/buildscripts/packaging/fpm/deb/build.sh @@ -54,7 +54,8 @@ sudo fpm -s dir -t deb -n "$PKG_NAME" -v "$VERSION" -f -p "$OUTPUT_DIR" \ --after-install "$POSTINSTALL_PATH" \ --before-remove "$PREUNINSTALL_PATH" \ --deb-no-default-config-files \ - --config-files "$CONFIG_INSTALL_PATH" \ + --config-files "$AGENT_CONFIG_INSTALL_PATH" \ + --config-files "$GATEWAY_CONFIG_INSTALL_PATH" \ --config-files "$FLUENTD_CONFIG_INSTALL_DIR" \ "$buildroot/"=/ diff --git a/internal/buildscripts/packaging/fpm/rpm/build.sh b/internal/buildscripts/packaging/fpm/rpm/build.sh index 483afcd4fb..c4f9709396 100755 --- a/internal/buildscripts/packaging/fpm/rpm/build.sh +++ b/internal/buildscripts/packaging/fpm/rpm/build.sh @@ -58,7 +58,8 @@ sudo fpm -s dir -t rpm -n "$PKG_NAME" -v "$VERSION" -f -p "$OUTPUT_DIR" \ --before-install "$PREINSTALL_PATH" \ --after-install "$POSTINSTALL_PATH" \ --before-remove "$PREUNINSTALL_PATH" \ - --config-files "$CONFIG_INSTALL_PATH" \ + --config-files "$AGENT_CONFIG_INSTALL_PATH" \ + --config-files "$GATEWAY_CONFIG_INSTALL_PATH" \ --config-files "$FLUENTD_CONFIG_INSTALL_DIR" \ "$buildroot/"=/ diff --git a/internal/buildscripts/packaging/installer/install.sh b/internal/buildscripts/packaging/installer/install.sh index 37b6bf5837..87ea517f10 100755 --- a/internal/buildscripts/packaging/installer/install.sh +++ b/internal/buildscripts/packaging/installer/install.sh @@ -56,8 +56,9 @@ get_distro_codename() { } collector_config_dir="/etc/otel/collector" -collector_config_path="${collector_config_dir}/agent_config.yaml" -collector_config_old_path="${collector_config_dir}/splunk_config_linux.yaml" +agent_config_path="${collector_config_dir}/agent_config.yaml" +gateway_config_path="${collector_config_dir}/gateway_config.yaml" +old_config_path="${collector_config_dir}/splunk_config_linux.yaml" collector_env_path="${collector_config_dir}/splunk-otel-collector.conf" collector_env_old_path="${collector_config_dir}/splunk_env" collector_bundle_dir="/usr/lib/splunk-otel-collector/agent-bundle" @@ -514,6 +515,7 @@ Options: (default: https://ingest.REALM.signalfx.com) --memory Total memory in MIB to allocate to the collector; automatically calculates the ballast size (default: "$default_memory_size") + --mode Configure the collector service to run in agent or gateway mode (default: "agent") --realm The Splunk realm to use (default: "$default_realm") The ingest, api, trace, and HEC endpoint URLs will automatically be inferred by this value --service-group Set the group for the splunk-otel-collector service (default: "$default_service_group") @@ -549,7 +551,9 @@ parse_args_and_install() { local td_agent_version="$default_td_agent_version" local trace_url= local uninstall="false" + local mode="agent" local with_fluentd="true" + local collector_config_path= while [ -n "${1-}" ]; do case $1 in @@ -591,6 +595,18 @@ parse_args_and_install() { memory="$2" shift 1 ;; + --mode) + case $2 in + agent|gateway) + mode="$2" + ;; + *) + echo "Unsupported mode '$2'" >&2 + exit 1 + ;; + esac + shift 1 + ;; --realm) realm="$2" shift 1 @@ -701,12 +717,39 @@ parse_args_and_install() { create_user_group "$service_user" "$service_group" configure_service_owner "$service_user" "$service_group" + if [ "$mode" = "agent" ]; then + if [ -f "$agent_config_path" ]; then + # use the agent config if the installed package includes it + collector_config_path="$agent_config_path" + elif [ -f "$old_config_path" ]; then + # use the old config if the installed package does not include the new agent config + collector_config_path="$old_config_path" + fi + else + if [ -f "$gateway_config_path" ]; then + # use the gateway config if the installed package includes it + collector_config_path="$gateway_config_path" + elif [ -f "$agent_config_path" ]; then + # use the agent config if the installed package includes it + collector_config_path="$agent_config_path" + elif [ -f "$old_config_path" ]; then + # use the old config if the installed package does not include the new agent or gateway config + collector_config_path="$old_config_path" + fi + fi + + if [ -z "$collector_config_path" ]; then + echo "ERROR: The installed splunk-otel-collector package does not include a supported config file!" >&2 + exit 1 + elif [ ! -f "$collector_config_path" ]; then + echo "ERROR: Config file $collector_config_path not found!" >&2 + exit 1 + fi + if [ ! -f "${collector_env_path}.example" ]; then collector_env_path=$collector_env_old_path fi - if [ ! -f "${collector_config_path}" ]; then - collector_config_path=$collector_config_old_path - fi + configure_env_file "SPLUNK_CONFIG" "$collector_config_path" "$collector_env_path" configure_env_file "SPLUNK_ACCESS_TOKEN" "$access_token" "$collector_env_path" configure_env_file "SPLUNK_REALM" "$realm" "$collector_env_path" diff --git a/internal/buildscripts/packaging/tests/installer_test.py b/internal/buildscripts/packaging/tests/installer_test.py index b03fd00fe1..9e2f1ab8fd 100644 --- a/internal/buildscripts/packaging/tests/installer_test.py +++ b/internal/buildscripts/packaging/tests/installer_test.py @@ -39,9 +39,13 @@ SPLUNK_ENV_PATH = "/etc/otel/collector/splunk-otel-collector.conf" OLD_SPLUNK_ENV_PATH = "/etc/otel/collector/splunk_env" +AGENT_CONFIG_PATH = "/etc/otel/collector/agent_config.yaml" +GATEWAY_CONFIG_PATH = "/etc/otel/collector/gateway_config.yaml" +OLD_CONFIG_PATH = "/etc/otel/collector/splunk_config_linux.yaml" TOTAL_MEMORY = "256" BALLAST = "128" + @pytest.mark.installer @pytest.mark.parametrize( "distro", @@ -49,14 +53,9 @@ + [pytest.param(distro, marks=pytest.mark.rpm) for distro in RPM_DISTROS], ) @pytest.mark.parametrize("version", VERSIONS) -@pytest.mark.parametrize("memory_option", ["memory", "ballast"]) -def test_installer(distro, version, memory_option): - install_cmd = f"sh -x /test/install.sh -- testing123 --realm us0" - - if memory_option == "memory": - install_cmd = f"{install_cmd} --{memory_option} {TOTAL_MEMORY}" - elif memory_option == "ballast": - install_cmd = f"{install_cmd} --{memory_option} {BALLAST}" +@pytest.mark.parametrize("mode", ["agent", "gateway"]) +def test_installer_mode(distro, version, mode): + install_cmd = f"sh -x /test/install.sh -- testing123 --realm us0 --memory {TOTAL_MEMORY} --mode {mode}" if version != "latest": install_cmd = f"{install_cmd} --collector-version {version.lstrip('v')}" @@ -74,16 +73,20 @@ def test_installer(distro, version, memory_option): run_container_cmd(container, install_cmd, env={"VERIFY_ACCESS_TOKEN": "false"}) time.sleep(5) + config_path = AGENT_CONFIG_PATH if mode == "agent" else GATEWAY_CONFIG_PATH + if container.exec_run(f"test -f {OLD_CONFIG_PATH}").exit_code == 0: + config_path = OLD_CONFIG_PATH + elif mode == "gateway" and container.exec_run(f"test -f {GATEWAY_CONFIG_PATH}").exit_code != 0: + config_path = AGENT_CONFIG_PATH + # verify env file created with configured parameters splunk_env_path = SPLUNK_ENV_PATH if container.exec_run(f"test -f {OLD_SPLUNK_ENV_PATH}").exit_code == 0: splunk_env_path = OLD_SPLUNK_ENV_PATH + run_container_cmd(container, f"grep '^SPLUNK_CONFIG={config_path}$' {splunk_env_path}") run_container_cmd(container, f"grep '^SPLUNK_ACCESS_TOKEN=testing123$' {splunk_env_path}") run_container_cmd(container, f"grep '^SPLUNK_REALM=us0$' {splunk_env_path}") - if memory_option == "memory": - run_container_cmd(container, f"grep '^SPLUNK_MEMORY_TOTAL_MIB={TOTAL_MEMORY}$' {splunk_env_path}") - elif memory_option == "ballast": - run_container_cmd(container, f"grep '^SPLUNK_BALLAST_SIZE_MIB={BALLAST}$' {splunk_env_path}") + run_container_cmd(container, f"grep '^SPLUNK_MEMORY_TOTAL_MIB={TOTAL_MEMORY}$' {splunk_env_path}") # verify collector service status assert wait_for(lambda: service_is_running(container, service_owner=SERVICE_OWNER)) @@ -112,6 +115,66 @@ def test_installer(distro, version, memory_option): assert container.exec_run("test -f /tmp/splunk-support-bundle.tar.gz").exit_code == 0 run_container_cmd(container, "sh -x /test/install.sh --uninstall") + + finally: + run_container_cmd(container, "journalctl -u td-agent --no-pager") + if container.exec_run("test -f /var/log/td-agent/td-agent.log").exit_code == 0: + run_container_cmd(container, "cat /var/log/td-agent/td-agent.log") + run_container_cmd(container, f"journalctl -u {SERVICE_NAME} --no-pager") + + +@pytest.mark.installer +@pytest.mark.parametrize( + "distro", + [pytest.param(distro, marks=pytest.mark.deb) for distro in DEB_DISTROS] + + [pytest.param(distro, marks=pytest.mark.rpm) for distro in RPM_DISTROS], + ) +@pytest.mark.parametrize("version", VERSIONS) +def test_installer_ballast(distro, version): + install_cmd = f"sh -x /test/install.sh -- testing123 --realm us0 --ballast {BALLAST}" + + if version != "latest": + install_cmd = f"{install_cmd} --collector-version {version.lstrip('v')}" + + if STAGE != "release": + assert STAGE in ("test", "beta"), f"Unsupported stage '{STAGE}'!" + install_cmd = f"{install_cmd} --{STAGE}" + + print(f"Testing installation on {distro} from {STAGE} stage ...") + with run_distro_container(distro) as container: + # run installer script + copy_file_into_container(container, INSTALLER_PATH, "/test/install.sh") + + try: + run_container_cmd(container, install_cmd, env={"VERIFY_ACCESS_TOKEN": "false"}) + time.sleep(5) + + config_path = AGENT_CONFIG_PATH + if container.exec_run(f"test -f {OLD_CONFIG_PATH}").exit_code == 0: + config_path = OLD_CONFIG_PATH + + splunk_env_path = SPLUNK_ENV_PATH + if container.exec_run(f"test -f {OLD_SPLUNK_ENV_PATH}").exit_code == 0: + splunk_env_path = OLD_SPLUNK_ENV_PATH + + # verify env file created with configured parameters + run_container_cmd(container, f"grep '^SPLUNK_CONFIG={config_path}$' {splunk_env_path}") + run_container_cmd(container, f"grep '^SPLUNK_ACCESS_TOKEN=testing123$' {splunk_env_path}") + run_container_cmd(container, f"grep '^SPLUNK_REALM=us0$' {splunk_env_path}") + run_container_cmd(container, f"grep '^SPLUNK_BALLAST_SIZE_MIB={BALLAST}$' {splunk_env_path}") + + # verify collector service status + assert wait_for(lambda: service_is_running(container, service_owner=SERVICE_OWNER)) + + # the td-agent service should only be running when installing + # collector packages that have our custom fluent config + if container.exec_run("test -f /etc/otel/collector/fluentd/fluent.conf").exit_code == 0: + assert container.exec_run("systemctl status td-agent").exit_code == 0 + else: + assert container.exec_run("systemctl status td-agent").exit_code != 0 + + run_container_cmd(container, "sh -x /test/install.sh --uninstall") + finally: run_container_cmd(container, "journalctl -u td-agent --no-pager") if container.exec_run("test -f /var/log/td-agent/td-agent.log").exit_code == 0: @@ -140,16 +203,23 @@ def test_installer_service_owner(distro, version): print(f"Testing installation on {distro} from {STAGE} stage ...") with run_distro_container(distro) as container: - # run installer script copy_file_into_container(container, INSTALLER_PATH, "/test/install.sh") - run_container_cmd(container, install_cmd, env={"VERIFY_ACCESS_TOKEN": "false"}) - time.sleep(5) try: - # verify env file created with configured parameters + # run installer script + run_container_cmd(container, install_cmd, env={"VERIFY_ACCESS_TOKEN": "false"}) + time.sleep(5) + + config_path = AGENT_CONFIG_PATH + if container.exec_run(f"test -f {OLD_CONFIG_PATH}").exit_code == 0: + config_path = OLD_CONFIG_PATH + splunk_env_path = SPLUNK_ENV_PATH if container.exec_run(f"test -f {OLD_SPLUNK_ENV_PATH}").exit_code == 0: splunk_env_path = OLD_SPLUNK_ENV_PATH + + # verify env file created with configured parameters + run_container_cmd(container, f"grep '^SPLUNK_CONFIG={config_path}$' {splunk_env_path}") run_container_cmd(container, f"grep '^SPLUNK_ACCESS_TOKEN=testing123$' {splunk_env_path}") run_container_cmd(container, f"grep '^SPLUNK_REALM=us0$' {splunk_env_path}") run_container_cmd(container, f"grep '^SPLUNK_MEMORY_TOTAL_MIB={TOTAL_MEMORY}$' {splunk_env_path}") @@ -167,3 +237,57 @@ def test_installer_service_owner(distro, version): finally: run_container_cmd(container, "journalctl -u td-agent --no-pager") run_container_cmd(container, f"journalctl -u {SERVICE_NAME} --no-pager") + + +@pytest.mark.installer +@pytest.mark.parametrize( + "distro", + [pytest.param(distro, marks=pytest.mark.deb) for distro in DEB_DISTROS] + + [pytest.param(distro, marks=pytest.mark.rpm) for distro in RPM_DISTROS], + ) +@pytest.mark.parametrize("version", VERSIONS) +def test_installer_without_fluentd(distro, version): + install_cmd = f"sh -x /test/install.sh -- testing123 --realm us0 --memory {TOTAL_MEMORY} --without-fluentd" + + if version != "latest": + install_cmd = f"{install_cmd} --collector-version {version.lstrip('v')}" + + if STAGE != "release": + assert STAGE in ("test", "beta"), f"Unsupported stage '{STAGE}'!" + install_cmd = f"{install_cmd} --{STAGE}" + + print(f"Testing installation on {distro} from {STAGE} stage ...") + with run_distro_container(distro) as container: + copy_file_into_container(container, INSTALLER_PATH, "/test/install.sh") + + try: + # run installer script + run_container_cmd(container, install_cmd, env={"VERIFY_ACCESS_TOKEN": "false"}) + time.sleep(5) + + config_path = AGENT_CONFIG_PATH + if container.exec_run(f"test -f {OLD_CONFIG_PATH}").exit_code == 0: + config_path = OLD_CONFIG_PATH + + splunk_env_path = SPLUNK_ENV_PATH + if container.exec_run(f"test -f {OLD_SPLUNK_ENV_PATH}").exit_code == 0: + splunk_env_path = OLD_SPLUNK_ENV_PATH + + # verify env file created with configured parameters + run_container_cmd(container, f"grep '^SPLUNK_CONFIG={config_path}$' {splunk_env_path}") + run_container_cmd(container, f"grep '^SPLUNK_ACCESS_TOKEN=testing123$' {splunk_env_path}") + run_container_cmd(container, f"grep '^SPLUNK_REALM=us0$' {splunk_env_path}") + run_container_cmd(container, f"grep '^SPLUNK_MEMORY_TOTAL_MIB={TOTAL_MEMORY}$' {splunk_env_path}") + + # verify collector service status + assert wait_for(lambda: service_is_running(container, service_owner=SERVICE_OWNER)) + + if distro in DEB_DISTROS: + assert container.exec_run("dpkg -s td-agent").exit_code != 0 + else: + assert container.exec_run("rpm -q td-agent").exit_code != 0 + + run_container_cmd(container, "sh -x /test/install.sh --uninstall") + + finally: + run_container_cmd(container, f"journalctl -u {SERVICE_NAME} --no-pager") diff --git a/internal/buildscripts/packaging/tests/package_test.py b/internal/buildscripts/packaging/tests/package_test.py index 903374201e..aa887c0ca0 100644 --- a/internal/buildscripts/packaging/tests/package_test.py +++ b/internal/buildscripts/packaging/tests/package_test.py @@ -54,7 +54,9 @@ def test_collector_package_install(distro): service_name = "splunk-otel-collector" service_owner = "splunk-otel-collector" service_proc = "otelcol" - config_path = "/etc/otel/collector/splunk-otel-collector.conf" + env_path = "/etc/otel/collector/splunk-otel-collector.conf" + agent_config_path = "/etc/otel/collector/agent_config.yaml" + gateway_config_path = "/etc/otel/collector/gateway_config.yaml" bundle_dir = "/usr/lib/splunk-otel-collector/agent-bundle" pkg_path = get_package(distro, pkg_name, pkg_dir) @@ -75,12 +77,15 @@ def test_collector_package_install(distro): run_container_cmd(container, f"test -d {bundle_dir}") run_container_cmd(container, f"test -d {bundle_dir}/run/collectd") + run_container_cmd(container, f"test -f {agent_config_path}") + run_container_cmd(container, f"test -f {gateway_config_path}") + # verify service is not running after install without config file time.sleep(5) assert not service_is_running(container, service_name, service_owner, service_proc) # verify service starts with config file - run_container_cmd(container, f"cp -f {config_path}.example {config_path}") + run_container_cmd(container, f"cp -f {env_path}.example {env_path}") run_container_cmd(container, f"systemctl start {service_name}") time.sleep(5) assert wait_for(lambda: service_is_running(container, service_name, service_owner, service_proc)) @@ -111,4 +116,4 @@ def test_collector_package_install(distro): assert not service_is_running(container, service_name, service_owner, service_proc) # verify config file is not removed - run_container_cmd(container, f"test -f {config_path}") + run_container_cmd(container, f"test -f {env_path}")