331 lines
8.5 KiB
Bash
Executable File
331 lines
8.5 KiB
Bash
Executable File
#!/bin/bash
|
||
set -e
|
||
|
||
# Rollback Application Deployment
|
||
# This script rolls back to a previous deployment using Ansible
|
||
|
||
SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)"
|
||
DEPLOYMENT_DIR="$(dirname "$SCRIPT_DIR")"
|
||
ANSIBLE_DIR="$DEPLOYMENT_DIR/ansible"
|
||
|
||
# Colors for output
|
||
RED='\033[0;31m'
|
||
GREEN='\033[0;32m'
|
||
YELLOW='\033[1;33m'
|
||
BLUE='\033[0;34m'
|
||
NC='\033[0m' # No Color
|
||
|
||
# Function to print colored messages
|
||
print_success() {
|
||
echo -e "${GREEN}✅ $1${NC}"
|
||
}
|
||
|
||
print_error() {
|
||
echo -e "${RED}❌ $1${NC}"
|
||
}
|
||
|
||
print_warning() {
|
||
echo -e "${YELLOW}⚠️ $1${NC}"
|
||
}
|
||
|
||
print_info() {
|
||
echo -e "${BLUE}ℹ️ $1${NC}"
|
||
}
|
||
|
||
# Show usage
|
||
usage() {
|
||
echo "Usage: $0 [version] [options]"
|
||
echo ""
|
||
echo "Arguments:"
|
||
echo " version Backup version to rollback to (e.g., 2025-01-28T15-30-00)"
|
||
echo " If not provided, will rollback to previous version"
|
||
echo ""
|
||
echo "Options:"
|
||
echo " --list List available backup versions"
|
||
echo " --dry-run Run in check mode without making changes"
|
||
echo " --help Show this help message"
|
||
echo ""
|
||
echo "Examples:"
|
||
echo " $0 # Rollback to previous version"
|
||
echo " $0 2025-01-28T15-30-00 # Rollback to specific version"
|
||
echo " $0 --list # List available backups"
|
||
echo " $0 2025-01-28T15-30-00 --dry-run # Test rollback"
|
||
exit 1
|
||
}
|
||
|
||
# Parse arguments
|
||
ROLLBACK_VERSION=""
|
||
LIST_BACKUPS=false
|
||
DRY_RUN=""
|
||
|
||
while [[ $# -gt 0 ]]; do
|
||
case $1 in
|
||
--list)
|
||
LIST_BACKUPS=true
|
||
shift
|
||
;;
|
||
--dry-run)
|
||
DRY_RUN="--check"
|
||
shift
|
||
;;
|
||
--help)
|
||
usage
|
||
;;
|
||
*)
|
||
if [ -z "$ROLLBACK_VERSION" ]; then
|
||
ROLLBACK_VERSION="$1"
|
||
shift
|
||
else
|
||
print_error "Unknown argument: $1"
|
||
usage
|
||
fi
|
||
;;
|
||
esac
|
||
done
|
||
|
||
echo ""
|
||
echo "🔄 Rollback Application Deployment"
|
||
echo "==================================="
|
||
echo ""
|
||
|
||
# Check if running from correct directory
|
||
if [ ! -f "$ANSIBLE_DIR/ansible.cfg" ]; then
|
||
print_error "Error: Must run from deployment/scripts directory"
|
||
exit 1
|
||
fi
|
||
|
||
cd "$ANSIBLE_DIR"
|
||
|
||
SSH_KEY="$HOME/.ssh/production"
|
||
DEPLOY_USER="deploy"
|
||
DEPLOY_HOST="94.16.110.151"
|
||
|
||
# List available backups
|
||
list_backups() {
|
||
print_info "Fetching available backups from production server..."
|
||
echo ""
|
||
|
||
if ! ssh -i "$SSH_KEY" "$DEPLOY_USER@$DEPLOY_HOST" \
|
||
"ls -lt /home/deploy/backups/ 2>/dev/null" | tail -n +2; then
|
||
print_error "Failed to list backups"
|
||
print_info "Make sure backups exist on production server: /home/deploy/backups/"
|
||
exit 1
|
||
fi
|
||
|
||
echo ""
|
||
print_info "To rollback to a specific version, run:"
|
||
echo " $0 <version>"
|
||
echo ""
|
||
print_info "To rollback to previous version, run:"
|
||
echo " $0"
|
||
exit 0
|
||
}
|
||
|
||
# Check Prerequisites
|
||
check_prerequisites() {
|
||
echo "Checking Prerequisites..."
|
||
echo "------------------------"
|
||
|
||
# Check Ansible
|
||
if ! command -v ansible &> /dev/null; then
|
||
print_error "Ansible is not installed"
|
||
exit 1
|
||
fi
|
||
print_success "Ansible installed"
|
||
|
||
# Check vault password
|
||
if [ ! -f "$ANSIBLE_DIR/secrets/.vault_pass" ]; then
|
||
print_error "Vault password file not found"
|
||
exit 1
|
||
fi
|
||
print_success "Vault password file found"
|
||
|
||
# Check playbook
|
||
if [ ! -f "$ANSIBLE_DIR/playbooks/rollback.yml" ]; then
|
||
print_error "Rollback playbook not found"
|
||
exit 1
|
||
fi
|
||
print_success "Rollback playbook found"
|
||
|
||
# Test connection
|
||
print_info "Testing connection to production..."
|
||
if ansible production -m ping > /dev/null 2>&1; then
|
||
print_success "Connection successful"
|
||
else
|
||
print_error "Connection to production failed"
|
||
exit 1
|
||
fi
|
||
|
||
echo ""
|
||
}
|
||
|
||
# Get current deployment info
|
||
get_current_deployment() {
|
||
print_info "Fetching current deployment information..."
|
||
|
||
CURRENT_IMAGE=$(ssh -i "$SSH_KEY" "$DEPLOY_USER@$DEPLOY_HOST" \
|
||
"docker service inspect app_app --format '{{.Spec.TaskTemplate.ContainerSpec.Image}}' 2>/dev/null" || echo "unknown")
|
||
|
||
if [ "$CURRENT_IMAGE" != "unknown" ]; then
|
||
print_info "Current deployment: $CURRENT_IMAGE"
|
||
else
|
||
print_warning "Could not determine current deployment"
|
||
fi
|
||
|
||
echo ""
|
||
}
|
||
|
||
# Main logic
|
||
if [ "$LIST_BACKUPS" = true ]; then
|
||
list_backups
|
||
fi
|
||
|
||
check_prerequisites
|
||
get_current_deployment
|
||
|
||
# Show available backups
|
||
echo "Available Backups"
|
||
echo "----------------"
|
||
ssh -i "$SSH_KEY" "$DEPLOY_USER@$DEPLOY_HOST" \
|
||
"ls -lt /home/deploy/backups/ 2>/dev/null | tail -n +2 | head -10" || {
|
||
print_warning "No backups found on production server"
|
||
echo ""
|
||
print_info "Backups are created automatically during deployments"
|
||
print_info "You need at least one previous deployment to rollback"
|
||
exit 1
|
||
}
|
||
echo ""
|
||
|
||
# Rollback Summary
|
||
echo "Rollback Summary"
|
||
echo "---------------"
|
||
if [ -n "$ROLLBACK_VERSION" ]; then
|
||
echo " Target Version: $ROLLBACK_VERSION"
|
||
echo " Current Image: $CURRENT_IMAGE"
|
||
else
|
||
echo " Target Version: Previous deployment (most recent backup)"
|
||
echo " Current Image: $CURRENT_IMAGE"
|
||
fi
|
||
if [ -n "$DRY_RUN" ]; then
|
||
echo " Mode: DRY RUN (no changes will be made)"
|
||
else
|
||
echo " Mode: PRODUCTION ROLLBACK"
|
||
fi
|
||
echo ""
|
||
|
||
# Confirmation
|
||
if [ -z "$DRY_RUN" ]; then
|
||
print_warning "⚠️ WARNING: This will rollback your production deployment!"
|
||
echo ""
|
||
read -p "Are you sure you want to proceed with rollback? (y/N): " -n 1 -r
|
||
echo
|
||
if [[ ! $REPLY =~ ^[Yy]$ ]]; then
|
||
print_warning "Rollback cancelled"
|
||
exit 0
|
||
fi
|
||
fi
|
||
|
||
echo ""
|
||
|
||
# Build ansible-playbook command
|
||
ANSIBLE_CMD="ansible-playbook $ANSIBLE_DIR/playbooks/rollback.yml"
|
||
ANSIBLE_CMD="$ANSIBLE_CMD --vault-password-file $ANSIBLE_DIR/secrets/.vault_pass"
|
||
|
||
# Add version if specified
|
||
if [ -n "$ROLLBACK_VERSION" ]; then
|
||
ANSIBLE_CMD="$ANSIBLE_CMD -e rollback_to_version=$ROLLBACK_VERSION"
|
||
fi
|
||
|
||
# Add dry-run flag if set
|
||
if [ -n "$DRY_RUN" ]; then
|
||
ANSIBLE_CMD="$ANSIBLE_CMD $DRY_RUN"
|
||
fi
|
||
|
||
# Execute rollback
|
||
print_info "Starting rollback..."
|
||
echo ""
|
||
|
||
if eval "$ANSIBLE_CMD"; then
|
||
echo ""
|
||
if [ -z "$DRY_RUN" ]; then
|
||
print_success "Rollback completed successfully!"
|
||
else
|
||
print_success "Dry run completed successfully!"
|
||
fi
|
||
else
|
||
echo ""
|
||
print_error "Rollback failed!"
|
||
echo ""
|
||
print_info "Check the Ansible output above for error details"
|
||
exit 1
|
||
fi
|
||
|
||
echo ""
|
||
|
||
# Post-rollback checks
|
||
if [ -z "$DRY_RUN" ]; then
|
||
echo "Post-Rollback Checks"
|
||
echo "-------------------"
|
||
|
||
# Check service status
|
||
print_info "Checking service status..."
|
||
ssh -i "$SSH_KEY" "$DEPLOY_USER@$DEPLOY_HOST" "docker service ls --filter name=app_" || true
|
||
echo ""
|
||
|
||
# Get new image
|
||
NEW_IMAGE=$(ssh -i "$SSH_KEY" "$DEPLOY_USER@$DEPLOY_HOST" \
|
||
"docker service inspect app_app --format '{{.Spec.TaskTemplate.ContainerSpec.Image}}' 2>/dev/null" || echo "unknown")
|
||
|
||
if [ "$NEW_IMAGE" != "unknown" ]; then
|
||
print_info "Rolled back to: $NEW_IMAGE"
|
||
fi
|
||
echo ""
|
||
|
||
# Show recent logs
|
||
print_info "Recent application logs:"
|
||
ssh -i "$SSH_KEY" "$DEPLOY_USER@$DEPLOY_HOST" "docker service logs --tail 20 app_app" || true
|
||
echo ""
|
||
|
||
# Summary
|
||
echo "✅ Rollback Complete!"
|
||
echo "===================="
|
||
echo ""
|
||
echo "Rollback Details:"
|
||
echo " From: $CURRENT_IMAGE"
|
||
echo " To: $NEW_IMAGE"
|
||
if [ -n "$ROLLBACK_VERSION" ]; then
|
||
echo " Version: $ROLLBACK_VERSION"
|
||
else
|
||
echo " Version: Previous deployment"
|
||
fi
|
||
echo ""
|
||
echo "Next Steps:"
|
||
echo ""
|
||
echo "1. Monitor application:"
|
||
echo " ssh -i $SSH_KEY $DEPLOY_USER@$DEPLOY_HOST 'docker service logs -f app_app'"
|
||
echo ""
|
||
echo "2. Check service status:"
|
||
echo " ssh -i $SSH_KEY $DEPLOY_USER@$DEPLOY_HOST 'docker service ps app_app'"
|
||
echo ""
|
||
echo "3. Test application:"
|
||
echo " curl https://michaelschiemer.de/health"
|
||
echo ""
|
||
echo "4. If rollback didn't fix the issue, check available backups:"
|
||
echo " $0 --list"
|
||
echo ""
|
||
else
|
||
echo "Dry Run Summary"
|
||
echo "==============="
|
||
echo ""
|
||
echo "This was a dry run. No changes were made to production."
|
||
echo ""
|
||
if [ -n "$ROLLBACK_VERSION" ]; then
|
||
echo "To rollback for real, run:"
|
||
echo " $0 $ROLLBACK_VERSION"
|
||
else
|
||
echo "To rollback for real, run:"
|
||
echo " $0"
|
||
fi
|
||
echo ""
|
||
fi
|