diff --git a/update-ubuntu-or-debian-server/README.md b/update-ubuntu-or-debian-server/README.md index 4e6ce6b..493a1d5 100644 --- a/update-ubuntu-or-debian-server/README.md +++ b/update-ubuntu-or-debian-server/README.md @@ -1,4 +1,570 @@ -# Run command +[![License: MIT](https://img.shields.io/badge/License-MIT-yellow.svg)](../LICENSE) +[![Last Commit](https://img.shields.io/github/last-commit/bigbeartechworld/big-bear-scripts)](https://github.com/bigbeartechworld/big-bear-scripts/commits/master) + +# πŸš€ BigBear Ubuntu/Debian Server Update Script v2.0.0 + +## πŸ“‘ Table of Contents + +- [Features](#features) + - [Core Functionality](#core-functionality) + - [Safety & Security](#safety--security) + - [Monitoring & Reporting](#monitoring--reporting) + - [Configuration Management](#configuration-management) +- [Prerequisites](#prerequisites) +- [Quick Start](#quick-start) +- [Command Line Options](#command-line-options) +- [Configuration](#configuration) +- [System Health Checks](#system-health-checks) +- [Security Features](#security-features) +- [Performance & Monitoring](#performance--monitoring) +- [Email Notifications](#email-notifications) +- [Automation & Scheduling](#automation--scheduling) +- [File Locations](#file-locations) +- [Advanced Usage](#advanced-usage) +- [Troubleshooting](#troubleshooting) +- [Contributing](#contributing) +- [License](#license) +- [Support](#support) +- [Version History](#version-history) + +## ⚠️ Security Notice + +**This script requires root/sudo privileges and performs critical system changes.** + +- Review the script before running, especially if downloaded from the internet. +- Only use on trusted systems and environments. +- Ensure you have recent backups before proceeding. +- Use caution when running in unattended or automated modes. + +## πŸ›‘ Disclaimer + +This script is provided β€œas is”, without warranty of any kind, express or implied. Big Bear Enterprises, LLC. and contributors are not liable for any damages or data loss resulting from the use of this script. Use at your own risk. Always review scripts and ensure you have backups before running on production systems. + +--- + +A comprehensive, enterprise-grade system update script for Ubuntu and Debian servers with advanced features, health monitoring, configuration management, and automated notifications. + +## ✨ Features + +### 🎯 Core Functionality + +- **Automated Package Management**: Update package lists, upgrade packages, perform full upgrades +- **Intelligent Cleanup**: Remove unnecessary packages and clean package cache +- **Interactive & Unattended Modes**: Run interactively with prompts or silently in automation +- **Visual Progress**: Beautiful UI with colors, progress bars, and Unicode symbols + +### πŸ›‘οΈ Safety & Security + +- **System Health Checks**: Monitor disk space, system load, memory usage, and running processes +- **Security Update Detection**: Identify and prioritize security updates +- **Package Exclusion**: Configure packages to exclude from updates +- **Backup Creation**: Optional system backup before major operations +- **Retry Logic**: Automatic retry for failed operations with configurable attempts + +### πŸ“Š Monitoring & Reporting + +- **Performance Tracking**: Monitor execution time, network usage, and system resources +- **Detailed Statistics**: Track packages upgraded/removed, disk space freed, security updates +- **Enhanced Logging**: Standard and JSON log formats for integration with monitoring tools +- **Email Notifications**: Automated email reports for unattended operations +- **Comprehensive Summary**: Beautiful terminal summary with all operation results + +### βš™οΈ Configuration Management + +- **Configuration File**: Persistent settings for automation preferences +- **Maintenance Windows**: Schedule updates during specific time periods +- **Parallel Downloads**: Support for apt-fast for faster package downloads +- **Command Line Options**: Full control via command-line arguments + +## πŸ“‹ Prerequisites + +- Ubuntu 18.04+ or Debian 9+ +- Bash 4.0+ +- Root/sudo privileges +- Optional: `bc` for mathematical calculations (auto-installed if missing) +- Optional: `apt-fast` for parallel downloads +- Optional: `mail` or `sendmail` for email notifications + +### Automatic Dependency Installation + +The script automatically detects and offers to install missing dependencies: + +- **bc**: Required for precise load average and memory calculations +- **apt-fast**: Optional for faster parallel package downloads +- **mailutils**: Optional for email notifications + +## πŸš€ Quick Start + +### Basic Usage + +```bash +# Download and run the script +curl -sSL https://raw.githubusercontent.com/bigbeartechworld/big-bear-scripts/master/update-ubuntu-or-debian-server/run.sh | bash +``` + +### Manual Installation + +```bash +# Clone the repository +git clone https://github.com/bigbeartechworld/big-bear-scripts.git +cd big-bear-scripts/update-ubuntu-or-debian-server + +# Make executable and run +chmod +x run.sh +./run.sh +``` + +## πŸ”§ Command Line Options + +```bash +./run.sh [OPTIONS] + +Options: + --unattended Run without user prompts (uses configuration file settings) + --force Force update despite health check warnings + --config Open configuration file editor + --help Show help message and exit +``` + +### Usage Examples + +```bash +# Interactive mode (default) +./run.sh + +# Unattended mode for automation +./run.sh --unattended + +# Force update despite health warnings +./run.sh --force + +# Edit configuration +./run.sh --config + +# Unattended with force override +./run.sh --unattended --force +``` + +## βš™οΈ Configuration + +The script creates a configuration file at `~/.bigbear-update.conf` on first run. + +### Configuration Options + +```bash +# Automatic operation settings +auto_update_package_list=true # Auto-update package lists in unattended mode +auto_upgrade_packages=true # Auto-upgrade packages in unattended mode +auto_full_upgrade=true # Auto-perform full upgrade in unattended mode +auto_remove_unnecessary=true # Auto-remove unnecessary packages in unattended mode +auto_clean_cache=true # Auto-clean package cache in unattended mode + +# Email notifications +enable_email_notifications=false # Enable email notifications +email_address="" # Email address for notifications + +# Package management +exclude_packages="" # Comma-separated list of packages to exclude +parallel_downloads=true # Use apt-fast if available for parallel downloads + +# Safety settings +min_disk_space_percent=20 # Minimum free disk space required (%) +max_load_average=2.0 # Maximum system load average allowed +backup_before_upgrade=false # Create backup before major operations +retry_count=3 # Number of retry attempts for failed operations + +# Security +check_security_updates=true # Check and report security updates + +# Scheduling +maintenance_window_start="02:00" # Start of maintenance window (24-hour format) +maintenance_window_end="04:00" # End of maintenance window (24-hour format) +``` + +### Configuration Management + +```bash +# Edit configuration file +./run.sh --config + +# Manual editing +nano ~/.bigbear-update.conf + +# View current configuration +cat ~/.bigbear-update.conf +``` + +## πŸ“Š System Health Checks + +The script performs comprehensive health checks before starting updates: + +### Health Check Items + +- **Disk Space**: Ensures minimum free space (configurable, default 20%) +- **System Load**: Checks current load average (configurable, default 2.0) +- **Memory Usage**: Monitors memory consumption (warns if >90%) +- **Process Conflicts**: Detects running package managers +- **Maintenance Window**: Validates update timing for unattended mode + +### Health Check Behavior + +- **Interactive Mode**: Prompts user to continue despite warnings +- **Unattended Mode**: Continues with warnings logged, exits on critical issues +- **Force Mode**: Bypasses all health checks (use with caution) + +## πŸ” Security Features + +### Security Update Detection + +- Identifies available security updates +- Prioritizes security patches in reporting +- Integrates with `unattended-upgrades` if available + +### Package Management Security + +- **Package Exclusion**: Prevent specific packages from being updated +- **Hold Packages**: Automatically hold excluded packages +- **Backup Integration**: Optional system backup before major changes + +### Audit Trail + +- **Comprehensive Logging**: All operations logged with timestamps +- **JSON Logging**: Machine-readable logs for monitoring integration +- **Email Notifications**: Automated reporting for unattended operations + +## πŸ“ˆ Performance & Monitoring + +### Performance Tracking + +- **Execution Time**: Total script runtime and per-step timing +- **Resource Monitoring**: Memory and network usage tracking +- **Disk Space Analysis**: Before/after disk usage comparison +- **Package Statistics**: Count of upgraded/removed packages + +### Logging System + +- **Standard Logs**: Human-readable logs in `/var/log/bigbear/` +- **JSON Logs**: Structured logs for monitoring tools +- **Email Reports**: Automated summaries for unattended runs + +### Integration Ready + +- **Monitoring Tools**: JSON logs compatible with ELK, Splunk, etc. +- **CRON Integration**: Perfect for scheduled automated updates +- **CI/CD Pipeline**: Suitable for infrastructure automation + +## πŸ“§ Email Notifications + +Configure email notifications for unattended operations: + +### Setup Email Notifications + +1. **Install mail client**: + + ```bash + # Ubuntu/Debian + sudo apt update && sudo apt install mailutils + ``` + +2. **Configure email in script**: + + ```bash + ./run.sh --config + # Set enable_email_notifications=true + # Set email_address="your-email@domain.com" + ``` + +3. **Test notification**: + ```bash + # Run a test update to verify email delivery + ./run.sh --unattended + ``` + +### Email Content + +- **Subject**: Includes hostname and operation status +- **Summary**: Package counts, execution time, disk space freed +- **Status**: Success/failure indication with error details +- **Log Location**: Path to detailed log files + +## πŸ—“οΈ Automation & Scheduling + +### CRON Integration + +```bash +# Edit crontab +crontab -e + +# Example: Run daily at 2 AM +0 2 * * * /path/to/big-bear-scripts/update-ubuntu-or-debian-server/run.sh --unattended + +# Example: Run weekly on Sunday at 3 AM +0 3 * * 0 /path/to/big-bear-scripts/update-ubuntu-or-debian-server/run.sh --unattended + +# Example: Run with email on completion +0 2 * * * /path/to/big-bear-scripts/update-ubuntu-or-debian-server/run.sh --unattended 2>&1 | mail -s "Update Report" admin@domain.com +``` + +### Systemd Timer (Alternative to CRON) + +Create systemd service and timer files: + +```bash +# Create service file +sudo nano /etc/systemd/system/bigbear-update.service +``` + +```ini +[Unit] +Description=BigBear System Update +After=network.target + +[Service] +Type=oneshot +ExecStart=/path/to/big-bear-scripts/update-ubuntu-or-debian-server/run.sh --unattended +User=root +StandardOutput=journal +StandardError=journal +``` + +```bash +# Create timer file +sudo nano /etc/systemd/system/bigbear-update.timer +``` + +```ini +[Unit] +Description=Run BigBear System Update Daily +Requires=bigbear-update.service + +[Timer] +OnCalendar=daily +RandomizedDelaySec=30m +Persistent=true + +[Install] +WantedBy=timers.target +``` + +```bash +# Enable and start timer +sudo systemctl enable bigbear-update.timer +sudo systemctl start bigbear-update.timer + +# Check status +sudo systemctl status bigbear-update.timer +``` + +## πŸ“ File Locations + +### Configuration & Logs + +``` +~/.bigbear-update.conf # Main configuration file +~/.config/bigbear/ # Configuration directory +/var/log/bigbear/ # Log directory (with fallback to ~/.local/log/bigbear/) +/var/log/bigbear/big-bear-update-ubuntu-server.log # Standard log +/var/log/bigbear/big-bear-update-ubuntu-server.json # JSON log +``` + +### Backup Location + +``` +/var/backups/bigbear-YYYYMMDD-HHMMSS/ # System backups (if enabled) +/tmp/bigbear-backup-location # Backup location tracker +``` + +## πŸ”§ Advanced Usage + +### Custom Package Exclusions + +```bash +# Edit configuration to exclude specific packages +./run.sh --config + +# Add packages to exclude (comma-separated) +exclude_packages="kernel-image,docker-ce,nginx" +``` + +### Backup Integration + +```bash +# Enable backup before upgrades +./run.sh --config + +# Set backup_before_upgrade=true +backup_before_upgrade=true +``` + +### Maintenance Window Scheduling + +```bash +# Configure maintenance window for unattended runs +./run.sh --config + +# Set maintenance window (24-hour format) +maintenance_window_start="02:00" +maintenance_window_end="04:00" +``` + +### Parallel Downloads + +```bash +# Install apt-fast for parallel downloads +sudo add-apt-repository ppa:apt-fast/stable +sudo apt update && sudo apt install apt-fast + +# Enable in configuration +parallel_downloads=true +``` + +## πŸ› Troubleshooting + +### Common Issues + +1. **Log Directory Permission Errors** + + ```bash + # Error: "tee: /root/.local/log/bigbear/...: No such file or directory" + # Solution: The script will automatically create fallback directories + # Or manually create the directory: + mkdir -p ~/.local/log/bigbear + ``` + +2. **Missing bc Command** + + ```bash + # Error: "bc: command not found" + # Solution: The script will offer to install it automatically + # Or install manually: + sudo apt update && sudo apt install bc + ``` + +3. **Permission Denied** + + ```bash + # Ensure script is executable + chmod +x run.sh + + # Run with sudo if needed + sudo ./run.sh + ``` + +4. **Configuration Not Loading** + + ```bash + # Check configuration file exists and is readable + ls -la ~/.bigbear-update.conf + + # Recreate configuration + rm ~/.bigbear-update.conf + ./run.sh # Will create new default config + ``` + +5. **Email Notifications Not Working** + + ```bash + # Test mail system + echo "Test" | mail -s "Test Subject" your-email@domain.com + + # Install mail client if missing + sudo apt install mailutils + ``` + +6. **Health Check Failures** + + ```bash + # Check disk space + df -h / + + # Check system load + uptime + + # Check memory usage + free -h + + # Force update despite health issues + ./run.sh --force + ``` + +### Debug Mode + +```bash +# Run with verbose output +bash -x ./run.sh + +# Check log files for details +tail -f /var/log/bigbear/big-bear-update-ubuntu-server.log +``` + +### Log Analysis + +```bash +# View recent operations +tail -n 50 /var/log/bigbear/big-bear-update-ubuntu-server.log + +# Search for errors +grep -i error /var/log/bigbear/big-bear-update-ubuntu-server.log + +# View JSON logs for monitoring +jq '.' /var/log/bigbear/big-bear-update-ubuntu-server.json +``` + +## 🀝 Contributing + +We welcome contributions! + +### Development Setup + +```bash +# Clone repository +git clone https://github.com/bigbeartechworld/big-bear-scripts.git +cd big-bear-scripts/update-ubuntu-or-debian-server + +# Create test environment +vagrant up # If using Vagrant + +# Test changes +./run.sh --help +``` + +## πŸ“„ License + +This project is licensed under the MIT License - see the [LICENSE](../LICENSE) file for details. + +## 🌟 Support + +- **Documentation**: This README and inline help (`./run.sh --help`) +- **Issues**: [Issues](https://community.bigbeartechworld.com/c/big-bear-scripts/9) +- **Discussions**: [BigBearTechWorld Community](https://community.bigbeartechworld.com) +- **Support the Project**: [Ko-fi](https://ko-fi.com/bigbeartechworld) + +## πŸ”„ Version History + +### v2.0.0 (Current) + +- ✨ Complete rewrite with enterprise features +- πŸ›‘οΈ System health monitoring +- βš™οΈ Configuration file management +- πŸ“§ Email notifications +- πŸ“Š Performance tracking and statistics +- πŸ” Enhanced security features +- 🎯 Backup and recovery options +- πŸš€ Parallel download support +- πŸ“‹ Comprehensive logging + +### v1.0.0 + +- 🎯 Basic update functionality +- πŸ’» Interactive and unattended modes +- 🎨 Enhanced visual interface +- πŸ“ Basic logging + +--- + +**Made with ❀️ by [BigBearTechWorld](https://ko-fi.com/bigbeartechworld)** + +_This script is part of the BigBear Scripts collection - making server management easier, one script at a time!_ ```bash bash -c "$(wget -qLO - https://raw.githubusercontent.com/bigbeartechworld/big-bear-scripts/master/update-ubuntu-or-debian-server/run.sh)" diff --git a/update-ubuntu-or-debian-server/run.sh b/update-ubuntu-or-debian-server/run.sh index 83f3058..d0fb6ad 100644 --- a/update-ubuntu-or-debian-server/run.sh +++ b/update-ubuntu-or-debian-server/run.sh @@ -2,68 +2,637 @@ # Define a message for branding purposes MESSAGE="Made by BigBearTechWorld" +VERSION="2.0.0" +SCRIPT_NAME="BigBear Ubuntu/Debian Server Update Script" + +# Configuration file path +CONFIG_FILE="$HOME/.bigbear-update.conf" +CONFIG_DIR="$HOME/.config/bigbear" # Set up logging -LOG_FILE="/var/log/big-bear-update-ubuntu-server.log" +LOG_DIR="/var/log/bigbear" +LOG_FILE="$LOG_DIR/big-bear-update-ubuntu-server.log" +JSON_LOG_FILE="$LOG_DIR/big-bear-update-ubuntu-server.json" -# Function for logging -log() { - echo "$(date '+%Y-%m-%d %H:%M:%S') - $1" | tee -a "$LOG_FILE" -} - -# Function to print a decorative line -print_decorative_line() { - printf "%s\n" "------------------------------------------------------" -} - -# Print the introduction message with decorations -echo -print_decorative_line -echo "Update Ubuntu/Debian Server Script" -print_decorative_line -echo -echo "$MESSAGE" -echo -print_decorative_line -echo -echo "If this is useful, please consider supporting my work at: https://ko-fi.com/bigbeartechworld" -echo -print_decorative_line - -# Check if --unattended flag is passed -if [[ "$1" == "--unattended" ]]; then - unattended=true -else - unattended=false +# Create log directory if it doesn't exist +if ! sudo mkdir -p "$LOG_DIR" 2>/dev/null; then + # Fallback to user's local directory + LOG_DIR="$HOME/.local/log/bigbear" + mkdir -p "$LOG_DIR" + LOG_FILE="$LOG_DIR/big-bear-update-ubuntu-server.log" + JSON_LOG_FILE="$LOG_DIR/big-bear-update-ubuntu-server.json" fi -# Function to prompt the user +# Color definitions for better visual appeal +RED='\033[0;31m' +GREEN='\033[0;32m' +YELLOW='\033[1;33m' +BLUE='\033[0;34m' +PURPLE='\033[0;35m' +CYAN='\033[0;36m' +WHITE='\033[1;37m' +BOLD='\033[1m' +NC='\033[0m' # No Color + +# Unicode symbols for better visual appeal +CHECK_MARK="βœ“" +CROSS_MARK="βœ—" +INFO_SYMBOL="β„Ή" +WARNING_SYMBOL="⚠" +ROCKET="πŸš€" +GEAR="βš™" +CLEAN="🧹" +SHIELD="πŸ›‘" +CLOCK="⏰" +CHART="πŸ“Š" +EMAIL="πŸ“§" +SAVE="πŸ’Ύ" + +# Performance tracking variables +START_TIME=$(date +%s) +STEP_START_TIME=$START_TIME +NETWORK_USAGE_START=0 +MEMORY_USAGE_START=0 + +# Statistics tracking +PACKAGES_UPGRADED=0 +PACKAGES_REMOVED=0 +SECURITY_UPDATES=0 +TOTAL_DOWNLOAD_SIZE=0 +FAILED_OPERATIONS=() + +# Default configuration +DEFAULT_CONFIG='# BigBear Update Script Configuration +# Set to true/false to enable/disable features by default +auto_update_package_list=true +auto_upgrade_packages=true +auto_full_upgrade=true +auto_remove_unnecessary=true +auto_clean_cache=true +enable_email_notifications=false +email_address="" +exclude_packages="" +min_disk_space_percent=20 +max_load_average=2.0 +backup_before_upgrade=false +retry_count=3 +parallel_downloads=true +check_security_updates=true +maintenance_window_start="02:00" +maintenance_window_end="04:00" +' + +# Helper: Strip ANSI color codes for length calculation +strip_ansi() { + echo -e "$1" | sed -r 's/\x1B\[[0-9;]*[mK]//g' +} + +# Helper: Count emoji as double-width (for πŸš€ only) +visible_length() { + local text="$(strip_ansi "$1")" + # Each πŸš€ is 2 columns, but Bash counts as 1, so add 1 extra per emoji + local emoji_count=$(grep -o "πŸš€" <<< "$text" | wc -l) + local base_len=${#text} + echo $((base_len + emoji_count)) +} + +# Print a centered line in a box of width 78 +center_box_line() { + local content="$1" + local color="$2" + local width=78 + local len=$(visible_length "$content") + local pad=$(( (width - len) / 2 )) + local extra=$(( width - len - pad )) + printf "${BLUE}β•‘${color}%*s%s%*s${BLUE}β•‘${NC}\n" $pad "" "$content" $extra "" +} + +# Function to print a decorative header +print_header() { + clear + local box_width=78 + echo -e "${BLUE}β•”$(printf '═%.0s' $(seq 1 $box_width))β•—${NC}" + center_box_line "UPDATE UBUNTU/DEBIAN SERVER" "${WHITE}${BOLD}" + center_box_line "Version $VERSION" "${WHITE}${BOLD}" + echo -e "${BLUE}β• $(printf '═%.0s' $(seq 1 $box_width))β•£${NC}" + center_box_line "$MESSAGE" "${CYAN}${BOLD}" + echo -e "${BLUE}β•š$(printf '═%.0s' $(seq 1 $box_width))╝${NC}" + echo + echo -e "${YELLOW}${BOLD}πŸ’– If this script helps you, please consider supporting my work:${NC}" + echo -e "${GREEN}${BOLD} β˜• Ko-fi: https://ko-fi.com/bigbeartechworld${NC}" + echo -e "${CYAN}${BOLD} 🌟 Star the repo: https://github.com/bigbeartechworld/big-bear-scripts${NC}" + echo + echo -e "${BLUE}────────────────────────────────────────────────────────────────────────────────${NC}" + echo +} + +# Function to log messages to file +log() { + local message="$1" + local level="${2:-INFO}" + local timestamp + timestamp=$(date +"%Y-%m-%d %H:%M:%S") + echo "[$timestamp] [$level] $message" >> "$LOG_FILE" + # Optionally, also log to JSON + if command -v jq >/dev/null 2>&1; then + jq -cn --arg timestamp "$timestamp" --arg level "$level" --arg message "$message" '{timestamp: $timestamp, level: $level, message: $message}' >> "$JSON_LOG_FILE" + else + # Manual escaping: replace backslashes, then double quotes, then remove newlines + local safe_message + safe_message=$(echo "$message" | sed 's/\\/\\\\/g; s/\"/\\\"/g; s/\r//g; s/\n/ /g') + echo "{\"timestamp\": \"$timestamp\", \"level\": \"$level\", \"message\": \"$safe_message\"}" >> "$JSON_LOG_FILE" + fi +} + +# Function to check and install missing dependencies +check_dependencies() { + local missing_deps=() + + # Check for bc (calculator) + if ! command -v bc >/dev/null 2>&1; then + missing_deps+=("bc") + fi + # Check for jq (JSON processor) + if ! command -v jq >/dev/null 2>&1; then + missing_deps+=("jq") + fi + + if [ ${#missing_deps[@]} -gt 0 ]; then + print_warning "Missing dependencies detected: ${missing_deps[*]}" + if [ "$unattended" = false ]; then + if prompt_user "Install missing dependencies?"; then + print_info "Installing missing dependencies..." + sudo apt update -qq >/dev/null 2>&1 + for dep in "${missing_deps[@]}"; do + sudo apt install -y "$dep" >/dev/null 2>&1 + if command -v "$dep" >/dev/null 2>&1; then + print_success "Installed $dep" + else + print_warning "Failed to install $dep" + fi + done + else + print_warning "Continuing without optional dependencies" + fi + else + print_info "Auto-installing missing dependencies in unattended mode..." + sudo apt update -qq >/dev/null 2>&1 + for dep in "${missing_deps[@]}"; do + sudo apt install -y "$dep" >/dev/null 2>&1 + log "Attempted to install dependency: $dep" + done + fi + fi +} + +# Function to load configuration +load_config() { + if [ ! -f "$CONFIG_FILE" ]; then + mkdir -p "$CONFIG_DIR" 2>/dev/null + echo "$DEFAULT_CONFIG" > "$CONFIG_FILE" + log "Created default configuration file at $CONFIG_FILE" + fi + + # Safely parse configuration file without executing arbitrary commands + while IFS= read -r line; do + # Skip empty lines and comments + [[ -z "$line" || "$line" =~ ^[[:space:]]*# ]] && continue + + # Only process lines that match key=value format (with optional spaces) + if [[ "$line" =~ ^[[:space:]]*([a-zA-Z_][a-zA-Z0-9_]*)[[:space:]]*=[[:space:]]*(.*)$ ]]; then + local key="${BASH_REMATCH[1]}" + local value="${BASH_REMATCH[2]}" + + # Remove surrounding quotes if present + if [[ "$value" =~ ^\"(.*)\"$ ]] || [[ "$value" =~ ^\'(.*)\'$ ]]; then + value="${BASH_REMATCH[1]}" + fi + + # Only allow known configuration variables for additional security + case "$key" in + auto_update_package_list|auto_upgrade_packages|auto_full_upgrade|auto_remove_unnecessary|auto_clean_cache|\ + enable_email_notifications|email_address|exclude_packages|min_disk_space_percent|max_load_average|\ + backup_before_upgrade|retry_count|parallel_downloads|check_security_updates|\ + maintenance_window_start|maintenance_window_end) + # Set the variable safely using printf -v + printf -v "$key" '%s' "$value" + export "$key" + ;; + *) + log "Ignoring unknown configuration variable: $key" "WARNING" + ;; + esac + fi + done < "$CONFIG_FILE" + + log "Configuration loaded from $CONFIG_FILE" +} + +# Function to check system health +check_system_health() { + local health_issues=() + + # Check disk space + local disk_usage=$(df / | awk 'NR==2 {print $5}' | sed 's/%//') + local free_space=$((100 - disk_usage)) + + if [ "$free_space" -lt "${min_disk_space_percent:-20}" ]; then + health_issues+=("Low disk space: ${free_space}% free (minimum: ${min_disk_space_percent:-20}%)") + fi + + # Check system load + local load_avg=$(uptime | awk -F'load average:' '{print $2}' | awk '{print $1}' | sed 's/,//') + if command -v bc >/dev/null 2>&1; then + if (( $(echo "$load_avg > ${max_load_average:-2.0}" | bc -l) )); then + health_issues+=("High system load: $load_avg (maximum: ${max_load_average:-2.0})") + fi + else + # Fallback without bc - simple integer comparison + local load_int=$(echo "$load_avg" | cut -d'.' -f1) + local max_load_int=$(echo "${max_load_average:-2.0}" | cut -d'.' -f1) + if [ "$load_int" -gt "$max_load_int" ]; then + health_issues+=("High system load: $load_avg (maximum: ${max_load_average:-2.0})") + fi + fi + + # Check memory usage + local mem_usage=$(free | grep Mem | awk '{printf "%.1f", $3/$2 * 100.0}') + if command -v bc >/dev/null 2>&1; then + if (( $(echo "$mem_usage > 90.0" | bc -l) )); then + health_issues+=("High memory usage: ${mem_usage}%") + fi + else + # Fallback without bc - simple integer comparison + local mem_int=$(echo "$mem_usage" | cut -d'.' -f1) + if [ "$mem_int" -gt 90 ]; then + health_issues+=("High memory usage: ${mem_usage}%") + fi + fi + + # Check if system is currently updating + if pgrep -x "apt" > /dev/null || pgrep -x "apt-get" > /dev/null || pgrep -x "dpkg" > /dev/null; then + health_issues+=("Another package manager is currently running") + fi + + if [ ${#health_issues[@]} -gt 0 ]; then + print_warning "System health issues detected:" + for issue in "${health_issues[@]}"; do + echo -e " ${RED}β€’ $issue${NC}" + done + + if [ "$unattended" = false ]; then + if ! prompt_user "Continue despite health issues?"; then + print_error "Aborting due to system health concerns" + exit 1 + fi + else + log "Continuing in unattended mode despite health issues" "WARNING" + fi + else + print_success "System health check passed" + fi +} + +# Function to create backup +create_backup() { + if [ "${backup_before_upgrade:-false}" = "true" ]; then + local backup_dir="/var/backups/bigbear-$(date +%Y%m%d-%H%M%S)" + print_info "Creating system backup..." + + sudo mkdir -p "$backup_dir" + sudo sh -c "dpkg --get-selections > \"$backup_dir/package-selections.txt\"" + sudo cp -r /etc/apt "$backup_dir/" + + print_success "Backup created at $backup_dir" + log "System backup created at $backup_dir" + echo "$backup_dir" > "/tmp/bigbear-backup-location" + fi +} + +# Function to send email notification +send_email_notification() { + if [ "${enable_email_notifications:-false}" = "true" ] && [ -n "${email_address:-}" ]; then + local subject="$1" + local body="$2" + + if command -v mail >/dev/null 2>&1; then + echo "$body" | mail -s "$subject" "$email_address" + log "Email notification sent to $email_address" + elif command -v sendmail >/dev/null 2>&1; then + { + echo "To: $email_address" + echo "Subject: $subject" + echo "" + echo "$body" + } | sendmail "$email_address" + log "Email notification sent to $email_address" + else + log "Email notification failed: no mail client available" "WARNING" + fi + fi +} + +# Function to get network usage +get_network_usage() { + local bytes=$(cat /proc/net/dev | grep -E "(eth0|wlan0|enp|wlp)" | head -1 | awk '{print $2 + $10}' 2>/dev/null) + # Return 0 if no interface found or empty result + if [ -z "$bytes" ]; then + echo "0" + return + fi + # Convert scientific notation to integer if necessary + if [[ "$bytes" == *"e+"* ]]; then + bytes=$(printf "%.0f" "$bytes") + fi + echo "$bytes" +} + +# Function to get memory usage +get_memory_usage() { + free -m | awk 'NR==2{printf "%.1f", $3*100/$2}' +} + +# Function to check for security updates +check_security_updates() { + if [ "${check_security_updates:-true}" = "true" ]; then + if command -v unattended-upgrades >/dev/null 2>&1; then + local security_count=$(apt list --upgradable 2>/dev/null | grep -c "security") + SECURITY_UPDATES=$security_count + if [ "$security_count" -gt 0 ]; then + print_warning "$security_count security updates available" + else + print_success "No security updates pending" + fi + fi + fi +} + +# Function to retry operations +retry_operation() { + local max_attempts="${retry_count:-3}" + local attempt=1 + local -a cmd=("$@") + + while [ $attempt -le $max_attempts ]; do + if "${cmd[@]}"; then + return 0 + else + print_warning "Attempt $attempt/$max_attempts failed, retrying in 5 seconds..." + sleep 5 + ((attempt++)) + fi + done + + FAILED_OPERATIONS+=("${cmd[*]}") + return 1 +} + +# Function to check if in maintenance window +in_maintenance_window() { + local current_time=$(date +%H:%M) + local start_time="${maintenance_window_start:-02:00}" + local end_time="${maintenance_window_end:-04:00}" + + # Convert times to minutes since midnight + local current_minutes=$(echo "$current_time" | awk -F: '{print $1 * 60 + $2}') + local start_minutes=$(echo "$start_time" | awk -F: '{print $1 * 60 + $2}') + local end_minutes=$(echo "$end_time" | awk -F: '{print $1 * 60 + $2}') + + # Handle maintenance window that crosses midnight + if [ $start_minutes -le $end_minutes ]; then + # Normal case: start <= end (e.g., 02:00 to 04:00) + if [ $current_minutes -ge $start_minutes ] && [ $current_minutes -le $end_minutes ]; then + return 0 + fi + else + # Wrap-around case: start > end (e.g., 22:00 to 02:00) + if [ $current_minutes -ge $start_minutes ] || [ $current_minutes -le $end_minutes ]; then + return 0 + fi + fi + + return 1 +} + +# Function to estimate time remaining +estimate_time_remaining() { + local current_step="$1" + local total_steps=5 + local current_step_num=0 + + case "$current_step" in + "update") current_step_num=1 ;; + "upgrade") current_step_num=2 ;; + "full-upgrade") current_step_num=3 ;; + "autoremove") current_step_num=4 ;; + "clean") current_step_num=5 ;; + esac + + local elapsed=$(($(date +%s) - START_TIME)) + local estimated_total=$((elapsed * total_steps / current_step_num)) + local remaining=$((estimated_total - elapsed)) + + if [ $remaining -gt 0 ]; then + print_info "Estimated time remaining: $((remaining / 60))m $((remaining % 60))s" + fi +} + +# Function to print section headers +print_section() { + echo + echo -e "${PURPLE}${BOLD}β–Ό $1${NC}" + echo -e "${BLUE}────────────────────────────────────────────────────────────────────────────────${NC}" + STEP_START_TIME=$(date +%s) +} + +# Function to print success message +print_success() { + echo -e "${GREEN}${BOLD}${CHECK_MARK} $1${NC}" +} + +# Function to print error message +print_error() { + echo -e "${RED}${BOLD}${CROSS_MARK} $1${NC}" +} + +# Function to print warning message +print_warning() { + echo -e "${YELLOW}${BOLD}${WARNING_SYMBOL} $1${NC}" +} + +# Function to print info message +print_info() { + echo -e "${CYAN}${BOLD}${INFO_SYMBOL} $1${NC}" +} + +# Enhanced progress bar function +show_progress_bar() { + local duration=$1 + local task=$2 + local progress=0 + + # Calculate sleep step with floating-point precision and minimum value + local sleep_step + if command -v bc >/dev/null 2>&1; then + sleep_step=$(echo "scale=3; $duration / 100" | bc) + # Ensure minimum sleep interval of 0.05 seconds + if (( $(echo "$sleep_step < 0.05" | bc -l) )); then + sleep_step="0.05" + fi + else + # Fallback using awk if bc is not available + sleep_step=$(awk "BEGIN {step = $duration / 100; print (step < 0.05) ? 0.05 : step}") + fi + + echo -ne "${CYAN}${GEAR} $task " + + while [ $progress -le 100 ]; do + local filled=$((progress / 5)) + local empty=$((20 - filled)) + + printf "\r${CYAN}${GEAR} $task [" + printf "%*s" $filled | tr ' ' 'β–ˆ' + printf "%*s" $empty | tr ' ' 'β–‘' + printf "] %d%%" $progress + + sleep "$sleep_step" + progress=$((progress + 1)) + done + + echo -e " ${GREEN}${CHECK_MARK}${NC}" +} + +# Function to show simple progress +show_progress() { + local duration=$1 + local task=$2 + echo -ne "${CYAN}${GEAR} $task" + for ((i=0; i<=duration; i++)); do + echo -ne "." + sleep 0.1 + done + echo -e " ${GREEN}${CHECK_MARK}${NC}" +} + +# Print the introduction +print_header + +# Load configuration +load_config + +# Parse command line arguments +unattended=false +force_update=false +config_only=false + +while [[ $# -gt 0 ]]; do + case $1 in + --unattended) + unattended=true + shift + ;; + --force) + force_update=true + shift + ;; + --config) + config_only=true + shift + ;; + --help) + echo "Usage: $0 [OPTIONS]" + echo "Options:" + echo " --unattended Run without prompts" + echo " --force Force update despite health issues" + echo " --config Edit configuration file" + echo " --help Show this help message" + exit 0 + ;; + *) + print_error "Unknown option: $1" + exit 1 + ;; + esac +done + +# Configuration mode +if [ "$config_only" = true ]; then + print_section "Configuration Editor" + if command -v nano >/dev/null 2>&1; then + nano "$CONFIG_FILE" + elif command -v vim >/dev/null 2>&1; then + vim "$CONFIG_FILE" + else + print_error "No text editor available. Please edit $CONFIG_FILE manually." + fi + exit 0 +fi + +# Mode detection +if [ "$unattended" = true ]; then + print_info "Running in unattended mode..." +else + print_info "Running in interactive mode..." +fi + +# Check maintenance window for unattended mode +if [ "$unattended" = true ] && ! in_maintenance_window && [ "$force_update" = false ]; then + print_warning "Outside maintenance window (${maintenance_window_start:-02:00}-${maintenance_window_end:-04:00})" + print_info "Use --force to override maintenance window check" + exit 0 +fi + +# Function to prompt the user with enhanced visuals prompt_user() { + local question="$1" + local config_var="$2" + if [ "$unattended" = true ]; then - return 0 # Automatically proceed in unattended mode + # Check configuration for auto-answers + if [ -n "$config_var" ]; then + local config_value="${!config_var}" + if [ "$config_value" = "true" ]; then + print_info "Auto-proceeding: $question" + return 0 + elif [ "$config_value" = "false" ]; then + print_info "Auto-skipping: $question" + return 1 + fi + fi + return 0 # Default to proceed in unattended mode fi - echo "$1 (y/n): " + echo + echo -e "${YELLOW}${BOLD}❓ $question${NC}" + echo -ne "${WHITE}${BOLD} Enter your choice (${GREEN}y${WHITE}/${RED}n${WHITE}): ${NC}" read -r response if [[ "$response" =~ ^[Yy]$ ]]; then + echo -e "${GREEN} ${CHECK_MARK} Proceeding...${NC}" return 0 # Proceed else + echo -e "${YELLOW} ${WARNING_SYMBOL} Skipping...${NC}" return 1 # Skip fi } # Check OS compatibility +print_section "System Compatibility Check" if [ -f /etc/os-release ]; then . /etc/os-release if [[ "$ID" != "ubuntu" && "$ID" != "debian" ]]; then - log "This script is intended for Ubuntu or Debian. Detected OS: $ID" + print_error "This script is intended for Ubuntu or Debian. Detected OS: $ID" exit 1 + else + print_success "Compatible OS detected: $PRETTY_NAME" + log "OS compatibility confirmed: $PRETTY_NAME" fi else - log "Unable to determine OS. This script is intended for Ubuntu or Debian." + print_error "Unable to determine OS. This script is intended for Ubuntu or Debian." exit 1 fi +# Note: Dependencies will be checked after prompt_user function is defined + # Function to check disk space check_disk_space() { df -h / | awk 'NR==2 {print $5}' | sed 's/%//' @@ -71,124 +640,346 @@ check_disk_space() { # Function to check and hold back problematic packages check_problematic_packages() { - problematic_packages=("package1" "package2") # Add known problematic packages here + local problematic_packages=() + + # Add packages from exclude list + if [ -n "${exclude_packages:-}" ]; then + IFS=',' read -ra ADDR <<< "$exclude_packages" + for package in "${ADDR[@]}"; do + problematic_packages+=("$(echo $package | xargs)") + done + fi + for package in "${problematic_packages[@]}"; do if dpkg -l | grep -q "^ii $package "; then - log "Holding back potentially problematic package: $package" + print_warning "Holding back excluded package: $package" sudo apt-mark hold "$package" + log "Package held: $package" fi done } -# Explain the script's function if not running in unattended mode -if [ "$unattended" = false ]; then - log "This script will help you update and maintain your Ubuntu/Debian server." - log "You will be prompted to confirm each step before proceeding." - log "To run this script in unattended mode without prompts, run it with the --unattended option." +# Check and install dependencies +print_section "Dependency Check" +check_dependencies + +# System health check +if [ "$force_update" = false ]; then + print_section "System Health Check" + check_system_health +else + print_warning "Skipping health check due to --force flag" fi -initial_space=$(check_disk_space) -log "Initial disk space used: $initial_space%" +# Initialize performance tracking +NETWORK_USAGE_START=$(get_network_usage) +MEMORY_USAGE_START=$(get_memory_usage) +# Explain the script's function if not running in unattended mode +if [ "$unattended" = false ]; then + print_section "Script Information" + print_info "This script will help you update and maintain your Ubuntu/Debian server." + print_info "You will be prompted to confirm each step before proceeding." + print_info "Configuration file: $CONFIG_FILE" + print_info "To run in unattended mode, use the --unattended option." +fi + +print_section "Disk Space Analysis" +initial_space=$(check_disk_space) +print_info "Initial disk space used: ${BOLD}$initial_space%${NC}" + +# Check for apt-fast for parallel downloads +if command -v apt-fast >/dev/null 2>&1 && [ "${parallel_downloads:-true}" = "true" ]; then + APT_CMD="apt-fast" + print_info "Using apt-fast for parallel downloads" +else + APT_CMD="apt" +fi + +# Security updates check +check_security_updates + +# Create backup if enabled +create_backup + +# Initialize tracking variables updated_package_list=false upgraded_packages=false full_upgrade_done=false removed_unnecessary=false cache_cleaned=false +# Check and hold excluded packages before upgrades +print_section "Package Exclusion Check" +check_problematic_packages +print_success "Package exclusion check completed" + # Step 1: Update the package list -if prompt_user "Do you want to update the package list?"; then - log "Updating package list..." - if ! sudo apt update; then - log "ERROR: Failed to update package list" +print_section "Step 1: Package List Update" +estimate_time_remaining "update" +if prompt_user "Do you want to update the package list?" "auto_update_package_list"; then + if retry_operation sudo "$APT_CMD" update >/dev/null 2>&1; then + show_progress_bar 10 "Updating package list" + print_success "Package list updated successfully" + updated_package_list=true + log "Package list updated successfully" + else + print_error "Failed to update package list after ${retry_count:-3} attempts" exit 1 fi - log "Package list updated successfully" - updated_package_list=true else + print_warning "Skipping package list update" log "Skipping package list update." fi # Step 2: Upgrade installed packages -if prompt_user "Do you want to upgrade installed packages?"; then - log "Upgrading installed packages..." - if ! sudo apt upgrade -y; then - log "ERROR: Failed to upgrade packages" +print_section "Step 2: Package Upgrade" +estimate_time_remaining "upgrade" +if prompt_user "Do you want to upgrade installed packages?" "auto_upgrade_packages"; then + print_info "Analyzing packages to upgrade..." + + # Get package count before upgrade + packages_before=$(dpkg -l | grep -c "^ii") + + print_info "Upgrading installed packages (this may take a while)..." + if retry_operation sudo "$APT_CMD" upgrade -y; then + packages_after=$(dpkg -l | grep -c "^ii") + PACKAGES_UPGRADED=$((packages_after - packages_before)) + print_success "Installed packages upgraded successfully" + print_info "Packages upgraded: $PACKAGES_UPGRADED" + upgraded_packages=true + log "Installed packages upgraded successfully. Count: $PACKAGES_UPGRADED" + else + print_error "Failed to upgrade packages after ${retry_count:-3} attempts" exit 1 fi - log "Installed packages upgraded successfully" - upgraded_packages=true else + print_warning "Skipping installed package upgrade" log "Skipping installed package upgrade." fi # Step 3: Perform full upgrade -if prompt_user "Do you want to perform a full upgrade?"; then - log "Performing a full upgrade..." - if ! sudo apt full-upgrade -y; then - log "ERROR: Failed to perform full upgrade" +print_section "Step 3: Full System Upgrade" +estimate_time_remaining "full-upgrade" +if prompt_user "Do you want to perform a full upgrade?" "auto_full_upgrade"; then + print_info "Performing a full upgrade (this may take a while)..." + if retry_operation sudo "$APT_CMD" full-upgrade -y; then + print_success "Full upgrade completed successfully" + full_upgrade_done=true + log "Full upgrade completed successfully" + else + print_error "Failed to perform full upgrade after ${retry_count:-3} attempts" exit 1 fi - log "Full upgrade completed successfully" - full_upgrade_done=true else + print_warning "Skipping full upgrade" log "Skipping full upgrade." fi # Step 4: Remove unnecessary packages -if prompt_user "Do you want to remove unnecessary packages?"; then - log "Removing unnecessary packages..." - if ! sudo apt autoremove -y; then - log "ERROR: Failed to remove unnecessary packages" +print_section "Step 4: Cleanup Unnecessary Packages" +estimate_time_remaining "autoremove" +if prompt_user "Do you want to remove unnecessary packages?" "auto_remove_unnecessary"; then + # Count packages before removal + packages_before_removal=$(dpkg -l | grep -c "^ii") + + if retry_operation sudo apt autoremove -y >/dev/null 2>&1; then + show_progress_bar 3 "Removing unnecessary packages" + packages_after_removal=$(dpkg -l | grep -c "^ii") + PACKAGES_REMOVED=$((packages_before_removal - packages_after_removal)) + print_success "Unnecessary packages removed successfully" + print_info "Packages removed: $PACKAGES_REMOVED" + removed_unnecessary=true + log "Unnecessary packages removed successfully. Count: $PACKAGES_REMOVED" + else + print_error "Failed to remove unnecessary packages after ${retry_count:-3} attempts" exit 1 fi - log "Unnecessary packages removed successfully" - removed_unnecessary=true else + print_warning "Skipping unnecessary package removal" log "Skipping unnecessary package removal." fi # Step 5: Clean up package files -if prompt_user "Do you want to clean up cached package files?"; then - log "Cleaning up cached package files..." - if ! sudo apt clean; then - log "ERROR: Failed to clean cached package files" +print_section "Step 5: Cache Cleanup" +estimate_time_remaining "clean" +if prompt_user "Do you want to clean up cached package files?" "auto_clean_cache"; then + # Get cache size before cleaning + cache_size_before=$(du -sm /var/cache/apt 2>/dev/null | cut -f1 || echo "0") + + if retry_operation sudo apt clean >/dev/null 2>&1; then + show_progress 8 "Cleaning cached package files" + cache_size_after=$(du -sm /var/cache/apt 2>/dev/null | cut -f1 || echo "0") + cache_freed=$((cache_size_before - cache_size_after)) + print_success "Cached package files cleaned successfully" + print_info "Cache space freed: ${cache_freed}MB" + cache_cleaned=true + log "Cached package files cleaned successfully. Space freed: ${cache_freed}MB" + else + print_error "Failed to clean cached package files after ${retry_count:-3} attempts" exit 1 fi - log "Cached package files cleaned successfully" - cache_cleaned=true else + print_warning "Skipping cache cleanup" log "Skipping cache cleanup." fi -# Check problematic packages -check_problematic_packages +# Performance metrics +END_TIME=$(date +%s) +TOTAL_TIME=$((END_TIME - START_TIME)) +NETWORK_USAGE_END=$(get_network_usage) +MEMORY_USAGE_END=$(get_memory_usage) +NETWORK_USED=$((NETWORK_USAGE_END - NETWORK_USAGE_START)) -# Print summary +# Print enhanced summary print_summary() { + final_space=$(check_disk_space) + space_freed=$((initial_space - final_space)) + + print_section "Update Summary Report" + echo -e "${BLUE}╔══════════════════════════════════════════════════════════════════════════════╗${NC}" + echo -e "${BLUE}β•‘${WHITE} ${SHIELD} SUMMARY REPORT ${SHIELD} ${BLUE}β•‘${NC}" + echo -e "${BLUE}╠══════════════════════════════════════════════════════════════════════════════╣${NC}" + + # Task completion status + if [ "$updated_package_list" = true ]; then + echo -e "${BLUE}β•‘ ${GREEN}${CHECK_MARK} Package list updated${NC} ${BLUE}β•‘${NC}" + else + echo -e "${BLUE}β•‘ ${YELLOW}${CROSS_MARK} Package list update skipped${NC} ${BLUE}β•‘${NC}" + fi + + if [ "$upgraded_packages" = true ]; then + echo -e "${BLUE}β•‘ ${GREEN}${CHECK_MARK} Packages upgraded${NC} (${PACKAGES_UPGRADED} packages) ${BLUE}β•‘${NC}" + else + echo -e "${BLUE}β•‘ ${YELLOW}${CROSS_MARK} Package upgrade skipped${NC} ${BLUE}β•‘${NC}" + fi + + if [ "$full_upgrade_done" = true ]; then + echo -e "${BLUE}β•‘ ${GREEN}${CHECK_MARK} Full upgrade performed${NC} ${BLUE}β•‘${NC}" + else + echo -e "${BLUE}β•‘ ${YELLOW}${CROSS_MARK} Full upgrade skipped${NC} ${BLUE}β•‘${NC}" + fi + + if [ "$removed_unnecessary" = true ]; then + echo -e "${BLUE}β•‘ ${GREEN}${CHECK_MARK} Unnecessary packages removed${NC} (${PACKAGES_REMOVED} packages) ${BLUE}β•‘${NC}" + else + echo -e "${BLUE}β•‘ ${YELLOW}${CROSS_MARK} Unnecessary package removal skipped${NC} ${BLUE}β•‘${NC}" + fi + + if [ "$cache_cleaned" = true ]; then + echo -e "${BLUE}β•‘ ${GREEN}${CHECK_MARK} Cache cleaned${NC} ${BLUE}β•‘${NC}" + else + echo -e "${BLUE}β•‘ ${YELLOW}${CROSS_MARK} Cache cleanup skipped${NC} ${BLUE}β•‘${NC}" + fi + + echo -e "${BLUE}β•‘${NC} ${BLUE}β•‘${NC}" + + # Performance metrics + echo -e "${BLUE}β•‘ ${CHART} Performance Metrics:${NC} ${BLUE}β•‘${NC}" + echo -e "${BLUE}β•‘ ${CLOCK} Total time: ${BOLD}$((TOTAL_TIME / 60))m $((TOTAL_TIME % 60))s${NC} ${BLUE}β•‘${NC}" + + if [ $space_freed -gt 0 ]; then + echo -e "${BLUE}β•‘ ${CLEAN} Disk space freed: ${GREEN}${BOLD}${space_freed}%${NC} ${BLUE}β•‘${NC}" + else + echo -e "${BLUE}β•‘ ${INFO_SYMBOL} Disk space used: ${BOLD}${final_space}%${NC} ${BLUE}β•‘${NC}" + fi + + if [ "$SECURITY_UPDATES" -gt 0 ]; then + echo -e "${BLUE}β•‘ ${SHIELD} Security updates: ${BOLD}${SECURITY_UPDATES}${NC} ${BLUE}β•‘${NC}" + fi + + if [ ${#FAILED_OPERATIONS[@]} -gt 0 ]; then + echo -e "${BLUE}β•‘ ${WARNING_SYMBOL} Failed operations: ${BOLD}${#FAILED_OPERATIONS[@]}${NC} ${BLUE}β•‘${NC}" + fi + + echo -e "${BLUE}β•šβ•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•${NC}" + + # Detailed logs log "Update Summary:" log "- Package list updated: $updated_package_list" - log "- Packages upgraded: $upgraded_packages" + log "- Packages upgraded: $upgraded_packages ($PACKAGES_UPGRADED packages)" log "- Full upgrade performed: $full_upgrade_done" - log "- Unnecessary packages removed: $removed_unnecessary" + log "- Unnecessary packages removed: $removed_unnecessary ($PACKAGES_REMOVED packages)" log "- Cache cleaned: $cache_cleaned" - log "- Disk space freed: $((initial_space - $(check_disk_space)))%" + log "- Total execution time: ${TOTAL_TIME}s" + log "- Disk space freed: ${space_freed}%" + log "- Security updates processed: $SECURITY_UPDATES" + log "- Failed operations: ${#FAILED_OPERATIONS[@]}" + + # Send email notification if enabled + if [ "${enable_email_notifications:-false}" = "true" ]; then + local email_body="Update Summary for $(hostname): +- Packages upgraded: $PACKAGES_UPGRADED +- Packages removed: $PACKAGES_REMOVED +- Security updates: $SECURITY_UPDATES +- Disk space freed: ${space_freed}% +- Total time: $((TOTAL_TIME / 60))m $((TOTAL_TIME % 60))s +- Status: $([ ${#FAILED_OPERATIONS[@]} -eq 0 ] && echo "Success" || echo "Completed with ${#FAILED_OPERATIONS[@]} failed operations") + +Log file: $LOG_FILE" + send_email_notification "System Update Completed - $(hostname)" "$email_body" + fi } print_summary # Check if reboot is required check_reboot_required() { + print_section "Reboot Check" if [ -f /var/run/reboot-required ]; then - log "A system reboot is required to complete the update process." + print_warning "A system reboot is required to complete the update process." + if [ -f /var/run/reboot-required.pkgs ]; then + print_info "Packages requiring reboot:" + while read -r pkg; do + echo -e " ${YELLOW}β€’ $pkg${NC}" + done < /var/run/reboot-required.pkgs + fi + if prompt_user "Do you want to reboot now?"; then + print_info "Rebooting system in 10 seconds... (Press Ctrl+C to cancel)" + for i in {10..1}; do + echo -ne "\r${YELLOW}Rebooting in $i seconds...${NC}" + sleep 1 + done + echo + log "System reboot initiated by user" + send_email_notification "System Reboot - $(hostname)" "System is rebooting to complete updates." sudo reboot else - log "Please remember to reboot your system as soon as possible." + print_warning "Please remember to reboot your system as soon as possible." + log "Reboot required but deferred by user" fi + else + print_success "No reboot required at this time." + log "No reboot required" fi } check_reboot_required -log "Script execution completed." +# Final cleanup and completion +print_section "Completion" +print_success "Script execution completed successfully!" + +if [ ${#FAILED_OPERATIONS[@]} -gt 0 ]; then + print_warning "Some operations failed:" + for op in "${FAILED_OPERATIONS[@]}"; do + echo -e " ${RED}β€’ $op${NC}" + done +fi + +echo +echo -e "${GREEN}${BOLD}Thank you for using BigBearTechWorld scripts! ${ROCKET}${NC}" +echo +echo -e "${YELLOW}${BOLD}πŸ’ Enjoyed this script? Show your support:${NC}" +echo -e "${GREEN} β˜• Buy me a tea: ${BOLD}https://ko-fi.com/bigbeartechworld${NC}" +echo -e "${CYAN} 🌟 Star on GitHub: ${BOLD}https://github.com/bigbeartechworld/big-bear-scripts${NC}" +echo -e "${PURPLE} πŸ“Ί Subscribe: ${BOLD}https://youtube.com/@BigBearTechWorld${NC}" +echo +echo -e "${BLUE}${BOLD}πŸ“ Files:${NC}" +echo -e "${CYAN} Configuration: $CONFIG_FILE${NC}" +echo -e "${CYAN} Logs: $LOG_FILE${NC}" +echo -e "${CYAN} JSON Log: $JSON_LOG_FILE${NC}" +echo + +log "Script execution completed successfully"