kamal-backup 0.3.0.beta18 → 0.3.0.beta19
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/cli.rb +0 -1
- data/lib/kamal_backup/redactor.rb +2 -1
- data/lib/kamal_backup/restic.rb +50 -83
- 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: f6e2e4d7d599e994a6dd0383c3bb1eb7b7f240a67af17a78eedbefe7b23540fb
|
|
4
|
+
data.tar.gz: 663af541d2ceb9b229ff9c213fbe5468cb441de5b3225dfaf308e7690125a2de
|
|
5
5
|
SHA512:
|
|
6
|
-
metadata.gz:
|
|
7
|
-
data.tar.gz:
|
|
6
|
+
metadata.gz: 623e8fc575ff63a2f35f29bec68a59ca8e6f0ae6990ba6f22d06753387577888e9160392efb7e39e4fe0fc7a6bc38e96be9e45cf6c8b6c252d0f701d1e3b9eaa
|
|
7
|
+
data.tar.gz: 2fbf13c515b41051cfb203e356f816717c4f72504ce38622df9adb36ced5c5a7799a953186323e6b7a340f1cc1c5730fe54b20776fac287793bd108b37eb969b
|
data/lib/kamal_backup/cli.rb
CHANGED
|
@@ -503,7 +503,6 @@ module KamalBackup
|
|
|
503
503
|
puts deploy_snippet
|
|
504
504
|
puts
|
|
505
505
|
puts "The accessory runs scheduled database and file backups with backup.schedule."
|
|
506
|
-
puts "kamal-backup passes RESTIC_PASSWORD to restic through a private temporary password file."
|
|
507
506
|
puts "For most Rails apps, restore local and drill local can infer the development database, Active Storage path, and tmp state directory."
|
|
508
507
|
puts "Local restore and drill also require the restic binary on your machine."
|
|
509
508
|
puts "Create config/kamal-backup.local.yml only if you need to override those local defaults."
|
|
@@ -1,6 +1,7 @@
|
|
|
1
1
|
module KamalBackup
|
|
2
2
|
class Redactor
|
|
3
3
|
SECRET_KEY_PATTERN = /(pass|password|secret|token|key|credential|authorization)/i
|
|
4
|
+
SENSITIVE_KEY_PATTERN = /(?:pass|password|secret|token|key|credential|authorization)|\A(?:user|username|pguser|.*_user|.*_username)\z/i
|
|
4
5
|
REDACTED = "[REDACTED]"
|
|
5
6
|
|
|
6
7
|
def initialize(secret_values: [], env: ENV)
|
|
@@ -16,7 +17,7 @@ module KamalBackup
|
|
|
16
17
|
|
|
17
18
|
def redact_value(key, value)
|
|
18
19
|
return nil if value.nil?
|
|
19
|
-
return REDACTED if key.to_s.match?(
|
|
20
|
+
return REDACTED if key.to_s.match?(SENSITIVE_KEY_PATTERN)
|
|
20
21
|
|
|
21
22
|
redact_string(value.to_s)
|
|
22
23
|
end
|
data/lib/kamal_backup/restic.rb
CHANGED
|
@@ -1,7 +1,6 @@
|
|
|
1
1
|
require "fileutils"
|
|
2
2
|
require "json"
|
|
3
3
|
require "open3"
|
|
4
|
-
require "tempfile"
|
|
5
4
|
require "time"
|
|
6
5
|
require_relative "command"
|
|
7
6
|
|
|
@@ -28,49 +27,43 @@ module KamalBackup
|
|
|
28
27
|
end
|
|
29
28
|
|
|
30
29
|
def backup_stream(command, filename:, tags:)
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
pipe_commands(command, restic_command, producer_label: "dump", consumer_label: "restic backup")
|
|
38
|
-
end
|
|
30
|
+
restic_command = CommandSpec.new(
|
|
31
|
+
argv: ["restic", "backup"] + host_args + ["--stdin", "--stdin-filename", filename] + tag_args(common_tags + tags),
|
|
32
|
+
env: restic_env
|
|
33
|
+
)
|
|
34
|
+
log("backing up stream as #{filename}")
|
|
35
|
+
pipe_commands(command, restic_command, producer_label: "dump", consumer_label: "restic backup")
|
|
39
36
|
end
|
|
40
37
|
|
|
41
38
|
def backup_file(path, filename:, tags:)
|
|
42
|
-
command =
|
|
39
|
+
command = CommandSpec.new(
|
|
40
|
+
argv: ["restic", "backup"] + host_args + ["--stdin", "--stdin-filename", filename] + tag_args(common_tags + tags),
|
|
41
|
+
env: restic_env
|
|
42
|
+
)
|
|
43
|
+
log("backing up file content as #{filename}")
|
|
43
44
|
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
copy_error = nil
|
|
58
|
-
begin
|
|
59
|
-
IO.copy_stream(file, stdin)
|
|
60
|
-
rescue Errno::EPIPE => e
|
|
61
|
-
copy_error = e
|
|
62
|
-
ensure
|
|
63
|
-
stdin.close unless stdin.closed?
|
|
64
|
-
end
|
|
65
|
-
out = stdout_reader.value
|
|
66
|
-
err = stderr_reader.value
|
|
67
|
-
status = wait_thread.value
|
|
68
|
-
output&.command_exit(context, status.exitstatus)
|
|
69
|
-
raise_command_error(command, status, out, err) unless status.success?
|
|
70
|
-
raise_stream_error(command, copy_error, out, err) if copy_error
|
|
71
|
-
|
|
72
|
-
CommandResult.new(stdout: out, stderr: err, status: status.exitstatus)
|
|
45
|
+
File.open(path, "rb") do |file|
|
|
46
|
+
output = Command.output
|
|
47
|
+
context = output&.command_start(command, redactor: redactor)
|
|
48
|
+
Open3.popen3(command.env, *command.argv) do |stdin, stdout, stderr, wait_thread|
|
|
49
|
+
stdout_reader = Thread.new { Command.collect_stream(stdout, command_output: output, context: context, stream: :stdout, redactor: redactor) }
|
|
50
|
+
stderr_reader = Thread.new { Command.collect_stream(stderr, command_output: output, context: context, stream: :stderr, redactor: redactor) }
|
|
51
|
+
copy_error = nil
|
|
52
|
+
begin
|
|
53
|
+
IO.copy_stream(file, stdin)
|
|
54
|
+
rescue Errno::EPIPE => e
|
|
55
|
+
copy_error = e
|
|
56
|
+
ensure
|
|
57
|
+
stdin.close unless stdin.closed?
|
|
73
58
|
end
|
|
59
|
+
out = stdout_reader.value
|
|
60
|
+
err = stderr_reader.value
|
|
61
|
+
status = wait_thread.value
|
|
62
|
+
output&.command_exit(context, status.exitstatus)
|
|
63
|
+
raise_command_error(command, status, out, err) unless status.success?
|
|
64
|
+
raise_stream_error(command, copy_error, out, err) if copy_error
|
|
65
|
+
|
|
66
|
+
CommandResult.new(stdout: out, stderr: err, status: status.exitstatus)
|
|
74
67
|
end
|
|
75
68
|
end
|
|
76
69
|
rescue Errno::ENOENT => e
|
|
@@ -160,31 +153,26 @@ module KamalBackup
|
|
|
160
153
|
end
|
|
161
154
|
|
|
162
155
|
def pipe_dump_to_command(snapshot, filename, command)
|
|
163
|
-
|
|
164
|
-
|
|
165
|
-
pipe_commands(restic_command, command, producer_label: "restic dump", consumer_label: command.argv.first)
|
|
166
|
-
end
|
|
156
|
+
restic_command = CommandSpec.new(argv: ["restic", "dump", snapshot, filename], env: restic_env)
|
|
157
|
+
pipe_commands(restic_command, command, producer_label: "restic dump", consumer_label: command.argv.first)
|
|
167
158
|
end
|
|
168
159
|
|
|
169
160
|
def write_dump_to_path(snapshot, filename, target_path)
|
|
170
|
-
command =
|
|
161
|
+
command = CommandSpec.new(argv: ["restic", "dump", snapshot, filename], env: restic_env)
|
|
171
162
|
target_path = File.expand_path(target_path)
|
|
172
163
|
FileUtils.mkdir_p(File.dirname(target_path))
|
|
173
164
|
temp_path = "#{target_path}.kamal-backup-#{$$}.tmp"
|
|
174
165
|
|
|
175
|
-
|
|
176
|
-
|
|
177
|
-
|
|
178
|
-
|
|
179
|
-
|
|
180
|
-
|
|
181
|
-
|
|
182
|
-
|
|
183
|
-
|
|
184
|
-
|
|
185
|
-
output&.command_exit(context, status.exitstatus)
|
|
186
|
-
raise_command_error(command, status, "", err) unless status.success?
|
|
187
|
-
end
|
|
166
|
+
output = Command.output
|
|
167
|
+
context = output&.command_start(command, redactor: redactor)
|
|
168
|
+
Open3.popen3(command.env, *command.argv) do |stdin, stdout, stderr, wait_thread|
|
|
169
|
+
stdin.close
|
|
170
|
+
stderr_reader = Thread.new { Command.collect_stream(stderr, command_output: output, context: context, stream: :stderr, redactor: redactor) }
|
|
171
|
+
File.open(temp_path, "wb") { |file| IO.copy_stream(stdout, file) }
|
|
172
|
+
err = stderr_reader.value
|
|
173
|
+
status = wait_thread.value
|
|
174
|
+
output&.command_exit(context, status.exitstatus)
|
|
175
|
+
raise_command_error(command, status, "", err) unless status.success?
|
|
188
176
|
end
|
|
189
177
|
File.rename(temp_path, target_path)
|
|
190
178
|
target_path
|
|
@@ -202,13 +190,11 @@ module KamalBackup
|
|
|
202
190
|
end
|
|
203
191
|
|
|
204
192
|
def run(args, log_output: true)
|
|
205
|
-
|
|
206
|
-
|
|
207
|
-
|
|
208
|
-
|
|
209
|
-
|
|
210
|
-
)
|
|
211
|
-
end
|
|
193
|
+
Command.capture(
|
|
194
|
+
CommandSpec.new(argv: ["restic"] + args, env: restic_env),
|
|
195
|
+
redactor: redactor,
|
|
196
|
+
log_output: log_output
|
|
197
|
+
)
|
|
212
198
|
end
|
|
213
199
|
|
|
214
200
|
def common_tags
|
|
@@ -270,25 +256,6 @@ module KamalBackup
|
|
|
270
256
|
end
|
|
271
257
|
end
|
|
272
258
|
|
|
273
|
-
def with_restic_env
|
|
274
|
-
env = restic_env
|
|
275
|
-
password_file = nil
|
|
276
|
-
|
|
277
|
-
if env["RESTIC_PASSWORD_FILE"] || env["RESTIC_PASSWORD_COMMAND"]
|
|
278
|
-
env.delete("RESTIC_PASSWORD")
|
|
279
|
-
elsif env["RESTIC_PASSWORD"]
|
|
280
|
-
password_file = Tempfile.new("kamal-backup-restic-password")
|
|
281
|
-
password_file.write(env.delete("RESTIC_PASSWORD"))
|
|
282
|
-
password_file.flush
|
|
283
|
-
File.chmod(0o600, password_file.path)
|
|
284
|
-
env["RESTIC_PASSWORD_FILE"] = password_file.path
|
|
285
|
-
end
|
|
286
|
-
|
|
287
|
-
yield env
|
|
288
|
-
ensure
|
|
289
|
-
password_file&.close!
|
|
290
|
-
end
|
|
291
|
-
|
|
292
259
|
def pipe_commands(producer, consumer, producer_label:, consumer_label:)
|
|
293
260
|
output = Command.output
|
|
294
261
|
producer_context = output&.command_start(producer, redactor: redactor)
|
data/lib/kamal_backup/version.rb
CHANGED