Module: Litestream

Defined in:
lib/litestream.rb,
lib/litestream/engine.rb,
lib/litestream/version.rb,
lib/litestream/commands.rb,
lib/litestream/upstream.rb,
app/jobs/litestream/verification_job.rb,
app/controllers/litestream/processes_controller.rb,
app/controllers/litestream/application_controller.rb,
app/controllers/litestream/restorations_controller.rb,
lib/litestream/generators/litestream/install_generator.rb

Defined Under Namespace

Modules: Commands, Generators, Upstream Classes: ApplicationController, Configuration, Engine, ProcessesController, RestorationsController, VerificationJob

Constant Summary collapse

VerificationFailure =
Class.new(StandardError)
VERSION =
"0.14.0"

Class Attribute Summary collapse

Class Method Summary collapse

Class Attribute Details

.configurationObject



11
12
13
# File 'lib/litestream.rb', line 11

def configuration
  @configuration ||= Configuration.new
end

Class Method Details

.config_pathObject



101
102
103
# File 'lib/litestream.rb', line 101

def config_path
  @@config_path || Rails.root.join("config", "litestream.yml")
end

.configure {|configuration| ... } ⇒ Object

Yields:



20
21
22
23
24
25
26
27
# File 'lib/litestream.rb', line 20

def self.configure
  deprecator.warn(
    "Configuring Litestream via Litestream.configure is deprecated. Use Rails.application.configure { config.litestream.* = ... } instead.",
    caller
  )
  self.configuration ||= Configuration.new
  yield(configuration)
end

.databasesObject



109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
# File 'lib/litestream.rb', line 109

def databases
  databases = Commands.databases

  databases.each do |db|
    generations = Commands.generations(db["path"])
    snapshots = Commands.snapshots(db["path"])
    db["path"] = db["path"].gsub(Rails.root.to_s, "[ROOT]")

    db["generations"] = generations.map do |generation|
      id = generation["generation"]
      replica = generation["name"]
      generation["snapshots"] = snapshots.select { |snapshot| snapshot["generation"] == id && snapshot["replica"] == replica }
        .map { |s| s.slice("index", "size", "created") }
      generation.slice("generation", "name", "lag", "start", "end", "snapshots")
    end
  end
end

.deprecatorObject



15
16
17
# File 'lib/litestream.rb', line 15

def deprecator
  @deprecator ||= ActiveSupport::Deprecation.new("0.12.0", "Litestream")
end

.passwordObject



69
70
71
# File 'lib/litestream.rb', line 69

def password
  ENV["LITESTREAM_PASSWORD"] || @@password
end

.queueObject



73
74
75
# File 'lib/litestream.rb', line 73

def queue
  ENV["LITESTREAM_QUEUE"] || @@queue || "default"
end

.replica_access_keyObject



93
94
95
# File 'lib/litestream.rb', line 93

def replica_access_key
  @@replica_access_key || configuration.replica_access_key
end

.replica_bucketObject



77
78
79
# File 'lib/litestream.rb', line 77

def replica_bucket
  @@replica_bucket || configuration.replica_bucket
end

.replica_endpointObject



85
86
87
# File 'lib/litestream.rb', line 85

def replica_endpoint
  @@replica_endpoint
end

.replica_key_idObject



89
90
91
# File 'lib/litestream.rb', line 89

def replica_key_id
  @@replica_key_id || configuration.replica_key_id
end

.replica_regionObject



81
82
83
# File 'lib/litestream.rb', line 81

def replica_region
  @@replica_region
end

.replicate_processObject



105
106
107
# File 'lib/litestream.rb', line 105

def replicate_process
  systemctl_info || process_info || {}
end

.systemctl_commandObject



97
98
99
# File 'lib/litestream.rb', line 97

def systemctl_command
  @@systemctl_command || "systemctl status litestream"
end

.usernameObject

use method instead of attr_accessor to ensure this works if variable set after Litestream is loaded



65
66
67
# File 'lib/litestream.rb', line 65

def username
  ENV["LITESTREAM_USERNAME"] || @@username || "litestream"
end

.verify!(database_path, replication_sleep: 10) ⇒ Object



40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
# File 'lib/litestream.rb', line 40

def verify!(database_path, replication_sleep: 10)
  database = SQLite3::Database.new(database_path)
  database.execute("CREATE TABLE IF NOT EXISTS _litestream_verification (id INTEGER PRIMARY KEY, uuid BLOB)")
  sentinel = SecureRandom.uuid
  database.execute("INSERT INTO _litestream_verification (uuid) VALUES (?)", [sentinel])
  # give the Litestream replication process time to replicate the sentinel value
  sleep replication_sleep

  backup_path = "tmp/#{Time.now.utc.strftime("%Y%m%d%H%M%S")}_#{sentinel}.sqlite3"
  Litestream::Commands.restore(database_path, **{"-o" => backup_path})

  backup = SQLite3::Database.new(backup_path)
  result = backup.execute("SELECT 1 FROM _litestream_verification WHERE uuid = ? LIMIT 1", sentinel) # => [[1]] || []

  raise VerificationFailure, "Verification failed for `#{database_path}`" if result.empty?

  true
ensure
  database.execute("DELETE FROM _litestream_verification WHERE uuid = ?", sentinel)
  database.close
  Dir.glob(backup_path + "*").each { |file| File.delete(file) }
end