lvmsync 3.2.0 → 3.2.1

Sign up to get free protection for your applications and to get access to all the features.
Files changed (5) hide show
  1. checksums.yaml +7 -0
  2. data/README.md +2 -2
  3. data/bin/lvmsync +53 -35
  4. data/lib/vgcfgbackup.treetop +1 -1
  5. metadata +38 -70
checksums.yaml ADDED
@@ -0,0 +1,7 @@
1
+ ---
2
+ SHA1:
3
+ metadata.gz: f78e30fa37ccf5150643fabe206713fe18750271
4
+ data.tar.gz: 0c0416476d7005349864889700f76541ad1eda45
5
+ SHA512:
6
+ metadata.gz: 8bdf6db2b0e37ce28af97557c0c3580b227379991b2abc0cdec656ca88333a51c48b75d2d68fd8cf826b4a0947791ea63ffebf25fb55efc11f94c641b3328741
7
+ data.tar.gz: 98f9474e839e61d8f6a17be2b9bd8976715cafa594c43ba066a1a9b5f6c18ae265b7da3577e415b476f6c7812fc521e02b9cfe4c43d17d2217c6333306080402
data/README.md CHANGED
@@ -107,7 +107,7 @@ Let's say you've got an LV, named `vmsrv1/somevm`, and you'd like to
107
107
  synchronise it to a new VM server, named `vmsrv2`. Assuming that `lvmsync` is
108
108
  installed on `vmsrv2` and `vmsrv2` has an LV named `vmsrv2/somevm` large
109
109
  enough to take the data, the following will do the trick rather nicely (all
110
- commands should be run on `vmsrv1`:
110
+ commands should be run on `vmsrv1`):
111
111
 
112
112
  # Take a snapshot before we do anything, so LVM will record all changes
113
113
  # made while we're doing the initial sync
@@ -168,7 +168,7 @@ each hour):
168
168
 
169
169
  This will produce files in /var/snapbacks named `somevm.<date-time>`. You
170
170
  need to create the `somevm-snapback-new` snapshot before you start
171
- `lvmsync`, so that you can guarantee no changes won't get noticed.
171
+ `lvmsync`, so that you can guarantee no changes will go unnoticed.
172
172
 
173
173
  There are some fairly large caveats to this method -- the LV will still be
174
174
  collecting writes while you're transferring the snapshots, so you won't get
data/bin/lvmsync CHANGED
@@ -43,10 +43,13 @@ def main()
43
43
  end
44
44
 
45
45
  opts.on("-v", "--[no-]verbose",
46
- "Run verbosely") { |v| options[:verbose] = v }
46
+ "Run verbosely") { |v| $verbose = v }
47
+
48
+ opts.on("-d", "--[no-]debug",
49
+ "Print debugging information") { |v| $debug = v }
47
50
 
48
51
  opts.on("-q", "--[no-]quiet",
49
- "Run quietly") { |v| options[:quiet] = v }
52
+ "Run quietly") { |v| $quiet = v }
50
53
 
51
54
  opts.on("-b <file>", "--snapback <file>",
52
55
  "Make a backup snapshot file on the destination") do |v|
@@ -75,49 +78,42 @@ def main()
75
78
  puts "lvmsync #{GVB.version}"
76
79
  exit 0
77
80
  rescue GVB::VersionUnobtainable
78
- $stderr.puts "Unable to determine lvmsync version."
79
- $stderr.puts "Install lvmsync as a gem, or run it from within a git checkout"
80
- exit 1
81
+ fatal "Unable to determine lvmsync version.\n" +
82
+ "Install lvmsync as a gem, or run it from within a git checkout"
81
83
  end
82
84
  end
83
85
  end.parse!
84
86
 
85
- if options[:quiet] and options[:verbose]
86
- $stderr.puts "I can't run quietly *and* verbosely at the same time!"
87
- exit 1
87
+ if $quiet and ($verbose or $debug)
88
+ fatal "I can't run quietly *and* verbosely at the same time!"
88
89
  end
