deploy.sh•12.7 kB
#!/bin/bash
# =================================================================
# MikroTik MCP Server - Build and Deploy Script
# =================================================================
# This script helps build and deploy the MikroTik MCP server
# Usage: ./scripts/deploy.sh [COMMAND] [OPTIONS]
set -e
# Script configuration
SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)"
PROJECT_DIR="$(dirname "$SCRIPT_DIR")"
ENV_FILE="$PROJECT_DIR/.env"
COMPOSE_FILE="$PROJECT_DIR/docker-compose.yml"
# Default values
DEFAULT_ENV="production"
DEFAULT_BUILD_TARGET="production"
# 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 "${GREEN}[$(date +'%Y-%m-%d %H:%M:%S')] $1${NC}"
}
warn() {
echo -e "${YELLOW}[$(date +'%Y-%m-%d %H:%M:%S')] WARNING: $1${NC}"
}
error() {
echo -e "${RED}[$(date +'%Y-%m-%d %H:%M:%S')] ERROR: $1${NC}"
exit 1
}
info() {
echo -e "${BLUE}[$(date +'%Y-%m-%d %H:%M:%S')] INFO: $1${NC}"
}
# Help function
show_help() {
cat << EOF
MikroTik MCP Server - Build and Deploy Script
USAGE:
$0 [COMMAND] [OPTIONS]
COMMANDS:
build Build Docker images
up Start all services
down Stop all services
restart Restart all services
logs Show container logs
status Show container status
shell Open shell in container
test Run tests
clean Clean up containers and images
init Initialize environment
backup Create backup
restore Restore from backup
update Update containers
health Check service health
help Show this help message
OPTIONS:
-e, --env ENV Environment (development|production) [default: production]
-s, --service SERVICE Target specific service
-f, --force Force operation (skip confirmations)
-v, --verbose Verbose output
-h, --help Show help
EXAMPLES:
$0 init # Initialize environment
$0 build # Build all images
$0 up -e development # Start in development mode
$0 logs -s mcp-mikrotik # Show logs for specific service
$0 shell -s routeros # Open shell in RouterOS container
$0 clean -f # Force clean without confirmation
ENVIRONMENT:
The script uses .env file for configuration. Copy .env.example to .env
and customize the values according to your setup.
EOF
}
# Check prerequisites
check_prerequisites() {
log "Checking prerequisites..."
# Check if Docker is installed
if ! command -v docker &> /dev/null; then
error "Docker is not installed. Please install Docker first."
fi
# Check if Docker Compose is installed
if ! command -v docker-compose &> /dev/null && ! docker compose version &> /dev/null; then
error "Docker Compose is not installed. Please install Docker Compose first."
fi
# Check if running as root (warn)
if [[ $EUID -eq 0 ]]; then
warn "Running as root. Consider running as a regular user."
fi
# Check if .env file exists
if [[ ! -f "$ENV_FILE" ]]; then
warn ".env file not found. Creating from .env.example..."
if [[ -f "$PROJECT_DIR/.env.example" ]]; then
cp "$PROJECT_DIR/.env.example" "$ENV_FILE"
info "Created .env file. Please edit it with your configuration."
else
error ".env.example file not found. Cannot create .env file."
fi
fi
log "Prerequisites check completed."
}
# Initialize environment
init_environment() {
log "Initializing environment..."
# Create necessary directories
mkdir -p "$PROJECT_DIR/logs"
mkdir -p "$PROJECT_DIR/backups"
mkdir -p "$PROJECT_DIR/ssh_keys"
# Set proper permissions
chmod 700 "$PROJECT_DIR/ssh_keys"
# Copy configuration files if they don't exist
if [[ ! -f "$PROJECT_DIR/mcp-config.json" ]] && [[ -f "$PROJECT_DIR/mcp-config.json.example" ]]; then
cp "$PROJECT_DIR/mcp-config.json.example" "$PROJECT_DIR/mcp-config.json"
info "Created mcp-config.json from example."
fi
log "Environment initialization completed."
}
# Build Docker images
build_images() {
local target="${1:-$DEFAULT_BUILD_TARGET}"
log "Building Docker images (target: $target)..."
cd "$PROJECT_DIR"
if [[ "$target" == "development" ]]; then
docker-compose build --target builder mcp-mikrotik
else
docker-compose build mcp-mikrotik
fi
log "Docker images built successfully."
}
# Start services
start_services() {
local env="${1:-$DEFAULT_ENV}"
local service="${2:-}"
log "Starting services (environment: $env)..."
cd "$PROJECT_DIR"
# Set compose profiles based on environment
if [[ "$env" == "development" ]]; then
export COMPOSE_PROFILES="dev"
fi
if [[ -n "$service" ]]; then
docker-compose up -d "$service"
log "Service $service started."
else
docker-compose up -d
log "All services started."
fi
# Wait for services to be ready
info "Waiting for services to be ready..."
sleep 5
# Show status
show_status
}
# Stop services
stop_services() {
local service="${1:-}"
log "Stopping services..."
cd "$PROJECT_DIR"
if [[ -n "$service" ]]; then
docker-compose stop "$service"
log "Service $service stopped."
else
docker-compose down
log "All services stopped."
fi
}
# Restart services
restart_services() {
local env="${1:-$DEFAULT_ENV}"
local service="${2:-}"
log "Restarting services..."
stop_services "$service"
sleep 2
start_services "$env" "$service"
}
# Show logs
show_logs() {
local service="${1:-}"
local follow="${2:-false}"
cd "$PROJECT_DIR"
if [[ "$follow" == "true" ]]; then
if [[ -n "$service" ]]; then
docker-compose logs -f "$service"
else
docker-compose logs -f
fi
else
if [[ -n "$service" ]]; then
docker-compose logs --tail=50 "$service"
else
docker-compose logs --tail=50
fi
fi
}
# Show status
show_status() {
log "Checking service status..."
cd "$PROJECT_DIR"
docker-compose ps
# Check health status
log "Health check results:"
docker-compose exec -T mcp-mikrotik python -c "import mcp_mikrotik; print('MCP MikroTik: Healthy')" 2>/dev/null || warn "MCP MikroTik: Unhealthy"
}
# Open shell in container
open_shell() {
local service="${1:-mcp-mikrotik}"
log "Opening shell in $service container..."
cd "$PROJECT_DIR"
if docker-compose ps "$service" | grep -q "Up"; then
docker-compose exec "$service" /bin/bash
else
warn "Service $service is not running. Starting it first..."
docker-compose up -d "$service"
sleep 3
docker-compose exec "$service" /bin/bash
fi
}
# Run tests
run_tests() {
log "Running tests..."
cd "$PROJECT_DIR"
# Build test image
docker-compose -f docker-compose.yml -f docker-compose.test.yml build test || {
# If test compose file doesn't exist, run tests in main container
docker-compose exec mcp-mikrotik python -m pytest tests/ || warn "Tests failed or not available"
}
}
# Clean up
cleanup() {
local force="${1:-false}"
if [[ "$force" != "true" ]]; then
read -p "Are you sure you want to clean up all containers and images? (y/N): " -n 1 -r
echo
if [[ ! $REPLY =~ ^[Yy]$ ]]; then
info "Cleanup cancelled."
return
fi
fi
log "Cleaning up containers and images..."
cd "$PROJECT_DIR"
# Stop and remove containers
docker-compose down -v --remove-orphans
# Remove images
docker-compose down --rmi all 2>/dev/null || true
# Remove unused volumes
docker volume prune -f
# Remove unused networks
docker network prune -f
log "Cleanup completed."
}
# Create backup
create_backup() {
local timestamp=$(date +%Y%m%d_%H%M%S)
local backup_dir="$PROJECT_DIR/backups"
local backup_file="$backup_dir/mikrotik_mcp_backup_$timestamp.tar.gz"
log "Creating backup..."
mkdir -p "$backup_dir"
# Create backup archive
tar -czf "$backup_file" \
-C "$PROJECT_DIR" \
--exclude='*.tar.gz' \
--exclude='logs/*' \
--exclude='.git' \
--exclude='node_modules' \
--exclude='__pycache__' \
.
log "Backup created: $backup_file"
}
# Restore from backup
restore_backup() {
local backup_file="$1"
if [[ -z "$backup_file" ]]; then
error "Backup file not specified. Usage: $0 restore /path/to/backup.tar.gz"
fi
if [[ ! -f "$backup_file" ]]; then
error "Backup file not found: $backup_file"
fi
log "Restoring from backup: $backup_file"
# Stop services first
stop_services
# Extract backup
tar -xzf "$backup_file" -C "$PROJECT_DIR"
log "Backup restored. Starting services..."
start_services
}
# Update containers
update_containers() {
log "Updating containers..."
cd "$PROJECT_DIR"
# Pull latest images
docker-compose pull
# Rebuild and restart
build_images
restart_services
log "Containers updated."
}
# Check health
check_health() {
log "Checking service health..."
cd "$PROJECT_DIR"
# Check if containers are running
if ! docker-compose ps | grep -q "Up"; then
error "No services are running."
fi
# Check MCP server health
if docker-compose exec -T mcp-mikrotik python -c "import mcp_mikrotik; print('OK')" &>/dev/null; then
log "MCP MikroTik server: Healthy"
else
error "MCP MikroTik server: Unhealthy"
fi
# Check RouterOS health (if running)
if docker-compose ps routeros | grep -q "Up"; then
log "RouterOS container: Running"
else
warn "RouterOS container: Not running"
fi
log "Health check completed."
}
# Parse command line arguments
parse_args() {
local env="$DEFAULT_ENV"
local service=""
local force="false"
local verbose="false"
local follow="false"
while [[ $# -gt 0 ]]; do
case $1 in
-e|--env)
env="$2"
shift 2
;;
-s|--service)
service="$2"
shift 2
;;
-f|--force)
force="true"
shift
;;
-v|--verbose)
verbose="true"
set -x
shift
;;
--follow)
follow="true"
shift
;;
-h|--help)
show_help
exit 0
;;
*)
break
;;
esac
done
echo "$env|$service|$force|$verbose|$follow"
}
# Main function
main() {
local command="${1:-help}"
shift || true
# Parse remaining arguments
local args
args=$(parse_args "$@")
IFS='|' read -r env service force verbose follow <<< "$args"
# Change to project directory
cd "$PROJECT_DIR"
case "$command" in
build)
check_prerequisites
build_images "$env"
;;
up|start)
check_prerequisites
start_services "$env" "$service"
;;
down|stop)
stop_services "$service"
;;
restart)
check_prerequisites
restart_services "$env" "$service"
;;
logs)
show_logs "$service" "$follow"
;;
status)
show_status
;;
shell)
open_shell "$service"
;;
test)
run_tests
;;
clean)
cleanup "$force"
;;
init)
check_prerequisites
init_environment
;;
backup)
create_backup
;;
restore)
restore_backup "$1"
;;
update)
check_prerequisites
update_containers
;;
health)
check_health
;;
help|--help|-h)
show_help
;;
*)
error "Unknown command: $command. Use '$0 help' for usage information."
;;
esac
}
# Run main function with all arguments
main "$@"