Files
michaelschiemer/deployment/scripts/rollback.sh

331 lines
8.5 KiB
Bash
Executable File
Raw Blame History

This file contains invisible Unicode characters
This file contains invisible Unicode characters that are indistinguishable to humans but may be processed differently by a computer. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
#!/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