89
90
 
90
91
  if options[:apply]
91
92
  if ARGV[0].nil?
92
- $stderr.puts "No destination device specified."
93
- exit 1
93
+ fatal "No destination device specified."
94
94
  end
95
95
  options[:device] = ARGV[0]
96
96
  run_apply(options)
97
97
  elsif options[:server]
98
- $stderr.puts "--server is deprecated; please use '--apply -' instead" unless opts[:quiet]
98
+ info "--server is deprecated; please use '--apply -' instead"
99
99
  if (ARGV[0].nil?)
100
- $stderr.puts "No destination block device specified. WTF?"
101
- exit 1
100
+ fatal "No destination block device specified. WTF?"
102
101
  end
103
102
  options[:apply] = '-'
104
103
  options[:device] = ARGV[0]
105
104
  run_apply(options)
106
105
  else
107
106
  if ARGV[0].nil?
108
- $stderr.puts "ERROR: No snapshot specified. Exiting."
109
- exit 1
107
+ fatal "No snapshot specified. Exiting. Do you need --help?"
110
108
  end
111
109
  options[:snapdev] = ARGV[0]
112
110
 
113
111
  if options[:stdout] and options[:snapback]
114
- $stderr.puts "--snapback cannot be used with --stdout"
115
- exit 1
112
+ fatal "--snapback cannot be used with --stdout"
116
113
  end
117
114
 
118
115
  if (options[:stdout].nil? and ARGV[1].nil?)
119
- $stderr.puts "No destination specified."
120
- exit 1
116
+ fatal "No destination specified."
121
117
  end
122
118
  if options[:stdout].nil?
123
119
  dev, host = ARGV[1].split(':', 2).reverse
@@ -143,18 +139,19 @@ end
143
139
  def process_dumpdata(instream, destdev, snapback = nil, opts = {})
144
140
  handshake = instream.readline.chomp
145
141
  unless handshake == PROTOCOL_VERSION
146
- $stderr.puts "Handshake failed; protocol mismatch? (saw '#{handshake}' expected '#{PROTOCOL_VERSION}'"
147
- exit 1
142
+ fatal "Handshake failed; protocol mismatch? (saw '#{handshake}' expected '#{PROTOCOL_VERSION}'"
148
143
  end
149
144
 
150
145
  snapback.puts handshake if snapback
151
146
 
147
+ verbose "Writing changed data to #{destdev.inspect}"
152
148
  File.open(destdev, 'w+') do |dest|
153
149
  while header = instream.read(12)
154
150
  offset, chunksize = header.unpack("QN")
155
151
  offset = ntohq(offset)
156
152
 
157
153
  begin
154
+ debug "Seeking to #{offset}"
158
155
  dest.seek offset
159
156
  rescue Errno::EINVAL
160
157
  # In certain rare circumstances, we want to transfer a block
@@ -164,6 +161,8 @@ def process_dumpdata(instream, destdev, snapback = nil, opts = {})
164
161
  # if you didn't notice that your dd shit itself, it's unlikely
165
162
  # you're going to notice now.
166
163
 
164
+ info "Write occured past end of device"
165
+
167
166
  # Skip the chunk of data
168
167
  instream.read(chunksize)
169
168
  # Go to the next chunk
@@ -173,9 +172,12 @@ def process_dumpdata(instream, destdev, snapback = nil, opts = {})
173
172
  if snapback
174
173
  snapback.write(header)
175
174
  snapback.write dest.read(chunksize)
175
+ # Got to back to where we were before, since the read from dest
176
+ # has advanced the file pointer by `chunksize`
176
177
  dest.seek offset
177
178
  end
178
179
  dest.write instream.read(chunksize)
180
+ debug "Wrote #{chunksize} bytes at #{offset}"
179
181
  end
180
182
  end
181
183
  end
@@ -189,13 +191,11 @@ def run_client(opts)
189
191
  lv = begin
