fix: ensure required env variables are present in .env

- Add ensure_env_variables function to install missing HOST, PORT, LOG_LEVEL, OAUTH2_ISSUER
- Call function when using existing .env file
- Clean up temporary fix scripts and test files
- Update install.sh with better validation and error handling
This commit is contained in:
cclohmar 2026-03-16 18:58:00 +00:00
parent 81d02ed49b
commit 80e8d93a27
17 changed files with 36 additions and 2642 deletions

View file

@ -1,249 +0,0 @@
#!/bin/bash
# Change MockAPI port configuration
# Run this script to change the port MockAPI runs on
set -e
echo "=== MockAPI Port Change Utility ==="
echo
APP_DIR="/opt/mockapi"
ENV_FILE="${APP_DIR}/.env"
SERVICE_FILE="/etc/systemd/system/mockapi.service"
# Colors for output
RED='\033[0;31m'
GREEN='\033[0;32m'
YELLOW='\033[1;33m'
BLUE='\033[0;34m'
NC='\033[0m' # No Color
print_status() {
echo -e "${GREEN}[+]${NC} $1"
}
print_warning() {
echo -e "${YELLOW}[!]${NC} $1"
}
print_error() {
echo -e "${RED}[!]${NC} $1"
}
print_info() {
echo -e "${BLUE}[i]${NC} $1"
}
# Check if running as root or with sudo
if [[ $EUID -ne 0 ]]; then
print_error "This script requires sudo privileges."
print_info "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: Show current configuration
print_status "Current configuration:"
CURRENT_PORT=$(grep "^PORT=" "$ENV_FILE" | cut -d'=' -f2 || echo "8000")
CURRENT_HOST=$(grep "^HOST=" "$ENV_FILE" | cut -d'=' -f2 || echo "0.0.0.0")
CURRENT_ISSUER=$(grep "^OAUTH2_ISSUER=" "$ENV_FILE" | cut -d'=' -f2 || echo "http://localhost:${CURRENT_PORT}")
echo " Current PORT: $CURRENT_PORT"
echo " Current HOST: $CURRENT_HOST"
echo " Current OAUTH2_ISSUER: $CURRENT_ISSUER"
echo
# Step 3: Ask for new port
read -p "Enter new port number [$CURRENT_PORT]: " NEW_PORT
NEW_PORT=${NEW_PORT:-$CURRENT_PORT}
# Validate new port
if [[ ! "$NEW_PORT" =~ ^[0-9]+$ ]]; then
print_error "Invalid port number: '$NEW_PORT'. Must be numeric."
exit 1
fi
if [[ "$NEW_PORT" -lt 1 ]] || [[ "$NEW_PORT" -gt 65535 ]]; then
print_error "Port number must be between 1 and 65535."
exit 1
fi
# Check if port is already in use
if command -v netstat &> /dev/null; then
if netstat -tuln | grep -q ":$NEW_PORT "; then
print_warning "Port $NEW_PORT appears to be in use!"
read -p "Continue anyway? (y/N): " -n 1 -r
echo
if [[ ! $REPLY =~ ^[Yy]$ ]]; then
exit 1
fi
fi
elif command -v ss &> /dev/null; then
if ss -tuln | grep -q ":$NEW_PORT "; then
print_warning "Port $NEW_PORT appears to be in use!"
read -p "Continue anyway? (y/N): " -n 1 -r
echo
if [[ ! $REPLY =~ ^[Yy]$ ]]; then
exit 1
fi
fi
fi
# Step 4: Ask for host (optional)
read -p "Enter host address [$CURRENT_HOST]: " NEW_HOST
NEW_HOST=${NEW_HOST:-$CURRENT_HOST}
# Step 5: Backup files
print_status "Creating backups..."
BACKUP_DIR="${APP_DIR}/backup_port_change_$(date +%Y%m%d_%H%M%S)"
mkdir -p "$BACKUP_DIR"
cp "$ENV_FILE" "$BACKUP_DIR/.env.backup"
cp "$SERVICE_FILE" "$BACKUP_DIR/mockapi.service.backup"
print_status "Backups saved to: $BACKUP_DIR"
# Step 6: Update .env file
print_status "Updating .env file..."
# Update PORT
if grep -q "^PORT=" "$ENV_FILE"; then
sed -i "s/^PORT=.*/PORT=$NEW_PORT/" "$ENV_FILE"
else
echo "PORT=$NEW_PORT" >> "$ENV_FILE"
fi
# Update HOST
if grep -q "^HOST=" "$ENV_FILE"; then
sed -i "s/^HOST=.*/HOST=$NEW_HOST/" "$ENV_FILE"
else
echo "HOST=$NEW_HOST" >> "$ENV_FILE"
fi
# Update OAUTH2_ISSUER
NEW_ISSUER="http://localhost:${NEW_PORT}"
if grep -q "^OAUTH2_ISSUER=" "$ENV_FILE"; then
sed -i "s|^OAUTH2_ISSUER=.*|OAUTH2_ISSUER=$NEW_ISSUER|" "$ENV_FILE"
else
echo "OAUTH2_ISSUER=$NEW_ISSUER" >> "$ENV_FILE"
fi
print_status "Updated .env file:"
echo " PORT=$NEW_PORT"
echo " HOST=$NEW_HOST"
echo " OAUTH2_ISSUER=$NEW_ISSUER"
# Step 7: Update service file
print_status "Updating service file..."
# Get virtual environment path
VENV_DIR=$(grep 'Environment="PATH=' "$SERVICE_FILE" | cut -d'=' -f2 | cut -d':' -f1 | sed 's/"//g' || echo "/opt/mockapi/venv")
# Get user and group from current service file
SERVICE_USER=$(grep "^User=" "$SERVICE_FILE" | cut -d'=' -f2)
SERVICE_GROUP=$(grep "^Group=" "$SERVICE_FILE" | cut -d'=' -f2)
# Create updated service file
cat > /tmp/mockapi_new.service << EOF
[Unit]
Description=Mock API Service
After=network.target
Wants=network.target
[Service]
Type=simple
User=$SERVICE_USER
Group=$SERVICE_GROUP
WorkingDirectory=$APP_DIR
Environment="PATH=$VENV_DIR/bin"
Environment="PYTHONPATH=$APP_DIR"
EnvironmentFile=$APP_DIR/.env
# Hardcoded port from .env (updated)
ExecStart=$VENV_DIR/bin/waitress-serve --host=$NEW_HOST --port=$NEW_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 service file
cp /tmp/mockapi_new.service "$SERVICE_FILE"
rm -f /tmp/mockapi_new.service
print_status "Service file updated with new port $NEW_PORT."
# Step 8: Reload systemd
print_status "Reloading systemd daemon..."
systemctl daemon-reload
# Step 9: Restart service
print_status "Restarting MockAPI service..."
if systemctl restart mockapi; then
print_status "Service restart initiated."
# Wait for service to start
sleep 3
if systemctl is-active --quiet mockapi; then
print_status "✓ Service is running on port $NEW_PORT!"
# Test health endpoint
print_status "Testing health endpoint..."
if curl -f -s --max-time 10 http://localhost:$NEW_PORT/health > /dev/null 2>&1; then
print_status "✓ Health check passed!"
echo
echo "=== Port Change Successful ==="
echo
echo "MockAPI is now running on:"
echo " URL: http://localhost:$NEW_PORT"
echo " Admin: http://localhost:$NEW_PORT/admin/login"
echo " Docs: http://localhost:$NEW_PORT/docs"
echo " Health: http://localhost:$NEW_PORT/health"
echo
echo "If accessing remotely, use:"
echo " http://$(hostname -I | awk '{print $1}'):$NEW_PORT"
else
print_warning "Service is running but health check failed."
print_info "This might be normal during initial startup."
echo
print_status "Service status:"
systemctl status mockapi --no-pager -l
fi
else
print_error "Service failed to start after port change."
echo
print_warning "Checking service logs..."
journalctl -u mockapi -n 30 --no-pager
echo
print_warning "Restoring from backup..."
cp "$BACKUP_DIR/.env.backup" "$ENV_FILE"
cp "$BACKUP_DIR/mockapi.service.backup" "$SERVICE_FILE"
systemctl daemon-reload
systemctl restart mockapi
print_status "Restored original configuration."
fi
else
print_error "Failed to restart service."
systemctl status mockapi --no-pager -l
fi
echo
print_status "=== Port Change Complete ==="
echo "Backup files are in: $BACKUP_DIR"
echo "If you need to revert, copy files from backup directory."

View file

