zfs 0.1.0 → 0.1.1

Sign up to get free protection for your applications and to get access to all the features.
Files changed (5) hide show
  1. data/README.md +10 -0
  2. data/lib/zfs.rb +57 -56
  3. data/spec/spec_helper.rb +5 -5
  4. data/zfs.gemspec +26 -0
  5. metadata +26 -14
data/README.md CHANGED
@@ -92,3 +92,13 @@ Uses a Vagrant VM with a custom Ubuntu + ZFS-on-Linux to do all the practical te
92
92
  * http://tomdoc.org/
93
93
  * http://www.bolthole.com/solaris/zrep/src/
94
94
  * Replace Open4 with Open3#popen3
95
+
96
+ ## Thoughts
97
+
98
+ ZFS('foo/bar'), using Rush just to execute commands - that seems somewhat excessive, seeing as Open3 oughta do it.
99
+ - either way, the idea was to avoid spawning shells all the time, but the solution isn't really to keep a shell open.
100
+ the solution is rather that we do some more caching, IMHO.
101
+
102
+ Rush - box.zfs('tank/foo').snapshot('snapname')
103
+ box.zfs('tank/foo').snapshots
104
+
data/lib/zfs.rb CHANGED
@@ -2,7 +2,7 @@
2
2
 
3
3
  require 'pathname'
4
4
  require 'date'
5
- require 'open4'
5
+ require 'open3'
6
6
 
7
7
  # Get ZFS object.
8
8
  def ZFS(path)
@@ -51,27 +51,26 @@ class ZFS
51
51
  def children(opts={})
52
52
  raise NotFound if !exist?
53
53
 
54
- stdout, stderr = [], []
55
54
  cmd = [ZFS.zfs_path].flatten + %w(list -H -r -oname -tfilesystem)
56
55
  cmd << '-d1' unless opts[:recursive]
57
56
  cmd << name
58
57
 
59
- Open4::spawn(cmd, stdout: stdout, stderr: stderr)
60
-
61
- stdout.shift # self
62
- stdout.collect do |filesystem|
63
- ZFS(filesystem.chomp)
58
+ stdout, stderr, status = Open3.capture3(*cmd)
59
+ if status.success? and stderr == ""
60
+ stdout.lines.drop(1).collect do |filesystem|
61
+ ZFS(filesystem.chomp)
62
+ end
63
+ else
64
+ raise Exception, "something went wrong"
64
65
  end
65
66
  end
66
67
 
67
68
  # Does the filesystem exist?
68
69
  def exist?
69
- stdout, stderr = [], []
70
70
  cmd = [ZFS.zfs_path].flatten + %w(list -H -oname) + [name]
71
71
 
72
- Open4::spawn(cmd, stdout: stdout, stderr: stderr, ignore_exit_failure: true)
73
-
74
- if stdout == ["#{name}\n"]
72
+ out, status = Open3.capture2e(*cmd)
73
+ if status.success? and out == "#{name}\n"
75
74
  true
76
75
  else
77
76
  false
@@ -82,18 +81,18 @@ class ZFS
82
81
  def create(opts={})
83
82
  return nil if exist?
84
83
 
85
- stdout, stderr = [], []
86
84
  cmd = [ZFS.zfs_path].flatten + ['create']
87
85
  cmd << '-p' if opts[:parents]
88
86
  cmd += ['-V', opts[:volume]] if opts[:volume]
89
87
  cmd << name
90
88
 
91
- Open4::spawn(cmd, stdout: stdout, stderr: stderr)
92
-
93
- if stdout.empty? and stderr.empty?
89
+ out, status = Open3.capture2e(*cmd)
90
+ if status.success? and out.empty?
94
91
  return self
92
+ elsif out.match(/dataset already exists\n$/)
93
+ nil
95
94
  else
96
- raise Exception, "something went wrong"
95
+ raise Exception, "something went wrong: #{out}, #{status}"
97
96
  end
98
97
  end
99
98
 
