zfs 0.1.0 → 0.1.1
Sign up to get free protection for your applications and to get access to all the features.
- 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:
|