diff --git a/snap-src/bin/logrotate-mongodb b/snap-src/bin/logrotate-mongodb new file mode 100755 index 000000000..345413297 --- /dev/null +++ b/snap-src/bin/logrotate-mongodb @@ -0,0 +1,188 @@ +#!/bin/bash + +# MongoDB Log Rotation Script for Wekan Snap +# This script handles log rotation for MongoDB logs in the Wekan snap environment + +set -e + +# Source settings if available, otherwise use defaults +if [ -f "$SNAP/bin/wekan-read-settings" ]; then + source $SNAP/bin/wekan-read-settings +else + # Default values when wekan-read-settings is not available + SNAP_COMMON="/var/snap/wekan/common" + SNAP_NAME="wekan" +fi + +# Configuration +MONGODB_LOG="${SNAP_COMMON}/mongodb.log" +MAX_SIZE_MB=100 +KEEP_COPIES=10 +COMPRESS_LOGS=true + +# Logging functions +log_message() { + local message="$1" + local timestamp=$(date '+%Y-%m-%d %H:%M:%S') + echo "[$timestamp] $message" +} + +log_error() { + local message="$1" + log_message "ERROR: $message" +} + +log_success() { + local message="$1" + log_message "SUCCESS: $message" +} + +log_warning() { + local message="$1" + log_message "WARNING: $message" +} + +# Check if log file exists and is large enough to rotate +check_rotation_needed() { + if [ ! -f "$MONGODB_LOG" ]; then + log_message "MongoDB log file not found: $MONGODB_LOG" + return 1 + fi + + # Get log file size in MB + local log_size_mb=$(du -m "$MONGODB_LOG" | cut -f1) + + if [ "$log_size_mb" -lt "$MAX_SIZE_MB" ]; then + log_message "MongoDB log size (${log_size_mb}MB) is below rotation threshold (${MAX_SIZE_MB}MB)" + return 1 + fi + + log_message "MongoDB log size (${log_size_mb}MB) exceeds rotation threshold (${MAX_SIZE_MB}MB)" + return 0 +} + +# Rotate MongoDB log file +rotate_log() { + local mongodb_log="$1" + local max_size_mb="$2" + local keep_copies="$3" + local compress="$4" + + log_message "Starting MongoDB log rotation" + + # Create rotated log file with timestamp + local timestamp=$(date +%Y%m%d-%H%M%S) + local rotated_log="${mongodb_log}.${timestamp}" + + # Copy current log to rotated file + if cp "$mongodb_log" "$rotated_log"; then + log_message "Created rotated log file: $rotated_log" + + # Truncate original log file + if > "$mongodb_log"; then + log_message "Truncated original log file" + else + log_error "Failed to truncate original log file" + return 1 + fi + + # Compress rotated log file if requested + if [ "$compress" = "true" ]; then + if gzip "$rotated_log"; then + log_message "Compressed rotated log file: ${rotated_log}.gz" + else + log_warning "Failed to compress rotated log file" + fi + fi + + # Clean up old rotated logs (keep only specified number) + local old_logs=$(ls -t "${mongodb_log}".* 2>/dev/null | tail -n +$((keep_copies + 1))) + if [ -n "$old_logs" ]; then + echo "$old_logs" | xargs rm -f + log_message "Cleaned up old rotated log files" + fi + + log_success "MongoDB log rotation completed successfully" + return 0 + else + log_error "Failed to create rotated log file" + return 1 + fi +} + +# Show log file statistics +show_log_stats() { + if [ ! -f "$MONGODB_LOG" ]; then + log_message "MongoDB log file not found: $MONGODB_LOG" + return 1 + fi + + local log_size_mb=$(du -m "$MONGODB_LOG" | cut -f1) + local log_lines=$(wc -l < "$MONGODB_LOG" 2>/dev/null || echo "0") + local rotated_count=$(ls -1 "${MONGODB_LOG}".* 2>/dev/null | wc -l) + + log_message "MongoDB Log Statistics:" + log_message " Current log size: ${log_size_mb}MB" + log_message " Current log lines: ${log_lines}" + log_message " Rotated log files: ${rotated_count}" + log_message " Rotation threshold: ${MAX_SIZE_MB}MB" + log_message " Keep copies: ${KEEP_COPIES}" +} + +# Force rotation regardless of size +force_rotation() { + log_message "Force rotating MongoDB log file" + + if [ ! -f "$MONGODB_LOG" ]; then + log_error "MongoDB log file not found: $MONGODB_LOG" + return 1 + fi + + rotate_log "$MONGODB_LOG" "$MAX_SIZE_MB" "$KEEP_COPIES" "$COMPRESS_LOGS" +} + +# Main function +main() { + local action="${1:-check}" + + case "$action" in + "check") + log_message "Checking if MongoDB log rotation is needed" + if check_rotation_needed; then + log_message "Log rotation is needed" + rotate_log "$MONGODB_LOG" "$MAX_SIZE_MB" "$KEEP_COPIES" "$COMPRESS_LOGS" + else + log_message "Log rotation is not needed" + fi + ;; + "force") + force_rotation + ;; + "stats") + show_log_stats + ;; + "help"|"-h"|"--help") + echo "Usage: $0 [check|force|stats|help]" + echo "" + echo "Commands:" + echo " check - Check if rotation is needed and rotate if so (default)" + echo " force - Force rotation regardless of log size" + echo " stats - Show log file statistics" + echo " help - Show this help message" + echo "" + echo "Configuration:" + echo " Log file: $MONGODB_LOG" + echo " Max size: ${MAX_SIZE_MB}MB" + echo " Keep copies: $KEEP_COPIES" + echo " Compress: $COMPRESS_LOGS" + ;; + *) + log_error "Unknown action: $action" + echo "Use '$0 help' for usage information" + exit 1 + ;; + esac +} + +# Run main function +main "$@" diff --git a/snap-src/bin/logrotate-setup b/snap-src/bin/logrotate-setup new file mode 100644 index 000000000..dbd63ebab --- /dev/null +++ b/snap-src/bin/logrotate-setup @@ -0,0 +1,175 @@ +#!/bin/bash + +# Wekan Log Rotation Setup Script +# This script sets up log rotation for Wekan snap installation + +set -e + +# Configuration +SNAP_NAME="wekan" +SNAP_COMMON="/var/snap/${SNAP_NAME}/common" +LOGROTATE_DIR="/etc/logrotate.d" +WEKAN_LOGROTATE_CONF="${LOGROTATE_DIR}/${SNAP_NAME}" + +# Log file paths +MONGODB_LOG="${SNAP_COMMON}/mongodb.log" +WEKAN_APP_LOG="${SNAP_COMMON}/wekan-app.log" +WEKAN_ERROR_LOG="${SNAP_COMMON}/wekan-error.log" + +# Log rotation configuration +ROTATE_SIZE="100M" +KEEP_DAYS="30" +KEEP_COPIES="10" + +log_message() { + echo "[$(date '+%Y-%m-%d %H:%M:%S')] $1" +} + +log_error() { + echo "[$(date '+%Y-%m-%d %H:%M:%S')] ERROR: $1" >&2 +} + +# Check if running as root +if [ "$EUID" -ne 0 ]; then + log_error "This script must be run as root" + exit 1 +fi + +# Check if snap is installed +if ! snap list | grep -q "^${SNAP_NAME} "; then + log_error "Snap ${SNAP_NAME} is not installed" + exit 1 +fi + +log_message "Setting up log rotation for Wekan snap..." + +# Create logrotate configuration +cat > "${WEKAN_LOGROTATE_CONF}" << EOF +# Wekan Snap Log Rotation Configuration +# Generated by wekan logrotate-setup script + +# MongoDB logs +${MONGODB_LOG} { + daily + missingok + rotate ${KEEP_COPIES} + compress + delaycompress + notifempty + create 644 root root + postrotate + # Send SIGUSR1 to MongoDB to reopen log file + if [ -f "${SNAP_COMMON}/mongodb.pid" ]; then + kill -USR1 \$(cat "${SNAP_COMMON}/mongodb.pid") 2>/dev/null || true + fi + # Alternative: restart MongoDB service if PID file doesn't exist + if [ ! -f "${SNAP_COMMON}/mongodb.pid" ]; then + snap restart ${SNAP_NAME}.mongodb 2>/dev/null || true + fi + endscript +} + +# Wekan application logs +${WEKAN_APP_LOG} { + daily + missingok + rotate ${KEEP_COPIES} + compress + delaycompress + notifempty + create 644 root root + postrotate + # Send SIGUSR1 to Wekan application to reopen log file + if [ -f "${SNAP_COMMON}/wekan.pid" ]; then + kill -USR1 \$(cat "${SNAP_COMMON}/wekan.pid") 2>/dev/null || true + fi + # Alternative: restart Wekan service if PID file doesn't exist + if [ ! -f "${SNAP_COMMON}/wekan.pid" ]; then + snap restart ${SNAP_NAME}.wekan 2>/dev/null || true + fi + endscript +} + +# Wekan error logs +${WEKAN_ERROR_LOG} { + daily + missingok + rotate ${KEEP_COPIES} + compress + delaycompress + notifempty + create 644 root root + postrotate + # Send SIGUSR1 to Wekan application to reopen log file + if [ -f "${SNAP_COMMON}/wekan.pid" ]; then + kill -USR1 \$(cat "${SNAP_COMMON}/wekan.pid") 2>/dev/null || true + fi + # Alternative: restart Wekan service if PID file doesn't exist + if [ ! -f "${SNAP_COMMON}/wekan.pid" ]; then + snap restart ${SNAP_NAME}.wekan 2>/dev/null || true + fi + endscript +} + +# Size-based rotation for large log files +${SNAP_COMMON}/*.log { + size ${ROTATE_SIZE} + missingok + rotate ${KEEP_COPIES} + compress + delaycompress + notifempty + create 644 root root + sharedscripts + postrotate + # Generic postrotate for all log files + # Try to signal processes to reopen log files + for pidfile in "${SNAP_COMMON}"/*.pid; do + if [ -f "\$pidfile" ]; then + kill -USR1 \$(cat "\$pidfile") 2>/dev/null || true + fi + done + # Restart services if no PID files found + if [ ! -f "${SNAP_COMMON}/mongodb.pid" ] && [ ! -f "${SNAP_COMMON}/wekan.pid" ]; then + snap restart ${SNAP_NAME}.mongodb 2>/dev/null || true + snap restart ${SNAP_NAME}.wekan 2>/dev/null || true + fi + endscript +} +EOF + +log_message "Created logrotate configuration: ${WEKAN_LOGROTATE_CONF}" + +# Test logrotate configuration +if logrotate -d "${WEKAN_LOGROTATE_CONF}" >/dev/null 2>&1; then + log_message "Logrotate configuration test passed" +else + log_error "Logrotate configuration test failed" + exit 1 +fi + +# Create log directory if it doesn't exist +mkdir -p "${SNAP_COMMON}" + +# Set proper permissions +chown root:root "${WEKAN_LOGROTATE_CONF}" +chmod 644 "${WEKAN_LOGROTATE_CONF}" + +# Create initial log files if they don't exist +touch "${MONGODB_LOG}" "${WEKAN_APP_LOG}" "${WEKAN_ERROR_LOG}" +chown root:root "${SNAP_COMMON}"/*.log +chmod 644 "${SNAP_COMMON}"/*.log + +log_message "Log rotation setup completed successfully" +log_message "Configuration file: ${WEKAN_LOGROTATE_CONF}" +log_message "Log files will be rotated daily and when they exceed ${ROTATE_SIZE}" +log_message "Log files will be kept for ${KEEP_DAYS} days (${KEEP_COPIES} copies)" +log_message "To test log rotation manually: sudo logrotate -f ${WEKAN_LOGROTATE_CONF}" +log_message "To view logrotate status: sudo logrotate -d ${WEKAN_LOGROTATE_CONF}" + +echo "" +echo "Next steps:" +echo "1. Configure MongoDB to log to file: sudo snap set ${SNAP_NAME} mongo-log-destination=snapcommon" +echo "2. Configure Wekan to log to file (if not already done)" +echo "3. Test log rotation: sudo logrotate -f ${WEKAN_LOGROTATE_CONF}" +echo "4. Monitor log files: ls -la ${SNAP_COMMON}/*.log*" diff --git a/snap-src/bin/mongodb-migrate b/snap-src/bin/mongodb-migrate index 28d42eba9..56fc33642 100755 --- a/snap-src/bin/mongodb-migrate +++ b/snap-src/bin/mongodb-migrate @@ -77,6 +77,11 @@ log_success() { log_message "SUCCESS: $message" } +log_warning() { + local message="$1" + log_message "WARNING: $message" +} + # Disk space checking functions check_disk_space() { local required_space_gb="$1" @@ -222,6 +227,28 @@ check_migration_needed() { return 1 } +# Display MongoDB log content for debugging +display_mongodb_log_content() { + local mongodb_log="${SNAP_COMMON}/mongodb.log" + + if [ ! -f "$mongodb_log" ]; then + log_message "MongoDB log file not found: $mongodb_log" + return 1 + fi + + log_message "MongoDB log file content (last 50 lines):" + if [ -r "$mongodb_log" ]; then + tail -50 "$mongodb_log" | while read -r line; do + log_message "LOG: $line" + done + else + log_message "MongoDB log file not readable, trying with sudo" + sudo tail -50 "$mongodb_log" 2>/dev/null | while read -r line; do + log_message "LOG: $line" + done + fi +} + # Detect if MongoDB upgrade is needed by checking log file detect_mongodb_upgrade_needed() { local mongodb_log="${SNAP_COMMON}/mongodb.log" @@ -232,20 +259,168 @@ detect_mongodb_upgrade_needed() { return 1 fi - # Check for the specific error message indicating upgrade is needed - if grep -q "This version of MongoDB is too recent to start up on the existing data files. Try MongoDB 4.2 or earlier." "$mongodb_log"; then - log_message "MongoDB upgrade needed detected in log file" + # Display log content for debugging + display_mongodb_log_content + + # Check file permissions and try to read with appropriate method + if [ ! -r "$mongodb_log" ]; then + log_message "MongoDB log file not readable, trying with sudo" + # Try to read with sudo if not readable + if ! sudo grep -q "too recent to start up on the existing data files" "$mongodb_log" 2>/dev/null; then + log_message "No MongoDB upgrade needed detected in log file (via sudo)" + return 1 + fi + else + # Check for various error messages that indicate upgrade is needed + # The exact message may vary between MongoDB versions + local upgrade_patterns=( + "This version of MongoDB is too recent to start up on the existing data files" + "too recent to start up on the existing data files" + "Try MongoDB 4.2 or earlier" + "unsupported format version" + "data files are incompatible" + "database files are incompatible" + "version too new" + "version too recent" + ) + + local found_upgrade_needed=false + for pattern in "${upgrade_patterns[@]}"; do + if grep -q "$pattern" "$mongodb_log" 2>/dev/null; then + log_message "Found upgrade pattern in log: '$pattern'" + found_upgrade_needed=true + break + fi + done + + if [ "$found_upgrade_needed" = false ]; then + log_message "No MongoDB upgrade needed detected in log file" + return 1 + fi + fi + + log_message "MongoDB upgrade needed detected in log file" + return 0 +} + +# Log rotation function for MongoDB logs +rotate_mongodb_logs() { + local mongodb_log="${SNAP_COMMON}/mongodb.log" + local max_size_mb=100 + local keep_copies=10 + + # Check if log file exists and is large enough to rotate + if [ ! -f "$mongodb_log" ]; then + log_message "MongoDB log file not found, skipping rotation" return 0 fi - # Also check for similar error messages that might indicate upgrade issues - if grep -q "too recent to start up on the existing data files" "$mongodb_log"; then - log_message "MongoDB upgrade needed detected in log file (alternative message)" + # Get log file size in MB + local log_size_mb=$(du -m "$mongodb_log" | cut -f1) + + if [ "$log_size_mb" -lt "$max_size_mb" ]; then + log_message "MongoDB log size (${log_size_mb}MB) is below rotation threshold (${max_size_mb}MB)" return 0 fi - log_message "No MongoDB upgrade needed detected in log file" - return 1 + log_message "Rotating MongoDB log file (size: ${log_size_mb}MB)" + + # Create rotated log file with timestamp + local timestamp=$(date +%Y%m%d-%H%M%S) + local rotated_log="${mongodb_log}.${timestamp}" + + # Copy current log to rotated file + if cp "$mongodb_log" "$rotated_log"; then + log_message "Created rotated log file: $rotated_log" + + # Truncate original log file + if > "$mongodb_log"; then + log_message "Truncated original log file" + else + log_error "Failed to truncate original log file" + return 1 + fi + + # Compress rotated log file + if gzip "$rotated_log"; then + log_message "Compressed rotated log file: ${rotated_log}.gz" + else + log_warning "Failed to compress rotated log file" + fi + + # Clean up old rotated logs (keep only specified number) + local old_logs=$(ls -t "${mongodb_log}".* 2>/dev/null | tail -n +$((keep_copies + 1))) + if [ -n "$old_logs" ]; then + echo "$old_logs" | xargs rm -f + log_message "Cleaned up old rotated log files" + fi + + log_success "MongoDB log rotation completed successfully" + return 0 + else + log_error "Failed to create rotated log file" + return 1 + fi +} + +# Enhanced log rotation function for migration logs +rotate_migration_logs() { + local migration_log="${SNAP_COMMON}/mongodb-migration-log.txt" + local max_size_mb=50 + local keep_copies=5 + + # Check if migration log file exists and is large enough to rotate + if [ ! -f "$migration_log" ]; then + log_message "Migration log file not found, skipping rotation" + return 0 + fi + + # Get log file size in MB + local log_size_mb=$(du -m "$migration_log" | cut -f1) + + if [ "$log_size_mb" -lt "$max_size_mb" ]; then + log_message "Migration log size (${log_size_mb}MB) is below rotation threshold (${max_size_mb}MB)" + return 0 + fi + + log_message "Rotating migration log file (size: ${log_size_mb}MB)" + + # Create rotated log file with timestamp + local timestamp=$(date +%Y%m%d-%H%M%S) + local rotated_log="${migration_log}.${timestamp}" + + # Copy current log to rotated file + if cp "$migration_log" "$rotated_log"; then + log_message "Created rotated migration log file: $rotated_log" + + # Truncate original log file + if > "$migration_log"; then + log_message "Truncated original migration log file" + else + log_error "Failed to truncate original migration log file" + return 1 + fi + + # Compress rotated log file + if gzip "$rotated_log"; then + log_message "Compressed rotated migration log file: ${rotated_log}.gz" + else + log_warning "Failed to compress rotated migration log file" + fi + + # Clean up old rotated logs (keep only specified number) + local old_logs=$(ls -t "${migration_log}".* 2>/dev/null | tail -n +$((keep_copies + 1))) + if [ -n "$old_logs" ]; then + echo "$old_logs" | xargs rm -f + log_message "Cleaned up old rotated migration log files" + fi + + log_success "Migration log rotation completed successfully" + return 0 + else + log_error "Failed to create rotated migration log file" + return 1 + fi } # Reset MONGO_LOG_DESTINATION to devnull after successful migration @@ -493,6 +668,18 @@ perform_migration() { log_message "Starting MongoDB migration from version 3 to 7" + # Rotate MongoDB logs before migration if needed + log_message "Checking if MongoDB log rotation is needed" + if ! rotate_mongodb_logs; then + log_warning "MongoDB log rotation failed, continuing with migration" + fi + + # Rotate migration logs before migration if needed + log_message "Checking if migration log rotation is needed" + if ! rotate_migration_logs; then + log_warning "Migration log rotation failed, continuing with migration" + fi + # Create backup before migration log_message "Creating backup before migration" if ! create_backup; then @@ -572,6 +759,18 @@ EOF log_success "MongoDB migration completed successfully" + # Rotate MongoDB logs after successful migration + log_message "Rotating MongoDB logs after successful migration" + if ! rotate_mongodb_logs; then + log_warning "MongoDB log rotation after migration failed" + fi + + # Rotate migration logs after successful migration + log_message "Rotating migration logs after successful migration" + if ! rotate_migration_logs; then + log_warning "Migration log rotation after migration failed" + fi + # Reset MONGO_LOG_DESTINATION to devnull after successful migration reset_mongo_log_destination