@@ -101,14 +100,13 @@ class ZFS
101
100
  def destroy!(opts={})
102
101
  raise NotFound if !exist?
103
102
 
104
- stdout, stderr = [], []
105
103
  cmd = [ZFS.zfs_path].flatten + ['destroy']
106
104
  cmd << '-r' if opts[:children]
107
105
  cmd << name
108
106
 
109
- Open4::spawn(cmd, stdout: stdout, stderr: stderr)
107
+ out, status = Open3.capture2e(*cmd)
110
108
 
111
- if stdout.empty? and stderr.empty?
109
+ if status.success? and out.empty?
112
110
  return true
113
111
  else
114
112
  raise Exception, "something went wrong"
@@ -126,25 +124,23 @@ class ZFS
126
124
  end
127
125
 
128
126
  def [](key)
129
- stdout, stderr = [], []
130
127
  cmd = [ZFS.zfs_path].flatten + %w(get -ovalue -Hp) + [key.to_s, name]
131
128
 
132
- Open4::spawn(cmd, stdout: stdout, stderr: stderr)
129
+ stdout, stderr, status = Open3.capture3(*cmd)
133
130
 
134
- if stderr.empty? and stdout.size == 1
135
- return stdout.first.chomp
131
+ if status.success? and stderr.empty? and stdout.lines.count == 1
132
+ return stdout.chomp
136
133
  else
137
134
  raise Exception, "something went wrong"
138
135
  end
139
136
  end
140
137
 
141
138
  def []=(key, value)
142
- stdout, stderr = [], []
143
139
  cmd = [ZFS.zfs_path].flatten + ['set', "#{key.to_s}=#{value}", name]
144
140
 
145
- Open4::spawn(cmd, stdout: stdout, stderr: stderr)
141
+ out, status = Open3.capture2e(*cmd)
146
142
 
147
- if stderr.empty? and stdout.empty?
143
+ if status.success? and out.empty?
148
144
  return value
149
145
  else
150
146
  raise Exception, "something went wrong"
@@ -157,28 +153,34 @@ class ZFS
157
153
 
158
154
  # Get an Array of all pools
159
155
  def pools
160
- stdout, stderr = [], []
161
156
  cmd = [ZFS.zpool_path].flatten + %w(list -Honame)
162
157
 
163
- Open4::spawn(cmd, stdout: stdout, stderr: stderr)
158
+ stdout, stderr, status = Open3.capture3(*cmd)
164
159
 
165
- stdout.collect do |pool|
166
- ZFS(pool.chomp)
160
+ if status.success? and stderr.empty?
161
+ stdout.lines.collect do |pool|
162
+ ZFS(pool.chomp)
163
+ end
164
+ else
165
+ raise Exception, "something went wrong"
167
166
  end
168
167
  end
169
168
 
170
169
  # Get a Hash of all mountpoints and their filesystems
171
170
  def mounts
172
- stdout, stderr = [], []
173
171
  cmd = [ZFS.zfs_path].flatten + %w(get -rHp -oname,value mountpoint)
174
172
 
175
- Open4::spawn(cmd, stdout: stdout, stderr: stderr)
173
+ stdout, stderr, status = Open3.capture3(*cmd)
176
174
 
177
- mounts = stdout.collect do |line|
178
- fs, path = line.chomp.split(/\t/, 2)
179
- [path, ZFS(fs)]
175
+ if status.success? and stderr.empty?
176
+ mounts = stdout.lines.collect do |line|
177
+ fs, path = line.chomp.split(/\t/, 2)
178
+ [path, ZFS(fs)]
179
+ end
180
+ Hash[mounts]
181
+ else
182
+ raise Exception, "something went wrong"
180
183
  end
181
- Hash[mounts]
182
184
  end
183
185
 
184
186
  # Define an attribute
@@ -340,15 +342,14 @@ class ZFS::Snapshot < ZFS
340
342
 
341
343
  newname = (parent + "@#{newname}").name
342
344
 