190
192
  LVM::LogicalVolume.new(snapshot)
191
193
  rescue RuntimeError => e
192
- $stderr.puts "#{snapshot}: could not find logical volume (#{e.message})"
193
- exit 1
194
+ fatal "#{snapshot}: could not find logical volume (#{e.message})"
194
195
  end
195
196
 
196
197
  unless lv.snapshot?
197
- $stderr.puts "#{snapshot}: Not a snapshot device"
198
- exit 1
198
+ fatal "#{snapshot}: Not a snapshot device"
199
199
  end
200
200
 
201
201
  # Since, in principle, we're not supposed to be reading from snapshot
@@ -208,14 +208,16 @@ def run_client(opts)
208
208
  snapback = opts[:snapback] ? "--snapback #{opts[:snapback]}" : ''
209
209
 
210
210
  source = opts[:source] || lv.origin.path
211
- $stderr.puts "Data source: #{source}" if opts[:verbose]
211
+ verbose "Data source: #{source}"
212
212
 
213
213
  if opts[:stdout]
214
214
  dump_changes(lv, source, $stdout, opts)
215
215
  else
216
- verbose = opts[:verbose] ? '-v' : ''
216
+ verbose = $verbose ? '-v' : ''
217
+ debug = $debug ? '-d' : ''
218
+
217
219
  server_cmd = if desthost
218
- "#{opts[:rsh]} #{desthost} lvmsync --apply - #{snapback} #{verbose} #{destdev}"
220
+ "#{opts[:rsh]} #{desthost} lvmsync --apply - #{snapback} #{verbose} #{debug} #{destdev}"
219
221
  else
220
222
  "#{$0} --apply - #{snapback} #{verbose} #{destdev}"
221
223
  end
@@ -232,7 +234,7 @@ def run_client(opts)
232
234
  until (active_fds = IO.select(fds, [], [], 0)).nil?
233
235
  active_fds[0].each do |fd|
234
236
  begin
235
- $stderr.puts "\e[2K\rremote:#{fd.readline}" unless opts[:quiet]
237
+ info "\e[2K\rremote:#{fd.readline}"
236
238
  rescue EOFError, Errno::EPIPE
237
239
  fd.close
238
240
  fds.delete(fd)
@@ -251,7 +253,7 @@ def run_client(opts)
251
253
  until (active_fds = IO.select(fds, [], [], 0.1)).nil?
252
254
  active_fds[0].each do |fd|
253
255
  begin
254
- $stderr.puts "\e[2K\rremote:#{fd.readline}" unless opts[:quiet]
256
+ info "\e[2K\rremote:#{fd.readline}"
255
257
  rescue EOFError, Errno::EPIPE
256
258
  fd.close
257
259
  fds.delete(fd)
@@ -262,7 +264,7 @@ def run_client(opts)
262
264
  end
263
265
 
264
266
  if (exit_status or $?).exitstatus != 0
265
- $stderr.puts "APPLY FAILED."
267
+ fatal "APPLY FAILED."
266
268
  end
267
269
  end
268
270
  end
@@ -282,8 +284,7 @@ def dump_changes(snapshot, source, outfd, opts)
282
284
  chunk_size = r.last - r.first + 1
283
285
  xfer_size += chunk_size
284
286
 
285
- $stderr.puts "Sending chunk #{r.to_s}..." if opts[:verbose]
286
- $stderr.puts "Seeking to #{r.first} in #{source}" if opts[:verbose]
287
+ debug "Sending chunk #{r.to_s}..."
287
288
 
288
289
  origindev.seek(r.first, IO::SEEK_SET)
289
290
 
@@ -297,7 +298,7 @@ def dump_changes(snapshot, source, outfd, opts)
297
298
  end
298
299
 
299
300
  # Progress bar!
300
- if xfer_count % 100 == 50 and !opts[:quiet]
301
+ if xfer_count % 100 == 50 and !$quiet
301
302
  $stderr.printf "\e[2K\rSending chunk %i of %i, %.2fMB/s",
