zfs 0.1.0 → 0.1.1

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 (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: