mockapi/fix_env_port_dynamic.sh
2026-03-16 18:40:22 +00:00

368 lines
No EOL
10 KiB
Bash

#!/bin/bash
# Fix MockAPI to use PORT from .env file dynamically
# This updates the systemd service to read HOST and PORT from .env at runtime
set -e
echo "=== Fix: Make MockAPI use PORT from .env dynamically ==="
echo
APP_DIR="/opt/mockapi"
ENV_FILE="${APP_DIR}/.env"
SERVICE_FILE="/etc/systemd/system/mockapi.service"
WRAPPER_SCRIPT="${APP_DIR}/start_mockapi.sh"
# Colors
GREEN='\033[0;32m'
YELLOW='\033[1;33m'
RED='\033[0;31m'
NC='\033[0m'
print_status() {
echo -e "${GREEN}[+]${NC} $1"
}
print_warning() {
echo -e "${YELLOW}[!]${NC} $1"
}
print_error() {
echo -e "${RED}[!]${NC} $1"
}
# Check if running as root
if [[ $EUID -ne 0 ]]; then
print_error "This script requires sudo privileges."
print_warning "Run with: sudo bash $0"
exit 1
fi
# Step 1: Check if files exist
if [[ ! -f "$ENV_FILE" ]]; then
print_error ".env file not found: $ENV_FILE"
exit 1
fi
if [[ ! -f "$SERVICE_FILE" ]]; then
print_error "Service file not found: $SERVICE_FILE"
exit 1
fi
# Step 2: Ensure PORT exists in .env
print_status "Checking .env file for PORT variable..."
if ! grep -q "^PORT=" "$ENV_FILE"; then
print_warning "PORT not found in .env. Adding PORT=8000..."
echo "PORT=8000" >> "$ENV_FILE"
print_status "Added PORT=8000 to .env"
else
PORT_VALUE=$(grep "^PORT=" "$ENV_FILE" | cut -d'=' -f2)
print_status "Found PORT in .env: $PORT_VALUE"
# Validate PORT is numeric
if [[ ! "$PORT_VALUE" =~ ^[0-9]+$ ]]; then
print_error "PORT is not numeric: '$PORT_VALUE'. Fixing to 8000."
sed -i "s/^PORT=.*/PORT=8000/" "$ENV_FILE"
print_status "Updated PORT to 8000"
fi
fi
# Step 3: Ensure HOST exists in .env
if ! grep -q "^HOST=" "$ENV_FILE"; then
print_warning "HOST not found in .env. Adding HOST=0.0.0.0..."
echo "HOST=0.0.0.0" >> "$ENV_FILE"
fi
# Step 4: Ensure OAUTH2_ISSUER matches port
CURRENT_PORT=$(grep "^PORT=" "$ENV_FILE" | cut -d'=' -f2)
EXPECTED_ISSUER="http://localhost:${CURRENT_PORT}"
if grep -q "^OAUTH2_ISSUER=" "$ENV_FILE"; then
CURRENT_ISSUER=$(grep "^OAUTH2_ISSUER=" "$ENV_FILE" | cut -d'=' -f2)
if [[ "$CURRENT_ISSUER" != "$EXPECTED_ISSUER" ]]; then
print_status "Updating OAUTH2_ISSUER to match port..."
sed -i "s|^OAUTH2_ISSUER=.*|OAUTH2_ISSUER=$EXPECTED_ISSUER|" "$ENV_FILE"
fi
else
print_warning "OAUTH2_ISSUER not found. Adding: $EXPECTED_ISSUER"
echo "OAUTH2_ISSUER=$EXPECTED_ISSUER" >> "$ENV_FILE"
fi
# Step 5: Create wrapper script
print_status "Creating wrapper script: $WRAPPER_SCRIPT"
cat > "$WRAPPER_SCRIPT" << 'EOF'
#!/bin/bash
# Wrapper script to start MockAPI with environment variables from .env
# Source the .env file
if [[ -f "/opt/mockapi/.env" ]]; then
set -a # Automatically export all variables
source "/opt/mockapi/.env"
set +a
else
echo "ERROR: .env file not found at /opt/mockapi/.env" >&2
exit 1
fi
# Validate PORT is numeric
if ! [[ "$PORT" =~ ^[0-9]+$ ]]; then
echo "ERROR: PORT must be numeric, got: '$PORT'" >&2
exit 1
fi
# Set defaults if not defined
HOST=${HOST:-0.0.0.0}
PORT=${PORT:-8000}
# Debug info (only if DEBUG is true)
if [[ "${DEBUG:-false}" == "true" ]] || [[ "${DEBUG:-false}" == "True" ]]; then
echo "Starting MockAPI with HOST=$HOST, PORT=$PORT"
echo "Using virtual environment: /opt/mockapi/venv"
fi
# Execute waitress with variables from .env
exec /opt/mockapi/venv/bin/waitress-serve --host="$HOST" --port="$PORT" wsgi:wsgi_app
EOF
chmod +x "$WRAPPER_SCRIPT"
print_status "Wrapper script created and made executable"
# Step 6: Backup current service file
print_status "Backing up current service file..."
BACKUP_FILE="${SERVICE_FILE}.backup.$(date +%s)"
cp "$SERVICE_FILE" "$BACKUP_FILE"
print_status "Backup created: $BACKUP_FILE"
# Step 7: Extract current settings from service file
CURRENT_USER=$(grep "^User=" "$SERVICE_FILE" | cut -d'=' -f2)
CURRENT_GROUP=$(grep "^Group=" "$SERVICE_FILE" | cut -d'=' -f2)
CURRENT_VENV=$(grep 'Environment="PATH=' "$SERVICE_FILE" | cut -d'=' -f2 | cut -d':' -f1 | sed 's/"//g' || echo "/opt/mockapi/venv")
print_status "Current service settings:"
print_status " User: $CURRENT_USER"
print_status " Group: $CURRENT_GROUP"
print_status " Venv: $CURRENT_VENV"
# Step 8: Create updated service file using wrapper script
print_status "Updating service file to use wrapper script..."
cat > "$SERVICE_FILE" << EOF
[Unit]
Description=Mock API Service
After=network.target
Wants=network.target
[Service]
Type=simple
User=$CURRENT_USER
Group=$CURRENT_GROUP
WorkingDirectory=$APP_DIR
Environment="PATH=$CURRENT_VENV/bin"
Environment="PYTHONPATH=$APP_DIR"
EnvironmentFile=$APP_DIR/.env
# Use wrapper script that sources .env and expands variables
ExecStart=$WRAPPER_SCRIPT
Restart=always
RestartSec=10
StandardOutput=syslog
StandardError=syslog
SyslogIdentifier=mockapi
# Security hardening
NoNewPrivileges=true
PrivateTmp=true
ProtectSystem=strict
ReadWritePaths=$APP_DIR
[Install]
WantedBy=multi-user.target
EOF
print_status "Service file updated to use wrapper script"
# Step 9: Alternative approach - direct variable expansion (simpler)
print_status "Also creating alternative simpler fix..."
# Create a second service file alternative without wrapper script
ALT_SERVICE="${SERVICE_FILE}.alternative"
cat > "$ALT_SERVICE" << 'EOF'
[Unit]
Description=Mock API Service (Alternative - direct expansion)
After=network.target
Wants=network.target
[Service]
Type=simple
User=$CURRENT_USER
Group=$CURRENT_GROUP
WorkingDirectory=$APP_DIR
Environment="PATH=$CURRENT_VENV/bin"
Environment="PYTHONPATH=$APP_DIR"
EnvironmentFile=$APP_DIR/.env
# Systemd expands variables from EnvironmentFile in ExecStart
ExecStart=$CURRENT_VENV/bin/waitress-serve --host=$HOST --port=$PORT wsgi:wsgi_app
Restart=always
RestartSec=10
StandardOutput=syslog
StandardError=syslog
SyslogIdentifier=mockapi
# Security hardening
NoNewPrivileges=true
PrivateTmp=true
ProtectSystem=strict
ReadWritePaths=$APP_DIR
[Install]
WantedBy=multi-user.target
EOF
# Replace $CURRENT_USER, $CURRENT_GROUP, etc. in the alternative file
sed -i "s|\\\$CURRENT_USER|$CURRENT_USER|g" "$ALT_SERVICE"
sed -i "s|\\\$CURRENT_GROUP|$CURRENT_GROUP|g" "$ALT_SERVICE"
sed -i "s|\\\$APP_DIR|$APP_DIR|g" "$ALT_SERVICE"
sed -i "s|\\\$CURRENT_VENV|$CURRENT_VENV|g" "$ALT_SERVICE"
print_status "Alternative service file created: $ALT_SERVICE"
print_status "Note: The alternative uses direct systemd variable expansion"
print_status " The main fix uses a wrapper script (more reliable)"
# Step 10: Test which approach to use
print_status "Testing variable expansion..."
# Try the direct expansion approach first
print_status "Trying direct expansion approach first..."
# Update service file to use direct expansion (cleaner)
cat > "$SERVICE_FILE" << EOF
[Unit]
Description=Mock API Service
After=network.target
Wants=network.target
[Service]
Type=simple
User=$CURRENT_USER
Group=$CURRENT_GROUP
WorkingDirectory=$APP_DIR
Environment="PATH=$CURRENT_VENV/bin"
Environment="PYTHONPATH=$APP_DIR"
EnvironmentFile=$APP_DIR/.env
# Systemd expands variables from EnvironmentFile in ExecStart
ExecStart=$CURRENT_VENV/bin/waitress-serve --host=\$HOST --port=\$PORT wsgi:wsgi_app
Restart=always
RestartSec=10
StandardOutput=syslog
StandardError=syslog
SyslogIdentifier=mockapi
# Security hardening
NoNewPrivileges=true
PrivateTmp=true
ProtectSystem=strict
ReadWritePaths=$APP_DIR
[Install]
WantedBy=multi-user.target
EOF
print_status "Updated service file with direct variable expansion"
print_warning "Note: Using escaped \$HOST and \$PORT to prevent HERE-doc expansion"
print_warning "Systemd should expand these from EnvironmentFile"
# Step 11: Reload and restart
print_status "Reloading systemd daemon..."
systemctl daemon-reload
print_status "Restarting MockAPI service..."
if systemctl restart mockapi; then
print_status "Service restart initiated..."
sleep 3
if systemctl is-active --quiet mockapi; then
print_status "✓ Service is running!"
# Test with current port
CURRENT_PORT=$(grep "^PORT=" "$ENV_FILE" | cut -d'=' -f2)
print_status "Testing health endpoint on port $CURRENT_PORT..."
if curl -f -s --max-time 10 http://localhost:$CURRENT_PORT/health > /dev/null 2>&1; then
print_status "✓ Health check passed!"
echo
echo "=== SUCCESS: MockAPI now uses PORT from .env dynamically ==="
echo
echo "You can now change the port by editing:"
echo " $ENV_FILE"
echo "And updating the PORT variable."
echo
echo "Then restart the service:"
echo " sudo systemctl restart mockapi"
echo
echo "Current configuration:"
echo " PORT: $CURRENT_PORT"
echo " Access: http://localhost:$CURRENT_PORT"
echo " Health: http://localhost:$CURRENT_PORT/health"
echo " Admin: http://localhost:$CURRENT_PORT/admin/login"
else
print_warning "Service running but health check failed."
print_warning "Checking service logs..."
journalctl -u mockapi -n 20 --no-pager
fi
else
print_error "Service failed to start with direct expansion."
print_status "Trying wrapper script approach..."
# Use wrapper script approach
cat > "$SERVICE_FILE" << EOF
[Unit]
Description=Mock API Service
After=network.target
Wants=network.target
[Service]
Type=simple
User=$CURRENT_USER
Group=$CURRENT_GROUP
WorkingDirectory=$APP_DIR
Environment="PATH=$CURRENT_VENV/bin"
EnvironmentFile=$APP_DIR/.env
# Use wrapper script
ExecStart=$WRAPPER_SCRIPT
Restart=always
RestartSec=10
StandardOutput=syslog
StandardError=syslog
SyslogIdentifier=mockapi
[Install]
WantedBy=multi-user.target
EOF
systemctl daemon-reload
systemctl restart mockapi
sleep 3
if systemctl is-active --quiet mockapi; then
print_status "✓ Service running with wrapper script!"
else
print_error "Both approaches failed. Check logs:"
journalctl -u mockapi -n 30 --no-pager
print_status "Restoring backup..."
cp "$BACKUP_FILE" "$SERVICE_FILE"
systemctl daemon-reload
systemctl restart mockapi
fi
fi
else
print_error "Failed to restart service."
systemctl status mockapi --no-pager -l
fi
echo
print_status "=== Fix completed ==="
echo "Backup files:"
echo " Service file: $BACKUP_FILE"
echo " Alternative: $ALT_SERVICE"
echo " Wrapper script: $WRAPPER_SCRIPT"
echo
echo "To change port:"
echo " 1. Edit $ENV_FILE and update PORT value"
echo " 2. Run: sudo systemctl restart mockapi"