kamal-backup 0.3.0.beta8 → 0.3.0.beta9
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- checksums.yaml +4 -4
- data/lib/kamal_backup/app.rb +59 -1
- data/lib/kamal_backup/cli.rb +14 -1
- data/lib/kamal_backup/version.rb +1 -1
- metadata +1 -1
checksums.yaml
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
---
|
|
2
2
|
SHA256:
|
|
3
|
-
metadata.gz:
|
|
4
|
-
data.tar.gz:
|
|
3
|
+
metadata.gz: c7c67946461c23a767a12d31d82389bb4e0fb3c75a5494f102c4dad8facecb2e
|
|
4
|
+
data.tar.gz: f0265c16c92bdf291bf19f0586589af08938962c5a6b79635f782559dee75d39
|
|
5
5
|
SHA512:
|
|
6
|
-
metadata.gz:
|
|
7
|
-
data.tar.gz:
|
|
6
|
+
metadata.gz: f919b9df92d55407c57745e61cfa4fd011c15060ab6edd5d93b75516fef13b22f0490e7010531bb6c464578df6a25faf8a485d6a35f5431f9a6e53331cef90a5
|
|
7
|
+
data.tar.gz: d7243e236effb7c4da158c70993af8896e39764952f9dc2155a123655ddac49931804c67dd10424d10a5ddcdd0208542a28fe798256691a4cb2287ef35bba242
|
data/lib/kamal_backup/app.rb
CHANGED
|
@@ -16,6 +16,8 @@ require_relative "schema"
|
|
|
16
16
|
|
|
17
17
|
module KamalBackup
|
|
18
18
|
class App
|
|
19
|
+
FRESH_BACKUP_GRACE_SECONDS = 5
|
|
20
|
+
|
|
19
21
|
attr_reader :config, :redactor
|
|
20
22
|
|
|
21
23
|
def initialize(env: ENV, config: nil, redactor: nil, restic: nil, database: nil, evidence_class: Evidence, scheduler_class: Scheduler)
|
|
@@ -28,6 +30,7 @@ module KamalBackup
|
|
|
28
30
|
end
|
|
29
31
|
|
|
30
32
|
def backup
|
|
33
|
+
started_at = Time.now.utc
|
|
31
34
|
config.validate_backup
|
|
32
35
|
require_restic!
|
|
33
36
|
|
|
@@ -43,7 +46,9 @@ module KamalBackup
|
|
|
43
46
|
restic.check
|
|
44
47
|
end
|
|
45
48
|
|
|
46
|
-
|
|
49
|
+
backup_summary(started_at: started_at, finished_at: Time.now.utc).tap do |summary|
|
|
50
|
+
validate_fresh_backup_summary!(summary, started_at: started_at)
|
|
51
|
+
end
|
|
47
52
|
end
|
|
48
53
|
|
|
49
54
|
def validate(check_files: true)
|
|
@@ -241,6 +246,59 @@ module KamalBackup
|
|
|
241
246
|
result[:files] = file_results.size == 1 ? file_results.first : file_results
|
|
242
247
|
end
|
|
243
248
|
|
|
249
|
+
def backup_summary(started_at:, finished_at:)
|
|
250
|
+
{
|
|
251
|
+
kind: "backup_result",
|
|
252
|
+
status: "ok",
|
|
253
|
+
started_at: started_at.iso8601,
|
|
254
|
+
finished_at: finished_at.iso8601,
|
|
255
|
+
databases: databases.map { |adapter| backup_snapshot_summary(adapter) },
|
|
256
|
+
files: backup_file_snapshot_summary
|
|
257
|
+
}
|
|
258
|
+
end
|
|
259
|
+
|
|
260
|
+
def backup_snapshot_summary(adapter)
|
|
261
|
+
snapshot = restic.latest_snapshot(tags: database_snapshot_tags(adapter))
|
|
262
|
+
snapshot_summary(snapshot).merge(
|
|
263
|
+
database: database_config_name(adapter),
|
|
264
|
+
adapter: adapter.adapter_name
|
|
265
|
+
)
|
|
266
|
+
end
|
|
267
|
+
|
|
268
|
+
def backup_file_snapshot_summary
|
|
269
|
+
return nil if config.backup_paths.empty?
|
|
270
|
+
|
|
271
|
+
snapshot_summary(restic.latest_snapshot(tags: ["type:files"]))
|
|
272
|
+
end
|
|
273
|
+
|
|
274
|
+
def snapshot_summary(snapshot)
|
|
275
|
+
{
|
|
276
|
+
snapshot: snapshot && (snapshot["short_id"] || snapshot["id"]),
|
|
277
|
+
time: snapshot && snapshot["time"]
|
|
278
|
+
}
|
|
279
|
+
end
|
|
280
|
+
|
|
281
|
+
def validate_fresh_backup_summary!(summary, started_at:)
|
|
282
|
+
stale_databases = summary.fetch(:databases).reject { |entry| fresh_snapshot?(entry, started_at) }
|
|
283
|
+
|
|
284
|
+
unless stale_databases.empty?
|
|
285
|
+
names = stale_databases.map { |entry| entry.fetch(:database) }.join(", ")
|
|
286
|
+
raise ConfigurationError, "backup did not create a fresh database snapshot for #{names}"
|
|
287
|
+
end
|
|
288
|
+
|
|
289
|
+
files = summary[:files]
|
|
290
|
+
if files && !fresh_snapshot?(files, started_at)
|
|
291
|
+
raise ConfigurationError, "backup did not create a fresh file snapshot"
|
|
292
|
+
end
|
|
293
|
+
end
|
|
294
|
+
|
|
295
|
+
def fresh_snapshot?(entry, started_at)
|
|
296
|
+
snapshot_time = Time.parse(entry[:time].to_s)
|
|
297
|
+
snapshot_time >= started_at - FRESH_BACKUP_GRACE_SECONDS
|
|
298
|
+
rescue ArgumentError
|
|
299
|
+
false
|
|
300
|
+
end
|
|
301
|
+
|
|
244
302
|
def database_snapshot_tags(adapter)
|
|
245
303
|
["type:database", "database:#{database_config_name(adapter)}", "adapter:#{adapter.adapter_name}"]
|
|
246
304
|
end
|
data/lib/kamal_backup/cli.rb
CHANGED
|
@@ -138,6 +138,19 @@ module KamalBackup
|
|
|
138
138
|
puts("fix: #{status_output.decorate(accessory_reboot_command, :yellow, :bold)}") if status == "out of sync"
|
|
139
139
|
end
|
|
140
140
|
|
|
141
|
+
def print_backup_result(result)
|
|
142
|
+
return unless result.is_a?(Hash)
|
|
143
|
+
|
|
144
|
+
puts("Backup completed at #{result.fetch(:finished_at)}")
|
|
145
|
+
result.fetch(:databases).each do |database|
|
|
146
|
+
puts("database #{database.fetch(:database)}: #{database.fetch(:snapshot)} at #{database.fetch(:time)}")
|
|
147
|
+
end
|
|
148
|
+
|
|
149
|
+
if files = result[:files]
|
|
150
|
+
puts("files: #{files.fetch(:snapshot)} at #{files.fetch(:time)}")
|
|
151
|
+
end
|
|
152
|
+
end
|
|
153
|
+
|
|
141
154
|
def validate_deploy_config
|
|
142
155
|
config = Config.new(
|
|
143
156
|
env: bridge.accessory_environment(accessory_name: accessory_name),
|
|
@@ -424,7 +437,7 @@ module KamalBackup
|
|
|
424
437
|
if remote_command_mode?
|
|
425
438
|
exec_remote(["kamal-backup", "backup"])
|
|
426
439
|
else
|
|
427
|
-
direct_app.backup
|
|
440
|
+
print_backup_result(direct_app.backup)
|
|
428
441
|
end
|
|
429
442
|
end
|
|
430
443
|
|
data/lib/kamal_backup/version.rb
CHANGED