diff --git a/app/app.rb b/app/app.rb index 30c4489..069bd4e 100644 --- a/app/app.rb +++ b/app/app.rb @@ -30,4 +30,11 @@ baktainer = Baktainer::Runner.new( } ) -baktainer.run \ No newline at end of file +if options[:now] + LOGGER.info('Running backup immediately (--now flag)') + baktainer.perform_backup + LOGGER.info('Backup completed, exiting') + exit 0 +else + baktainer.run +end \ No newline at end of file diff --git a/app/lib/baktainer/backup_monitor.rb b/app/lib/baktainer/backup_monitor.rb index f625fa7..12c02c8 100644 --- a/app/lib/baktainer/backup_monitor.rb +++ b/app/lib/baktainer/backup_monitor.rb @@ -15,6 +15,9 @@ class Baktainer::BackupMonitor @start_times = Concurrent::Hash.new @backup_history = Concurrent::Array.new @mutex = Mutex.new + + # Load historical backups on startup + load_historical_backups end def start_backup(container_name, engine) @@ -162,12 +165,75 @@ class Baktainer::BackupMonitor private + def load_historical_backups + backup_dir = ENV['BT_BACKUP_DIR'] || '/backups' + + unless Dir.exist?(backup_dir) + @logger.debug("Backup directory #{backup_dir} does not exist, skipping historical backup loading") + return + end + + @logger.info("Loading historical backup data from #{backup_dir}") + + begin + # Find all .meta files recursively + meta_files = Dir.glob(File.join(backup_dir, '**', '*.meta')) + loaded_count = 0 + + meta_files.each do |meta_file| + begin + # Read and parse metadata + metadata = JSON.parse(File.read(meta_file)) + + # Convert to backup history format + backup_record = { + container_name: metadata['container_name'], + timestamp: metadata['timestamp'], + duration: estimate_backup_duration(metadata['file_size']), + file_size: metadata['file_size'], + file_path: File.join(File.dirname(meta_file), metadata['backup_file']), + status: File.exist?(File.join(File.dirname(meta_file), metadata['backup_file'])) ? 'success' : 'failed' + } + + # Add to history + @backup_history << backup_record + loaded_count += 1 + + rescue JSON::ParserError => e + @logger.warn("Failed to parse metadata file #{meta_file}: #{e.message}") + rescue => e + @logger.warn("Error loading backup metadata from #{meta_file}: #{e.message}") + end + end + + # Sort by timestamp and keep only the most recent 1000 records + @backup_history.sort_by! { |backup| backup[:timestamp] } + @backup_history = @backup_history.last(1000) + + @logger.info("Loaded #{loaded_count} historical backups from #{meta_files.size} metadata files") + + rescue => e + @logger.error("Error loading historical backups: #{e.message}") + @logger.debug(e.backtrace.join("\n")) + end + end + + def estimate_backup_duration(file_size) + # Estimate duration based on file size + # Assume ~1MB/second processing speed as a reasonable estimate + return 1.0 if file_size.nil? || file_size <= 0 + + size_mb = file_size.to_f / (1024 * 1024) + [size_mb, 1.0].max # Minimum 1 second + end + def record_backup_metrics(backup_record) @mutex.synchronize do @backup_history << backup_record - # Keep only last 1000 records to prevent memory bloat - @backup_history.shift if @backup_history.size > 1000 + # Sort by timestamp and keep only last 1000 records to prevent memory bloat + @backup_history.sort_by! { |backup| backup[:timestamp] } + @backup_history = @backup_history.last(1000) # Check for performance issues check_performance_alerts(backup_record) diff --git a/app/lib/baktainer/dashboard.html b/app/lib/baktainer/dashboard.html index fe52dd4..3b26c96 100644 --- a/app/lib/baktainer/dashboard.html +++ b/app/lib/baktainer/dashboard.html @@ -86,6 +86,7 @@ color: #27ae60; } + .success { color: #27ae60; } .error { color: #e74c3c; } .warning { color: #f39c12; } @@ -132,6 +133,38 @@ .loading { display: none; color: #7f8c8d; + } + + .pagination-container { + display: flex; + justify-content: center; + align-items: center; + margin-top: 1rem; + gap: 0.5rem; + } + + .pagination-button { + padding: 0.5rem 1rem; + background: #3498db; + color: white; + border: none; + border-radius: 4px; + cursor: pointer; + font-size: 0.9rem; + } + + .pagination-button:hover { + background: #2980b9; + } + + .pagination-button:disabled { + background: #bdc3c7; + cursor: not-allowed; + } + + .pagination-info { + color: #666; + font-size: 0.9rem; font-style: italic; } @@ -204,6 +237,9 @@