302
303
  xfer_count,
303
304
  change_count,
@@ -311,7 +312,7 @@ def dump_changes(snapshot, source, outfd, opts)
311
312
  total_size = origindev.tell
312
313
  end
313
314
 
314
- unless opts[:quiet]
315
+ unless $quiet
315
316
  $stderr.printf "\rTransferred %i bytes in %.2f seconds\n",
316
317
  xfer_size, Time.now - start_time
317
318
 
@@ -336,4 +337,21 @@ def parse_snapshot_name(origname)
336
337
  end
337
338
  end
338
339
 
340
+ def debug(s)
341
+ $stderr.puts s if $debug
342
+ end
343
+
344
+ def verbose(s)
345
+ $stderr.puts s if $verbose or $debug
346
+ end
347
+
348
+ def info(s)
349
+ $stderr.puts s unless $quiet
350
+ end
351
+
352
+ def fatal(s, status=1)
353
+ $stderr.puts "FATAL ERROR: #{s}"
354
+ exit status
355
+ end
356
+
339
357
  main
@@ -24,7 +24,7 @@ grammar VgCfgBackup
24
24
  end
25
25
 
26
26
  rule list
27
- "[" space? ((string / integer) ", " / (string / integer))* space? "]" <List>
27
+ "[" space? ((string / integer) "," space? / (string / integer))* space? "]" <List>
28
28
  end
29
29
 
30
30
  rule space
metadata CHANGED
@@ -1,206 +1,181 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: lvmsync
3
3
  version: !ruby/object:Gem::Version
4
- version: 3.2.0
5
- prerelease:
4
+ version: 3.2.1
6
5
  platform: ruby
7
6
  authors:
8
7
  - Matt Palmer
9
8
  autorequire:
10
9
  bindir: bin
11
10
  cert_chain: []
12
- date: 2014-10-14 00:00:00.000000000 Z
11
+ date: 2015-02-25 00:00:00.000000000 Z
13
12
  dependencies:
14
13
  - !ruby/object:Gem::Dependency
15
14
  name: git-version-bump
16
15
  requirement: !ruby/object:Gem::Requirement
17
- none: false
18
16
  requirements:
19
- - - ~>
17
+ - - "~>"
20
18
  - !ruby/object:Gem::Version
21
19
  version: '0.10'
22
20
  type: :runtime
23
21
  prerelease: false
24
22
  version_requirements: !ruby/object:Gem::Requirement
25
- none: false
26
23
  requirements:
27
- - - ~>
24
+ - - "~>"
28
25
  - !ruby/object:Gem::Version
29
26
  version: '0.10'
30
27
  - !ruby/object:Gem::Dependency
31
28
  name: treetop
32
29
  requirement: !ruby/object:Gem::Requirement
33
- none: false
34
30
  requirements:
35
- - - ! '>='
31
+ - - ">="
36
32
  - !ruby/object:Gem::Version
37
33
  version: '0'
38
34
  type: :runtime
39
35
  prerelease: false
40
36
  version_requirements: !ruby/object:Gem::Requirement
41
- none: false
42
37
  requirements:
43
- - - ! '>='
38
+ - - ">="
44
39
  - !ruby/object:Gem::Version
45
40
  version: '0'
46
41
  - !ruby/object:Gem::Dependency
47
42
  name: bundler
48
43
  requirement: !ruby/object:Gem::Requirement
49
- none: false
50
44
  requirements:
51
- - - ! '>='
45
+ - - ">="
52
46
  - !ruby/object:Gem::Version
53
47
  version: '0'
54
48
  type: :development
55
49
  prerelease: false
56
50
  version_requirements: !ruby/object:Gem::Requirement
57
- none: false
58
51
  requirements:
59
- - - ! '>='
52
+ - - ">="
60
53
  - !ruby/object:Gem::Version
61
54
  version: '0'
