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.
Files changed (2) hide show
  1. data/bin/lvmsync +67 -28
  2. 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] = true }
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
- "ssh #{desthost} lvmsync --apply - #{snapback} #{verbose} #{destdev}"
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
- dump_changes(lv, stdin_fd, opts) do
205
- more_to_read = true
206
- while more_to_read
207
- more_to_read = false
208
- (IO.select([stdout_fd, stderr_fd], [], [], 0) || [[]])[0].each do |fd|
209
- more_to_read = true
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
- # lolwhateva
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
- [stderr_fd, stdout_fd].each do |fd|
220
- until fd.eof?
221
- $stderr.puts "\e[2K\rremote:#{fd.readline}"
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(lv, outfd, opts)
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 = lv.changes.length
277
+ change_count = snapshot.changes.length
241
278
 
242
- File.open(lv.origin.path, 'r') do |origindev|
243
- lv.changes.each do |r|
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 #{lv.origin.path}" if opts[:verbose]
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
- $stderr.printf "\rTransferred %i bytes in %.2f seconds\n",
278
- xfer_size, Time.now - start_time
314
+ unless opts[:quiet]
315
+ $stderr.printf "\rTransferred %i bytes in %.2f seconds\n",
316
+ xfer_size, Time.now - start_time
279
317
 
280
- $stderr.printf "You transferred your changes %.2fx faster than a full dd!\n",
281
- total_size.to_f / xfer_size
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.1.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 00:00:00.000000000 Z
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: -1253006935794364430
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: -1253006935794364430
250
+ hash: -3943591993715626870
251
251
  requirements: []
252
252
  rubyforge_project:
253
253
  rubygems_version: 1.8.23