diff --git a/integration-examples/system-scanner/README.md b/integration-examples/system-scanner/README.md new file mode 100644 index 0000000..b946109 --- /dev/null +++ b/integration-examples/system-scanner/README.md @@ -0,0 +1,206 @@ +# SystemScanner + +This project is designed to check and report information about the operating system and various runtime environments installed on a machine, such as Java, Python, Node.js, and .NET Framework (on Windows). + +## ⚠️ Warning: Work in Progress + +**PLEASE NOTE: This project is currently in early development stages and is considered a rough work in progress.** + +## Features + +- Check operating system information +- Check Java runtime version +- Check Python runtime version +- Check Node.js runtime version +- Check OpenTelemetry Collector version and path +- Check .NET Framework versions (Windows only) + +## Project Structure + +```plaintext +system-scanner/ +│ +├── os_info.py +├── runtime_versions.py +├── dotnet_framework.py +└── main.py +``` + +### Module Descriptions + +- **`os_info.py`**: Retrieves operating system information. +- **`runtime_versions.py`**: Handles version checking and retrieval for various runtimes like Java, Python, and Node.js. +- **`dotnet_framework.py`**: Specifically deals with retrieving .NET Framework versions on Windows systems. +- **`main.py`**: Entry point to orchestrate the retrieval and logging of system information. + +## Requirements + +- Python 3.9 or higher + +## Installation + +1. Clone the repository: + ```bash + git clone https://github.com/splunk/observability-content-contrib.git + +2. Navigate into the project directory: + ```bash + cd observability-content-contrib/integration-examples/system-scanner + ``` + +## Usage + +To run the script and get information about your system's versions and runtimes, execute: +```bash +python3 main.py +``` + +### Output + +The script generates a formatted report directly to the console, structured as follows: + +``` +================================================== +SYSTEM SCANNER REPORT +================================================== + +OPERATING SYSTEM INFORMATION: + System: [OS Name] + Version: [OS Version] + Architecture: [OS Architecture] + +-------------------------------------------------- +RUNTIME VERSIONS: + Java: [Java Version] + Python: [Python Version] + Node.js: [Node.js Version] + +-------------------------------------------------- +OPENTELEMETRY COLLECTOR INFORMATION: + Version: [OTel Collector Version] + Path: [OTel Collector Path] + +-------------------------------------------------- +[.NET FRAMEWORK VERSIONS (if on Windows)] + +================================================== +END OF SYSTEM SCANNER REPORT +================================================== +``` + + +If running the script(s) isn't an option (for security reasons, etc), the same information can be obtained by referencing the below commands. + + +## Common Commands: Bash vs PowerShell + +For users who need to run commands manually or understand the underlying operations, here are some common commands used in this project with their Bash and PowerShell equivalents: + +| Operation | Bash (Unix-like systems) | PowerShell (Windows) | +|-----------|--------------------------|----------------------| +| Check Java version | `java -version` | `java -version` | +| Check Python version | `python --version` | `python --version` | +| Check Node.js version | `node --version` | `node --version` | +| Check OS version | `uname -a` | `[System.Environment]::OSVersion.Version` | +| List directory contents | `ls -l` | `Get-ChildItem` or `dir` | +| Create a directory | `mkdir -p new_folder` | `New-Item -ItemType Directory -Name new_folder` | +| Remove a file | `rm file.txt` | `Remove-Item file.txt` | +| Set an environment variable | `export VAR_NAME=value` | `$env:VAR_NAME = "value"` | +| Read an environment variable | `echo $VAR_NAME` | `$env:VAR_NAME` | +| Find a file | `find /path -name filename` | `Get-ChildItem -Path C:\ -Recurse -Filter filename` | +| Check if a file exists | `test -f filename && echo "Exists"` | `if (Test-Path filename) { "Exists" }` | +| Get current directory | `pwd` | `Get-Location` or `pwd` | +| Move/Rename a file | `mv old_name new_name` | `Move-Item -Path old_name -Destination new_name` | +| Copy a file | `cp source destination` | `Copy-Item -Path source -Destination destination` | +| Get OTel Collector version | `/bin/otelcol -v` | TBD | + +Note: Some commands (like checking runtime versions) may be identical in both environments, while others differ significantly. + +## .NET Framework Version Check (Windows Only) + +To check the installed .NET Framework versions on a Windows system, you can use the following PowerShell command: + +```powershell +Get-ChildItem 'HKLM:\SOFTWARE\Microsoft\NET Framework Setup\NDP' -Recurse | Get-ItemProperty -Name version -EA 0 | Where { $_.PSChildName -Match '^(?!S)\p{L}'} | Select PSChildName, version +``` + +This command is already implemented in the `dotnet_framework.py` module for Windows systems. + + + +## OTel Collector config location(s) (Default) + +**Windows** +```powershell +C:\ProgramData\Splunk\OpenTelemetry Collector\agent_config.yaml +``` + +**Linux** +```bash +/etc/otel/collector/agent_config.yaml +``` + +The environment file with the required variables/values for the Splunk OpenTelemetry Collector service based on the specified parameters. + +```bash +/etc/otel/collector/splunk-otel-collector.conf +``` + + +## Tailing Collector Logs +**Linux** + +Splunk Distro of OpenTelemetry: + +```bash +sudo journalctl -u splunk-otel-collector -f -n 200 +``` + +```bash +tail -f /var/log/[splunk-otel-collector] +``` + +Upstream OTel Collector (contrib): +```bash +sudo journalctl -u otelcol-contrib -f -n 200 +``` + +```bash +tail -f /var/log/[otelcol-contrib] +``` + +## Getting Status/Restarting the OTel Collector + +**Linux** + +Splunk Distribution: +```bash +sudo systemctl [status/stop/start/restart] splunk-otel-collector +``` + +Upstream Contrib: +```bash +sudo systemctl [status/stop/start/restart] otelcol-contrib +``` + +**Windows** + +Stop the Collector service: + +```powershell +[Stop-Service/Start-Service] splunk-otel-collector +``` + +### Logging + +While the main output is printed to the console, the script also generates a log file (`system_scanner.log`) in the same directory. This log file can be useful for debugging purposes. + +## Error Handling + +The script includes robust error handling mechanisms to catch potential exceptions during execution. Any errors or unexpected behaviors will be reflected in the output. + +## Contributing + +If you wish to contribute to this project, please fork the repository and submit a pull request. + +**Note**: This project uses standard Python libraries to maintain portability and minimize dependencies. diff --git a/integration-examples/system-scanner/dotnet_framework.py b/integration-examples/system-scanner/dotnet_framework.py new file mode 100644 index 0000000..48c9511 --- /dev/null +++ b/integration-examples/system-scanner/dotnet_framework.py @@ -0,0 +1,84 @@ +""" +SystemScanner: .NET Framework Detection Module + +This module is designed to detect and report installed versions +of the .NET Framework on Windows systems. + +It uses the Windows Registry to gather this information and is +only functional on Windows operating systems. + +Note: This module relies on the winreg library, which is only +available on Windows systems. On other operating systems, +the get_dotnet_versions function will return a message +indicating that the winreg module is not available. +""" + +try: + import winreg as reg + + def get_dotnet_versions(): + try: + net_versions = [] + path = r"SOFTWARE\Microsoft\NET Framework Setup\NDP" + + def check_versions(key): + i = 0 + while True: + try: + subkey_name = reg.EnumKey(key, i) + subkey_path = f"{path}\\{subkey_name}" + with reg.OpenKey(reg.HKEY_LOCAL_MACHINE, subkey_path) as subkey: + try: + version, _ = reg.QueryValueEx(subkey, "Version") + net_versions.append((subkey_name, version)) + except FileNotFoundError: + pass + i += 1 + except OSError: + break + + with reg.OpenKey(reg.HKEY_LOCAL_MACHINE, path) as main_key: + check_versions(main_key) + + return net_versions + + except OSError as e: + return f"Error accessing registry: {e}" + +except ImportError: + + def get_dotnet_versions(): + return "winreg module not available on this platform" + + +# Saving for a future iteration: + +# def get_dotnet_versions(): +# try: +# net_versions = [] +# path = r"SOFTWARE\Microsoft\NET Framework Setup\NDP" + +# def iterate_registry(key): +# stack = [(key, 0)] +# while stack: +# current_key, i = stack.pop() +# try: +# subkey_name = reg.EnumKey(current_key, i) +# subkey_path = f"{path}\\{subkey_name}" +# with reg.OpenKey(reg.HKEY_LOCAL_MACHINE, subkey_path) as subkey: +# try: +# version, _ = reg.QueryValueEx(subkey, "Version") +# net_versions.append((subkey_name, version)) +# except FileNotFoundError: +# pass +# stack.append((current_key, i + 1)) +# except OSError: +# break + +# with reg.OpenKey(reg.HKEY_LOCAL_MACHINE, path) as main_key: +# iterate_registry(main_key) + +# return net_versions + +# except OSError as e: +# return f"Error accessing registry: {e}" diff --git a/integration-examples/system-scanner/main.py b/integration-examples/system-scanner/main.py new file mode 100644 index 0000000..37765af --- /dev/null +++ b/integration-examples/system-scanner/main.py @@ -0,0 +1,80 @@ +#!/usr/bin/env python3 + +""" +SystemScanner +Version 0.2 +Author: Brandon Blinderman +""" + +from os_info import get_os_info +from runtime_versions import RuntimeFactory +from dotnet_framework import get_dotnet_versions +import logging + + +def print_separator(): + print("-" * 50) + + +def main(): + # Set up logging for debug purposes, but don't use it for main output + logging.basicConfig( + level=logging.DEBUG, filename="system_scanner.log", filemode="w" + ) + logger = logging.getLogger(__name__) + + print("=" * 50) + print("SYSTEM SCANNER REPORT") + print("=" * 50) + print() + + # Operating System Information + os_name, os_version, os_architecture = get_os_info() + print("OPERATING SYSTEM INFORMATION:") + print(f" System: {os_name}") + print(f" Version: {os_version}") + print(f" Architecture: {os_architecture}") + + print_separator() + + # Runtime Versions + factory = RuntimeFactory() + print("RUNTIME VERSIONS:") + + java_version = factory.get_version("java") + print(f" Java: {java_version}") + + python_version = factory.get_version("python") + print(f" Python: {python_version}") + + node_version = factory.get_version("node") + print(f" Node.js: {node_version}") + + print_separator() + + # OpenTelemetry Collector Information + print("OPENTELEMETRY COLLECTOR INFORMATION:") + otel_version, otel_path = factory.get_otel_collector_info() + print(f" Version: {otel_version}") + print(f" Path: {otel_path if otel_path else 'Not found'}") + + print_separator() + + # .NET Framework Versions (Windows only) + if os_name == "Windows": + print(".NET FRAMEWORK VERSIONS:") + dotnet_versions = get_dotnet_versions() + if isinstance(dotnet_versions, list): + for name, version in dotnet_versions: + print(f" {name}: {version}") + else: + print(f" Error: {dotnet_versions}") + + print() + print("=" * 50) + print("END OF SYSTEM SCANNER REPORT") + print("=" * 50) + + +if __name__ == "__main__": + main() diff --git a/integration-examples/system-scanner/os_info.py b/integration-examples/system-scanner/os_info.py new file mode 100644 index 0000000..66579e2 --- /dev/null +++ b/integration-examples/system-scanner/os_info.py @@ -0,0 +1,64 @@ +""" +SystemScanner: OS Information Module + +This module provides functionality to retrieve detailed information +about the operating system on which the script is running. + +It includes functions to get the system name, release version, +and architecture. +""" + +import platform +# import subprocess + + +def get_os_info(): + system = platform.system() + release = platform.release() + architecture = platform.machine() + + return system, release, architecture + + +## Leaving this for a future upgrade. + +# def get_os_info(): +# system = platform.system() +# version = platform.release() +# detailed_version = "" + +# if system == "Darwin": # macOS +# mac_version = platform.mac_ver()[0] +# detailed_version = f"macOS {mac_version}" +# elif system == "Linux": +# try: +# # Try to get the distribution name and version +# distro = subprocess.check_output(["lsb_release", "-ds"]).decode().strip() +# detailed_version = distro +# except: +# # If lsb_release is not available, try reading from /etc/os-release +# try: +# with open("/etc/os-release") as f: +# lines = f.readlines() +# for line in lines: +# if line.startswith("PRETTY_NAME="): +# detailed_version = line.split("=")[1].strip().strip('"') +# break +# except: +# detailed_version = "Unknown Linux distribution" +# elif system == "Windows": +# win_version = platform.win32_ver() +# detailed_version = f"Windows {win_version[0]} {win_version[1]}" +# else: +# detailed_version = f"Unknown OS: {system} {version}" + +# return system, version, detailed_version + +# def main(): +# system, version, detailed_version = get_os_info() +# print(f"Operating System: {system}") +# print(f"Kernel Version: {version}") +# print(f"Detailed Version: {detailed_version}") + +# if __name__ == "__main__": +# main() diff --git a/integration-examples/system-scanner/runtime_versions.py b/integration-examples/system-scanner/runtime_versions.py new file mode 100644 index 0000000..fb88d32 --- /dev/null +++ b/integration-examples/system-scanner/runtime_versions.py @@ -0,0 +1,73 @@ +""" +SystemScanner: Runtime Versions Module + +This module is responsible for detecting and reporting versions +of various runtime environments installed on the system, such as +Java, Python, and Node.js. + +It uses a factory pattern to manage different runtime version checks. +""" + +import os +import sys +import subprocess + + +class RuntimeFactory: + def __init__(self): + self.executors = { + "java": ["java", "-version"], + "node": ["node", "-v"], + "python": lambda: f"{sys.version_info.major}.{sys.version_info.minor}.{sys.version_info.micro}", + } + + def get_version(self, runtime_name): + command = self.executors.get(runtime_name) + if callable(command): + return command() + elif command: + return self.execute_command(command) + return f"{runtime_name} not supported" + + def execute_command(self, command): + try: + result = subprocess.run( + command, stderr=subprocess.STDOUT, stdout=subprocess.PIPE, check=True + ) + return result.stdout.decode().strip() + except subprocess.CalledProcessError as e: + return f"Command failed: {e}" + except FileNotFoundError: + return f"{command[0]} not found" + + def get_otel_collector_info(self): + try: + if os.name == "nt": # Windows + result = subprocess.run( + ["where", "otelcol"], capture_output=True, text=True + ) + if result.returncode == 0: + otelcol_path = result.stdout.strip().split("\n")[0] + version_result = subprocess.run( + [otelcol_path, "--version"], capture_output=True, text=True + ) + else: + return "OpenTelemetry Collector not found", None + else: # Unix-like systems + otelcol_path = "/bin/otelcol" + version_result = subprocess.run( + [otelcol_path, "--version"], capture_output=True, text=True + ) + + if version_result.returncode == 0: + version_info = version_result.stdout or version_result.stderr + return version_info.strip(), otelcol_path + else: + return ( + "Unable to determine OpenTelemetry Collector version", + otelcol_path, + ) + except FileNotFoundError: + return "OpenTelemetry Collector not found", None + except Exception as e: + return f"Error checking OpenTelemetry Collector version: {str(e)}", None