@ -1,181 +0,0 @@
#!/bin/bash
# Check MockAPI port configuration consistency
# Run this to verify port settings are correct
echo "=== MockAPI Port Configuration Check ==="
echo
APP_DIR="/opt/mockapi"
ENV_FILE="${APP_DIR}/.env"
SERVICE_FILE="/etc/systemd/system/mockapi.service"
# Colors
GREEN='\033[0;32m'
YELLOW='\033[1;33m'
RED='\033[0;31m'
NC='\033[0m' # No Color
print_ok() {
echo -e "${GREEN}[✓]${NC} $1"
}
print_warning() {
echo -e "${YELLOW}[!]${NC} $1"
}
print_error() {
echo -e "${RED}[✗]${NC} $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
print_ok "Checking configuration files..."
# Read values from .env
ENV_PORT=$(grep "^PORT=" "$ENV_FILE" | cut -d'=' -f2 || echo "NOT_FOUND")
ENV_HOST=$(grep "^HOST=" "$ENV_FILE" | cut -d'=' -f2 || echo "NOT_FOUND")
ENV_ISSUER=$(grep "^OAUTH2_ISSUER=" "$ENV_FILE" | cut -d'=' -f2 || echo "NOT_FOUND")
# Read from service file
SERVICE_LINE=$(grep "^ExecStart=" "$SERVICE_FILE" || echo "NOT_FOUND")
if [[ "$SERVICE_LINE" != "NOT_FOUND" ]]; then
# Extract host and port from ExecStart
SERVICE_HOST=$(echo "$SERVICE_LINE" | grep -o -- '--host=[^ ]*' | cut -d'=' -f2 || echo "NOT_FOUND")
SERVICE_PORT=$(echo "$SERVICE_LINE" | grep -o -- '--port=[^ ]*' | cut -d'=' -f2 || echo "NOT_FOUND")
else
SERVICE_HOST="NOT_FOUND"
SERVICE_PORT="NOT_FOUND"
fi
echo
echo "=== Current Configuration ==="
echo
echo ".env file ($ENV_FILE):"
echo " PORT: $ENV_PORT"
echo " HOST: $ENV_HOST"
echo " OAUTH2_ISSUER: $ENV_ISSUER"
echo
echo "Service file ($SERVICE_FILE):"
echo " HOST in ExecStart: $SERVICE_HOST"
echo " PORT in ExecStart: $SERVICE_PORT"
echo
echo "=== Analysis ==="
echo
# Check 1: Port numeric validation
if [[ "$ENV_PORT" =~ ^[0-9]+$ ]]; then
print_ok "PORT in .env is numeric: $ENV_PORT"
else
print_error "PORT in .env is not numeric: '$ENV_PORT'"
fi
if [[ "$SERVICE_PORT" =~ ^[0-9]+$ ]]; then
print_ok "PORT in service file is numeric: $SERVICE_PORT"
else
print_error "PORT in service file is not numeric: '$SERVICE_PORT'"
fi
# Check 2: Port consistency
if [[ "$ENV_PORT" == "$SERVICE_PORT" ]]; then
print_ok "Ports match: .env=$ENV_PORT, service=$SERVICE_PORT"
else
print_error "Port mismatch! .env=$ENV_PORT, service=$SERVICE_PORT"
fi
# Check 3: Host consistency
if [[ "$ENV_HOST" == "$SERVICE_HOST" ]]; then
print_ok "Hosts match: .env=$ENV_HOST, service=$SERVICE_HOST"
elif [[ "$ENV_HOST" == "NOT_FOUND" ]] || [[ "$SERVICE_HOST" == "NOT_FOUND" ]]; then
print_warning "Host not found in one or both files"
else
print_error "Host mismatch! .env=$ENV_HOST, service=$SERVICE_HOST"
fi
# Check 4: OAUTH2_ISSUER consistency
EXPECTED_ISSUER="http://localhost:${ENV_PORT}"
if [[ "$ENV_ISSUER" == "$EXPECTED_ISSUER" ]]; then
print_ok "OAUTH2_ISSUER matches port: $ENV_ISSUER"
elif [[ "$ENV_ISSUER" == "NOT_FOUND" ]]; then
print_warning "OAUTH2_ISSUER not found in .env"
else
print_warning "OAUTH2_ISSUER doesn't match port: $ENV_ISSUER (expected: $EXPECTED_ISSUER)"
fi
# Check 5: Service status
echo
echo "=== Service Status ==="
echo
if systemctl is-active --quiet mockapi 2>/dev/null; then
print_ok "Service is running"
# Try to get actual listening port
if command -v ss &> /dev/null; then
LISTENING_PORT=$(ss -tuln | grep ":$ENV_PORT " | head -1 | awk '{print $4}' | cut -d':' -f2)
if [[ -n "$LISTENING_PORT" ]]; then
print_ok "Service is listening on port: $LISTENING_PORT"
if [[ "$LISTENING_PORT" == "$ENV_PORT" ]]; then
print_ok "Listening port matches configured port"
else
print_error "Listening port ($LISTENING_PORT) doesn't match configured port ($ENV_PORT)"
fi
fi
fi
# Test health endpoint
echo
echo "Testing health endpoint..."
if curl -f -s --max-time 5 http://localhost:${ENV_PORT}/health > /dev/null 2>&1; then
print_ok "Health check passed: http://localhost:${ENV_PORT}/health"
else
print_warning "Health check failed on port $ENV_PORT"
print_warning "Service might be starting up or have issues"
fi
else
print_error "Service is not running"
echo "Status:"
systemctl status mockapi --no-pager -l | head -20
fi
echo
echo "=== Recommendations ==="
echo
if [[ "$ENV_PORT" != "$SERVICE_PORT" ]]; then
echo "1. Fix port mismatch:"
echo " Run: sudo bash change_port.sh"
echo " Or manually update .env and service file to match"
fi
if [[ ! "$ENV_PORT" =~ ^[0-9]+$ ]]; then
echo "2. Fix invalid PORT in .env:"
echo " Edit $ENV_FILE and set PORT to a numeric value (e.g., 8000)"
fi
if [[ "$ENV_ISSUER" != "http://localhost:${ENV_PORT}" ]] && [[ "$ENV_ISSUER" != "NOT_FOUND" ]]; then
echo "3. Update OAUTH2_ISSUER to match port:"
echo " Edit $ENV_FILE and set: OAUTH2_ISSUER=http://localhost:${ENV_PORT}"
fi
if ! systemctl is-active --quiet mockapi 2>/dev/null; then
echo "4. Start the service:"
echo " sudo systemctl start mockapi"
echo " sudo systemctl status mockapi"
fi
echo
echo "=== Summary ==="
echo "Run 'sudo bash change_port.sh' to fix any configuration issues."
echo "Run 'sudo systemctl restart mockapi' after making changes."

View file

@ -1,4 +0,0 @@
# Netscape HTTP Cookie File
# https://curl.se/docs/http-cookies.html
# This file was generated by libcurl! Edit at your own risk.

View file

@ -1,368 +0,0 @@
#!/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"

View file

@ -1,74 +0,0 @@
#!/bin/bash
# Add missing PORT variable to .env file
# Run this if PORT is not defined in .env
set -e
echo "=== Fix Missing PORT in .env ==="
echo
APP_DIR="/opt/mockapi"
ENV_FILE="${APP_DIR}/.env"
if [[ ! -f "$ENV_FILE" ]]; then
echo "ERROR: .env file not found: $ENV_FILE"
exit 1
fi
# Check if PORT exists
if grep -q "^PORT=" "$ENV_FILE"; then
CURRENT_PORT=$(grep "^PORT=" "$ENV_FILE" | cut -d'=' -f2)
echo "PORT already exists in .env: $CURRENT_PORT"
# Validate it's numeric
if [[ ! "$CURRENT_PORT" =~ ^[0-9]+$ ]]; then
echo "WARNING: PORT is not numeric: '$CURRENT_PORT'. Fixing to 8000."
sed -i "s/^PORT=.*/PORT=8000/" "$ENV_FILE"
echo "Updated PORT to 8000."
else
echo "PORT is valid numeric value."
fi
else
echo "PORT not found in .env. Adding PORT=8000..."
echo "PORT=8000" >> "$ENV_FILE"
echo "Added PORT=8000 to .env."
fi
# Check if HOST exists
if ! grep -q "^HOST=" "$ENV_FILE"; then
echo "HOST not found in .env. Adding HOST=0.0.0.0..."
echo "HOST=0.0.0.0" >> "$ENV_FILE"
fi
# Check if OAUTH2_ISSUER exists and 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
echo "Updating OAUTH2_ISSUER to match port..."
sed -i "s|^OAUTH2_ISSUER=.*|OAUTH2_ISSUER=$EXPECTED_ISSUER|" "$ENV_FILE"
echo "Updated OAUTH2_ISSUER to: $EXPECTED_ISSUER"
else
echo "OAUTH2_ISSUER already matches port."
fi
else
echo "OAUTH2_ISSUER not found. Adding: $EXPECTED_ISSUER"
echo "OAUTH2_ISSUER=$EXPECTED_ISSUER" >> "$ENV_FILE"
fi
echo
echo "=== Updated .env file ==="
echo "Contents of $ENV_FILE:"
echo "------------------------"
grep -E "^(PORT|HOST|OAUTH2_ISSUER)=" "$ENV_FILE"
echo "------------------------"
echo
echo "Note: After updating .env, you may need to:"
echo "1. Update service file with new port (if changed)"
echo "2. Run: sudo systemctl daemon-reload"
echo "3. Run: sudo systemctl restart mockapi"
echo
echo "Use 'sudo bash change_port.sh' to update both .env and service file."

View file

@ -1,140 +0,0 @@
#!/bin/bash
# Immediate fix for Waitress port issue - run on VPS
# This script fixes the service file to use hardcoded port from .env
set -e
echo "=== Immediate Fix for Waitress Port Issue ==="
echo
APP_DIR="/opt/mockapi"
SERVICE_FILE="/etc/systemd/system/mockapi.service"
ENV_FILE="${APP_DIR}/.env"
# Check if running as root or with sudo
if [[ $EUID -eq 0 ]]; then
echo "Running as root."
elif sudo -n true 2>/dev/null; then
echo "Has sudo privileges."
else
echo "ERROR: This script needs sudo privileges."
echo "Run with: sudo bash $0"
exit 1
fi
# Step 1: Check files exist
if [[ ! -f "$ENV_FILE" ]]; then
echo "ERROR: .env file not found at $ENV_FILE"
exit 1
fi
if [[ ! -f "$SERVICE_FILE" ]]; then
echo "ERROR: Service file not found at $SERVICE_FILE"
exit 1
fi
# Step 2: Read port from .env
PORT=$(grep "^PORT=" "$ENV_FILE" | cut -d'=' -f2 || echo "8000")
HOST=$(grep "^HOST=" "$ENV_FILE" | cut -d'=' -f2 || echo "0.0.0.0")
# Validate port is numeric
if [[ ! "$PORT" =~ ^[0-9]+$ ]]; then
echo "WARNING: PORT '$PORT' is not numeric. Using 8000."
PORT="8000"
# Fix .env
sed -i "s/^PORT=.*/PORT=8000/" "$ENV_FILE" 2>/dev/null || \
echo "PORT=8000" >> "$ENV_FILE"
fi
echo "Found in .env: HOST=$HOST, PORT=$PORT"
echo
# Step 3: Backup service file
BACKUP="${SERVICE_FILE}.backup.$(date +%s)"
cp "$SERVICE_FILE" "$BACKUP"
echo "Backup created: $BACKUP"
# Step 4: Update service file
echo "Updating service file..."
# Get virtual environment path from current service file or use default
VENV_DIR=$(grep "Environment=\"PATH=" "$SERVICE_FILE" | cut -d'=' -f2 | cut -d':' -f1 | sed 's/"//g' || echo "/opt/mockapi/venv")
# Extract other settings from current file
SERVICE_USER=$(grep "^User=" "$SERVICE_FILE" | cut -d'=' -f2)
SERVICE_GROUP=$(grep "^Group=" "$SERVICE_FILE" | cut -d'=' -f2)
# Create fixed service file
cat > /tmp/mockapi_fixed.service << EOF
[Unit]
Description=Mock API Service
After=network.target
Wants=network.target
[Service]
Type=simple
User=$SERVICE_USER
Group=$SERVICE_GROUP
WorkingDirectory=$APP_DIR
Environment="PATH=$VENV_DIR/bin"
Environment="PYTHONPATH=$APP_DIR"
EnvironmentFile=$APP_DIR/.env
# Fixed: Hardcoded port from .env
ExecStart=$VENV_DIR/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 service file
cp /tmp/mockapi_fixed.service "$SERVICE_FILE"
rm /tmp/mockapi_fixed.service
echo "Service file updated with hardcoded port $PORT."
echo
# Step 5: Reload and restart
echo "Reloading systemd..."
systemctl daemon-reload
echo "Restarting service..."
if systemctl restart mockapi; then
echo "Service restart initiated."
# Wait and check
sleep 3
if systemctl is-active --quiet mockapi; then
echo "SUCCESS: Service is running!"
echo
echo "MockAPI should now be accessible at:"
echo " http://$(hostname -I | awk '{print $1}'):$PORT"
echo " http://localhost:$PORT"
echo
echo "Test with: curl http://localhost:$PORT/health"
else
echo "WARNING: Service not active after restart."
echo "Checking logs..."
journalctl -u mockapi -n 20 --no-pager
fi
else
echo "ERROR: Failed to restart service."
systemctl status mockapi --no-pager -l
fi
echo
echo "=== Fix completed ==="
echo "If issues persist, restore backup:"
echo " cp $BACKUP $SERVICE_FILE"
echo " systemctl daemon-reload"
echo " systemctl restart mockapi"

View file

@ -1,191 +0,0 @@
#!/bin/bash
# Simple fix: Remove backslashes from $HOST and $PORT in service file
# This allows systemd to expand variables from .env
set -e
echo "=== Fix: Remove backslashes from \$HOST and \$PORT in service file ==="
echo
SERVICE_FILE="/etc/systemd/system/mockapi.service"
APP_DIR="/opt/mockapi"
ENV_FILE="${APP_DIR}/.env"
# Check if running as root
if [[ $EUID -ne 0 ]]; then
echo "ERROR: This script requires sudo privileges."
exit 1
fi
# Check if service file exists
if [[ ! -f "$SERVICE_FILE" ]]; then
echo "ERROR: Service file not found: $SERVICE_FILE"
exit 1
fi
echo "Current service file: $SERVICE_FILE"
echo
# Backup
BACKUP="${SERVICE_FILE}.backup.$(date +%s)"
cp "$SERVICE_FILE" "$BACKUP"
echo "Backup created: $BACKUP"
echo
# Check current ExecStart
echo "Current ExecStart line:"
grep "^ExecStart=" "$SERVICE_FILE"
echo
# Check if we have escaped variables
if grep -q "\\\\\$HOST\|\\\\\$PORT" "$SERVICE_FILE"; then
echo "Found escaped variables (\\\$HOST and/or \\\$PORT). Removing backslashes..."
# Remove backslashes before $HOST and $PORT
sed -i 's/--host=\\\$HOST/--host=$HOST/g' "$SERVICE_FILE"
sed -i 's/--port=\\\$PORT/--port=$PORT/g' "$SERVICE_FILE"
echo "Backslashes removed."
else
echo "No escaped variables found. Checking for other patterns..."
# Check if we have $HOST and $PORT without backslashes
if grep -q "--host=\$HOST --port=\$PORT" "$SERVICE_FILE"; then
echo "Already has unescaped \$HOST and \$PORT. Good."
elif grep -q "--host=[0-9]" "$SERVICE_FILE"; then
echo "Has hardcoded host/port. Need to replace with variables."
# Extract current hardcoded values
CURRENT_LINE=$(grep "^ExecStart=" "$SERVICE_FILE")
HOST_VALUE=$(echo "$CURRENT_LINE" | sed -n 's/.*--host=\([^ ]*\).*/\1/p')
PORT_VALUE=$(echo "$CURRENT_LINE" | sed -n 's/.*--port=\([^ ]*\).*/\1/p')
echo "Current hardcoded values: host=$HOST_VALUE, port=$PORT_VALUE"
# Ensure .env has these values
if [[ ! -f "$ENV_FILE" ]]; then
echo "WARNING: .env file not found: $ENV_FILE"
else
# Update or add PORT in .env
if ! grep -q "^PORT=" "$ENV_FILE"; then
echo "PORT=$PORT_VALUE" >> "$ENV_FILE"
echo "Added PORT=$PORT_VALUE to .env"
fi
# Update or add HOST in .env
if ! grep -q "^HOST=" "$ENV_FILE"; then
echo "HOST=$HOST_VALUE" >> "$ENV_FILE"
echo "Added HOST=$HOST_VALUE to .env"
fi
fi
# Replace hardcoded values with variables
sed -i "s|--host=$HOST_VALUE --port=$PORT_VALUE|--host=\$HOST --port=\$PORT|" "$SERVICE_FILE"
echo "Replaced hardcoded values with variables."
else
echo "Unknown ExecStart format. Manual inspection needed."
fi
fi
echo
echo "Updated ExecStart line:"
grep "^ExecStart=" "$SERVICE_FILE"
echo
# Ensure PORT exists in .env
if [[ -f "$ENV_FILE" ]]; then
echo "Checking .env file..."
if ! grep -q "^PORT=" "$ENV_FILE"; then
echo "WARNING: PORT not found in .env. Adding PORT=8000..."
echo "PORT=8000" >> "$ENV_FILE"
fi
if ! grep -q "^HOST=" "$ENV_FILE"; then
echo "WARNING: HOST not found in .env. Adding HOST=0.0.0.0..."
echo "HOST=0.0.0.0" >> "$ENV_FILE"
fi
PORT_VALUE=$(grep "^PORT=" "$ENV_FILE" | cut -d'=' -f2)
echo "Current PORT in .env: $PORT_VALUE"
else
echo "WARNING: .env file not found at $ENV_FILE"
echo "Creating basic .env file..."
cat > "$ENV_FILE" << EOF
PORT=8000
HOST=0.0.0.0
OAUTH2_ISSUER=http://localhost:8000
EOF
chmod 600 "$ENV_FILE"
echo "Created .env file with default values"
fi
# Reload systemd
echo
echo "Reloading systemd daemon..."
systemctl daemon-reload
# Restart service
echo "Restarting MockAPI service..."
if systemctl restart mockapi; then
echo "Service restart initiated."
sleep 3
if systemctl is-active --quiet mockapi; then
echo "SUCCESS: Service is running!"
# Test health endpoint
PORT_VALUE=$(grep "^PORT=" "$ENV_FILE" 2>/dev/null | cut -d'=' -f2 || echo "8000")
echo
echo "Testing health endpoint on port $PORT_VALUE..."
if curl -f -s --max-time 10 http://localhost:$PORT_VALUE/health > /dev/null 2>&1; then
echo "✓ Health check passed!"
echo
echo "=== FIX SUCCESSFUL ==="
echo "MockAPI now uses PORT from .env file dynamically."
echo
echo "To change port:"
echo " 1. Edit $ENV_FILE"
echo " 2. Update the PORT value"
echo " 3. Run: sudo systemctl restart mockapi"
echo
echo "Current port: $PORT_VALUE"
echo "Access: http://localhost:$PORT_VALUE"
else
echo "WARNING: Service running but health check failed."
echo "Checking logs..."
journalctl -u mockapi -n 10 --no-pager
fi
else
echo "ERROR: Service failed to start after fix."
echo "Checking logs..."
journalctl -u mockapi -n 20 --no-pager
# Try fallback: check if maybe we need different escaping
echo
echo "Trying alternative approach..."
# Check if the issue is with $HOST $PORT not being expanded
# Maybe systemd isn't expanding them. Let's check EnvironmentFile line
if ! grep -q "EnvironmentFile=" "$SERVICE_FILE"; then
echo "Adding EnvironmentFile directive..."
# Add EnvironmentFile after existing Environment lines
sed -i '/^Environment=.*/a EnvironmentFile='"$APP_DIR"'/.env' "$SERVICE_FILE"
systemctl daemon-reload
systemctl restart mockapi
fi
fi
else
echo "ERROR: Failed to restart service."
systemctl status mockapi --no-pager -l
fi
echo
echo "=== Summary ==="
echo "Backup: $BACKUP"
echo "Service file updated to use \$HOST and \$PORT (no backslashes)"
echo "Systemd should now expand these from .env file at runtime"
echo
echo "If port changes don't work, check:"
echo " 1. .env file exists and is readable by service user"
echo " 2. PORT value in .env is numeric"
echo " 3. Service file has 'EnvironmentFile=$APP_DIR/.env' line"

View file

@ -1,226 +0,0 @@
#!/bin/bash
# Simple fix: Update service file to use $HOST and $PORT from .env
# No wrapper script, just fix the variable expansion
set -e
echo "=== Fix: Update service to use \$HOST and \$PORT from .env ==="
echo
APP_DIR="/opt/mockapi"
ENV_FILE="${APP_DIR}/.env"
SERVICE_FILE="/etc/systemd/system/mockapi.service"
# 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."
exit 1
fi
# Step 1: Check files
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..."
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"
fi
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
# Validate PORT is numeric
PORT_VALUE=$(grep "^PORT=" "$ENV_FILE" | cut -d'=' -f2)
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"
PORT_VALUE="8000"
fi
# Step 3: Backup service file
print_status "Backing up service file..."
BACKUP_FILE="${SERVICE_FILE}.backup.$(date +%s)"
cp "$SERVICE_FILE" "$BACKUP_FILE"
print_status "Backup created: $BACKUP_FILE"
# Step 4: Check current ExecStart
print_status "Checking current ExecStart line..."
CURRENT_EXEC=$(grep "^ExecStart=" "$SERVICE_FILE")
echo "Current: $CURRENT_EXEC"
# Step 5: Update ExecStart to use $HOST and $PORT
print_status "Updating ExecStart to use variables from .env..."
# We need to replace the ExecStart line with one that uses $HOST and $PORT
# But we need to be careful about escaping for sed
# First, get the current venv path from the existing ExecStart or Environment line
VENV_PATH=$(grep 'Environment="PATH=' "$SERVICE_FILE" | cut -d'=' -f2 | cut -d':' -f1 | sed 's/"//g')
if [[ -z "$VENV_PATH" ]]; then
# Try to extract from ExecStart
VENV_PATH=$(echo "$CURRENT_EXEC" | sed -n "s|^ExecStart=\(.*\)/waitress-serve.*|\1|p")
if [[ -z "$VENV_PATH" ]]; then
VENV_PATH="/opt/mockapi/venv"
print_warning "Could not detect venv path, using default: $VENV_PATH"
fi
fi
print_status "Detected venv path: $VENV_PATH"
# Create a temporary file with the updated service configuration
TMP_FILE=$(mktemp)
# Read the current service file and update ExecStart
while IFS= read -r line; do
if [[ "$line" =~ ^ExecStart= ]]; then
# Replace with new ExecStart using variables
echo "ExecStart=$VENV_PATH/bin/waitress-serve --host=\$HOST --port=\$PORT wsgi:wsgi_app"
print_status "Updated ExecStart line"
else
echo "$line"
fi
done < "$SERVICE_FILE" > "$TMP_FILE"
# Replace the service file
mv "$TMP_FILE" "$SERVICE_FILE"
# Step 6: Verify the change
print_status "Verifying update..."
UPDATED_EXEC=$(grep "^ExecStart=" "$SERVICE_FILE")
echo "Updated: $UPDATED_EXEC"
# Check if we have the escaped \$HOST and \$PORT
if echo "$UPDATED_EXEC" | grep -q "\\\\\$HOST\|\\\\\$PORT"; then
print_warning "Found escaped variables (\\\$HOST/\\\$PORT). This might still cause issues."
print_status "Trying alternative: unescaped variables..."
# Create alternative without backslashes
TMP_FILE2=$(mktemp)
while IFS= read -r line; do
if [[ "$line" =~ ^ExecStart= ]]; then
# Use unescaped variables
echo "ExecStart=$VENV_PATH/bin/waitress-serve --host=\$HOST --port=\$PORT wsgi:wsgi_app"
else
echo "$line"
fi
done < "$SERVICE_FILE" > "$TMP_FILE2"
# The issue: $HOST and $PORT in the HERE-document above will expand
# We need to write literal $HOST and $PORT. Let's use sed instead.
sed -i 's/--host=\\\$HOST --port=\\\$PORT/--host=$HOST --port=$PORT/' "$TMP_FILE2"
mv "$TMP_FILE2" "$SERVICE_FILE"
print_status "Updated with unescaped variables"
fi
# Final check
FINAL_EXEC=$(grep "^ExecStart=" "$SERVICE_FILE")
echo "Final ExecStart: $FINAL_EXEC"
# Step 7: Test if it looks correct
if echo "$FINAL_EXEC" | grep -q "--host=\$HOST --port=\$PORT"; then
print_status "✓ ExecStart looks correct (uses \$HOST and \$PORT)"
elif echo "$FINAL_EXEC" | grep -q "--host=\\\$HOST --port=\\\$PORT"; then
print_warning "ExecStart has escaped variables (\\\$HOST/\\\$PORT)"
print_warning "This might still cause the original error."
else
print_warning "ExecStart format unexpected: $FINAL_EXEC"
fi
# Step 8: Reload and restart
print_status "Reloading systemd..."
systemctl daemon-reload
print_status "Restarting 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 health endpoint
print_status "Testing health endpoint on port $PORT_VALUE..."
if curl -f -s --max-time 10 http://localhost:$PORT_VALUE/health > /dev/null 2>&1; then
print_status "✓ Health check passed!"
echo
echo "=== SUCCESS ==="
echo "MockAPI service now uses PORT from .env file."
echo
echo "To change port:"
echo " 1. Edit $ENV_FILE"
echo " 2. Update the PORT value"
echo " 3. Run: sudo systemctl restart mockapi"
echo
echo "Current port: $PORT_VALUE"
echo "Access: http://localhost:$PORT_VALUE"
else
print_warning "Service running but health check failed."
journalctl -u mockapi -n 10 --no-pager
fi
else
print_error "Service failed to start."
echo "Checking logs..."
journalctl -u mockapi -n 20 --no-pager
# Try one more approach: use a simple hardcoded port as fallback
print_status "Trying fallback: hardcoding port $PORT_VALUE..."
sed -i "s|--host=\$HOST --port=\$PORT|--host=0.0.0.0 --port=$PORT_VALUE|" "$SERVICE_FILE"
systemctl daemon-reload
systemctl restart mockapi
sleep 3
if systemctl is-active --quiet mockapi; then
print_status "✓ Service running with hardcoded port $PORT_VALUE"
print_warning "Note: Port is now hardcoded. To change port, update service file."
else
print_error "All attempts failed. 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: $BACKUP_FILE"
echo "To manually change port in the future:"
echo " 1. Edit $ENV_FILE (update PORT)"
echo " 2. Edit $SERVICE_FILE (update --port value in ExecStart)"
echo " 3. sudo systemctl daemon-reload"
echo " 4. sudo systemctl restart mockapi"

View file

@ -1,128 +0,0 @@
#!/bin/bash
# Fix service port issue where $PORT is not being expanded properly
set -e
echo "=== Fixing MockAPI Service Port Issue ==="
echo
APP_DIR="/opt/mockapi"
SERVICE_FILE="/etc/systemd/system/mockapi.service"
print_status() {
echo -e "\033[0;32m[+]\033[0m $1"
}
print_warning() {
echo -e "\033[1;33m[!]\033[0m $1"
}
print_error() {
echo -e "\033[0;31m[!]\033[0m $1"
}
# Step 1: Check if service file exists
if [[ ! -f "$SERVICE_FILE" ]]; then
print_error "Service file not found: $SERVICE_FILE"
print_warning "Make sure MockAPI is installed first."
exit 1
fi
# Step 2: Backup service file
print_status "Backing up service file..."
BACKUP_FILE="${SERVICE_FILE}.backup.$(date +%s)"
sudo cp "$SERVICE_FILE" "$BACKUP_FILE"
print_status "Backup created: $BACKUP_FILE"
# Step 3: Check current ExecStart line
print_status "Checking current ExecStart configuration..."
CURRENT_EXEC=$(grep "^ExecStart=" "$SERVICE_FILE")
echo "Current ExecStart: $CURRENT_EXEC"
# Check if we have the escaped \$PORT issue
if echo "$CURRENT_EXEC" | grep -q "\\\\\$PORT"; then
print_warning "Found escaped \$PORT in ExecStart line. This causes Waitress to parse '\$PORT' as a string."
print_status "Fixing ExecStart line..."
# Create temporary file with fixed service config
TMP_SERVICE=$(mktemp)
# Read and fix the service file
sudo cat "$SERVICE_FILE" | while IFS= read -r line; do
if [[ "$line" =~ ^ExecStart=.*waitress-serve.* ]]; then
# Remove backslashes before $HOST and $PORT
fixed_line=$(echo "$line" | sed 's/--host=\\\$HOST/--host=$HOST/g' | sed 's/--port=\\\$PORT/--port=$PORT/g')
echo "$fixed_line"
print_status "Fixed: $fixed_line"
else
echo "$line"
fi
done > "$TMP_SERVICE"
# Replace service file
sudo mv "$TMP_SERVICE" "$SERVICE_FILE"
sudo chmod 644 "$SERVICE_FILE"
print_status "Service file updated."
else
print_status "ExecStart line looks correct (no escaped \$PORT)."
fi
# Step 4: Alternative approach - check if we should use environment variables directly
print_status "Checking if .env has PORT and HOST set..."
if [[ -f "${APP_DIR}/.env" ]]; then
ENV_PORT=$(grep "^PORT=" "${APP_DIR}/.env" | cut -d'=' -f2 || echo "8000")
ENV_HOST=$(grep "^HOST=" "${APP_DIR}/.env" | cut -d'=' -f2 || echo "0.0.0.0")
print_status "Found in .env: PORT=$ENV_PORT, HOST=$ENV_HOST"
# Validate PORT is numeric
if [[ ! "$ENV_PORT" =~ ^[0-9]+$ ]]; then
print_error "PORT in .env is not numeric: '$ENV_PORT'"
print_status "Setting PORT to 8000"
sudo sed -i "s/^PORT=.*/PORT=8000/" "${APP_DIR}/.env"
fi
else
print_warning ".env file not found at ${APP_DIR}/.env"
fi
# Step 5: Reload systemd and restart service
print_status "Reloading systemd daemon..."
sudo systemctl daemon-reload
print_status "Restarting MockAPI service..."
if sudo systemctl restart mockapi; then
print_status "Service restart initiated."
sleep 3
if sudo systemctl is-active --quiet mockapi; then
print_status "✓ Service is running successfully!"
echo
print_status "Testing health endpoint..."
if curl -f -s http://localhost:${ENV_PORT:-8000}/health > /dev/null 2>&1; then
print_status "✓ Health check passed!"
echo
echo "Access your MockAPI:"
echo " Admin UI: http://localhost:${ENV_PORT:-8000}/admin/login"
echo " API Docs: http://localhost:${ENV_PORT:-8000}/docs"
echo " Health check: http://localhost:${ENV_PORT:-8000}/health"
else
print_warning "Health check failed. Checking service status..."
sudo systemctl status mockapi --no-pager -l
fi
else
print_error "Service failed to start after fix."
echo
print_warning "Checking service logs..."
sudo journalctl -u mockapi -n 30 --no-pager
fi
else
print_error "Failed to restart service."
sudo systemctl status mockapi --no-pager -l
fi
echo
print_status "=== Fix completed ==="
echo "Backup service file: $BACKUP_FILE"
echo "If you encounter issues, restore with: sudo cp $BACKUP_FILE $SERVICE_FILE && sudo systemctl daemon-reload"

View file

@ -1,425 +0,0 @@
#!/bin/bash
# Complete fix script for MockAPI VPS deployment issues
# Run this on the VPS as the same user who installed MockAPI
set -e
echo "=== MockAPI VPS Complete Fix Script ==="
echo
APP_DIR="/opt/mockapi"
ENV_FILE="${APP_DIR}/.env"
CONFIG_FILE="${APP_DIR}/app/core/config.py"
APP_FILE="${APP_DIR}/app/core/app.py"
# Function to print colored output
print_status() {
echo -e "\033[0;32m[+]\033[0m $1"
}
print_warning() {
echo -e "\033[1;33m[!]\033[0m $1"
}
print_error() {
echo -e "\033[0;31m[!]\033[0m $1"
}
# Step 0: Check we're in the right place
print_status "Step 0: Checking environment"
if [[ ! -d "$APP_DIR" ]]; then
print_error "Application directory not found: $APP_DIR"
exit 1
fi
if [[ ! -f "$CONFIG_FILE" ]]; then
print_error "Config file not found: $CONFIG_FILE"
exit 1
fi
cd "$APP_DIR"
# Step 1: Backup original files
print_status "Step 1: Backing up original files"
BACKUP_DIR="${APP_DIR}/backup_$(date +%s)"
mkdir -p "$BACKUP_DIR"
cp "$CONFIG_FILE" "$BACKUP_DIR/config.py.backup"
cp "$APP_FILE" "$BACKUP_DIR/app.py.backup"
if [[ -f "$ENV_FILE" ]]; then
cp "$ENV_FILE" "$BACKUP_DIR/env.backup"
fi
print_status "Backups created in: $BACKUP_DIR"
# Step 2: Fix config.py - add missing fields and allow extra fields
print_status "Step 2: Fixing config.py"
# Check if log_level field already exists
if ! grep -q "log_level:" "$CONFIG_FILE"; then
print_status "Adding log_level, host, and port fields to config.py"
# Insert after the version field line
sed -i '/version: str = "1.0.0"/a\ log_level: str = "INFO"\n host: str = "0.0.0.0"\n port: int = 8000' "$CONFIG_FILE"
else
print_status "log_level field already exists"
fi
# Ensure model_config allows extra fields
if grep -q 'model_config = ConfigDict(env_file=".env")' "$CONFIG_FILE"; then
print_status "Updating model_config to allow extra fields"
sed -i 's/model_config = ConfigDict(env_file=".env")/model_config = ConfigDict(env_file=".env", extra="allow")/' "$CONFIG_FILE"
elif grep -q 'extra="allow"' "$CONFIG_FILE"; then
print_status "model_config already allows extra fields"
else
print_warning "Could not find model_config line to update"
fi
# Step 3: Fix app.py - update logging configuration
print_status "Step 3: Fixing app.py logging configuration"
# Check if log_level_map already exists
if ! grep -q "log_level_map" "$APP_FILE"; then
print_status "Updating logging configuration in app.py"
# Create a temporary file with the new logging config
cat > /tmp/new_logging_config.py << 'EOF'
# Convert log level string to logging constant
log_level_map = {
"DEBUG": logging.DEBUG,
"INFO": logging.INFO,
"WARNING": logging.WARNING,
"ERROR": logging.ERROR,
"CRITICAL": logging.CRITICAL,
}
log_level = log_level_map.get(settings.log_level.upper(), logging.INFO)
logging.basicConfig(
level=logging.DEBUG if settings.debug else log_level,
format="%(asctime)s - %(name)s - %(levelname)s - %(message)s",
)
logger = logging.getLogger(__name__)
EOF
# Replace the old logging.basicConfig block
# Find the line numbers of the old block
START_LINE=$(grep -n "logging.basicConfig" "$APP_FILE" | head -1 | cut -d: -f1)
if [[ -n "$START_LINE" ]]; then
# Find the next line after the closing parenthesis
END_LINE=$((START_LINE + 3))
# Check if we have the right pattern
if sed -n "${START_LINE},${END_LINE}p" "$APP_FILE" | grep -q "logger = logging.getLogger"; then
# Replace lines START_LINE to END_LINE with new config
sed -i "${START_LINE},${END_LINE}d" "$APP_FILE"
sed -i "${START_LINE}r /tmp/new_logging_config.py" "$APP_FILE"
print_status "Updated logging configuration"
else
print_warning "Could not find exact logging block pattern, attempting manual replacement"
# Fallback: replace the whole block we can identify
sed -i '/logging.basicConfig/,/^logger = logging.getLogger/d' "$APP_FILE"
sed -i "/import logging/a\\
# Convert log level string to logging constant\\
log_level_map = {\\
\"DEBUG\": logging.DEBUG,\\
\"INFO\": logging.INFO,\\
\"WARNING\": logging.WARNING,\\
\"ERROR\": logging.ERROR,\\
\"CRITICAL\": logging.CRITICAL,\\
}\\
log_level = log_level_map.get(settings.log_level.upper(), logging.INFO)\\
\\
logging.basicConfig(\\
level=logging.DEBUG if settings.debug else log_level,\\
format=\"%(asctime)s - %(name)s - %(levelname)s - %(message)s\",\\
)\\
logger = logging.getLogger(__name__)" "$APP_FILE"
fi
else
print_error "Could not find logging.basicConfig in app.py"
fi
rm /tmp/new_logging_config.py
else
print_status "Logging configuration already updated"
fi
# Step 4: Fix .env file format issues
print_status "Step 4: Fixing .env file format issues"
if [[ -f "$ENV_FILE" ]]; then
# Fix OAUTH2_SUPPORTED_SCOPES to proper JSON format
SCOPES_LINE=$(grep -i "^OAUTH2_SUPPORTED_SCOPES=" "$ENV_FILE" | head -1)
if [[ -n "$SCOPES_LINE" ]]; then
SCOPES_VALUE=$(echo "$SCOPES_LINE" | cut -d'=' -f2-)
# Check if value is valid JSON array
if ! python3 -c "import json; json.loads('$SCOPES_VALUE')" 2>/dev/null; then
print_warning "OAUTH2_SUPPORTED_SCOPES value is not valid JSON: $SCOPES_VALUE"
print_status "Converting to JSON array format"
# Convert space-separated or comma-separated to JSON array
CLEAN_VALUE=$(echo "$SCOPES_VALUE" | sed 's/"//g' | sed "s/'//g")
JSON_ARRAY=$(echo "$CLEAN_VALUE" | python3 -c "
import sys, json
value = sys.stdin.read().strip()
if ',' in value:
items = [item.strip() for item in value.split(',')]
else:
items = [item.strip() for item in value.split()]
print(json.dumps([item for item in items if item]))
")
# Update .env file
sed -i "s/^OAUTH2_SUPPORTED_SCOPES=.*$/OAUTH2_SUPPORTED_SCOPES=$JSON_ARRAY/" "$ENV_FILE"
print_status "Updated OAUTH2_SUPPORTED_SCOPES to: $JSON_ARRAY"
else
print_status "OAUTH2_SUPPORTED_SCOPES already in valid JSON format"
fi
fi
# Fix OAUTH2_SUPPORTED_GRANT_TYPES to proper JSON format
GRANT_LINE=$(grep -i "^OAUTH2_SUPPORTED_GRANT_TYPES=" "$ENV_FILE" | head -1)
if [[ -n "$GRANT_LINE" ]]; then
GRANT_VALUE=$(echo "$GRANT_LINE" | cut -d'=' -f2-)
# Check if value is valid JSON array
if ! python3 -c "import json; json.loads('$GRANT_VALUE')" 2>/dev/null; then
print_warning "OAUTH2_SUPPORTED_GRANT_TYPES value is not valid JSON: $GRANT_VALUE"
print_status "Converting to JSON array format"
# Convert space-separated or comma-separated to JSON array
CLEAN_VALUE=$(echo "$GRANT_VALUE" | sed 's/"//g' | sed "s/'//g")
JSON_ARRAY=$(echo "$CLEAN_VALUE" | python3 -c "
import sys, json
value = sys.stdin.read().strip()
if ',' in value:
items = [item.strip() for item in value.split(',')]
else:
items = [item.strip() for item in value.split()]
print(json.dumps([item for item in items if item]))
")
# Update .env file
sed -i "s/^OAUTH2_SUPPORTED_GRANT_TYPES=.*$/OAUTH2_SUPPORTED_GRANT_TYPES=$JSON_ARRAY/" "$ENV_FILE"
print_status "Updated OAUTH2_SUPPORTED_GRANT_TYPES to: $JSON_ARRAY"
else
print_status "OAUTH2_SUPPORTED_GRANT_TYPES already in valid JSON format"
fi
fi
# Remove duplicate entries
print_status "Checking for duplicate entries in .env"
for FIELD in OAUTH2_SUPPORTED_SCOPES OAUTH2_SUPPORTED_GRANT_TYPES; do
COUNT=$(grep -i "^${FIELD}=" "$ENV_FILE" | wc -l)
if [[ $COUNT -gt 1 ]]; then
print_warning "Found $COUNT entries for $FIELD, keeping only the first"
FIRST_LINE=$(grep -i -n "^${FIELD}=" "$ENV_FILE" | head -1 | cut -d: -f1)
# Create temp file without any of this field
grep -v -i "^${FIELD}=" "$ENV_FILE" > "${ENV_FILE}.tmp"
# Add back the first occurrence
grep -i "^${FIELD}=" "$ENV_FILE" | head -1 >> "${ENV_FILE}.tmp"
mv "${ENV_FILE}.tmp" "$ENV_FILE"
fi
done
# Ensure required fields exist
print_status "Ensuring all required fields exist in .env"
if ! grep -q "^LOG_LEVEL=" "$ENV_FILE"; then
echo "LOG_LEVEL=INFO" >> "$ENV_FILE"
print_status "Added LOG_LEVEL=INFO"
fi
if ! grep -q "^HOST=" "$ENV_FILE"; then
echo "HOST=0.0.0.0" >> "$ENV_FILE"
print_status "Added HOST=0.0.0.0"
fi
if ! grep -q "^PORT=" "$ENV_FILE"; then
echo "PORT=8000" >> "$ENV_FILE"
print_status "Added PORT=8000"
fi
if ! grep -q "^OAUTH2_AUTHORIZATION_CODE_EXPIRE_MINUTES=" "$ENV_FILE"; then
echo "OAUTH2_AUTHORIZATION_CODE_EXPIRE_MINUTES=10" >> "$ENV_FILE"
print_status "Added OAUTH2_AUTHORIZATION_CODE_EXPIRE_MINUTES=10"
fi
if ! grep -q "^OAUTH2_PKCE_REQUIRED=" "$ENV_FILE"; then
echo "OAUTH2_PKCE_REQUIRED=false" >> "$ENV_FILE"
print_status "Added OAUTH2_PKCE_REQUIRED=false"
fi
# Update OAUTH2_ISSUER if port has changed
CURRENT_PORT=$(grep "^PORT=" "$ENV_FILE" | cut -d'=' -f2)
CURRENT_ISSUER=$(grep "^OAUTH2_ISSUER=" "$ENV_FILE" | cut -d'=' -f2)
EXPECTED_ISSUER="http://localhost:${CURRENT_PORT}"
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 ".env file not found, skipping .env fixes"
fi
# Step 5: Test the configuration
print_status "Step 5: Testing configuration import"
cat > test_config.py << 'EOF'
import os
import sys
import json
# Add app directory to path
sys.path.insert(0, os.getcwd())
try:
print("Attempting to import config...")
from app.core.config import settings
print("✓ Config import successful!")
print(f" DEBUG: {settings.debug}")
print(f" LOG_LEVEL: {settings.log_level}")
print(f" HOST: {settings.host}")
print(f" PORT: {settings.port}")
print(f" OAUTH2_SUPPORTED_SCOPES: {settings.oauth2_supported_scopes}")
print(f" OAUTH2_SUPPORTED_GRANT_TYPES: {settings.oauth2_supported_grant_types}")
print(f" Type of scopes: {type(settings.oauth2_supported_scopes)}")
print(f" Type of grant types: {type(settings.oauth2_supported_grant_types)}")
# Test JSON serialization
print(f" Scopes as JSON: {json.dumps(settings.oauth2_supported_scopes)}")
print("✓ All configuration tests passed!")
except Exception as e:
print(f"✗ Config import failed: {e}")
import traceback
traceback.print_exc()
sys.exit(1)
EOF
if python3 test_config.py; then
print_status "Configuration test passed!"
rm test_config.py
else
print_error "Configuration test failed"
print_warning "Check the error above. The .env file may still have issues."
exit 1
fi
# Step 5.5: Fix service file port issue
print_status "Step 5.5: Fixing service file port configuration"
SERVICE_FILE="/etc/systemd/system/mockapi.service"
if [[ -f "$SERVICE_FILE" ]]; then
print_status "Checking service file for port configuration issues..."
# Check if service file has the escaped \$PORT issue
if grep -q "\\\\\$PORT" "$SERVICE_FILE" || grep -q "--port=\\\$PORT" "$SERVICE_FILE"; then
print_warning "Found escaped \$PORT in service file. Fixing..."
# Read port from .env
SERVICE_PORT=$(grep "^PORT=" "$ENV_FILE" | cut -d'=' -f2 || echo "8000")
SERVICE_HOST=$(grep "^HOST=" "$ENV_FILE" | cut -d'=' -f2 || echo "0.0.0.0")
# Validate port
if [[ ! "$SERVICE_PORT" =~ ^[0-9]+$ ]]; then
print_warning "PORT '$SERVICE_PORT' is not numeric. Using 8000."
SERVICE_PORT="8000"
sed -i "s/^PORT=.*/PORT=8000/" "$ENV_FILE"
fi
print_status "Updating service file with hardcoded port: $SERVICE_PORT"
# Backup service file
SERVICE_BACKUP="${SERVICE_FILE}.backup.$(date +%s)"
sudo cp "$SERVICE_FILE" "$SERVICE_BACKUP"
print_status "Service file backed up to: $SERVICE_BACKUP"
# Get VENV_DIR from current service file
VENV_DIR=$(grep 'Environment="PATH=' "$SERVICE_FILE" | cut -d'=' -f2 | cut -d':' -f1 | sed 's/"//g' || echo "/opt/mockapi/venv")
# Create fixed service file
sudo tee "$SERVICE_FILE" > /dev/null << EOF
[Unit]
Description=Mock API Service
After=network.target
Wants=network.target
[Service]
Type=simple
User=$(grep "^User=" "$SERVICE_FILE" | cut -d'=' -f2)
Group=$(grep "^Group=" "$SERVICE_FILE" | cut -d'=' -f2)
WorkingDirectory=$APP_DIR
Environment="PATH=$VENV_DIR/bin"
Environment="PYTHONPATH=$APP_DIR"
EnvironmentFile=$APP_DIR/.env
# Fixed: Hardcoded port from .env
ExecStart=$VENV_DIR/bin/waitress-serve --host=$SERVICE_HOST --port=$SERVICE_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 "Service file updated with hardcoded port $SERVICE_PORT."
sudo systemctl daemon-reload
print_status "Systemd daemon reloaded."
else
print_status "Service file port configuration looks correct."
fi
else
print_warning "Service file not found: $SERVICE_FILE"
print_warning "Service won't be fixed. Install service first with install.sh."
fi
# Step 6: Restart the service
print_status "Step 6: Restarting MockAPI service"
sudo systemctl restart mockapi
sleep 5
if sudo systemctl is-active --quiet mockapi; then
print_status "✓ Service is running successfully!"
echo
echo "Service status:"
sudo systemctl status mockapi --no-pager -l
echo
print_status "Testing API endpoints..."
# Read port from .env for testing
TEST_PORT=$(grep "^PORT=" "$ENV_FILE" 2>/dev/null | cut -d'=' -f2 || echo "8000")
if [[ ! "$TEST_PORT" =~ ^[0-9]+$ ]]; then
TEST_PORT="8000"
fi
if curl -f -s http://localhost:$TEST_PORT/health > /dev/null 2>&1; then
print_status "✓ Health check passed: http://localhost:$TEST_PORT/health"
echo
echo "Access your MockAPI:"
echo " Admin UI: http://localhost:$TEST_PORT/admin/login"
echo " API Docs: http://localhost:$TEST_PORT/docs"
echo " Health check: http://localhost:$TEST_PORT/health"
else
print_warning "Health check failed. Checking logs..."
sudo journalctl -u mockapi -n 10 --no-pager
fi
else
print_error "Service failed to start"
echo
print_warning "Checking service logs..."
sudo journalctl -u mockapi -n 30 --no-pager
echo
print_warning "If the service still fails, check:"
print_warning "1. The .env file format: ${ENV_FILE}"
print_warning "2. File permissions in ${APP_DIR}"
print_warning "3. Database file permissions"
exit 1
fi
echo
print_status "=== Fix completed successfully! ==="
echo
echo "Backup files are in: $BACKUP_DIR"
echo "If you encounter issues, you can restore from backup."
echo

View file

@ -1,255 +0,0 @@
#!/bin/bash
# Fix script for MockAPI VPS deployment issues
set -e
echo "=== MockAPI VPS Issue Fixer ==="
echo
APP_DIR="/opt/mockapi"
ENV_FILE="${APP_DIR}/.env"
# Function to print colored output
print_status() {
echo -e "\033[0;32m[+]\033[0m $1"
}
print_warning() {
echo -e "\033[1;33m[!]\033[0m $1"
}
print_error() {
echo -e "\033[0;31m[!]\033[0m $1"
}
# Step 1: Check current .env file
print_status "Step 1: Checking current .env file"
if [[ ! -f "$ENV_FILE" ]]; then
print_error ".env file not found at $ENV_FILE"
exit 1
fi
echo "Current .env file content:"
echo "--------------------------"
cat "$ENV_FILE"
echo "--------------------------"
echo
# Step 2: Check for duplicate entries
print_status "Step 2: Checking for duplicate entries in .env"
DUPLICATES=$(grep -i "^OAUTH2_SUPPORTED_SCOPES=" "$ENV_FILE" | wc -l)
if [[ $DUPLICATES -gt 1 ]]; then
print_warning "Found $DUPLICATES entries for OAUTH2_SUPPORTED_SCOPES"
# Keep only the first one
FIRST_LINE=$(grep -i -n "^OAUTH2_SUPPORTED_SCOPES=" "$ENV_FILE" | head -1 | cut -d: -f1)
print_status "Keeping only line $FIRST_LINE"
# Create backup
cp "$ENV_FILE" "${ENV_FILE}.backup.$(date +%s)"
# Remove all OAUTH2_SUPPORTED_SCOPES lines, then add correct one
grep -v -i "^OAUTH2_SUPPORTED_SCOPES=" "$ENV_FILE" > "${ENV_FILE}.tmp"
# Add correct entry (from first line)
CORRECT_LINE=$(grep -i "^OAUTH2_SUPPORTED_SCOPES=" "$ENV_FILE" | head -1)
echo "$CORRECT_LINE" >> "${ENV_FILE}.tmp"
mv "${ENV_FILE}.tmp" "$ENV_FILE"
print_status "Removed duplicate entries"
fi
# Also check for OAUTH2_SUPPORTED_GRANT_TYPES duplicates
DUPLICATES_GRANT=$(grep -i "^OAUTH2_SUPPORTED_GRANT_TYPES=" "$ENV_FILE" | wc -l)
if [[ $DUPLICATES_GRANT -gt 1 ]]; then
print_warning "Found $DUPLICATES_GRANT entries for OAUTH2_SUPPORTED_GRANT_TYPES"
# Keep only the first one
FIRST_LINE=$(grep -i -n "^OAUTH2_SUPPORTED_GRANT_TYPES=" "$ENV_FILE" | head -1 | cut -d: -f1)
print_status "Keeping only line $FIRST_LINE"
# Create backup if not already done
if [[ ! -f "${ENV_FILE}.backup" ]]; then
cp "$ENV_FILE" "${ENV_FILE}.backup"
fi
# Remove all OAUTH2_SUPPORTED_GRANT_TYPES lines, then add correct one
grep -v -i "^OAUTH2_SUPPORTED_GRANT_TYPES=" "$ENV_FILE" > "${ENV_FILE}.tmp"
# Add correct entry (from first line)
CORRECT_LINE=$(grep -i "^OAUTH2_SUPPORTED_GRANT_TYPES=" "$ENV_FILE" | head -1)
echo "$CORRECT_LINE" >> "${ENV_FILE}.tmp"
mv "${ENV_FILE}.tmp" "$ENV_FILE"
print_status "Removed duplicate grant types entries"
fi
# Step 3: Ensure proper JSON format for list fields
print_status "Step 3: Ensuring proper JSON format for list fields"
# Backup if not already done
if [[ ! -f "${ENV_FILE}.backup" ]]; then
cp "$ENV_FILE" "${ENV_FILE}.backup"
fi
# Fix OAUTH2_SUPPORTED_SCOPES if not in JSON format
SCOPES_LINE=$(grep -i "^OAUTH2_SUPPORTED_SCOPES=" "$ENV_FILE" | head -1)
if [[ -n "$SCOPES_LINE" ]]; then
SCOPES_VALUE=$(echo "$SCOPES_LINE" | cut -d'=' -f2-)
# Check if value is valid JSON array
if ! python3 -c "import json; json.loads('$SCOPES_VALUE')" 2>/dev/null; then
print_warning "OAUTH2_SUPPORTED_SCOPES value is not valid JSON: $SCOPES_VALUE"
print_status "Converting to JSON array format"
# Convert space-separated or comma-separated to JSON array
# Remove quotes and split
CLEAN_VALUE=$(echo "$SCOPES_VALUE" | sed 's/"//g' | sed "s/'//g")
# Convert to JSON array
JSON_ARRAY=$(echo "$CLEAN_VALUE" | python3 -c "
import sys, json
value = sys.stdin.read().strip()
if ',' in value:
items = [item.strip() for item in value.split(',')]
else:
items = [item.strip() for item in value.split()]
print(json.dumps([item for item in items if item]))
")
# Update .env file
sed -i "s/^OAUTH2_SUPPORTED_SCOPES=.*$/OAUTH2_SUPPORTED_SCOPES=$JSON_ARRAY/" "$ENV_FILE"
print_status "Updated OAUTH2_SUPPORTED_SCOPES to: $JSON_ARRAY"
else
print_status "OAUTH2_SUPPORTED_SCOPES already in valid JSON format"
fi
fi
# Fix OAUTH2_SUPPORTED_GRANT_TYPES if not in JSON format
GRANT_LINE=$(grep -i "^OAUTH2_SUPPORTED_GRANT_TYPES=" "$ENV_FILE" | head -1)
if [[ -n "$GRANT_LINE" ]]; then
GRANT_VALUE=$(echo "$GRANT_LINE" | cut -d'=' -f2-)
# Check if value is valid JSON array
if ! python3 -c "import json; json.loads('$GRANT_VALUE')" 2>/dev/null; then
print_warning "OAUTH2_SUPPORTED_GRANT_TYPES value is not valid JSON: $GRANT_VALUE"
print_status "Converting to JSON array format"
# Convert space-separated or comma-separated to JSON array
# Remove quotes and split
CLEAN_VALUE=$(echo "$GRANT_VALUE" | sed 's/"//g' | sed "s/'//g")
# Convert to JSON array
JSON_ARRAY=$(echo "$CLEAN_VALUE" | python3 -c "
import sys, json
value = sys.stdin.read().strip()
if ',' in value:
items = [item.strip() for item in value.split(',')]
else:
items = [item.strip() for item in value.split()]
print(json.dumps([item for item in items if item]))
")
# Update .env file
sed -i "s/^OAUTH2_SUPPORTED_GRANT_TYPES=.*$/OAUTH2_SUPPORTED_GRANT_TYPES=$JSON_ARRAY/" "$ENV_FILE"
print_status "Updated OAUTH2_SUPPORTED_GRANT_TYPES to: $JSON_ARRAY"
else
print_status "OAUTH2_SUPPORTED_GRANT_TYPES already in valid JSON format"
fi
fi
# Step 4: Add missing OAuth2 settings if not present
print_status "Step 4: Adding missing OAuth2 settings"
if ! grep -q "^OAUTH2_AUTHORIZATION_CODE_EXPIRE_MINUTES=" "$ENV_FILE"; then
echo "OAUTH2_AUTHORIZATION_CODE_EXPIRE_MINUTES=10" >> "$ENV_FILE"
print_status "Added OAUTH2_AUTHORIZATION_CODE_EXPIRE_MINUTES=10"
fi
if ! grep -q "^OAUTH2_PKCE_REQUIRED=" "$ENV_FILE"; then
echo "OAUTH2_PKCE_REQUIRED=false" >> "$ENV_FILE"
print_status "Added OAUTH2_PKCE_REQUIRED=false"
fi
# Step 5: Test config import
print_status "Step 5: Testing configuration import"
cd "$APP_DIR"
# Create test script
cat > test_config.py << 'EOF'
import os
import sys
import json
# Add app directory to path
sys.path.insert(0, os.getcwd())
try:
print("Attempting to import config...")
from app.core.config import settings
print("✓ Config import successful!")
print(f" DEBUG: {settings.debug}")
print(f" OAUTH2_SUPPORTED_SCOPES: {settings.oauth2_supported_scopes}")
print(f" OAUTH2_SUPPORTED_GRANT_TYPES: {settings.oauth2_supported_grant_types}")
print(f" Type of scopes: {type(settings.oauth2_supported_scopes)}")
print(f" Type of grant types: {type(settings.oauth2_supported_grant_types)}")
# Also test JSON serialization
print(f" Scopes as JSON: {json.dumps(settings.oauth2_supported_scopes)}")
except Exception as e:
print(f"✗ Config import failed: {e}")
import traceback
traceback.print_exc()
sys.exit(1)
EOF
# Run test
if python3 test_config.py; then
print_status "Configuration test passed!"
rm test_config.py
else
print_error "Configuration test failed"
print_warning "Check the error above. The .env file may still have issues."
exit 1
fi
# Step 6: Check for environment variables that might interfere
print_status "Step 6: Checking for interfering environment variables"
ENV_VARS=$(env | grep -i oauth)
if [[ -n "$ENV_VARS" ]]; then
print_warning "Found OAuth-related environment variables that might override .env:"
echo "$ENV_VARS"
print_warning "These may cause conflicts with .env file settings."
fi
# Step 7: Restart service
print_status "Step 7: Restarting MockAPI service"
sudo systemctl restart mockapi
sleep 3
if sudo systemctl is-active --quiet mockapi; then
print_status "✓ Service is running successfully!"
echo
echo "Service status:"
sudo systemctl status mockapi --no-pager -l
echo
print_status "Testing API endpoints..."
if curl -f http://localhost:8000/health > /dev/null 2>&1; then
print_status "✓ Health check passed: http://localhost:8000/health"
else
print_warning "Health check failed. Checking logs..."
sudo journalctl -u mockapi -n 10 --no-pager
fi
else
print_error "Service failed to start"
echo
print_warning "Checking service logs..."
sudo journalctl -u mockapi -n 30 --no-pager
exit 1
fi
echo
print_status "=== Fix completed successfully! ==="
echo
echo "Access your MockAPI:"
echo " Admin UI: http://localhost:8000/admin/login"
echo " API Docs: http://localhost:8000/docs"
echo " Health check: http://localhost:8000/health"
echo
echo "Credentials are in: $ENV_FILE"
echo "Backup created at: ${ENV_FILE}.backup"

View file

@ -1,262 +0,0 @@
#!/bin/bash
# Comprehensive fix for Waitress port parsing issue on VPS
set -e
echo "=== Fixing Waitress Port Parsing Issue ==="
echo
APP_DIR="/opt/mockapi"
SERVICE_FILE="/etc/systemd/system/mockapi.service"
ENV_FILE="${APP_DIR}/.env"
print_status() {
echo -e "\033[0;32m[+]\033[0m $1"
}
print_warning() {
echo -e "\033[1;33m[!]\033[0m $1"
}
print_error() {
echo -e "\033[0;31m[!]\033[0m $1"
}
# Step 1: Check environment
print_status "Step 1: Checking environment"
if [[ ! -d "$APP_DIR" ]]; then
print_error "Application directory not found: $APP_DIR"
exit 1
fi
if [[ ! -f "$SERVICE_FILE" ]]; then
print_error "Service file not found: $SERVICE_FILE"
exit 1
fi
cd "$APP_DIR"
# Step 2: Read current port from .env
print_status "Step 2: Reading current configuration"
PORT="8000"
HOST="0.0.0.0"
if [[ -f "$ENV_FILE" ]]; then
if grep -q "^PORT=" "$ENV_FILE"; then
PORT=$(grep "^PORT=" "$ENV_FILE" | cut -d'=' -f2)
print_status "Found PORT in .env: $PORT"
# Validate PORT is numeric
if [[ ! "$PORT" =~ ^[0-9]+$ ]]; then
print_error "PORT is not numeric: '$PORT'. Setting to 8000."
PORT="8000"
sudo sed -i "s/^PORT=.*/PORT=8000/" "$ENV_FILE"
fi
else
print_warning "PORT not found in .env, adding PORT=8000"
echo "PORT=8000" | sudo tee -a "$ENV_FILE" > /dev/null
fi
if grep -q "^HOST=" "$ENV_FILE"; then
HOST=$(grep "^HOST=" "$ENV_FILE" | cut -d'=' -f2)
print_status "Found HOST in .env: $HOST"
else
print_warning "HOST not found in .env, adding HOST=0.0.0.0"
echo "HOST=0.0.0.0" | sudo tee -a "$ENV_FILE" > /dev/null
fi
else
print_error ".env file not found: $ENV_FILE"
exit 1
fi
# Step 3: Backup service file
print_status "Step 3: Backing up service file"
BACKUP_FILE="${SERVICE_FILE}.backup.$(date +%s)"
sudo cp "$SERVICE_FILE" "$BACKUP_FILE"
print_status "Backup created: $BACKUP_FILE"
# Step 4: Fix service file - OPTION 1: Use shell expansion
print_status "Step 4: Fixing service file ExecStart command"
print_warning "Current issue: Waitress receives literal string '\$PORT' instead of expanded value"
print_status "Solution 1: Use /bin/sh -c to enable shell variable expansion"
# Get the virtual environment path
VENV_DIR="${APP_DIR}/venv"
if [[ ! -d "$VENV_DIR" ]]; then
print_error "Virtual environment not found: $VENV_DIR"
exit 1
fi
# Read current service file to get other settings
CURRENT_USER=$(grep "^User=" "$SERVICE_FILE" | cut -d'=' -f2)
CURRENT_GROUP=$(grep "^Group=" "$SERVICE_FILE" | cut -d'=' -f2)
CURRENT_WORKDIR=$(grep "^WorkingDirectory=" "$SERVICE_FILE" | cut -d'=' -f2)
print_status "Current service settings:"
print_status " User: $CURRENT_USER"
print_status " Group: $CURRENT_GROUP"
print_status " WorkingDirectory: $CURRENT_WORKDIR"
# Create new service file with fixed ExecStart
print_status "Creating fixed service file..."
sudo tee "$SERVICE_FILE" > /dev/null << EOF
[Unit]
Description=Mock API Service
After=network.target
Wants=network.target
[Service]
Type=simple
User=$CURRENT_USER
Group=$CURRENT_GROUP
WorkingDirectory=$CURRENT_WORKDIR
Environment="PATH=$VENV_DIR/bin"
Environment="PYTHONPATH=$APP_DIR"
EnvironmentFile=$APP_DIR/.env
# Use shell to expand environment variables
ExecStart=/bin/sh -c "$VENV_DIR/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 "Service file updated with shell expansion."
# Step 5: Alternative simpler fix - hardcode port based on .env value
print_status "Alternative approach available: Hardcode port in service file"
print_warning "Would you like to hardcode port $PORT in service file instead? (y/N)"
read -p "Choice: " -n 1 -r
echo
if [[ $REPLY =~ ^[Yy]$ ]]; then
print_status "Hardcoding port $PORT in service file..."
sudo tee "$SERVICE_FILE" > /dev/null << EOF
[Unit]
Description=Mock API Service
After=network.target
Wants=network.target
[Service]
Type=simple
User=$CURRENT_USER
Group=$CURRENT_GROUP
WorkingDirectory=$CURRENT_WORKDIR
Environment="PATH=$VENV_DIR/bin"
Environment="PYTHONPATH=$APP_DIR"
EnvironmentFile=$APP_DIR/.env
# Hardcoded port based on .env value
ExecStart=$VENV_DIR/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 "Service file updated with hardcoded port $PORT."
print_warning "Note: If you change PORT in .env, you must update service file manually."
fi
# Step 6: Reload and restart
print_status "Step 5: Reloading systemd daemon..."
sudo systemctl daemon-reload
print_status "Step 6: Restarting service..."
sudo systemctl restart mockapi
sleep 3
# Step 7: Verify
print_status "Step 7: Verifying service status..."
if sudo systemctl is-active --quiet mockapi; then
print_status "✓ Service is running!"
echo
print_status "Testing health endpoint on port $PORT..."
if curl -f -s --max-time 10 http://localhost:$PORT/health > /dev/null 2>&1; then
print_status "✓ Health check passed!"
echo
echo "=== Service Fixed Successfully ==="
echo "MockAPI is now running on:"
echo " URL: http://localhost:$PORT"
echo " Admin: http://localhost:$PORT/admin/login"
echo " Docs: http://localhost:$PORT/docs"
echo " Health: http://localhost:$PORT/health"
else
print_warning "Health check failed (might be starting up). Checking logs..."
sleep 2
if curl -f -s --max-time 5 http://localhost:$PORT/health > /dev/null 2>&1; then
print_status "✓ Health check passed on second attempt!"
else
print_warning "Service running but health check failing. Checking logs..."
sudo journalctl -u mockapi -n 20 --no-pager
fi
fi
else
print_error "Service failed to start after fix."
echo
print_warning "Checking service logs..."
sudo journalctl -u mockapi -n 30 --no-pager
echo
print_warning "Trying alternative approach with simplified service file..."
# Try a simpler approach - just hardcode common values
print_status "Creating minimal service file..."
sudo tee "$SERVICE_FILE" > /dev/null << EOF
[Unit]
Description=Mock API Service
After=network.target
[Service]
Type=simple
User=$CURRENT_USER
Group=$CURRENT_GROUP
WorkingDirectory=$APP_DIR
Environment="PATH=$VENV_DIR/bin"
ExecStart=$VENV_DIR/bin/waitress-serve --host=0.0.0.0 --port=8000 wsgi:wsgi_app
Restart=always
RestartSec=10
[Install]
WantedBy=multi-user.target
EOF
sudo systemctl daemon-reload
sudo systemctl restart mockapi
sleep 3
if sudo systemctl is-active --quiet mockapi; then
print_status "✓ Service started with hardcoded values!"
print_warning "Running on default port 8000. Update .env to match."
sudo sed -i "s/^PORT=.*/PORT=8000/" "$ENV_FILE"
else
print_error "All fixes failed. Please check manual configuration."
sudo journalctl -u mockapi -n 30 --no-pager
fi
fi
echo
print_status "=== Fix script completed ==="
echo "Backup service file: $BACKUP_FILE"
echo "Current .env PORT: $PORT"
echo "Current .env HOST: $HOST"

View file

@ -113,6 +113,39 @@ generate_random_string() {
openssl rand -base64 $((length * 3 / 4)) | tr -d '/+=' | head -c "$length" openssl rand -base64 $((length * 3 / 4)) | tr -d '/+=' | head -c "$length"
} }
ensure_env_variables() {
print_info "Ensuring required environment variables exist..."
local env_file="${APP_DIR}/.env"
if [[ ! -f "$env_file" ]]; then
return
fi
# Ensure HOST exists
if ! grep -q "^HOST=" "$env_file"; then
echo "HOST=0.0.0.0" >> "$env_file"
print_info "Added missing HOST to .env"
fi
# Ensure PORT exists
if ! grep -q "^PORT=" "$env_file"; then
echo "PORT=8000" >> "$env_file"
print_info "Added missing PORT to .env"
fi
# Ensure LOG_LEVEL exists
if ! grep -q "^LOG_LEVEL=" "$env_file"; then
echo "LOG_LEVEL=INFO" >> "$env_file"
print_info "Added missing LOG_LEVEL to .env"
fi
# Ensure OAUTH2_ISSUER exists
if ! grep -q "^OAUTH2_ISSUER=" "$env_file"; then
# Try to get PORT from .env or default
local port_value="8000"
if grep -q "^PORT=" "$env_file"; then
port_value=$(grep "^PORT=" "$env_file" | cut -d'=' -f2)
fi
echo "OAUTH2_ISSUER=http://localhost:$port_value" >> "$env_file"
print_info "Added missing OAUTH2_ISSUER to .env"
fi
}
setup_environment() { setup_environment() {
print_status "Setting up Python virtual environment..." print_status "Setting up Python virtual environment..."
@ -177,6 +210,7 @@ configure_application() {
echo echo
if [[ ! $REPLY =~ ^[Yy]$ ]]; then if [[ ! $REPLY =~ ^[Yy]$ ]]; then
print_info "Using existing .env file." print_info "Using existing .env file."
ensure_env_variables
return return
fi fi
fi fi
@ -227,6 +261,8 @@ HOST=0.0.0.0
PORT=${PORT} PORT=${PORT}
EOF EOF
ensure_env_variables
# Set secure permissions # Set secure permissions
chmod 600 "${APP_DIR}/.env" chmod 600 "${APP_DIR}/.env"

View file

@ -1,20 +0,0 @@
#!/usr/bin/env python3
"""
Alternative development runner that avoids the WSGI initialization.
"""
import uvicorn
import logging
logging.basicConfig(level=logging.INFO)
logger = logging.getLogger(__name__)
if __name__ == "__main__":
logger.info("Starting development server on http://0.0.0.0:8000")
# Import and run the app directly without WSGI initialization
uvicorn.run(
"app.core.app:app", # Import string for reload support
host="0.0.0.0",
port=8000,
reload=True,
log_level="info"
)

View file

@ -1,29 +0,0 @@
# Mock API Configuration
# Generated on test
# Database Configuration
DATABASE_URL=sqlite+aiosqlite:///./mockapi.db
# Admin Authentication
ADMIN_USERNAME=admin
ADMIN_PASSWORD=admin123
# Security
SECRET_KEY=testsecretkey
# Application Settings
DEBUG=False
LOG_LEVEL=INFO
# OAuth2 Settings
OAUTH2_ISSUER=http://localhost:8000
OAUTH2_ACCESS_TOKEN_EXPIRE_MINUTES=30
OAUTH2_REFRESH_TOKEN_EXPIRE_DAYS=7
OAUTH2_AUTHORIZATION_CODE_EXPIRE_MINUTES=10
OAUTH2_SUPPORTED_GRANT_TYPES=["authorization_code", "client_credentials", "refresh_token"]
OAUTH2_SUPPORTED_SCOPES=["openid", "profile", "email", "api:read", "api:write"]
OAUTH2_PKCE_REQUIRED=false
# Server Settings
HOST=0.0.0.0
PORT=8000

View file

@ -1,36 +0,0 @@
import os
import sys
import json
# Add parent directory to path
sys.path.insert(0, os.path.dirname(os.path.dirname(os.path.abspath(__file__))))
# Set environment variable to use our test .env
os.environ['ENV_FILE'] = os.path.join(os.path.dirname(__file__), 'env.test.txt')
print(f"Using env file: {os.environ['ENV_FILE']}")
try:
print("Attempting to import config...")
from app.core.config import settings
print("✓ Config import successful!")
print(f" DEBUG: {settings.debug}")
print(f" LOG_LEVEL: {settings.log_level}")
print(f" HOST: {settings.host}")
print(f" PORT: {settings.port}")
print(f" OAUTH2_SUPPORTED_SCOPES: {settings.oauth2_supported_scopes}")
print(f" OAUTH2_SUPPORTED_GRANT_TYPES: {settings.oauth2_supported_grant_types}")
print(f" Type of scopes: {type(settings.oauth2_supported_scopes)}")
print(f" Type of grant types: {type(settings.oauth2_supported_grant_types)}")
# Test JSON serialization
print(f" Scopes as JSON: {json.dumps(settings.oauth2_supported_scopes)}")
print("✓ All configuration tests passed!")
except Exception as e:
print(f"✗ Config import failed: {e}")
import traceback
traceback.print_exc()
sys.exit(1)

View file

@ -1,54 +0,0 @@
#!/usr/bin/env python3
"""
Test if the application runs correctly.
"""
import sys
import subprocess
import time
import requests
def test_app_start():
"""Try to start the app and make a request."""
print("Testing application startup...")
# Start the app in a subprocess
proc = subprocess.Popen(
[sys.executable, "-m", "uvicorn", "app.core.app:app", "--host", "0.0.0.0", "--port", "8001"],
stdout=subprocess.PIPE,
stderr=subprocess.PIPE,
text=True
)
try:
# Give it time to start
time.sleep(3)
# Try to make a request
print("Making test request...")
try:
resp = requests.get("http://localhost:8001/health", timeout=5)
print(f"Response: {resp.status_code} - {resp.json()}")
if resp.status_code == 200:
print("✅ Application starts and responds correctly")
return True
else:
print(f"❌ Unexpected status: {resp.status_code}")
except requests.exceptions.ConnectionError:
print("❌ Could not connect to server")
# Check process output
stdout, stderr = proc.communicate(timeout=1)
print(f"STDOUT: {stdout[:200]}")
print(f"STDERR: {stderr[:200]}")
except Exception as e:
print(f"Error: {e}")
finally:
proc.terminate()
proc.wait()
return False
if __name__ == "__main__":
success = test_app_start()
sys.exit(0 if success else 1)