diff --git a/.env b/.env deleted file mode 100644 index 5d98f9c..0000000 --- a/.env +++ /dev/null @@ -1,15 +0,0 @@ -# Wallarm Preflight Check Results -# Generated: 2026-04-21 15:47:43 -# Script: ./wallarm-ct-check.sh - -result=pass -os_name=darwin -os_version=25.3.0 -architecture=x86_64 -init_system=darwin -us_cloud_reachable=true -eu_cloud_reachable=true -registry_reachable=false -download_reachable=false -git_reachable=true - diff --git a/README.md b/README.md index 4a59276..16abc38 100644 --- a/README.md +++ b/README.md @@ -1,90 +1,95 @@ -# Wallarm Native Node Manager +# Wallarm Node Manager -Single-binary deployment and management for Wallarm Native Nodes (connector mode, no Docker). -One command to get started, one TUI to manage everything. +Single-binary deployment and management for Wallarm filtering nodes. +Interactive menu, multi-instance, zero runtime dependencies. ## Quick Start ```bash curl -fsSL "https://git.sechpoint.app/customer-engineering/wallarm/raw/branch/main/setup.sh" | bash -sudo /opt/wallarm/deploy +sudo /opt/fw/deploy ``` -That's it. The binary runs preflight checks, then opens an interactive TUI: -- **First run**: configuration wizard (cloud region, API token, node name, listen address) -- **Subsequent runs**: dashboard with node list, add/remove/configure actions - -## Features - -- **Single binary** — 2MB, zero runtime dependencies, works on any Linux -- **Interactive TUI** — bubbletea-powered forms and dashboard -- **Preflight checks** — runs on every start: system, network, cloud reachability, resources -- **Multi-node** — manage multiple Wallarm nodes on the same host via systemd -- **Remote tunnel** — `wallarm --tunnel` opens a reverse SSH tunnel over TLS:443 via Zoraxy -- **State persistence** — `~/.wallarm/state.json` tracks all deployments - ## Commands ``` -deploy Interactive TUI (wizard or dashboard) -deploy --tunnel Start reverse SSH tunnel to sechpoint.app -deploy --version Show version -deploy --help Show help +/opt/fw/deploy Interactive menu +/opt/fw/deploy --deploy-all Deploy all nodes from fw.conf +/opt/fw/deploy --version Show version ``` -## Dashboard +## Menu ``` -📊 Wallarm Dashboard -Type: native | Cloud: EU (api.wallarm.com) -────────────────────────────────────────────────── - -Nodes: - ● srv1 — running (0.0.0.0:8081) - ● srv2 — running (0.0.0.0:8082) - -Actions: - [a] Add node - [c] Configure - [r] Remove node - [t] Start tunnel +─── Main Menu ─── + [1] Deploy a node + [2] Edit a node + [3] Show status + [4] Remove a node + [5] Remote tunnel + [6] Dashboard (TUI) [q] Quit ``` +## Configuration + +Node configuration is stored in `/opt/fw/fw.conf`: + +```json +{ + "nodes": { + "srv1": { + "token": "...", + "cloud": "EU", + "port": "8081", + "upstream_ip": "10.1.0.10", + "upstream_port": "8081", + "labels": "group=srv1", + "mode": "monitoring" + } + } +} +``` + +Modes: `monitoring`, `safe_blocking`, `block`, `off`. + ## Architecture ``` -wallarm/ -├── cmd/wallarm/main.go Entrypoint: preflight → TUI -├── internal/ -│ ├── shared/ System detection, validation, connectivity -│ ├── preflight/ Mandatory checks on every start -│ ├── state/ ~/.wallarm/state.json persistence -│ ├── native/ Systemd units, installer, node management -│ ├── tunnel/ Reverse SSH over TLS:443 via Zoraxy -│ └── ui/ Bubbletea TUI (wizard + dashboard) -├── bin/ -│ └── wallarm-linux-amd64 Pre-built binary -├── deploy.sh One-command bootstrap -├── go.mod / go.sum -└── Makefile Cross-compile targets +cmd/deploy/main.go Entry point — menu, deploy, edit, remove +internal/ + native/ Node deployment, systemd, nginx + preflight/ System checks (14) + state/ /opt/fw/state.json persistence + tunnel/ Reverse SSH over TLS:443 + ui/ Bubbletea TUI (dashboard) + shared/ Validation, connectivity +setup.sh Bootstrap — clones repo, builds binary +Makefile Cross-compile targets ``` -## Building from Source +## Directory Layout -```bash -go build -ldflags "-s -w -X main.version=$(git describe --tags)" -o wallarm ./cmd/wallarm/ -make linux-amd64 # Cross-compile -make all # All targets +``` +/opt/fw/ +├── deploy Go binary +├── fw.conf Node configuration (JSON) +├── state.json Deployment state +├── {name}/wallarm/ Per-instance files +│ ├── nginx/ Instance NGINX +│ ├── modules/ Wallarm modules +│ ├── etc/ Wallarm config +│ └── ... +└── wallarm-aio.sh Cached Wallarm installer ``` -## Prerequisites +## Requirements -- Linux (systemd required) +- Linux with systemd - x86_64 or aarch64 - 2GB+ RAM, 10GB+ disk -- Outbound connectivity to Wallarm cloud (US/EU) +- Outbound to api.wallarm.com (EU) or us1.api.wallarm.com (US) -## License +## Remote Assistance -Proprietary — see repository for terms. +See [JUMP_SERVER.md](JUMP_SERVER.md) for jump server setup. diff --git a/changelog.md b/changelog.md deleted file mode 100644 index 76cd4fa..0000000 --- a/changelog.md +++ /dev/null @@ -1,86 +0,0 @@ -# Changelog - -All notable changes to this project will be documented in this file. - -The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/), -and this project adheres to date-based versioning (YYYY-MM.x). - -## [2026-08.1] - 2026-08-01 -### Fixed -- **setup.sh interactive prompt broken under `curl ... | bash`**: the deployment-type prompt and overwrite confirmation read from stdin, which is the script pipe (not the terminal) when piped to bash — the prompt was silently skipped and only Docker scripts were downloaded. setup.sh is now **non-interactive by default and downloads BOTH deployment types** (`docker/` + `native/`), so the native option is always available. Use `DEPLOYMENT_TYPE=docker|native` to download only one type. - -### Added -- **Native deployment**: Wallarm filtering node can now be deployed directly on the OS **without Docker** via the unified manager `native/wallarm-native.sh` (Wallarm Native Node, go-node, `connector-server` mode) - - `--preflight` checks (root, systemd, architecture, required commands, installer + Wallarm cloud connectivity, disk/memory, listen-port availability); auto-run before `--install` - - Interactive parallel multi-node installation with per-node systemd template units (`wallarm-node@.service`) - - `--config` (address/token/labels, safe env rewrite), `--remove`, `--status [NODE]` - - All-in-one installer from `repo.wallarm.com` (overridable via `WALLARM_INSTALLER_URL`/`WALLARM_INSTALLER_ARCH`) -- **Shared library**: `common/wallarm-lib.sh` extracted and reused by both deployment types - - Colors, logging (`log_message`, `fail_with_remediation`), early error handler - - System detection (OS/arch/init), network connectivity tests - - Preflight `.env` parsing (`load_env_file`), cloud region selection (`select_cloud_region`) - - Validation helpers (IP, CIDR, port), artifact download + checksum verification - -### Changed -- **Repository structure** now separates deployment types: - - `docker/` – all Docker-based scripts moved here (`git mv`, history preserved) - - `docker/binaries/` and `docker/images/` – Docker artifacts moved into the Docker tree - - `native/` – native (no-Docker) deployment, containing only the unified `wallarm-native.sh` - - `common/` – shared library -- **Removed** the `native/wallarm-ct-*.sh` scripts (NGINX-module based native deployment) so the native deployment is represented solely by the unified `wallarm-native.sh`; the `wallarm-ct-*` family is now Docker-only -- **Artifact URLs** updated to the `docker/` prefix (`/docker/binaries/...`, `/docker/images/...`) -- **Docker scripts** refactored to source `common/wallarm-lib.sh` (removed duplicated helper functions; behavior preserved) -- **setup.sh** downloads the shared library and scripts per deployment type into `docker/`/`native/` (native = `wallarm-native.sh`); supports `DEPLOYMENT_TYPE=docker|native` to download only one type -- **README.md** rewritten to document both deployment types, the new structure, and the unified native manager - -### Notes -- The `wallarm-ct-*` script family is Docker-only; native deployment uses `wallarm-native.sh` -- Native multi-node is supported via per-node systemd template units -- Docker deployment behavior is unchanged apart from the new directory layout - -## [2026-04.1] - 2026-04-21 -### Added -- Initial changelog file with versioning schema -- Date-based versioning system (YYYY-MM.x) - -### Changed -- **Variable renaming**: All `GITLAB_*` variables renamed to `GIT_*` prefix - - `GITLAB_BASE_URL` → `GIT_BASE_URL` - - `GITLAB_RAW_URL` → `GIT_RAW_URL` (with updated path) - - `GITLAB_DOCKER_BINARY_URL` → `GIT_DOCKER_BINARY_URL` - - `GITLAB_DOCKER_CHECKSUM_URL` → `GIT_DOCKER_CHECKSUM_URL` - - `GITLAB_WALLARM_IMAGE_URL` → `GIT_WALLARM_IMAGE_URL` - - `GITLAB_WALLARM_CHECKSUM_URL` → `GIT_WALLARM_CHECKSUM_URL` - - `GITLAB_REACHABLE` → `GIT_REACHABLE` -- **URL structure**: Updated `GIT_RAW_URL` from `/-/raw/main` to `/raw/branch/main` path (corrected for download compatibility) -- **Terminology**: Replaced all "GitLab" references in comments and log messages with "Git Repositorys" -- **Documentation**: Updated README.md to reflect new terminology -- **URL correction**: Corrected setup.sh download URL in README.md back to `/raw/branch/main/` pattern for download compatibility -- **Branding**: Removed all Forgejo references from codebase and documentation for neutrality -- **Fallback chains**: Simplified from three-tier to two-tier approach - - Docker binary: `Git Repositorys → local dir → current dir` (removed `→ internal proxy`) - - Wallarm image: `Git Repositorys → local dir → current dir` (removed `→ internal registry`) - -### Removed -- Internal registry fallback options and related variables: - - `INTERNAL_DOCKER_REGISTRY` and `INTERNAL_DOCKER_DOWNLOAD` - - `DOCKER_REGISTRY_HOST` and `DOCKER_DOWNLOAD_HOST` - - `DOCKER_STATIC_BASE_URL` and `WALLARM_IMAGE_SOURCE` -- Connectivity tests for internal registry/download servers -- Remediation instructions mentioning internal fallback options -- All references to internal proxy/registry in error messages - -### Technical Details -- **Commits**: - - `3158ee7` (chore: refactor git references and remove internal registry fallback) - - `509909d` (chore: remove Forgejo references and fix setup URL) -- **Files modified**: 4 files changed, additional modifications - - `README.md` - Documentation updates and URL fixes - - `setup.sh` - URL base update and Forgejo reference removal - - `wallarm-ct-check.sh` - Variable renaming and logic simplification - - `wallarm-ct-deploy.sh` - Variable renaming and fallback chain updates - -### Notes -- Scripts maintain backward compatibility with existing artifact URLs -- Simplified error handling focuses on primary Git Repositorys source and local files -- No functional changes to core deployment logic \ No newline at end of file diff --git a/common/wallarm-lib.sh b/common/wallarm-lib.sh deleted file mode 100755 index b208b7a..0000000 --- a/common/wallarm-lib.sh +++ /dev/null @@ -1,530 +0,0 @@ -#!/bin/bash -# ============================================================================== -# WALLARM COMMON LIBRARY - shared functions for docker/ and native/ deployment -# ============================================================================== -# Purpose: Single source of truth for functionality shared by both deployment -# types (Docker container vs native NGINX install). -# Usage: Scripts source this file AFTER setting `set -euo pipefail` and before -# defining their own functions: -# source "$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)/../common/wallarm-lib.sh" -# The library does NOT set the error trap itself; each script owns its -# error handling configuration. -# ============================================================================== - -# ------------------------------------------------------------------------------ -# COLOR DEFINITIONS (for better UX) -# ------------------------------------------------------------------------------ -RED='\033[0;31m' -GREEN='\033[0;32m' -YELLOW='\033[1;33m' -BLUE='\033[1;34m' -CYAN='\033[0;36m' -MAGENTA='\033[0;35m' -BOLD='\033[1m' -NC='\033[0m' # No Color - -# ------------------------------------------------------------------------------ -# SSL SECURITY SETTINGS -# WALLARM_INSECURE_SSL=1 disables SSL certificate validation (for self-signed -# certs). Kept as a default of 1 for backward compatibility with existing usage. -# ------------------------------------------------------------------------------ -INSECURE_SSL="${WALLARM_INSECURE_SSL:-1}" -if [ "$INSECURE_SSL" = "1" ]; then - CURL_INSECURE_FLAG="-k" -else - CURL_INSECURE_FLAG="" -fi - -# ------------------------------------------------------------------------------ -# EARLY ERROR HANDLER -# Use with: trap early_error_handler ERR -# Handles failures before log_message is available (or when logging is not set). -# ------------------------------------------------------------------------------ -early_error_handler() { - echo -e "${RED}${BOLD}[ERROR]${NC} Script failed at line $LINENO. Command: $BASH_COMMAND" >&2 - exit 1 -} - -# ------------------------------------------------------------------------------ -# LOGGING -# ------------------------------------------------------------------------------ - -# Log a message to stderr (colored) and to $LOG_FILE (if set). -log_message() { - local level="$1" - local message="$2" - local timestamp - timestamp=$(date '+%Y-%m-%d %H:%M:%S') - - local color="$NC" - case "$level" in - "INFO") color="${BLUE}" ;; - "SUCCESS") color="${GREEN}" ;; - "WARNING") color="${YELLOW}" ;; - "ERROR") color="${RED}" ;; - "DEBUG") color="${CYAN}" ;; - esac - - echo -e "${color}[${timestamp}] ${level}: ${message}${NC}" >&2 - if [ -n "${LOG_FILE:-}" ]; then - echo "[${timestamp}] ${level}: ${message}" >> "$LOG_FILE" - fi -} - -# Log an ERROR, print a remediation banner, and exit non-zero. -fail_with_remediation() { - local error_msg="$1" - local remediation="$2" - - log_message "ERROR" "$error_msg" - echo -e "\n${RED}${BOLD}╔══════════════════════════════════════════════════════════════╗${NC}" - echo -e "${RED}${BOLD}║ DEPLOYMENT FAILED ║${NC}" - echo -e "${RED}${BOLD}╚══════════════════════════════════════════════════════════════╝${NC}" - echo -e "\n${YELLOW}${BOLD}Root Cause:${NC} $error_msg" - echo -e "\n${YELLOW}${BOLD}How to Fix:${NC}" - echo -e "$remediation" - echo -e "\n${YELLOW}Check the full log for details:${NC} ${LOG_FILE:-stdout}" - exit 1 -} - -# ------------------------------------------------------------------------------ -# MISC HELPERS -# ------------------------------------------------------------------------------ - -# Extract hostname from a URL, stripping protocol and credentials for safe logging. -extract_hostname_from_url() { - local url="$1" - local hostpart="${url#*://}" - hostpart="${hostpart#*@}" - hostpart="${hostpart%%[:/]*}" - echo "$hostpart" -} - -# Check whether a command exists (respects PATH + common system directories). -command_exists() { - local cmd="$1" - if command -v "$cmd" >/dev/null 2>&1; then - return 0 - fi - local system_dirs=("/usr/sbin" "/sbin" "/usr/local/sbin" "/usr/bin" "/bin" "/usr/local/bin") - for dir in "${system_dirs[@]}"; do - if [ -x "$dir/$cmd" ]; then - return 0 - fi - done - return 1 -} - -# Validate an IPv4 address (basic format + octet range check). -validate_ip_address() { - local ip="$1" - - if [[ ! "$ip" =~ ^[0-9]{1,3}\.[0-9]{1,3}\.[0-9]{1,3}\.[0-9]{1,3}$ ]]; then - return 1 - fi - - IFS='.' read -r i1 i2 i3 i4 <<< "$ip" - if [ "$i1" -gt 255 ] || [ "$i2" -gt 255 ] || [ "$i3" -gt 255 ] || [ "$i4" -gt 255 ]; then - return 1 - fi - - return 0 -} - -# Validate an IP or CIDR entry (IPv4 with optional /prefix). Returns 0 if valid. -validate_ip_or_cidr() { - local entry="$1" - - if [[ ! "$entry" =~ ^[0-9]{1,3}\.[0-9]{1,3}\.[0-9]{1,3}\.[0-9]{1,3}(/[0-9]{1,2})?$ ]]; then - return 1 - fi - - IFS='/' read -r ip cidr <<< "$entry" - IFS='.' read -r o1 o2 o3 o4 <<< "$ip" - if [ "$o1" -gt 255 ] || [ "$o2" -gt 255 ] || [ "$o3" -gt 255 ] || [ "$o4" -gt 255 ]; then - return 1 - fi - if [ -n "$cidr" ] && { [ "$cidr" -lt 0 ] || [ "$cidr" -gt 32 ]; }; then - return 1 - fi - - return 0 -} - -# Check if a TCP/UDP port is currently in use. Returns 0 when available. -check_port_available() { - local port="$1" - local protocol="${2:-tcp}" - - log_message "DEBUG" "Checking port $port/$protocol availability..." - - if command -v ss >/dev/null 2>&1; then - if ss -"${protocol:0:1}"ln | grep -q ":$port "; then - return 1 # Port in use - fi - elif command -v netstat >/dev/null 2>&1; then - if netstat -tulpn 2>/dev/null | grep -E ":$port\s" >/dev/null 2>&1; then - return 1 # Port in use - fi - else - log_message "WARNING" "Neither ss nor netstat available, cannot check port $port" - fi - - return 0 # Port available (or cannot check) -} - -# ------------------------------------------------------------------------------ -# SYSTEM DETECTION -# ------------------------------------------------------------------------------ - -# Detect OS name and version. Prints "name:version". -detect_os_and_version() { - log_message "INFO" "Detecting OS and version..." - - local os_name="" - local os_version="" - - if [ -f /etc/os-release ]; then - . /etc/os-release - os_name="$ID" - os_version="$VERSION_ID" - elif [ -f /etc/redhat-release ]; then - os_name="rhel" - os_version=$(sed -e 's/.*release \([0-9]\+\)\..*/\1/' /etc/redhat-release) - elif [ -f /etc/alpine-release ]; then - os_name="alpine" - os_version=$(cat /etc/alpine-release) - else - os_name=$(uname -s | tr '[:upper:]' '[:lower:]') - os_version=$(uname -r) - fi - - os_name="${os_name//[$'\t\r\n']/}" - os_version="${os_version//[$'\t\r\n']/}" - - case "$os_name" in - "ubuntu"|"debian"|"centos"|"rhel"|"alpine"|"amzn"|"ol"|"rocky"|"almalinux") - log_message "SUCCESS" "OS detected: $os_name $os_version (supported)" - ;; - *) - log_message "WARNING" "OS '$os_name' not explicitly tested but may work" - ;; - esac - - echo "$os_name:$os_version" -} - -# Detect architecture. Prints a normalized value (x86_64/aarch64/armhf/unknown). -detect_architecture() { - log_message "INFO" "Detecting system architecture..." - - local arch - arch=$(uname -m) - local docker_arch="" - - case "$arch" in - x86_64|x64|amd64) - docker_arch="x86_64" - log_message "SUCCESS" "Architecture: x86_64 (Intel/AMD 64-bit)" - ;; - aarch64|arm64) - docker_arch="aarch64" - log_message "SUCCESS" "Architecture: aarch64 (ARM 64-bit)" - ;; - armv7l|armhf) - docker_arch="armhf" - log_message "SUCCESS" "Architecture: armhf (ARM 32-bit)" - ;; - *) - log_message "ERROR" "Unsupported architecture: $arch" - docker_arch="unknown" - ;; - esac - - echo "$docker_arch" -} - -# Detect the init system. Prints one of systemd/openrc/sysvinit/upstart/unknown. -detect_init_system() { - log_message "INFO" "Detecting init system..." - - local init_system="unknown" - - if [ "$(uname -s)" = "Darwin" ]; then - init_system="darwin" - log_message "SUCCESS" "Init system: darwin (macOS)" - elif command -v systemctl >/dev/null 2>&1 && systemctl --version >/dev/null 2>&1; then - init_system="systemd" - log_message "SUCCESS" "Init system: systemd" - elif { [ -d /etc/init.d ] && [ -x /sbin/initctl ]; } || [ -x /sbin/init ]; then - init_system="sysvinit" - log_message "SUCCESS" "Init system: sysvinit" - elif [ -d /etc/rc.d ] && [ -x /sbin/rc-service ]; then - init_system="openrc" - log_message "SUCCESS" "Init system: openrc (Alpine)" - elif [ -x /sbin/upstart ]; then - init_system="upstart" - log_message "SUCCESS" "Init system: upstart" - else - log_message "WARNING" "Could not determine init system" - fi - - echo "$init_system" -} - -# ------------------------------------------------------------------------------ -# NETWORK CONNECTIVITY -# ------------------------------------------------------------------------------ - -# Test connectivity to a host/URL. Returns 0 when reachable. -test_connectivity() { - local host="$1" - local description="$2" - local timeout="${3:-10}" - - local display_host - display_host=$(extract_hostname_from_url "$host") - log_message "INFO" "Testing connectivity to $description ($display_host)..." - - local url="$host" - if [[ ! "$host" =~ ^https?:// ]]; then - url="https://$host" - fi - - if curl -sL $CURL_INSECURE_FLAG --connect-timeout "$timeout" "$url" >/dev/null 2>&1; then - log_message "SUCCESS" "$description is reachable" - return 0 - else - log_message "ERROR" "$description is NOT reachable" - return 1 - fi -} - -# Test a set of cloud endpoints. Prints "true" if all reachable, else "false". -test_cloud_endpoints() { - local cloud_name="$1" - shift - local endpoints=("$@") - - log_message "INFO" "Testing $cloud_name cloud endpoints..." - - local all_reachable=true - local endpoint - for endpoint in "${endpoints[@]}"; do - if ! test_connectivity "$endpoint" "$cloud_name cloud endpoint $endpoint"; then - all_reachable=false - fi - done - - if [ "$all_reachable" = "true" ]; then - log_message "SUCCESS" "All $cloud_name cloud endpoints reachable" - echo "true" - else - log_message "WARNING" "Some $cloud_name cloud endpoints unreachable" - echo "false" - fi -} - -# ------------------------------------------------------------------------------ -# ENVIRONMENT FILE HANDLING -# ------------------------------------------------------------------------------ - -# Load a preflight .env file into global variables. Returns 1 if file missing. -load_env_file() { - local env_file="${1:-$ENV_FILE}" - - if [ ! -f "$env_file" ]; then - log_message "ERROR" "Environment file not found: $env_file" - return 1 - fi - - local key value - while IFS='=' read -r key value; do - [[ "$key" =~ ^#.*$ ]] && continue - [[ -z "$key" ]] && continue - - value="${value%\"}" - value="${value#\"}" - - case "$key" in - result) CHECK_RESULT="$value" ;; - os_name) OS_NAME="$value" ;; - os_version) OS_VERSION="$value" ;; - architecture) ARCHITECTURE="$value" ;; - init_system) INIT_SYSTEM="$value" ;; - us_cloud_reachable) US_CLOUD_REACHABLE="$value" ;; - eu_cloud_reachable) EU_CLOUD_REACHABLE="$value" ;; - registry_reachable) REGISTRY_REACHABLE="$value" ;; - download_reachable) DOWNLOAD_REACHABLE="$value" ;; - git_reachable) GIT_REACHABLE="$value" ;; - installer_reachable) INSTALLER_REACHABLE="$value" ;; - esac - done < "$env_file" - - log_message "SUCCESS" "Loaded preflight results from $env_file" - return 0 -} - -# ------------------------------------------------------------------------------ -# CLOUD REGION SELECTION -# Sets CLOUD_REGION and API_HOST based on reachability from the preflight check. -# ------------------------------------------------------------------------------ -select_cloud_region() { - log_message "INFO" "Selecting Wallarm Cloud region..." - - echo -e "\n${CYAN}${BOLD}Wallarm Cloud Region Selection:${NC}" - - local available_options=() - - if [ "${US_CLOUD_REACHABLE:-false}" = "true" ]; then - echo -e "1. ${YELLOW}US Cloud${NC} (us1.api.wallarm.com) - For US-based deployments" - available_options+=("1" "US") - fi - - if [ "${EU_CLOUD_REACHABLE:-false}" = "true" ]; then - echo -e "2. ${YELLOW}EU Cloud${NC} (api.wallarm.com) - For EU-based deployments" - available_options+=("2" "EU") - fi - - if [ ${#available_options[@]} -eq 0 ]; then - fail_with_remediation "No cloud regions available" \ - "Preflight check showed no reachable cloud regions. -1. Check network connectivity to Wallarm endpoints -2. Run the preflight check again -3. Contact network administrator if behind firewall" - fi - - local pattern - pattern="^($(IFS='|'; echo "${available_options[*]}"))$" - - local cloud_choice="" - while [[ ! "$cloud_choice" =~ $pattern ]]; do - if [ ${#available_options[@]} -eq 2 ]; then - if [ "${US_CLOUD_REACHABLE:-false}" = "true" ]; then - cloud_choice="US" - break - else - cloud_choice="EU" - break - fi - fi - - read -r -p "$(echo -e "${YELLOW}Enter choice [1/US or 2/EU]: ${NC}")" cloud_choice - cloud_choice=$(echo "$cloud_choice" | tr '[:lower:]' '[:upper:]') - - case "$cloud_choice" in - 1|"US") - if [ "${US_CLOUD_REACHABLE:-false}" = "true" ]; then - CLOUD_REGION="US" - API_HOST="us1.api.wallarm.com" - log_message "INFO" "Selected US Cloud" - else - echo -e "${RED}US Cloud is not reachable (per preflight check)${NC}" - cloud_choice="" - fi - ;; - 2|"EU") - if [ "${EU_CLOUD_REACHABLE:-false}" = "true" ]; then - CLOUD_REGION="EU" - API_HOST="api.wallarm.com" - log_message "INFO" "Selected EU Cloud" - else - echo -e "${RED}EU Cloud is not reachable (per preflight check)${NC}" - cloud_choice="" - fi - ;; - *) - if [ -n "$cloud_choice" ]; then - echo -e "${RED}Invalid choice. Select from available options above.${NC}" - fi - ;; - esac - done - - log_message "SUCCESS" "Cloud region selected: $CLOUD_REGION ($API_HOST)" -} - -# ------------------------------------------------------------------------------ -# ARTIFACT DOWNLOAD (Git Repositorys primary source) -# ------------------------------------------------------------------------------ - -# Download a file from Git Repositorys. Returns 0 on success. -download_from_git() { - local url="$1" - local output_path="$2" - local description="$3" - - log_message "INFO" "Attempting to download $description from Git Repositorys..." - log_message "DEBUG" "URL: $url" - log_message "DEBUG" "Output path: $output_path" - - if curl -fL "$CURL_INSECURE_FLAG" --connect-timeout 30 --max-time 300 --progress-bar "$url" -o "$output_path"; then - log_message "SUCCESS" "Downloaded $description to $output_path" - return 0 - else - local curl_exit=$? - log_message "ERROR" "Failed to download $description from Git Repositorys (curl exit: $curl_exit)" - if [ -f "$output_path" ]; then - rm -f "$output_path" - log_message "DEBUG" "Removed partial download: $output_path" - fi - return 1 - fi -} - -# Verify a file against a checksum file or URL. Returns 0 on success; -# skips verification (returns 0) when the checksum cannot be obtained. -verify_checksum() { - local file_path="$1" - local checksum_file_or_url="$2" - local description="$3" - - log_message "INFO" "Verifying $description checksum..." - - local checksum_file="" - if [[ "$checksum_file_or_url" =~ ^https?:// ]]; then - checksum_file="/tmp/$(basename "$checksum_file_or_url")" - log_message "DEBUG" "Downloading checksum from URL: $checksum_file_or_url" - if ! curl -fL "$CURL_INSECURE_FLAG" --connect-timeout 10 --max-time 30 -s "$checksum_file_or_url" -o "$checksum_file"; then - log_message "WARNING" "Could not download checksum file, skipping verification" - return 0 - fi - else - checksum_file="$checksum_file_or_url" - fi - - if [ ! -f "$checksum_file" ]; then - log_message "WARNING" "Checksum file not found: $checksum_file, skipping verification" - return 0 - fi - - local expected_checksum - expected_checksum=$(awk '{print $1}' "$checksum_file" 2>/dev/null) - if [ -z "$expected_checksum" ]; then - log_message "WARNING" "Could not read checksum from $checksum_file, skipping verification" - return 0 - fi - - log_message "DEBUG" "Computing SHA256 checksum of $file_path..." - local actual_checksum - if command -v sha256sum >/dev/null 2>&1; then - actual_checksum=$(sha256sum "$file_path" | awk '{print $1}') - elif command -v shasum >/dev/null 2>&1; then - actual_checksum=$(shasum -a 256 "$file_path" | awk '{print $1}') - else - log_message "WARNING" "sha256sum or shasum not available, skipping checksum verification" - return 0 - fi - - if [ "$expected_checksum" = "$actual_checksum" ]; then - log_message "SUCCESS" "$description checksum verified successfully" - return 0 - else - log_message "ERROR" "$description checksum verification FAILED" - log_message "DEBUG" "Expected: $expected_checksum" - log_message "DEBUG" "Actual: $actual_checksum" - rm -f "$file_path" - log_message "INFO" "Removed corrupted file: $file_path" - return 1 - fi -} diff --git a/docker/binaries/README.md b/docker/binaries/README.md deleted file mode 100644 index bfe08a7..0000000 --- a/docker/binaries/README.md +++ /dev/null @@ -1,16 +0,0 @@ -# Docker Static Binaries - -This directory contains Docker static binaries for offline installation. - -- `docker-29.2.1.tgz`: Docker 29.2.1 static binary for x86_64 -- `docker-29.2.1.tgz.sha256`: SHA256 checksum for verification - -## Usage -```bash -# Verify integrity -sha256sum -c docker-29.2.1.tgz.sha256 - -# Extract and install -tar xzvf docker-29.2.1.tgz -sudo cp docker/* /usr/bin/ -``` diff --git a/docker/binaries/docker-29.2.1.tgz b/docker/binaries/docker-29.2.1.tgz deleted file mode 100644 index a07c074..0000000 Binary files a/docker/binaries/docker-29.2.1.tgz and /dev/null differ diff --git a/docker/binaries/docker-29.2.1.tgz.sha256 b/docker/binaries/docker-29.2.1.tgz.sha256 deleted file mode 100644 index f56820a..0000000 --- a/docker/binaries/docker-29.2.1.tgz.sha256 +++ /dev/null @@ -1 +0,0 @@ -995b1d0b51e96d551a3b49c552c0170bc6ce9f8b9e0866b8c15bbc67d1cf93a3 binaries/docker-29.2.1.tgz diff --git a/docker/images/README.md b/docker/images/README.md deleted file mode 100644 index 5089ea4..0000000 --- a/docker/images/README.md +++ /dev/null @@ -1,15 +0,0 @@ -# Wallarm Docker Images - -This directory contains Wallarm node Docker images for offline deployment. - -- `wallarm-node-6.11.0-rc1.tar.gz`: Wallarm node version 6.11.0-rc1 -- `wallarm-node-6.11.0-rc1.tar.gz.sha256`: SHA256 checksum for verification - -## Usage -```bash -# Verify integrity -sha256sum -c wallarm-node-6.11.0-rc1.tar.gz.sha256 - -# Load into Docker -gunzip -c wallarm-node-6.11.0-rc1.tar.gz | docker load -``` diff --git a/docker/images/wallarm-node-6.11.0-rc1.tar.gz b/docker/images/wallarm-node-6.11.0-rc1.tar.gz deleted file mode 100644 index e78bf40..0000000 Binary files a/docker/images/wallarm-node-6.11.0-rc1.tar.gz and /dev/null differ diff --git a/docker/images/wallarm-node-6.11.0-rc1.tar.gz.sha256 b/docker/images/wallarm-node-6.11.0-rc1.tar.gz.sha256 deleted file mode 100644 index 09c5396..0000000 --- a/docker/images/wallarm-node-6.11.0-rc1.tar.gz.sha256 +++ /dev/null @@ -1 +0,0 @@ -ab4d9c6d2fdde6a855a0a1dc2db8cce6168926a39a45d715dc3dcf2ff0de85c5 images/wallarm-node-6.11.0-rc1.tar.gz diff --git a/docker/wallarm-ct-check.sh b/docker/wallarm-ct-check.sh deleted file mode 100755 index 53ad35a..0000000 --- a/docker/wallarm-ct-check.sh +++ /dev/null @@ -1,549 +0,0 @@ -#!/bin/bash -# ============================================================================== -# WALLARM PREFLIGHT CHECK SCRIPT - V1.3 (Docker deployment) -# ============================================================================== -# Purpose: Validate system readiness for Wallarm Docker deployment -# Features: -# - Non-interactive system validation (sudo, OS, architecture, init system) -# - Network connectivity testing (US/EU cloud) -# - Docker artifact source validation (Git Repositorys / local binaries/images) -# - Outputs results to .env file for deployment script -# - DAU-friendly error messages with remediation -# ============================================================================== - -# Script location and shared library (colors, logging, validation, detection, connectivity) -SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)" -# shellcheck source=./wallarm-lib.sh -source "$SCRIPT_DIR/wallarm-lib.sh" - -# Strict error handling -set -euo pipefail -trap early_error_handler ERR - -# Configuration -ENV_FILE=".env" -LOG_FILE="${HOME:-.}/logs/wallarm-check.log" - -# Git Repositorys artifact URLs (primary source) - Docker deployment artifacts -GIT_BASE_URL="https://git.sechpoint.app/customer-engineering/wallarm" -GIT_RAW_URL="https://git.sechpoint.app/customer-engineering/wallarm/raw/branch/main" -GIT_DOCKER_BINARY_URL="${GIT_RAW_URL}/docker/binaries/docker-29.2.1.tgz" -GIT_WALLARM_IMAGE_URL="${GIT_RAW_URL}/docker/images/wallarm-node-6.11.0-rc1.tar.gz" - -# Local artifact directories (relative to script location) -LOCAL_BINARY_DIR="${SCRIPT_DIR}/binaries" -LOCAL_IMAGE_DIR="${SCRIPT_DIR}/images" - -# Cloud endpoints (from Wallarm documentation) -EU_DATA_NODES=("api.wallarm.com" "node-data0.eu1.wallarm.com" "node-data1.eu1.wallarm.com") -US_DATA_NODES=("us1.api.wallarm.com" "node-data0.us1.wallarm.com" "node-data1.us1.wallarm.com") - -# Global result tracking -CHECK_RESULT="pass" -CHECK_ERRORS=() -GIT_REACHABLE="false" - -# ============================================================================== -# RESULT TRACKING & ENV FILE -# ============================================================================== - -add_error() { - local error_msg="$1" - CHECK_ERRORS+=("$error_msg") - CHECK_RESULT="fail" - log_message "ERROR" "$error_msg" -} - -write_env_file() { - local os_name="$1" - local os_version="$2" - local architecture="$3" - local init_system="$4" - local us_cloud_reachable="$5" - local eu_cloud_reachable="$6" - local registry_reachable="$7" - local download_reachable="$8" - local git_reachable="${9:-false}" - - cat > "$ENV_FILE" << EOF -# Wallarm Preflight Check Results -# Generated: $(date '+%Y-%m-%d %H:%M:%S') -# Script: $0 - -result=$CHECK_RESULT -os_name=$os_name -os_version=$os_version -architecture=$architecture -init_system=$init_system -us_cloud_reachable=$us_cloud_reachable -eu_cloud_reachable=$eu_cloud_reachable -registry_reachable=$registry_reachable -download_reachable=$download_reachable -git_reachable=$git_reachable - -EOF - - if [ ${#CHECK_ERRORS[@]} -gt 0 ]; then - echo "# Errors:" >> "$ENV_FILE" - for i in "${!CHECK_ERRORS[@]}"; do - echo "error_$i=\"${CHECK_ERRORS[$i]}\"" >> "$ENV_FILE" - done - fi - - log_message "SUCCESS" "Check results written to $ENV_FILE" -} - -# ============================================================================== -# PRE-FLIGHT VALIDATION FUNCTIONS -# ============================================================================== - -validate_sudo_access() { - log_message "INFO" "Validating sudo access..." - - local os_name - os_name=$(uname -s | tr '[:upper:]' '[:lower:]') - - if ! command -v sudo >/dev/null 2>&1; then - add_error "sudo command not found" - return 1 - fi - - if [ "$os_name" = "darwin" ]; then - log_message "WARNING" "macOS detected: sudo authentication test skipped (may prompt during deployment)" - log_message "INFO" "Note: macOS is not a supported deployment target. This check is for Linux servers." - return 0 - fi - - if ! sudo -v; then - add_error "sudo authentication failed" - return 1 - fi - - log_message "SUCCESS" "Sudo access validated" - return 0 -} - -validate_required_commands() { - log_message "INFO" "Validating required system commands..." - - local missing_commands=() - - local os_name - os_name=$(uname -s | tr '[:upper:]' '[:lower:]') - - # Core commands required for both check and deployment scripts - local core_commands=( - "tar" # Required for extracting Docker binaries in deployment - "curl" # Required for connectivity testing - "grep" # Used extensively - "cut" # Used for parsing output - "tr" # Used for text transformations - "sed" # Used for text processing - "head" # Used for limiting output - "tail" # Used for limiting output - "ls" # Used for file listing - "date" # Used for logging timestamps - "mkdir" # Used for creating directories - "chmod" # Used for permission changes - "stat" # Used for file information (required for file size checks) - "tee" # Required for writing configuration files - "cp" # Required for copying Docker binaries - "rm" # Required for cleanup operations - ) - - # Linux-specific commands (not available on macOS) - if [ "$os_name" != "darwin" ]; then - core_commands+=( - "getent" # Required for checking group existence - "groupadd" # Required for creating docker group (sudo) - "usermod" # Required for adding user to docker group (sudo) - "iptables" # Required for Docker network bridge creation (Docker static binaries v1.4+) - ) - fi - - # Check each core command (command_exists comes from common library) - local cmd - for cmd in "${core_commands[@]}"; do - if ! command_exists "$cmd"; then - missing_commands+=("$cmd") - fi - done - - # Check for port checking utility (ss or netstat) - if [ "$os_name" != "darwin" ]; then - if ! command_exists ss && ! command_exists netstat; then - missing_commands+=("ss or netstat") - fi - fi - - # Detect init system and validate its control command - if [ "$os_name" != "darwin" ]; then - local init_system - init_system=$(detect_init_system) - - case "$init_system" in - "systemd") - if ! command_exists systemctl; then - missing_commands+=("systemctl") - fi - ;; - "openrc") - if ! command_exists rc-service; then - missing_commands+=("rc-service") - fi - ;; - "sysvinit") - if ! command_exists service; then - missing_commands+=("service") - fi - ;; - "upstart") - if ! command_exists initctl; then - missing_commands+=("initctl") - fi - ;; - *) - log_message "WARNING" "Unknown init system '$init_system', cannot validate init command" - ;; - esac - else - log_message "INFO" "Skipping init system validation on macOS (not a deployment target)" - fi - - if [ ${#missing_commands[@]} -gt 0 ]; then - local missing_list - missing_list=$(IFS=', '; echo "${missing_commands[*]}") - add_error "Missing required commands: $missing_list" - log_message "ERROR" "Please install missing commands and run the check again." - return 1 - fi - - # Special check: iptables version must be 1.4 or higher for Docker static binaries - if [ "$os_name" != "darwin" ]; then - log_message "INFO" "Checking iptables version (requires 1.4+ for Docker)..." - if command_exists iptables; then - local iptables_version - iptables_version=$(iptables --version 2>/dev/null | head -1 | grep -o '[0-9]\+\.[0-9]\+' | head -1) - if [ -n "$iptables_version" ]; then - log_message "INFO" "Found iptables version $iptables_version" - local major_version minor_version - major_version=$(echo "$iptables_version" | cut -d. -f1) - minor_version=$(echo "$iptables_version" | cut -d. -f2) - - if [ "$major_version" -lt 1 ] || ([ "$major_version" -eq 1 ] && [ "$minor_version" -lt 4 ]); then - add_error "iptables version $iptables_version is too old. Docker requires iptables 1.4 or higher." - log_message "ERROR" "Please upgrade iptables to version 1.4 or higher." - return 1 - fi - else - log_message "WARNING" "Could not determine iptables version, continuing anyway" - fi - else - add_error "iptables command not found (required for Docker network bridge)" - return 1 - fi - else - log_message "INFO" "Skipping iptables check on macOS (not a deployment target)" - fi - - log_message "SUCCESS" "All required system commands are available" - return 0 -} - -# ============================================================================== -# NETWORK CONNECTIVITY & ARTIFACT SOURCE TESTING -# ============================================================================== - -perform_network_tests() { - log_message "INFO" "=== NETWORK CONNECTIVITY TESTING ===" - - # Test US cloud endpoints - local us_reachable - us_reachable=$(test_cloud_endpoints "US" "${US_DATA_NODES[@]}") - - # Test EU cloud endpoints - local eu_reachable - eu_reachable=$(test_cloud_endpoints "EU" "${EU_DATA_NODES[@]}") - - local registry_reachable="false" - local download_reachable="false" - - # Check for local fallback resources (multiple locations) - log_message "INFO" "Checking for local artifact fallback resources..." - - # Docker binary locations (priority: local binaries directory -> current directory) - local has_local_docker=false - local docker_sources=() - - if [ -d "$LOCAL_BINARY_DIR" ]; then - log_message "INFO" "Checking local binaries directory: $LOCAL_BINARY_DIR" - local binary_files - binary_files=$(ls "$LOCAL_BINARY_DIR"/*.tgz 2>/dev/null | head -5) - if [ -n "$binary_files" ]; then - log_message "SUCCESS" "Found local Docker binaries in $LOCAL_BINARY_DIR:" - while IFS= read -r file; do - log_message "SUCCESS" " - $(basename "$file")" - done <<< "$binary_files" - has_local_docker=true - docker_sources+=("$LOCAL_BINARY_DIR/") - fi - fi - - local current_docker_files - current_docker_files=$(ls docker-*.tgz 2>/dev/null | head -5) - if [ -n "$current_docker_files" ]; then - log_message "SUCCESS" "Found local Docker binaries in current directory:" - while IFS= read -r file; do - log_message "SUCCESS" " - $file" - done <<< "$current_docker_files" - has_local_docker=true - docker_sources+=("current directory") - fi - - if [ "$has_local_docker" = "false" ]; then - log_message "WARNING" "No local Docker binaries found in $LOCAL_BINARY_DIR/ or current directory" - else - log_message "INFO" "Docker binary sources: ${docker_sources[*]}" - fi - - # Wallarm image locations (priority: local images directory -> current directory) - local has_local_wallarm=false - local wallarm_sources=() - - if [ -d "$LOCAL_IMAGE_DIR" ]; then - log_message "INFO" "Checking local images directory: $LOCAL_IMAGE_DIR" - local image_files - image_files=$(ls "$LOCAL_IMAGE_DIR"/*.tar.gz "$LOCAL_IMAGE_DIR"/*.tar 2>/dev/null | head -5) - if [ -n "$image_files" ]; then - log_message "SUCCESS" "Found local Wallarm images in $LOCAL_IMAGE_DIR:" - while IFS= read -r file; do - log_message "SUCCESS" " - $(basename "$file")" - done <<< "$image_files" - has_local_wallarm=true - wallarm_sources+=("$LOCAL_IMAGE_DIR/") - fi - fi - - local current_image_files - current_image_files=$(ls wallarm-node-*.tar.gz wallarm-node-*.tar 2>/dev/null | head -5) - if [ -n "$current_image_files" ]; then - log_message "SUCCESS" "Found local Wallarm images in current directory:" - while IFS= read -r file; do - log_message "SUCCESS" " - $file" - done <<< "$current_image_files" - has_local_wallarm=true - wallarm_sources+=("current directory") - fi - - if [ "$has_local_wallarm" = "false" ]; then - log_message "WARNING" "No local Wallarm images found in $LOCAL_IMAGE_DIR/ or current directory" - else - log_message "INFO" "Wallarm image sources: ${wallarm_sources[*]}" - fi - - echo "$us_reachable:$eu_reachable:$registry_reachable:$download_reachable" -} - -# ============================================================================== -# MAIN FUNCTION -# ============================================================================== - -main() { - clear - echo -e "${BLUE}${BOLD}" - echo "╔══════════════════════════════════════════════════════════════╗" - echo "║ WALLARM PREFLIGHT CHECK SCRIPT (Docker) - V1.3 ║" - echo "║ System Readiness Validation for Deployment ║" - echo "╚══════════════════════════════════════════════════════════════╝${NC}" - echo -e "\n${YELLOW}Starting preflight check at: $(date)${NC}" - - # Initialize logging - local log_dir="${HOME:-.}/logs" - if [ ! -d "$log_dir" ]; then - if ! mkdir -p "$log_dir"; then - echo -e "${YELLOW}Cannot create log directory $log_dir, falling back to current directory...${NC}" - log_dir="." - fi - fi - - LOG_FILE="$log_dir/wallarm-check.log" - if ! : > "$LOG_FILE"; then - echo -e "${RED}Cannot create log file at $LOG_FILE${NC}" - echo -e "${YELLOW}Falling back to current directory...${NC}" - LOG_FILE="./wallarm-check.log" - : > "$LOG_FILE" 2>/dev/null || true - fi - if ! chmod 644 "$LOG_FILE" 2>/dev/null; then - echo -e "${YELLOW}Warning: Could not set permissions on log file${NC}" - fi - - log_message "INFO" "=== Wallarm Preflight Check Started ===" - - if [ "$INSECURE_SSL" = "1" ]; then - log_message "WARNING" "SSL certificate validation is DISABLED (insecure). Set WALLARM_INSECURE_SSL=0 to enable validation." - fi - - # Phase 1: System validation - log_message "INFO" "=== PHASE 1: SYSTEM VALIDATION ===" - - if ! validate_required_commands; then - add_error "Required system commands validation failed" - fi - - if ! validate_sudo_access; then - add_error "Sudo access validation failed" - fi - - local os_info - os_info=$(detect_os_and_version) - local os_name - os_name=$(echo "$os_info" | cut -d: -f1) - local os_version - os_version=$(echo "$os_info" | cut -d: -f2) - - local architecture - architecture=$(detect_architecture) - if [ "$architecture" = "unknown" ]; then - add_error "Unsupported architecture detected" - fi - - local init_system - init_system=$(detect_init_system) - - log_message "SUCCESS" "System validation completed:" - log_message "SUCCESS" " OS: $os_name $os_version" - log_message "SUCCESS" " Architecture: $architecture" - log_message "SUCCESS" " Init System: $init_system" - - # Phase 2: Network connectivity testing - log_message "INFO" "=== PHASE 2: NETWORK CONNECTIVITY TESTING ===" - - log_message "INFO" "Testing connectivity to Git Repositorys artifact repository..." - GIT_REACHABLE="false" - if test_connectivity "$GIT_DOCKER_BINARY_URL" "Git Repositorys Docker artifact"; then - GIT_REACHABLE="true" - log_message "SUCCESS" "Git Repositorys Docker artifact is reachable (primary source)" - else - log_message "WARNING" "Git Repositorys Docker artifact is not reachable - will use fallback sources" - fi - - local network_results - network_results=$(perform_network_tests) - local us_reachable - us_reachable=$(echo "$network_results" | cut -d: -f1) - local eu_reachable - eu_reachable=$(echo "$network_results" | cut -d: -f2) - local registry_reachable - registry_reachable=$(echo "$network_results" | cut -d: -f3) - local download_reachable - download_reachable=$(echo "$network_results" | cut -d: -f4) - - # Critical check: Need at least one source for Docker and Wallarm - # Priority: Git Repositorys (primary) -> local files - - if [ "$GIT_REACHABLE" = "true" ]; then - log_message "SUCCESS" "Git Repositorys artifact repository is reachable (primary source available)" - else - log_message "WARNING" "Git Repositorys artifact repository is not reachable - checking fallback sources" - - local has_local_docker=false - local has_local_wallarm=false - - if [ -d "$LOCAL_BINARY_DIR" ] && [ -n "$(ls "$LOCAL_BINARY_DIR"/*.tgz 2>/dev/null)" ]; then - has_local_docker=true - log_message "INFO" "Found local Docker binaries in $LOCAL_BINARY_DIR/" - elif [ -n "$(ls docker-*.tgz 2>/dev/null)" ]; then - has_local_docker=true - log_message "INFO" "Found local Docker binaries in current directory" - fi - - if [ -d "$LOCAL_IMAGE_DIR" ] && [ -n "$(ls "$LOCAL_IMAGE_DIR"/*.tar.gz "$LOCAL_IMAGE_DIR"/*.tar 2>/dev/null)" ]; then - has_local_wallarm=true - log_message "INFO" "Found local Wallarm images in $LOCAL_IMAGE_DIR/" - elif [ -n "$(ls wallarm-node-*.tar.gz wallarm-node-*.tar 2>/dev/null)" ]; then - has_local_wallarm=true - log_message "INFO" "Found local Wallarm images in current directory" - fi - - local has_sufficient_resources=true - - if [ "$has_local_docker" = "false" ]; then - log_message "ERROR" "No Docker binary source available" - log_message "ERROR" " - Git Repositorys artifacts unreachable: $GIT_RAW_URL" - log_message "ERROR" " - Local binaries not found in $LOCAL_BINARY_DIR/ or current directory" - - has_sufficient_resources=false - fi - - if [ "$has_local_wallarm" = "false" ]; then - log_message "ERROR" "No Wallarm image source available" - log_message "ERROR" " - Git Repositorys artifacts unreachable: $GIT_RAW_URL" - log_message "ERROR" " - Local images not found in $LOCAL_IMAGE_DIR/ or current directory" - - has_sufficient_resources=false - fi - - if [ "$has_sufficient_resources" = "false" ]; then - add_error "Insufficient resources: Need at least one source for Docker and Wallarm artifacts. - -Possible sources: -1. Git Repositorys (primary): Ensure network access to $GIT_RAW_URL -2. Local files: Place artifacts in: - - Docker binary: $LOCAL_BINARY_DIR/docker-29.2.1.tgz or current directory - - Wallarm image: $LOCAL_IMAGE_DIR/wallarm-node-6.11.0-rc1.tar.gz or current directory" - fi - fi - - log_message "SUCCESS" "Network testing completed:" - log_message "SUCCESS" " Git Repositorys Artifacts Reachable: $GIT_REACHABLE" - log_message "SUCCESS" " US Cloud Reachable: $us_reachable" - log_message "SUCCESS" " EU Cloud Reachable: $eu_reachable" - log_message "SUCCESS" " Fallback Registry Reachable: $registry_reachable" - log_message "SUCCESS" " Fallback Download Reachable: $download_reachable" - - # Phase 3: Write results - log_message "INFO" "=== PHASE 3: WRITING RESULTS ===" - - write_env_file "$os_name" "$os_version" "$architecture" "$init_system" \ - "$us_reachable" "$eu_reachable" "$registry_reachable" "$download_reachable" \ - "$GIT_REACHABLE" - - # Final summary - if [ "$CHECK_RESULT" = "pass" ]; then - log_message "SUCCESS" "=== PREFLIGHT CHECK PASSED ===" - echo -e "\n${GREEN}${BOLD}╔══════════════════════════════════════════════════════════════╗${NC}" - echo -e "${GREEN}${BOLD}║ PREFLIGHT CHECK PASSED - SYSTEM READY ║${NC}" - echo -e "${GREEN}${BOLD}╚══════════════════════════════════════════════════════════════╝${NC}" - echo -e "\n${CYAN}System is ready for Wallarm Docker deployment.${NC}" - echo -e "${YELLOW}Check results: $ENV_FILE${NC}" - echo -e "${YELLOW}Full log: $LOG_FILE${NC}" - echo -e "\n${GREEN}Next step: Run ./docker/wallarm-ct-deploy.sh to proceed with deployment${NC}" - exit 0 - else - log_message "ERROR" "=== PREFLIGHT CHECK FAILED ===" - echo -e "\n${RED}${BOLD}╔══════════════════════════════════════════════════════════════╗${NC}" - echo -e "${RED}${BOLD}║ PREFLIGHT CHECK FAILED - SYSTEM NOT READY ║${NC}" - echo -e "${RED}${BOLD}╚══════════════════════════════════════════════════════════════╝${NC}" - echo -e "\n${YELLOW}${BOLD}Issues found:${NC}" - for error in "${CHECK_ERRORS[@]}"; do - echo -e " ${RED}•${NC} $error" - done - echo -e "\n${YELLOW}Check results: $ENV_FILE${NC}" - echo -e "${YELLOW}Full log: $LOG_FILE${NC}" - echo -e "\n${CYAN}Please fix the issues above and run the check again.${NC}" - exit 1 - fi -} - -# ============================================================================== -# SCRIPT EXECUTION -# ============================================================================== - -# Ensure we're in bash -if [ -z "$BASH_VERSION" ]; then - echo "Error: This script must be run with bash" >&2 - exit 1 -fi - -# Run main function -main "$@" diff --git a/docker/wallarm-ct-deploy.sh b/docker/wallarm-ct-deploy.sh deleted file mode 100755 index 9d0bf4c..0000000 --- a/docker/wallarm-ct-deploy.sh +++ /dev/null @@ -1,1653 +0,0 @@ -#!/bin/bash -# ============================================================================== -# WALLARM DEPLOYMENT SCRIPT - V1.3 (Docker deployment) -# ============================================================================== -# Purpose: Deploy Wallarm filtering node (Docker container) after preflight check -# Features: -# - Reads preflight check results from .env file -# - Interactive configuration (cloud region, ports, token, upstream) -# - Docker installation with LXC optimization (VFS storage driver) -# - Wallarm node deployment with persistence -# - Deployment verification with handshake test -# - DAU-friendly error handling with remediation -# ============================================================================== - -# Script location and shared library (colors, logging, validation, detection, connectivity) -SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)" -# shellcheck source=./wallarm-lib.sh -source "$SCRIPT_DIR/wallarm-lib.sh" - -# Strict error handling -set -euo pipefail -trap early_error_handler ERR - -# Configuration -ENV_FILE=".env" -LOG_FILE="${HOME:-.}/logs/wallarm-deployment.log" - -# Git Repositorys artifact URLs (primary source) - Docker deployment artifacts -GIT_BASE_URL="https://git.sechpoint.app/customer-engineering/wallarm" -GIT_RAW_URL="https://git.sechpoint.app/customer-engineering/wallarm/raw/branch/main" -GIT_DOCKER_BINARY_URL="${GIT_RAW_URL}/docker/binaries/docker-29.2.1.tgz" -GIT_DOCKER_CHECKSUM_URL="${GIT_RAW_URL}/docker/binaries/docker-29.2.1.tgz.sha256" -GIT_WALLARM_IMAGE_URL="${GIT_RAW_URL}/docker/images/wallarm-node-6.11.0-rc1.tar.gz" -GIT_WALLARM_CHECKSUM_URL="${GIT_RAW_URL}/docker/images/wallarm-node-6.11.0-rc1.tar.gz.sha256" - -# Local artifact directories (relative to script location) -LOCAL_BINARY_DIR="${SCRIPT_DIR}/binaries" -LOCAL_IMAGE_DIR="${SCRIPT_DIR}/images" - -DOCKER_VERSION="29.2.1" # Version from stealth deployment guide -WALLARM_IMAGE_TARGET="wallarm/node:6.11.0-rc1" - - - -# Deployment variables (set during execution) -CLOUD_REGION="" -API_HOST="" -INGRESS_PORT="" -MONITORING_PORT="" -UPSTREAM_IP="" -UPSTREAM_PORT="" -WALLARM_TOKEN="" -INSTANCE_NAME="" -INSTANCE_DIR="" - -# Resource reachability from check script -US_CLOUD_REACHABLE="false" -EU_CLOUD_REACHABLE="false" -REGISTRY_REACHABLE="false" -DOWNLOAD_REACHABLE="false" -GIT_REACHABLE="false" - -# ============================================================================== -# PREFLIGHT CHECK VERIFICATION -# ============================================================================== - -verify_preflight_check() { - log_message "INFO" "Verifying preflight check results..." - - if [ ! -f "$ENV_FILE" ]; then - log_message "ERROR" "Preflight check file not found: $ENV_FILE" - echo -e "\n${YELLOW}Preflight check has not been run or .env file is missing.${NC}" - echo -e "${YELLOW}Would you like to run the preflight check now?${NC}" - read -r -p "$(echo -e "${YELLOW}Run preflight check? (Y/n): ${NC}")" -n 1 - echo - if [[ ! $REPLY =~ ^[Nn]$ ]]; then - echo -e "${CYAN}Running preflight check...${NC}" - if ! "$SCRIPT_DIR/wallarm-ct-check.sh"; then - fail_with_remediation "Preflight check failed" \ - "Run the preflight check manually and fix any issues: -1. $SCRIPT_DIR/wallarm-ct-check.sh -2. Review the errors in $ENV_FILE -3. Fix the issues and run this script again" - fi - else - fail_with_remediation "Preflight check required" \ - "Run the preflight check before deployment: -1. $SCRIPT_DIR/wallarm-ct-check.sh -2. Review results in $ENV_FILE -3. Run this script again" - fi - fi - - # Load environment variables from .env file (from shared library) - if ! load_env_file "$ENV_FILE"; then - fail_with_remediation "Cannot load preflight results" \ - "The preflight check results file could not be read. -1. Run the preflight check: $SCRIPT_DIR/wallarm-ct-check.sh -2. Verify $ENV_FILE exists and is readable -3. Run this script again" - fi - - if [ "$CHECK_RESULT" != "pass" ]; then - log_message "ERROR" "Preflight check failed (result: $CHECK_RESULT)" - echo -e "\n${YELLOW}Preflight check found issues. Please review:${NC}" - echo -e "${YELLOW}1. Check file: $ENV_FILE${NC}" - echo -e "${YELLOW}2. Run: $SCRIPT_DIR/wallarm-ct-check.sh${NC}" - echo -e "${YELLOW}3. Fix the issues and try again${NC}" - exit 1 - fi - - log_message "SUCCESS" "Preflight check verified:" - log_message "SUCCESS" " OS: $OS_NAME $OS_VERSION" - log_message "SUCCESS" " Architecture: $ARCHITECTURE" - log_message "SUCCESS" " Init System: $INIT_SYSTEM" - log_message "SUCCESS" " US Cloud Reachable: $US_CLOUD_REACHABLE" - log_message "SUCCESS" " EU Cloud Reachable: $EU_CLOUD_REACHABLE" - log_message "SUCCESS" " Registry Reachable: $REGISTRY_REACHABLE" - log_message "SUCCESS" " Download Reachable: $DOWNLOAD_REACHABLE" - log_message "SUCCESS" " Git Repositorys Reachable: $GIT_REACHABLE" - - # Check for local artifact directories - if [ -d "$LOCAL_BINARY_DIR" ]; then - log_message "INFO" " Local binaries directory: $LOCAL_BINARY_DIR (exists)" - local binary_count=$(ls "$LOCAL_BINARY_DIR"/*.tgz 2>/dev/null | wc -l) - if [ "$binary_count" -gt 0 ]; then - log_message "INFO" " Found $binary_count Docker binary file(s)" - fi - else - log_message "INFO" " Local binaries directory: $LOCAL_BINARY_DIR (not found)" - fi - - if [ -d "$LOCAL_IMAGE_DIR" ]; then - log_message "INFO" " Local images directory: $LOCAL_IMAGE_DIR (exists)" - local image_count=$(ls "$LOCAL_IMAGE_DIR"/*.tar.gz 2>/dev/null | wc -l) - if [ "$image_count" -gt 0 ]; then - log_message "INFO" " Found $image_count Wallarm image file(s)" - fi - else - log_message "INFO" " Local images directory: $LOCAL_IMAGE_DIR (not found)" - fi - - # Validate we have at least one cloud region reachable - if [ "$US_CLOUD_REACHABLE" = "false" ] && [ "$EU_CLOUD_REACHABLE" = "false" ]; then - fail_with_remediation "No Wallarm cloud region reachable" \ - "Network connectivity issues detected: -1. Check firewall rules for Wallarm cloud endpoints -2. Verify network connectivity -3. Run preflight check again: $SCRIPT_DIR/wallarm-ct-check.sh" - fi - - # Validate we have resources for Docker/Wallarm - # Primary source: Git Repositorys; fallback: local directories - if [ "$GIT_REACHABLE" = "false" ]; then - log_message "WARNING" "Git Repositorys not reachable, checking for local resources..." - - local has_local_resources=true - - # Check local binaries directory first, then current directory as fallback - if [ ! -f "$LOCAL_BINARY_DIR/docker-29.2.1.tgz" ] && [ -z "$(ls docker-*.tgz 2>/dev/null)" ]; then - log_message "ERROR" "No local Docker binary found" - has_local_resources=false - fi - - # Check local images directory first, then current directory as fallback - if [ ! -f "$LOCAL_IMAGE_DIR/wallarm-node-6.11.0-rc1.tar.gz" ] && [ -z "$(ls wallarm-node-*.tar.gz wallarm-node-*.tar 2>/dev/null)" ]; then - log_message "ERROR" "No local Wallarm image found" - has_local_resources=false - fi - - if [ "$has_local_resources" = "false" ]; then - fail_with_remediation "Insufficient resources for deployment" \ - "Please provide either: -1. Network access to Git Repositorys: $GIT_RAW_URL -2. Local files in binaries/ and images/ directories: - - $LOCAL_BINARY_DIR/docker-29.2.1.tgz - - $LOCAL_IMAGE_DIR/wallarm-node-6.11.0-rc1.tar.gz -3. Local files in current directory as fallback: - - docker-*.tgz - - wallarm-node-*.tar.gz or wallarm-node-*.tar" - fi - else - log_message "SUCCESS" "Git Repositorys reachable - will download artifacts from $GIT_RAW_URL" - fi -} - -# ============================================================================== -# CONFIGURATION COLLECTION FUNCTIONS -# ============================================================================== -# select_cloud_region, validate_ip_address and check_port_available are provided -# by the shared library (../common/wallarm-lib.sh). - -collect_configuration() { - log_message "INFO" "Collecting deployment configuration..." - - # Get ingress port - local default_port=80 - local ingress_port="" - while [[ ! "$ingress_port" =~ ^[0-9]+$ ]] || [ "$ingress_port" -lt 1 ] || [ "$ingress_port" -gt 65535 ]; do - read -r -p "$(echo -e "${YELLOW}Enter inbound port [${default_port}]: ${NC}")" ingress_port - ingress_port="${ingress_port:-$default_port}" - - if [[ ! "$ingress_port" =~ ^[0-9]+$ ]]; then - echo -e "${RED}Port must be a number${NC}" - elif [ "$ingress_port" -lt 1 ] || [ "$ingress_port" -gt 65535 ]; then - echo -e "${RED}Port must be between 1 and 65535${NC}" - elif ! check_port_available "$ingress_port"; then - echo -e "${RED}Port $ingress_port is already in use${NC}" - ingress_port="" - fi - done - - # Calculate monitoring port (ingress + 10, check for conflicts) - local monitoring_port=$((ingress_port + 10)) - if ! check_port_available "$monitoring_port"; then - log_message "WARNING" "Port $monitoring_port is in use, choosing alternative..." - monitoring_port=$((ingress_port + 100)) - if ! check_port_available "$monitoring_port"; then - monitoring_port=$((ingress_port + 200)) - fi - fi - log_message "INFO" "Monitoring port will be: $monitoring_port" - - # Get application server details - local upstream_ip="" - local upstream_port="" - - echo -e "\n${CYAN}${BOLD}Application Server Configuration:${NC}" - echo -e "${YELLOW}Enter the IP/hostname and port of your backend application${NC}" - - while [[ -z "$upstream_ip" ]]; do - read -r -p "$(echo -e "${YELLOW}Upstream App IP/Hostname [127.0.0.1]: ${NC}")" upstream_ip - upstream_ip="${upstream_ip:-127.0.0.1}" - - # Validate IP/hostname format - if ! validate_ip_address "$upstream_ip" && \ - ! [[ "$upstream_ip" =~ ^[a-zA-Z0-9][a-zA-Z0-9.-]*[a-zA-Z0-9]$ ]]; then - echo -e "${RED}Invalid IP/hostname format${NC}" - upstream_ip="" - fi - done - - while [[ ! "$upstream_port" =~ ^[0-9]+$ ]] || [ "$upstream_port" -lt 1 ] || [ "$upstream_port" -gt 65535 ]; do - read -r -p "$(echo -e "${YELLOW}Upstream App Port [8080]: ${NC}")" upstream_port - upstream_port="${upstream_port:-8080}" - - if [[ ! "$upstream_port" =~ ^[0-9]+$ ]]; then - echo -e "${RED}Port must be a number${NC}" - elif [ "$upstream_port" -lt 1 ] || [ "$upstream_port" -gt 65535 ]; then - echo -e "${RED}Port must be between 1 and 65535${NC}" - fi - done - - # Verify application server reachability - log_message "INFO" "Verifying application server reachability..." - if timeout 5 bash -c "cat < /dev/null > /dev/tcp/$upstream_ip/$upstream_port" 2>/dev/null; then - log_message "SUCCESS" "Application server $upstream_ip:$upstream_port is reachable" - else - log_message "WARNING" "Application server $upstream_ip:$upstream_port is not reachable" - echo -e "${YELLOW}${BOLD}Warning:${NC} Cannot reach application server at $upstream_ip:$upstream_port" - echo -e "${YELLOW}This may cause the Wallarm node to fail. Possible reasons:${NC}" - echo -e "1. Application server is not running" - echo -e "2. Firewall blocking port $upstream_port" - echo -e "3. Wrong IP/hostname" - echo -e "4. Application server not listening on that port" - - read -r -p "$(echo -e "${YELLOW}Continue anyway? (y/N): ${NC}")" -n 1 - echo - if [[ ! $REPLY =~ ^[Yy]$ ]]; then - fail_with_remediation "Application server unreachable" \ - "Ensure your application server is accessible: -1. Start your application server -2. Check it's listening: sudo ss -tlnp | grep :$upstream_port -3. Verify firewall rules allow inbound connections -4. Test connectivity: telnet $upstream_ip $upstream_port -5. If using hostname, verify DNS resolution: nslookup $upstream_ip" - fi - fi - - # Get Wallarm node token - local wallarm_token="" - echo -e "\n${CYAN}${BOLD}Wallarm Node Token:${NC}" - echo -e "${YELLOW}Get your token from Wallarm Console:${NC}" - echo -e "Create a new 'Wallarm node' and copy the token (will be visible as you type)" - while [[ -z "$wallarm_token" ]]; do - read -r -p "$(echo -e "${YELLOW}Paste Wallarm Node Token: ${NC}")" wallarm_token - # Trim whitespace and newlines - wallarm_token=$(echo "$wallarm_token" | tr -d '[:space:]') - - if [[ -z "$wallarm_token" ]]; then - echo -e "${RED}Token cannot be empty${NC}" - elif [[ ! "$wallarm_token" =~ ^[A-Za-z0-9_+/=\-]+$ ]]; then - echo -e "${RED}Token contains invalid characters. Wallarm tokens are base64 strings (A-Z, a-z, 0-9, _, -, +, /, =)${NC}" - echo -e "${YELLOW}First 20 chars of what you entered: '${wallarm_token:0:20}...'${NC}" - wallarm_token="" - else - # Show confirmation of token length (but not full token for security) - token_length=${#wallarm_token} - echo -e "${GREEN}Token accepted (${token_length} characters).${NC}" - echo -e "${YELLOW}First 8 chars for verification: ${wallarm_token:0:8}...${NC}" - fi - done - - # Get trusted proxy IPs for real IP configuration - local trusted_proxies="" - echo -e "\n${CYAN}${BOLD}Real Client IP Configuration:${NC}" - echo -e "${YELLOW}For Wallarm to see the real client IP, specify the IP address(es) of trusted proxies" - echo -e "(e.g., load balancers, firewalls, CDNs) that forward traffic to this node.${NC}" - echo -e "${YELLOW}You can enter:${NC}" - echo -e " - Single IP: 10.0.0.10" - echo -e " - CIDR range: 10.0.0.0/24" - echo -e " - Multiple entries separated by spaces: 10.0.0.10 10.0.1.0/24 192.168.1.1" - echo -e "${YELLOW}If unsure, you can leave empty and configure later${NC}" - - read -r -p "$(echo -e "${YELLOW}Trusted proxy IPs/CIDRs (space-separated): ${NC}")" trusted_proxies_input - - # Validate and clean up the input - local validated_proxies=() - if [[ -n "$trusted_proxies_input" ]]; then - # Split input by spaces - IFS=' ' read -ra proxy_array <<< "$trusted_proxies_input" - - for proxy in "${proxy_array[@]}"; do - # Trim whitespace - proxy=$(echo "$proxy" | xargs) - if [[ -n "$proxy" ]]; then - # Validate IP or CIDR - if [[ "$proxy" =~ ^[0-9]{1,3}\.[0-9]{1,3}\.[0-9]{1,3}\.[0-9]{1,3}(/[0-9]{1,2})?$ ]]; then - # Basic IP format validation - IFS='/' read -r ip cidr <<< "$proxy" - IFS='.' read -r o1 o2 o3 o4 <<< "$ip" - if [[ $o1 -le 255 && $o2 -le 255 && $o3 -le 255 && $o4 -le 255 ]]; then - if [[ -z "$cidr" ]] || [[ $cidr -ge 0 && $cidr -le 32 ]]; then - validated_proxies+=("$proxy") - else - echo -e "${RED}Invalid CIDR prefix length for $proxy (must be 0-32)${NC}" - fi - else - echo -e "${RED}Invalid IP octets in $proxy${NC}" - fi - else - echo -e "${RED}Invalid IP/CIDR format: $proxy${NC}" - echo -e "${YELLOW}Example valid formats: 10.0.0.10, 10.0.0.0/24, 192.168.1.1${NC}" - fi - fi - done - - if [[ ${#validated_proxies[@]} -eq 0 ]]; then - echo -e "${YELLOW}No valid proxy IPs provided. Will skip set_real_ip_from configuration.${NC}" - echo -e "${YELLOW}You can manually edit /etc/nginx/conf.d/wallarm.conf later to add set_real_ip_from directives.${NC}" - trusted_proxies="" - else - trusted_proxies="${validated_proxies[*]}" - echo -e "${GREEN}Trusted proxies configured: $trusted_proxies${NC}" - fi - else - echo -e "${YELLOW}No trusted proxies specified. The node will see the last hop IP only.${NC}" - echo -e "${YELLOW}For real client IP detection, you'll need to manually configure set_real_ip_from in nginx config.${NC}" - fi - - # Generate instance name and directory - local instance_name - instance_name="wallarm-$(hostname -s | tr '[:upper:]' '[:lower:]')-$(date +%Y%m%d)" - local instance_dir="/opt/$instance_name" - - # Ensure directory exists - sudo mkdir -p "$instance_dir" - - log_message "SUCCESS" "Configuration collected:" - log_message "SUCCESS" " Ingress Port: $ingress_port" - log_message "SUCCESS" " Monitoring Port: $monitoring_port" - log_message "SUCCESS" " Upstream: $upstream_ip:$upstream_port" - if [[ -n "$trusted_proxies" ]]; then - log_message "SUCCESS" " Trusted Proxies: $trusted_proxies" - else - log_message "INFO" " Trusted Proxies: Not configured (will need manual setup)" - fi - log_message "SUCCESS" " Instance: $instance_name" - log_message "SUCCESS" " Directory: $instance_dir" - - # Set global variables - INGRESS_PORT="$ingress_port" - MONITORING_PORT="$monitoring_port" - UPSTREAM_IP="$upstream_ip" - UPSTREAM_PORT="$upstream_port" - WALLARM_TOKEN="$wallarm_token" - INSTANCE_NAME="$instance_name" - INSTANCE_DIR="$instance_dir" - TRUSTED_PROXIES="$trusted_proxies" -} - -# ============================================================================== -# DOCKER ENGINE SETUP (LXC OPTIMIZED) -# ============================================================================== - -setup_docker_engine() { - log_message "INFO" "Setting up Docker Engine for LXC/stealth deployment..." - - # Check if Docker is already installed and running - if command -v docker >/dev/null 2>&1 && sudo docker info >/dev/null 2>&1; then - local docker_version - docker_version=$(docker --version | cut -d' ' -f3 | tr -d ',') - log_message "SUCCESS" "Docker is already installed and running (version $docker_version)" - - # Check if Docker is configured for LXC - if sudo docker info 2>/dev/null | grep -q "Storage Driver: vfs"; then - log_message "SUCCESS" "Docker is already configured with VFS storage driver (LXC compatible)" - else - log_message "WARNING" "Docker is not using VFS storage driver. LXC compatibility may be limited." - fi - return 0 - fi - - log_message "INFO" "Docker not found or not running. Proceeding with installation..." - - # Determine binary source (priority: Git Repositorys -> local dir -> current dir) - local binary_file="docker-$DOCKER_VERSION.tgz" - local binary_path="" - - # 1. Try Git Repositorys download (primary source) - log_message "INFO" "Attempting to download Docker binary from Git Repositorys..." - if download_from_git "$GIT_DOCKER_BINARY_URL" "$binary_file" "Docker binary"; then - if verify_checksum "$binary_file" "$GIT_DOCKER_CHECKSUM_URL" "Docker binary"; then - binary_path="$binary_file" - log_message "SUCCESS" "Docker binary downloaded from Git Repositorys and checksum verified" - else - log_message "WARNING" "Git Repositorys Docker binary checksum verification failed, trying other sources" - # Remove corrupted download - rm -f "$binary_file" - fi - fi - - # 2. Check local binaries directory - if [ -z "$binary_path" ] && [ -d "$LOCAL_BINARY_DIR" ]; then - log_message "INFO" "Checking local binaries directory: $LOCAL_BINARY_DIR" - local local_binary="$LOCAL_BINARY_DIR/docker-29.2.1.tgz" - local local_checksum="$LOCAL_BINARY_DIR/docker-29.2.1.tgz.sha256" - - if [ -f "$local_binary" ]; then - log_message "INFO" "Found local Docker binary: $local_binary" - # Copy to current directory for consistency with extraction logic - cp "$local_binary" "$binary_file" - if verify_checksum "$binary_file" "$local_checksum" "local Docker binary"; then - binary_path="$binary_file" - log_message "SUCCESS" "Using local Docker binary from binaries directory" - else - log_message "WARNING" "Local Docker binary checksum verification failed" - rm -f "$binary_file" - fi - fi - fi - - # 3. Check current directory for any docker-*.tgz (existing fallback) - if [ -z "$binary_path" ]; then - log_message "INFO" "Checking current directory for Docker binaries..." - local local_files - local_files=$(ls docker-*.tgz 2>/dev/null | head -1) - if [ -n "$local_files" ]; then - binary_path="$local_files" - log_message "SUCCESS" "Using local Docker binary: $binary_path" - # Optional: Try to verify checksum if .sha256 file exists - local checksum_file="${local_files}.sha256" - if [ -f "$checksum_file" ]; then - if verify_checksum "$binary_path" "$checksum_file" "Docker binary"; then - log_message "SUCCESS" "Local Docker binary checksum verified" - else - log_message "WARNING" "Local Docker binary checksum verification failed, but continuing" - fi - fi - fi - fi - - - - # 5. Final fallback: no binary available - if [ -z "$binary_path" ]; then - fail_with_remediation "No Docker binary available" \ - "Please provide a Docker static binary using one of these methods: -1. Git Repositorys (primary): Ensure network access to $GIT_RAW_URL -2. Local binaries directory: Place docker-29.2.1.tgz and .sha256 in $LOCAL_BINARY_DIR/ -3. Current directory: Place any docker-*.tgz file in current directory - - -Re-run the script after providing the binary." - fi - - # Extract and install - log_message "INFO" "Extracting Docker binary..." - - # First verify the tar file exists and is readable - if [ ! -f "$binary_path" ]; then - fail_with_remediation "Docker binary file not found" \ - "File $binary_path does not exist. Check download and file permissions." - fi - - if [ ! -r "$binary_path" ]; then - fail_with_remediation "Docker binary file not readable" \ - "Cannot read file $binary_path. Check file permissions." - fi - - # Test if it's a valid tar archive - log_message "DEBUG" "Testing tar archive integrity..." - - # First check if we can read the file - if [ ! -r "$binary_path" ]; then - log_message "ERROR" "Cannot read file: $binary_path" - log_message "INFO" "File permissions: $(ls -la "$binary_path" 2>/dev/null || echo "cannot stat")" - fail_with_remediation "Cannot read Docker binary file" \ - "File $binary_path exists but is not readable. -1. Check file permissions: ls -la $binary_path -2. Fix permissions: chmod 644 $binary_path -3. Or download fresh copy" - fi - - # Try to get file type information - local file_type="unknown" - if command -v file >/dev/null 2>&1; then - file_type=$(file "$binary_path" 2>/dev/null || echo "file command failed") - elif command -v hexdump >/dev/null 2>&1; then - # Check magic bytes manually - local magic_bytes=$(hexdump -n 2 -C "$binary_path" 2>/dev/null | head -1 | cut -d' ' -f2-3 || echo "no magic") - file_type="hexdump: $magic_bytes" - fi - - log_message "INFO" "File info: $binary_path ($(stat -c%s "$binary_path") bytes)" - log_message "INFO" "File type: $file_type" - log_message "INFO" "Current directory: $(pwd)" - log_message "INFO" "Full path: $(readlink -f "$binary_path" 2>/dev/null || echo "$binary_path")" - - # Test tar archive with error capture - local tar_test_output - tar_test_output=$(tar -tzf "$binary_path" 2>&1) - local tar_test_exit=$? - - if [ $tar_test_exit -ne 0 ]; then - log_message "ERROR" "File $binary_path is not a valid tar.gz archive (tar exit: $tar_test_exit)" - log_message "DEBUG" "Tar test output: $tar_test_output" - - # Check if it might be a different compression format - log_message "INFO" "Checking for alternative compression formats..." - - # Try gunzip test - if command -v gunzip >/dev/null 2>&1; then - if gunzip -t "$binary_path" 2>/dev/null; then - log_message "WARNING" "File is valid gzip but tar can't read it" - else - log_message "INFO" "Not a valid gzip file either" - fi - fi - - # Check first few bytes - if command -v xxd >/dev/null 2>&1; then - log_message "DEBUG" "First 20 bytes: $(xxd -l 20 "$binary_path" 2>/dev/null || echo "cannot read")" - elif command -v od >/dev/null 2>&1; then - log_message "DEBUG" "First 20 bytes: $(od -x -N 20 "$binary_path" 2>/dev/null | head -2 || echo "cannot read")" - fi - - fail_with_remediation "Docker binary file is corrupted or invalid" \ - "The Docker binary file is not a valid tar.gz archive. -Tar error: $tar_test_output - -File info: $(stat -c%s "$binary_path") bytes, type: $file_type - -Possible solutions: -1. The download may have been interrupted or corrupted -2. The file may be in wrong format (not tar.gz) -3. Server might be serving wrong content - -Steps to fix: -1. Delete corrupted file: rm -f docker-*.tgz -2. Check disk space: df -h . -3. Try alternative sources: - a) Git Repositorys: curl -L '$GIT_DOCKER_BINARY_URL' -o docker.tgz - b) Local directory: Check $LOCAL_BINARY_DIR/docker-29.2.1.tgz - -4. Verify downloaded file: file test.tgz && tar -tzf test.tgz -5. Check if tar command works: tar --version" - fi - - log_message "SUCCESS" "Tar archive validation passed" - - # Extract the archive - log_message "DEBUG" "Extracting files from $binary_path..." - local tar_output - tar_output=$(tar xzvf "$binary_path" 2>&1) - local tar_exit=$? - - if [ $tar_exit -ne 0 ]; then - log_message "ERROR" "Failed to extract files from $binary_path (exit code: $tar_exit)" - log_message "DEBUG" "Tar output: $tar_output" - log_message "INFO" "Checking extracted files..." - if [ -d "docker" ]; then - log_message "WARNING" "Some files were extracted to 'docker/' directory" - ls -la docker/ 2>/dev/null | head -10 || true - fi - fail_with_remediation "Failed to extract Docker binary" \ - "Extraction failed. Possible reasons: -1. Insufficient disk space: df -h . -2. Permission issues in current directory -3. Corrupted archive (partial download) -4. File system issues - -Tar error: $tar_output - -Check disk space and permissions, then try manual extraction: - tar xzvf $binary_path" - else - log_message "SUCCESS" "Docker binary extracted successfully" - fi - - log_message "INFO" "Installing Docker binaries to /usr/bin/" - sudo cp docker/* /usr/bin/ 2>/dev/null || { - fail_with_remediation "Failed to copy Docker binaries" \ - "Permission denied copying to /usr/bin/ -1. Ensure you have sudo privileges -2. Check disk space: df -h / -3. Manual installation: - sudo cp docker/* /usr/bin/" - } - - # Ensure binaries are executable - log_message "INFO" "Setting executable permissions on Docker binaries..." - sudo chmod +x /usr/bin/dockerd /usr/bin/docker 2>/dev/null || { - log_message "WARNING" "Could not set executable permissions on Docker binaries" - } - - # Verify Docker binaries work - log_message "INFO" "Verifying Docker binaries..." - if ! sudo /usr/bin/dockerd --version 2>/dev/null; then - fail_with_remediation "Docker binary verification failed" \ -"Docker binary (/usr/bin/dockerd) appears to be corrupted or incompatible. -The binary was extracted from $binary_path but doesn't run. - -Check the binary: - sudo file /usr/bin/dockerd - sudo ls -la /usr/bin/dockerd - sudo /usr/bin/dockerd --version - -The Docker static binary might be for wrong architecture or corrupted. -Try downloading manually from one of these sources: -1. Git Repositorys: curl -L '$GIT_DOCKER_BINARY_URL' -o docker.tgz -2. Local directory: Check $LOCAL_BINARY_DIR/docker-29.2.1.tgz - - -Then extract and install: - tar xzvf docker.tgz - sudo cp docker/* /usr/bin/" - else - local docker_version - docker_version=$(sudo /usr/bin/dockerd --version 2>&1 | head -1) - log_message "SUCCESS" "Docker binary verified: $docker_version" - fi - - # Cleanup extracted directory - log_message "INFO" "Cleaning up extracted Docker binaries directory..." - rm -rf docker - log_message "INFO" "Cleanup completed" - - # DEBUG: Mark start of docker group section - log_message "INFO" "=== Starting docker group creation ===" - - # Create docker group (required for systemd socket configuration and dockerd --group) - log_message "INFO" "Creating docker group for Docker socket access..." - - # Check if group already exists - log_message "INFO" "Checking if docker group exists..." - local getent_output - if getent_output=$(getent group docker 2>&1); then - getent_exit=0 - else - getent_exit=$? - fi - log_message "INFO" "getent group docker result: exit=$getent_exit, output='$getent_output'" - - if [ $getent_exit -eq 0 ]; then - log_message "SUCCESS" "Docker group already exists: $getent_output" - else - # Attempt to create docker group with error capture - log_message "INFO" "Attempting to create docker group with sudo groupadd docker..." - local groupadd_output - if groupadd_output=$(sudo groupadd docker 2>&1); then - groupadd_exit=0 - else - groupadd_exit=$? - fi - - if [ $groupadd_exit -eq 0 ]; then - log_message "SUCCESS" "Created docker group" - else - log_message "ERROR" "Failed to create docker group (exit code: $groupadd_exit)" - log_message "INFO" "groupadd command output: $groupadd_output" - - # Check if group was somehow created despite error - log_message "INFO" "Checking if docker group was created despite groupadd failure..." - local check_getent_output - if check_getent_output=$(getent group docker 2>&1); then - check_getent_exit=0 - else - check_getent_exit=$? - fi - log_message "INFO" "Post-failure check: exit=$check_getent_exit, output='$check_getent_output'" - - if [ $check_getent_exit -eq 0 ]; then - log_message "WARNING" "Docker group exists despite groupadd failure, continuing..." - else - fail_with_remediation "Cannot create docker group" \ -"The docker group is required for Docker socket access. Please create it manually: - -1. Check if groupadd command is available: which groupadd -2. Check permissions: sudo -v -3. Manual group creation: sudo groupadd docker -4. Verify: getent group docker - -If groupadd fails, you may need to: -- Check system user/group database -- Use alternative: sudo addgroup docker (Debian/Ubuntu) -- Edit /etc/group manually (advanced users only)" - fi - fi - fi - - # Final verification that docker group exists - log_message "INFO" "Final verification of docker group existence..." - local final_getent_output - if final_getent_output=$(getent group docker 2>&1); then - final_getent_exit=0 - else - final_getent_exit=$? - fi - log_message "INFO" "Final getent result: exit=$final_getent_exit, output='$final_getent_output'" - - if [ $final_getent_exit -ne 0 ]; then - fail_with_remediation "Docker group verification failed" \ -"The docker group does not exist after creation attempts. This will cause Docker startup to fail. - -Please create the docker group manually and re-run the script: -1. sudo groupadd docker -2. Verify: getent group docker | grep docker -3. Re-run this script" - fi - - # Log group details for debugging - local docker_gid - docker_gid=$(echo "$final_getent_output" | cut -d: -f3) - log_message "INFO" "Docker group details: GID=$docker_gid" - - log_message "SUCCESS" "Docker group verified and ready (GID: $docker_gid)" - - # DEBUG: Mark end of docker group section - log_message "INFO" "=== Finished docker group creation ===" - - # Configure Docker daemon for LXC (VFS storage driver, cgroupfs) - log_message "INFO" "Configuring Docker daemon for LXC (VFS storage driver, cgroupfs)..." - - # Create docker configuration directory - sudo mkdir -p /etc/docker - - # Create daemon.json for LXC optimization - sudo tee /etc/docker/daemon.json > /dev/null < /dev/null <<'EOF' -[Unit] -Description=Docker Engine -After=network-online.target firewalld.service containerd.service -Wants=network-online.target -Requires=docker.socket - -[Service] -Type=notify -ExecStart=/usr/bin/dockerd --group docker -ExecReload=/bin/kill -s HUP $MAINPID -TimeoutSec=0 -RestartSec=2 -Restart=always -StartLimitBurst=3 -StartLimitInterval=60s -LimitNOFILE=infinity -LimitNPROC=infinity -LimitCORE=infinity -TasksMax=infinity -Delegate=yes -KillMode=process - -[Install] -WantedBy=multi-user.target -EOF - - sudo tee /etc/systemd/system/docker.socket > /dev/null <<'EOF' -[Unit] -Description=Docker Socket for the API - -[Socket] -ListenStream=/var/run/docker.sock -SocketMode=0660 -SocketUser=root -SocketGroup=docker - -[Install] -WantedBy=sockets.target -EOF - - sudo systemctl daemon-reload - - log_message "INFO" "Enabling Docker service to start on boot..." - if ! sudo systemctl enable docker; then - log_message "ERROR" "systemctl enable docker failed with exit code: $?" - fail_with_remediation "Failed to enable Docker service" \ -"Docker service could not be enabled to start on boot. Common causes: -1. Docker socket unit (docker.socket) has configuration errors -2. The docker group may not exist -3. Systemd unit file has syntax errors - -Check docker.socket status: - sudo systemctl status docker.socket --no-pager - -Verify docker group exists: - getent group docker - -Check systemd unit files: - sudo systemctl cat docker.socket - sudo systemctl cat docker.service" - fi - - log_message "INFO" "Starting Docker service (systemd)..." - # Start the service and capture exit code - if sudo systemctl start docker; then - start_exit=0 - else - start_exit=$? - fi - - # Give Docker a moment to start or fail - sleep 2 - - # Check if service is actually active - if ! sudo systemctl is-active docker --quiet; then - log_message "ERROR" "Docker service failed to start (systemctl start exit: $start_exit)" - log_message "INFO" "Checking docker.socket status..." - sudo systemctl status docker.socket --no-pager 2>&1 | head -20 || true - - log_message "INFO" "Checking docker.service status..." - sudo systemctl status docker.service --no-pager 2>&1 | head -30 || true - - log_message "INFO" "Checking Docker daemon logs..." - sudo journalctl -u docker --no-pager -n 30 2>&1 | head -50 || true - - log_message "INFO" "Checking Docker socket logs..." - sudo journalctl -u docker.socket --no-pager -n 20 2>&1 | head -30 || true - - fail_with_remediation "Failed to start Docker service" \ -"Docker service failed to start. Common causes: -1. Missing iptables (Docker static binaries require iptables v1.4+ for network bridge) -2. Docker daemon configuration error (check /etc/docker/daemon.json) -3. Storage driver issues (VFS may not be compatible) -4. Cgroup configuration problems -5. Port conflicts or resource limits - -Latest Docker daemon logs: -$(sudo journalctl -u docker --no-pager -n 30 2>&1 | tail -20) - -Check Docker configuration: - sudo cat /etc/docker/daemon.json - -Verify iptables is installed: - which iptables || echo 'iptables not found' - iptables --version 2>/dev/null || echo 'Cannot check version' - -Install iptables if missing: - # Debian/Ubuntu: sudo apt-get update && sudo apt-get install -y iptables - # RHEL/CentOS: sudo yum install -y iptables - # Alpine: sudo apk add iptables - -Verify docker group exists: - getent group docker - -Manual start attempt for debugging: - sudo dockerd --group docker --debug" - fi - ;; - - "openrc") - # Alpine OpenRC configuration - sudo tee /etc/init.d/docker > /dev/null <<'EOF' -#!/sbin/openrc-run -description="Docker Engine" -command="/usr/bin/dockerd" -command_args="--group docker" -pidfile="/run/docker.pid" -command_background=true - -depend() { - need net - after firewall -} -EOF - - sudo chmod +x /etc/init.d/docker - sudo rc-update add docker default - - log_message "INFO" "Starting Docker service (OpenRC)..." - if ! sudo rc-service docker start; then - log_message "ERROR" "rc-service docker start failed with exit code: $?" - fail_with_remediation "Failed to start Docker service (OpenRC)" \ -"Docker service failed to start under OpenRC. Common causes: -1. Missing iptables (Docker static binaries require iptables v1.4+ for network bridge) -2. Docker socket or port conflicts -3. Missing dependencies -4. Docker configuration errors - -Check OpenRC logs: - sudo rc-service docker status - sudo cat /var/log/docker.log 2>/dev/null || echo "No docker.log found" - -Verify iptables is installed: - which iptables || echo 'iptables not found' - iptables --version 2>/dev/null || echo 'Cannot check version' - -Install iptables if missing: - # Alpine: sudo apk add iptables - # Debian/Ubuntu: sudo apt-get update && sudo apt-get install -y iptables - # RHEL/CentOS: sudo yum install -y iptables - -Verify docker group exists: - getent group docker - -Manual start attempt: - sudo dockerd --group docker --debug" - fi - ;; - - "sysvinit") - # Traditional SysV init script - sudo tee /etc/init.d/docker > /dev/null <<'EOF' -#!/bin/bash -### BEGIN INIT INFO -# Provides: docker -# Required-Start: $local_fs $network $remote_fs -# Required-Stop: $local_fs $network $remote_fs -# Default-Start: 2 3 4 5 -# Default-Stop: 0 1 6 -# Short-Description: Docker Engine -# Description: Docker container runtime -### END INIT INFO - -DESC="Docker Engine" -DAEMON=/usr/bin/dockerd -DAEMON_ARGS="--group docker" -PIDFILE=/var/run/docker.pid -SCRIPTNAME=/etc/init.d/docker - -[ -x "$DAEMON" ] || exit 0 - -. /lib/lsb/init-functions - -case "$1" in - start) - log_daemon_msg "Starting $DESC" "docker" - start-stop-daemon --start --background --pidfile "$PIDFILE" \ - --exec "$DAEMON" -- $DAEMON_ARGS - log_end_msg $? - ;; - stop) - log_daemon_msg "Stopping $DESC" "docker" - start-stop-daemon --stop --pidfile "$PIDFILE" --retry 10 - log_end_msg $? - ;; - restart) - $0 stop - sleep 1 - $0 start - ;; - status) - status_of_proc -p "$PIDFILE" "$DAEMON" docker - ;; - *) - echo "Usage: $SCRIPTNAME {start|stop|restart|status}" - exit 3 - ;; -esac - -exit 0 -EOF - - sudo chmod +x /etc/init.d/docker - sudo update-rc.d docker defaults - - log_message "INFO" "Starting Docker service (SysV init)..." - if ! sudo service docker start; then - log_message "ERROR" "service docker start failed with exit code: $?" - fail_with_remediation "Failed to start Docker service (SysV init)" \ -"Docker service failed to start under SysV init. Common causes: -1. Missing iptables (Docker static binaries require iptables v1.4+ for network bridge) -2. Docker socket or port conflicts -3. Missing dependencies or configuration errors -4. The docker group may not exist or be accessible - -Check service status: - sudo service docker status - -Verify iptables is installed: - which iptables || echo 'iptables not found' - iptables --version 2>/dev/null || echo 'Cannot check version' - -Install iptables if missing: - # Debian/Ubuntu: sudo apt-get update && sudo apt-get install -y iptables - # RHEL/CentOS: sudo yum install -y iptables - # Alpine: sudo apk add iptables - -Verify docker group exists: - getent group docker - -Check for Docker logs: - sudo dockerd --group docker --debug 2>&1 | head -50" - fi - ;; - - *) - log_message "WARNING" "Unknown init system '$INIT_SYSTEM', trying systemd defaults" - sudo systemctl daemon-reload 2>/dev/null || true - sudo systemctl enable docker 2>/dev/null || true - sudo systemctl start docker 2>/dev/null || { - log_message "ERROR" "Failed to start Docker with unknown init system" - echo -e "${YELLOW}Please start Docker manually and re-run the script${NC}" - exit 1 - } - ;; - esac - - # Verify Docker is running - log_message "INFO" "Verifying Docker service..." - sleep 3 # Give Docker time to start - - if ! sudo docker info >/dev/null 2>&1; then - fail_with_remediation "Docker failed to start" \ - "Docker installation completed but service failed to start: -1. Check Docker logs: journalctl -u docker (systemd) or /var/log/docker.log -2. Verify iptables is installed (Docker static binaries require iptables v1.4+): - which iptables || echo 'iptables not found' - iptables --version 2>/dev/null || echo 'Cannot check version' -3. Install iptables if missing: - # Debian/Ubuntu: sudo apt-get update && sudo apt-get install -y iptables - # RHEL/CentOS: sudo yum install -y iptables - # Alpine: sudo apk add iptables -4. Verify configuration: sudo dockerd --debug -5. Manual start: sudo dockerd --group docker &" - fi - - # Verify Docker is using VFS storage driver - log_message "INFO" "Verifying Docker storage driver configuration..." - if sudo docker info 2>/dev/null | grep -q "Storage Driver: vfs"; then - log_message "SUCCESS" "Docker configured with VFS storage driver (LXC compatible)" - else - log_message "WARNING" "Docker is not using VFS storage driver. Checking current driver..." - sudo docker info 2>/dev/null | grep "Storage Driver:" || log_message "ERROR" "Could not determine storage driver" - log_message "WARNING" "LXC compatibility may be limited without VFS storage driver" - fi - - # Add current user to docker group for passwordless docker commands - log_message "INFO" "Adding current user to docker group..." - - # Security notice: docker group grants root-equivalent privileges - echo -e "${YELLOW}${BOLD}Security Notice:${NC} Adding your user to the 'docker' group grants root-equivalent privileges." - echo -e "${YELLOW}Any user in the docker group can run commands as root on the host system.${NC}" - echo -e "${YELLOW}Only proceed if you understand and accept this security risk.${NC}" - - read -r -p "$(echo -e "${YELLOW}Add $(whoami) to docker group? (Y/n): ${NC}")" -n 1 - echo - if [[ ! $REPLY =~ ^[Nn]$ ]]; then - sudo usermod -aG docker "$(whoami)" 2>/dev/null && \ - log_message "SUCCESS" "Added $(whoami) to docker group (log out and back in for changes)" - else - log_message "WARNING" "Skipping docker group addition. You will need to use sudo for docker commands." - echo -e "${YELLOW}Note: You can manually add yourself to docker group later with:${NC}" - echo -e "${CYAN} sudo usermod -aG docker $(whoami)${NC}" - echo -e "${YELLOW}Then log out and back in for changes to take effect.${NC}" - fi - - log_message "SUCCESS" "Docker Engine setup completed successfully" -} - -# ============================================================================== -# WALLARM NODE DEPLOYMENT -# ============================================================================== - -deploy_wallarm_node() { - log_message "INFO" "Deploying Wallarm filtering node..." - - # Load Wallarm Docker image (priority: Git Repositorys -> local dir -> current dir) - log_message "INFO" "Loading Wallarm Docker image..." - local image_loaded=false - - # 1. Try Git Repositorys download (primary source) - local git_image_file="wallarm-node-6.11.0-rc1.tar.gz" - if [ "$image_loaded" = "false" ]; then - log_message "INFO" "Attempting to download Wallarm image from Git Repositorys..." - if download_from_git "$GIT_WALLARM_IMAGE_URL" "$git_image_file" "Wallarm Docker image"; then - if verify_checksum "$git_image_file" "$GIT_WALLARM_CHECKSUM_URL" "Wallarm Docker image"; then - log_message "INFO" "Loading Wallarm image from Git Repositorys download..." - if gunzip -c "$git_image_file" | sudo docker load; then - log_message "SUCCESS" "Wallarm image loaded from Git Repositorys download" - image_loaded=true - else - log_message "ERROR" "Failed to load Wallarm image from Git Repositorys download" - fi - # Cleanup downloaded file - rm -f "$git_image_file" - else - log_message "WARNING" "Git Repositorys Wallarm image checksum verification failed" - rm -f "$git_image_file" - fi - fi - fi - - # 2. Check local images directory - if [ "$image_loaded" = "false" ] && [ -d "$LOCAL_IMAGE_DIR" ]; then - log_message "INFO" "Checking local images directory: $LOCAL_IMAGE_DIR" - local local_image="$LOCAL_IMAGE_DIR/wallarm-node-6.11.0-rc1.tar.gz" - local local_checksum="$LOCAL_IMAGE_DIR/wallarm-node-6.11.0-rc1.tar.gz.sha256" - - if [ -f "$local_image" ]; then - log_message "INFO" "Found local Wallarm image: $local_image" - if verify_checksum "$local_image" "$local_checksum" "local Wallarm image"; then - log_message "INFO" "Loading Wallarm image from local directory..." - if gunzip -c "$local_image" | sudo docker load; then - log_message "SUCCESS" "Wallarm image loaded from local directory" - image_loaded=true - else - log_message "ERROR" "Failed to load Wallarm image from local directory" - fi - else - log_message "WARNING" "Local Wallarm image checksum verification failed" - fi - fi - fi - - # 3. Check current directory for compressed image (tar.gz) - if [ "$image_loaded" = "false" ]; then - log_message "INFO" "Checking current directory for Wallarm image (tar.gz)..." - local gz_image - gz_image=$(ls wallarm-node-*.tar.gz 2>/dev/null | head -1) - if [ -n "$gz_image" ]; then - log_message "INFO" "Found compressed Wallarm image: $gz_image" - # Verify checksum if .sha256 file exists - local checksum_file="${gz_image}.sha256" - if [ -f "$checksum_file" ]; then - if ! verify_checksum "$gz_image" "$checksum_file" "Wallarm image"; then - log_message "WARNING" "Wallarm image checksum verification failed, but attempting load anyway" - fi - fi - log_message "INFO" "Loading compressed Wallarm image..." - if gunzip -c "$gz_image" | sudo docker load; then - log_message "SUCCESS" "Wallarm image loaded from compressed file" - image_loaded=true - else - log_message "ERROR" "Failed to load Wallarm image from $gz_image" - fi - fi - fi - - # 4. Check current directory for uncompressed image (tar) - existing fallback - if [ "$image_loaded" = "false" ]; then - log_message "INFO" "Checking current directory for Wallarm image (tar)..." - local tar_image - tar_image=$(ls wallarm-node-*.tar 2>/dev/null | head -1) - if [ -n "$tar_image" ]; then - log_message "INFO" "Found uncompressed Wallarm image: $tar_image" - if ! sudo docker load -i "$tar_image"; then - log_message "ERROR" "Failed to load Wallarm image from $tar_image" - else - log_message "SUCCESS" "Wallarm image loaded from uncompressed file" - image_loaded=true - fi - fi - fi - - - - # 6. Final fallback: no image available - if [ "$image_loaded" = "false" ]; then - fail_with_remediation "No Wallarm image available" \ - "Please provide a Wallarm Docker image using one of these methods: -1. Git Repositorys (primary): Ensure network access to $GIT_RAW_URL -2. Local images directory: Place wallarm-node-6.11.0-rc1.tar.gz and .sha256 in $LOCAL_IMAGE_DIR/ -3. Current directory: Place wallarm-node-*.tar.gz or wallarm-node-*.tar file in current directory - - Save for offline use: docker save $WALLARM_IMAGE_TARGET -o wallarm-node-latest.tar - -Re-run the script after providing the image." - fi - - # Ensure image is tagged with standard name (for consistency) - if [ "$image_loaded" = "true" ] && [ "$REGISTRY_REACHABLE" = "false" ]; then - # If we loaded from local file, tag the loaded image with standard name - local loaded_image_id - loaded_image_id=$(sudo docker images --format "{{.ID}}" --filter "dangling=false" | head -1) - if [ -n "$loaded_image_id" ]; then - sudo docker tag "$loaded_image_id" "$WALLARM_IMAGE_TARGET" - log_message "INFO" "Tagged loaded image as $WALLARM_IMAGE_TARGET" - fi - fi - -# Create nginx configuration -log_message "INFO" "Creating nginx configuration..." -local nginx_config="$INSTANCE_DIR/nginx.conf" - -# Start building the configuration file -sudo tee "$nginx_config" > /dev/null < /dev/null < /dev/null < /dev/null < /dev/null <> "\$LOG_FILE" - -# Stop existing container if running -sudo docker stop "\$CONTAINER_NAME" 2>/dev/null || true -sudo docker rm "\$CONTAINER_NAME" 2>/dev/null || true - -# Start new container -sudo docker run -d \\ - --name "\$CONTAINER_NAME" \\ - --restart always \\ - -p $INGRESS_PORT:80 \\ - -p $MONITORING_PORT:90 \\ - -e WALLARM_API_TOKEN="$WALLARM_TOKEN" \\ - -e WALLARM_API_HOST="$API_HOST" \\ - -e NGINX_BACKEND="$UPSTREAM_IP:$UPSTREAM_PORT" \\ - -e WALLARM_MODE="monitoring" \\ - -v "\$NGINX_CONFIG:/etc/nginx/http.d/default.conf:ro" \\ - $WALLARM_IMAGE_TARGET - -echo "\$(date) - Container started with ID: \$(sudo docker ps -q -f name=\$CONTAINER_NAME)" >> "\$LOG_FILE" - -# Verify container is running -sleep 3 -if sudo docker ps | grep -q "\$CONTAINER_NAME"; then - echo "\$(date) - Verification: Container is running" >> "\$LOG_FILE" - echo "Wallarm node \$CONTAINER_NAME started successfully" -else - echo "\$(date) - ERROR: Container failed to start" >> "\$LOG_FILE" - sudo docker logs "\$CONTAINER_NAME" >> "\$LOG_FILE" 2>&1 - exit 1 -fi -EOF - - sudo chmod +x "$start_script" - log_message "SUCCESS" "Start script created: $start_script" - - # Create init system service for automatic startup - log_message "INFO" "Creating service for automatic startup (init system: $INIT_SYSTEM)..." - - case "$INIT_SYSTEM" in - "systemd") - local service_file="/etc/systemd/system/wallarm-$INSTANCE_NAME.service" - sudo tee "$service_file" > /dev/null </dev/null || \ - log_message "WARNING" "Failed to enable systemd service (may already exist)" - ;; - - "openrc") - local service_file="/etc/init.d/wallarm-$INSTANCE_NAME" - sudo tee "$service_file" > /dev/null </dev/null || true - docker rm $INSTANCE_NAME 2>/dev/null || true - eend \$? -} -EOF - sudo chmod +x "$service_file" - sudo rc-update add "wallarm-$INSTANCE_NAME" default 2>/dev/null || \ - log_message "WARNING" "Failed to add OpenRC service (may already exist)" - ;; - - "sysvinit") - local service_file="/etc/init.d/wallarm-$INSTANCE_NAME" - sudo tee "$service_file" > /dev/null </dev/null || true - docker rm $INSTANCE_NAME 2>/dev/null || true - log_end_msg \$? - ;; - restart) - \$0 stop - sleep 2 - \$0 start - ;; - status) - if docker ps | grep -q "$INSTANCE_NAME"; then - echo "$INSTANCE_NAME is running" - exit 0 - else - echo "$INSTANCE_NAME is not running" - exit 1 - fi - ;; - *) - echo "Usage: \$0 {start|stop|restart|status}" - exit 3 - ;; -esac - -exit 0 -EOF - sudo chmod +x "$service_file" - sudo update-rc.d "wallarm-$INSTANCE_NAME" defaults 2>/dev/null || \ - log_message "WARNING" "Failed to add SysV init service (may already exist)" - ;; - - *) - log_message "WARNING" "Unknown init system, not creating service (manual start via $start_script)" - ;; - esac - - # Start the Wallarm node - log_message "INFO" "Starting Wallarm filtering node..." - if ! sudo "$start_script"; then - fail_with_remediation "Failed to start Wallarm node" \ - "Container failed to start. Check: -1. Docker logs: sudo docker logs $INSTANCE_NAME -2. Port conflicts: sudo ss -tlnp | grep ':$INGRESS_PORT\|:$MONITORING_PORT' -3. Docker status: sudo docker info -4. Manual start attempt: sudo $start_script" - fi - - log_message "SUCCESS" "Wallarm filtering node deployed successfully" - log_message "SUCCESS" " Container: $INSTANCE_NAME" - log_message "SUCCESS" " Ingress Port: $INGRESS_PORT" - log_message "SUCCESS" " Monitoring Port: $MONITORING_PORT" - log_message "SUCCESS" " Upstream: $UPSTREAM_IP:$UPSTREAM_PORT" - log_message "SUCCESS" " Config Directory: $INSTANCE_DIR" -} - -# ============================================================================== -# DEPLOYMENT VERIFICATION -# ============================================================================== - -verify_deployment() { - log_message "INFO" "Verifying Wallarm deployment..." - - # Check if container is running - log_message "INFO" "Checking if container is running..." - if ! sudo docker ps | grep -q "$INSTANCE_NAME"; then - fail_with_remediation "Wallarm container is not running" \ - "Container failed to start or crashed: -1. Check container logs: sudo docker logs $INSTANCE_NAME -2. Check Docker service: sudo systemctl status docker (or equivalent) -3. Manual start: sudo $INSTANCE_DIR/start.sh" - fi - log_message "SUCCESS" "Container is running" - - # Test ingress port - log_message "INFO" "Testing ingress port $INGRESS_PORT..." - if ! check_port_available "$INGRESS_PORT"; then - log_message "SUCCESS" "Ingress port $INGRESS_PORT is in use (as expected)" - else - log_message "WARNING" "Ingress port $INGRESS_PORT appears available (container may not be listening)" - fi - - # Test monitoring port - log_message "INFO" "Testing monitoring port $MONITORING_PORT..." - if ! check_port_available "$MONITORING_PORT"; then - log_message "SUCCESS" "Monitoring port $MONITORING_PORT is in use (as expected)" - else - log_message "WARNING" "Monitoring port $MONITORING_PORT appears available" - fi - - # Test health check endpoint - log_message "INFO" "Testing health check endpoint..." - local health_check_url="http://localhost:$INGRESS_PORT/health" - if curl -sf --connect-timeout 5 "$health_check_url" >/dev/null 2>&1; then - log_message "SUCCESS" "Health check endpoint responsive" - else - log_message "WARNING" "Health check endpoint not responsive (may need time to start)" - sleep 5 - if curl -sf --connect-timeout 5 "$health_check_url" >/dev/null 2>&1; then - log_message "SUCCESS" "Health check endpoint now responsive" - else - log_message "WARNING" "Health check endpoint still not responsive (check nginx config)" - fi - fi - - # Test handshake through filtering node - log_message "INFO" "Testing handshake through filtering node to upstream..." - local test_url="http://localhost:$INGRESS_PORT/" - if curl -sfI --connect-timeout 10 "$test_url" >/dev/null 2>&1; then - log_message "SUCCESS" "Handshake successful: filtering node can reach upstream" - else - log_message "WARNING" "Handshake failed (upstream may not be responding)" - log_message "INFO" "Checking if upstream is directly reachable..." - if timeout 5 bash -c "cat < /dev/null > /dev/tcp/$UPSTREAM_IP/$UPSTREAM_PORT" 2>/dev/null; then - log_message "ERROR" "Upstream is reachable but filtering node cannot proxy" - echo -e "${YELLOW}Possible nginx configuration issue. Check:${NC}" - echo -e "1. Container logs: sudo docker logs $INSTANCE_NAME" - echo -e "2. Nginx config: sudo docker exec $INSTANCE_NAME cat /etc/nginx/http.d/default.conf" - else - log_message "WARNING" "Upstream server is not reachable (as previously warned)" - fi - fi - - # Check Wallarm cloud synchronization - log_message "INFO" "Checking Wallarm cloud synchronization (this may take 30 seconds)..." - echo -e "${YELLOW}Note: Full synchronization with Wallarm cloud may take several minutes.${NC}" - echo -e "${YELLOW}You can check sync status in Wallarm Console.${NC}" - - # Quick test: check container logs for synchronization messages - if sudo docker logs "$INSTANCE_NAME" 2>&1 | tail -20 | grep -i "sync\|connected\|token" >/dev/null 2>&1; then - log_message "SUCCESS" "Wallarm node appears to be communicating with cloud" - else - log_message "WARNING" "No cloud synchronization messages in logs yet (may need time)" - fi - - log_message "SUCCESS" "Deployment verification completed" - echo -e "\n${GREEN}${BOLD}Verification Summary:${NC}" - echo -e " ${GREEN}✓${NC} Container running: $INSTANCE_NAME" - echo -e " ${GREEN}✓${NC} Ingress port: $INGRESS_PORT" - echo -e " ${GREEN}✓${NC} Monitoring port: $MONITORING_PORT" - echo -e " ${GREEN}✓${NC} Upstream: $UPSTREAM_IP:$UPSTREAM_PORT" - echo -e " ${GREEN}✓${NC} Cloud region: $CLOUD_REGION ($API_HOST)" -} - -# ============================================================================== -# MAIN FUNCTION -# ============================================================================== - -main() { - clear - echo -e "${BLUE}${BOLD}" - echo "╔══════════════════════════════════════════════════════════════╗" - echo "║ WALLARM DEPLOYMENT SCRIPT (Docker) - V1.3 ║" - echo "║ LXC-Optimized Filtering Node Deployment ║" - echo "╚══════════════════════════════════════════════════════════════╝${NC}" - echo -e "\n${YELLOW}Starting deployment at: $(date)${NC}" - - # Initialize logging - # Create logs directory if it doesn't exist - local log_dir="${HOME:-.}/logs" - if [ ! -d "$log_dir" ]; then - if ! mkdir -p "$log_dir"; then - echo -e "${YELLOW}Cannot create log directory $log_dir, falling back to current directory...${NC}" - log_dir="." - fi - fi - - LOG_FILE="$log_dir/wallarm-deployment.log" - if ! : > "$LOG_FILE"; then - echo -e "${RED}Cannot create log file at $LOG_FILE${NC}" - echo -e "${YELLOW}Falling back to current directory...${NC}" - LOG_FILE="./wallarm-deployment.log" - : > "$LOG_FILE" 2>/dev/null || true - fi - if ! chmod 644 "$LOG_FILE" 2>/dev/null; then - echo -e "${YELLOW}Warning: Could not set permissions on log file${NC}" - fi - - log_message "INFO" "=== Wallarm Deployment Started ===" - - # SSL security warning - if [ "$INSECURE_SSL" = "1" ]; then - log_message "WARNING" "SSL certificate validation is DISABLED (insecure). Set WALLARM_INSECURE_SSL=0 to enable validation." - fi - - # Phase 1: Verify preflight check - log_message "INFO" "=== PHASE 1: PREFLIGHT CHECK VERIFICATION ===" - verify_preflight_check - - # Phase 2: Configuration collection - log_message "INFO" "=== PHASE 2: CONFIGURATION COLLECTION ===" - select_cloud_region - collect_configuration - - # Phase 3: Docker engine setup (LXC optimized) - log_message "INFO" "=== PHASE 3: DOCKER ENGINE SETUP (LXC OPTIMIZED) ===" - setup_docker_engine - - # Phase 4: Deployment - log_message "INFO" "=== PHASE 4: DEPLOYMENT ===" - deploy_wallarm_node - - # Phase 5: Verification - log_message "INFO" "=== PHASE 5: VERIFICATION ===" - verify_deployment - - # Success message - log_message "SUCCESS" "=== WALLARM DEPLOYMENT COMPLETED SUCCESSFULLY ===" - echo -e "\n${GREEN}${BOLD}╔══════════════════════════════════════════════════════════════╗${NC}" - echo -e "${GREEN}${BOLD}║ WALLARM FILTERING NODE DEPLOYMENT SUCCESSFUL ║${NC}" - echo -e "${GREEN}${BOLD}╚══════════════════════════════════════════════════════════════╝${NC}" - echo -e "\n${CYAN}The Wallarm filtering node is now active and protecting your application.${NC}" - echo -e "${YELLOW}Full deployment log: $LOG_FILE${NC}" - echo -e "${YELLOW}Instance directory: $INSTANCE_DIR${NC}" - echo -e "\n${GREEN}To stop the node:${NC} sudo docker stop $INSTANCE_NAME" - echo -e "${GREEN}To restart:${NC} sudo $INSTANCE_DIR/start.sh" - echo -e "${GREEN}To view logs:${NC} sudo docker logs -f $INSTANCE_NAME" - echo -e "\n${MAGENTA}${BOLD}Deployment completed successfully!${NC}" - echo -e "\n${YELLOW}Important next steps:${NC}" - echo -e "1. Monitor sync status in Wallarm Console" - echo -e "2. Test attack detection with safe test: curl http://localhost:$INGRESS_PORT/?wallarm_test=1" - echo -e "3. Review logs periodically: sudo docker logs --tail 50 $INSTANCE_NAME" -} - -# ============================================================================== -# SCRIPT EXECUTION -# ============================================================================== - -# Ensure we're in bash -if [ -z "$BASH_VERSION" ]; then - echo "Error: This script must be run with bash" >&2 - exit 1 -fi - -# Run main function -main "$@" diff --git a/docker/wallarm-ct-reconfigure.sh b/docker/wallarm-ct-reconfigure.sh deleted file mode 100755 index d74b9ef..0000000 --- a/docker/wallarm-ct-reconfigure.sh +++ /dev/null @@ -1,268 +0,0 @@ -#!/bin/bash -# ============================================================================== -# WALLARM RECONFIGURATION SCRIPT - V1.1 (Docker deployment) -# ============================================================================== -# Purpose: Modify nginx configuration of an existing Wallarm Docker node -# Features: -# - Update set_real_ip_from (trusted proxy IPs/CIDRs) -# - Change wallarm_mode (monitoring/block) -# - Backup current config before changes -# - Interactive prompts with validation -# ============================================================================== - -# Script location and shared library (colors, logging, validation) -SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)" -# shellcheck source=./wallarm-lib.sh -source "$SCRIPT_DIR/wallarm-lib.sh" - -set -euo pipefail -trap early_error_handler ERR - -# ============================================================================== -# CHECK FOR SUDO / ROOT PRIVILEGES -# ============================================================================== -if [ "$EUID" -ne 0 ]; then - echo -e "${RED}${BOLD}ERROR:${NC} This script must be run with sudo or as root." - echo -e "${YELLOW}Please run: sudo $0${NC}" - exit 1 -fi - -# ============================================================================== -# CONFIGURATION -# ============================================================================== -INSTANCE_DIR="/opt" -INSTANCE_NAME="" - -# ============================================================================== -# FUNCTIONS -# ============================================================================== - -# Function to find the Wallarm instance directory -find_wallarm_instance() { - local dirs=() - while IFS= read -r dir; do - if [[ -d "$dir" && -f "$dir/nginx.conf" && -f "$dir/start.sh" ]]; then - dirs+=("$dir") - fi - done < <(find "$INSTANCE_DIR" -maxdepth 1 -type d -name "wallarm-*" 2>/dev/null) - - if [ ${#dirs[@]} -eq 0 ]; then - echo -e "${RED}No Wallarm instance found in $INSTANCE_DIR.${NC}" - exit 1 - elif [ ${#dirs[@]} -eq 1 ]; then - INSTANCE_DIR="${dirs[0]}" - INSTANCE_NAME=$(basename "$INSTANCE_DIR") - echo -e "${GREEN}Found instance: $INSTANCE_NAME${NC}" - else - echo -e "${YELLOW}Multiple Wallarm instances found:${NC}" - for i in "${!dirs[@]}"; do - echo "$((i+1)). $(basename "${dirs[$i]}")" - done - read -r -p "Select instance number: " choice - if [[ "$choice" =~ ^[0-9]+$ ]] && [ "$choice" -ge 1 ] && [ "$choice" -le ${#dirs[@]} ]; then - INSTANCE_DIR="${dirs[$((choice-1))]}" - INSTANCE_NAME=$(basename "$INSTANCE_DIR") - else - echo -e "${RED}Invalid selection.${NC}" - exit 1 - fi - fi -} - -# Validate IP/CIDR format -validate_proxy() { - local proxy="$1" - if [[ "$proxy" =~ ^[0-9]{1,3}\.[0-9]{1,3}\.[0-9]{1,3}\.[0-9]{1,3}(/[0-9]{1,2})?$ ]]; then - IFS='/' read -r ip cidr <<< "$proxy" - IFS='.' read -r o1 o2 o3 o4 <<< "$ip" - if [ "$o1" -le 255 ] && [ "$o2" -le 255 ] && [ "$o3" -le 255 ] && [ "$o4" -le 255 ]; then - if [ -z "$cidr" ] || ( [ "$cidr" -ge 0 ] && [ "$cidr" -le 32 ] ); then - return 0 - fi - fi - fi - return 1 -} - -# Parse current configuration to get existing values -parse_current_config() { - local config_file="$1" - # Get current wallarm_mode - current_mode=$(grep -oP 'wallarm_mode\s+\K\S+' "$config_file" | head -1) - # Get current set_real_ip_from lines - current_proxies=$(grep -oP 'set_real_ip_from\s+\K\S+' "$config_file") -} - -# Update configuration -update_config() { - local config_file="$1" - local backup_file="$config_file.backup.$(date +%Y%m%d_%H%M%S)" - - echo -e "${YELLOW}Backing up current config to $backup_file${NC}" - cp "$config_file" "$backup_file" - - # Read new values interactively - echo -e "\n${CYAN}${BOLD}Current set_real_ip_from entries:${NC}" - if [ -n "$current_proxies" ]; then - echo "$current_proxies" | while read -r proxy; do - echo " $proxy" - done - else - echo " (none)" - fi - - echo -e "\n${YELLOW}Do you want to change the trusted proxy IPs/CIDRs? (y/N)${NC}" - read -r change_proxy - if [[ "$change_proxy" =~ ^[Yy]$ ]]; then - echo -e "${YELLOW}Enter new trusted proxy IPs/CIDRs (space-separated, or empty to remove all):${NC}" - read -r new_proxies_input - new_proxies=() - if [[ -n "$new_proxies_input" ]]; then - IFS=' ' read -ra proxy_array <<< "$new_proxies_input" - for proxy in "${proxy_array[@]}"; do - proxy=$(echo "$proxy" | xargs) - if validate_proxy "$proxy"; then - new_proxies+=("$proxy") - else - echo -e "${RED}Invalid format: $proxy. Skipping.${NC}" - fi - done - fi - else - # Keep existing - while read -r proxy; do - new_proxies+=("$proxy") - done <<< "$current_proxies" - fi - - echo -e "\n${CYAN}${BOLD}Current wallarm_mode:${NC} ${current_mode:-not set}" - echo -e "${YELLOW}Do you want to change the wallarm_mode? (y/N)${NC}" - read -r change_mode - if [[ "$change_mode" =~ ^[Yy]$ ]]; then - echo -e "${YELLOW}Select new mode:${NC}" - echo "1. monitoring" - echo "2. block" - read -r mode_choice - case "$mode_choice" in - 1) new_mode="monitoring" ;; - 2) new_mode="block" ;; - *) echo -e "${RED}Invalid choice, keeping current mode.${NC}"; new_mode="$current_mode" ;; - esac - else - new_mode="$current_mode" - fi - - # Now rebuild the config file - # We'll create a temporary file and replace the original - temp_config=$(mktemp) - - # Read original config line by line and modify as needed - in_server_block=false - while IFS= read -r line; do - # Detect start of server block - if [[ "$line" =~ ^[[:space:]]*server[[:space:]]*{ ]]; then - in_server_block=true - fi - - # If we are inside server block, we may need to replace lines - if $in_server_block; then - # Replace set_real_ip_from lines with new ones - if [[ "$line" =~ ^[[:space:]]*set_real_ip_from[[:space:]]+ ]]; then - # Skip original set_real_ip_from lines (will be added later) - continue - fi - # Replace wallarm_mode line - if [[ "$line" =~ ^[[:space:]]*wallarm_mode[[:space:]]+ ]]; then - # We'll add new line after processing all lines - continue - fi - fi - - # Write line to temp file - echo "$line" >> "$temp_config" - - # After writing the line, if we are at the end of the server block, we may need to insert new directives - if $in_server_block && [[ "$line" =~ ^[[:space:]]*}$ ]]; then - in_server_block=false - # Insert the new set_real_ip_from lines just before the closing brace - if [ ${#new_proxies[@]} -gt 0 ]; then - for proxy in "${new_proxies[@]}"; do - echo " set_real_ip_from $proxy;" >> "$temp_config" - done - echo " real_ip_header X-Real-IP;" >> "$temp_config" - echo " real_ip_recursive on;" >> "$temp_config" - elif [ -n "$current_proxies" ]; then - # If we removed all proxies, we should also remove the real_ip_header and real_ip_recursive lines - # But that's tricky; we'll just not add them, but they might remain in the file if they were separate. - # Simpler: after rebuild, we need to ensure they are not there. We'll do a final cleanup. - echo -e "${YELLOW}Removing all set_real_ip_from directives.${NC}" - fi - # Insert new wallarm_mode - if [ -n "$new_mode" ]; then - echo " wallarm_mode $new_mode;" >> "$temp_config" - fi - fi - done < "$config_file" - - # After building the temp file, we need to ensure any leftover real_ip_header lines are removed if no proxies. - if [ ${#new_proxies[@]} -eq 0 ]; then - # Remove lines containing real_ip_header and real_ip_recursive if they exist - sed -i '/real_ip_header/d' "$temp_config" - sed -i '/real_ip_recursive/d' "$temp_config" - fi - - # Replace the original config with the new one - mv "$temp_config" "$config_file" - chmod 644 "$config_file" - - echo -e "${GREEN}Configuration updated.${NC}" -} - -restart_container() { - local container_name="$1" - echo -e "${YELLOW}Restarting container $container_name to apply changes...${NC}" - if docker ps --format "{{.Names}}" | grep -q "^$container_name$"; then - docker restart "$container_name" - echo -e "${GREEN}Container restarted.${NC}" - else - echo -e "${RED}Container $container_name is not running. Starting it...${NC}" - if [ -f "$INSTANCE_DIR/start.sh" ]; then - "$INSTANCE_DIR/start.sh" - else - echo -e "${RED}No start script found. Please start manually: docker start $container_name${NC}" - exit 1 - fi - fi -} - -main() { - echo -e "${BLUE}${BOLD}" - echo "╔══════════════════════════════════════════════════════════════╗" - echo "║ WALLARM RECONFIGURATION SCRIPT - V1.0 ║" - echo "║ Modify nginx.conf (trusted proxies / mode) ║" - echo "╚══════════════════════════════════════════════════════════════╝${NC}" - - find_wallarm_instance - - local config_file="$INSTANCE_DIR/nginx.conf" - if [ ! -f "$config_file" ]; then - echo -e "${RED}Configuration file not found: $config_file${NC}" - exit 1 - fi - - parse_current_config "$config_file" - update_config "$config_file" - - echo -e "${YELLOW}Do you want to restart the container now? (Y/n)${NC}" - read -r restart_choice - if [[ ! "$restart_choice" =~ ^[Nn]$ ]]; then - restart_container "$INSTANCE_NAME" - else - echo -e "${YELLOW}Changes will take effect after container restart.${NC}" - echo -e "You can restart later with: docker restart $INSTANCE_NAME" - fi - - echo -e "\n${GREEN}${BOLD}Reconfiguration completed.${NC}" -} - -main "$@" \ No newline at end of file diff --git a/docker/wallarm-ct-uninstall.sh b/docker/wallarm-ct-uninstall.sh deleted file mode 100755 index 9c9a383..0000000 --- a/docker/wallarm-ct-uninstall.sh +++ /dev/null @@ -1,512 +0,0 @@ -#!/bin/bash -# ============================================================================== -# WALLARM UNINSTALL SCRIPT - V1.1 (Docker deployment) -# ============================================================================== -# Purpose: Safely remove a Wallarm Docker node and cleanup Docker installation -# Features: -# - Interactive confirmation with safety checks -# - Stops and removes Wallarm container and image -# - Removes Docker service files created by deployment script -# - Optional cleanup of Docker binaries (if no other containers exist) -# - Preserves user data and logs (with option to remove) -# - DAU-friendly warnings and confirmations -# ============================================================================== - -# Script location and shared library (colors, logging, validation) -SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)" -# shellcheck source=./wallarm-lib.sh -source "$SCRIPT_DIR/wallarm-lib.sh" - -# Strict error handling -set -euo pipefail -trap early_error_handler ERR - -# ============================================================================== -# FUNCTIONS -# ============================================================================== - -# Ask for confirmation -confirm() { - local prompt="$1" - local default="${2:-n}" - local options="[y/N]" - - if [ "$default" = "y" ]; then - options="[Y/n]" - fi - - echo -e -n "${YELLOW}${prompt} ${options}${NC} " - read -r response - - case "$response" in - [yY][eE][sS]|[yY]) - return 0 - ;; - [nN][oO]|[nN]) - return 1 - ;; - "") - # Use default - if [ "$default" = "y" ]; then - return 0 - else - return 1 - fi - ;; - *) - # Invalid input, treat as no - return 1 - ;; - esac -} - -# Check if running as root or with sudo -check_sudo() { - if [ "$EUID" -ne 0 ]; then - log_message "INFO" "This script requires sudo privileges" - if ! sudo -n true 2>/dev/null; then - log_message "INFO" "Please enter your sudo password when prompted" - sudo -v - fi - fi -} - -# Detect init system -detect_init_system() { - if command -v systemctl >/dev/null 2>&1 && systemctl --version >/dev/null 2>&1; then - echo "systemd" - elif [ -d /run/openrc ]; then - echo "openrc" - elif [ -f /etc/init.d/docker ]; then - echo "sysvinit" - else - echo "unknown" - fi -} - -# Check if Docker is installed and running -check_docker() { - if ! command -v docker >/dev/null 2>&1; then - log_message "WARNING" "Docker command not found" - return 1 - fi - - if ! sudo docker info >/dev/null 2>&1; then - log_message "WARNING" "Docker is not running" - return 1 - fi - - return 0 -} - -# Check for other Docker containers (besides Wallarm) -check_other_containers() { - local wallarm_container="wallarm-node" - local all_containers - all_containers=$(sudo docker ps -a -q 2>/dev/null | wc -l) - local wallarm_containers - wallarm_containers=$(sudo docker ps -a --filter "name=${wallarm_container}" -q 2>/dev/null | wc -l) - - if [ "$all_containers" -gt "$wallarm_containers" ]; then - log_message "WARNING" "Found other Docker containers besides Wallarm" - sudo docker ps -a --format "table {{.Names}}\t{{.Image}}\t{{.Status}}" | grep -v "$wallarm_container" || true - return 0 # Other containers exist - fi - - return 1 # Only Wallarm containers or no containers -} - -# Stop and remove Wallarm container -remove_wallarm_container() { - local container_name="wallarm-node" - - log_message "INFO" "Looking for Wallarm container..." - - if sudo docker ps -a --filter "name=${container_name}" --format "{{.Names}}" | grep -q "${container_name}"; then - log_message "INFO" "Found Wallarm container: ${container_name}" - - # Stop container if running - if sudo docker ps --filter "name=${container_name}" --filter "status=running" --format "{{.Names}}" | grep -q "${container_name}"; then - log_message "INFO" "Stopping Wallarm container..." - sudo docker stop "${container_name}" || { - log_message "WARNING" "Failed to stop container, attempting force stop" - sudo docker kill "${container_name}" 2>/dev/null || true - } - fi - - # Remove container - log_message "INFO" "Removing Wallarm container..." - sudo docker rm -f "${container_name}" 2>/dev/null || { - log_message "WARNING" "Failed to remove container, it may already be removed" - } - - log_message "SUCCESS" "Wallarm container removed" - else - log_message "INFO" "No Wallarm container found" - fi -} - -# Remove Wallarm image -remove_wallarm_image() { - local image_name="wallarm/node" - - log_message "INFO" "Looking for Wallarm image..." - - if sudo docker images --format "{{.Repository}}" | grep -q "^${image_name}"; then - log_message "INFO" "Found Wallarm image: ${image_name}" - - # Check if image is used by any containers - local used_by - used_by=$(sudo docker ps -a --filter "ancestor=${image_name}" -q 2>/dev/null | wc -l) - - if [ "$used_by" -gt 0 ]; then - log_message "WARNING" "Image ${image_name} is still in use by containers, skipping removal" - return - fi - - # Remove image - log_message "INFO" "Removing Wallarm image..." - sudo docker rmi "${image_name}:latest" 2>/dev/null || { - log_message "WARNING" "Failed to remove image, it may be in use or already removed" - } - - # Also try to remove by ID if tag removal failed - local image_id - image_id=$(sudo docker images --filter "reference=${image_name}" --format "{{.ID}}" 2>/dev/null | head -1) - if [ -n "$image_id" ]; then - sudo docker rmi -f "$image_id" 2>/dev/null || true - fi - - log_message "SUCCESS" "Wallarm image removed" - else - log_message "INFO" "No Wallarm image found" - fi -} - -# Remove Docker service files (created by deployment script) -remove_docker_service_files() { - local init_system - init_system=$(detect_init_system) - - log_message "INFO" "Removing Docker service files for init system: ${init_system}" - - case "$init_system" in - "systemd") - # Stop and disable Docker service - if sudo systemctl is-active docker --quiet 2>/dev/null; then - log_message "INFO" "Stopping Docker service..." - sudo systemctl stop docker 2>/dev/null || true - fi - - if sudo systemctl is-enabled docker --quiet 2>/dev/null; then - log_message "INFO" "Disabling Docker service..." - sudo systemctl disable docker 2>/dev/null || true - fi - - # Remove systemd unit files (if they exist and were created by our script) - local systemd_files=( - "/etc/systemd/system/docker.socket" - "/etc/systemd/system/docker.service" - "/usr/lib/systemd/system/docker.socket" - "/usr/lib/systemd/system/docker.service" - ) - - for file in "${systemd_files[@]}"; do - if [ -f "$file" ]; then - log_message "INFO" "Removing systemd file: $file" - sudo rm -f "$file" - fi - done - - sudo systemctl daemon-reload 2>/dev/null || true - ;; - - "openrc") - # Stop and remove from runlevels - if sudo rc-service docker status 2>/dev/null | grep -q "started"; then - log_message "INFO" "Stopping Docker service (OpenRC)..." - sudo rc-service docker stop 2>/dev/null || true - fi - - if [ -f /etc/init.d/docker ]; then - log_message "INFO" "Removing OpenRC init script..." - sudo rc-update del docker default 2>/dev/null || true - sudo rm -f /etc/init.d/docker - fi - ;; - - "sysvinit") - # Stop service - if [ -f /etc/init.d/docker ]; then - log_message "INFO" "Stopping Docker service (SysV init)..." - sudo service docker stop 2>/dev/null || true - - # Remove from startup - if command -v update-rc.d >/dev/null 2>&1; then - sudo update-rc.d -f docker remove 2>/dev/null || true - elif command -v chkconfig >/dev/null 2>&1; then - sudo chkconfig --del docker 2>/dev/null || true - fi - - log_message "INFO" "Removing SysV init script..." - sudo rm -f /etc/init.d/docker - fi - ;; - - *) - log_message "WARNING" "Unknown init system, skipping service file cleanup" - ;; - esac - - log_message "SUCCESS" "Docker service files removed" -} - -# Remove Docker binaries (optional, only if no other containers exist) -remove_docker_binaries() { - local docker_binaries=( - "/usr/bin/docker" - "/usr/bin/dockerd" - "/usr/bin/docker-init" - "/usr/bin/docker-proxy" - "/usr/bin/containerd" - "/usr/bin/containerd-shim" - "/usr/bin/containerd-shim-runc-v1" - "/usr/bin/containerd-shim-runc-v2" - "/usr/bin/runc" - ) - - log_message "INFO" "Checking Docker binaries..." - - local binaries_found=0 - for binary in "${docker_binaries[@]}"; do - if [ -f "$binary" ]; then - binaries_found=$((binaries_found + 1)) - fi - done - - if [ "$binaries_found" -eq 0 ]; then - log_message "INFO" "No Docker binaries found in /usr/bin/" - return - fi - - if confirm "Remove Docker binaries from /usr/bin/? (Only do this if Docker was installed by wallarm-ct-deploy.sh)" "n"; then - log_message "WARNING" "Removing Docker binaries..." - - for binary in "${docker_binaries[@]}"; do - if [ -f "$binary" ]; then - log_message "INFO" "Removing $binary" - sudo rm -f "$binary" - fi - done - - # Also remove CNI plugins if they exist - if [ -d "/opt/cni/bin" ]; then - log_message "INFO" "Removing CNI plugins from /opt/cni/bin/" - sudo rm -rf /opt/cni/bin/* - fi - - log_message "SUCCESS" "Docker binaries removed" - else - log_message "INFO" "Skipping Docker binary removal" - fi -} - -# Remove Docker configuration files -remove_docker_config() { - local config_files=( - "/etc/docker/daemon.json" - "/etc/containerd/config.toml" - "/var/lib/docker" # Warning: This removes all Docker data! - ) - - log_message "INFO" "Checking Docker configuration files..." - - # Only remove daemon.json if it was created by our script - if [ -f "/etc/docker/daemon.json" ]; then - log_message "INFO" "Found /etc/docker/daemon.json" - if grep -q "storage-driver.*vfs" "/etc/docker/daemon.json" 2>/dev/null; then - log_message "INFO" "This appears to be the VFS configuration from wallarm-ct-deploy.sh" - if confirm "Remove /etc/docker/daemon.json?" "n"; then - sudo rm -f "/etc/docker/daemon.json" - log_message "SUCCESS" "Docker configuration removed" - fi - else - log_message "WARNING" "/etc/docker/daemon.json doesn't appear to be from wallarm-ct-deploy.sh, skipping" - fi - fi - - # Warn about Docker data directory - if [ -d "/var/lib/docker" ]; then - log_message "WARNING" "/var/lib/docker contains Docker data (images, containers, volumes)" - log_message "WARNING" "Removing this directory will delete ALL Docker data on the system" - if confirm "Remove /var/lib/docker? (WARNING: Deletes ALL Docker data)" "n"; then - log_message "WARNING" "Removing /var/lib/docker - this may take a while..." - sudo rm -rf /var/lib/docker - log_message "SUCCESS" "Docker data directory removed" - fi - fi -} - -# Remove docker group (if empty) -remove_docker_group() { - log_message "INFO" "Checking docker group..." - - if getent group docker >/dev/null; then - local group_users - group_users=$(getent group docker | cut -d: -f4) - - if [ -z "$group_users" ]; then - log_message "INFO" "Docker group exists and has no users" - if confirm "Remove docker group?" "n"; then - sudo groupdel docker 2>/dev/null || { - log_message "WARNING" "Failed to remove docker group (may be system group)" - } - log_message "SUCCESS" "Docker group removed" - fi - else - log_message "WARNING" "Docker group has users: $group_users" - log_message "INFO" "Skipping docker group removal (users still present)" - fi - else - log_message "INFO" "Docker group not found" - fi -} - -# Remove Wallarm-specific files and logs -remove_wallarm_files() { - local wallarm_files=( - "$HOME/wallarm-start.sh" - "$HOME/wallarm-stop.sh" - "$HOME/wallarm-status.sh" - "/usr/local/bin/wallarm-start" - "/usr/local/bin/wallarm-stop" - "/usr/local/bin/wallarm-status" - ) - - log_message "INFO" "Removing Wallarm scripts and logs..." - - # Remove scripts - for file in "${wallarm_files[@]}"; do - if [ -f "$file" ]; then - log_message "INFO" "Removing $file" - sudo rm -f "$file" - fi - done - - # Remove log directory (if empty) - local log_dir="$HOME/logs" - if [ -d "$log_dir" ]; then - log_message "INFO" "Found log directory: $log_dir" - if [ -z "$(ls -A "$log_dir" 2>/dev/null)" ]; then - log_message "INFO" "Log directory is empty, removing..." - sudo rmdir "$log_dir" 2>/dev/null || true - else - log_message "INFO" "Log directory contains files, preserving..." - fi - fi - - # Remove .env file if it exists - if [ -f ".env" ]; then - log_message "INFO" "Removing .env file..." - rm -f ".env" - fi - - log_message "SUCCESS" "Wallarm files cleaned up" -} - -# Main uninstall function -main() { - echo -e "${CYAN}${BOLD}" - echo "╔══════════════════════════════════════════════════════════════╗" - echo "║ WALLARM UNINSTALLATION ║" - echo "╚══════════════════════════════════════════════════════════════╝" - echo -e "${NC}" - - echo -e "${YELLOW}This script will remove Wallarm filtering node and cleanup Docker installation.${NC}" - echo -e "${YELLOW}You will be asked for confirmation before each destructive operation.${NC}" - echo "" - - if ! confirm "Do you want to continue with the uninstallation?" "n"; then - log_message "INFO" "Uninstallation cancelled by user" - exit 0 - fi - - # Check sudo - check_sudo - - # Check Docker - if check_docker; then - log_message "INFO" "Docker is installed and running" - - # Check for other containers - if check_other_containers; then - log_message "WARNING" "Other Docker containers exist on this system" - echo -e "${YELLOW}Warning: Removing Docker may affect other containers.${NC}" - echo -e "${YELLOW}Consider leaving Docker installed if you need it for other purposes.${NC}" - echo "" - fi - else - log_message "WARNING" "Docker is not running or not installed" - fi - - # Step 1: Remove Wallarm container and image - echo "" - echo -e "${CYAN}${BOLD}Step 1: Remove Wallarm container and image${NC}" - if confirm "Stop and remove Wallarm container and image?" "y"; then - remove_wallarm_container - remove_wallarm_image - else - log_message "INFO" "Skipping Wallarm container/image removal" - fi - - # Step 2: Remove Docker service files - echo "" - echo -e "${CYAN}${BOLD}Step 2: Remove Docker service files${NC}" - if confirm "Remove Docker service files (systemd/OpenRC/SysV init scripts)?" "y"; then - remove_docker_service_files - else - log_message "INFO" "Skipping Docker service file removal" - fi - - # Step 3: Optional Docker binary removal - echo "" - echo -e "${CYAN}${BOLD}Step 3: Docker binaries and configuration${NC}" - remove_docker_binaries - remove_docker_config - - # Step 4: Remove docker group - echo "" - echo -e "${CYAN}${BOLD}Step 4: System cleanup${NC}" - remove_docker_group - - # Step 5: Remove Wallarm files - echo "" - echo -e "${CYAN}${BOLD}Step 5: Wallarm files and logs${NC}" - if confirm "Remove Wallarm scripts and log files?" "y"; then - remove_wallarm_files - else - log_message "INFO" "Skipping Wallarm file cleanup" - fi - - # Final message - echo "" - echo -e "${GREEN}${BOLD}╔══════════════════════════════════════════════════════════════╗${NC}" - echo -e "${GREEN}${BOLD}║ UNINSTALLATION COMPLETE ║${NC}" - echo -e "${GREEN}${BOLD}╚══════════════════════════════════════════════════════════════╝${NC}" - echo "" - echo -e "${GREEN}Wallarm filtering node has been removed.${NC}" - echo "" - echo -e "${YELLOW}Note:${NC}" - echo -e " • Docker may still be installed on your system" - echo -e " • Docker data in /var/lib/docker may still exist" - echo -e " • User may still be in docker group (check with 'groups')" - echo "" - echo -e "To completely remove Docker, you may need to:" - echo -e " 1. Remove Docker package using your system's package manager" - echo -e " 2. Remove /var/lib/docker directory (contains all Docker data)" - echo -e " 3. Remove user from docker group: sudo gpasswd -d \$USER docker" - echo "" -} - -# Run main function -main "$@" \ No newline at end of file diff --git a/docker/wallarm-docker.sh b/docker/wallarm-docker.sh deleted file mode 100644 index df79efa..0000000 --- a/docker/wallarm-docker.sh +++ /dev/null @@ -1,91 +0,0 @@ -#!/bin/bash -# ============================================================================== -# Wallarm Docker Node Manager - Unified single-script manager -# ============================================================================== -# Delegates to the individual docker/* scripts for preflight, deployment, -# reconfiguration, and removal — providing a single entry point matching the -# native/wallarm-native.sh command interface. -# -# Commands: -# --preflight Run preflight checks only (no installation). -# --install Interactive deployment of a Wallarm Docker node. -# --config Reconfigure an existing Docker node. -# --remove Remove a Docker node completely. -# --status Show running Wallarm containers. -# --help|-h Show help. -# ============================================================================== - -set -euo pipefail - -SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)" - -# Shell script files this wrapper delegates to (must be in the same directory) -CHECK_SCRIPT="${SCRIPT_DIR}/wallarm-ct-check.sh" -DEPLOY_SCRIPT="${SCRIPT_DIR}/wallarm-ct-deploy.sh" -RECONF_SCRIPT="${SCRIPT_DIR}/wallarm-ct-reconfigure.sh" -REMOVE_SCRIPT="${SCRIPT_DIR}/wallarm-ct-uninstall.sh" - -show_help() { - cat <&2 - echo " Run setup.sh first to download all deployment scripts." >&2 - exit 1 - fi -} - -case "${1:-}" in - --preflight) - require_script "$CHECK_SCRIPT" "Preflight (wallarm-ct-check.sh)" - exec "$CHECK_SCRIPT" "${@:2}" - ;; - --install) - require_script "$DEPLOY_SCRIPT" "Deploy (wallarm-ct-deploy.sh)" - exec sudo "$DEPLOY_SCRIPT" "${@:2}" - ;; - --config) - require_script "$RECONF_SCRIPT" "Reconfigure (wallarm-ct-reconfigure.sh)" - exec sudo "$RECONF_SCRIPT" "${@:2}" - ;; - --remove) - require_script "$REMOVE_SCRIPT" "Uninstall (wallarm-ct-uninstall.sh)" - exec sudo "$REMOVE_SCRIPT" "${@:2}" - ;; - --status) - echo "Wallarm Docker Nodes:" - if command -v docker >/dev/null 2>&1; then - docker ps --filter "name=wallarm-" \ - --format "table {{.Names}}\t{{.Status}}\t{{.Ports}}" 2>/dev/null || true - else - echo " Docker is not installed or not in PATH." - fi - ;; - --help|-h) - show_help - ;; - *) - show_help - exit 1 - ;; -esac diff --git a/native/wallarm-native.sh b/native/wallarm-native.sh deleted file mode 100755 index 6bd2f50..0000000 --- a/native/wallarm-native.sh +++ /dev/null @@ -1,498 +0,0 @@ -#!/bin/bash -# ============================================================================== -# Wallarm Native Node Manager - Install, Configure, Remove, and Control -# ============================================================================== -# Unified single-script manager for the Wallarm Native Node (connector mode, -# NO Docker). Manages multiple isolated nodes under ${BASE_DIR}/nodes with a -# systemd template unit (wallarm-node@.service). -# -# NOTE: This targets the Wallarm Native Node product (go-node, connector-server -# mode, all-in-one installer) - distinct from the NGINX-module based native -# deployment in ./wallarm-ct-deploy.sh. -# -# Commands: -# --preflight Run preflight checks only (no installation). -# --install Interactive installation of one or more nodes (parallel). -# --config Update an existing node's configuration. -# Options: --node NAME --address IP:PORT [--token TOKEN] [--labels LABELS] -# --remove Remove a node completely. -# Options: --node NAME -# --status [NODE] Show systemd status for a node, or all nodes. -# --help|-h Show help. -# ============================================================================== - -set -euo pipefail - -# Script location and shared library (logging, detection, connectivity, validation) -SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)" -# shellcheck source=./wallarm-lib.sh -source "$SCRIPT_DIR/wallarm-lib.sh" - -# --- Constants --- -BASE_DIR="/opt/wallarm" -NODES_DIR="${BASE_DIR}/nodes" -SYSTEMD_TEMPLATE="/etc/systemd/system/wallarm-node@.service" - -# Wallarm Native Node all-in-one installer (latest, x86_64 by default) -# Override WALLARM_INSTALLER_URL to pin a version; WALLARM_INSTALLER_ARCH to -# select the architecture suffix. -INSTALLER_BASE_URL="https://repo.wallarm.com/linux/wallarm-native-node/latest/all-in-one" -INSTALLER_ARCH="${WALLARM_INSTALLER_ARCH:-x86_64}" -INSTALLER_URL="${WALLARM_INSTALLER_URL:-${INSTALLER_BASE_URL}/wallarm-native-node-aio-${INSTALLER_ARCH}-latest.sh}" - -# Wallarm cloud endpoints (for connectivity checks) -EU_DATA_NODES=("api.wallarm.com" "node-data0.eu1.wallarm.com" "node-data1.eu1.wallarm.com") -US_DATA_NODES=("us1.api.wallarm.com" "node-data0.us1.wallarm.com" "node-data1.us1.wallarm.com") - -# Cloud region selection (populated by preflight, used by select_cloud_region) -US_CLOUD_REACHABLE="false" -EU_CLOUD_REACHABLE="false" -CLOUD_REGION="" -API_HOST="" - -# --- Helper functions --- -log() { echo ">>> $*"; } -err() { echo "!!! $*" >&2; } - -check_root() { - if [[ $EUID -ne 0 ]]; then - err "This script must be run as root (for systemd and /opt write access)." - exit 1 - fi -} - -ensure_dirs() { - mkdir -p "${NODES_DIR}" -} - -generate_systemd_template() { - if [[ ! -f "${SYSTEMD_TEMPLATE}" ]]; then - log "Creating systemd template: ${SYSTEMD_TEMPLATE}" - cat > "${SYSTEMD_TEMPLATE}" < "${env_file}" <= 2GB free on the nodes volume) - local avail_kb - avail_kb=$(df -k "$BASE_DIR" 2>/dev/null | awk 'NR==2 {print $4}' || true) - if [[ -n "$avail_kb" ]] && (( avail_kb < 2097152 )); then - err "Preflight failed: insufficient disk space on $BASE_DIR (need >= 2GB free)." - failed=1 - fi - - # 8. Memory (>= 2GB recommended; warning only) - if command_exists free; then - local mem_mb - mem_mb=$(free -m 2>/dev/null | awk '/Mem:/ {print $2}') - if [[ -n "$mem_mb" ]] && (( mem_mb < 2048 )); then - err "Warning: only ${mem_mb}MB RAM detected (2GB+ recommended)." - fi - fi - - if [[ $failed -ne 0 ]]; then - err "Preflight check FAILED. Resolve the issues above and re-run." - return 1 - fi - - log "Preflight checks passed." - return 0 -} - -# Validate a listen address (IP:PORT) and check its port is free -check_listen_port() { - local address="$1" - local port="${address##*:}" - if [[ ! "$port" =~ ^[0-9]+$ ]] || (( port < 1 || port > 65535 )); then - err "Invalid listen address (expected IP:PORT): $address" - return 1 - fi - if ! check_port_available "$port"; then - err "Listen port $port (for $address) is already in use." - return 1 - fi - return 0 -} - -# --- Core actions --- -install_single_node() { - local node_name="$1" - local listen_address="$2" - local api_token="$3" - local api_host="$4" - local labels="${5:-group=${node_name}}" - - local work_dir="${NODES_DIR}/${node_name}" - local installer_path="${work_dir}/wallarm-native-node-aio.sh" - - log "[${node_name}] Installing (listening on ${listen_address})..." - - mkdir -p "${work_dir}/etc" "${work_dir}/var/log" "${work_dir}/var/run" - - # 1. Write config - cat > "${work_dir}/etc/go-node.yaml" < "${work_dir}/install.log" 2>&1; then - log "[${node_name}] Installation successful." - # Enable and start the systemd service - systemctl enable "wallarm-node@${node_name}" 2>/dev/null || true - systemctl start "wallarm-node@${node_name}" - log "[${node_name}] Service started (systemctl status wallarm-node@${node_name})" - else - err "[${node_name}] Installation failed. Check ${work_dir}/install.log" - return 1 - fi -} - -cmd_preflight() { - check_root - echo "" - if run_preflight; then - log "Preflight passed - system ready for --install." - exit 0 - else - exit 1 - fi -} - -cmd_install() { - check_root - if ! run_preflight; then - exit 1 - fi - ensure_dirs - generate_systemd_template - - read -p "Enter Wallarm API Token (with Deploy role): " WALLARM_API_TOKEN - if [[ -z "$WALLARM_API_TOKEN" ]]; then - err "API Token cannot be empty." - exit 1 - fi - - # Select Wallarm cloud region (US/EU) - select_cloud_region - - echo "" - echo "Enter each node's name and listening address (format: name IP:Port)" - echo "Example: node1 0.0.0.0:8081" - echo "Leave name blank to finish." - - declare -a NODE_NAMES=() - declare -a NODE_ADDRESSES=() - - while true; do - read -p "Node name (blank to stop): " name - [[ -z "$name" ]] && break - read -p "Listening address (e.g., 0.0.0.0:8081): " address - if [[ -z "$address" ]]; then - err "Address cannot be empty, skipping." - continue - fi - NODE_NAMES+=("$name") - NODE_ADDRESSES+=("$address") - done - - if [[ ${#NODE_NAMES[@]} -eq 0 ]]; then - err "No nodes provided." - exit 1 - fi - - # Validate listen ports before installing anything - local address - for address in "${NODE_ADDRESSES[@]}"; do - if ! check_listen_port "$address"; then - exit 1 - fi - done - - echo "" - echo "Will install ${#NODE_NAMES[@]} nodes in parallel:" - for i in "${!NODE_NAMES[@]}"; do - echo " - ${NODE_NAMES[$i]} -> ${NODE_ADDRESSES[$i]}" - done - read -p "Proceed? (y/N): " confirm - [[ ! "$confirm" =~ ^[Yy]$ ]] && { echo "Cancelled."; exit 0; } - - echo "" - log "Starting parallel installations..." - - declare -a INSTALL_PIDS=() - for i in "${!NODE_NAMES[@]}"; do - install_single_node "${NODE_NAMES[$i]}" "${NODE_ADDRESSES[$i]}" "$WALLARM_API_TOKEN" "$API_HOST" & - INSTALL_PIDS+=($!) - done - - FAILED=0 - local pid - for pid in "${INSTALL_PIDS[@]}"; do - wait "$pid" || ((FAILED++)) - done - - if [[ $FAILED -eq 0 ]]; then - log "All nodes installed and started via systemd." - else - err "$FAILED node(s) failed. Check individual install.log files." - fi -} - -cmd_config() { - # Usage: --config --node NAME --address IP:PORT [--token TOKEN] [--labels LABELS] - check_root - local node_name="" address="" token="" labels="" - - while [[ $# -gt 0 ]]; do - case "$1" in - --node) [[ $# -ge 2 ]] || { err "--node requires a value"; exit 1; }; node_name="$2"; shift 2 ;; - --address) [[ $# -ge 2 ]] || { err "--address requires a value"; exit 1; }; address="$2"; shift 2 ;; - --token) [[ $# -ge 2 ]] || { err "--token requires a value"; exit 1; }; token="$2"; shift 2 ;; - --labels) [[ $# -ge 2 ]] || { err "--labels requires a value"; exit 1; }; labels="$2"; shift 2 ;; - *) err "Unknown config option: $1"; exit 1 ;; - esac - done - - if [[ -z "$node_name" ]]; then - err "Missing --node" - exit 1 - fi - - local work_dir="${NODES_DIR}/${node_name}" - if [[ ! -d "$work_dir" ]]; then - err "Node '$node_name' does not exist in ${NODES_DIR}" - exit 1 - fi - - # Update config file - if [[ -n "$address" ]]; then - if ! check_listen_port "$address"; then - exit 1 - fi - log "Updating listening address to $address" - sed -i "s|^\([[:space:]]*address: \).*|\1\"${address}\"|" "${work_dir}/etc/go-node.yaml" - fi - - # Update env file if token or labels provided (rewrite to avoid sed escaping issues) - if [[ -n "$token" || -n "$labels" ]]; then - local env_file="${work_dir}/env" - [[ -f "$env_file" ]] || { err "env file not found"; exit 1; } - local current_token current_labels - current_token=$(grep '^WALLARM_API_TOKEN=' "$env_file" | cut -d= -f2-) - current_labels=$(grep '^WALLARM_LABELS=' "$env_file" | cut -d= -f2-) - write_env_file "$node_name" "${token:-$current_token}" "${labels:-$current_labels}" - log "Token/labels updated for $node_name." - fi - - log "Configuration updated for $node_name. Restart with: systemctl restart wallarm-node@${node_name}" -} - -cmd_remove() { - check_root - local node_name="" - while [[ $# -gt 0 ]]; do - case "$1" in - --node) [[ $# -ge 2 ]] || { err "--node requires a value"; exit 1; }; node_name="$2"; shift 2 ;; - *) err "Unknown remove option: $1"; exit 1 ;; - esac - done - - if [[ -z "$node_name" ]]; then - err "Missing --node" - exit 1 - fi - - local work_dir="${NODES_DIR}/${node_name}" - if [[ ! -d "$work_dir" ]]; then - err "Node '$node_name' does not exist." - exit 1 - fi - - log "Stopping and disabling service..." - systemctl stop "wallarm-node@${node_name}" 2>/dev/null || true - systemctl disable "wallarm-node@${node_name}" 2>/dev/null || true - - log "Removing directory ${work_dir}..." - rm -rf "$work_dir" - log "Node $node_name removed." -} - -cmd_status() { - # Show systemd status for all found nodes or a specific one - local node_name="${1:-}" - if [[ -n "$node_name" ]]; then - systemctl status "wallarm-node@${node_name}" --no-pager - else - echo "Wallarm Nodes status:" - local dir name - for dir in "${NODES_DIR}"/*/; do - if [[ -d "$dir" ]]; then - name=$(basename "$dir") - echo "--- $name ---" - systemctl status "wallarm-node@${name}" --no-pager | head -5 - echo "" - fi - done - fi -} - -# --- Help --- -show_help() { - cat <