62
55
  - !ruby/object:Gem::Dependency
63
56
  name: github-release
64
57
  requirement: !ruby/object:Gem::Requirement
65
- none: false
66
58
  requirements:
67
- - - ! '>='
59
+ - - ">="
68
60
  - !ruby/object:Gem::Version
69
61
  version: '0'
70
62
  type: :development
71
63
  prerelease: false
72
64
  version_requirements: !ruby/object:Gem::Requirement
73
- none: false
74
65
  requirements:
75
- - - ! '>='
66
+ - - ">="
76
67
  - !ruby/object:Gem::Version
77
68
  version: '0'
78
69
  - !ruby/object:Gem::Dependency
79
70
  name: guard-spork
80
71
  requirement: !ruby/object:Gem::Requirement
81
- none: false
82
72
  requirements:
83
- - - ! '>='
73
+ - - ">="
84
74
  - !ruby/object:Gem::Version
85
75
  version: '0'
86
76
  type: :development
87
77
  prerelease: false
88
78
  version_requirements: !ruby/object:Gem::Requirement
89
- none: false
90
79
  requirements:
91
- - - ! '>='
80
+ - - ">="
92
81
  - !ruby/object:Gem::Version
93
82
  version: '0'
94
83
  - !ruby/object:Gem::Dependency
95
84
  name: guard-rspec
96
85
  requirement: !ruby/object:Gem::Requirement
97
- none: false
98
86
  requirements:
99
- - - ! '>='
87
+ - - ">="
100
88
  - !ruby/object:Gem::Version
101
89
  version: '0'
102
90
  type: :development
103
91
  prerelease: false
104
92
  version_requirements: !ruby/object:Gem::Requirement
105
- none: false
106
93
  requirements:
107
- - - ! '>='
94
+ - - ">="
108
95
  - !ruby/object:Gem::Version
109
96
  version: '0'
110
97
  - !ruby/object:Gem::Dependency
111
98
  name: plymouth
112
99
  requirement: !ruby/object:Gem::Requirement
113
- none: false
114
100
  requirements:
115
- - - ! '>='
101
+ - - ">="
116
102
  - !ruby/object:Gem::Version
117
103
  version: '0'
118
104
  type: :development
119
105
  prerelease: false
120
106
  version_requirements: !ruby/object:Gem::Requirement
121
- none: false
122
107
  requirements:
123
- - - ! '>='
108
+ - - ">="
124
109
  - !ruby/object:Gem::Version
125
110
  version: '0'
126
111
  - !ruby/object:Gem::Dependency
127
- name: pry-debugger
112
+ name: pry-byebug
128
113
  requirement: !ruby/object:Gem::Requirement
129
- none: false
130
114
  requirements:
131
- - - ! '>='
115
+ - - ">="
132
116
  - !ruby/object:Gem::Version
133
117
  version: '0'
134
118
  type: :development
135
119
  prerelease: false
136
120
  version_requirements: !ruby/object:Gem::Requirement
137
- none: false
138
121
  requirements:
139
- - - ! '>='
122
+ - - ">="
140
123
  - !ruby/object:Gem::Version
141
124
  version: '0'
142
125
  - !ruby/object:Gem::Dependency
143
126
  name: rake
144
127
  requirement: !ruby/object:Gem::Requirement
145
- none: false
146
128
  requirements:
147
- - - ! '>='
129
+ - - ">="
148
130
  - !ruby/object:Gem::Version
149
131
  version: '0'
150
132
  type: :development
151
133
  prerelease: false
152
134
  version_requirements: !ruby/object:Gem::Requirement
153
- none: false
154
135
  requirements:
155
- - - ! '>='
136
+ - - ">="
156
137
  - !ruby/object:Gem::Version
157
138
  version: '0'
158
139
  - !ruby/object:Gem::Dependency
159
140
  name: rb-inotify
160
141
  requirement: !ruby/object:Gem::Requirement
161
- none: false
162
142
  requirements:
