chore: remove old bash/docker files, update README
This commit is contained in:
parent
1924d5b1df
commit
0e781b157e
16 changed files with 64 additions and 4294 deletions
15
.env
15
.env
|
|
@ -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
|
|
||||||
|
|
||||||
123
README.md
123
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).
|
Single-binary deployment and management for Wallarm filtering nodes.
|
||||||
One command to get started, one TUI to manage everything.
|
Interactive menu, multi-instance, zero runtime dependencies.
|
||||||
|
|
||||||
## Quick Start
|
## Quick Start
|
||||||
|
|
||||||
```bash
|
```bash
|
||||||
curl -fsSL "https://git.sechpoint.app/customer-engineering/wallarm/raw/branch/main/setup.sh" | 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
|
## Commands
|
||||||
|
|
||||||
```
|
```
|
||||||
deploy Interactive TUI (wizard or dashboard)
|
/opt/fw/deploy Interactive menu
|
||||||
deploy --tunnel Start reverse SSH tunnel to sechpoint.app
|
/opt/fw/deploy --deploy-all Deploy all nodes from fw.conf
|
||||||
deploy --version Show version
|
/opt/fw/deploy --version Show version
|
||||||
deploy --help Show help
|
|
||||||
```
|
```
|
||||||
|
|
||||||
## Dashboard
|
## Menu
|
||||||
|
|
||||||
```
|
```
|
||||||
📊 Wallarm Dashboard
|
─── Main Menu ───
|
||||||
Type: native | Cloud: EU (api.wallarm.com)
|
[1] Deploy a node
|
||||||
──────────────────────────────────────────────────
|
[2] Edit a node
|
||||||
|
[3] Show status
|
||||||
Nodes:
|
[4] Remove a node
|
||||||
● srv1 — running (0.0.0.0:8081)
|
[5] Remote tunnel
|
||||||
● srv2 — running (0.0.0.0:8082)
|
[6] Dashboard (TUI)
|
||||||
|
|
||||||
Actions:
|
|
||||||
[a] Add node
|
|
||||||
[c] Configure
|
|
||||||
[r] Remove node
|
|
||||||
[t] Start tunnel
|
|
||||||
[q] Quit
|
[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
|
## Architecture
|
||||||
|
|
||||||
```
|
```
|
||||||
wallarm/
|
cmd/deploy/main.go Entry point — menu, deploy, edit, remove
|
||||||
├── cmd/wallarm/main.go Entrypoint: preflight → TUI
|
internal/
|
||||||
├── internal/
|
native/ Node deployment, systemd, nginx
|
||||||
│ ├── shared/ System detection, validation, connectivity
|
preflight/ System checks (14)
|
||||||
│ ├── preflight/ Mandatory checks on every start
|
state/ /opt/fw/state.json persistence
|
||||||
│ ├── state/ ~/.wallarm/state.json persistence
|
tunnel/ Reverse SSH over TLS:443
|
||||||
│ ├── native/ Systemd units, installer, node management
|
ui/ Bubbletea TUI (dashboard)
|
||||||
│ ├── tunnel/ Reverse SSH over TLS:443 via Zoraxy
|
shared/ Validation, connectivity
|
||||||
│ └── ui/ Bubbletea TUI (wizard + dashboard)
|
setup.sh Bootstrap — clones repo, builds binary
|
||||||
├── bin/
|
Makefile Cross-compile targets
|
||||||
│ └── wallarm-linux-amd64 Pre-built binary
|
|
||||||
├── deploy.sh One-command bootstrap
|
|
||||||
├── go.mod / go.sum
|
|
||||||
└── 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/
|
/opt/fw/
|
||||||
make linux-amd64 # Cross-compile
|
├── deploy Go binary
|
||||||
make all # All targets
|
├── 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
|
- x86_64 or aarch64
|
||||||
- 2GB+ RAM, 10GB+ disk
|
- 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.
|
||||||
|
|
|
||||||
86
changelog.md
86
changelog.md
|
|
@ -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@<name>.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
|
|
||||||
|
|
@ -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
|
|
||||||
}
|
|
||||||
|
|
@ -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/
|
|
||||||
```
|
|
||||||
Binary file not shown.
|
|
@ -1 +0,0 @@
|
||||||
995b1d0b51e96d551a3b49c552c0170bc6ce9f8b9e0866b8c15bbc67d1cf93a3 binaries/docker-29.2.1.tgz
|
|
||||||
|
|
@ -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
|
|
||||||
```
|
|
||||||
Binary file not shown.
|
|
@ -1 +0,0 @@
|
||||||
ab4d9c6d2fdde6a855a0a1dc2db8cce6168926a39a45d715dc3dcf2ff0de85c5 images/wallarm-node-6.11.0-rc1.tar.gz
|
|
||||||
|
|
@ -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 "$@"
|
|
||||||
File diff suppressed because it is too large
Load diff
|
|
@ -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 "$@"
|
|
||||||
|
|
@ -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 "$@"
|
|
||||||
|
|
@ -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 <<EOF
|
|
||||||
Usage: $0 COMMAND [OPTIONS]
|
|
||||||
|
|
||||||
Commands:
|
|
||||||
--preflight Run system validation and preflight checks
|
|
||||||
--install Interactive deployment of a Wallarm Docker node
|
|
||||||
--config Reconfigure an existing Docker node (proxies, mode)
|
|
||||||
--remove Uninstall a Wallarm Docker node
|
|
||||||
--status Show running Wallarm containers
|
|
||||||
|
|
||||||
Examples:
|
|
||||||
$0 --preflight
|
|
||||||
sudo $0 --install
|
|
||||||
sudo $0 --config
|
|
||||||
sudo $0 --remove
|
|
||||||
EOF
|
|
||||||
}
|
|
||||||
|
|
||||||
# Ensure the delegated script exists
|
|
||||||
require_script() {
|
|
||||||
local script="$1"
|
|
||||||
local name="$2"
|
|
||||||
if [[ ! -x "$script" ]]; then
|
|
||||||
echo "!!! $name script not found or not executable: $script" >&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
|
|
||||||
|
|
@ -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@<name>.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}" <<EOF
|
|
||||||
[Unit]
|
|
||||||
Description=Wallarm Native Node - %I
|
|
||||||
After=network.target
|
|
||||||
|
|
||||||
[Service]
|
|
||||||
Type=simple
|
|
||||||
WorkingDirectory=${NODES_DIR}/%i
|
|
||||||
EnvironmentFile=${NODES_DIR}/%i/env
|
|
||||||
ExecStart=${NODES_DIR}/%i/wallarm-native-node-aio.sh start
|
|
||||||
ExecStop=${NODES_DIR}/%i/wallarm-native-node-aio.sh stop
|
|
||||||
Restart=on-failure
|
|
||||||
RestartSec=5
|
|
||||||
User=root
|
|
||||||
|
|
||||||
[Install]
|
|
||||||
WantedBy=multi-user.target
|
|
||||||
EOF
|
|
||||||
systemctl daemon-reload
|
|
||||||
fi
|
|
||||||
}
|
|
||||||
|
|
||||||
write_env_file() {
|
|
||||||
local node_name="$1"
|
|
||||||
local api_token="$2"
|
|
||||||
local api_host="$3"
|
|
||||||
local labels="$4"
|
|
||||||
local config_path="${NODES_DIR}/${node_name}/etc/go-node.yaml"
|
|
||||||
local env_file="${NODES_DIR}/${node_name}/env"
|
|
||||||
|
|
||||||
cat > "${env_file}" <<EOF
|
|
||||||
WALLARM_API_TOKEN=${api_token}
|
|
||||||
WALLARM_API_HOST=${api_host}
|
|
||||||
WALLARM_LABELS=${labels}
|
|
||||||
WALLARM_CONFIG_PATH=${config_path}
|
|
||||||
EOF
|
|
||||||
chmod 600 "${env_file}" # token is sensitive
|
|
||||||
}
|
|
||||||
|
|
||||||
# --- Preflight checks ---
|
|
||||||
run_preflight() {
|
|
||||||
local failed=0
|
|
||||||
|
|
||||||
log "Running preflight checks..."
|
|
||||||
|
|
||||||
# 1. Root privileges
|
|
||||||
if [[ $EUID -ne 0 ]]; then
|
|
||||||
err "Preflight failed: must be run as root."
|
|
||||||
failed=1
|
|
||||||
fi
|
|
||||||
|
|
||||||
# 2. Init system must be systemd (template unit management)
|
|
||||||
local init_system
|
|
||||||
init_system=$(detect_init_system)
|
|
||||||
if [[ "$init_system" != "systemd" ]]; then
|
|
||||||
err "Preflight failed: this manager requires systemd (detected: $init_system)."
|
|
||||||
failed=1
|
|
||||||
fi
|
|
||||||
|
|
||||||
# 3. Architecture
|
|
||||||
local arch
|
|
||||||
arch=$(detect_architecture)
|
|
||||||
if [[ "$arch" != "x86_64" && "$arch" != "aarch64" ]]; then
|
|
||||||
err "Preflight failed: unsupported architecture '$arch' for the native node installer."
|
|
||||||
failed=1
|
|
||||||
fi
|
|
||||||
log "Architecture: ${arch} (installer suffix: ${INSTALLER_ARCH})"
|
|
||||||
|
|
||||||
# 4. Required commands
|
|
||||||
local required_cmds=(curl systemctl sed mkdir rm sleep)
|
|
||||||
local missing=()
|
|
||||||
local cmd
|
|
||||||
for cmd in "${required_cmds[@]}"; do
|
|
||||||
if ! command_exists "$cmd"; then
|
|
||||||
missing+=("$cmd")
|
|
||||||
fi
|
|
||||||
done
|
|
||||||
if [[ ${#missing[@]} -gt 0 ]]; then
|
|
||||||
err "Preflight failed: missing required commands: ${missing[*]}"
|
|
||||||
failed=1
|
|
||||||
fi
|
|
||||||
|
|
||||||
# 5. Installer reachability
|
|
||||||
if ! test_connectivity "$INSTALLER_URL" "Wallarm native node installer"; then
|
|
||||||
err "Preflight failed: installer not reachable: $INSTALLER_URL"
|
|
||||||
failed=1
|
|
||||||
fi
|
|
||||||
|
|
||||||
# 6. Wallarm cloud reachability (must have at least one reachable region)
|
|
||||||
local us eu
|
|
||||||
us=$(test_cloud_endpoints "US" "${US_DATA_NODES[@]}")
|
|
||||||
eu=$(test_cloud_endpoints "EU" "${EU_DATA_NODES[@]}")
|
|
||||||
US_CLOUD_REACHABLE="$us"
|
|
||||||
EU_CLOUD_REACHABLE="$eu"
|
|
||||||
if [[ "$us" != "true" && "$eu" != "true" ]]; then
|
|
||||||
err "Preflight failed: no Wallarm cloud region reachable (US/EU)."
|
|
||||||
failed=1
|
|
||||||
fi
|
|
||||||
|
|
||||||
# 7. Disk space (>= 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" <<EOF
|
|
||||||
mode: connector-server
|
|
||||||
connector:
|
|
||||||
address: "${listen_address}"
|
|
||||||
EOF
|
|
||||||
|
|
||||||
# 2. Download installer if missing
|
|
||||||
if [[ ! -f "${installer_path}" ]]; then
|
|
||||||
log "[${node_name}] Downloading installer..."
|
|
||||||
curl -fsSL -o "${installer_path}" "${INSTALLER_URL}" || {
|
|
||||||
err "[${node_name}] Download failed"
|
|
||||||
return 1
|
|
||||||
}
|
|
||||||
chmod +x "${installer_path}"
|
|
||||||
fi
|
|
||||||
|
|
||||||
# 3. Write environment file (used by systemd and manual scripts)
|
|
||||||
write_env_file "${node_name}" "${api_token}" "${api_host}" "${labels}"
|
|
||||||
|
|
||||||
# 4. Run installer
|
|
||||||
cd "${work_dir}" || return 1
|
|
||||||
if WALLARM_API_TOKEN="${api_token}" \
|
|
||||||
WALLARM_API_HOST="${api_host}" \
|
|
||||||
WALLARM_LABELS="${labels}" \
|
|
||||||
WALLARM_CONFIG_PATH="${work_dir}/etc/go-node.yaml" \
|
|
||||||
./wallarm-native-node-aio.sh install \
|
|
||||||
-- --config-dir "${work_dir}/etc" \
|
|
||||||
-- --log-dir "${work_dir}/var/log" \
|
|
||||||
-- --pid-dir "${work_dir}/var/run" \
|
|
||||||
> "${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 <<EOF
|
|
||||||
Usage: $0 [COMMAND] [OPTIONS]
|
|
||||||
|
|
||||||
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.
|
|
||||||
|
|
||||||
Environment:
|
|
||||||
WALLARM_INSTALLER_URL Override the all-in-one installer URL (default: repo.wallarm.com latest).
|
|
||||||
WALLARM_INSTALLER_ARCH Installer architecture suffix (default: x86_64).
|
|
||||||
|
|
||||||
Examples:
|
|
||||||
$0 --preflight
|
|
||||||
$0 --install
|
|
||||||
$0 --config --node node1 --address 0.0.0.0:9090
|
|
||||||
$0 --remove --node node2
|
|
||||||
$0 --status
|
|
||||||
EOF
|
|
||||||
}
|
|
||||||
|
|
||||||
# --- Main argument parsing ---
|
|
||||||
if [[ $# -eq 0 ]]; then
|
|
||||||
show_help
|
|
||||||
exit 0
|
|
||||||
fi
|
|
||||||
|
|
||||||
case "$1" in
|
|
||||||
--preflight) shift; cmd_preflight "$@" ;;
|
|
||||||
--install) shift; cmd_install "$@" ;;
|
|
||||||
--config) shift; cmd_config "$@" ;;
|
|
||||||
--remove) shift; cmd_remove "$@" ;;
|
|
||||||
--status) shift; cmd_status "$@" ;;
|
|
||||||
--help|-h) show_help ;;
|
|
||||||
*) err "Unknown command: $1"; show_help; exit 1 ;;
|
|
||||||
esac
|
|
||||||
Loading…
Reference in a new issue