lvmsync 3.1.3 → 3.2.0
Sign up to get free protection for your applications and to get access to all the features.
- 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
|