kamal-backup 0.3.0.beta17 → 0.3.0.beta18
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 +1 -0
- data/lib/kamal_backup/restic.rb +83 -50
- 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: f7b7f6a104e974d738b46ed67b5ece749627d8d33737845f9e9e7ea0e921ce21
|
|
4
|
+
data.tar.gz: e95a651804aa74ec1146989f0db3428e4c8510dc247ef07383e8b0f3d0168f43
|
|
5
5
|
SHA512:
|
|
6
|
-
metadata.gz:
|
|
7
|
-
data.tar.gz:
|
|
6
|
+
metadata.gz: 447bbd9c378d92aef836e0f05cf751ef9b978121b9e3ff5d8675b943441f028aaa082809e9adf462d3380e6035e35dfd52cd74cac68c0ac6fef099632ff89429
|
|
7
|
+
data.tar.gz: 7f414a27f4c452371b9c88fb91ac7aece2bd9771d92ae835997487fa252aeb2f053955cce3a76741be12cd4f6fe31c7c206a2d2ccbdf356a595f34e5d007986b
|
data/lib/kamal_backup/cli.rb
CHANGED
|
@@ -503,6 +503,7 @@ 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."
|
|
506
507
|
puts "For most Rails apps, restore local and drill local can infer the development database, Active Storage path, and tmp state directory."
|
|
507
508
|
puts "Local restore and drill also require the restic binary on your machine."
|
|
508
509
|
puts "Create config/kamal-backup.local.yml only if you need to override those local defaults."
|
data/lib/kamal_backup/restic.rb
CHANGED
|
@@ -1,6 +1,7 @@
|
|
|
1
1
|
require "fileutils"
|
|
2
2
|
require "json"
|
|
3
3
|
require "open3"
|
|
4
|
+
require "tempfile"
|
|
4
5
|
require "time"
|
|
5
6
|
require_relative "command"
|
|
6
7
|
|
|
@@ -27,43 +28,49 @@ module KamalBackup
|
|
|
27
28
|
end
|
|
28
29
|
|
|
29
30
|
def backup_stream(command, filename:, tags:)
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
31
|
+
with_restic_env do |env|
|
|
32
|
+
restic_command = CommandSpec.new(
|
|
33
|
+
argv: ["restic", "backup"] + host_args + ["--stdin", "--stdin-filename", filename] + tag_args(common_tags + tags),
|
|
34
|
+
env: env
|
|
35
|
+
)
|
|
36
|
+
log("backing up stream as #{filename}")
|
|
37
|
+
pipe_commands(command, restic_command, producer_label: "dump", consumer_label: "restic backup")
|
|
38
|
+
end
|
|
36
39
|
end
|
|
37
40
|
|
|
38
41
|
def backup_file(path, filename:, tags:)
|
|
39
|
-
command =
|
|
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}")
|
|
42
|
+
command = nil
|
|
44
43
|
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
|
|
44
|
+
with_restic_env do |env|
|
|
45
|
+
command = CommandSpec.new(
|
|
46
|
+
argv: ["restic", "backup"] + host_args + ["--stdin", "--stdin-filename", filename] + tag_args(common_tags + tags),
|
|
47
|
+
env: env
|
|
48
|
+
)
|
|
49
|
+
log("backing up file content as #{filename}")
|
|
50
|
+
|
|
51
|
+
File.open(path, "rb") do |file|
|
|
52
|
+
output = Command.output
|
|
53
|
+
context = output&.command_start(command, redactor: redactor)
|
|
54
|
+
Open3.popen3(command.env, *command.argv) do |stdin, stdout, stderr, wait_thread|
|
|
55
|
+
stdout_reader = Thread.new { Command.collect_stream(stdout, command_output: output, context: context, stream: :stdout, redactor: redactor) }
|
|
56
|
+
stderr_reader = Thread.new { Command.collect_stream(stderr, command_output: output, context: context, stream: :stderr, redactor: redactor) }
|
|
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)
|
|
58
73
|
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)
|
|
67
74
|
end
|
|
68
75
|
end
|
|
69
76
|
rescue Errno::ENOENT => e
|
|
@@ -153,26 +160,31 @@ module KamalBackup
|
|
|
153
160
|
end
|
|
154
161
|
|
|
155
162
|
def pipe_dump_to_command(snapshot, filename, command)
|
|
156
|
-
|
|
157
|
-
|
|
163
|
+
with_restic_env do |env|
|
|
164
|
+
restic_command = CommandSpec.new(argv: ["restic", "dump", snapshot, filename], env: env)
|
|
165
|
+
pipe_commands(restic_command, command, producer_label: "restic dump", consumer_label: command.argv.first)
|
|
166
|
+
end
|
|
158
167
|
end
|
|
159
168
|
|
|
160
169
|
def write_dump_to_path(snapshot, filename, target_path)
|
|
161
|
-
command =
|
|
170
|
+
command = nil
|
|
162
171
|
target_path = File.expand_path(target_path)
|
|
163
172
|
FileUtils.mkdir_p(File.dirname(target_path))
|
|
164
173
|
temp_path = "#{target_path}.kamal-backup-#{$$}.tmp"
|
|
165
174
|
|
|
166
|
-
|
|
167
|
-
|
|
168
|
-
|
|
169
|
-
|
|
170
|
-
|
|
171
|
-
|
|
172
|
-
|
|
173
|
-
|
|
174
|
-
|
|
175
|
-
|
|
175
|
+
with_restic_env do |env|
|
|
176
|
+
command = CommandSpec.new(argv: ["restic", "dump", snapshot, filename], env: env)
|
|
177
|
+
output = Command.output
|
|
178
|
+
context = output&.command_start(command, redactor: redactor)
|
|
179
|
+
Open3.popen3(command.env, *command.argv) do |stdin, stdout, stderr, wait_thread|
|
|
180
|
+
stdin.close
|
|
181
|
+
stderr_reader = Thread.new { Command.collect_stream(stderr, command_output: output, context: context, stream: :stderr, redactor: redactor) }
|
|
182
|
+
File.open(temp_path, "wb") { |file| IO.copy_stream(stdout, file) }
|
|
183
|
+
err = stderr_reader.value
|
|
184
|
+
status = wait_thread.value
|
|
185
|
+
output&.command_exit(context, status.exitstatus)
|
|
186
|
+
raise_command_error(command, status, "", err) unless status.success?
|
|
187
|
+
end
|
|
176
188
|
end
|
|
177
189
|
File.rename(temp_path, target_path)
|
|
178
190
|
target_path
|
|
@@ -190,11 +202,13 @@ module KamalBackup
|
|
|
190
202
|
end
|
|
191
203
|
|
|
192
204
|
def run(args, log_output: true)
|
|
193
|
-
|
|
194
|
-
|
|
195
|
-
|
|
196
|
-
|
|
197
|
-
|
|
205
|
+
with_restic_env do |env|
|
|
206
|
+
Command.capture(
|
|
207
|
+
CommandSpec.new(argv: ["restic"] + args, env: env),
|
|
208
|
+
redactor: redactor,
|
|
209
|
+
log_output: log_output
|
|
210
|
+
)
|
|
211
|
+
end
|
|
198
212
|
end
|
|
199
213
|
|
|
200
214
|
def common_tags
|
|
@@ -256,6 +270,25 @@ module KamalBackup
|
|
|
256
270
|
end
|
|
257
271
|
end
|
|
258
272
|
|
|
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
|
+
|
|
259
292
|
def pipe_commands(producer, consumer, producer_label:, consumer_label:)
|
|
260
293
|
output = Command.output
|
|
261
294
|
producer_context = output&.command_start(producer, redactor: redactor)
|
data/lib/kamal_backup/version.rb
CHANGED