diff --git a/scripts/auto-instrumentation/instrumentation-java-so-tomcat.sh b/scripts/auto-instrumentation/instrumentation-java-so-tomcat.sh old mode 100644 new mode 100755 index e1f5952..8566afa --- a/scripts/auto-instrumentation/instrumentation-java-so-tomcat.sh +++ b/scripts/auto-instrumentation/instrumentation-java-so-tomcat.sh @@ -54,6 +54,82 @@ err() { echo "ERROR: $*" >&2; exit 1; } info() { echo "INFO: $*"; } warn() { echo "WARN: $*"; } +# Configuration file for storing credentials +MW_CONFIG_FILE="/etc/middleware/config" + +# Function to store MW_API_KEY and MW_TARGET in system configuration +store_middleware_credentials() { + local api_key="$1" + local target="$2" + + # Create config directory if it doesn't exist + mkdir -p "$(dirname "$MW_CONFIG_FILE")" + + # Store the credentials in a secure config file + cat > "$MW_CONFIG_FILE" </dev/null | tr '\0' '\n' | grep -E "OTEL_EXPORTER_OTLP_ENDPOINT|JAVA_TOOL_OPTIONS" || echo "") + # Check if this specific WAR application is already instrumented + # We'll use a WAR-specific marker file to track instrumentation status + local war_marker_file="" + if [ -n "$catalina_base" ] && [ -d "$catalina_base" ]; then + war_marker_file="$catalina_base/webapps/$app_name/.otel-instrumented" + elif [ -n "$catalina_home" ] && [ -d "$catalina_home" ]; then + war_marker_file="$catalina_home/webapps/$app_name/.otel-instrumented" + fi - if echo "$env_output" | grep -q "OTEL_EXPORTER_OTLP_ENDPOINT"; then - info "Tomcat application $app_name is already instrumented" + if [ -f "$war_marker_file" ]; then + info "WAR application $app_name is already instrumented" return 0 fi # Create backup of Tomcat configuration - local backup_dir="/tmp/tomcat-otel-backup-$(date +%Y%m%d_%H%M%S)" + local backup_dir + backup_dir="/tmp/tomcat-otel-backup-$(date +%Y%m%d_%H%M%S)" mkdir -p "$backup_dir" # Find and backup setenv.sh or catalina.sh @@ -483,7 +641,63 @@ update_tomcat_app() { catalina_script="$catalina_home/bin/catalina.sh" fi - # Create or update setenv.sh with OTEL configuration + # Create WAR-specific marker file and configuration + if [ -n "$catalina_base" ] && [ -d "$catalina_base" ]; then + # Create WAR-specific marker file + touch "$war_marker_file" + echo "Instrumented on: $(date)" > "$war_marker_file" + echo "Service name: $app_name" >> "$war_marker_file" + echo "WAR path: $catalina_base/webapps/$app_name" >> "$war_marker_file" + + # Create WAR-specific OpenTelemetry configuration using environment variables + # This approach uses OpenTelemetry's built-in service name detection + local war_config_dir="$catalina_base/webapps/$app_name/WEB-INF/classes" + mkdir -p "$war_config_dir" + + # Create a simple environment file that sets WAR-specific service name + local war_env_file="$war_config_dir/otel-war.env" + cat > "$war_env_file" < "$war_marker_file" + echo "Service name: $app_name" >> "$war_marker_file" + echo "WAR path: $catalina_home/webapps/$app_name" >> "$war_marker_file" + + # Create WAR-specific OpenTelemetry configuration using environment variables + local war_config_dir="$catalina_home/webapps/$app_name/WEB-INF/classes" + mkdir -p "$war_config_dir" + + # Create a simple environment file that sets WAR-specific service name + local war_env_file="$war_config_dir/otel-war.env" + cat > "$war_env_file" < "$setenv_file" <> "$setenv_file" </dev/null | tr '\0' '\n' | grep -E "OTEL_EXPORTER_OTLP_ENDPOINT" || echo "") + # Check if already instrumented using WAR-specific marker file + local war_marker_file="" + if [ -n "$catalina_base" ] && [ -d "$catalina_base" ]; then + war_marker_file="$catalina_base/webapps/$app_name/.otel-instrumented" + elif [ -n "$catalina_home" ] && [ -d "$catalina_home" ]; then + war_marker_file="$catalina_home/webapps/$app_name/.otel-instrumented" + fi - if echo "$env_output" | grep -q "OTEL_EXPORTER_OTLP_ENDPOINT"; then - info "Tomcat application $app_name is already instrumented" + if [ -f "$war_marker_file" ]; then + info "WAR application $app_name is already instrumented" return 0 fi # Update the Tomcat application - update_tomcat_app "$found_app_id" "$found_pid" "$catalina_home" "$catalina_base" "$app_name" "$app_path" - - if [ $? -eq 0 ]; then + if update_tomcat_app "$found_app_id" "$found_pid" "$catalina_home" "$catalina_base" "$app_name" "$app_path"; then info "✓ Successfully added OTEL instrumentation to Tomcat application: $app_name" else err "Failed to add OTEL instrumentation to Tomcat application: $app_name" @@ -1244,9 +1472,16 @@ list_instrumented_apps() { for app_info in "${tomcat_apps[@]}"; do IFS='|' read -r app_id pid catalina_home catalina_base app_name app_path <<< "$app_info" - local env_output - env_output=$(cat "/proc/$pid/environ" 2>/dev/null | tr '\0' '\n' | grep -E "OTEL_EXPORTER_OTLP_ENDPOINT" || echo "") - if [ -n "$env_output" ]; then + + # Check for WAR-specific instrumentation marker file + local war_marker_file="" + if [ -n "$catalina_base" ] && [ -d "$catalina_base" ]; then + war_marker_file="$catalina_base/webapps/$app_name/.otel-instrumented" + elif [ -n "$catalina_home" ] && [ -d "$catalina_home" ]; then + war_marker_file="$catalina_home/webapps/$app_name/.otel-instrumented" + fi + + if [ -f "$war_marker_file" ]; then info "✓ Tomcat App: $app_name (PID: $pid) (instrumented) - App ID: $app_id" instrumented_count=$((instrumented_count + 1)) else @@ -1525,7 +1760,7 @@ uninstrument_tomcat_app() { info "Removing OTEL instrumentation from Tomcat application: $app_id" # Parse the app_id to get components - IFS='-' read -r prefix pid suffix <<< "$app_id" + IFS='-' read -r prefix pid _ <<< "$app_id" if [ "$prefix" != "tomcat" ]; then err "Invalid Tomcat application ID format: $app_id" return 1 @@ -1550,72 +1785,89 @@ uninstrument_tomcat_app() { IFS='|' read -r found_app_id found_pid catalina_home catalina_base app_name app_path <<< "$app_info" - # Check if already uninstrumented - local env_output - env_output=$(cat "/proc/$found_pid/environ" 2>/dev/null | tr '\0' '\n' | grep -E "OTEL_EXPORTER_OTLP_ENDPOINT" || echo "") + # Check if already uninstrumented using WAR-specific marker file + local war_marker_file="" + if [ -n "$catalina_base" ] && [ -d "$catalina_base" ]; then + war_marker_file="$catalina_base/webapps/$app_name/.otel-instrumented" + elif [ -n "$catalina_home" ] && [ -d "$catalina_home" ]; then + war_marker_file="$catalina_home/webapps/$app_name/.otel-instrumented" + fi - if [ -z "$env_output" ]; then - info "Tomcat application $app_name is not instrumented" + if [ ! -f "$war_marker_file" ]; then + info "WAR application $app_name is not instrumented" return 0 fi - # Find and remove setenv.sh or restore backup - local setenv_file="" + # Remove WAR-specific OpenTelemetry configuration + local war_config_dir="" if [ -n "$catalina_base" ] && [ -d "$catalina_base" ]; then - setenv_file="$catalina_base/bin/setenv.sh" + war_config_dir="$catalina_base/webapps/$app_name/WEB-INF/classes" elif [ -n "$catalina_home" ] && [ -d "$catalina_home" ]; then - setenv_file="$catalina_home/bin/setenv.sh" + war_config_dir="$catalina_home/webapps/$app_name/WEB-INF/classes" fi - if [ -n "$setenv_file" ] && [ -f "$setenv_file" ]; then - # Check if this is our auto-generated setenv.sh - if grep -q "OpenTelemetry instrumentation for Tomcat (auto-generated)" "$setenv_file"; then - # Remove the auto-generated setenv.sh - rm -f "$setenv_file" - info "Removed auto-generated setenv.sh: $setenv_file" - - # Look for backup and restore it - local backup_dir="/tmp/tomcat-otel-backup-*" - for backup in $backup_dir; do - if [ -d "$backup" ] && [ -f "$backup/setenv.sh.backup" ]; then - cp "$backup/setenv.sh.backup" "$setenv_file" - chmod +x "$setenv_file" - info "Restored original setenv.sh from backup" - break - fi - done - else - # Remove OTEL-related lines from existing setenv.sh - local temp_file - temp_file=$(mktemp) - grep -v -E "OTEL_|javaagent.*opentelemetry|otel\.javaagent" "$setenv_file" > "$temp_file" - mv "$temp_file" "$setenv_file" - chmod +x "$setenv_file" - info "Removed OTEL configuration from setenv.sh: $setenv_file" + if [ -n "$war_config_dir" ] && [ -d "$war_config_dir" ]; then + # Remove WAR-specific environment file + local war_env_file="$war_config_dir/otel-war.env" + if [ -f "$war_env_file" ]; then + rm -f "$war_env_file" + info "Removed WAR-specific environment file: $war_env_file" + fi + + # Remove WAR-specific OpenTelemetry configuration file + local otel_config_file="$war_config_dir/otel.properties" + if [ -f "$otel_config_file" ]; then + rm -f "$otel_config_file" + info "Removed WAR-specific OpenTelemetry configuration: $otel_config_file" fi fi - # If this is a systemd service, also remove from service file - local service_name="" - for service in $(systemctl list-units --type=service --state=active --no-pager --no-legend | awk '{print $1}' | grep -E '\.(service)$'); do - local service_pid - service_pid=$(systemctl show "$service" --property=MainPID --no-pager 2>/dev/null | cut -d'=' -f2- || echo "") - if [ "$service_pid" = "$found_pid" ]; then - service_name="$service" - break + # Remove WAR-specific marker file + if [ -f "$war_marker_file" ]; then + rm -f "$war_marker_file" + info "Removed WAR instrumentation marker: $war_marker_file" + fi + + # Check if there are other WAR applications still instrumented on this Tomcat instance + local other_instrumented_war=false + local tomcat_apps + mapfile -t tomcat_apps < <(detect_tomcat_apps) + + for app_info in "${tomcat_apps[@]}"; do + IFS='|' read -r other_app_id other_pid other_catalina_home other_catalina_base other_app_name _ <<< "$app_info" + + # Skip the current app + if [ "$other_app_id" = "$app_id" ]; then + continue + fi + + # Check if this other app is on the same Tomcat instance + if [ "$other_pid" = "$found_pid" ]; then + # Check if this other app is still instrumented + local other_war_marker_file="" + if [ -n "$other_catalina_base" ] && [ -d "$other_catalina_base" ]; then + other_war_marker_file="$other_catalina_base/webapps/$other_app_name/.otel-instrumented" + elif [ -n "$other_catalina_home" ] && [ -d "$other_catalina_home" ]; then + other_war_marker_file="$other_catalina_home/webapps/$other_app_name/.otel-instrumented" + fi + + if [ -f "$other_war_marker_file" ]; then + other_instrumented_war=true + info "Found other instrumented WAR application: $other_app_name" + break + fi fi done - if [ -n "$service_name" ]; then - info "Found systemd service for Tomcat: $service_name" - uninstrument_service "$service_name" + # Only remove server-level configuration if no other WAR apps are instrumented + if [ "$other_instrumented_war" = false ]; then + info "No other WAR applications are instrumented on this Tomcat instance" + info "Server-level OpenTelemetry agent will remain active for future WAR instrumentation" + info "Note: The OpenTelemetry agent is still loaded at the server level" + info "This allows other WAR applications to be instrumented without server restart" else - # For standalone Tomcat, we need to restart it to pick up the changes - info "Tomcat is not managed by systemd, manual restart required" - info "Please restart Tomcat to remove OpenTelemetry instrumentation:" - info " - Stop: kill $found_pid" - info " - Start: $catalina_script start" - warn "Manual restart required for Tomcat application: $app_name" + info "Other WAR applications are still instrumented on this Tomcat instance" + info "Server-level OpenTelemetry agent will remain active" fi info "✓ Successfully removed OTEL instrumentation from Tomcat application: $app_name" @@ -1630,6 +1882,14 @@ install_binary() { info "Installing system-wide binary: $binary_name" + # Store current credentials if they are set + if [ -n "${MW_API_KEY:-}" ] || [ -n "${MW_TARGET:-}" ]; then + info "Storing current MW_API_KEY and MW_TARGET for future use" + store_middleware_credentials "${MW_API_KEY:-}" "${MW_TARGET:-}" + else + info "No MW_API_KEY or MW_TARGET provided, will use stored values or defaults" + fi + # Create a wrapper script that calls the original script cat > "$binary_path" </dev/null | cut -d'=' -f2- | tr -d '"' || echo "") + target=$(sudo grep "^MW_TARGET=" "$MW_CONFIG_FILE" 2>/dev/null | cut -d'=' -f2- | tr -d '"' || echo "") + fi + + if [ -n "${MW_API_KEY:-}" ] || [ -n "$api_key" ]; then + local key="${MW_API_KEY:-$api_key}" + info "MW_API_KEY: ${key:0:10}..." # Show only first 10 characters for security + else + info "MW_API_KEY: not set" + fi + if [ -n "${MW_TARGET:-}" ] || [ -n "$target" ]; then + local endpoint="${MW_TARGET:-$target}" + info "MW_TARGET: $endpoint" + else + info "MW_TARGET: not set" + fi + else + info "No stored credentials found at $MW_CONFIG_FILE" + fi +} # Function to remove OTEL instrumentation from all Java apps uninstrument_all() { info "Removing OTEL instrumentation from all Java applications..." @@ -1869,7 +2188,7 @@ if [ "$EUID" -ne 0 ]; then # Preserve all environment variables exec sudo -E "$0" "$@" ;; - help|-h|--help|list-instrumented|validate) + help|-h|--help|list-instrumented|validate|show-credentials) # These commands can run without sudo ;; *) @@ -2221,7 +2540,6 @@ Commands: update-services Update existing Java services with OTEL configuration update-docker Update existing Java Docker containers with OTEL wrapper update-tomcat Update existing Tomcat applications with OTEL configuration - a validate Validate that all Java services, containers, and Tomcat apps are properly instrumented instrument-all Do install-host + docker-wrapper (does not run patch-k8s by default) instrument-service Add OTEL instrumentation to specific service @@ -2233,6 +2551,8 @@ Commands: uninstrument-tomcat Remove OTEL instrumentation from specific Tomcat application list-instrumented List all currently instrumented Java apps (services, containers, and Tomcat) uninstall-binary Remove system-wide binary "mw-instrument" + update-credentials Update stored MW_API_KEY and MW_TARGET + show-credentials Show current stored credentials Environment Variables: OTEL_EXPORTER_OTLP_ENDPOINT OpenTelemetry endpoint (priority: OTEL_EXPORTER_OTLP_ENDPOINT > MW_TARGET > localhost:4317) @@ -2248,15 +2568,25 @@ Examples: sudo $0 install-binary mw-instrument instrument-all + # Store credentials during install-binary (will be reused automatically) + sudo MW_API_KEY=abc123 MW_TARGET=https://middleware.io:443 $0 install-binary + mw-instrument instrument-all # Uses stored credentials automatically + + # Update stored credentials + sudo $0 update-credentials "new-api-key" "https://new-endpoint:443" + + # Show current stored credentials + sudo $0 show-credentials + # Environment variable priority examples: sudo OTEL_EXPORTER_OTLP_ENDPOINT=https://your-endpoint:4317 $0 install-host # Uses explicit endpoint sudo MW_TARGET=https://middleware.io:443 $0 install-host # Uses MW_TARGET (fallback) - sudo $0 install-host # Uses localhost:4317 (final fallback) + sudo $0 install-host # Uses stored values or localhost:4317 (final fallback) # Authentication header priority examples: sudo OTEL_EXPORTER_OTLP_HEADERS="authorization=my-key" $0 install-host # Uses explicit headers sudo MW_API_KEY=abc123 $0 install-host # Uses MW_API_KEY (fallback) - sudo $0 install-host # Uses default headers + sudo $0 install-host # Uses stored values or default headers sudo $0 install-agent sudo OTEL_DIR=/opt/otel FORCE=1 $0 install-agent sudo $0 install-host @@ -2279,6 +2609,15 @@ EOF } main() { + # Load stored credentials for commands that need them (unless explicitly overridden) + case "${1:-}" in + install-binary|install-host|docker-wrapper|update-services|update-docker|update-tomcat|all|instrument-all|instrument-service|instrument-container|instrument-tomcat|validate) + if [ -z "${MW_TARGET:-}" ] && [ -z "${MW_API_KEY:-}" ]; then + load_middleware_credentials + fi + ;; + esac + case "${1:-}" in install-binary) install_binary ;; uninstall-binary) uninstall_binary ;; @@ -2374,6 +2713,9 @@ main() { exit 1 fi uninstrument_tomcat_app "$2" ;; + update-credentials) + update_credentials "$2" "$3" ;; + show-credentials) show_credentials ;; "") # Default behavior: install-binary if not installed, otherwise show help if [ -f "/usr/local/bin/mw-instrument" ]; then