343
- stdout, stderr = [], []
344
345
  cmd = [ZFS.zfs_path].flatten + ['rename']
345
346
  cmd << '-r' if opts[:children]
346
347
  cmd << name
347
348
  cmd << newname
348
349
 
349
- Open4::spawn(cmd, stdout: stdout, stderr: stderr)
350
+ out, status = Open3.capture2e(*cmd)
350
351
 
351
- if stdout.empty? and stderr.empty?
352
+ if status.success? and out.empty?
352
353
  initialize(newname)
353
354
  return self
354
355
  else
@@ -362,15 +363,14 @@ class ZFS::Snapshot < ZFS
362
363
 
363
364
  raise AlreadyExists if ZFS(clone).exist?
364
365
 
365
- stdout, stderr = [], []
366
366
  cmd = [ZFS.zfs_path].flatten + ['clone']
367
367
  cmd << '-p' if opts[:parents]
368
368
  cmd << name
369
369
  cmd << clone
370
370
 
371
- Open4::spawn(cmd, stdout: stdout, stderr: stderr)
371
+ out, status = Open3.capture2e(*cmd)
372
372
 
373
- if stdout.empty? and stderr.empty?
373
+ if status.success? and out.empty?
374
374
  return ZFS(clone)
375
375
  else
376
376
  raise Exception, "something went wrong"
@@ -419,8 +419,8 @@ class ZFS::Snapshot < ZFS
419
419
  receive_opts << '-d' if opts[:use_sent_name]
420
420
  receive_opts << dest
421
421
 
422
- Open4::popen4(*receive_opts) do |rpid, rstdin, rstdout, rstderr|
423
- Open4::popen4(*send_opts) do |spid, sstdin, sstdout, sstderr|
422
+ Open3.popen3(*receive_opts) do |rstdin, rstdout, rstderr, rthr|
423
+ Open3.popen3(*send_opts) do |sstdin, sstdout, sstderr, sthr|
424
424
  while !sstdout.eof?
425
425
  rstdin.write(sstdout.read(16384))
426
426
  end
@@ -446,15 +446,14 @@ class ZFS::Filesystem < ZFS
446
446
  def rename!(newname, opts={})
447
447
  raise AlreadyExists if ZFS(newname).exist?
448
448
 
449
- stdout, stderr = [], []
450
449
  cmd = [ZFS.zfs_path].flatten + ['rename']
451
450
  cmd << '-p' if opts[:parents]
452
451
  cmd << name
453
452
  cmd << newname
454
453
 
455
- Open4::spawn(cmd, stdout: stdout, stderr: stderr)
454
+ out, status = Open3.capture2e(*cmd)
456
455
 
457
- if stdout.empty? and stderr.empty?
456
+ if status.success? and out.empty?
458
457
  initialize(newname)
459
458
  return self
460
459
  else
@@ -467,14 +466,13 @@ class ZFS::Filesystem < ZFS
467
466
  raise NotFound, "no such filesystem" if !exist?
468
467
  raise AlreadyExists, "#{snapname} exists" if ZFS("#{name}@#{snapname}").exist?
469
468
 
470
- stdout, stderr = [], []
471
469
  cmd = [ZFS.zfs_path].flatten + ['snapshot']
472
470
  cmd << '-r' if opts[:children]
473
471
  cmd << "#{name}@#{snapname}"
474
472
 
475
- Open4::spawn(cmd, stdout: stdout, stderr: stderr)
473
+ out, status = Open3.capture2e(*cmd)
476
474
 
477
- if stdout.empty? and stderr.empty?
475
+ if status.success? and out.empty?
478
476
  return ZFS("#{name}@#{snapname}")
479
477
  else
480
478
  raise Exception, "something went wrong"
@@ -488,10 +486,14 @@ class ZFS::Filesystem < ZFS
488
486
  stdout, stderr = [], []
489
487
  cmd = [ZFS.zfs_path].flatten + %w(list -H -d1 -r -oname -tsnapshot) + [name]
