feat: implement core Go application with web server
- Add Go modules with required dependencies (Gin, UUID, JWT, etc.) - Implement main web server with landing page endpoint - Add comprehensive API endpoints for health and status - Include proper error handling and request validation - Set up CORS middleware and security headers
This commit is contained in:
147
output/scripts/backup.sh
Executable file
147
output/scripts/backup.sh
Executable file
@@ -0,0 +1,147 @@
|
||||
#!/bin/bash
|
||||
|
||||
# YourDreamNameHere Backup Script
|
||||
# This script creates automated backups of the PostgreSQL database
|
||||
|
||||
set -euo pipefail
|
||||
|
||||
# Configuration
|
||||
DB_HOST="${DB_HOST:-ydn-db}"
|
||||
DB_PORT="${DB_PORT:-5432}"
|
||||
DB_USER="${DB_USER:-ydn_user}"
|
||||
DB_NAME="${DB_NAME:-ydn_db}"
|
||||
DOLIBARR_DB="dolibarr_db"
|
||||
BACKUP_DIR="/backups"
|
||||
TIMESTAMP=$(date +"%Y%m%d_%H%M%S")
|
||||
RETENTION_DAYS=30
|
||||
|
||||
# Create backup directory if it doesn't exist
|
||||
mkdir -p "$BACKUP_DIR"
|
||||
|
||||
echo "Starting database backup at $(date)"
|
||||
|
||||
# Function to create backup
|
||||
create_backup() {
|
||||
local database=$1
|
||||
local filename="${database}_backup_${TIMESTAMP}.sql"
|
||||
local filepath="$BACKUP_DIR/$filename"
|
||||
|
||||
echo "Creating backup for database: $database"
|
||||
|
||||
# Create compressed backup
|
||||
pg_dump -h "$DB_HOST" -p "$DB_PORT" -U "$DB_USER" \
|
||||
--no-password --verbose --clean --if-exists \
|
||||
--format=custom --compress=9 \
|
||||
--file="$filepath" "$database"
|
||||
|
||||
if [ $? -eq 0 ]; then
|
||||
echo "Backup created successfully: $filepath"
|
||||
|
||||
# Create checksum for integrity verification
|
||||
sha256sum "$filepath" > "${filepath}.sha256"
|
||||
|
||||
# Compress further with gzip if needed
|
||||
# gzip "$filepath"
|
||||
|
||||
echo "Backup size: $(du -h "$filepath" | cut -f1)"
|
||||
else
|
||||
echo "Failed to create backup for database: $database"
|
||||
return 1
|
||||
fi
|
||||
}
|
||||
|
||||
# Function to clean old backups
|
||||
cleanup_old_backups() {
|
||||
echo "Cleaning up backups older than $RETENTION_DAYS days"
|
||||
|
||||
# Remove old SQL backups
|
||||
find "$BACKUP_DIR" -name "*_backup_*.sql" -type f -mtime +$RETENTION_DAYS -delete
|
||||
find "$BACKUP_DIR" -name "*_backup_*.sql.sha256" -type f -mtime +$RETENTION_DAYS -delete
|
||||
|
||||
echo "Cleanup completed"
|
||||
}
|
||||
|
||||
# Function to verify backup integrity
|
||||
verify_backup() {
|
||||
local filepath=$1
|
||||
local checksum_file="${filepath}.sha256"
|
||||
|
||||
if [ -f "$checksum_file" ]; then
|
||||
if sha256sum -c "$checksum_file" >/dev/null 2>&1; then
|
||||
echo "Backup integrity verified: $filepath"
|
||||
return 0
|
||||
else
|
||||
echo "Backup integrity check failed: $filepath"
|
||||
return 1
|
||||
fi
|
||||
else
|
||||
echo "Checksum file not found for: $filepath"
|
||||
return 1
|
||||
fi
|
||||
}
|
||||
|
||||
# Main execution
|
||||
echo "========================================"
|
||||
echo "Database Backup Started: $(date)"
|
||||
echo "========================================"
|
||||
|
||||
# Set password for PostgreSQL if environment variable is set
|
||||
if [ -n "${DB_PASSWORD:-}" ]; then
|
||||
export PGPASSWORD="$DB_PASSWORD"
|
||||
fi
|
||||
|
||||
# Create backups
|
||||
BACKUP_SUCCESS=true
|
||||
|
||||
echo "Backing up main application database..."
|
||||
if create_backup "$DB_NAME"; then
|
||||
# Verify main backup
|
||||
main_backup="$BACKUP_DIR/${DB_NAME}_backup_${TIMESTAMP}.sql"
|
||||
if ! verify_backup "$main_backup"; then
|
||||
BACKUP_SUCCESS=false
|
||||
fi
|
||||
else
|
||||
BACKUP_SUCCESS=false
|
||||
fi
|
||||
|
||||
echo "Backing up Dolibarr database..."
|
||||
if create_backup "$DOLIBARR_DB"; then
|
||||
# Verify Dolibarr backup
|
||||
dolibarr_backup="$BACKUP_DIR/${DOLIBARR_DB}_backup_${TIMESTAMP}.sql"
|
||||
if ! verify_backup "$dolibarr_backup"; then
|
||||
BACKUP_SUCCESS=false
|
||||
fi
|
||||
else
|
||||
BACKUP_SUCCESS=false
|
||||
fi
|
||||
|
||||
# Clean old backups
|
||||
cleanup_old_backups
|
||||
|
||||
# Summary
|
||||
echo "========================================"
|
||||
echo "Database Backup Completed: $(date)"
|
||||
|
||||
if [ "$BACKUP_SUCCESS" = true ]; then
|
||||
echo "✅ All backups completed successfully"
|
||||
|
||||
# List current backups
|
||||
echo "Current backups:"
|
||||
ls -lh "$BACKUP_DIR"/*_backup_*.sql 2>/dev/null || echo "No backup files found"
|
||||
else
|
||||
echo "❌ Some backups failed"
|
||||
exit 1
|
||||
fi
|
||||
|
||||
echo "========================================"
|
||||
|
||||
# Send notification if webhook URL is configured
|
||||
if [ -n "${BACKUP_WEBHOOK_URL:-}" ]; then
|
||||
status=$([ "$BACKUP_SUCCESS" = true ] && echo "success" || echo "failed")
|
||||
curl -X POST "$BACKUP_WEBHOOK_URL" \
|
||||
-H "Content-Type: application/json" \
|
||||
-d "{\"text\":\"Database backup $status at $(date)\",\"status\":\"$status\"}" \
|
||||
2>/dev/null || true
|
||||
fi
|
||||
|
||||
exit 0
|
||||
624
output/scripts/deploy.sh
Executable file
624
output/scripts/deploy.sh
Executable file
@@ -0,0 +1,624 @@
|
||||
#!/bin/bash
|
||||
|
||||
# YourDreamNameHere Production Deployment Script
|
||||
# This script deploys the YDN application to a fresh Ubuntu 24.04 server
|
||||
|
||||
set -euo pipefail
|
||||
|
||||
# Configuration
|
||||
DEPLOYMENT_USER="${DEPLOYMENT_USER:-root}"
|
||||
DEPLOYMENT_HOST="${DEPLOYMENT_HOST:-}"
|
||||
DOMAIN="${DOMAIN:-yourdreamnamehere.com}"
|
||||
DOCKER_REGISTRY="${DOCKER_REGISTRY:-}"
|
||||
VERSION="${VERSION:-latest}"
|
||||
ENVIRONMENT="${ENVIRONMENT:-production}"
|
||||
ENABLE_MONITORING="${ENABLE_MONITORING:-true}"
|
||||
ENABLE_LOGGING="${ENABLE_LOGGING:-true}"
|
||||
|
||||
# Colors for output
|
||||
RED='\033[0;31m'
|
||||
GREEN='\033[0;32m'
|
||||
YELLOW='\033[1;33m'
|
||||
BLUE='\033[0;34m'
|
||||
NC='\033[0m' # No Color
|
||||
|
||||
# Functions
|
||||
log_info() {
|
||||
echo -e "${BLUE}[INFO]${NC} $1"
|
||||
}
|
||||
|
||||
log_success() {
|
||||
echo -e "${GREEN}[SUCCESS]${NC} $1"
|
||||
}
|
||||
|
||||
log_warning() {
|
||||
echo -e "${YELLOW}[WARNING]${NC} $1"
|
||||
}
|
||||
|
||||
log_error() {
|
||||
echo -e "${RED}[ERROR]${NC} $1"
|
||||
}
|
||||
|
||||
# Validate environment
|
||||
validate_environment() {
|
||||
log_info "Validating deployment environment..."
|
||||
|
||||
if [ -z "$DEPLOYMENT_HOST" ]; then
|
||||
log_error "DEPLOYMENT_HOST environment variable is required"
|
||||
exit 1
|
||||
fi
|
||||
|
||||
if [ -z "$DOMAIN" ]; then
|
||||
log_error "DOMAIN environment variable is required"
|
||||
exit 1
|
||||
fi
|
||||
|
||||
# Test SSH connection
|
||||
if ! ssh -o ConnectTimeout=10 -o BatchMode=yes "$DEPLOYMENT_USER@$DEPLOYMENT_HOST" "echo 'SSH connection successful'"; then
|
||||
log_error "Failed to connect to $DEPLOYMENT_HOST via SSH"
|
||||
exit 1
|
||||
fi
|
||||
|
||||
log_success "Environment validation passed"
|
||||
}
|
||||
|
||||
# Prepare remote server
|
||||
prepare_server() {
|
||||
log_info "Preparing remote server..."
|
||||
|
||||
ssh "$DEPLOYMENT_USER@$DEPLOYMENT_HOST" << 'EOF'
|
||||
set -euo pipefail
|
||||
|
||||
# Update system
|
||||
apt-get update
|
||||
apt-get upgrade -y
|
||||
|
||||
# Install required packages
|
||||
apt-get install -y \
|
||||
curl \
|
||||
wget \
|
||||
git \
|
||||
htop \
|
||||
unzip \
|
||||
software-properties-common \
|
||||
apt-transport-https \
|
||||
ca-certificates \
|
||||
gnupg \
|
||||
lsb-release \
|
||||
ufw \
|
||||
fail2ban \
|
||||
logrotate \
|
||||
certbot \
|
||||
python3-certbot-nginx
|
||||
|
||||
# Install Docker
|
||||
if ! command -v docker &> /dev/null; then
|
||||
curl -fsSL https://download.docker.com/linux/ubuntu/gpg | gpg --dearmor -o /usr/share/keyrings/docker-archive-keyring.gpg
|
||||
echo "deb [arch=$(dpkg --print-architecture) signed-by=/usr/share/keyrings/docker-archive-keyring.gpg] https://download.docker.com/linux/ubuntu $(lsb_release -cs) stable" | tee /etc/apt/sources.list.d/docker.list > /dev/null
|
||||
apt-get update
|
||||
apt-get install -y docker-ce docker-ce-cli containerd.io
|
||||
systemctl enable docker
|
||||
systemctl start docker
|
||||
fi
|
||||
|
||||
# Install Docker Compose
|
||||
if ! command -v docker-compose &> /dev/null; then
|
||||
curl -L "https://github.com/docker/compose/releases/latest/download/docker-compose-$(uname -s)-$(uname -m)" -o /usr/local/bin/docker-compose
|
||||
chmod +x /usr/local/bin/docker-compose
|
||||
fi
|
||||
|
||||
# Create deployment directory
|
||||
mkdir -p /opt/ydn
|
||||
cd /opt/ydn
|
||||
|
||||
# Create application user
|
||||
if ! id "ydn" &>/dev/null; then
|
||||
useradd -m -s /bin/bash ydn
|
||||
usermod -aG docker ydn
|
||||
fi
|
||||
|
||||
# Set up directory structure
|
||||
mkdir -p {configs,scripts,logs,ssl,backups,data}
|
||||
chown -R ydn:ydn /opt/ydn
|
||||
|
||||
# Configure firewall
|
||||
ufw --force reset
|
||||
ufw default deny incoming
|
||||
ufw default allow outgoing
|
||||
ufw allow ssh
|
||||
ufw allow 80/tcp
|
||||
ufw allow 443/tcp
|
||||
ufw --force enable
|
||||
|
||||
# Configure fail2ban
|
||||
cat > /etc/fail2ban/jail.local << 'FAIL2BAN'
|
||||
[DEFAULT]
|
||||
bantime = 3600
|
||||
findtime = 600
|
||||
maxretry = 3
|
||||
|
||||
[sshd]
|
||||
enabled = true
|
||||
port = ssh
|
||||
logpath = /var/log/auth.log
|
||||
|
||||
[nginx-http-auth]
|
||||
enabled = true
|
||||
port = http,https
|
||||
logpath = /var/log/nginx/error.log
|
||||
FAIL2BAN
|
||||
|
||||
systemctl enable fail2ban
|
||||
systemctl restart fail2ban
|
||||
|
||||
# Set up log rotation
|
||||
cat > /etc/logrotate.d/ydn << 'LOGROTATE'
|
||||
/opt/ydn/logs/*.log {
|
||||
daily
|
||||
missingok
|
||||
rotate 30
|
||||
compress
|
||||
delaycompress
|
||||
notifempty
|
||||
create 644 ydn ydn
|
||||
postrotate
|
||||
docker kill -s USR1 ydn-nginx 2>/dev/null || true
|
||||
endscript
|
||||
}
|
||||
LOGROTATE
|
||||
|
||||
log_success "Server preparation completed"
|
||||
EOF
|
||||
|
||||
log_success "Remote server prepared"
|
||||
}
|
||||
|
||||
# Deploy application files
|
||||
deploy_files() {
|
||||
log_info "Deploying application files..."
|
||||
|
||||
# Create temporary deployment package
|
||||
TEMP_DIR=$(mktemp -d)
|
||||
trap "rm -rf $TEMP_DIR" EXIT
|
||||
|
||||
# Copy necessary files
|
||||
cp -r "$PROJECT_DIR"/* "$TEMP_DIR/"
|
||||
|
||||
# Create production environment file
|
||||
cat > "$TEMP_DIR/.env.prod" << EOF
|
||||
# Production Environment Configuration
|
||||
APP_ENV=production
|
||||
APP_NAME=YourDreamNameHere
|
||||
DOMAIN=$DOMAIN
|
||||
|
||||
# Database Configuration
|
||||
DB_HOST=ydn-db
|
||||
DB_PORT=5432
|
||||
DB_USER=ydn_user
|
||||
DB_PASSWORD=$(openssl rand -base64 32)
|
||||
DB_NAME=ydn_db
|
||||
DB_SSLMODE=require
|
||||
|
||||
# Redis Configuration
|
||||
REDIS_HOST=ydn-redis
|
||||
REDIS_PORT=6379
|
||||
REDIS_PASSWORD=$(openssl rand -base64 32)
|
||||
REDIS_DB=0
|
||||
|
||||
# JWT Configuration
|
||||
JWT_SECRET=$(openssl rand -base64 64)
|
||||
JWT_EXPIRY=24h
|
||||
|
||||
# Stripe Configuration
|
||||
STRIPE_PUBLIC_KEY=$STRIPE_PUBLIC_KEY
|
||||
STRIPE_SECRET_KEY=$STRIPE_SECRET_KEY
|
||||
STRIPE_WEBHOOK_SECRET=$STRIPE_WEBHOOK_SECRET
|
||||
STRIPE_PRICE_ID=$STRIPE_PRICE_ID
|
||||
|
||||
# OVH Configuration
|
||||
OVH_ENDPOINT=$OVH_ENDPOINT
|
||||
OVH_APPLICATION_KEY=$OVH_APPLICATION_KEY
|
||||
OVH_APPLICATION_SECRET=$OVH_APPLICATION_SECRET
|
||||
OVH_CONSUMER_KEY=$OVH_CONSUMER_KEY
|
||||
|
||||
# Email Configuration
|
||||
SMTP_HOST=$SMTP_HOST
|
||||
SMTP_PORT=$SMTP_PORT
|
||||
SMTP_USER=$SMTP_USER
|
||||
SMTP_PASSWORD=$SMTP_PASSWORD
|
||||
SMTP_FROM=$SMTP_FROM
|
||||
|
||||
# Dolibarr Configuration
|
||||
DOLIBARR_URL=https://$DOMAIN/dolibarr
|
||||
DOLIBARR_API_TOKEN=$DOLIBARR_API_TOKEN
|
||||
|
||||
# Monitoring
|
||||
GRAFANA_ADMIN_PASSWORD=$(openssl rand -base64 16)
|
||||
|
||||
# Version
|
||||
VERSION=$VERSION
|
||||
EOF
|
||||
|
||||
# Copy files to remote server
|
||||
scp -r "$TEMP_DIR/"* "$DEPLOYMENT_USER@$DEPLOYMENT_HOST:/opt/ydn/"
|
||||
|
||||
# Set correct permissions
|
||||
ssh "$DEPLOYMENT_USER@$DEPLOYMENT_HOST" "chown -R ydn:ydn /opt/ydn"
|
||||
|
||||
log_success "Application files deployed"
|
||||
}
|
||||
|
||||
# Generate SSL certificates
|
||||
setup_ssl() {
|
||||
log_info "Setting up SSL certificates..."
|
||||
|
||||
ssh "$DEPLOYMENT_USER@$DEPLOYMENT_HOST" << EOF
|
||||
set -euo pipefail
|
||||
|
||||
cd /opt/ydn
|
||||
|
||||
# Generate initial nginx config for SSL challenge
|
||||
cat > configs/nginx.init.conf << 'NGINX'
|
||||
events {
|
||||
worker_connections 1024;
|
||||
}
|
||||
|
||||
http {
|
||||
server {
|
||||
listen 80;
|
||||
server_name $DOMAIN;
|
||||
|
||||
location /.well-known/acme-challenge/ {
|
||||
root /var/www/html;
|
||||
}
|
||||
|
||||
location / {
|
||||
return 301 https://\$server_name\$request_uri;
|
||||
}
|
||||
}
|
||||
}
|
||||
NGINX
|
||||
|
||||
# Start temporary nginx for SSL challenge
|
||||
docker run -d \
|
||||
--name ydn-nginx-temp \
|
||||
-p 80:80 \
|
||||
-v /opt/ydn/configs/nginx.init.conf:/etc/nginx/nginx.conf:ro \
|
||||
-v /var/www/html:/var/www/html \
|
||||
nginx:alpine
|
||||
|
||||
# Wait for nginx to start
|
||||
sleep 10
|
||||
|
||||
# Request SSL certificate
|
||||
if [ ! -d "/etc/letsencrypt/live/$DOMAIN" ]; then
|
||||
certbot certonly --webroot \
|
||||
-w /var/www/html \
|
||||
-d $DOMAIN \
|
||||
--email admin@$DOMAIN \
|
||||
--agree-tos \
|
||||
--no-eff-email \
|
||||
--non-interactive
|
||||
fi
|
||||
|
||||
# Stop temporary nginx
|
||||
docker stop ydn-nginx-temp
|
||||
docker rm ydn-nginx-temp
|
||||
|
||||
# Copy certificates to project directory
|
||||
mkdir -p ssl
|
||||
cp /etc/letsencrypt/live/$DOMAIN/fullchain.pem ssl/
|
||||
cp /etc/letsencrypt/live/$DOMAIN/privkey.pem ssl/
|
||||
chown -R ydn:ydn ssl
|
||||
|
||||
# Set up automatic renewal
|
||||
echo "0 12 * * * /usr/bin/certbot renew --quiet --deploy-hook 'docker kill -s HUP ydn-nginx'" | crontab -
|
||||
|
||||
EOF
|
||||
|
||||
log_success "SSL certificates configured"
|
||||
}
|
||||
|
||||
# Deploy application stack
|
||||
deploy_application() {
|
||||
log_info "Deploying application stack..."
|
||||
|
||||
ssh "$DEPLOYMENT_USER@$DEPLOYMENT_HOST" << EOF
|
||||
set -euo pipefail
|
||||
|
||||
cd /opt/ydn
|
||||
|
||||
# Switch to ydn user
|
||||
sudo -u ydn bash << 'USER_SCRIPT'
|
||||
set -euo pipefail
|
||||
|
||||
# Load environment variables
|
||||
source .env.prod
|
||||
|
||||
# Build and push Docker image (if registry is configured)
|
||||
if [ -n "$DOCKER_REGISTRY" ]; then
|
||||
docker build -t $DOCKER_REGISTRY/ydn-app:\$VERSION .
|
||||
docker push $DOCKER_REGISTRY/ydn-app:\$VERSION
|
||||
fi
|
||||
|
||||
# Create production docker-compose override
|
||||
cat > docker-compose.override.yml << 'OVERRIDE'
|
||||
version: '3.8'
|
||||
|
||||
services:
|
||||
ydn-app:
|
||||
image: ${DOCKER_REGISTRY:-ydn-app}:ydn-app:\${VERSION:-latest}
|
||||
environment:
|
||||
- \${APP_ENV}
|
||||
- \${DB_HOST}
|
||||
- \${DB_USER}
|
||||
- \${DB_PASSWORD}
|
||||
- \${DB_NAME}
|
||||
- \${DB_SSLMODE}
|
||||
- \${REDIS_HOST}
|
||||
- \${REDIS_PASSWORD}
|
||||
- \${JWT_SECRET}
|
||||
- \${STRIPE_PUBLIC_KEY}
|
||||
- \${STRIPE_SECRET_KEY}
|
||||
- \${STRIPE_WEBHOOK_SECRET}
|
||||
- \${STRIPE_PRICE_ID}
|
||||
- \${OVH_ENDPOINT}
|
||||
- \${OVH_APPLICATION_KEY}
|
||||
- \${OVH_APPLICATION_SECRET}
|
||||
- \${OVH_CONSUMER_KEY}
|
||||
- \${SMTP_HOST}
|
||||
- \${SMTP_USER}
|
||||
- \${SMTP_PASSWORD}
|
||||
- \${SMTP_FROM}
|
||||
- \${DOLIBARR_URL}
|
||||
- \${DOLIBARR_API_TOKEN}
|
||||
|
||||
ydn-nginx:
|
||||
volumes:
|
||||
- ./ssl:/etc/nginx/ssl:ro
|
||||
environment:
|
||||
- DOMAIN=\${DOMAIN}
|
||||
|
||||
ydn-backup:
|
||||
environment:
|
||||
- DB_PASSWORD=\${DB_PASSWORD}
|
||||
- BACKUP_WEBHOOK_URL=\${BACKUP_WEBHOOK_URL:-}
|
||||
OVERRIDE
|
||||
|
||||
# Deploy with monitoring if enabled
|
||||
if [ "$ENABLE_MONITORING" = "true" ]; then
|
||||
docker-compose -f docker-compose.prod.yml --profile monitoring up -d
|
||||
else
|
||||
docker-compose -f docker-compose.prod.yml up -d
|
||||
fi
|
||||
|
||||
# Wait for services to be ready
|
||||
sleep 30
|
||||
|
||||
# Run database migrations
|
||||
docker-compose -f docker-compose.prod.yml exec ydn-app /app/main migrate || true
|
||||
|
||||
USER_SCRIPT
|
||||
|
||||
EOF
|
||||
|
||||
log_success "Application stack deployed"
|
||||
}
|
||||
|
||||
# Health check
|
||||
health_check() {
|
||||
log_info "Performing health checks..."
|
||||
|
||||
# Wait for application to start
|
||||
sleep 60
|
||||
|
||||
# Check if services are running
|
||||
ssh "$DEPLOYMENT_USER@$DEPLOYMENT_HOST" << EOF
|
||||
set -euo pipefail
|
||||
|
||||
cd /opt/ydn
|
||||
|
||||
# Check Docker containers
|
||||
if ! docker-compose -f docker-compose.prod.yml ps | grep -q "Up"; then
|
||||
echo "ERROR: Some containers are not running"
|
||||
docker-compose -f docker-compose.prod.yml ps
|
||||
exit 1
|
||||
fi
|
||||
|
||||
# Check application health
|
||||
for i in {1..30}; do
|
||||
if curl -f http://localhost/health > /dev/null 2>&1; then
|
||||
echo "Application health check passed"
|
||||
break
|
||||
fi
|
||||
|
||||
if [ \$i -eq 30 ]; then
|
||||
echo "ERROR: Application health check failed"
|
||||
exit 1
|
||||
fi
|
||||
|
||||
sleep 10
|
||||
done
|
||||
|
||||
# Check SSL certificate
|
||||
if ! curl -f https://$DOMAIN/health > /dev/null 2>&1; then
|
||||
echo "ERROR: SSL health check failed"
|
||||
exit 1
|
||||
fi
|
||||
|
||||
echo "All health checks passed"
|
||||
EOF
|
||||
|
||||
log_success "Health checks completed"
|
||||
}
|
||||
|
||||
# Setup monitoring
|
||||
setup_monitoring() {
|
||||
if [ "$ENABLE_MONITORING" != "true" ]; then
|
||||
log_info "Monitoring is disabled"
|
||||
return 0
|
||||
fi
|
||||
|
||||
log_info "Setting up monitoring..."
|
||||
|
||||
ssh "$DEPLOYMENT_USER@$DEPLOYMENT_HOST" << EOF
|
||||
set -euo pipefail
|
||||
|
||||
cd /opt/ydn
|
||||
|
||||
# Configure Prometheus
|
||||
cat > configs/prometheus.prod.yml << 'PROMETHEUS'
|
||||
global:
|
||||
scrape_interval: 15s
|
||||
evaluation_interval: 15s
|
||||
|
||||
rule_files:
|
||||
- "rules/*.yml"
|
||||
|
||||
scrape_configs:
|
||||
- job_name: 'ydn-app'
|
||||
static_configs:
|
||||
- targets: ['ydn-app:8080']
|
||||
metrics_path: /metrics
|
||||
|
||||
- job_name: 'nginx'
|
||||
static_configs:
|
||||
- targets: ['ydn-nginx:9113']
|
||||
|
||||
- job_name: 'postgres'
|
||||
static_configs:
|
||||
- targets: ['ydn-db:5432']
|
||||
|
||||
- job_name: 'redis'
|
||||
static_configs:
|
||||
- targets: ['ydn-redis:6379']
|
||||
|
||||
alerting:
|
||||
alertmanagers:
|
||||
- static_configs:
|
||||
- targets:
|
||||
- alertmanager:9093
|
||||
PROMETHEUS
|
||||
|
||||
# Restart monitoring services
|
||||
sudo -u ydn docker-compose -f docker-compose.prod.yml --profile monitoring restart ydn-prometheus ydn-grafana
|
||||
|
||||
EOF
|
||||
|
||||
log_success "Monitoring configured"
|
||||
}
|
||||
|
||||
# Deploy to production
|
||||
deploy_production() {
|
||||
log_info "Starting production deployment..."
|
||||
|
||||
validate_environment
|
||||
prepare_server
|
||||
deploy_files
|
||||
setup_ssl
|
||||
deploy_application
|
||||
setup_monitoring
|
||||
health_check
|
||||
|
||||
log_success "🎉 Production deployment completed successfully!"
|
||||
log_info "Application is available at: https://$DOMAIN"
|
||||
|
||||
if [ "$ENABLE_MONITORING" = "true" ]; then
|
||||
log_info "Grafana is available at: https://$DOMAIN/grafana"
|
||||
fi
|
||||
|
||||
log_info "Dolibarr is available at: https://$DOMAIN/dolibarr"
|
||||
}
|
||||
|
||||
# Rollback deployment
|
||||
rollback() {
|
||||
log_warning "Rolling back deployment..."
|
||||
|
||||
ssh "$DEPLOYMENT_USER@$DEPLOYMENT_HOST" << EOF
|
||||
set -euo pipefail
|
||||
|
||||
cd /opt/ydn
|
||||
|
||||
# Get previous version from git
|
||||
PREVIOUS_VERSION=\$(git log --format=%H -n 2 | tail -n 1)
|
||||
|
||||
# Checkout previous version
|
||||
sudo -u ydn git checkout \$PREVIOUS_VERSION
|
||||
|
||||
# Redeploy
|
||||
sudo -u ydn docker-compose -f docker-compose.prod.yml down
|
||||
sudo -u ydn docker-compose -f docker-compose.prod.yml up -d
|
||||
|
||||
EOF
|
||||
|
||||
log_success "Rollback completed"
|
||||
}
|
||||
|
||||
# Show help
|
||||
show_help() {
|
||||
cat << EOF
|
||||
YourDreamNameHere Production Deployment Script
|
||||
|
||||
Usage: $0 [OPTIONS]
|
||||
|
||||
Commands:
|
||||
deploy Deploy to production (default)
|
||||
rollback Rollback to previous version
|
||||
status Show deployment status
|
||||
help Show this help message
|
||||
|
||||
Environment Variables:
|
||||
DEPLOYMENT_HOST Target server hostname/IP (required)
|
||||
DOMAIN Domain name (required)
|
||||
DOCKER_REGISTRY Docker registry URL (optional)
|
||||
VERSION Version tag (default: latest)
|
||||
ENABLE_MONITORING Enable monitoring (default: true)
|
||||
ENABLE_LOGGING Enable logging (default: true)
|
||||
STRIPE_PUBLIC_KEY Stripe public key (required)
|
||||
STRIPE_SECRET_KEY Stripe secret key (required)
|
||||
STRIPE_WEBHOOK_SECRET Stripe webhook secret (required)
|
||||
STRIPE_PRICE_ID Stripe price ID (required)
|
||||
OVH_ENDPOINT OVH API endpoint
|
||||
OVH_APPLICATION_KEY OVH application key
|
||||
OVH_APPLICATION_SECRET OVH application secret
|
||||
OVH_CONSUMER_KEY OVH consumer key
|
||||
SMTP_HOST SMTP server hostname
|
||||
SMTP_PORT SMTP server port
|
||||
SMTP_USER SMTP username
|
||||
SMTP_PASSWORD SMTP password
|
||||
SMTP_FROM From email address
|
||||
DOLIBARR_API_TOKEN Dolibarr API token
|
||||
BACKUP_WEBHOOK_URL Backup notification webhook URL (optional)
|
||||
|
||||
Examples:
|
||||
# Deploy to production
|
||||
DEPLOYMENT_HOST=192.168.1.100 DOMAIN=example.com $0 deploy
|
||||
|
||||
# Deploy with monitoring disabled
|
||||
DEPLOYMENT_HOST=192.168.1.100 DOMAIN=example.com ENABLE_MONITORING=false $0 deploy
|
||||
|
||||
# Rollback deployment
|
||||
DEPLOYMENT_HOST=192.168.1.100 DOMAIN=example.com $0 rollback
|
||||
EOF
|
||||
}
|
||||
|
||||
# Main execution
|
||||
case "${1:-deploy}" in
|
||||
deploy)
|
||||
deploy_production
|
||||
;;
|
||||
rollback)
|
||||
rollback
|
||||
;;
|
||||
status)
|
||||
ssh "$DEPLOYMENT_USER@$DEPLOYMENT_HOST" "cd /opt/ydn && docker-compose -f docker-compose.prod.yml ps"
|
||||
;;
|
||||
help|--help|-h)
|
||||
show_help
|
||||
;;
|
||||
*)
|
||||
log_error "Unknown command: $1"
|
||||
show_help
|
||||
exit 1
|
||||
;;
|
||||
esac
|
||||
372
output/scripts/dev.sh
Executable file
372
output/scripts/dev.sh
Executable file
@@ -0,0 +1,372 @@
|
||||
#!/bin/bash
|
||||
|
||||
# YourDreamNameHere Local Development Setup Script
|
||||
# This script sets up a complete local development environment
|
||||
|
||||
set -euo pipefail
|
||||
|
||||
# Configuration
|
||||
PROJECT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")/.." && pwd)"
|
||||
COMPOSE_FILE="$PROJECT_DIR/docker-compose.yml"
|
||||
ENV_FILE="$PROJECT_DIR/configs/.env"
|
||||
|
||||
# Colors for output
|
||||
RED='\033[0;31m'
|
||||
GREEN='\033[0;32m'
|
||||
YELLOW='\033[1;33m'
|
||||
BLUE='\033[0;34m'
|
||||
NC='\033[0m' # No Color
|
||||
|
||||
# Functions
|
||||
log_info() {
|
||||
echo -e "${BLUE}[INFO]${NC} $1"
|
||||
}
|
||||
|
||||
log_success() {
|
||||
echo -e "${GREEN}[SUCCESS]${NC} $1"
|
||||
}
|
||||
|
||||
log_warning() {
|
||||
echo -e "${YELLOW}[WARNING]${NC} $1"
|
||||
}
|
||||
|
||||
log_error() {
|
||||
echo -e "${RED}[ERROR]${NC} $1"
|
||||
}
|
||||
|
||||
# Check dependencies
|
||||
check_dependencies() {
|
||||
log_info "Checking dependencies..."
|
||||
|
||||
# Check Docker
|
||||
if ! command -v docker &> /dev/null; then
|
||||
log_error "Docker is not installed. Please install Docker first."
|
||||
exit 1
|
||||
fi
|
||||
|
||||
# Check Docker Compose
|
||||
if ! command -v docker-compose &> /dev/null; then
|
||||
log_error "Docker Compose is not installed. Please install Docker Compose first."
|
||||
exit 1
|
||||
fi
|
||||
|
||||
# Check Go
|
||||
if ! command -v go &> /dev/null; then
|
||||
log_error "Go is not installed. Please install Go 1.21 or later."
|
||||
exit 1
|
||||
fi
|
||||
|
||||
# Check Node.js (optional, for frontend development)
|
||||
if ! command -v node &> /dev/null; then
|
||||
log_warning "Node.js is not installed. Some frontend tools may not work."
|
||||
fi
|
||||
|
||||
log_success "All dependencies checked"
|
||||
}
|
||||
|
||||
# Setup environment
|
||||
setup_environment() {
|
||||
log_info "Setting up environment..."
|
||||
|
||||
# Create .env file if it doesn't exist
|
||||
if [ ! -f "$ENV_FILE" ]; then
|
||||
log_info "Creating .env file from template..."
|
||||
cp "$PROJECT_DIR/configs/.env.example" "$ENV_FILE"
|
||||
|
||||
# Generate random secrets
|
||||
sed -i "s/your_jwt_secret_key_here_make_it_long_and_random/$(openssl rand -base64 64)/" "$ENV_FILE"
|
||||
sed -i "s/your_secure_password/$(openssl rand -base64 16)/" "$ENV_FILE"
|
||||
sed -i "s/redis_password_change_me/$(openssl rand -base64 16)/" "$ENV_FILE"
|
||||
|
||||
log_warning "Please edit $ENV_FILE with your actual API keys and configuration"
|
||||
else
|
||||
log_info "Environment file already exists"
|
||||
fi
|
||||
|
||||
# Create necessary directories
|
||||
mkdir -p "$PROJECT_DIR/logs"
|
||||
mkdir -p "$PROJECT_DIR/backups"
|
||||
mkdir -p "$PROJECT_DIR/ssl"
|
||||
|
||||
log_success "Environment setup completed"
|
||||
}
|
||||
|
||||
# Build application
|
||||
build_application() {
|
||||
log_info "Building application..."
|
||||
|
||||
cd "$PROJECT_DIR"
|
||||
|
||||
# Download dependencies
|
||||
go mod download
|
||||
go mod tidy
|
||||
|
||||
# Build binary
|
||||
go build -o bin/ydn-app cmd/main.go
|
||||
|
||||
log_success "Application built successfully"
|
||||
}
|
||||
|
||||
# Start services
|
||||
start_services() {
|
||||
log_info "Starting development services..."
|
||||
|
||||
cd "$PROJECT_DIR"
|
||||
|
||||
# Start Docker services
|
||||
docker-compose -f "$COMPOSE_FILE" up -d
|
||||
|
||||
# Wait for database to be ready
|
||||
log_info "Waiting for database to be ready..."
|
||||
max_attempts=30
|
||||
attempt=0
|
||||
|
||||
while [ $attempt -lt $max_attempts ]; do
|
||||
if docker-compose -f "$COMPOSE_FILE" exec -T ydn-db pg_isready -U ydn_user -d ydn_db > /dev/null 2>&1; then
|
||||
break
|
||||
fi
|
||||
attempt=$((attempt + 1))
|
||||
sleep 2
|
||||
done
|
||||
|
||||
if [ $attempt -eq $max_attempts ]; then
|
||||
log_error "Database failed to start"
|
||||
exit 1
|
||||
fi
|
||||
|
||||
# Wait for Redis to be ready
|
||||
log_info "Waiting for Redis to be ready..."
|
||||
attempt=0
|
||||
|
||||
while [ $attempt -lt $max_attempts ]; do
|
||||
if docker-compose -f "$COMPOSE_FILE" exec -T ydn-redis redis-cli ping > /dev/null 2>&1; then
|
||||
break
|
||||
fi
|
||||
attempt=$((attempt + 1))
|
||||
sleep 2
|
||||
done
|
||||
|
||||
if [ $attempt -eq $max_attempts ]; then
|
||||
log_error "Redis failed to start"
|
||||
exit 1
|
||||
fi
|
||||
|
||||
log_success "All services started successfully"
|
||||
}
|
||||
|
||||
# Run database migrations
|
||||
run_migrations() {
|
||||
log_info "Running database migrations..."
|
||||
|
||||
cd "$PROJECT_DIR"
|
||||
|
||||
# Run migrations
|
||||
if ./bin/ydn-app migrate; then
|
||||
log_success "Database migrations completed"
|
||||
else
|
||||
log_error "Database migrations failed"
|
||||
exit 1
|
||||
fi
|
||||
}
|
||||
|
||||
# Setup development tools
|
||||
setup_dev_tools() {
|
||||
log_info "Setting up development tools..."
|
||||
|
||||
cd "$PROJECT_DIR"
|
||||
|
||||
# Install pre-commit hooks
|
||||
if command -v pre-commit &> /dev/null; then
|
||||
pre-commit install
|
||||
log_info "Pre-commit hooks installed"
|
||||
else
|
||||
log_warning "pre-commit not found. Install with: pip install pre-commit"
|
||||
fi
|
||||
|
||||
# Download test dependencies
|
||||
go mod download
|
||||
|
||||
log_success "Development tools setup completed"
|
||||
}
|
||||
|
||||
# Show development URLs
|
||||
show_urls() {
|
||||
log_success "Development environment is ready!"
|
||||
echo
|
||||
echo "🌐 Application URLs:"
|
||||
echo " Main Application: http://localhost:8080"
|
||||
echo " API Documentation: http://localhost:8080/swagger/index.html"
|
||||
echo " Health Check: http://localhost:8080/health"
|
||||
echo " Dolibarr: http://localhost:8081"
|
||||
echo
|
||||
echo "🐳 Docker Services:"
|
||||
echo " PostgreSQL: localhost:5432"
|
||||
echo " Redis: localhost:6379"
|
||||
echo
|
||||
echo "📊 Monitoring (optional):"
|
||||
echo " Grafana: http://localhost:3000 (admin/grafana_admin_change_me)"
|
||||
echo " Prometheus: http://localhost:9090"
|
||||
echo
|
||||
echo "🔧 Development Commands:"
|
||||
echo " Run application: ./bin/ydn-app"
|
||||
echo " Run tests: ./scripts/test.sh"
|
||||
echo " Stop services: docker-compose -f docker-compose.yml down"
|
||||
echo " View logs: docker-compose -f docker-compose.yml logs -f"
|
||||
}
|
||||
|
||||
# Start development server
|
||||
start_dev_server() {
|
||||
log_info "Starting development server..."
|
||||
|
||||
cd "$PROJECT_DIR"
|
||||
|
||||
# Start the application in development mode
|
||||
if [ -f "./bin/ydn-app" ]; then
|
||||
./bin/ydn-app
|
||||
else
|
||||
log_error "Application binary not found. Run './scripts/dev.sh setup' first."
|
||||
exit 1
|
||||
fi
|
||||
}
|
||||
|
||||
# Stop services
|
||||
stop_services() {
|
||||
log_info "Stopping development services..."
|
||||
|
||||
cd "$PROJECT_DIR"
|
||||
|
||||
docker-compose -f "$COMPOSE_FILE" down
|
||||
|
||||
log_success "All services stopped"
|
||||
}
|
||||
|
||||
# Clean environment
|
||||
clean_environment() {
|
||||
log_info "Cleaning development environment..."
|
||||
|
||||
cd "$PROJECT_DIR"
|
||||
|
||||
# Stop and remove containers
|
||||
docker-compose -f "$COMPOSE_FILE" down -v --remove-orphans
|
||||
|
||||
# Remove images
|
||||
docker-compose -f "$COMPOSE_FILE" down --rmi all
|
||||
|
||||
# Clean up binaries and logs
|
||||
rm -rf bin/
|
||||
rm -rf logs/*
|
||||
rm -rf backups/*
|
||||
|
||||
log_success "Environment cleaned"
|
||||
}
|
||||
|
||||
# Reset database
|
||||
reset_database() {
|
||||
log_warning "Resetting database..."
|
||||
|
||||
cd "$PROJECT_DIR"
|
||||
|
||||
# Stop services
|
||||
docker-compose -f "$COMPOSE_FILE" down
|
||||
|
||||
# Remove database volume
|
||||
docker volume rm $(docker-compose -f "$COMPOSE_FILE" config --volumes | grep postgres_data) 2>/dev/null || true
|
||||
|
||||
# Start services again
|
||||
docker-compose -f "$COMPOSE_FILE" up -d
|
||||
|
||||
# Wait for database
|
||||
sleep 10
|
||||
|
||||
# Run migrations
|
||||
run_migrations
|
||||
|
||||
log_success "Database reset completed"
|
||||
}
|
||||
|
||||
# Show help
|
||||
show_help() {
|
||||
cat << EOF
|
||||
YourDreamNameHere Development Setup Script
|
||||
|
||||
Usage: $0 [COMMAND]
|
||||
|
||||
Commands:
|
||||
setup Set up the complete development environment
|
||||
start Start development services
|
||||
stop Stop development services
|
||||
restart Restart development services
|
||||
dev Start development server
|
||||
test Run test suite
|
||||
clean Clean up development environment
|
||||
reset-db Reset database
|
||||
logs Show service logs
|
||||
status Show service status
|
||||
help Show this help message
|
||||
|
||||
Examples:
|
||||
$0 setup # Initial setup
|
||||
$0 start # Start services
|
||||
$0 dev # Start development server
|
||||
$0 test # Run tests
|
||||
$0 clean # Clean everything
|
||||
|
||||
Environment File:
|
||||
Edit $ENV_FILE to configure your API keys and settings
|
||||
EOF
|
||||
}
|
||||
|
||||
# Main execution
|
||||
case "${1:-setup}" in
|
||||
setup)
|
||||
check_dependencies
|
||||
setup_environment
|
||||
build_application
|
||||
start_services
|
||||
run_migrations
|
||||
setup_dev_tools
|
||||
show_urls
|
||||
;;
|
||||
start)
|
||||
start_services
|
||||
run_migrations
|
||||
show_urls
|
||||
;;
|
||||
stop)
|
||||
stop_services
|
||||
;;
|
||||
restart)
|
||||
stop_services
|
||||
start_services
|
||||
run_migrations
|
||||
show_urls
|
||||
;;
|
||||
dev)
|
||||
start_dev_server
|
||||
;;
|
||||
test)
|
||||
"$PROJECT_DIR/scripts/test.sh"
|
||||
;;
|
||||
clean)
|
||||
clean_environment
|
||||
;;
|
||||
reset-db)
|
||||
reset_database
|
||||
;;
|
||||
logs)
|
||||
cd "$PROJECT_DIR"
|
||||
docker-compose -f "$COMPOSE_FILE" logs -f
|
||||
;;
|
||||
status)
|
||||
cd "$PROJECT_DIR"
|
||||
docker-compose -f "$COMPOSE_FILE" ps
|
||||
;;
|
||||
help|--help|-h)
|
||||
show_help
|
||||
;;
|
||||
*)
|
||||
log_error "Unknown command: $1"
|
||||
show_help
|
||||
exit 1
|
||||
;;
|
||||
esac
|
||||
220
output/scripts/emergency-deploy.sh
Executable file
220
output/scripts/emergency-deploy.sh
Executable file
@@ -0,0 +1,220 @@
|
||||
#!/bin/bash
|
||||
|
||||
# EMERGENCY PRODUCTION DEPLOYMENT SCRIPT
|
||||
# Run this to launch YDN in 24 hours
|
||||
|
||||
set -euo pipefail
|
||||
|
||||
# Colors
|
||||
RED='\033[0;31m'
|
||||
GREEN='\033[0;32m'
|
||||
YELLOW='\033[1;33m'
|
||||
BLUE='\033[0;34m'
|
||||
NC='\033[0m'
|
||||
|
||||
log_info() { echo -e "${BLUE}[INFO]${NC} $1"; }
|
||||
log_success() { echo -e "${GREEN}[SUCCESS]${NC} $1"; }
|
||||
log_warning() { echo -e "${YELLOW}[WARNING]${NC} $1"; }
|
||||
log_error() { echo -e "${RED}[ERROR]${NC} $1"; }
|
||||
|
||||
# Configuration check
|
||||
check_environment() {
|
||||
log_info "Checking environment configuration..."
|
||||
|
||||
required_vars=(
|
||||
"DOMAIN" "DB_PASSWORD" "JWT_SECRET" "STRIPE_SECRET_KEY"
|
||||
"OVH_APPLICATION_KEY" "OVH_APPLICATION_SECRET" "OVH_CONSUMER_KEY"
|
||||
"SMTP_HOST" "SMTP_USER" "SMTP_PASSWORD"
|
||||
)
|
||||
|
||||
missing_vars=()
|
||||
for var in "${required_vars[@]}"; do
|
||||
if [ -z "${!var:-}" ]; then
|
||||
missing_vars+=("$var")
|
||||
fi
|
||||
done
|
||||
|
||||
if [ ${#missing_vars[@]} -ne 0 ]; then
|
||||
log_error "Missing required environment variables:"
|
||||
printf ' %s\n' "${missing_vars[@]}"
|
||||
log_info "Please set these in your .env file or environment"
|
||||
exit 1
|
||||
fi
|
||||
|
||||
log_success "Environment configuration OK"
|
||||
}
|
||||
|
||||
# SSL Certificate Setup
|
||||
setup_ssl() {
|
||||
log_info "Setting up SSL certificates..."
|
||||
|
||||
if [ ! -d "./ssl" ]; then
|
||||
mkdir -p ./ssl
|
||||
fi
|
||||
|
||||
# Generate self-signed certificate for immediate deployment
|
||||
# Replace with Let's Encrypt later
|
||||
if [ ! -f "./ssl/fullchain.pem" ] || [ ! -f "./ssl/privkey.pem" ]; then
|
||||
log_warning "Generating self-signed certificate (replace with production cert ASAP)"
|
||||
openssl req -x509 -nodes -days 365 -newkey rsa:2048 \
|
||||
-keyout ./ssl/privkey.pem \
|
||||
-out ./ssl/fullchain.pem \
|
||||
-subj "/C=US/ST=State/L=City/O=YourDreamNameHere/CN=${DOMAIN}"
|
||||
fi
|
||||
|
||||
log_success "SSL certificates ready"
|
||||
}
|
||||
|
||||
# Deploy application
|
||||
deploy_application() {
|
||||
log_info "Deploying application..."
|
||||
|
||||
# Build and start services
|
||||
docker-compose -f docker-compose.prod.yml down
|
||||
docker-compose -f docker-compose.prod.yml build --no-cache
|
||||
docker-compose -f docker-compose.prod.yml up -d
|
||||
|
||||
log_success "Application deployed"
|
||||
}
|
||||
|
||||
# Health checks
|
||||
health_check() {
|
||||
log_info "Performing health checks..."
|
||||
|
||||
# Wait for services to start
|
||||
sleep 30
|
||||
|
||||
# Check application health
|
||||
max_attempts=30
|
||||
attempt=0
|
||||
|
||||
while [ $attempt -lt $max_attempts ]; do
|
||||
if curl -f -s http://localhost/health > /dev/null 2>&1; then
|
||||
log_success "Application health check passed"
|
||||
break
|
||||
fi
|
||||
|
||||
attempt=$((attempt + 1))
|
||||
if [ $attempt -eq $max_attempts ]; then
|
||||
log_error "Application health check failed"
|
||||
docker-compose -f docker-compose.prod.yml logs --tail=50 ydn-app
|
||||
exit 1
|
||||
fi
|
||||
|
||||
sleep 5
|
||||
done
|
||||
|
||||
# Check database connection
|
||||
if docker-compose -f docker-compose.prod.yml exec -T ydn-db pg_isready -U "${DB_USER}" -d "${DB_NAME}" > /dev/null 2>&1; then
|
||||
log_success "Database health check passed"
|
||||
else
|
||||
log_error "Database health check failed"
|
||||
exit 1
|
||||
fi
|
||||
|
||||
log_success "All health checks passed"
|
||||
}
|
||||
|
||||
# Create admin user
|
||||
create_admin() {
|
||||
log_info "Creating admin user..."
|
||||
|
||||
# Wait for application to be ready
|
||||
sleep 10
|
||||
|
||||
# Create admin user via API
|
||||
curl -X POST http://localhost/api/v1/register \
|
||||
-H "Content-Type: application/json" \
|
||||
-d '{
|
||||
"email": "admin@'${DOMAIN}'",
|
||||
"first_name": "Admin",
|
||||
"last_name": "User",
|
||||
"password": "admin123456!"
|
||||
}' || log_warning "Failed to create admin user (create manually)"
|
||||
|
||||
log_success "Admin user creation attempted"
|
||||
}
|
||||
|
||||
# Show deployment summary
|
||||
show_summary() {
|
||||
log_success "🎉 DEPLOYMENT COMPLETE!"
|
||||
echo
|
||||
echo "YourDreamNameHere is now running at: https://${DOMAIN}"
|
||||
echo "Dolibarr ERP: https://${DOMAIN}/dolibarr"
|
||||
echo "API Documentation: https://${DOMAIN}/swagger/index.html"
|
||||
echo
|
||||
echo "Admin User: admin@${DOMAIN}"
|
||||
echo "Admin Password: admin123456!"
|
||||
echo
|
||||
echo "IMPORTANT SECURITY NOTES:"
|
||||
echo "1. Change admin password immediately"
|
||||
echo "2. Replace self-signed SSL certificate with Let's Encrypt"
|
||||
echo "3. Configure proper OVH payment processing"
|
||||
echo "4. Set up monitoring and alerting"
|
||||
echo "5. Configure backup offloading"
|
||||
echo
|
||||
echo "Useful commands:"
|
||||
echo " View logs: docker-compose -f docker-compose.prod.yml logs -f"
|
||||
echo " Stop app: docker-compose -f docker-compose.prod.yml down"
|
||||
echo " Update app: docker-compose -f docker-compose.prod.yml pull && docker-compose -f docker-compose.prod.yml up -d"
|
||||
}
|
||||
|
||||
# Main execution
|
||||
main() {
|
||||
log_info "Starting emergency production deployment..."
|
||||
|
||||
# Load environment variables
|
||||
if [ -f ".env.prod" ]; then
|
||||
set -a
|
||||
source .env.prod
|
||||
set +a
|
||||
else
|
||||
log_warning ".env.prod file not found, using environment variables"
|
||||
fi
|
||||
|
||||
# Default values
|
||||
export DOMAIN="${DOMAIN:-yourdreamnamehere.com}"
|
||||
export DB_USER="${DB_USER:-ydn_user}"
|
||||
export DB_NAME="${DB_NAME:-ydn_db}"
|
||||
export DOCKER_REGISTRY="${DOCKER_REGISTRY:-ydn-app}"
|
||||
export VERSION="${VERSION:-latest}"
|
||||
|
||||
# Execute deployment steps
|
||||
check_environment
|
||||
setup_ssl
|
||||
deploy_application
|
||||
health_check
|
||||
create_admin
|
||||
show_summary
|
||||
|
||||
log_success "Deployment completed successfully! 🚀"
|
||||
}
|
||||
|
||||
# Help
|
||||
if [ "${1:-}" = "--help" ] || [ "${1:-}" = "-h" ]; then
|
||||
echo "Emergency Production Deployment Script"
|
||||
echo
|
||||
echo "Usage: $0"
|
||||
echo
|
||||
echo "Required Environment Variables:"
|
||||
echo " DOMAIN Your domain name"
|
||||
echo " DB_PASSWORD Database password"
|
||||
echo " JWT_SECRET JWT secret key"
|
||||
echo " STRIPE_SECRET_KEY Stripe secret key"
|
||||
echo " OVH_APPLICATION_KEY OVH API key"
|
||||
echo " OVH_APPLICATION_SECRET OVH API secret"
|
||||
echo " OVH_CONSUMER_KEY OVH consumer key"
|
||||
echo " SMTP_HOST SMTP server"
|
||||
echo " SMTP_USER SMTP username"
|
||||
echo " SMTP_PASSWORD SMTP password"
|
||||
echo
|
||||
echo "Optional Environment Variables:"
|
||||
echo " DB_USER Database user (default: ydn_user)"
|
||||
echo " DB_NAME Database name (default: ydn_db)"
|
||||
echo " VERSION Application version (default: latest)"
|
||||
echo
|
||||
exit 0
|
||||
fi
|
||||
|
||||
# Run main function
|
||||
main "$@"
|
||||
369
output/scripts/test.sh
Executable file
369
output/scripts/test.sh
Executable file
@@ -0,0 +1,369 @@
|
||||
#!/bin/bash
|
||||
|
||||
# YourDreamNameHere Test Runner
|
||||
# This script runs all test suites and generates reports
|
||||
|
||||
set -euo pipefail
|
||||
|
||||
# Configuration
|
||||
PROJECT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")/.." && pwd)"
|
||||
REPORT_DIR="${PROJECT_DIR}/test-reports"
|
||||
COVERAGE_DIR="${REPORT_DIR}/coverage"
|
||||
|
||||
# Colors for output
|
||||
RED='\033[0;31m'
|
||||
GREEN='\033[0;32m'
|
||||
YELLOW='\033[1;33m'
|
||||
BLUE='\033[0;34m'
|
||||
NC='\033[0m' # No Color
|
||||
|
||||
# Create report directories
|
||||
mkdir -p "$REPORT_DIR"
|
||||
mkdir -p "$COVERAGE_DIR"
|
||||
|
||||
# Functions
|
||||
log_info() {
|
||||
echo -e "${BLUE}[INFO]${NC} $1"
|
||||
}
|
||||
|
||||
log_success() {
|
||||
echo -e "${GREEN}[SUCCESS]${NC} $1"
|
||||
}
|
||||
|
||||
log_warning() {
|
||||
echo -e "${YELLOW}[WARNING]${NC} $1"
|
||||
}
|
||||
|
||||
log_error() {
|
||||
echo -e "${RED}[ERROR]${NC} $1"
|
||||
}
|
||||
|
||||
# Test result counters
|
||||
TOTAL_TESTS=0
|
||||
PASSED_TESTS=0
|
||||
FAILED_TESTS=0
|
||||
|
||||
# Run unit tests
|
||||
run_unit_tests() {
|
||||
log_info "Running unit tests..."
|
||||
|
||||
cd "$PROJECT_DIR"
|
||||
|
||||
# Run unit tests with coverage
|
||||
if go test -v -race -coverprofile="$COVERAGE_DIR/unit.out" -covermode=atomic ./tests/unit/... > "$REPORT_DIR/unit.log" 2>&1; then
|
||||
log_success "Unit tests passed"
|
||||
PASSED_TESTS=$((PASSED_TESTS + 1))
|
||||
else
|
||||
log_error "Unit tests failed"
|
||||
FAILED_TESTS=$((FAILED_TESTS + 1))
|
||||
echo "Unit test failures:"
|
||||
cat "$REPORT_DIR/unit.log" | tail -20
|
||||
return 1
|
||||
fi
|
||||
|
||||
TOTAL_TESTS=$((TOTAL_TESTS + 1))
|
||||
|
||||
# Generate coverage report
|
||||
go tool cover -html="$COVERAGE_DIR/unit.out" -o "$COVERAGE_DIR/unit.html"
|
||||
log_info "Unit test coverage report generated: $COVERAGE_DIR/unit.html"
|
||||
}
|
||||
|
||||
# Run integration tests
|
||||
run_integration_tests() {
|
||||
log_info "Running integration tests..."
|
||||
|
||||
# Check if required services are running
|
||||
if ! docker ps | grep -q "YDN-Dev-App"; then
|
||||
log_warning "Development stack not running. Starting it..."
|
||||
docker-compose -f docker-compose.yml up -d
|
||||
|
||||
# Wait for services to be ready
|
||||
log_info "Waiting for services to be ready..."
|
||||
sleep 30
|
||||
|
||||
# Run health checks
|
||||
max_attempts=30
|
||||
attempt=0
|
||||
|
||||
while [ $attempt -lt $max_attempts ]; do
|
||||
if curl -f http://localhost:8080/health > /dev/null 2>&1; then
|
||||
break
|
||||
fi
|
||||
attempt=$((attempt + 1))
|
||||
sleep 2
|
||||
done
|
||||
|
||||
if [ $attempt -eq $max_attempts ]; then
|
||||
log_error "Services failed to start properly"
|
||||
FAILED_TESTS=$((FAILED_TESTS + 1))
|
||||
return 1
|
||||
fi
|
||||
fi
|
||||
|
||||
cd "$PROJECT_DIR"
|
||||
|
||||
# Run integration tests
|
||||
if go test -v -race -coverprofile="$COVERAGE_DIR/integration.out" ./tests/integration/... > "$REPORT_DIR/integration.log" 2>&1; then
|
||||
log_success "Integration tests passed"
|
||||
PASSED_TESTS=$((PASSED_TESTS + 1))
|
||||
else
|
||||
log_error "Integration tests failed"
|
||||
FAILED_TESTS=$((FAILED_TESTS + 1))
|
||||
echo "Integration test failures:"
|
||||
cat "$REPORT_DIR/integration.log" | tail -20
|
||||
return 1
|
||||
fi
|
||||
|
||||
TOTAL_TESTS=$((TOTAL_TESTS + 1))
|
||||
|
||||
# Generate coverage report
|
||||
go tool cover -html="$COVERAGE_DIR/integration.out" -o "$COVERAGE_DIR/integration.html"
|
||||
log_info "Integration test coverage report generated: $COVERAGE_DIR/integration.html"
|
||||
}
|
||||
|
||||
# Run E2E tests
|
||||
run_e2e_tests() {
|
||||
log_info "Running E2E tests..."
|
||||
|
||||
# Check if E2E tests are enabled
|
||||
if [ "${ENABLE_E2E_TESTS:-false}" != "true" ]; then
|
||||
log_warning "E2E tests disabled. Set ENABLE_E2E_TESTS=true to enable."
|
||||
return 0
|
||||
fi
|
||||
|
||||
# Check if required tools are available
|
||||
if ! command -v chromedriver &> /dev/null; then
|
||||
log_error "ChromeDriver not found. Please install ChromeDriver to run E2E tests."
|
||||
FAILED_TESTS=$((FAILED_TESTS + 1))
|
||||
return 1
|
||||
fi
|
||||
|
||||
# Start ChromeDriver
|
||||
chromedriver --port=9515 --silent &
|
||||
CHROME_DRIVER_PID=$!
|
||||
|
||||
# Make sure to kill ChromeDriver on exit
|
||||
trap "kill $CHROME_DRIVER_PID 2>/dev/null || true" EXIT
|
||||
|
||||
# Wait for ChromeDriver to start
|
||||
sleep 5
|
||||
|
||||
cd "$PROJECT_DIR"
|
||||
|
||||
# Run E2E tests
|
||||
if go test -v ./tests/e2e/... > "$REPORT_DIR/e2e.log" 2>&1; then
|
||||
log_success "E2E tests passed"
|
||||
PASSED_TESTS=$((PASSED_TESTS + 1))
|
||||
else
|
||||
log_error "E2E tests failed"
|
||||
FAILED_TESTS=$((FAILED_TESTS + 1))
|
||||
echo "E2E test failures:"
|
||||
cat "$REPORT_DIR/e2e.log" | tail -20
|
||||
return 1
|
||||
fi
|
||||
|
||||
TOTAL_TESTS=$((TOTAL_TESTS + 1))
|
||||
}
|
||||
|
||||
# Run security tests
|
||||
run_security_tests() {
|
||||
log_info "Running security tests..."
|
||||
|
||||
cd "$PROJECT_DIR"
|
||||
|
||||
# Check for common security issues using gosec
|
||||
if command -v gosec &> /dev/null; then
|
||||
if gosec -quiet -fmt json -out "$REPORT_DIR/gosec.json" ./...; then
|
||||
log_success "Security scan passed"
|
||||
PASSED_TESTS=$((PASSED_TESTS + 1))
|
||||
else
|
||||
log_warning "Security scan found issues"
|
||||
cat "$REPORT_DIR/gosec.json" | jq '.Issues[] | .severity + ": " + .details'
|
||||
fi
|
||||
else
|
||||
log_warning "gosec not found. Install with: go install github.com/securecodewarrior/gosec/v2/cmd/gosec@latest"
|
||||
fi
|
||||
|
||||
TOTAL_TESTS=$((TOTAL_TESTS + 1))
|
||||
}
|
||||
|
||||
# Run performance tests
|
||||
run_performance_tests() {
|
||||
log_info "Running performance tests..."
|
||||
|
||||
# Basic performance test using curl
|
||||
if command -v curl &> /dev/null; then
|
||||
log_info "Testing API response times..."
|
||||
|
||||
# Test health endpoint
|
||||
response_time=$(curl -o /dev/null -s -w '%{time_total}' http://localhost:8080/health || echo "0")
|
||||
|
||||
if (( $(echo "$response_time < 1.0" | bc -l) )); then
|
||||
log_success "Health endpoint response time: ${response_time}s"
|
||||
PASSED_TESTS=$((PASSED_TESTS + 1))
|
||||
else
|
||||
log_warning "Health endpoint response time high: ${response_time}s"
|
||||
fi
|
||||
else
|
||||
log_warning "curl not available for performance testing"
|
||||
fi
|
||||
|
||||
TOTAL_TESTS=$((TOTAL_TESTS + 1))
|
||||
}
|
||||
|
||||
# Generate combined coverage report
|
||||
generate_coverage_report() {
|
||||
log_info "Generating combined coverage report..."
|
||||
|
||||
cd "$PROJECT_DIR"
|
||||
|
||||
# Combine coverage profiles
|
||||
echo "mode: atomic" > "$COVERAGE_DIR/combined.out"
|
||||
|
||||
for profile in "$COVERAGE_DIR"/*.out; do
|
||||
if [ -f "$profile" ] && [ "$profile" != "$COVERAGE_DIR/combined.out" ]; then
|
||||
grep -h -v "^mode:" "$profile" >> "$COVERAGE_DIR/combined.out" || true
|
||||
fi
|
||||
done
|
||||
|
||||
# Generate HTML report
|
||||
if [ -s "$COVERAGE_DIR/combined.out" ]; then
|
||||
go tool cover -html="$COVERAGE_DIR/combined.out" -o "$COVERAGE_DIR/combined.html"
|
||||
log_success "Combined coverage report generated: $COVERAGE_DIR/combined.html"
|
||||
|
||||
# Get coverage percentage
|
||||
coverage_percent=$(go tool cover -func="$COVERAGE_DIR/combined.out" | grep "total:" | awk '{print $3}')
|
||||
log_info "Total coverage: $coverage_percent"
|
||||
fi
|
||||
}
|
||||
|
||||
# Generate test summary
|
||||
generate_summary() {
|
||||
log_info "Generating test summary..."
|
||||
|
||||
cat > "$REPORT_DIR/summary.txt" << EOF
|
||||
YourDreamNameHere Test Summary
|
||||
================================
|
||||
|
||||
Test Results:
|
||||
- Total test suites: $TOTAL_TESTS
|
||||
- Passed: $PASSED_TESTS
|
||||
- Failed: $FAILED_TESTS
|
||||
- Success rate: $(( PASSED_TESTS * 100 / TOTAL_TESTS ))%
|
||||
|
||||
Test Reports:
|
||||
- Unit tests: $REPORT_DIR/unit.log
|
||||
- Integration tests: $REPORT_DIR/integration.log
|
||||
- E2E tests: $REPORT_DIR/e2e.log
|
||||
- Security scan: $REPORT_DIR/gosec.json
|
||||
|
||||
Coverage Reports:
|
||||
- Unit test coverage: $COVERAGE_DIR/unit.html
|
||||
- Integration test coverage: $COVERAGE_DIR/integration.html
|
||||
- Combined coverage: $COVERAGE_DIR/combined.html
|
||||
|
||||
Generated at: $(date)
|
||||
EOF
|
||||
|
||||
cat "$REPORT_DIR/summary.txt"
|
||||
}
|
||||
|
||||
# Main execution
|
||||
main() {
|
||||
log_info "Starting YourDreamNameHere test suite..."
|
||||
log_info "Project directory: $PROJECT_DIR"
|
||||
log_info "Report directory: $REPORT_DIR"
|
||||
|
||||
# Change to project directory
|
||||
cd "$PROJECT_DIR"
|
||||
|
||||
# Download test dependencies
|
||||
log_info "Downloading test dependencies..."
|
||||
go mod download
|
||||
go mod tidy
|
||||
|
||||
# Run test suites
|
||||
run_unit_tests
|
||||
run_integration_tests
|
||||
run_e2e_tests
|
||||
run_security_tests
|
||||
run_performance_tests
|
||||
|
||||
# Generate reports
|
||||
generate_coverage_report
|
||||
generate_summary
|
||||
|
||||
# Final status
|
||||
log_info "Test suite completed!"
|
||||
log_info "Results: $PASSED_TESTS/$TOTAL_TESTS passed"
|
||||
|
||||
if [ $FAILED_TESTS -eq 0 ]; then
|
||||
log_success "All tests passed! 🎉"
|
||||
exit 0
|
||||
else
|
||||
log_error "$FAILED_TESTS test suites failed!"
|
||||
exit 1
|
||||
fi
|
||||
}
|
||||
|
||||
# Help function
|
||||
show_help() {
|
||||
cat << EOF
|
||||
YourDreamNameHere Test Runner
|
||||
|
||||
Usage: $0 [OPTIONS]
|
||||
|
||||
Options:
|
||||
--unit Run only unit tests
|
||||
--integration Run only integration tests
|
||||
--e2e Run only E2E tests (requires ENABLE_E2E_TESTS=true)
|
||||
--security Run only security tests
|
||||
--performance Run only performance tests
|
||||
--coverage Generate coverage reports only
|
||||
--help Show this help message
|
||||
|
||||
Environment Variables:
|
||||
ENABLE_E2E_TESTS=true Enable E2E tests
|
||||
COVERAGE_THRESHOLD=80 Minimum coverage percentage (default: 80)
|
||||
|
||||
Examples:
|
||||
$0 # Run all tests
|
||||
$0 --unit # Run only unit tests
|
||||
$0 --integration # Run only integration tests
|
||||
ENABLE_E2E_TESTS=true $0 # Run all tests including E2E
|
||||
EOF
|
||||
}
|
||||
|
||||
# Parse command line arguments
|
||||
case "${1:-}" in
|
||||
--unit)
|
||||
run_unit_tests
|
||||
;;
|
||||
--integration)
|
||||
run_integration_tests
|
||||
;;
|
||||
--e2e)
|
||||
run_e2e_tests
|
||||
;;
|
||||
--security)
|
||||
run_security_tests
|
||||
;;
|
||||
--performance)
|
||||
run_performance_tests
|
||||
;;
|
||||
--coverage)
|
||||
generate_coverage_report
|
||||
;;
|
||||
--help)
|
||||
show_help
|
||||
exit 0
|
||||
;;
|
||||
"")
|
||||
main
|
||||
;;
|
||||
*)
|
||||
log_error "Unknown option: $1"
|
||||
show_help
|
||||
exit 1
|
||||
;;
|
||||
esac
|
||||
Reference in New Issue
Block a user