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.
- data/README.md +10 -0
- data/lib/zfs.rb +57 -56
- data/spec/spec_helper.rb +5 -5
- data/zfs.gemspec +26 -0
- 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 '
|
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
|
-
|
60
|
-
|
61
|
-
|
62
|
-
|
63
|
-
|
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
|
-
|
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
|
-
|
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
|
-
|
107
|
+
out, status = Open3.capture2e(*cmd)
|
110
108
|
|
111
|
-
if
|
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
|
-
|
129
|
+
stdout, stderr, status = Open3.capture3(*cmd)
|
133
130
|
|
134
|
-
if stderr.empty? and stdout.
|
135
|
-
return stdout.
|
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
|
-
|
141
|
+
out, status = Open3.capture2e(*cmd)
|
146
142
|
|
147
|
-
if
|
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
|
-
|
158
|
+
stdout, stderr, status = Open3.capture3(*cmd)
|
164
159
|
|
165
|
-
|
166
|
-
|
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
|
-
|
173
|
+
stdout, stderr, status = Open3.capture3(*cmd)
|
176
174
|
|
177
|
-
|
178
|
-
|
179
|
-
|
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
|
-
|
350
|
+
out, status = Open3.capture2e(*cmd)
|
350
351
|
|
351
|
-
if
|
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
|
-
|
371
|
+
out, status = Open3.capture2e(*cmd)
|
372
372
|
|
373
|
-
if
|
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
|
-
|
423
|
-
|
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
|
-
|
454
|
+
out, status = Open3.capture2e(*cmd)
|
456
455
|
|
457
|
-
if
|
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
|
-
|
473
|
+
out, status = Open3.capture2e(*cmd)
|
476
474
|
|
477
|
-
if
|
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
|
-
|
489
|
+
stdout, stderr, status = Open3.capture3(*cmd)
|
492
490
|
|
493
|
-
|
494
|
-
|
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
|
-
|
506
|
+
out, status = Open3.capture2e(*cmd)
|
506
507
|
|
507
|
-
if
|
508
|
+
if status.success? and out.empty?
|
508
509
|
return self
|
509
510
|
else
|
510
511
|
raise Exception, "something went wrong"
|
data/spec/spec_helper.rb
CHANGED
@@ -2,17 +2,17 @@
|
|
2
2
|
$LOAD_PATH.push(File.expand_path('../lib/zfs'))
|
3
3
|
|
4
4
|
require 'zfs'
|
5
|
-
require '
|
5
|
+
require 'open3'
|
6
6
|
|
7
7
|
shared_context "vagrant" do
|
8
8
|
before(:all) do
|
9
|
-
ZFS.zfs_path = %w(ssh vagrant
|
10
|
-
ZFS.zpool_path = %w(ssh vagrant
|
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
|
-
|
15
|
-
|
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'
|
data/zfs.gemspec
ADDED
@@ -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.
|
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: &
|
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.
|
21
|
+
version: 2.9.0
|
22
22
|
type: :development
|
23
23
|
prerelease: false
|
24
|
-
version_requirements: *
|
24
|
+
version_requirements: *70359894859060
|
25
25
|
- !ruby/object:Gem::Dependency
|
26
26
|
name: guard-rspec
|
27
|
-
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: *
|
35
|
+
version_requirements: *70359894857920
|
36
36
|
- !ruby/object:Gem::Dependency
|
37
37
|
name: guard-bundler
|
38
|
-
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: *
|
46
|
+
version_requirements: *70359894856640
|
47
47
|
- !ruby/object:Gem::Dependency
|
48
48
|
name: rake
|
49
|
-
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: *
|
57
|
+
version_requirements: *70359894855400
|
58
58
|
- !ruby/object:Gem::Dependency
|
59
|
-
name:
|
60
|
-
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: :
|
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: *
|
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:
|