kamal-backup 0.3.0.beta3 → 0.3.0.beta5
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/README.md +1 -1
- data/lib/kamal_backup/app.rb +2 -7
- data/lib/kamal_backup/databases/base.rb +7 -7
- data/lib/kamal_backup/databases/sqlite.rb +3 -3
- data/lib/kamal_backup/restic.rb +57 -9
- data/lib/kamal_backup/version.rb +1 -1
- metadata +2 -2
checksums.yaml
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
---
|
|
2
2
|
SHA256:
|
|
3
|
-
metadata.gz:
|
|
4
|
-
data.tar.gz:
|
|
3
|
+
metadata.gz: 0b92197e0f2d480ca2cebd5e2505304686b739ca0ed4c61c24b4b4caca39054d
|
|
4
|
+
data.tar.gz: ff2b00e495d6690956d1ed8070bc43989ca1a9e4b9846b6503ababa26adbd01f
|
|
5
5
|
SHA512:
|
|
6
|
-
metadata.gz:
|
|
7
|
-
data.tar.gz:
|
|
6
|
+
metadata.gz: c8f93d59add03f4bf66b48ae0ea61cf46c7682c527ac604fcbd98a8c0790e6cc77d9d45759fabbfb5d6fcbce25da0e82b421f56cc8771820c57b1933539634c2
|
|
7
|
+
data.tar.gz: ebd54357f4bdc1829a71cb76fcef4e60000661ce7eb8f4d1a974fb22438b1054fe96bfa26095509d74fd50e5a13d5e234fa0c845440c8f33ddfd49e798b307f4
|
data/README.md
CHANGED
|
@@ -141,7 +141,7 @@ Run the release helper from a clean `master` checkout:
|
|
|
141
141
|
bin/release 0.2.9
|
|
142
142
|
```
|
|
143
143
|
|
|
144
|
-
It updates `lib/kamal_backup/version.rb`,
|
|
144
|
+
It updates `lib/kamal_backup/version.rb`, syncs `Gemfile.lock`, commits `Release 0.2.9`, and pushes `master`. CI runs the test suite and docs build, publishes the RubyGem and Docker image tags, then creates `v0.2.9`, the GitHub release, and the docs deployment from the release commit.
|
|
145
145
|
|
|
146
146
|
Use `bin/release 0.2.9 --no-push` to prepare the commit locally without publishing.
|
|
147
147
|
|
data/lib/kamal_backup/app.rb
CHANGED
|
@@ -31,10 +31,9 @@ module KamalBackup
|
|
|
31
31
|
config.validate_backup
|
|
32
32
|
require_restic!
|
|
33
33
|
|
|
34
|
-
timestamp = current_timestamp
|
|
35
34
|
restic.ensure_repository
|
|
36
|
-
databases.each { |database| database.backup(restic
|
|
37
|
-
restic.backup_paths(config.backup_paths, tags: ["type:files"
|
|
35
|
+
databases.each { |database| database.backup(restic) }
|
|
36
|
+
restic.backup_paths(config.backup_paths, tags: ["type:files"])
|
|
38
37
|
|
|
39
38
|
if config.forget_after_backup?
|
|
40
39
|
restic.forget_after_success
|
|
@@ -135,10 +134,6 @@ module KamalBackup
|
|
|
135
134
|
end
|
|
136
135
|
|
|
137
136
|
private
|
|
138
|
-
def current_timestamp
|
|
139
|
-
Time.now.utc.strftime("%Y%m%dT%H%M%SZ")
|
|
140
|
-
end
|
|
141
|
-
|
|
142
137
|
def build_restore_result(scope, snapshot)
|
|
143
138
|
started_at = Time.now.utc
|
|
144
139
|
result = Schema.record(
|
|
@@ -24,11 +24,11 @@ module KamalBackup
|
|
|
24
24
|
@redactor = redactor
|
|
25
25
|
end
|
|
26
26
|
|
|
27
|
-
def backup(restic
|
|
27
|
+
def backup(restic)
|
|
28
28
|
restic.backup_stream(
|
|
29
29
|
dump_command,
|
|
30
|
-
filename: database_filename
|
|
31
|
-
tags: backup_tags
|
|
30
|
+
filename: database_filename,
|
|
31
|
+
tags: backup_tags
|
|
32
32
|
)
|
|
33
33
|
end
|
|
34
34
|
|
|
@@ -41,14 +41,14 @@ module KamalBackup
|
|
|
41
41
|
restic.pipe_dump_to_command(snapshot, filename, scratch_restore_command(target))
|
|
42
42
|
end
|
|
43
43
|
|
|
44
|
-
def database_filename
|
|
44
|
+
def database_filename
|
|
45
45
|
app = config.app_name.gsub(/[^A-Za-z0-9_.-]+/, "-")
|
|
46
46
|
database = config.database_name.gsub(/[^A-Za-z0-9_.-]+/, "-")
|
|
47
|
-
"databases
|
|
47
|
+
"databases/#{app}/#{database}/#{adapter_name}.#{dump_extension}"
|
|
48
48
|
end
|
|
49
49
|
|
|
50
|
-
def backup_tags
|
|
51
|
-
["type:database", "database:#{config.database_name}", "adapter:#{adapter_name}"
|
|
50
|
+
def backup_tags
|
|
51
|
+
["type:database", "database:#{config.database_name}", "adapter:#{adapter_name}"]
|
|
52
52
|
end
|
|
53
53
|
|
|
54
54
|
def adapter_name
|
|
@@ -13,7 +13,7 @@ module KamalBackup
|
|
|
13
13
|
"sqlite3"
|
|
14
14
|
end
|
|
15
15
|
|
|
16
|
-
def backup(restic
|
|
16
|
+
def backup(restic)
|
|
17
17
|
source = sqlite_source
|
|
18
18
|
Tempfile.create(["kamal-backup-", ".sqlite3"]) do |tempfile|
|
|
19
19
|
tempfile.close
|
|
@@ -23,8 +23,8 @@ module KamalBackup
|
|
|
23
23
|
)
|
|
24
24
|
restic.backup_file(
|
|
25
25
|
tempfile.path,
|
|
26
|
-
filename: database_filename
|
|
27
|
-
tags: backup_tags
|
|
26
|
+
filename: database_filename,
|
|
27
|
+
tags: backup_tags
|
|
28
28
|
)
|
|
29
29
|
end
|
|
30
30
|
end
|
data/lib/kamal_backup/restic.rb
CHANGED
|
@@ -28,7 +28,7 @@ module KamalBackup
|
|
|
28
28
|
|
|
29
29
|
def backup_stream(command, filename:, tags:)
|
|
30
30
|
restic_command = CommandSpec.new(
|
|
31
|
-
argv: ["restic", "backup"
|
|
31
|
+
argv: ["restic", "backup"] + host_args + ["--stdin", "--stdin-filename", filename] + tag_args(common_tags + tags),
|
|
32
32
|
env: restic_env
|
|
33
33
|
)
|
|
34
34
|
log("backing up stream as #{filename}")
|
|
@@ -37,7 +37,7 @@ module KamalBackup
|
|
|
37
37
|
|
|
38
38
|
def backup_file(path, filename:, tags:)
|
|
39
39
|
command = CommandSpec.new(
|
|
40
|
-
argv: ["restic", "backup"
|
|
40
|
+
argv: ["restic", "backup"] + host_args + ["--stdin", "--stdin-filename", filename] + tag_args(common_tags + tags),
|
|
41
41
|
env: restic_env
|
|
42
42
|
)
|
|
43
43
|
log("backing up file content as #{filename}")
|
|
@@ -66,7 +66,7 @@ module KamalBackup
|
|
|
66
66
|
if paths.any?
|
|
67
67
|
path_tags = paths.map { |path| "path:#{config.backup_path_label(path)}" }
|
|
68
68
|
log("backing up #{paths.size} file path(s): #{paths.join(", ")}")
|
|
69
|
-
run(["backup"] + paths + tag_args(common_tags + tags + path_tags))
|
|
69
|
+
run(["backup"] + host_args + paths + tag_args(common_tags + tags + path_tags))
|
|
70
70
|
end
|
|
71
71
|
end
|
|
72
72
|
|
|
@@ -75,9 +75,11 @@ module KamalBackup
|
|
|
75
75
|
end
|
|
76
76
|
|
|
77
77
|
def forget_after_success
|
|
78
|
-
|
|
79
|
-
|
|
80
|
-
|
|
78
|
+
retention_tag_sets.each do |tags|
|
|
79
|
+
args = ["forget", "--prune", "--group-by", "host"] + config.retention_args + filter_tag_args(tags)
|
|
80
|
+
log("running restic forget/prune with retention policy for #{retention_scope(tags)}")
|
|
81
|
+
run(args)
|
|
82
|
+
end
|
|
81
83
|
end
|
|
82
84
|
|
|
83
85
|
def check
|
|
@@ -93,11 +95,11 @@ module KamalBackup
|
|
|
93
95
|
end
|
|
94
96
|
|
|
95
97
|
def snapshots(tags: common_tags)
|
|
96
|
-
run(["snapshots"] +
|
|
98
|
+
run(["snapshots"] + filter_tag_args(tags))
|
|
97
99
|
end
|
|
98
100
|
|
|
99
101
|
def snapshots_json(tags: common_tags)
|
|
100
|
-
output = run(["snapshots", "--json"] +
|
|
102
|
+
output = run(["snapshots", "--json"] + filter_tag_args(tags)).stdout
|
|
101
103
|
snapshots = JSON.parse(output)
|
|
102
104
|
required_tags = tags.compact
|
|
103
105
|
snapshots.select do |snapshot|
|
|
@@ -126,13 +128,15 @@ module KamalBackup
|
|
|
126
128
|
legacy_prefix = "databases/#{config.app_name}/#{adapter}/"
|
|
127
129
|
app = config.app_name.gsub(/[^A-Za-z0-9_.-]+/, "-")
|
|
128
130
|
database = database_name.to_s.gsub(/[^A-Za-z0-9_.-]+/, "-")
|
|
131
|
+
stable_prefix = database.empty? ? nil : "databases/#{app}/#{database}/#{adapter}."
|
|
129
132
|
flat_prefix = "databases-#{app}-#{adapter}-"
|
|
130
133
|
named_flat_prefix = database.empty? ? nil : "databases-#{app}-#{database}-#{adapter}-"
|
|
131
134
|
ls_json(snapshot).find do |entry|
|
|
132
135
|
next false unless entry["type"] == "file"
|
|
133
136
|
|
|
134
137
|
normalized = entry["path"].to_s.sub(%r{\A/+}, "")
|
|
135
|
-
normalized.start_with?(
|
|
138
|
+
(stable_prefix && normalized.start_with?(stable_prefix)) ||
|
|
139
|
+
normalized.start_with?(legacy_prefix) ||
|
|
136
140
|
File.basename(normalized).start_with?(flat_prefix) ||
|
|
137
141
|
(named_flat_prefix && File.basename(normalized).start_with?(named_flat_prefix))
|
|
138
142
|
end&.fetch("path")
|
|
@@ -181,10 +185,54 @@ module KamalBackup
|
|
|
181
185
|
end
|
|
182
186
|
|
|
183
187
|
private
|
|
188
|
+
def retention_tag_sets
|
|
189
|
+
database_retention_tag_sets + file_retention_tag_sets
|
|
190
|
+
end
|
|
191
|
+
|
|
192
|
+
def database_retention_tag_sets
|
|
193
|
+
config.databases.group_by(&:database_adapter).flat_map do |adapter, databases|
|
|
194
|
+
if databases.one?
|
|
195
|
+
# Pre-0.3 database snapshots did not include database:<name>, so keep
|
|
196
|
+
# the single-database filter broad enough for retention to prune them.
|
|
197
|
+
[common_tags + ["type:database", "adapter:#{adapter}"]]
|
|
198
|
+
else
|
|
199
|
+
databases.map do |database|
|
|
200
|
+
common_tags + ["type:database", "database:#{database.database_name}", "adapter:#{adapter}"]
|
|
201
|
+
end
|
|
202
|
+
end
|
|
203
|
+
end
|
|
204
|
+
end
|
|
205
|
+
|
|
206
|
+
def file_retention_tag_sets
|
|
207
|
+
config.backup_paths.any? ? [common_tags + ["type:files"]] : []
|
|
208
|
+
end
|
|
209
|
+
|
|
210
|
+
def retention_scope(tags)
|
|
211
|
+
tags.reject { |tag| tag == "kamal-backup" || tag.start_with?("app:") }.join(", ")
|
|
212
|
+
end
|
|
213
|
+
|
|
184
214
|
def tag_args(tags)
|
|
185
215
|
tags.compact.each_with_object([]) { |tag, args| args.concat(["--tag", tag]) }
|
|
186
216
|
end
|
|
187
217
|
|
|
218
|
+
def host_args
|
|
219
|
+
["--host", restic_host]
|
|
220
|
+
end
|
|
221
|
+
|
|
222
|
+
def restic_host
|
|
223
|
+
normalize_restic_host([config.app_name, config.accessory_name || "backup"].compact.join("-"))
|
|
224
|
+
end
|
|
225
|
+
|
|
226
|
+
def normalize_restic_host(value)
|
|
227
|
+
normalized = value.to_s.gsub(/[^A-Za-z0-9_.-]+/, "-").gsub(/\A-+|-+\z/, "")
|
|
228
|
+
normalized.empty? ? "kamal-backup" : normalized
|
|
229
|
+
end
|
|
230
|
+
|
|
231
|
+
def filter_tag_args(tags)
|
|
232
|
+
tags = tags.compact
|
|
233
|
+
tags.empty? ? [] : ["--tag", tags.join(",")]
|
|
234
|
+
end
|
|
235
|
+
|
|
188
236
|
def restic_env
|
|
189
237
|
config.env.each_with_object({}) do |(key, value), env|
|
|
190
238
|
env[key] = value if key.to_s.match?(RESTIC_ENV_PATTERN)
|
data/lib/kamal_backup/version.rb
CHANGED
metadata
CHANGED
|
@@ -1,14 +1,14 @@
|
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
|
2
2
|
name: kamal-backup
|
|
3
3
|
version: !ruby/object:Gem::Version
|
|
4
|
-
version: 0.3.0.
|
|
4
|
+
version: 0.3.0.beta5
|
|
5
5
|
platform: ruby
|
|
6
6
|
authors:
|
|
7
7
|
- crmne
|
|
8
8
|
autorequire:
|
|
9
9
|
bindir: exe
|
|
10
10
|
cert_chain: []
|
|
11
|
-
date: 2026-
|
|
11
|
+
date: 2026-06-02 00:00:00.000000000 Z
|
|
12
12
|
dependencies:
|
|
13
13
|
- !ruby/object:Gem::Dependency
|
|
14
14
|
name: thor
|