368 lines
No EOL
10 KiB
Bash
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" |