163
- - - ~>
143
+ - - "~>"
164
144
  - !ruby/object:Gem::Version
165
145
  version: '0.9'
166
146
  type: :development
167
147
  prerelease: false
168
148
  version_requirements: !ruby/object:Gem::Requirement
169
- none: false
170
149
  requirements:
171
- - - ~>
150
+ - - "~>"
172
151
  - !ruby/object:Gem::Version
173
152
  version: '0.9'
174
153
  - !ruby/object:Gem::Dependency
175
154
  name: rdoc
176
155
  requirement: !ruby/object:Gem::Requirement
177
- none: false
178
156
  requirements:
179
- - - ! '>='
157
+ - - ">="
180
158
  - !ruby/object:Gem::Version
181
159
  version: '0'
182
160
  type: :development
183
161
  prerelease: false
184
162
  version_requirements: !ruby/object:Gem::Requirement
185
- none: false
186
163
  requirements:
187
- - - ! '>='
164
+ - - ">="
188
165
  - !ruby/object:Gem::Version
189
166
  version: '0'
190
167
  - !ruby/object:Gem::Dependency
191
168
  name: rspec
192
169
  requirement: !ruby/object:Gem::Requirement
193
- none: false
194
170
  requirements:
195
- - - ! '>='
171
+ - - ">="
196
172
  - !ruby/object:Gem::Version
197
173
  version: '0'
198
174
  type: :development
199
175
  prerelease: false
200
176
  version_requirements: !ruby/object:Gem::Requirement
201
- none: false
202
177
  requirements:
203
- - - ! '>='
178
+ - - ">="
204
179
  - !ruby/object:Gem::Version
205
180
  version: '0'
206
181
  description:
@@ -211,47 +186,40 @@ extensions: []
211
186
  extra_rdoc_files:
212
187
  - README.md
213
188
  files:
214
- - README.md
215
189
  - LICENCE
190
+ - README.md
216
191
  - bin/lvmsync
217
192
  - lib/lvm.rb
218
- - lib/lvm/lv_config.rb
193
+ - lib/lvm/helpers.rb
219
194
  - lib/lvm/logical_volume.rb
220
- - lib/lvm/thin_snapshot.rb
195
+ - lib/lvm/lv_config.rb
196
+ - lib/lvm/pv_config.rb
221
197
  - lib/lvm/snapshot.rb
198
+ - lib/lvm/thin_snapshot.rb
222
199
  - lib/lvm/vg_config.rb
223
- - lib/lvm/helpers.rb
224
- - lib/lvm/pv_config.rb
225
- - lib/vgcfgbackup.treetop
226
200
  - lib/vgcfgbackup.rb
201
+ - lib/vgcfgbackup.treetop
227
202
  homepage: http://theshed.hezmatt.org/lvmsync
228
203
  licenses: []
204
+ metadata: {}
229
205
  post_install_message:
230
206
  rdoc_options: []
231
207
  require_paths:
232
208
  - lib
233
209
  required_ruby_version: !ruby/object:Gem::Requirement
234
- none: false
235
210
  requirements:
236
- - - ! '>='
211
+ - - ">="
237
212
  - !ruby/object:Gem::Version
238
213
  version: '0'
239
- segments:
240
- - 0
241
- hash: -3943591993715626870
242
214
  required_rubygems_version: !ruby/object:Gem::Requirement
243
- none: false
244
215
  requirements:
245
- - - ! '>='
216
+ - - ">="
246
217
  - !ruby/object:Gem::Version
247
218
  version: '0'
248
- segments:
249
- - 0
250
- hash: -3943591993715626870
251
219
  requirements: []
252
220
  rubyforge_project:
253
- rubygems_version: 1.8.23
221
+ rubygems_version: 2.2.2
254
222
  signing_key:
255
- specification_version: 3
223
+ specification_version: 4
256
224
  summary: Efficiently transfer changes in LVM snapshots
257
225
  test_files: []