lvmsync 3.1.3 → 3.2.0
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.
- data/bin/lvmsync +67 -28
- metadata +4 -4
data/bin/lvmsync
CHANGED
@@ -28,7 +28,8 @@ include LVM::Helpers
|
|
28
28
|
|
29
29
|
def main()
|
30
30
|
# Parse me some options
|
31
|
-
options = {}
|
31
|
+
options = { :rsh => "ssh" }
|
32
|
+
|
32
33
|
OptionParser.new do |opts|
|
33
34
|
opts.banner = "Usage: lvmsync [options]"
|
34
35
|
opts.separator ""
|
@@ -40,19 +41,35 @@ def main()
|
|
40
41
|
opts.on("--server", "Run in server mode (deprecated; use '--apply -' instead)") do |v|
|
41
42
|
options[:server] = true
|
42
43
|
end
|
44
|
+
|
43
45
|
opts.on("-v", "--[no-]verbose",
|
44
|
-
"Run verbosely") { |v| options[:verbose] =
|
46
|
+
"Run verbosely") { |v| options[:verbose] = v }
|
47
|
+
|
48
|
+
opts.on("-q", "--[no-]quiet",
|
49
|
+
"Run quietly") { |v| options[:quiet] = v }
|
50
|
+
|
45
51
|
opts.on("-b <file>", "--snapback <file>",
|
46
52
|
"Make a backup snapshot file on the destination") do |v|
|
47
53
|
options[:snapback] = v
|
48
54
|
end
|
55
|
+
|
49
56
|
opts.on("-a", "--apply <file>",
|
50
57
|
"Apply mode: write the contents of a snapback file to a device") do |v|
|
51
58
|
options[:apply] = v
|
52
59
|
end
|
60
|
+
|
53
61
|
opts.on("-s", "--stdout", "Write output data to stdout rather than another lvmsync process") do |v|
|
54
62
|
options[:stdout] = true
|
55
63
|
end
|
64
|
+
|
65
|
+
opts.on("-r", "--data-source", "Read data blocks from a block device other than the snapshot origin") do |v|
|
66
|
+
options[:source] = v
|
67
|
+
end
|
68
|
+
|
69
|
+
opts.on("-e", "--rsh <command-string>", "Use specified command when invoking SSH") do |v|
|
70
|
+
options[:rsh] = v
|
71
|
+
end
|
72
|
+
|
56
73
|
opts.on("-V", "--version", "Print version of lvmsync") do |v|
|
57
74
|
begin
|
58
75
|
puts "lvmsync #{GVB.version}"
|
@@ -65,6 +82,11 @@ def main()
|
|
65
82
|
end
|
66
83
|
end.parse!
|
67
84
|
|
85
|
+
if options[:quiet] and options[:verbose]
|
86
|
+
$stderr.puts "I can't run quietly *and* verbosely at the same time!"
|
87
|
+
exit 1
|
88
|
+
end
|
89
|
+
|
68
90
|
if options[:apply]
|
69
91
|
if ARGV[0].nil?
|
70
92
|
$stderr.puts "No destination device specified."
|
@@ -73,7 +95,7 @@ def main()
|
|
73
95
|
options[:device] = ARGV[0]
|
74
96
|
run_apply(options)
|
75
97
|
elsif options[:server]
|
76
|
-
$stderr.puts "--server is deprecated; please use '--apply -' instead"
|
98
|
+
$stderr.puts "--server is deprecated; please use '--apply -' instead" unless opts[:quiet]
|
77
99
|
if (ARGV[0].nil?)
|
78
100
|
$stderr.puts "No destination block device specified. WTF?"
|
79
101
|
exit 1
|
@@ -176,8 +198,6 @@ def run_client(opts)
|
|
176
198
|
exit 1
|
177
199
|
end
|
178
200
|
|
179
|
-
$stderr.puts "Origin device: #{lv.origin.path}" if opts[:verbose]
|
180
|
-
|
181
201
|
# Since, in principle, we're not supposed to be reading from snapshot
|
182
202
|
# devices directly, the kernel makes no attempt to make the device's read
|
183
203
|
# cache stay in sync with the actual state of the device. As a result,
|
@@ -187,12 +207,15 @@ def run_client(opts)
|
|
187
207
|
|
188
208
|
snapback = opts[:snapback] ? "--snapback #{opts[:snapback]}" : ''
|
189
209
|
|
210
|
+
source = opts[:source] || lv.origin.path
|
211
|
+
$stderr.puts "Data source: #{source}" if opts[:verbose]
|
212
|
+
|
190
213
|
if opts[:stdout]
|
191
|
-
dump_changes(lv, $stdout, opts)
|
214
|
+
dump_changes(lv, source, $stdout, opts)
|
192
215
|
else
|
193
216
|
verbose = opts[:verbose] ? '-v' : ''
|
194
217
|
server_cmd = if desthost
|
195
|
-
"
|
218
|
+
"#{opts[:rsh]} #{desthost} lvmsync --apply - #{snapback} #{verbose} #{destdev}"
|
196
219
|
else
|
197
220
|
"#{$0} --apply - #{snapback} #{verbose} #{destdev}"
|
198
221
|
end
|
@@ -201,24 +224,38 @@ def run_client(opts)
|
|
201
224
|
errors = nil
|
202
225
|
|
203
226
|
Open3.popen3(server_cmd) do |stdin_fd, stdout_fd, stderr_fd, wait_thr|
|
204
|
-
|
205
|
-
|
206
|
-
|
207
|
-
|
208
|
-
|
209
|
-
|
227
|
+
fds = [stdout_fd, stderr_fd]
|
228
|
+
|
229
|
+
dump_changes(lv, source, stdin_fd, opts) do
|
230
|
+
# Remember that this fires between *every* block sent to the
|
231
|
+
# receiver, so don't do anything particularly slow in here!
|
232
|
+
until (active_fds = IO.select(fds, [], [], 0)).nil?
|
233
|
+
active_fds[0].each do |fd|
|
210
234
|
begin
|
211
|
-
$stderr.puts "\e[2K\rremote:#{fd.readline}"
|
235
|
+
$stderr.puts "\e[2K\rremote:#{fd.readline}" unless opts[:quiet]
|
212
236
|
rescue EOFError, Errno::EPIPE
|
213
|
-
|
237
|
+
fd.close
|
238
|
+
fds.delete(fd)
|
214
239
|
end
|
215
240
|
end
|
216
241
|
end
|
217
242
|
end
|
243
|
+
|
218
244
|
stdin_fd.close
|
219
|
-
|
220
|
-
|
221
|
-
|
245
|
+
|
246
|
+
# Read any residual data that might be left in the stdout/stderr of
|
247
|
+
# the remote; we've got to do this with a timeout because of
|
248
|
+
# OpenSSH, which, when used in ControlMaster ("multiplexing") mode,
|
249
|
+
# holds open stderr, meaning that IO.select will never indicate
|
250
|
+
# that stderr is finished.
|
251
|
+
until (active_fds = IO.select(fds, [], [], 0.1)).nil?
|
252
|
+
active_fds[0].each do |fd|
|
253
|
+
begin
|
254
|
+
$stderr.puts "\e[2K\rremote:#{fd.readline}" unless opts[:quiet]
|
255
|
+
rescue EOFError, Errno::EPIPE
|
256
|
+
fd.close
|
257
|
+
fds.delete(fd)
|
258
|
+
end
|
222
259
|
end
|
223
260
|
end
|
224
261
|
exit_status = wait_thr.value if wait_thr
|
@@ -230,23 +267,23 @@ def run_client(opts)
|
|
230
267
|
end
|
231
268
|
end
|
232
269
|
|
233
|
-
def dump_changes(
|
270
|
+
def dump_changes(snapshot, source, outfd, opts)
|
234
271
|
outfd.puts PROTOCOL_VERSION
|
235
272
|
|
236
273
|
start_time = Time.now
|
237
274
|
xfer_count = 0
|
238
275
|
xfer_size = 0
|
239
276
|
total_size = 0
|
240
|
-
change_count =
|
277
|
+
change_count = snapshot.changes.length
|
241
278
|
|
242
|
-
File.open(
|
243
|
-
|
279
|
+
File.open(source, 'r') do |origindev|
|
280
|
+
snapshot.changes.each do |r|
|
244
281
|
xfer_count += 1
|
245
282
|
chunk_size = r.last - r.first + 1
|
246
283
|
xfer_size += chunk_size
|
247
284
|
|
248
285
|
$stderr.puts "Sending chunk #{r.to_s}..." if opts[:verbose]
|
249
|
-
$stderr.puts "Seeking to #{r.first} in #{
|
286
|
+
$stderr.puts "Seeking to #{r.first} in #{source}" if opts[:verbose]
|
250
287
|
|
251
288
|
origindev.seek(r.first, IO::SEEK_SET)
|
252
289
|
|
@@ -260,7 +297,7 @@ def dump_changes(lv, outfd, opts)
|
|
260
297
|
end
|
261
298
|
|
262
299
|
# Progress bar!
|
263
|
-
if xfer_count % 100 == 50
|
300
|
+
if xfer_count % 100 == 50 and !opts[:quiet]
|
264
301
|
$stderr.printf "\e[2K\rSending chunk %i of %i, %.2fMB/s",
|
265
302
|
xfer_count,
|
266
303
|
change_count,
|
@@ -274,11 +311,13 @@ def dump_changes(lv, outfd, opts)
|
|
274
311
|
total_size = origindev.tell
|
275
312
|
end
|
276
313
|
|
277
|
-
|
278
|
-
|
314
|
+
unless opts[:quiet]
|
315
|
+
$stderr.printf "\rTransferred %i bytes in %.2f seconds\n",
|
316
|
+
xfer_size, Time.now - start_time
|
279
317
|
|
280
|
-
|
281
|
-
|
318
|
+
$stderr.printf "You transferred your changes %.2fx faster than a full dd!\n",
|
319
|
+
total_size.to_f / xfer_size
|
320
|
+
end
|
282
321
|
end
|
283
322
|
|
284
323
|
# Take a device name in any number of different formats and return a [VG, LV] pair.
|
metadata
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: lvmsync
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 3.
|
4
|
+
version: 3.2.0
|
5
5
|
prerelease:
|
6
6
|
platform: ruby
|
7
7
|
authors:
|
@@ -9,7 +9,7 @@ authors:
|
|
9
9
|
autorequire:
|
10
10
|
bindir: bin
|
11
11
|
cert_chain: []
|
12
|
-
date: 2014-10-
|
12
|
+
date: 2014-10-14 00:00:00.000000000 Z
|
13
13
|
dependencies:
|
14
14
|
- !ruby/object:Gem::Dependency
|
15
15
|
name: git-version-bump
|
@@ -238,7 +238,7 @@ required_ruby_version: !ruby/object:Gem::Requirement
|
|
238
238
|
version: '0'
|
239
239
|
segments:
|
240
240
|
- 0
|
241
|
-
hash: -
|
241
|
+
hash: -3943591993715626870
|
242
242
|
required_rubygems_version: !ruby/object:Gem::Requirement
|
243
243
|
none: false
|
244
244
|
requirements:
|
@@ -247,7 +247,7 @@ required_rubygems_version: !ruby/object:Gem::Requirement
|
|
247
247
|
version: '0'
|
248
248
|
segments:
|
249
249
|
- 0
|
250
|
-
hash: -
|
250
|
+
hash: -3943591993715626870
|
251
251
|
requirements: []
|
252
252
|
rubyforge_project:
|
253
253
|
rubygems_version: 1.8.23
|