chore: auto-commit 2026-03-16 15:28
This commit is contained in:
parent
f1991c3983
commit
7da4eff745
2 changed files with 507 additions and 0 deletions
434
install.sh
Normal file
434
install.sh
Normal file
|
|
@ -0,0 +1,434 @@
|
||||||
|
#!/bin/bash
|
||||||
|
|
||||||
|
# Mock API Installation Script
|
||||||
|
# This script installs the Mock API application as a systemd service
|
||||||
|
|
||||||
|
set -e # Exit on error
|
||||||
|
|
||||||
|
# Colors for output
|
||||||
|
RED='\033[0;31m'
|
||||||
|
GREEN='\033[0;32m'
|
||||||
|
YELLOW='\033[1;33m'
|
||||||
|
BLUE='\033[0;34m'
|
||||||
|
NC='\033[0m' # No Color
|
||||||
|
|
||||||
|
# Configuration
|
||||||
|
APP_NAME="mockapi"
|
||||||
|
APP_DIR="/opt/mockapi"
|
||||||
|
SERVICE_NAME="mockapi"
|
||||||
|
SERVICE_FILE="/etc/systemd/system/${SERVICE_NAME}.service"
|
||||||
|
VENV_DIR="${APP_DIR}/venv"
|
||||||
|
PORT="8000"
|
||||||
|
RUN_USER="www-data" # Default user, can be changed below
|
||||||
|
|
||||||
|
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_root() {
|
||||||
|
if [[ $EUID -eq 0 ]]; then
|
||||||
|
print_warning "Running as root. It's recommended to run this script as a regular user."
|
||||||
|
read -p "Continue anyway? (y/N): " -n 1 -r
|
||||||
|
echo
|
||||||
|
if [[ ! $REPLY =~ ^[Yy]$ ]]; then
|
||||||
|
exit 1
|
||||||
|
fi
|
||||||
|
fi
|
||||||
|
}
|
||||||
|
|
||||||
|
check_prerequisites() {
|
||||||
|
print_status "Checking prerequisites..."
|
||||||
|
|
||||||
|
# Check Python
|
||||||
|
if ! command -v python3 &> /dev/null; then
|
||||||
|
print_error "Python3 is not installed. Please install it first."
|
||||||
|
print_info "On Ubuntu/Debian: sudo apt-get install python3"
|
||||||
|
exit 1
|
||||||
|
fi
|
||||||
|
|
||||||
|
# Check pip
|
||||||
|
if ! command -v pip3 &> /dev/null; then
|
||||||
|
print_warning "pip3 not found. Installing..."
|
||||||
|
sudo apt-get update
|
||||||
|
sudo apt-get install -y python3-pip
|
||||||
|
fi
|
||||||
|
|
||||||
|
# Check virtualenv
|
||||||
|
if ! python3 -m venv --help &> /dev/null; then
|
||||||
|
print_warning "venv module not available. Installing..."
|
||||||
|
sudo apt-get install -y python3-venv
|
||||||
|
fi
|
||||||
|
|
||||||
|
print_status "Prerequisites check passed."
|
||||||
|
}
|
||||||
|
|
||||||
|
generate_random_string() {
|
||||||
|
local length=$1
|
||||||
|
openssl rand -base64 $((length * 3 / 4)) | tr -d '/+=' | head -c "$length"
|
||||||
|
}
|
||||||
|
|
||||||
|
setup_environment() {
|
||||||
|
print_status "Setting up Python virtual environment..."
|
||||||
|
|
||||||
|
# Create virtual environment
|
||||||
|
if [[ ! -d "$VENV_DIR" ]]; then
|
||||||
|
python3 -m venv "$VENV_DIR"
|
||||||
|
print_status "Virtual environment created at $VENV_DIR"
|
||||||
|
else
|
||||||
|
print_warning "Virtual environment already exists at $VENV_DIR"
|
||||||
|
read -p "Recreate virtual environment? (y/N): " -n 1 -r
|
||||||
|
echo
|
||||||
|
if [[ $REPLY =~ ^[Yy]$ ]]; then
|
||||||
|
rm -rf "$VENV_DIR"
|
||||||
|
python3 -m venv "$VENV_DIR"
|
||||||
|
print_status "Virtual environment recreated."
|
||||||
|
fi
|
||||||
|
fi
|
||||||
|
|
||||||
|
# Activate virtual environment and install dependencies
|
||||||
|
source "${VENV_DIR}/bin/activate"
|
||||||
|
pip install --upgrade pip
|
||||||
|
|
||||||
|
print_status "Installing Python dependencies..."
|
||||||
|
pip install -r "${APP_DIR}/requirements.txt"
|
||||||
|
|
||||||
|
deactivate
|
||||||
|
print_status "Dependencies installed."
|
||||||
|
}
|
||||||
|
|
||||||
|
configure_application() {
|
||||||
|
print_status "Configuring application..."
|
||||||
|
|
||||||
|
# Check if .env exists
|
||||||
|
if [[ -f "${APP_DIR}/.env" ]]; then
|
||||||
|
print_warning ".env file already exists."
|
||||||
|
read -p "Overwrite with new configuration? (y/N): " -n 1 -r
|
||||||
|
echo
|
||||||
|
if [[ ! $REPLY =~ ^[Yy]$ ]]; then
|
||||||
|
print_info "Using existing .env file."
|
||||||
|
return
|
||||||
|
fi
|
||||||
|
fi
|
||||||
|
|
||||||
|
# Generate secure credentials
|
||||||
|
print_info "Generating secure credentials..."
|
||||||
|
ADMIN_PASSWORD=$(generate_random_string 16)
|
||||||
|
SECRET_KEY=$(generate_random_string 64)
|
||||||
|
|
||||||
|
# Ask for admin username
|
||||||
|
read -p "Enter admin username [admin]: " admin_username
|
||||||
|
ADMIN_USERNAME=${admin_username:-admin}
|
||||||
|
|
||||||
|
# Ask for database path
|
||||||
|
read -p "Enter database path [${APP_DIR}/mockapi.db]: " db_path
|
||||||
|
DB_PATH=${db_path:-${APP_DIR}/mockapi.db}
|
||||||
|
|
||||||
|
# Create .env file with generated credentials
|
||||||
|
cat > "${APP_DIR}/.env" << EOF
|
||||||
|
# Mock API Configuration
|
||||||
|
# Generated on $(date)
|
||||||
|
|
||||||
|
# Database Configuration
|
||||||
|
DATABASE_URL=sqlite+aiosqlite:///${DB_PATH}
|
||||||
|
|
||||||
|
# Admin Authentication
|
||||||
|
ADMIN_USERNAME=${ADMIN_USERNAME}
|
||||||
|
ADMIN_PASSWORD=${ADMIN_PASSWORD}
|
||||||
|
|
||||||
|
# Security
|
||||||
|
SECRET_KEY=${SECRET_KEY}
|
||||||
|
|
||||||
|
# Application Settings
|
||||||
|
DEBUG=False
|
||||||
|
LOG_LEVEL=INFO
|
||||||
|
|
||||||
|
# OAuth2 Settings
|
||||||
|
OAUTH2_ISSUER=http://localhost:${PORT}
|
||||||
|
OAUTH2_ACCESS_TOKEN_EXPIRE_MINUTES=30
|
||||||
|
OAUTH2_REFRESH_TOKEN_EXPIRE_DAYS=7
|
||||||
|
OAUTH2_SUPPORTED_SCOPES=openid profile email api:read api:write
|
||||||
|
|
||||||
|
# Server Settings
|
||||||
|
HOST=0.0.0.0
|
||||||
|
PORT=${PORT}
|
||||||
|
EOF
|
||||||
|
|
||||||
|
# Set secure permissions
|
||||||
|
chmod 600 "${APP_DIR}/.env"
|
||||||
|
|
||||||
|
print_status "Created .env file with secure credentials."
|
||||||
|
print_info "Admin username: ${ADMIN_USERNAME}"
|
||||||
|
print_info "Admin password: ${ADMIN_PASSWORD}"
|
||||||
|
print_info "Secret key: ${SECRET_KEY:0:16}..."
|
||||||
|
|
||||||
|
echo
|
||||||
|
print_warning "IMPORTANT: Save these credentials in a secure location!"
|
||||||
|
print_warning "You will need the admin password to log in."
|
||||||
|
echo
|
||||||
|
|
||||||
|
# Create database directory if needed
|
||||||
|
DB_DIR=$(dirname "$DB_PATH")
|
||||||
|
if [[ ! -d "$DB_DIR" ]]; then
|
||||||
|
mkdir -p "$DB_DIR"
|
||||||
|
fi
|
||||||
|
}
|
||||||
|
|
||||||
|
setup_systemd_service() {
|
||||||
|
print_status "Setting up systemd service..."
|
||||||
|
|
||||||
|
# Ask for run user
|
||||||
|
echo
|
||||||
|
print_warning "Choose a user to run the service:"
|
||||||
|
echo "1) www-data (recommended for web applications)"
|
||||||
|
echo "2) Current user ($USER)"
|
||||||
|
echo "3) Create new user 'mockapi'"
|
||||||
|
echo "4) Custom user"
|
||||||
|
read -p "Enter choice [1-4]: " user_choice
|
||||||
|
|
||||||
|
case $user_choice in
|
||||||
|
1)
|
||||||
|
RUN_USER="www-data"
|
||||||
|
;;
|
||||||
|
2)
|
||||||
|
RUN_USER="$USER"
|
||||||
|
;;
|
||||||
|
3)
|
||||||
|
RUN_USER="mockapi"
|
||||||
|
if ! id -u "$RUN_USER" &> /dev/null; then
|
||||||
|
sudo adduser --system --no-create-home --group "$RUN_USER"
|
||||||
|
print_status "Created user '$RUN_USER'"
|
||||||
|
fi
|
||||||
|
;;
|
||||||
|
4)
|
||||||
|
read -p "Enter username: " custom_user
|
||||||
|
if id -u "$custom_user" &> /dev/null; then
|
||||||
|
RUN_USER="$custom_user"
|
||||||
|
else
|
||||||
|
print_error "User '$custom_user' does not exist."
|
||||||
|
exit 1
|
||||||
|
fi
|
||||||
|
;;
|
||||||
|
*)
|
||||||
|
RUN_USER="www-data"
|
||||||
|
print_warning "Using default user: www-data"
|
||||||
|
;;
|
||||||
|
esac
|
||||||
|
|
||||||
|
# Ask for port
|
||||||
|
read -p "Enter port number [8000]: " custom_port
|
||||||
|
if [[ -n "$custom_port" ]]; then
|
||||||
|
PORT="$custom_port"
|
||||||
|
# Update PORT in .env if it exists
|
||||||
|
if [[ -f "${APP_DIR}/.env" ]]; then
|
||||||
|
sed -i "s/^PORT=.*/PORT=${PORT}/" "${APP_DIR}/.env"
|
||||||
|
sed -i "s|^OAUTH2_ISSUER=.*|OAUTH2_ISSUER=http://localhost:${PORT}|" "${APP_DIR}/.env"
|
||||||
|
fi
|
||||||
|
fi
|
||||||
|
|
||||||
|
# Create systemd service file
|
||||||
|
print_status "Creating systemd service file at $SERVICE_FILE..."
|
||||||
|
|
||||||
|
sudo tee "$SERVICE_FILE" > /dev/null << EOF
|
||||||
|
[Unit]
|
||||||
|
Description=Mock API Service
|
||||||
|
After=network.target
|
||||||
|
Wants=network.target
|
||||||
|
|
||||||
|
[Service]
|
||||||
|
Type=simple
|
||||||
|
User=$RUN_USER
|
||||||
|
Group=$RUN_USER
|
||||||
|
WorkingDirectory=$APP_DIR
|
||||||
|
Environment="PATH=$VENV_DIR/bin"
|
||||||
|
Environment="PYTHONPATH=$APP_DIR"
|
||||||
|
EnvironmentFile=$APP_DIR/.env
|
||||||
|
ExecStart=$VENV_DIR/bin/waitress-serve --host=\$HOST --port=\$PORT wsgi:wsgi_app
|
||||||
|
Restart=always
|
||||||
|
RestartSec=10
|
||||||
|
StandardOutput=syslog
|
||||||
|
StandardError=syslog
|
||||||
|
SyslogIdentifier=$SERVICE_NAME
|
||||||
|
|
||||||
|
# Security hardening
|
||||||
|
NoNewPrivileges=true
|
||||||
|
PrivateTmp=true
|
||||||
|
ProtectSystem=strict
|
||||||
|
ReadWritePaths=$APP_DIR
|
||||||
|
|
||||||
|
[Install]
|
||||||
|
WantedBy=multi-user.target
|
||||||
|
EOF
|
||||||
|
|
||||||
|
print_status "Systemd service file created."
|
||||||
|
|
||||||
|
# Set ownership and permissions
|
||||||
|
print_status "Setting ownership and permissions..."
|
||||||
|
|
||||||
|
# Set ownership of app directory
|
||||||
|
sudo chown -R "$RUN_USER:$RUN_USER" "$APP_DIR"
|
||||||
|
|
||||||
|
# Make sure install script is executable
|
||||||
|
sudo chmod +x "$APP_DIR/install.sh"
|
||||||
|
|
||||||
|
# Reload systemd
|
||||||
|
sudo systemctl daemon-reload
|
||||||
|
|
||||||
|
print_status "Systemd service configured."
|
||||||
|
}
|
||||||
|
|
||||||
|
initialize_database() {
|
||||||
|
print_status "Initializing database..."
|
||||||
|
|
||||||
|
# Activate virtual environment
|
||||||
|
source "${VENV_DIR}/bin/activate"
|
||||||
|
|
||||||
|
# Run a simple Python script to initialize database
|
||||||
|
python3 -c "
|
||||||
|
import asyncio
|
||||||
|
import sys
|
||||||
|
sys.path.insert(0, '${APP_DIR}')
|
||||||
|
from app.core.database import engine
|
||||||
|
from app.core.config import settings
|
||||||
|
import asyncio
|
||||||
|
|
||||||
|
async def init_db():
|
||||||
|
from sqlalchemy.ext.asyncio import AsyncSession
|
||||||
|
from sqlalchemy.orm import sessionmaker
|
||||||
|
from app.core.database import Base
|
||||||
|
from app.modules.endpoints.models import Endpoint
|
||||||
|
from app.modules.oauth2.models import OAuthClient, OAuthToken, OAuthUser
|
||||||
|
|
||||||
|
async with engine.begin() as conn:
|
||||||
|
await conn.run_sync(Base.metadata.create_all)
|
||||||
|
print('Database tables created successfully')
|
||||||
|
|
||||||
|
asyncio.run(init_db())
|
||||||
|
"
|
||||||
|
|
||||||
|
deactivate
|
||||||
|
print_status "Database initialized."
|
||||||
|
}
|
||||||
|
|
||||||
|
start_service() {
|
||||||
|
print_status "Starting and enabling service..."
|
||||||
|
|
||||||
|
# Enable and start the service
|
||||||
|
sudo systemctl enable "$SERVICE_NAME"
|
||||||
|
sudo systemctl start "$SERVICE_NAME"
|
||||||
|
|
||||||
|
# Wait a moment for service to start
|
||||||
|
sleep 5
|
||||||
|
|
||||||
|
# Check service status
|
||||||
|
if sudo systemctl is-active --quiet "$SERVICE_NAME"; then
|
||||||
|
print_status "Service is running successfully!"
|
||||||
|
else
|
||||||
|
print_error "Service failed to start. Checking logs..."
|
||||||
|
sudo journalctl -u "$SERVICE_NAME" -n 20 --no-pager
|
||||||
|
exit 1
|
||||||
|
fi
|
||||||
|
}
|
||||||
|
|
||||||
|
show_summary() {
|
||||||
|
# Read credentials from .env for summary
|
||||||
|
if [[ -f "${APP_DIR}/.env" ]]; then
|
||||||
|
ADMIN_USERNAME=$(grep "^ADMIN_USERNAME=" "${APP_DIR}/.env" | cut -d'=' -f2)
|
||||||
|
ADMIN_PASSWORD=$(grep "^ADMIN_PASSWORD=" "${APP_DIR}/.env" | cut -d'=' -f2)
|
||||||
|
fi
|
||||||
|
|
||||||
|
echo
|
||||||
|
echo -e "${GREEN}========================================${NC}"
|
||||||
|
echo -e "${GREEN} Installation Complete! ${NC}"
|
||||||
|
echo -e "${GREEN}========================================${NC}"
|
||||||
|
echo
|
||||||
|
echo "Application Details:"
|
||||||
|
echo " Directory: $APP_DIR"
|
||||||
|
echo " Service: $SERVICE_NAME"
|
||||||
|
echo " Run User: $RUN_USER"
|
||||||
|
echo " Port: $PORT"
|
||||||
|
echo " Virtual Env: $VENV_DIR"
|
||||||
|
echo
|
||||||
|
echo "Credentials (saved in ${APP_DIR}/.env):"
|
||||||
|
echo " Admin Username: $ADMIN_USERNAME"
|
||||||
|
echo " Admin Password: $ADMIN_PASSWORD"
|
||||||
|
echo
|
||||||
|
echo "Service Management Commands:"
|
||||||
|
echo " sudo systemctl start $SERVICE_NAME"
|
||||||
|
echo " sudo systemctl stop $SERVICE_NAME"
|
||||||
|
echo " sudo systemctl restart $SERVICE_NAME"
|
||||||
|
echo " sudo systemctl status $SERVICE_NAME"
|
||||||
|
echo " sudo journalctl -u $SERVICE_NAME -f"
|
||||||
|
echo
|
||||||
|
echo "Access the application:"
|
||||||
|
echo " Admin UI: http://localhost:$PORT/admin/login"
|
||||||
|
echo " API Docs: http://localhost:$PORT/docs"
|
||||||
|
echo " Health Check: http://localhost:$PORT/health"
|
||||||
|
echo
|
||||||
|
echo "Configuration Files:"
|
||||||
|
echo " Environment: $APP_DIR/.env"
|
||||||
|
echo " Service: $SERVICE_FILE"
|
||||||
|
echo " Database: $(grep "^DATABASE_URL=" "${APP_DIR}/.env" | cut -d'/' -f4-)"
|
||||||
|
echo
|
||||||
|
print_warning "IMPORTANT: Change admin password after first login!"
|
||||||
|
print_warning "Keep the .env file secure - it contains sensitive credentials."
|
||||||
|
echo
|
||||||
|
print_info "To update configuration, edit $APP_DIR/.env and restart:"
|
||||||
|
print_info " sudo systemctl restart $SERVICE_NAME"
|
||||||
|
echo
|
||||||
|
}
|
||||||
|
|
||||||
|
main() {
|
||||||
|
echo -e "${GREEN}========================================${NC}"
|
||||||
|
echo -e "${GREEN} Mock API Installation Script ${NC}"
|
||||||
|
echo -e "${GREEN}========================================${NC}"
|
||||||
|
echo
|
||||||
|
|
||||||
|
# Check if running as root (warn but allow)
|
||||||
|
check_root
|
||||||
|
|
||||||
|
# Check if app directory exists
|
||||||
|
if [[ ! -d "$APP_DIR" ]]; then
|
||||||
|
print_error "Application directory not found: $APP_DIR"
|
||||||
|
print_info "Please clone the repository first:"
|
||||||
|
print_info " cd /opt/"
|
||||||
|
print_info " sudo git clone https://git.sechpoint.app/customer-engineering/mockapi.git"
|
||||||
|
print_info " sudo chown -R \$USER:\$USER /opt/mockapi"
|
||||||
|
exit 1
|
||||||
|
fi
|
||||||
|
|
||||||
|
# Check prerequisites
|
||||||
|
check_prerequisites
|
||||||
|
|
||||||
|
# Setup Python environment
|
||||||
|
setup_environment
|
||||||
|
|
||||||
|
# Configure application
|
||||||
|
configure_application
|
||||||
|
|
||||||
|
# Initialize database
|
||||||
|
initialize_database
|
||||||
|
|
||||||
|
# Setup systemd service
|
||||||
|
setup_systemd_service
|
||||||
|
|
||||||
|
# Start the service
|
||||||
|
start_service
|
||||||
|
|
||||||
|
# Show summary
|
||||||
|
show_summary
|
||||||
|
}
|
||||||
|
|
||||||
|
# Run main function
|
||||||
|
main
|
||||||
73
uninstall.sh
Normal file
73
uninstall.sh
Normal file
|
|
@ -0,0 +1,73 @@
|
||||||
|
#!/bin/bash
|
||||||
|
|
||||||
|
# Mock API Uninstallation Script
|
||||||
|
|
||||||
|
set -e
|
||||||
|
|
||||||
|
# Colors
|
||||||
|
RED='\033[0;31m'
|
||||||
|
GREEN='\033[0;32m'
|
||||||
|
YELLOW='\033[1;33m'
|
||||||
|
NC='\033[0m'
|
||||||
|
|
||||||
|
APP_DIR="/opt/mockapi"
|
||||||
|
SERVICE_NAME="mockapi"
|
||||||
|
SERVICE_FILE="/etc/systemd/system/${SERVICE_NAME}.service"
|
||||||
|
|
||||||
|
print_status() {
|
||||||
|
echo -e "${GREEN}[+]${NC} $1"
|
||||||
|
}
|
||||||
|
|
||||||
|
print_warning() {
|
||||||
|
echo -e "${YELLOW}[!]${NC} $1
|
||||||
|
}
|
||||||
|
|
||||||
|
print_error() {
|
||||||
|
echo -e "${RED}[!]${NC} $1"
|
||||||
|
}
|
||||||
|
|
||||||
|
echo -e "${GREEN}========================================${NC}"
|
||||||
|
echo -e "${GREEN} Mock API Uninstallation Script ${NC}"
|
||||||
|
echo -e "${GREEN}========================================${NC}"
|
||||||
|
echo
|
||||||
|
|
||||||
|
# Confirm uninstallation
|
||||||
|
read -p "Are you sure you want to uninstall Mock API? (y/N): " -n 1 -r
|
||||||
|
echo
|
||||||
|
if [[ ! $REPLY =~ ^[Yy]$ ]]; then
|
||||||
|
echo "Uninstallation cancelled."
|
||||||
|
exit 0
|
||||||
|
fi
|
||||||
|
|
||||||
|
# Stop and disable service
|
||||||
|
if systemctl is-active --quiet "$SERVICE_NAME" 2>/dev/null; then
|
||||||
|
print_status "Stopping service..."
|
||||||
|
sudo systemctl stop "$SERVICE_NAME"
|
||||||
|
fi
|
||||||
|
|
||||||
|
if systemctl is-enabled --quiet "$SERVICE_NAME" 2>/dev/null; then
|
||||||
|
print_status "Disabling service..."
|
||||||
|
sudo systemctl disable "$SERVICE_NAME"
|
||||||
|
fi
|
||||||
|
|
||||||
|
# Remove service file
|
||||||
|
if [[ -f "$SERVICE_FILE" ]]; then
|
||||||
|
print_status "Removing service file..."
|
||||||
|
sudo rm "$SERVICE_FILE"
|
||||||
|
sudo systemctl daemon-reload
|
||||||
|
fi
|
||||||
|
|
||||||
|
# Ask about removing application directory
|
||||||
|
if [[ -d "$APP_DIR" ]]; then
|
||||||
|
read -p "Remove application directory ($APP_DIR)? (y/N): " -n 1 -r
|
||||||
|
echo
|
||||||
|
if [[ $REPLY =~ ^[Yy]$ ]]; then
|
||||||
|
print_status "Removing application directory..."
|
||||||
|
sudo rm -rf "$APP_DIR"
|
||||||
|
else
|
||||||
|
print_status "Application directory kept at $APP_DIR"
|
||||||
|
print_warning "Note: .env file with credentials is still in $APP_DIR"
|
||||||
|
fi
|
||||||
|
fi
|
||||||
|
|
||||||
|
print_status "Uninstallation complete!"
|
||||||
Loading…
Reference in a new issue