490
488
 
491
- Open4::spawn(cmd, stdout: stdout, stderr: stderr)
489
+ stdout, stderr, status = Open3.capture3(*cmd)
492
490
 
493
- stdout.collect do |snap|
494
- ZFS(snap.chomp)
491
+ if status.success? and stderr.empty?
492
+ stdout.lines.collect do |snap|
493
+ ZFS(snap.chomp)
494
+ end
495
+ else
496
+ raise Exception, "something went wrong"
495
497
  end
496
498
  end
497
499
 
@@ -499,12 +501,11 @@ class ZFS::Filesystem < ZFS
499
501
  def promote!
500
502
  raise NotFound, "filesystem is not a clone" if self.origin.nil?
501
503
 
502
- stdout, stderr = [], []
503
504
  cmd = [ZFS.zfs_path].flatten + ['promote', name]
504
505
 
505
- Open4::spawn(cmd, stdout: stdout, stderr: stderr)
506
+ out, status = Open3.capture2e(*cmd)
506
507
 
507
- if stdout.empty? and stderr.empty?
508
+ if status.success? and out.empty?
508
509
  return self
509
510
  else
510
511
  raise Exception, "something went wrong"
@@ -2,17 +2,17 @@
2
2
  $LOAD_PATH.push(File.expand_path('../lib/zfs'))
3
3
 
4
4
  require 'zfs'
5
- require 'open4'
5
+ require 'open3'
6
6
 
7
7
  shared_context "vagrant" do
8
8
  before(:all) do
9
- ZFS.zfs_path = %w(ssh vagrant-zfs sudo zfs)
10
- ZFS.zpool_path = %w(ssh vagrant-zfs sudo zpool)
9
+ ZFS.zfs_path = %w(ssh vagrant sudo zfs)
10
+ ZFS.zpool_path = %w(ssh vagrant sudo zpool)
11
11
  end
12
12
 
13
13
  after(:all) do
14
- Open4::spawn([*ZFS.zfs_path]+['destroy -r tank/foo'], ignore_exit_failure: true)
15
- Open4::spawn([*ZFS.zfs_path]+['destroy -r tank/bar'], ignore_exit_failure: true)
14
+ Open3.capture2e(*(ZFS.zfs_path+%w('destroy -r tank/foo'])))
15
+ Open3.capture2e(*(ZFS.zfs_path+%w('destroy -r tank/bar')))
16
16
 
17
17
  ZFS.zfs_path = 'zfs'
18
18
  ZFS.zpool_path = 'zpool'
@@ -0,0 +1,26 @@
1
+ # -*- encoding: utf-8 -*-
2
+ $:.push File.expand_path("../lib", __FILE__)
3
+ require 'rake'
4
+
5
+ Gem::Specification.new do |s|
6
+ s.name = "zfs"
7
+ s.version = "0.1.1"
8
+ s.platform = Gem::Platform::RUBY
9
+ s.authors = %w(kvs)
10
+ s.email = %w(kvs@binarysolutions.dk)
11
+ s.homepage = "https://github.com/kvs/ruby-zfs"
12
+ s.summary = "An library for interacting with ZFS"
13
+ s.description = %q{Makes it possible to query and manipulate ZFS filesystems, snapshots, etc.}
14
+
15
+ s.files = `git ls-files`.split("\n")
16
+ s.test_files = `git ls-files -- {test,spec,features}/*`.split("\n")
17
+ s.executables = `git ls-files -- bin/*`.split("\n").map { |f| File.basename(f) }
18
+ s.require_paths = ["lib"]
19
+
20
+ s.add_development_dependency "rspec", ["~> 2.9.0"]
21
+ s.add_development_dependency "guard-rspec"
22
+ s.add_development_dependency "guard-bundler"
23
+ s.add_development_dependency "rake"
24
+ s.add_development_dependency "vagrant"
25
+ s.add_development_dependency "vagrant-proxyssh"
26
+ end
metadata CHANGED
@@ -1,7 +1,7 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: zfs
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.1.0
4
+ version: 0.1.1
5
5
  prerelease:
