diff --git a/package/Dockerfile b/package/Dockerfile index c61bb433b2..c8ec42d318 100644 --- a/package/Dockerfile +++ b/package/Dockerfile @@ -83,6 +83,7 @@ COPY package/etc/local_config /etc/syslog-ng/local_config COPY package/sbin/entrypoint.sh / COPY package/sbin/healthcheck.sh / COPY package/sbin/healthcheck.py / +COPY package/sbin/telemetry.py / COPY package/sbin/source_ports_validator.py / ENV SC4S_CONTAINER_OPTS=--no-caps diff --git a/package/sbin/entrypoint.sh b/package/sbin/entrypoint.sh index e4bb36c88e..4c2cadef63 100755 --- a/package/sbin/entrypoint.sh +++ b/package/sbin/entrypoint.sh @@ -190,7 +190,7 @@ fi SC4S_DEST_SPLUNK_HEC_DEFAULT_URL=$(echo $SC4S_DEST_SPLUNK_HEC_DEFAULT_URL | sed 's/\(https\{0,1\}\:\/\/[^\/, ]*\)[^, ]*/\1\/services\/collector\/event/g' | sed 's/,/ /g') if [ "$SC4S_DEST_SPLUNK_HEC_GLOBAL" != "no" ] then - HEC=$(echo $SC4S_DEST_SPLUNK_HEC_DEFAULT_URL | cut -d' ' -f 1) + export HEC=$(echo $SC4S_DEST_SPLUNK_HEC_DEFAULT_URL | cut -d' ' -f 1) if [ "${SC4S_DEST_SPLUNK_HEC_DEFAULT_TLS_VERIFY}" == "no" ]; then export NO_VERIFY=-k ; fi if [ -n "${SC4S_DEST_SPLUNK_HEC_DEFAULT_TLS_MOUNT}" ]; then @@ -220,6 +220,9 @@ then fi fi +# Collect and Send Telemetry metadata +python3 /telemetry.py + # Clearing the local db that stores ip host pairs if [ "${SC4S_CLEAR_NAME_CACHE}" == "yes" ] || [ "${SC4S_CLEAR_NAME_CACHE}" == "1" ] || [ "${SC4S_CLEAR_NAME_CACHE}" == "true" ] then diff --git a/package/sbin/telemetry.py b/package/sbin/telemetry.py new file mode 100644 index 0000000000..283e789f04 --- /dev/null +++ b/package/sbin/telemetry.py @@ -0,0 +1,135 @@ +import json +import os +import platform +import subprocess +from datetime import datetime + +import requests +import urllib3 + + +def subprocess_command_executor(command_string): + try: + result = subprocess.run( + command_string, shell=True, capture_output=True, text=True, check=True + ) + return result.stdout.strip() + except subprocess.CalledProcessError as e: + print(f"Command failed with error code {e.returncode}") + print(f"Stdout: {e.stdout.strip()}") + print(f"Stderr: {e.stderr.strip()}") + except FileNotFoundError: + print("Error: The shell or a command within the pipeline was not found.") + except Exception as e: + print(f"An unexpected error occurred: {e}") + + +def get_os_values() -> dict: + try: + command_string = "cat /etc/*-release" + os_text_data = subprocess_command_executor(command_string) + os_dict = dict() + for line in os_text_data.replace('"', "").split("\n"): + try: + key, val = line.split("=") + except ValueError: + continue + else: + os_dict[key.strip()] = val.strip() + return os_dict + except Exception as e: + print(f"An unexpected error occurred: {e}") + + +def get_physical_cpu_cores(): + try: + command_string = "nproc" + return subprocess_command_executor(command_string) + except Exception as e: + print(f"An unexpected error occurred: {e}") + + +def get_runtime_environment(): + try: + command_string = '[ -f /.dockerenv ] && echo "docker" || echo "unknown"' + return subprocess_command_executor(command_string) + except Exception as e: + print(f"An unexpected error occurred: {e}") + + +def telemetry_data_collector(): + os_values = get_os_values() + payload_data = { + "datetime": str(datetime.now()), + "app_name": "sc4s", + "app_version": "unknown", + "app_edition": "unknown", + "os_name": os_values.get("NAME", "unknown"), + "os_version": os_values.get("VERSION_ID", "unknown"), + "os_release": os_values.get("VERSION", "unknown"), + "kernel_name": platform.system() or "unknown", + "kernel_version": platform.uname().version or "unknown", + "kernel_release": platform.uname().release or "unknown", + "cpu_architecture": platform.uname().machine or "unknown", + "cpu_count": get_physical_cpu_cores() or "unknown", + "runtime_environment": get_runtime_environment() or "unknown", + "runtime_version": "unknown", + "runtime_mode": "unknown", + "runtime_base_os_name": os_values.get("NAME", "unknown"), + "runtime_base_os_version": os_values.get("VERSION_ID", "unknown"), + "runtime_base_os_release": os_values.get("VERSION", "unknown"), + "orchestrator": "unknown", + } + + return payload_data + + +def main(): + # print("telemetry_data_collector := ") + # print(telemetry_data_collector()) + + # Environment variables (same as in your shell) + SC4S_DEST_SPLUNK_HEC_DEFAULT_URL = os.getenv("HEC") + SC4S_DEST_SPLUNK_HEC_DEFAULT_TOKEN = os.getenv("SC4S_DEST_SPLUNK_HEC_DEFAULT_TOKEN") + SC4S_DEST_SPLUNK_HEC_FALLBACK_INDEX = os.getenv( + "SC4S_DEST_SPLUNK_HEC_FALLBACK_INDEX" + ) + + # Prepare headers and payload + headers = { + "Authorization": f"Splunk {SC4S_DEST_SPLUNK_HEC_DEFAULT_TOKEN}", + "Content-Type": "application/json", + } + + telemetry_data = telemetry_data_collector() + payload = { + "event": telemetry_data, + "sourcetype": "sc4s:probe", + "index": SC4S_DEST_SPLUNK_HEC_FALLBACK_INDEX, + } + + print(f"{SC4S_DEST_SPLUNK_HEC_DEFAULT_URL = }") + print(f"{SC4S_DEST_SPLUNK_HEC_DEFAULT_TOKEN = }") + print(f"{headers = }") + print(f"{payload = }") + + # Send the request + try: + import code + + code.interact(local=dict(globals(), **locals())) + + response = requests.post( + SC4S_DEST_SPLUNK_HEC_DEFAULT_URL, + headers=headers, + data=json.dumps(payload), + verify=False, + ) + print(f"Status: {response.status_code}") + print(response.text) + except requests.RequestException as e: + print(f"Error sending event: {e}") + + +if __name__ == "__main__": + main()