TODO: - Add individual hook for completed backups - Add hook for fullly completed backups - Optionally limit time for each backup
105 lines
3.1 KiB
Ruby
105 lines
3.1 KiB
Ruby
# frozen_string_literal: true
|
|
|
|
# Baktainer is a class responsible for managing database backups using Docker containers.
|
|
#
|
|
# It supports the following database engines: PostgreSQL, MySQL, MariaDB, and Sqlite3.
|
|
#
|
|
# @example Initialize a Baktainer instance
|
|
# baktainer = Baktainer.new(url: 'unix:///var/run/docker.sock', ssl: true, ssl_options: {})
|
|
#
|
|
# @example Run the backup process
|
|
# baktainer.run
|
|
#
|
|
# @!attribute [r] SUPPORTED_ENGINES
|
|
# @return [Array<String>] The list of supported database engines.
|
|
#
|
|
# @param url [String] The Docker API URL. Defaults to 'unix:///var/run/docker.sock'.
|
|
# @param ssl [Boolean] Whether to use SSL for Docker API communication. Defaults to false.
|
|
#
|
|
# @method perform_backup
|
|
# Starts the backup process by searching for Docker containers and performing backups.
|
|
# Logs the process at various stages.
|
|
#
|
|
# @method run
|
|
# Schedules and runs the backup process at a specified time.
|
|
# If the time is invalid or not provided, defaults to 05:00.
|
|
#
|
|
# @private
|
|
# @method setup_ssl
|
|
# Configures SSL settings for Docker API communication if SSL is enabled.
|
|
# Uses environment variables `BT_CA`, `BT_CERT`, and `BT_KEY` for SSL certificates and keys.
|
|
module Baktainer
|
|
end
|
|
|
|
require 'docker-api'
|
|
require 'cron_calc'
|
|
require 'concurrent/executor/fixed_thread_pool'
|
|
require 'baktainer/logger'
|
|
require 'baktainer/container'
|
|
require 'baktainer/backup_command'
|
|
|
|
STDOUT.sync = true
|
|
|
|
|
|
class Baktainer::Runner
|
|
def initialize(url: 'unix:///var/run/docker.sock', ssl: false, ssl_options: {}, threads: 5)
|
|
@pool = Concurrent::FixedThreadPool.new(threads)
|
|
@url = url
|
|
@ssl = ssl
|
|
@ssl_options = ssl_options
|
|
Docker.url = @url
|
|
setup_ssl
|
|
LOGGER.level = ENV['LOG_LEVEL']&.to_sym || :info
|
|
end
|
|
|
|
def perform_backup
|
|
LOGGER.info('Starting backup process.')
|
|
LOGGER.debug('Docker Searching for containers.')
|
|
Baktainer::Containers.find_all.each do |container|
|
|
@pool.post do
|
|
begin
|
|
LOGGER.info("Backing up container #{container.name} with engine #{container.engine}.")
|
|
container.backup
|
|
LOGGER.info("Backup completed for container #{container.name}.")
|
|
rescue StandardError => e
|
|
LOGGER.error("Error backing up container #{container.name}: #{e.message}")
|
|
LOGGER.debug(e.backtrace.join("\n"))
|
|
end
|
|
end
|
|
end
|
|
end
|
|
|
|
def run
|
|
run_at = ENV['BT_CRON'] || '0 0 * * *'
|
|
begin
|
|
@cron = CronCalc.new(run_at)
|
|
rescue
|
|
LOGGER.error("Invalid cron format for BT_CRON: #{run_at}.")
|
|
end
|
|
|
|
loop do
|
|
now = Time.now
|
|
next_run = @cron.next.first
|
|
sleep_duration = next_run - now
|
|
LOGGER.info("Sleeping for #{sleep_duration} seconds until #{next_run}.")
|
|
sleep(sleep_duration)
|
|
perform_backup
|
|
end
|
|
end
|
|
|
|
private
|
|
|
|
def setup_ssl
|
|
return unless @ssl
|
|
|
|
@cert_store = OpenSSL::X509::Store.new
|
|
@cerificate = OpenSSL::X509::Certificate.new(ENV['BT_CA'])
|
|
@cert_store.add_cert(@cerificate)
|
|
Docker.options = {
|
|
client_cert_data: ENV['BT_CERT'],
|
|
client_key_data: ENV['BT_KEY'],
|
|
ssl_cert_store: @cert_store,
|
|
scheme: 'https'
|
|
}
|
|
end
|
|
end
|