6
6
  platform: ruby
7
7
  authors:
@@ -13,18 +13,18 @@ date: 2012-03-21 00:00:00.000000000 Z
13
13
  dependencies:
14
14
  - !ruby/object:Gem::Dependency
15
15
  name: rspec
16
- requirement: &70251194879920 !ruby/object:Gem::Requirement
16
+ requirement: &70359894859060 !ruby/object:Gem::Requirement
17
17
  none: false
18
18
  requirements:
19
19
  - - ~>
20
20
  - !ruby/object:Gem::Version
21
- version: 2.8.0
21
+ version: 2.9.0
22
22
  type: :development
23
23
  prerelease: false
24
- version_requirements: *70251194879920
24
+ version_requirements: *70359894859060
25
25
  - !ruby/object:Gem::Dependency
26
26
  name: guard-rspec
27
- requirement: &70251194879320 !ruby/object:Gem::Requirement
27
+ requirement: &70359894857920 !ruby/object:Gem::Requirement
28
28
  none: false
29
29
  requirements:
30
30
  - - ! '>='
@@ -32,10 +32,10 @@ dependencies:
32
32
  version: '0'
33
33
  type: :development
34
34
  prerelease: false
35
- version_requirements: *70251194879320
35
+ version_requirements: *70359894857920
36
36
  - !ruby/object:Gem::Dependency
37
37
  name: guard-bundler
38
- requirement: &70251194878680 !ruby/object:Gem::Requirement
38
+ requirement: &70359894856640 !ruby/object:Gem::Requirement
39
39
  none: false
40
40
  requirements:
41
41
  - - ! '>='
@@ -43,10 +43,10 @@ dependencies:
43
43
  version: '0'
44
44
  type: :development
45
45
  prerelease: false
46
- version_requirements: *70251194878680
46
+ version_requirements: *70359894856640
47
47
  - !ruby/object:Gem::Dependency
48
48
  name: rake
49
- requirement: &70251194878160 !ruby/object:Gem::Requirement
49
+ requirement: &70359894855400 !ruby/object:Gem::Requirement
50
50
  none: false
51
51
  requirements:
52
52
  - - ! '>='
@@ -54,18 +54,29 @@ dependencies:
54
54
  version: '0'
55
55
  type: :development
56
56
  prerelease: false
57
- version_requirements: *70251194878160
57
+ version_requirements: *70359894855400
58
58
  - !ruby/object:Gem::Dependency
59
- name: open4
60
- requirement: &70251199214680 !ruby/object:Gem::Requirement
59
+ name: vagrant
60
+ requirement: &70359894854060 !ruby/object:Gem::Requirement
61
61
  none: false
62
62
  requirements:
63
63
  - - ! '>='
64
64
  - !ruby/object:Gem::Version
65
65
  version: '0'
66
- type: :runtime
66
+ type: :development
67
+ prerelease: false
68
+ version_requirements: *70359894854060
69
+ - !ruby/object:Gem::Dependency
70
+ name: vagrant-proxyssh
71
+ requirement: &70359894853300 !ruby/object:Gem::Requirement
72
+ none: false
73
+ requirements:
74
+ - - ! '>='
75
+ - !ruby/object:Gem::Version
76
+ version: '0'
77
+ type: :development
67
78
  prerelease: false
68
- version_requirements: *70251199214680
79
+ version_requirements: *70359894853300
69
80
  description: Makes it possible to query and manipulate ZFS filesystems, snapshots,
70
81
  etc.
71
82
  email:
@@ -83,6 +94,7 @@ files:
83
94
  - lib/zfs.rb
84
95
  - spec/spec_helper.rb
85
96
  - spec/zfs_spec.rb
97
+ - zfs.gemspec
86
98
  homepage: https://github.com/kvs/ruby-zfs
87
99
  licenses: []
88
100
  post_install_message: