ci: standardize pytest invocation and add security scanning
Some checks failed
Blockchain Synchronization Verification / sync-verification (push) Failing after 8s
CLI Tests / test-cli (push) Successful in 10s
Contract Performance Benchmarks / benchmark-gas-usage (push) Successful in 1m22s
Contract Performance Benchmarks / benchmark-execution-time (push) Successful in 1m11s
Contract Performance Benchmarks / benchmark-throughput (push) Successful in 1m13s
Cross-Chain Functionality Tests / test-cross-chain-sync (push) Failing after 5s
Cross-Chain Functionality Tests / test-cross-chain-transactions (push) Successful in 5s
Cross-Chain Functionality Tests / test-cross-chain-bridge (push) Has been skipped
Cross-Chain Functionality Tests / test-multi-chain-consensus (push) Failing after 3s
Cross-Chain Functionality Tests / aggregate-results (push) Has been skipped
Cross-Node Transaction Testing / transaction-test (push) Successful in 5s
Deploy to Testnet / deploy-testnet (push) Successful in 1m14s
Contract Performance Benchmarks / compare-benchmarks (push) Has been cancelled
Documentation Validation / validate-docs (push) Failing after 10s
Multi-Node Stress Testing / stress-test (push) Has been cancelled
Node Failover Simulation / failover-test (push) Has been cancelled
Security Scanning / security-scan (push) Has been cancelled
Smart Contract Tests / test-solidity (map[name:aitbc-contracts path:contracts]) (push) Has been cancelled
Smart Contract Tests / test-solidity (map[name:aitbc-token path:packages/solidity/aitbc-token]) (push) Has been cancelled
Smart Contract Tests / test-foundry (push) Has been cancelled
Smart Contract Tests / lint-solidity (push) Has been cancelled
Smart Contract Tests / deploy-contracts (push) Has been cancelled
Documentation Validation / validate-policies-strict (push) Successful in 3s
Integration Tests / test-service-integration (push) Failing after 45s
Multi-Chain Island Architecture Tests / test-multi-chain-island (push) Failing after 2s
Multi-Node Blockchain Health Monitoring / health-check (push) Successful in 5s
P2P Network Verification / p2p-verification (push) Successful in 3s
Production Tests / Production Integration Tests (push) Failing after 7s
Python Tests / test-python (push) Failing after 46s
Staking Tests / test-staking-service (push) Failing after 2s
Staking Tests / test-staking-integration (push) Has been skipped
Staking Tests / test-staking-contract (push) Has been skipped
Staking Tests / run-staking-test-runner (push) Has been skipped
Systemd Sync / sync-systemd (push) Successful in 21s
API Endpoint Tests / test-api-endpoints (push) Failing after 12m19s
Some checks failed
Blockchain Synchronization Verification / sync-verification (push) Failing after 8s
CLI Tests / test-cli (push) Successful in 10s
Contract Performance Benchmarks / benchmark-gas-usage (push) Successful in 1m22s
Contract Performance Benchmarks / benchmark-execution-time (push) Successful in 1m11s
Contract Performance Benchmarks / benchmark-throughput (push) Successful in 1m13s
Cross-Chain Functionality Tests / test-cross-chain-sync (push) Failing after 5s
Cross-Chain Functionality Tests / test-cross-chain-transactions (push) Successful in 5s
Cross-Chain Functionality Tests / test-cross-chain-bridge (push) Has been skipped
Cross-Chain Functionality Tests / test-multi-chain-consensus (push) Failing after 3s
Cross-Chain Functionality Tests / aggregate-results (push) Has been skipped
Cross-Node Transaction Testing / transaction-test (push) Successful in 5s
Deploy to Testnet / deploy-testnet (push) Successful in 1m14s
Contract Performance Benchmarks / compare-benchmarks (push) Has been cancelled
Documentation Validation / validate-docs (push) Failing after 10s
Multi-Node Stress Testing / stress-test (push) Has been cancelled
Node Failover Simulation / failover-test (push) Has been cancelled
Security Scanning / security-scan (push) Has been cancelled
Smart Contract Tests / test-solidity (map[name:aitbc-contracts path:contracts]) (push) Has been cancelled
Smart Contract Tests / test-solidity (map[name:aitbc-token path:packages/solidity/aitbc-token]) (push) Has been cancelled
Smart Contract Tests / test-foundry (push) Has been cancelled
Smart Contract Tests / lint-solidity (push) Has been cancelled
Smart Contract Tests / deploy-contracts (push) Has been cancelled
Documentation Validation / validate-policies-strict (push) Successful in 3s
Integration Tests / test-service-integration (push) Failing after 45s
Multi-Chain Island Architecture Tests / test-multi-chain-island (push) Failing after 2s
Multi-Node Blockchain Health Monitoring / health-check (push) Successful in 5s
P2P Network Verification / p2p-verification (push) Successful in 3s
Production Tests / Production Integration Tests (push) Failing after 7s
Python Tests / test-python (push) Failing after 46s
Staking Tests / test-staking-service (push) Failing after 2s
Staking Tests / test-staking-integration (push) Has been skipped
Staking Tests / test-staking-contract (push) Has been skipped
Staking Tests / run-staking-test-runner (push) Has been skipped
Systemd Sync / sync-systemd (push) Successful in 21s
API Endpoint Tests / test-api-endpoints (push) Failing after 12m19s
- Changed pytest calls to use `venv/bin/python -m pytest` with explicit config - Added `--rootdir "$PWD"` and `--import-mode=importlib` for consistent imports - Fixed PYTHONPATH to use absolute paths with $PWD prefix - Added smart contract security scanning for Solidity files - Added Circom circuit security checks for ZK proof circuits - Added ZK proof implementation security validation - Added contracts/** to security scanning workflow
This commit is contained in:
432
scripts/deploy/deploy.sh
Executable file
432
scripts/deploy/deploy.sh
Executable file
@@ -0,0 +1,432 @@
|
||||
#!/bin/bash
|
||||
|
||||
# AITBC Systemd Deployment Script
|
||||
# One-command setup for AITBC services using systemd
|
||||
# This script handles automated deployment of AITBC services on Linux servers
|
||||
|
||||
set -e
|
||||
|
||||
SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)"
|
||||
source "$SCRIPT_DIR/../utils/deploy_common.sh"
|
||||
|
||||
# Configuration
|
||||
REPO_ROOT="${REPO_ROOT:-/opt/aitbc}"
|
||||
VENV_DIR="$REPO_ROOT/venv"
|
||||
PYTHON_VERSION="3.13"
|
||||
BACKUP_DIR="$REPO_ROOT/.backup"
|
||||
|
||||
# Check prerequisites
|
||||
check_prerequisites() {
|
||||
log "Checking system prerequisites..."
|
||||
|
||||
check_root
|
||||
|
||||
# Check Linux distribution
|
||||
if [[ ! -f /etc/os-release ]]; then
|
||||
error "Cannot detect Linux distribution"
|
||||
fi
|
||||
source /etc/os-release
|
||||
log "Detected OS: $PRETTY_NAME"
|
||||
|
||||
# Check Python version
|
||||
require_command python3
|
||||
|
||||
PYTHON_VER=$(python3 --version | awk '{print $2}')
|
||||
log "Python version: $PYTHON_VER"
|
||||
require_min_version "$PYTHON_VER" "$PYTHON_VERSION" "Python"
|
||||
|
||||
# Check systemd
|
||||
require_command systemctl
|
||||
|
||||
# Check required system tools
|
||||
require_commands git curl jq
|
||||
|
||||
success "Prerequisites check passed"
|
||||
}
|
||||
|
||||
# Install system dependencies
|
||||
install_dependencies() {
|
||||
log "Installing system dependencies..."
|
||||
|
||||
if [[ "$ID" == "ubuntu" ]] || [[ "$ID" == "debian" ]]; then
|
||||
apt-get update
|
||||
apt-get install -y \
|
||||
python3-venv \
|
||||
python3-dev \
|
||||
build-essential \
|
||||
libssl-dev \
|
||||
libffi-dev \
|
||||
postgresql \
|
||||
postgresql-contrib \
|
||||
redis-server \
|
||||
nginx \
|
||||
jq \
|
||||
curl \
|
||||
git
|
||||
elif [[ "$ID" == "centos" ]] || [[ "$ID" == "rhel" ]] || [[ "$ID" == "fedora" ]]; then
|
||||
dnf install -y \
|
||||
python3-venv \
|
||||
python3-devel \
|
||||
gcc \
|
||||
openssl-devel \
|
||||
libffi-devel \
|
||||
postgresql-server \
|
||||
postgresql-contrib \
|
||||
redis \
|
||||
nginx \
|
||||
jq \
|
||||
curl \
|
||||
git
|
||||
else
|
||||
warning "Unsupported distribution. Please install dependencies manually"
|
||||
return 0
|
||||
fi
|
||||
|
||||
success "System dependencies installed"
|
||||
}
|
||||
|
||||
# Setup repository
|
||||
setup_repository() {
|
||||
log "Setting up repository..."
|
||||
|
||||
# Create backup of existing deployment
|
||||
if [[ -d "$REPO_ROOT" ]]; then
|
||||
log "Creating backup of existing deployment..."
|
||||
BACKUP_TIMESTAMP=$(date +%Y%m%d_%H%M%S)
|
||||
BACKUP_PATH="$BACKUP_DIR/backup_$BACKUP_TIMESTAMP"
|
||||
mkdir -p "$BACKUP_DIR"
|
||||
cp -r "$REPO_ROOT" "$BACKUP_PATH" || warning "Backup failed, continuing anyway"
|
||||
log "Backup created at: $BACKUP_PATH"
|
||||
fi
|
||||
|
||||
# Clone or update repository
|
||||
if [[ -d "$REPO_ROOT/.git" ]]; then
|
||||
log "Updating existing repository..."
|
||||
cd "$REPO_ROOT"
|
||||
git pull || warning "Git pull failed, continuing with existing code"
|
||||
else
|
||||
log "Cloning repository..."
|
||||
# REPO_URL should be set as environment variable
|
||||
REPO_URL="${REPO_URL:-https://github.com/your-org/aitbc.git}"
|
||||
git clone "$REPO_URL" "$REPO_ROOT"
|
||||
fi
|
||||
|
||||
success "Repository setup completed"
|
||||
}
|
||||
|
||||
# Create virtual environment
|
||||
create_venv() {
|
||||
log "Creating Python virtual environment..."
|
||||
|
||||
if [[ -d "$VENV_DIR" ]]; then
|
||||
log "Virtual environment already exists, recreating..."
|
||||
rm -rf "$VENV_DIR"
|
||||
fi
|
||||
|
||||
python3 -m venv "$VENV_DIR"
|
||||
success "Virtual environment created"
|
||||
}
|
||||
|
||||
# Install Python dependencies
|
||||
install_python_dependencies() {
|
||||
log "Installing Python dependencies..."
|
||||
|
||||
# Activate virtual environment
|
||||
source "$VENV_DIR/bin/activate"
|
||||
|
||||
# Upgrade pip
|
||||
pip install --upgrade pip setuptools wheel
|
||||
|
||||
# Install requirements
|
||||
if [[ -f "$REPO_ROOT/requirements.txt" ]]; then
|
||||
pip install -r "$REPO_ROOT/requirements.txt"
|
||||
else
|
||||
warning "requirements.txt not found, installing basic dependencies"
|
||||
pip install fastapi uvicorn sqlmodel alembic pydantic httpx requests
|
||||
fi
|
||||
|
||||
success "Python dependencies installed"
|
||||
}
|
||||
|
||||
# Configure environment
|
||||
configure_environment() {
|
||||
log "Configuring environment variables..."
|
||||
|
||||
# Create /etc/aitbc directory
|
||||
mkdir -p /etc/aitbc
|
||||
|
||||
# Setup node.env if it doesn't exist
|
||||
if [[ ! -f /etc/aitbc/node.env ]] && [[ -f "$REPO_ROOT/examples/node.env.example" ]]; then
|
||||
cp "$REPO_ROOT/examples/node.env.example" /etc/aitbc/node.env
|
||||
warning "Created /etc/aitbc/node.env from template. Please edit with node-specific values"
|
||||
fi
|
||||
|
||||
# Generate unique node IDs if not set
|
||||
if [[ -f /etc/aitbc/node.env ]]; then
|
||||
if grep -q "node-<unique-uuid-here>" /etc/aitbc/node.env; then
|
||||
log "Generating unique node IDs..."
|
||||
UUID=$(uuidgen | tr -d '-')
|
||||
sed -i "s/node-<unique-uuid-here>/node-$UUID/g" /etc/aitbc/node.env
|
||||
sed -i "s/ait1<unique-uuid-here>/ait1$UUID/g" /etc/aitbc/node.env
|
||||
log "Generated node IDs with UUID: $UUID"
|
||||
fi
|
||||
fi
|
||||
|
||||
# Setup blockchain.env if it doesn't exist
|
||||
if [[ ! -f /etc/aitbc/blockchain.env ]]; then
|
||||
if [[ -f "$REPO_ROOT/examples/env.example" ]]; then
|
||||
# Extract relevant blockchain configuration from examples/env.example
|
||||
grep -E "^(chain_id|CHAIN_ID|rpc_bind_host|rpc_bind_port|p2p_bind_host|p2p_bind_port|enable_block_production|block_time_seconds|proposer_id)" "$REPO_ROOT/examples/env.example" > /etc/aitbc/blockchain.env || true
|
||||
fi
|
||||
|
||||
# Add defaults if file is empty
|
||||
if [[ ! -s /etc/aitbc/blockchain.env ]]; then
|
||||
cat > /etc/aitbc/blockchain.env << EOF
|
||||
# Blockchain Configuration
|
||||
chain_id=ait-testnet
|
||||
rpc_bind_host=0.0.0.0
|
||||
rpc_bind_port=8006
|
||||
p2p_bind_host=0.0.0.0
|
||||
p2p_bind_port=7070
|
||||
enable_block_production=true
|
||||
EOF
|
||||
fi
|
||||
fi
|
||||
|
||||
# Setup secrets directory
|
||||
mkdir -p /run/aitbc/secrets
|
||||
touch /run/aitbc/secrets/.env
|
||||
|
||||
success "Environment configuration completed"
|
||||
}
|
||||
|
||||
# Initialize databases
|
||||
initialize_databases() {
|
||||
log "Initializing databases..."
|
||||
|
||||
# Start PostgreSQL if not running
|
||||
if systemctl is-active --quiet postgresql || systemctl is-active --quiet postgresql@13-main; then
|
||||
log "PostgreSQL is already running"
|
||||
else
|
||||
log "Starting PostgreSQL..."
|
||||
systemctl start postgresql || systemctl start postgresql@13-main || warning "Failed to start PostgreSQL"
|
||||
fi
|
||||
|
||||
# Create databases if they don't exist
|
||||
if command -v psql &> /dev/null; then
|
||||
for db in aitbc aitbc_coordinator aitbc_marketplace; do
|
||||
if ! sudo -u postgres psql -lqt | cut -d \| -f 1 | grep -qw $db; then
|
||||
log "Creating database: $db"
|
||||
sudo -u postgres createdb $db || warning "Failed to create database $db"
|
||||
fi
|
||||
done
|
||||
fi
|
||||
|
||||
# Start Redis if not running
|
||||
if systemctl is-active --quiet redis-server || systemctl is-active --quiet redis; then
|
||||
log "Redis is already running"
|
||||
else
|
||||
log "Starting Redis..."
|
||||
systemctl start redis-server || systemctl start redis || warning "Failed to start Redis"
|
||||
fi
|
||||
|
||||
success "Database initialization completed"
|
||||
}
|
||||
|
||||
# Setup systemd services
|
||||
setup_systemd_services() {
|
||||
log "Setting up systemd services..."
|
||||
|
||||
# Link systemd service files
|
||||
if [[ -f "$REPO_ROOT/scripts/utils/link-systemd.sh" ]]; then
|
||||
bash "$REPO_ROOT/scripts/utils/link-systemd.sh"
|
||||
else
|
||||
# Manual linking
|
||||
log "Linking systemd service files..."
|
||||
mkdir -p /etc/systemd/system
|
||||
for service in "$REPO_ROOT/systemd"/*.service; do
|
||||
if [[ -f "$service" ]]; then
|
||||
ln -sf "$service" "/etc/systemd/system/$(basename $service)"
|
||||
fi
|
||||
done
|
||||
fi
|
||||
|
||||
# Reload systemd
|
||||
systemctl daemon-reload
|
||||
|
||||
success "Systemd services setup completed"
|
||||
}
|
||||
|
||||
# Start services in dependency order
|
||||
start_services() {
|
||||
log "Starting AITBC services..."
|
||||
|
||||
# Define service startup order
|
||||
SERVICES=(
|
||||
"postgresql"
|
||||
"redis-server"
|
||||
"aitbc-blockchain-p2p"
|
||||
"aitbc-blockchain-node"
|
||||
"aitbc-blockchain-rpc"
|
||||
"aitbc-coordinator-api"
|
||||
"aitbc-exchange-api"
|
||||
"aitbc-wallet"
|
||||
"aitbc-agent-daemon"
|
||||
"aitbc-agent-coordinator"
|
||||
"aitbc-marketplace"
|
||||
)
|
||||
|
||||
for service in "${SERVICES[@]}"; do
|
||||
log "Starting $service..."
|
||||
if systemctl list-unit-files | grep -q "^$service.service"; then
|
||||
systemctl enable "$service" 2>/dev/null || true
|
||||
systemctl start "$service" || warning "Failed to start $service"
|
||||
sleep 2
|
||||
else
|
||||
log "$service not found, skipping"
|
||||
fi
|
||||
done
|
||||
|
||||
success "Services started"
|
||||
}
|
||||
|
||||
# Run health checks
|
||||
run_health_checks() {
|
||||
log "Running health checks..."
|
||||
|
||||
# Wait for services to be ready
|
||||
log "Waiting for services to stabilize..."
|
||||
sleep 10
|
||||
|
||||
# Check service status
|
||||
FAILED_SERVICES=()
|
||||
for service in aitbc-blockchain-node aitbc-blockchain-rpc aitbc-coordinator-api; do
|
||||
if systemctl is-active --quiet "$service"; then
|
||||
success "$service is running"
|
||||
else
|
||||
error "$service is not running"
|
||||
FAILED_SERVICES+=("$service")
|
||||
fi
|
||||
done
|
||||
|
||||
# Check API endpoints if available
|
||||
if command -v curl &> /dev/null; then
|
||||
log "Checking API endpoints..."
|
||||
|
||||
# Check blockchain RPC
|
||||
if curl -sf http://localhost:8006/health > /dev/null 2>&1; then
|
||||
success "Blockchain RPC health check passed"
|
||||
else
|
||||
warning "Blockchain RPC health check failed"
|
||||
fi
|
||||
|
||||
# Check coordinator API
|
||||
if curl -sf http://localhost:8011/health > /dev/null 2>&1; then
|
||||
success "Coordinator API health check passed"
|
||||
else
|
||||
warning "Coordinator API health check failed"
|
||||
fi
|
||||
fi
|
||||
|
||||
if [[ ${#FAILED_SERVICES[@]} -gt 0 ]]; then
|
||||
error "Some services failed to start: ${FAILED_SERVICES[*]}"
|
||||
fi
|
||||
|
||||
success "Health checks completed"
|
||||
}
|
||||
|
||||
# Rollback deployment
|
||||
rollback_deployment() {
|
||||
log "Rolling back deployment..."
|
||||
|
||||
# Find latest backup
|
||||
LATEST_BACKUP=$(ls -t "$BACKUP_DIR"/backup_* 2>/dev/null | head -1)
|
||||
|
||||
if [[ -z "$LATEST_BACKUP" ]]; then
|
||||
error "No backup found for rollback"
|
||||
fi
|
||||
|
||||
log "Restoring from: $LATEST_BACKUP"
|
||||
|
||||
# Stop services
|
||||
log "Stopping services..."
|
||||
for service in aitbc-*; do
|
||||
systemctl stop "$service" 2>/dev/null || true
|
||||
done
|
||||
|
||||
# Restore backup
|
||||
rm -rf "$REPO_ROOT"
|
||||
cp -r "$LATEST_BACKUP" "$REPO_ROOT"
|
||||
|
||||
# Restart services
|
||||
start_services
|
||||
|
||||
success "Rollback completed"
|
||||
}
|
||||
|
||||
# Display deployment status
|
||||
display_status() {
|
||||
log "Deployment Status"
|
||||
echo "=================="
|
||||
echo "Repository: $REPO_ROOT"
|
||||
echo "Virtual Environment: $VENV_DIR"
|
||||
echo "Python: $(python3 --version)"
|
||||
echo ""
|
||||
echo "Service Status:"
|
||||
systemctl list-units --type=service --state=running | grep aitbc || echo "No AITBC services running"
|
||||
echo ""
|
||||
echo "Next Steps:"
|
||||
echo "1. Edit /etc/aitbc/blockchain.env with blockchain configuration"
|
||||
echo "2. Edit /etc/aitbc/node.env with node-specific values"
|
||||
echo "3. Restart services: systemctl restart aitbc-*"
|
||||
echo "4. Check logs: journalctl -u aitbc-blockchain-node -f"
|
||||
echo "5. Run health checks: $REPO_ROOT/scripts/monitoring/health_check.sh"
|
||||
}
|
||||
|
||||
# Main deployment function
|
||||
main() {
|
||||
local COMMAND="${1:-deploy}"
|
||||
|
||||
case "$COMMAND" in
|
||||
"deploy")
|
||||
log "Starting AITBC deployment..."
|
||||
check_prerequisites
|
||||
install_dependencies
|
||||
setup_repository
|
||||
create_venv
|
||||
install_python_dependencies
|
||||
configure_environment
|
||||
initialize_databases
|
||||
setup_systemd_services
|
||||
start_services
|
||||
run_health_checks
|
||||
display_status
|
||||
success "Deployment completed successfully!"
|
||||
;;
|
||||
"rollback")
|
||||
rollback_deployment
|
||||
;;
|
||||
"status")
|
||||
display_status
|
||||
;;
|
||||
"health-check")
|
||||
run_health_checks
|
||||
;;
|
||||
*)
|
||||
echo "Usage: $0 {deploy|rollback|status|health-check}"
|
||||
echo ""
|
||||
echo "Commands:"
|
||||
echo " deploy - Full deployment of AITBC services"
|
||||
echo " rollback - Rollback to previous deployment"
|
||||
echo " status - Display deployment status"
|
||||
echo " health-check - Run health checks on services"
|
||||
exit 1
|
||||
;;
|
||||
esac
|
||||
}
|
||||
|
||||
# Handle script interruption
|
||||
trap 'error "Script interrupted"' INT TERM
|
||||
|
||||
# Run main function
|
||||
main "$@"
|
||||
350
scripts/deploy/validate-env.sh
Executable file
350
scripts/deploy/validate-env.sh
Executable file
@@ -0,0 +1,350 @@
|
||||
#!/bin/bash
|
||||
|
||||
# AITBC Environment Validation Script
|
||||
# Validates environment configuration before deployment
|
||||
|
||||
set -e
|
||||
|
||||
# Configuration
|
||||
REPO_ROOT="${REPO_ROOT:-/opt/aitbc}"
|
||||
NODE_ENV_FILE="/etc/aitbc/node.env"
|
||||
BLOCKCHAIN_ENV_FILE="/etc/aitbc/blockchain.env"
|
||||
|
||||
# Colors for output
|
||||
RED='\033[0;31m'
|
||||
GREEN='\033[0;32m'
|
||||
YELLOW='\033[1;33m'
|
||||
BLUE='\033[0;34m'
|
||||
NC='\033[0m' # No Color
|
||||
|
||||
# Logging functions
|
||||
log() {
|
||||
echo -e "${BLUE}[INFO]${NC} $1"
|
||||
}
|
||||
|
||||
error() {
|
||||
echo -e "${RED}[ERROR]${NC} $1"
|
||||
}
|
||||
|
||||
success() {
|
||||
echo -e "${GREEN}[SUCCESS]${NC} $1"
|
||||
}
|
||||
|
||||
warning() {
|
||||
echo -e "${YELLOW}[WARNING]${NC} $1"
|
||||
}
|
||||
|
||||
# Validate port number
|
||||
validate_port() {
|
||||
local port="$1"
|
||||
local name="$2"
|
||||
|
||||
if [[ ! "$port" =~ ^[0-9]+$ ]]; then
|
||||
error "$name: '$port' is not a valid number"
|
||||
return 1
|
||||
fi
|
||||
|
||||
if [[ "$port" -lt 1 ]] || [[ "$port" -gt 65535 ]]; then
|
||||
error "$name: '$port' is out of valid range (1-65535)"
|
||||
return 1
|
||||
fi
|
||||
|
||||
# Check if port is already in use
|
||||
if command -v ss &> /dev/null; then
|
||||
if ss -tuln | grep -q ":$port "; then
|
||||
warning "$name: Port $port is already in use"
|
||||
fi
|
||||
fi
|
||||
|
||||
return 0
|
||||
}
|
||||
|
||||
# Validate URL format
|
||||
validate_url() {
|
||||
local url="$1"
|
||||
local name="$2"
|
||||
|
||||
if [[ ! "$url" =~ ^[a-zA-Z+]+:// ]]; then
|
||||
error "$name: '$url' is not a valid URL"
|
||||
return 1
|
||||
fi
|
||||
|
||||
return 0
|
||||
}
|
||||
|
||||
# Validate boolean
|
||||
validate_boolean() {
|
||||
local value="$1"
|
||||
local name="$2"
|
||||
|
||||
if [[ "$value" != "true" ]] && [[ "$value" != "false" ]]; then
|
||||
error "$name: '$value' must be 'true' or 'false'"
|
||||
return 1
|
||||
fi
|
||||
|
||||
return 0
|
||||
}
|
||||
|
||||
# Validate database connectivity
|
||||
validate_database() {
|
||||
local db_url="$1"
|
||||
local name="$2"
|
||||
|
||||
if [[ "$db_url" =~ postgresql:// ]] || [[ "$db_url" =~ postgresql\+asyncpg:// ]]; then
|
||||
log "$name: PostgreSQL URL detected"
|
||||
|
||||
# Extract host and port
|
||||
local host=$(echo "$db_url" | sed -n 's/.*@\([^:]*\):.*/\1/p')
|
||||
local port=$(echo "$db_url" | sed -n 's/.*:\([0-9]*\)\/.*/\1/p')
|
||||
|
||||
if [[ -n "$host" ]] && [[ -n "$port" ]]; then
|
||||
log "Testing PostgreSQL connectivity to $host:$port..."
|
||||
if command -v pg_isready &> /dev/null; then
|
||||
if pg_isready -h "$host" -p "$port" &> /dev/null; then
|
||||
success "$name: PostgreSQL is reachable"
|
||||
else
|
||||
warning "$name: PostgreSQL is not reachable at $host:$port"
|
||||
fi
|
||||
fi
|
||||
fi
|
||||
elif [[ "$db_url" =~ sqlite:// ]] || [[ "$db_url" =~ sqlite\+aiosqlite:// ]]; then
|
||||
log "$name: SQLite URL detected"
|
||||
|
||||
# Extract database path
|
||||
local db_path=$(echo "$db_url" | sed -n 's/.*\/\/\([^?]*\).*/\1/p')
|
||||
|
||||
if [[ -n "$db_path" ]]; then
|
||||
local db_dir=$(dirname "$db_path")
|
||||
if [[ ! -d "$db_dir" ]]; then
|
||||
warning "$name: Database directory $db_dir does not exist"
|
||||
else
|
||||
if [[ ! -w "$db_dir" ]]; then
|
||||
error "$name: Database directory $db_dir is not writable"
|
||||
return 1
|
||||
fi
|
||||
fi
|
||||
fi
|
||||
else
|
||||
error "$name: Unsupported database URL format"
|
||||
return 1
|
||||
fi
|
||||
|
||||
return 0
|
||||
}
|
||||
|
||||
# Validate Redis connectivity
|
||||
validate_redis() {
|
||||
local redis_host="${1:-localhost}"
|
||||
local redis_port="${2:-6379}"
|
||||
|
||||
log "Testing Redis connectivity to $redis_host:$redis_port..."
|
||||
|
||||
if command -v redis-cli &> /dev/null; then
|
||||
if redis-cli -h "$redis_host" -p "$redis_port" ping &> /dev/null; then
|
||||
success "Redis is reachable"
|
||||
else
|
||||
warning "Redis is not reachable at $redis_host:$redis_port"
|
||||
fi
|
||||
else
|
||||
warning "redis-cli not found, skipping Redis connectivity check"
|
||||
fi
|
||||
}
|
||||
|
||||
# Validate environment file
|
||||
validate_env_file() {
|
||||
local env_file="$1"
|
||||
local file_name="$2"
|
||||
|
||||
if [[ ! -f "$env_file" ]]; then
|
||||
error "$file_name: File not found at $env_file"
|
||||
return 1
|
||||
fi
|
||||
|
||||
if [[ ! -r "$env_file" ]]; then
|
||||
error "$file_name: File is not readable"
|
||||
return 1
|
||||
fi
|
||||
|
||||
log "Validating $file_name..."
|
||||
|
||||
# Source the file to validate variables
|
||||
source "$env_file"
|
||||
|
||||
return 0
|
||||
}
|
||||
|
||||
# Validate blockchain.env file
|
||||
validate_blockchain_env() {
|
||||
log "Validating blockchain.env file..."
|
||||
|
||||
if [[ ! -f "$BLOCKCHAIN_ENV_FILE" ]]; then
|
||||
error "blockchain.env not found at $BLOCKCHAIN_ENV_FILE"
|
||||
error "Please create /etc/aitbc/blockchain.env with blockchain configuration"
|
||||
return 1
|
||||
fi
|
||||
|
||||
# Load environment variables
|
||||
source "$BLOCKCHAIN_ENV_FILE"
|
||||
|
||||
ERRORS=0
|
||||
|
||||
# Validate blockchain configuration
|
||||
if [[ -z "$chain_id" ]] && [[ -z "$CHAIN_ID" ]]; then
|
||||
error "chain_id or CHAIN_ID is not set"
|
||||
ERRORS=$((ERRORS + 1))
|
||||
fi
|
||||
|
||||
if [[ -n "$rpc_bind_port" ]]; then
|
||||
validate_port "$rpc_bind_port" "rpc_bind_port" || ERRORS=$((ERRORS + 1))
|
||||
fi
|
||||
|
||||
if [[ -n "$p2p_bind_port" ]]; then
|
||||
validate_port "$p2p_bind_port" "p2p_bind_port" || ERRORS=$((ERRORS + 1))
|
||||
fi
|
||||
|
||||
# Validate boolean settings
|
||||
if [[ -n "$enable_block_production" ]]; then
|
||||
validate_boolean "$enable_block_production" "enable_block_production" || ERRORS=$((ERRORS + 1))
|
||||
fi
|
||||
|
||||
if [[ $ERRORS -gt 0 ]]; then
|
||||
error "Found $ERRORS error(s) in blockchain.env file"
|
||||
return 1
|
||||
fi
|
||||
|
||||
success "blockchain.env file validation passed"
|
||||
return 0
|
||||
}
|
||||
|
||||
# Validate node.env file
|
||||
validate_node_env() {
|
||||
log "Validating node.env file..."
|
||||
|
||||
if [[ ! -f "$NODE_ENV_FILE" ]]; then
|
||||
error "node.env not found at $NODE_ENV_FILE"
|
||||
error "Please copy examples/node.env.example to /etc/aitbc/node.env"
|
||||
return 1
|
||||
fi
|
||||
|
||||
# Load environment variables
|
||||
source "$NODE_ENV_FILE"
|
||||
|
||||
ERRORS=0
|
||||
|
||||
# Check for placeholder UUIDs
|
||||
if grep -q "node-<unique-uuid-here>" "$NODE_ENV_FILE"; then
|
||||
error "NODE_ID contains placeholder UUID. Please set a unique value"
|
||||
ERRORS=$((ERRORS + 1))
|
||||
fi
|
||||
|
||||
if grep -q "ait1<unique-uuid-here>" "$NODE_ENV_FILE"; then
|
||||
error "proposer_id contains placeholder UUID. Please set a unique value"
|
||||
ERRORS=$((ERRORS + 1))
|
||||
fi
|
||||
|
||||
# Validate required fields
|
||||
if [[ -z "$NODE_ID" ]]; then
|
||||
error "NODE_ID is not set"
|
||||
ERRORS=$((ERRORS + 1))
|
||||
fi
|
||||
|
||||
if [[ -z "$p2p_node_id" ]]; then
|
||||
error "p2p_node_id is not set"
|
||||
ERRORS=$((ERRORS + 1))
|
||||
fi
|
||||
|
||||
if [[ -z "$proposer_id" ]]; then
|
||||
error "proposer_id is not set"
|
||||
ERRORS=$((ERRORS + 1))
|
||||
fi
|
||||
|
||||
if [[ -z "$p2p_peers" ]]; then
|
||||
warning "p2p_peers is not set. This node may not connect to the network"
|
||||
fi
|
||||
|
||||
if [[ $ERRORS -gt 0 ]]; then
|
||||
error "Found $ERRORS error(s) in node.env file"
|
||||
return 1
|
||||
fi
|
||||
|
||||
success "node.env file validation passed"
|
||||
return 0
|
||||
}
|
||||
|
||||
# Check system prerequisites
|
||||
check_system_prerequisites() {
|
||||
log "Checking system prerequisites..."
|
||||
|
||||
ERRORS=0
|
||||
|
||||
# Check Python version
|
||||
if ! command -v python3 &> /dev/null; then
|
||||
error "Python 3 is not installed"
|
||||
ERRORS=$((ERRORS + 1))
|
||||
else
|
||||
PYTHON_VER=$(python3 --version | awk '{print $2}')
|
||||
log "Python version: $PYTHON_VER"
|
||||
fi
|
||||
|
||||
# Check systemd
|
||||
if ! command -v systemctl &> /dev/null; then
|
||||
error "systemd is not available"
|
||||
ERRORS=$((ERRORS + 1))
|
||||
fi
|
||||
|
||||
# Check PostgreSQL
|
||||
if ! command -v psql &> /dev/null; then
|
||||
warning "PostgreSQL client not found. Database validation may be limited"
|
||||
fi
|
||||
|
||||
# Check Redis
|
||||
if ! command -v redis-cli &> /dev/null; then
|
||||
warning "Redis client not found. Redis validation may be limited"
|
||||
fi
|
||||
|
||||
if [[ $ERRORS -gt 0 ]]; then
|
||||
error "System prerequisites check failed"
|
||||
return 1
|
||||
fi
|
||||
|
||||
success "System prerequisites check passed"
|
||||
return 0
|
||||
}
|
||||
|
||||
# Main validation function
|
||||
main() {
|
||||
log "Starting AITBC environment validation..."
|
||||
echo ""
|
||||
|
||||
TOTAL_ERRORS=0
|
||||
|
||||
# Check system prerequisites
|
||||
check_system_prerequisites || TOTAL_ERRORS=$((TOTAL_ERRORS + 1))
|
||||
echo ""
|
||||
|
||||
# Validate environment files (only /etc/aitbc/blockchain.env and /etc/aitbc/node.env are allowed)
|
||||
validate_blockchain_env || TOTAL_ERRORS=$((TOTAL_ERRORS + 1))
|
||||
echo ""
|
||||
|
||||
validate_node_env || TOTAL_ERRORS=$((TOTAL_ERRORS + 1))
|
||||
echo ""
|
||||
|
||||
# Summary
|
||||
if [[ $TOTAL_ERRORS -eq 0 ]]; then
|
||||
success "All environment validation checks passed!"
|
||||
echo ""
|
||||
log "You can proceed with deployment using: scripts/deploy/deploy.sh"
|
||||
return 0
|
||||
else
|
||||
error "Environment validation failed with $TOTAL_ERRORS error(s)"
|
||||
echo ""
|
||||
log "Please fix the errors above before proceeding with deployment"
|
||||
return 1
|
||||
fi
|
||||
}
|
||||
|
||||
# Handle script interruption
|
||||
trap 'error "Script interrupted"' INT TERM
|
||||
|
||||
# Run main function
|
||||
main "$@"
|
||||
Reference in New Issue
Block a user