🔐 Security hardening: auth, rate limiting, brute force protection
- Add comprehensive security package with: - API Key generation and validation (SHA256 hash) - Password policy enforcement (min 12 chars, complexity) - Rate limiting with presets (auth, api, ingest, export) - Brute force protection (5 attempts, 15min lockout) - Security headers middleware - IP whitelisting - Audit logging structure - Secure token generation - Enhanced auth middleware: - JWT + API Key dual authentication - Token revocation via Redis - Scope-based authorization - Role-based access control - Updated installer with: - Interactive setup for client customization - Auto-generated secure credentials - Docker all-in-one image - Agent installer script - Added documentation: - SECURITY.md - Complete security guide - INSTALL.md - Installation guide - .env.example - Configuration reference
This commit is contained in:
867
install.sh
867
install.sh
@@ -1,49 +1,844 @@
|
||||
#!/bin/bash
|
||||
#
|
||||
# 🐍 OPHION - Instalador Interativo
|
||||
# Plataforma de Observabilidade Open Source
|
||||
#
|
||||
# Uso: curl -fsSL https://get.ophion.io | bash
|
||||
#
|
||||
|
||||
set -e
|
||||
|
||||
echo "🐍 OPHION - Observability Platform Installer"
|
||||
echo "============================================="
|
||||
# Cores
|
||||
RED='\033[0;31m'
|
||||
GREEN='\033[0;32m'
|
||||
YELLOW='\033[1;33m'
|
||||
BLUE='\033[0;34m'
|
||||
PURPLE='\033[0;35m'
|
||||
CYAN='\033[0;36m'
|
||||
NC='\033[0m' # No Color
|
||||
|
||||
# Check Docker
|
||||
if ! command -v docker &> /dev/null; then
|
||||
echo "❌ Docker not found. Installing..."
|
||||
curl -fsSL https://get.docker.com | sh
|
||||
fi
|
||||
# ASCII Art
|
||||
show_banner() {
|
||||
echo -e "${PURPLE}"
|
||||
cat << "EOF"
|
||||
____ _____ _ _ _____ ____ _ _
|
||||
/ __ \| __ \| | | |_ _/ __ \| \ | |
|
||||
| | | | |__) | |__| | | || | | | \| |
|
||||
| | | | ___/| __ | | || | | | . ` |
|
||||
| |__| | | | | | |_| || |__| | |\ |
|
||||
\____/|_| |_| |_|_____\____/|_| \_|
|
||||
|
||||
Open Source Observability Platform
|
||||
Made with 🖤 in Brazil
|
||||
EOF
|
||||
echo -e "${NC}"
|
||||
}
|
||||
|
||||
# Check Docker Compose
|
||||
if ! command -v docker-compose &> /dev/null && ! docker compose version &> /dev/null; then
|
||||
echo "❌ Docker Compose not found. Please install it."
|
||||
# Logging
|
||||
log_info() { echo -e "${BLUE}[INFO]${NC} $1"; }
|
||||
log_success() { echo -e "${GREEN}[✓]${NC} $1"; }
|
||||
log_warn() { echo -e "${YELLOW}[!]${NC} $1"; }
|
||||
log_error() { echo -e "${RED}[✗]${NC} $1"; }
|
||||
|
||||
# Verificar requisitos
|
||||
check_requirements() {
|
||||
log_info "Verificando requisitos..."
|
||||
|
||||
# Docker
|
||||
if ! command -v docker &> /dev/null; then
|
||||
log_error "Docker não encontrado!"
|
||||
echo ""
|
||||
echo "Instale o Docker primeiro:"
|
||||
echo " curl -fsSL https://get.docker.com | sh"
|
||||
exit 1
|
||||
fi
|
||||
log_success "Docker instalado"
|
||||
|
||||
# Docker Compose
|
||||
if ! docker compose version &> /dev/null && ! command -v docker-compose &> /dev/null; then
|
||||
log_error "Docker Compose não encontrado!"
|
||||
exit 1
|
||||
fi
|
||||
log_success "Docker Compose instalado"
|
||||
|
||||
# Verificar se Docker está rodando
|
||||
if ! docker info &> /dev/null; then
|
||||
log_error "Docker não está rodando!"
|
||||
echo " sudo systemctl start docker"
|
||||
exit 1
|
||||
fi
|
||||
log_success "Docker está rodando"
|
||||
}
|
||||
|
||||
# Gerar string aleatória
|
||||
generate_secret() {
|
||||
openssl rand -hex 32 2>/dev/null || head -c 64 /dev/urandom | base64 | tr -dc 'a-zA-Z0-9' | head -c 64
|
||||
}
|
||||
|
||||
# Gerar API Key
|
||||
generate_api_key() {
|
||||
echo "ophion_$(openssl rand -hex 32 2>/dev/null || head -c 64 /dev/urandom | base64 | tr -dc 'a-zA-Z0-9' | head -c 64)"
|
||||
}
|
||||
|
||||
# Coletar informações do cliente
|
||||
collect_info() {
|
||||
echo ""
|
||||
echo -e "${CYAN}═══════════════════════════════════════════════════════════${NC}"
|
||||
echo -e "${CYAN} CONFIGURAÇÃO INICIAL ${NC}"
|
||||
echo -e "${CYAN}═══════════════════════════════════════════════════════════${NC}"
|
||||
echo ""
|
||||
|
||||
# Nome da organização
|
||||
read -p "📋 Nome da sua empresa/organização: " ORG_NAME
|
||||
ORG_NAME=${ORG_NAME:-"Minha Empresa"}
|
||||
|
||||
# Email do admin
|
||||
read -p "📧 Email do administrador: " ADMIN_EMAIL
|
||||
while [[ ! "$ADMIN_EMAIL" =~ ^[a-zA-Z0-9._%+-]+@[a-zA-Z0-9.-]+\.[a-zA-Z]{2,}$ ]]; do
|
||||
log_warn "Email inválido!"
|
||||
read -p "📧 Email do administrador: " ADMIN_EMAIL
|
||||
done
|
||||
|
||||
# Senha do admin
|
||||
echo -n "🔐 Senha do administrador (mín. 8 caracteres): "
|
||||
read -s ADMIN_PASSWORD
|
||||
echo ""
|
||||
while [[ ${#ADMIN_PASSWORD} -lt 8 ]]; do
|
||||
log_warn "Senha muito curta!"
|
||||
echo -n "🔐 Senha do administrador (mín. 8 caracteres): "
|
||||
read -s ADMIN_PASSWORD
|
||||
echo ""
|
||||
done
|
||||
|
||||
# Domínio (opcional)
|
||||
read -p "🌐 Domínio (deixe vazio para localhost): " DOMAIN
|
||||
DOMAIN=${DOMAIN:-"localhost"}
|
||||
|
||||
# Porta
|
||||
read -p "🔌 Porta do servidor [8080]: " SERVER_PORT
|
||||
SERVER_PORT=${SERVER_PORT:-8080}
|
||||
|
||||
# Porta do dashboard
|
||||
read -p "🖥️ Porta do dashboard [3000]: " DASHBOARD_PORT
|
||||
DASHBOARD_PORT=${DASHBOARD_PORT:-3000}
|
||||
|
||||
# Habilitar HTTPS?
|
||||
if [[ "$DOMAIN" != "localhost" ]]; then
|
||||
read -p "🔒 Habilitar HTTPS com Let's Encrypt? (s/n) [s]: " ENABLE_HTTPS
|
||||
ENABLE_HTTPS=${ENABLE_HTTPS:-s}
|
||||
else
|
||||
ENABLE_HTTPS="n"
|
||||
fi
|
||||
|
||||
# Telegram para alertas (opcional)
|
||||
echo ""
|
||||
read -p "📱 Configurar alertas no Telegram? (s/n) [n]: " ENABLE_TELEGRAM
|
||||
if [[ "$ENABLE_TELEGRAM" =~ ^[sS]$ ]]; then
|
||||
read -p " Bot Token: " TELEGRAM_BOT_TOKEN
|
||||
read -p " Chat ID: " TELEGRAM_CHAT_ID
|
||||
fi
|
||||
|
||||
echo ""
|
||||
log_success "Informações coletadas!"
|
||||
}
|
||||
|
||||
# Criar diretório de instalação
|
||||
setup_directory() {
|
||||
INSTALL_DIR="/opt/ophion"
|
||||
|
||||
log_info "Criando diretório de instalação em $INSTALL_DIR..."
|
||||
|
||||
sudo mkdir -p "$INSTALL_DIR"
|
||||
sudo mkdir -p "$INSTALL_DIR/data/postgres"
|
||||
sudo mkdir -p "$INSTALL_DIR/data/clickhouse"
|
||||
sudo mkdir -p "$INSTALL_DIR/data/redis"
|
||||
sudo mkdir -p "$INSTALL_DIR/configs"
|
||||
sudo mkdir -p "$INSTALL_DIR/logs"
|
||||
|
||||
sudo chown -R $USER:$USER "$INSTALL_DIR"
|
||||
|
||||
cd "$INSTALL_DIR"
|
||||
log_success "Diretório criado"
|
||||
}
|
||||
|
||||
# Gerar arquivo .env
|
||||
generate_env() {
|
||||
log_info "Gerando configuração..."
|
||||
|
||||
JWT_SECRET=$(generate_secret)
|
||||
POSTGRES_PASSWORD=$(generate_secret | head -c 32)
|
||||
API_KEY=$(generate_api_key)
|
||||
|
||||
cat > "$INSTALL_DIR/.env" << EOF
|
||||
# ═══════════════════════════════════════════════════════════
|
||||
# 🐍 OPHION - Configuração
|
||||
# Gerado em: $(date)
|
||||
# Organização: $ORG_NAME
|
||||
# ═══════════════════════════════════════════════════════════
|
||||
|
||||
# Organização
|
||||
ORG_NAME="$ORG_NAME"
|
||||
ADMIN_EMAIL="$ADMIN_EMAIL"
|
||||
ADMIN_PASSWORD="$ADMIN_PASSWORD"
|
||||
|
||||
# Rede
|
||||
DOMAIN=$DOMAIN
|
||||
SERVER_PORT=$SERVER_PORT
|
||||
DASHBOARD_PORT=$DASHBOARD_PORT
|
||||
API_URL=http://ophion-server:8080
|
||||
|
||||
# Segurança (NÃO COMPARTILHE!)
|
||||
JWT_SECRET=$JWT_SECRET
|
||||
API_KEY=$API_KEY
|
||||
|
||||
# PostgreSQL
|
||||
POSTGRES_USER=ophion
|
||||
POSTGRES_PASSWORD=$POSTGRES_PASSWORD
|
||||
POSTGRES_DB=ophion
|
||||
DATABASE_URL=postgres://ophion:$POSTGRES_PASSWORD@postgres:5432/ophion
|
||||
|
||||
# ClickHouse
|
||||
CLICKHOUSE_URL=clickhouse://clickhouse:9000/ophion
|
||||
|
||||
# Redis
|
||||
REDIS_URL=redis://redis:6379
|
||||
|
||||
# Telegram Alertas
|
||||
TELEGRAM_ENABLED=${ENABLE_TELEGRAM:-n}
|
||||
TELEGRAM_BOT_TOKEN=${TELEGRAM_BOT_TOKEN:-}
|
||||
TELEGRAM_CHAT_ID=${TELEGRAM_CHAT_ID:-}
|
||||
|
||||
# OpenAI (para recursos de IA)
|
||||
OPENAI_API_KEY=
|
||||
|
||||
# Timezone
|
||||
TZ=America/Sao_Paulo
|
||||
EOF
|
||||
|
||||
chmod 600 "$INSTALL_DIR/.env"
|
||||
log_success "Arquivo .env gerado"
|
||||
}
|
||||
|
||||
# Gerar docker-compose.yml
|
||||
generate_compose() {
|
||||
log_info "Gerando docker-compose.yml..."
|
||||
|
||||
cat > "$INSTALL_DIR/docker-compose.yml" << 'EOF'
|
||||
version: '3.8'
|
||||
|
||||
services:
|
||||
# ═══════════════════════════════════════════════════════════
|
||||
# 🐍 OPHION Server (API)
|
||||
# ═══════════════════════════════════════════════════════════
|
||||
ophion-server:
|
||||
image: ghcr.io/bigtux/ophion-server:latest
|
||||
container_name: ophion-server
|
||||
ports:
|
||||
- "${SERVER_PORT}:8080"
|
||||
environment:
|
||||
- DATABASE_URL=${DATABASE_URL}
|
||||
- CLICKHOUSE_URL=${CLICKHOUSE_URL}
|
||||
- REDIS_URL=${REDIS_URL}
|
||||
- JWT_SECRET=${JWT_SECRET}
|
||||
- ADMIN_EMAIL=${ADMIN_EMAIL}
|
||||
- ADMIN_PASSWORD=${ADMIN_PASSWORD}
|
||||
- ORG_NAME=${ORG_NAME}
|
||||
- TELEGRAM_ENABLED=${TELEGRAM_ENABLED}
|
||||
- TELEGRAM_BOT_TOKEN=${TELEGRAM_BOT_TOKEN}
|
||||
- TELEGRAM_CHAT_ID=${TELEGRAM_CHAT_ID}
|
||||
- OPENAI_API_KEY=${OPENAI_API_KEY}
|
||||
- TZ=${TZ}
|
||||
volumes:
|
||||
- ./configs:/app/configs:ro
|
||||
- ./logs:/app/logs
|
||||
depends_on:
|
||||
postgres:
|
||||
condition: service_healthy
|
||||
clickhouse:
|
||||
condition: service_started
|
||||
redis:
|
||||
condition: service_started
|
||||
healthcheck:
|
||||
test: ["CMD", "wget", "-q", "--spider", "http://localhost:8080/health"]
|
||||
interval: 30s
|
||||
timeout: 10s
|
||||
retries: 3
|
||||
restart: unless-stopped
|
||||
networks:
|
||||
- ophion-net
|
||||
|
||||
# ═══════════════════════════════════════════════════════════
|
||||
# 🖥️ OPHION Dashboard (Web UI)
|
||||
# ═══════════════════════════════════════════════════════════
|
||||
ophion-web:
|
||||
image: ghcr.io/bigtux/ophion-web:latest
|
||||
container_name: ophion-web
|
||||
ports:
|
||||
- "${DASHBOARD_PORT}:3000"
|
||||
environment:
|
||||
- API_URL=http://ophion-server:8080
|
||||
- NEXT_PUBLIC_API_URL=http://${DOMAIN}:${SERVER_PORT}
|
||||
- ORG_NAME=${ORG_NAME}
|
||||
depends_on:
|
||||
- ophion-server
|
||||
restart: unless-stopped
|
||||
networks:
|
||||
- ophion-net
|
||||
|
||||
# ═══════════════════════════════════════════════════════════
|
||||
# 🐘 PostgreSQL (Metadados, Usuários, Config)
|
||||
# ═══════════════════════════════════════════════════════════
|
||||
postgres:
|
||||
image: postgres:16-alpine
|
||||
container_name: ophion-postgres
|
||||
environment:
|
||||
- POSTGRES_USER=${POSTGRES_USER}
|
||||
- POSTGRES_PASSWORD=${POSTGRES_PASSWORD}
|
||||
- POSTGRES_DB=${POSTGRES_DB}
|
||||
volumes:
|
||||
- ./data/postgres:/var/lib/postgresql/data
|
||||
- ./init/postgres:/docker-entrypoint-initdb.d:ro
|
||||
healthcheck:
|
||||
test: ["CMD-SHELL", "pg_isready -U ${POSTGRES_USER} -d ${POSTGRES_DB}"]
|
||||
interval: 10s
|
||||
timeout: 5s
|
||||
retries: 5
|
||||
restart: unless-stopped
|
||||
networks:
|
||||
- ophion-net
|
||||
|
||||
# ═══════════════════════════════════════════════════════════
|
||||
# 🏠 ClickHouse (Métricas, Logs, Traces)
|
||||
# ═══════════════════════════════════════════════════════════
|
||||
clickhouse:
|
||||
image: clickhouse/clickhouse-server:24.1
|
||||
container_name: ophion-clickhouse
|
||||
volumes:
|
||||
- ./data/clickhouse:/var/lib/clickhouse
|
||||
- ./init/clickhouse:/docker-entrypoint-initdb.d:ro
|
||||
ulimits:
|
||||
nofile:
|
||||
soft: 262144
|
||||
hard: 262144
|
||||
restart: unless-stopped
|
||||
networks:
|
||||
- ophion-net
|
||||
|
||||
# ═══════════════════════════════════════════════════════════
|
||||
# 🔴 Redis (Cache, Sessions, Filas)
|
||||
# ═══════════════════════════════════════════════════════════
|
||||
redis:
|
||||
image: redis:7-alpine
|
||||
container_name: ophion-redis
|
||||
command: redis-server --appendonly yes
|
||||
volumes:
|
||||
- ./data/redis:/data
|
||||
healthcheck:
|
||||
test: ["CMD", "redis-cli", "ping"]
|
||||
interval: 10s
|
||||
timeout: 5s
|
||||
retries: 3
|
||||
restart: unless-stopped
|
||||
networks:
|
||||
- ophion-net
|
||||
|
||||
networks:
|
||||
ophion-net:
|
||||
driver: bridge
|
||||
|
||||
EOF
|
||||
|
||||
log_success "docker-compose.yml gerado"
|
||||
}
|
||||
|
||||
# Gerar scripts SQL de inicialização
|
||||
generate_init_scripts() {
|
||||
log_info "Gerando scripts de inicialização..."
|
||||
|
||||
mkdir -p "$INSTALL_DIR/init/postgres"
|
||||
mkdir -p "$INSTALL_DIR/init/clickhouse"
|
||||
|
||||
# PostgreSQL init
|
||||
cat > "$INSTALL_DIR/init/postgres/01-schema.sql" << 'EOF'
|
||||
-- ═══════════════════════════════════════════════════════════
|
||||
-- 🐍 OPHION - Schema PostgreSQL
|
||||
-- ═══════════════════════════════════════════════════════════
|
||||
|
||||
-- Extensões
|
||||
CREATE EXTENSION IF NOT EXISTS "uuid-ossp";
|
||||
CREATE EXTENSION IF NOT EXISTS "pgcrypto";
|
||||
|
||||
-- Organizações
|
||||
CREATE TABLE organizations (
|
||||
id UUID PRIMARY KEY DEFAULT uuid_generate_v4(),
|
||||
name VARCHAR(255) NOT NULL,
|
||||
slug VARCHAR(100) UNIQUE NOT NULL,
|
||||
settings JSONB DEFAULT '{}',
|
||||
created_at TIMESTAMPTZ DEFAULT NOW(),
|
||||
updated_at TIMESTAMPTZ DEFAULT NOW()
|
||||
);
|
||||
|
||||
-- Usuários
|
||||
CREATE TABLE users (
|
||||
id UUID PRIMARY KEY DEFAULT uuid_generate_v4(),
|
||||
org_id UUID REFERENCES organizations(id) ON DELETE CASCADE,
|
||||
email VARCHAR(255) UNIQUE NOT NULL,
|
||||
password_hash VARCHAR(255) NOT NULL,
|
||||
name VARCHAR(255),
|
||||
role VARCHAR(50) DEFAULT 'viewer',
|
||||
avatar_url TEXT,
|
||||
settings JSONB DEFAULT '{}',
|
||||
last_login_at TIMESTAMPTZ,
|
||||
created_at TIMESTAMPTZ DEFAULT NOW(),
|
||||
updated_at TIMESTAMPTZ DEFAULT NOW()
|
||||
);
|
||||
|
||||
-- API Keys
|
||||
CREATE TABLE api_keys (
|
||||
id UUID PRIMARY KEY DEFAULT uuid_generate_v4(),
|
||||
org_id UUID REFERENCES organizations(id) ON DELETE CASCADE,
|
||||
key_hash VARCHAR(64) NOT NULL,
|
||||
key_prefix VARCHAR(20) NOT NULL,
|
||||
name VARCHAR(255),
|
||||
description TEXT,
|
||||
scopes TEXT[] DEFAULT ARRAY['metrics:write', 'logs:write'],
|
||||
created_by UUID REFERENCES users(id),
|
||||
last_used_at TIMESTAMPTZ,
|
||||
expires_at TIMESTAMPTZ,
|
||||
revoked BOOLEAN DEFAULT FALSE,
|
||||
created_at TIMESTAMPTZ DEFAULT NOW()
|
||||
);
|
||||
|
||||
-- Hosts/Agents
|
||||
CREATE TABLE hosts (
|
||||
id UUID PRIMARY KEY DEFAULT uuid_generate_v4(),
|
||||
org_id UUID REFERENCES organizations(id) ON DELETE CASCADE,
|
||||
hostname VARCHAR(255) NOT NULL,
|
||||
ip_address INET,
|
||||
os VARCHAR(100),
|
||||
arch VARCHAR(50),
|
||||
agent_version VARCHAR(50),
|
||||
tags JSONB DEFAULT '{}',
|
||||
status VARCHAR(50) DEFAULT 'unknown',
|
||||
last_seen_at TIMESTAMPTZ,
|
||||
created_at TIMESTAMPTZ DEFAULT NOW(),
|
||||
UNIQUE(org_id, hostname)
|
||||
);
|
||||
|
||||
-- Alert Rules
|
||||
CREATE TABLE alert_rules (
|
||||
id UUID PRIMARY KEY DEFAULT uuid_generate_v4(),
|
||||
org_id UUID REFERENCES organizations(id) ON DELETE CASCADE,
|
||||
name VARCHAR(255) NOT NULL,
|
||||
description TEXT,
|
||||
query TEXT NOT NULL,
|
||||
condition VARCHAR(50) NOT NULL,
|
||||
threshold DECIMAL,
|
||||
severity VARCHAR(50) DEFAULT 'warning',
|
||||
enabled BOOLEAN DEFAULT TRUE,
|
||||
notify_channels JSONB DEFAULT '[]',
|
||||
created_by UUID REFERENCES users(id),
|
||||
created_at TIMESTAMPTZ DEFAULT NOW(),
|
||||
updated_at TIMESTAMPTZ DEFAULT NOW()
|
||||
);
|
||||
|
||||
-- Alert History
|
||||
CREATE TABLE alert_history (
|
||||
id UUID PRIMARY KEY DEFAULT uuid_generate_v4(),
|
||||
rule_id UUID REFERENCES alert_rules(id) ON DELETE CASCADE,
|
||||
org_id UUID REFERENCES organizations(id) ON DELETE CASCADE,
|
||||
host_id UUID REFERENCES hosts(id),
|
||||
severity VARCHAR(50),
|
||||
status VARCHAR(50) DEFAULT 'firing',
|
||||
message TEXT,
|
||||
value DECIMAL,
|
||||
fired_at TIMESTAMPTZ DEFAULT NOW(),
|
||||
resolved_at TIMESTAMPTZ,
|
||||
acknowledged_by UUID REFERENCES users(id),
|
||||
acknowledged_at TIMESTAMPTZ
|
||||
);
|
||||
|
||||
-- Dashboards
|
||||
CREATE TABLE dashboards (
|
||||
id UUID PRIMARY KEY DEFAULT uuid_generate_v4(),
|
||||
org_id UUID REFERENCES organizations(id) ON DELETE CASCADE,
|
||||
name VARCHAR(255) NOT NULL,
|
||||
description TEXT,
|
||||
layout JSONB DEFAULT '[]',
|
||||
is_default BOOLEAN DEFAULT FALSE,
|
||||
created_by UUID REFERENCES users(id),
|
||||
created_at TIMESTAMPTZ DEFAULT NOW(),
|
||||
updated_at TIMESTAMPTZ DEFAULT NOW()
|
||||
);
|
||||
|
||||
-- Índices
|
||||
CREATE INDEX idx_users_org ON users(org_id);
|
||||
CREATE INDEX idx_users_email ON users(email);
|
||||
CREATE INDEX idx_api_keys_org ON api_keys(org_id);
|
||||
CREATE INDEX idx_api_keys_prefix ON api_keys(key_prefix);
|
||||
CREATE INDEX idx_hosts_org ON hosts(org_id);
|
||||
CREATE INDEX idx_hosts_status ON hosts(status);
|
||||
CREATE INDEX idx_alert_history_org ON alert_history(org_id);
|
||||
CREATE INDEX idx_alert_history_status ON alert_history(status);
|
||||
CREATE INDEX idx_alert_history_fired ON alert_history(fired_at DESC);
|
||||
|
||||
EOF
|
||||
|
||||
# ClickHouse init
|
||||
cat > "$INSTALL_DIR/init/clickhouse/01-schema.sql" << 'EOF'
|
||||
-- ═══════════════════════════════════════════════════════════
|
||||
-- 🐍 OPHION - Schema ClickHouse
|
||||
-- ═══════════════════════════════════════════════════════════
|
||||
|
||||
CREATE DATABASE IF NOT EXISTS ophion;
|
||||
|
||||
-- Métricas de Sistema
|
||||
CREATE TABLE IF NOT EXISTS ophion.metrics (
|
||||
org_id UUID,
|
||||
host_id UUID,
|
||||
hostname LowCardinality(String),
|
||||
metric_name LowCardinality(String),
|
||||
metric_type LowCardinality(String),
|
||||
value Float64,
|
||||
tags Map(String, String),
|
||||
timestamp DateTime64(3),
|
||||
INDEX idx_metric_name metric_name TYPE bloom_filter GRANULARITY 4,
|
||||
INDEX idx_hostname hostname TYPE bloom_filter GRANULARITY 4
|
||||
) ENGINE = MergeTree()
|
||||
PARTITION BY toYYYYMM(timestamp)
|
||||
ORDER BY (org_id, host_id, metric_name, timestamp)
|
||||
TTL timestamp + INTERVAL 90 DAY;
|
||||
|
||||
-- Logs
|
||||
CREATE TABLE IF NOT EXISTS ophion.logs (
|
||||
org_id UUID,
|
||||
host_id UUID,
|
||||
hostname LowCardinality(String),
|
||||
service LowCardinality(String),
|
||||
level LowCardinality(String),
|
||||
message String,
|
||||
attributes Map(String, String),
|
||||
trace_id String,
|
||||
span_id String,
|
||||
timestamp DateTime64(3),
|
||||
INDEX idx_level level TYPE set(0) GRANULARITY 4,
|
||||
INDEX idx_service service TYPE bloom_filter GRANULARITY 4,
|
||||
INDEX idx_message message TYPE tokenbf_v1(10240, 3, 0) GRANULARITY 4
|
||||
) ENGINE = MergeTree()
|
||||
PARTITION BY toYYYYMM(timestamp)
|
||||
ORDER BY (org_id, timestamp, host_id)
|
||||
TTL timestamp + INTERVAL 30 DAY;
|
||||
|
||||
-- Traces (Spans)
|
||||
CREATE TABLE IF NOT EXISTS ophion.traces (
|
||||
org_id UUID,
|
||||
trace_id String,
|
||||
span_id String,
|
||||
parent_span_id String,
|
||||
operation_name LowCardinality(String),
|
||||
service_name LowCardinality(String),
|
||||
kind LowCardinality(String),
|
||||
status_code UInt8,
|
||||
status_message String,
|
||||
attributes Map(String, String),
|
||||
events Nested(
|
||||
name String,
|
||||
timestamp DateTime64(3),
|
||||
attributes Map(String, String)
|
||||
),
|
||||
duration_ms Float64,
|
||||
start_time DateTime64(3),
|
||||
end_time DateTime64(3),
|
||||
INDEX idx_trace_id trace_id TYPE bloom_filter GRANULARITY 4,
|
||||
INDEX idx_service service_name TYPE bloom_filter GRANULARITY 4
|
||||
) ENGINE = MergeTree()
|
||||
PARTITION BY toYYYYMM(start_time)
|
||||
ORDER BY (org_id, service_name, start_time, trace_id)
|
||||
TTL start_time + INTERVAL 14 DAY;
|
||||
|
||||
-- Aggregated metrics (rollups)
|
||||
CREATE TABLE IF NOT EXISTS ophion.metrics_hourly (
|
||||
org_id UUID,
|
||||
host_id UUID,
|
||||
metric_name LowCardinality(String),
|
||||
hour DateTime,
|
||||
min_value Float64,
|
||||
max_value Float64,
|
||||
avg_value Float64,
|
||||
count UInt64
|
||||
) ENGINE = SummingMergeTree()
|
||||
PARTITION BY toYYYYMM(hour)
|
||||
ORDER BY (org_id, host_id, metric_name, hour)
|
||||
TTL hour + INTERVAL 1 YEAR;
|
||||
|
||||
-- Materialized view para rollup
|
||||
CREATE MATERIALIZED VIEW IF NOT EXISTS ophion.metrics_hourly_mv
|
||||
TO ophion.metrics_hourly AS
|
||||
SELECT
|
||||
org_id,
|
||||
host_id,
|
||||
metric_name,
|
||||
toStartOfHour(timestamp) AS hour,
|
||||
min(value) AS min_value,
|
||||
max(value) AS max_value,
|
||||
avg(value) AS avg_value,
|
||||
count() AS count
|
||||
FROM ophion.metrics
|
||||
GROUP BY org_id, host_id, metric_name, hour;
|
||||
|
||||
EOF
|
||||
|
||||
log_success "Scripts de inicialização gerados"
|
||||
}
|
||||
|
||||
# Gerar script do Agent
|
||||
generate_agent_installer() {
|
||||
log_info "Gerando instalador do agent..."
|
||||
|
||||
mkdir -p "$INSTALL_DIR/scripts"
|
||||
|
||||
cat > "$INSTALL_DIR/scripts/install-agent.sh" << EOF
|
||||
#!/bin/bash
|
||||
#
|
||||
# 🐍 OPHION Agent Installer
|
||||
# Servidor: http://${DOMAIN}:${SERVER_PORT}
|
||||
#
|
||||
|
||||
set -e
|
||||
|
||||
API_KEY="${API_KEY}"
|
||||
SERVER_URL="http://${DOMAIN}:${SERVER_PORT}"
|
||||
|
||||
echo "🐍 Instalando OPHION Agent..."
|
||||
|
||||
# Detectar OS
|
||||
if [[ -f /etc/debian_version ]]; then
|
||||
OS="debian"
|
||||
elif [[ -f /etc/redhat-release ]]; then
|
||||
OS="redhat"
|
||||
else
|
||||
echo "OS não suportado!"
|
||||
exit 1
|
||||
fi
|
||||
|
||||
# Create directory
|
||||
INSTALL_DIR="${OPHION_DIR:-/opt/ophion}"
|
||||
mkdir -p "$INSTALL_DIR"
|
||||
# Baixar agent
|
||||
curl -fsSL -o /tmp/ophion-agent "\${SERVER_URL}/downloads/agent/linux/amd64/ophion-agent"
|
||||
chmod +x /tmp/ophion-agent
|
||||
sudo mv /tmp/ophion-agent /usr/local/bin/
|
||||
|
||||
# Criar config
|
||||
sudo mkdir -p /etc/ophion
|
||||
sudo tee /etc/ophion/agent.yaml > /dev/null << AGENTEOF
|
||||
server:
|
||||
url: \${SERVER_URL}
|
||||
api_key: \${API_KEY}
|
||||
|
||||
collection:
|
||||
interval: 30s
|
||||
|
||||
metrics:
|
||||
enabled: true
|
||||
include:
|
||||
- cpu
|
||||
- memory
|
||||
- disk
|
||||
- network
|
||||
- processes
|
||||
|
||||
logs:
|
||||
enabled: true
|
||||
paths:
|
||||
- /var/log/syslog
|
||||
- /var/log/auth.log
|
||||
AGENTEOF
|
||||
|
||||
# Criar systemd service
|
||||
sudo tee /etc/systemd/system/ophion-agent.service > /dev/null << SERVICEEOF
|
||||
[Unit]
|
||||
Description=OPHION Monitoring Agent
|
||||
After=network.target
|
||||
|
||||
[Service]
|
||||
Type=simple
|
||||
ExecStart=/usr/local/bin/ophion-agent -config /etc/ophion/agent.yaml
|
||||
Restart=always
|
||||
RestartSec=10
|
||||
|
||||
[Install]
|
||||
WantedBy=multi-user.target
|
||||
SERVICEEOF
|
||||
|
||||
# Iniciar
|
||||
sudo systemctl daemon-reload
|
||||
sudo systemctl enable ophion-agent
|
||||
sudo systemctl start ophion-agent
|
||||
|
||||
echo ""
|
||||
echo "✅ OPHION Agent instalado!"
|
||||
echo " Status: sudo systemctl status ophion-agent"
|
||||
echo " Logs: sudo journalctl -u ophion-agent -f"
|
||||
EOF
|
||||
|
||||
chmod +x "$INSTALL_DIR/scripts/install-agent.sh"
|
||||
log_success "Instalador do agent gerado"
|
||||
}
|
||||
|
||||
# Gerar comandos de gerenciamento
|
||||
generate_cli() {
|
||||
log_info "Gerando CLI de gerenciamento..."
|
||||
|
||||
cat > "$INSTALL_DIR/ophion" << 'EOF'
|
||||
#!/bin/bash
|
||||
#
|
||||
# 🐍 OPHION CLI
|
||||
#
|
||||
|
||||
INSTALL_DIR="/opt/ophion"
|
||||
cd "$INSTALL_DIR"
|
||||
|
||||
# Download docker-compose
|
||||
echo "📥 Downloading OPHION..."
|
||||
curl -fsSL https://raw.githubusercontent.com/bigtux/ophion/main/deploy/docker/docker-compose.yml -o docker-compose.yml
|
||||
case "$1" in
|
||||
start)
|
||||
echo "🚀 Iniciando OPHION..."
|
||||
docker compose up -d
|
||||
echo "✅ OPHION iniciado!"
|
||||
echo " Dashboard: http://localhost:${DASHBOARD_PORT:-3000}"
|
||||
echo " API: http://localhost:${SERVER_PORT:-8080}"
|
||||
;;
|
||||
stop)
|
||||
echo "🛑 Parando OPHION..."
|
||||
docker compose down
|
||||
echo "✅ OPHION parado"
|
||||
;;
|
||||
restart)
|
||||
echo "🔄 Reiniciando OPHION..."
|
||||
docker compose restart
|
||||
echo "✅ OPHION reiniciado"
|
||||
;;
|
||||
status)
|
||||
docker compose ps
|
||||
;;
|
||||
logs)
|
||||
docker compose logs -f ${2:-ophion-server}
|
||||
;;
|
||||
update)
|
||||
echo "📦 Atualizando OPHION..."
|
||||
docker compose pull
|
||||
docker compose up -d
|
||||
echo "✅ OPHION atualizado!"
|
||||
;;
|
||||
backup)
|
||||
BACKUP_DIR="$INSTALL_DIR/backups/$(date +%Y%m%d_%H%M%S)"
|
||||
mkdir -p "$BACKUP_DIR"
|
||||
echo "💾 Criando backup em $BACKUP_DIR..."
|
||||
docker compose exec -T postgres pg_dump -U ophion ophion > "$BACKUP_DIR/postgres.sql"
|
||||
cp "$INSTALL_DIR/.env" "$BACKUP_DIR/"
|
||||
echo "✅ Backup criado!"
|
||||
;;
|
||||
api-key)
|
||||
NEW_KEY="ophion_$(openssl rand -hex 32)"
|
||||
echo "🔑 Nova API Key gerada:"
|
||||
echo ""
|
||||
echo " $NEW_KEY"
|
||||
echo ""
|
||||
echo "⚠️ Salve esta key! Ela não será mostrada novamente."
|
||||
;;
|
||||
agent-install)
|
||||
echo ""
|
||||
echo "Para instalar o agent em outro servidor, execute:"
|
||||
echo ""
|
||||
echo " curl -fsSL http://$(hostname -I | awk '{print $1}'):${SERVER_PORT:-8080}/install-agent.sh | sudo bash"
|
||||
echo ""
|
||||
;;
|
||||
*)
|
||||
echo "🐍 OPHION CLI"
|
||||
echo ""
|
||||
echo "Uso: ophion <comando>"
|
||||
echo ""
|
||||
echo "Comandos:"
|
||||
echo " start Iniciar todos os serviços"
|
||||
echo " stop Parar todos os serviços"
|
||||
echo " restart Reiniciar todos os serviços"
|
||||
echo " status Ver status dos serviços"
|
||||
echo " logs [svc] Ver logs (padrão: ophion-server)"
|
||||
echo " update Atualizar para última versão"
|
||||
echo " backup Criar backup dos dados"
|
||||
echo " api-key Gerar nova API key"
|
||||
echo " agent-install Mostrar comando de instalação do agent"
|
||||
;;
|
||||
esac
|
||||
EOF
|
||||
|
||||
# Generate secrets
|
||||
JWT_SECRET=$(openssl rand -hex 32)
|
||||
echo "JWT_SECRET=$JWT_SECRET" > .env
|
||||
chmod +x "$INSTALL_DIR/ophion"
|
||||
sudo ln -sf "$INSTALL_DIR/ophion" /usr/local/bin/ophion
|
||||
|
||||
log_success "CLI instalado em /usr/local/bin/ophion"
|
||||
}
|
||||
|
||||
# Start services
|
||||
echo "🚀 Starting OPHION..."
|
||||
docker compose up -d
|
||||
# Resumo final
|
||||
show_summary() {
|
||||
echo ""
|
||||
echo -e "${GREEN}═══════════════════════════════════════════════════════════${NC}"
|
||||
echo -e "${GREEN} 🎉 OPHION INSTALADO COM SUCESSO! ${NC}"
|
||||
echo -e "${GREEN}═══════════════════════════════════════════════════════════${NC}"
|
||||
echo ""
|
||||
echo -e " ${CYAN}Organização:${NC} $ORG_NAME"
|
||||
echo -e " ${CYAN}Admin:${NC} $ADMIN_EMAIL"
|
||||
echo ""
|
||||
echo -e " ${CYAN}Dashboard:${NC} http://${DOMAIN}:${DASHBOARD_PORT}"
|
||||
echo -e " ${CYAN}API:${NC} http://${DOMAIN}:${SERVER_PORT}"
|
||||
echo ""
|
||||
echo -e " ${YELLOW}🔑 API Key (SALVE AGORA!):${NC}"
|
||||
echo -e " ${PURPLE}$API_KEY${NC}"
|
||||
echo ""
|
||||
echo -e " ${CYAN}Diretório:${NC} $INSTALL_DIR"
|
||||
echo ""
|
||||
echo -e "${GREEN}───────────────────────────────────────────────────────────${NC}"
|
||||
echo ""
|
||||
echo " Comandos úteis:"
|
||||
echo ""
|
||||
echo " ophion start # Iniciar"
|
||||
echo " ophion stop # Parar"
|
||||
echo " ophion status # Ver status"
|
||||
echo " ophion logs # Ver logs"
|
||||
echo " ophion agent-install # Instalar agent em outros servidores"
|
||||
echo ""
|
||||
echo -e "${GREEN}───────────────────────────────────────────────────────────${NC}"
|
||||
echo ""
|
||||
|
||||
read -p "🚀 Iniciar OPHION agora? (s/n) [s]: " START_NOW
|
||||
START_NOW=${START_NOW:-s}
|
||||
|
||||
if [[ "$START_NOW" =~ ^[sS]$ ]]; then
|
||||
echo ""
|
||||
log_info "Iniciando serviços..."
|
||||
cd "$INSTALL_DIR"
|
||||
docker compose up -d
|
||||
|
||||
echo ""
|
||||
log_success "OPHION está rodando!"
|
||||
echo ""
|
||||
echo -e " Acesse: ${CYAN}http://${DOMAIN}:${DASHBOARD_PORT}${NC}"
|
||||
echo -e " Login: ${CYAN}${ADMIN_EMAIL}${NC}"
|
||||
echo ""
|
||||
fi
|
||||
}
|
||||
|
||||
echo ""
|
||||
echo "✅ OPHION installed successfully!"
|
||||
echo ""
|
||||
echo "📊 Dashboard: http://localhost:3000"
|
||||
echo "🔌 API: http://localhost:8080"
|
||||
echo ""
|
||||
echo "Next steps:"
|
||||
echo "1. Open http://localhost:3000 in your browser"
|
||||
echo "2. Create your admin account"
|
||||
echo "3. Add your first server with the agent"
|
||||
echo ""
|
||||
echo "To install the agent on a server:"
|
||||
echo " curl -fsSL https://get.ophion.io/agent | bash"
|
||||
echo ""
|
||||
# ═══════════════════════════════════════════════════════════
|
||||
# MAIN
|
||||
# ═══════════════════════════════════════════════════════════
|
||||
|
||||
main() {
|
||||
clear
|
||||
show_banner
|
||||
check_requirements
|
||||
collect_info
|
||||
setup_directory
|
||||
generate_env
|
||||
generate_compose
|
||||
generate_init_scripts
|
||||
generate_agent_installer
|
||||
generate_cli
|
||||
show_summary
|
||||
}
|
||||
|
||||
main "$@"
|
||||
|
||||
Reference in New Issue
Block a user