vagrant-zfs-box 0.0.1
Sign up to get free protection for your applications and to get access to all the features.
- data/lib/vagrant/downloaders/file.rb +22 -0
- data/lib/vagrant_init.rb +6 -0
- data/lib/vagrant_zfs.rb +14 -0
- data/lib/vagrant_zfs/actions.rb +4 -0
- data/lib/vagrant_zfs/actions/box/destroy.rb +23 -0
- data/lib/vagrant_zfs/actions/box/unpackage.rb +82 -0
- data/lib/vagrant_zfs/actions/vm/destroy.rb +38 -0
- data/lib/vagrant_zfs/actions/vm/import.rb +72 -0
- data/lib/vagrant_zfs/vboxmanage.rb +105 -0
- data/lib/vagrant_zfs/version.rb +3 -0
- data/lib/vagrant_zfs/zfs.rb +79 -0
- data/lib/vagrant_zfs/zfs_config.rb +3 -0
- metadata +57 -0
@@ -0,0 +1,22 @@
|
|
1
|
+
require 'fileutils'
|
2
|
+
|
3
|
+
module Vagrant
|
4
|
+
module Downloaders
|
5
|
+
# "Downloads" a file to a temporary file. Basically, this downloader
|
6
|
+
# simply does a file copy.
|
7
|
+
class File < Base
|
8
|
+
def self.match?(uri)
|
9
|
+
::File.file?(::File.expand_path(uri))
|
10
|
+
end
|
11
|
+
|
12
|
+
def prepare(source_url)
|
13
|
+
raise Errors::DownloaderFileDoesntExist if !::File.file?(::File.expand_path(source_url))
|
14
|
+
end
|
15
|
+
|
16
|
+
def download!(source_url, destination_file)
|
17
|
+
@ui.info I18n.t("vagrant.downloaders.file.download")
|
18
|
+
FileUtils.symlink(::File.expand_path(source_url), destination_file.path, :force => true)
|
19
|
+
end
|
20
|
+
end
|
21
|
+
end
|
22
|
+
end
|
data/lib/vagrant_init.rb
ADDED
data/lib/vagrant_zfs.rb
ADDED
@@ -0,0 +1,14 @@
|
|
1
|
+
require 'vagrant'
|
2
|
+
require 'vagrant/action/builder'
|
3
|
+
require 'vagrant_zfs/zfs_config'
|
4
|
+
require 'vagrant_zfs/zfs'
|
5
|
+
require 'vagrant_zfs/vboxmanage'
|
6
|
+
require 'vagrant_zfs/actions'
|
7
|
+
require 'vagrant_zfs/version'
|
8
|
+
|
9
|
+
Vagrant.config_keys.register(:zfs) { ZfsConfig }
|
10
|
+
Vagrant.actions[:box_remove].replace(Vagrant::Action::Box::Destroy, VagrantZFS::Action::Box::Destroy)
|
11
|
+
Vagrant.actions[:box_add].replace(Vagrant::Action::Box::Unpackage, VagrantZFS::Action::Box::Unpackage)
|
12
|
+
Vagrant.actions[:up].delete(Vagrant::Action::VM::DefaultName)
|
13
|
+
Vagrant.actions[:up].replace(Vagrant::Action::VM::Import, VagrantZFS::Action::VM::Import)
|
14
|
+
Vagrant.actions[:destroy].replace(Vagrant::Action::VM::Destroy, VagrantZFS::Action::VM::Destroy)
|
@@ -0,0 +1,23 @@
|
|
1
|
+
module VagrantZFS
|
2
|
+
module Action
|
3
|
+
module Box
|
4
|
+
class Destroy
|
5
|
+
def initialize(app, env)
|
6
|
+
@app = app
|
7
|
+
@env = env
|
8
|
+
end
|
9
|
+
|
10
|
+
def call(env)
|
11
|
+
# Delete the existing box
|
12
|
+
env[:ui].info I18n.t("vagrant.actions.box.destroy.destroying", :name => env[:box_name])
|
13
|
+
VagrantZFS::ZFS.destroy_at env['box_directory'].to_s
|
14
|
+
|
15
|
+
# Reload the box collection
|
16
|
+
env[:box_collection].reload!
|
17
|
+
|
18
|
+
@app.call(env)
|
19
|
+
end
|
20
|
+
end
|
21
|
+
end
|
22
|
+
end
|
23
|
+
end
|
@@ -0,0 +1,82 @@
|
|
1
|
+
require 'archive/tar/minitar'
|
2
|
+
module VagrantZFS
|
3
|
+
module Action
|
4
|
+
module Box
|
5
|
+
# Unpackages a downloaded box to a given directory with a given
|
6
|
+
# name.
|
7
|
+
#
|
8
|
+
# This variant will first create a ZFS directory from a configured
|
9
|
+
# zpool and then unpack the box into the directory.
|
10
|
+
#
|
11
|
+
# # Required Variables
|
12
|
+
#
|
13
|
+
# * `download.temp_path` - A location for the downloaded box. This is
|
14
|
+
# set by the {Download} action.
|
15
|
+
# * `box` - A {Vagrant::Box} object.
|
16
|
+
#
|
17
|
+
class Unpackage
|
18
|
+
attr_reader :box_directory
|
19
|
+
|
20
|
+
def initialize(app, env)
|
21
|
+
@logger = Log4r::Logger.new("vagrant_zfs::action::box::unpackage")
|
22
|
+
@app = app
|
23
|
+
@env = env
|
24
|
+
end
|
25
|
+
|
26
|
+
def call(env)
|
27
|
+
@env = env
|
28
|
+
|
29
|
+
setup_box_directory
|
30
|
+
decompress
|
31
|
+
|
32
|
+
@app.call(@env)
|
33
|
+
end
|
34
|
+
|
35
|
+
def recover(env)
|
36
|
+
if box_directory && File.directory?(box_directory)
|
37
|
+
VagrantZFS::ZFS.destroy env[:zfs_name]
|
38
|
+
FileUtils.rm_rf(box_directory)
|
39
|
+
end
|
40
|
+
end
|
41
|
+
|
42
|
+
def zpool
|
43
|
+
# Is the zpool specified in the Vagrantfile?
|
44
|
+
if @env['global_config'].zfs.zpool
|
45
|
+
@env['global_config'].zfs.zpool
|
46
|
+
else
|
47
|
+
# If we have only one zpool available, go with that.
|
48
|
+
zpools = VagrantZFS::ZFS.zpool_list
|
49
|
+
if zpools.length == 1
|
50
|
+
zpools.first
|
51
|
+
else
|
52
|
+
raise Exception, "zpool not specified and more than one available."
|
53
|
+
end
|
54
|
+
end
|
55
|
+
end
|
56
|
+
|
57
|
+
def setup_box_directory
|
58
|
+
if File.directory?(@env["box_directory"])
|
59
|
+
raise Errors::BoxAlreadyExists, :name => @env["box_name"]
|
60
|
+
end
|
61
|
+
|
62
|
+
puts "ZPOOL: #{zpool}"
|
63
|
+
@env[:zfs_name] = "#{zpool}/vagrant_#{@env["box_name"]}"
|
64
|
+
mountpoint = "#{@env["box_directory"]}"
|
65
|
+
VagrantZFS::ZFS.create @env[:zfs_name], mountpoint
|
66
|
+
@box_directory = @env["box_directory"]
|
67
|
+
end
|
68
|
+
|
69
|
+
def decompress
|
70
|
+
Dir.chdir(@env["box_directory"]) do
|
71
|
+
@env[:ui].info I18n.t("vagrant.actions.box.unpackage.extracting")
|
72
|
+
begin
|
73
|
+
Archive::Tar::Minitar.unpack(@env["download.temp_path"], @env["box_directory"].to_s)
|
74
|
+
rescue SystemCallError
|
75
|
+
raise Errors::BoxUnpackageFailure
|
76
|
+
end
|
77
|
+
end
|
78
|
+
end
|
79
|
+
end
|
80
|
+
end
|
81
|
+
end
|
82
|
+
end
|
@@ -0,0 +1,38 @@
|
|
1
|
+
module VagrantZFS
|
2
|
+
module Action
|
3
|
+
module VM
|
4
|
+
class Destroy
|
5
|
+
def initialize(app, env)
|
6
|
+
@logger = Log4r::Logger.new("vagrant_zfs::action::vm::destroy")
|
7
|
+
@app = app
|
8
|
+
end
|
9
|
+
|
10
|
+
def call(env)
|
11
|
+
env[:ui].info I18n.t("vagrant.actions.vm.destroy.destroying")
|
12
|
+
|
13
|
+
cmd = "VBoxManage showvminfo #{env[:vm].uuid}"
|
14
|
+
stdout, stderr, status = Open3.capture3(*cmd)
|
15
|
+
if status.success? and stderr.empty?
|
16
|
+
instance_name = stdout.lines.grep(/^Name:\s*(.+)/){$1}.first
|
17
|
+
else
|
18
|
+
raise Exception, "Could not find instance name for VM #{env[:vm].uuid}"
|
19
|
+
end
|
20
|
+
|
21
|
+
zpool = 'SSD'
|
22
|
+
fs = "#{zpool}/vagrant_#{env[:vm].config.vm.box}"
|
23
|
+
clonename = "#{fs}/#{instance_name}"
|
24
|
+
snapname = "#{fs}@#{instance_name}"
|
25
|
+
|
26
|
+
env[:vm].driver.delete
|
27
|
+
env[:vm].uuid = nil
|
28
|
+
|
29
|
+
VagrantZFS::ZFS.destroy clonename
|
30
|
+
VagrantZFS::ZFS.destroy snapname
|
31
|
+
|
32
|
+
|
33
|
+
@app.call(env)
|
34
|
+
end
|
35
|
+
end
|
36
|
+
end
|
37
|
+
end
|
38
|
+
end
|
@@ -0,0 +1,72 @@
|
|
1
|
+
module VagrantZFS
|
2
|
+
module Action
|
3
|
+
module VM
|
4
|
+
class Import
|
5
|
+
def initialize(app, env)
|
6
|
+
@logger = Log4r::Logger.new("vagrant_zfs::action::vm::import")
|
7
|
+
@env = env
|
8
|
+
@app = app
|
9
|
+
end
|
10
|
+
|
11
|
+
def find_basebox_filesystem
|
12
|
+
fs = VagrantZFS::ZFS.mounts.select do |mountpoint,fs|
|
13
|
+
mountpoint == @env[:vm].box.directory.to_s
|
14
|
+
end.first[1]
|
15
|
+
@logger.debug "Found base box filesystem: #{fs}"
|
16
|
+
fs
|
17
|
+
end
|
18
|
+
|
19
|
+
def call(env)
|
20
|
+
env[:ui].info I18n.t("vagrant.actions.vm.import.importing", :name => env[:vm].box.name)
|
21
|
+
|
22
|
+
# Import the virtual machine
|
23
|
+
ovf_file = env[:vm].box.directory.join("box.ovf").to_s
|
24
|
+
|
25
|
+
fs = find_basebox_filesystem
|
26
|
+
|
27
|
+
instance_name = env[:root_path].basename.to_s + "_#{Time.now.to_i}"
|
28
|
+
env[:name] = instance_name
|
29
|
+
|
30
|
+
VagrantZFS::ZFS.snapshot fs, instance_name
|
31
|
+
|
32
|
+
user_home = ENV['HOME']
|
33
|
+
vagrant_home = "#{user_home}/.vagrant.d"
|
34
|
+
instance_root = vagrant_home + "/instances"
|
35
|
+
|
36
|
+
clonename = "#{fs}/#{instance_name}"
|
37
|
+
mountpoint = "#{instance_root}/#{instance_name}"
|
38
|
+
VagrantZFS::ZFS.clone! "#{fs}@#{instance_name}", clonename
|
39
|
+
VagrantZFS::ZFS.set_mountpoint clonename, mountpoint
|
40
|
+
|
41
|
+
hdd = instance_root + "/" + instance_name + "/box-disk1.vmdk"
|
42
|
+
|
43
|
+
env[:vm].uuid = VagrantZFS::VBoxManage.createvm instance_name, instance_root
|
44
|
+
|
45
|
+
VagrantZFS::VBoxManage.setup env[:vm].uuid, hdd
|
46
|
+
|
47
|
+
# # If we got interrupted, then the import could have been
|
48
|
+
# # interrupted and its not a big deal. Just return out.
|
49
|
+
# return if env[:interrupted]
|
50
|
+
|
51
|
+
# Flag as erroneous and return if import failed
|
52
|
+
raise Errors::VMImportFailure if !env[:vm].uuid
|
53
|
+
|
54
|
+
# # Import completed successfully. Continue the chain
|
55
|
+
@app.call(env)
|
56
|
+
end
|
57
|
+
|
58
|
+
def recover(env)
|
59
|
+
if env[:vm].created?
|
60
|
+
return if env["vagrant.error"].is_a?(Errors::VagrantError)
|
61
|
+
|
62
|
+
# Interrupted, destroy the VM. We note that we don't want to
|
63
|
+
# validate the configuration here.
|
64
|
+
destroy_env = env.clone
|
65
|
+
destroy_env[:validate] = false
|
66
|
+
env[:action_runner].run(:destroy, destroy_env)
|
67
|
+
end
|
68
|
+
end
|
69
|
+
end
|
70
|
+
end
|
71
|
+
end
|
72
|
+
end
|
@@ -0,0 +1,105 @@
|
|
1
|
+
require 'open3'
|
2
|
+
module VagrantZFS
|
3
|
+
class VBoxManage
|
4
|
+
def self.exec cmd
|
5
|
+
cmd = "VBoxManage " + cmd
|
6
|
+
stdout, stderr, status = Open3.capture3(cmd)
|
7
|
+
|
8
|
+
if status.success? and stderr.empty?
|
9
|
+
return stdout
|
10
|
+
else
|
11
|
+
raise Exception, "VBoxManage Error: #{cmd}\n #{stdout}\n #{stderr}\n #{status}"
|
12
|
+
end
|
13
|
+
end
|
14
|
+
|
15
|
+
def self.createvm instance_name, instance_root
|
16
|
+
cmd = "createvm --name #{instance_name} --register --basefolder #{instance_root}"
|
17
|
+
lines = self.exec(cmd).split(/\n/)
|
18
|
+
uuid = lines.grep(/^UUID:\s*([-0-9a-z]+)/){$1}.first
|
19
|
+
end
|
20
|
+
|
21
|
+
def self.modifyvm uuid, arg
|
22
|
+
self.exec "modifyvm #{uuid} #{arg}"
|
23
|
+
end
|
24
|
+
|
25
|
+
def self.add_nat uuid
|
26
|
+
self.modifyvm uuid, "--nic1 nat"
|
27
|
+
end
|
28
|
+
|
29
|
+
def self.cpus uuid, cpus
|
30
|
+
self.modifyvm uuid, "--cpus #{cpus}"
|
31
|
+
end
|
32
|
+
|
33
|
+
def self.memory uuid, memory
|
34
|
+
self.modifyvm uuid, "--memory #{memory}"
|
35
|
+
end
|
36
|
+
|
37
|
+
def self.gethduuid file
|
38
|
+
# I found the line number may be 23, but search 40 just to be sure.
|
39
|
+
cmd="head -n 40 #{file}|grep --text --byte-offset --max-count=1 ddb.uuid.image="
|
40
|
+
stdout, stderr, status = Open3.capture3(cmd)
|
41
|
+
unless status.success? and stderr.empty?
|
42
|
+
raise Exception, "gethduuid Error: #{cmd}\n #{stdout}\n #{stderr}\n #{status}"
|
43
|
+
end
|
44
|
+
# UUID format is a string of hyphen-punctuated character groups of 8-4-4-4-12.
|
45
|
+
uuid = stdout.match(/ddb.uuid.image="(\w{8}-\w{4}-\w{4}-\w{4}-\w{12})"/).captures.first
|
46
|
+
end
|
47
|
+
|
48
|
+
def self.sethduuid_shell file
|
49
|
+
# I found the line number may be 23, but search 40 just to be sure.
|
50
|
+
cmd="head -n 40 #{file}|grep --text --byte-offset --max-count=1 ddb.uuid.image="
|
51
|
+
stdout, stderr, status = Open3.capture3(cmd)
|
52
|
+
unless status.success? and stderr.empty?
|
53
|
+
raise Exception, "gethduuid Error: #{cmd}\n #{stdout}\n #{stderr}\n #{status}"
|
54
|
+
end
|
55
|
+
# The number before : is the byte offset number.
|
56
|
+
uuid_offset = stdout.split(':').first.to_i + 'ddb.uuid.image="'.length
|
57
|
+
uuid_length = 36
|
58
|
+
|
59
|
+
# Generate a new UUID
|
60
|
+
stdout, stderr, status = Open3.capture3("uuidgen")
|
61
|
+
unless status.success? and stderr.empty?
|
62
|
+
raise Exception, "gethduuid Error: #{cmd}\n #{stdout}\n #{stderr}\n #{status}"
|
63
|
+
end
|
64
|
+
new_uuid = stdout.chomp
|
65
|
+
|
66
|
+
# Edit the vmdk-file inplace.
|
67
|
+
cmd = "echo #{new_uuid} | dd of=#{file} seek=#{uuid_offset} bs=1 count=#{uuid_length} conv=notrunc"
|
68
|
+
`#{cmd}` ? new_uuid : nil
|
69
|
+
end
|
70
|
+
|
71
|
+
def self.sethduuid file
|
72
|
+
self.exec "internalcommands sethduuid #{file}"
|
73
|
+
end
|
74
|
+
|
75
|
+
def self.add_storagectl uuid
|
76
|
+
self.exec "storagectl #{uuid} --name 'SATA Controller' --add sata --controller IntelAHCI --sataportcount 4 --hostiocache on --bootable on"
|
77
|
+
end
|
78
|
+
|
79
|
+
def self.add_disk uuid, hddfile
|
80
|
+
self.exec "storageattach #{uuid} --storagectl 'SATA Controller' --port 0 --type hdd --nonrotational on --medium #{hddfile}"
|
81
|
+
end
|
82
|
+
|
83
|
+
def self.setup uuid, hddfile
|
84
|
+
uuid_pre = self.gethduuid(hddfile)
|
85
|
+
self.sethduuid hddfile
|
86
|
+
uuid_post = self.gethduuid(hddfile)
|
87
|
+
|
88
|
+
# Did self.sethduuid work?
|
89
|
+
unless uuid_pre != uuid_post
|
90
|
+
puts "VBoxManage internalcommands sethduuid did not work. Trying shell with dd"
|
91
|
+
self.sethduuid_shell hddfile
|
92
|
+
uuid_post = self.gethduuid(hddfile)
|
93
|
+
unless uuid_pre != uuid_post
|
94
|
+
puts "Did not succeed to sethduuid."
|
95
|
+
end
|
96
|
+
end
|
97
|
+
|
98
|
+
self.add_storagectl uuid
|
99
|
+
self.add_disk uuid, hddfile
|
100
|
+
self.add_nat uuid
|
101
|
+
self.cpus uuid, "1"
|
102
|
+
self.memory uuid, "512"
|
103
|
+
end
|
104
|
+
end
|
105
|
+
end
|
@@ -0,0 +1,79 @@
|
|
1
|
+
require 'open3'
|
2
|
+
module VagrantZFS
|
3
|
+
class ZFS
|
4
|
+
def self.exec cmd
|
5
|
+
cmd = "zfs " + cmd
|
6
|
+
stdout, stderr, status = Open3.capture3(cmd)
|
7
|
+
|
8
|
+
if status.success? and stderr.empty?
|
9
|
+
return stdout
|
10
|
+
else
|
11
|
+
raise Exception, "ZFS Error: #{cmd}\n #{stdout}\n #{stderr}\n #{status}"
|
12
|
+
end
|
13
|
+
end
|
14
|
+
|
15
|
+
def self.zpool_list
|
16
|
+
`zpool list -H -o name`.split(/\n/)
|
17
|
+
end
|
18
|
+
|
19
|
+
def self.create fs_name, mountpoint
|
20
|
+
cmd = "create -o mountpoint=#{mountpoint} #{fs_name}"
|
21
|
+
self.exec cmd
|
22
|
+
end
|
23
|
+
|
24
|
+
def self.destroy fs_name
|
25
|
+
cmd = "destroy #{fs_name}"
|
26
|
+
self.exec cmd
|
27
|
+
end
|
28
|
+
|
29
|
+
def self.destroy_at mountpoint
|
30
|
+
fs = VagrantZFS::ZFS.mounts.select do |mounted_at,fs|
|
31
|
+
mounted_at == mountpoint
|
32
|
+
end.first[1]
|
33
|
+
puts "Will destroy #{fs} mounted at #{mountpoint}"
|
34
|
+
self.destroy fs
|
35
|
+
end
|
36
|
+
|
37
|
+
def self.mounts
|
38
|
+
cmd = "get -rHp -oname,value mountpoint"
|
39
|
+
lines = self.exec(cmd).split(/\n/)
|
40
|
+
mounts = lines.collect do |line|
|
41
|
+
fs, path = line.chomp.split(/\t/, 2)
|
42
|
+
[path, fs]
|
43
|
+
end
|
44
|
+
Hash[mounts]
|
45
|
+
end
|
46
|
+
|
47
|
+
def self.set_mountpoint fs_name, mountpoint
|
48
|
+
cmd = "set mountpoint=#{mountpoint} #{fs_name}"
|
49
|
+
self.exec cmd
|
50
|
+
end
|
51
|
+
|
52
|
+
def self.snapshot(fsname, snapname)
|
53
|
+
#raise NotFound, "no such filesystem" if !exist?
|
54
|
+
#raise AlreadyExists, "Snapshot #{snapname} already exists" if ZFS("#{fsname}@#{snapname}").exist?
|
55
|
+
|
56
|
+
cmd = "snapshot #{fsname}@#{snapname}"
|
57
|
+
self.exec cmd
|
58
|
+
return "#{fsname}@#{snapname}"
|
59
|
+
end
|
60
|
+
|
61
|
+
def self.snapshot(fsname, snapname, opts={})
|
62
|
+
#raise NotFound, "no such filesystem" if !exist?
|
63
|
+
#raise AlreadyExists, "Snapshot #{snapname} already exists" if ZFS("#{fsname}@#{snapname}").exist?
|
64
|
+
|
65
|
+
cmd = "snapshot #{fsname}@#{snapname}"
|
66
|
+
self.exec cmd
|
67
|
+
return "#{fsname}@#{snapname}"
|
68
|
+
end
|
69
|
+
|
70
|
+
# Clone snapshot
|
71
|
+
def self.clone!(snapname, clonename)
|
72
|
+
#clonename = clone.name if clone.is_a? ZFS
|
73
|
+
#raise AlreadyExists if ZFS(clone).exist?
|
74
|
+
|
75
|
+
cmd = "clone #{snapname} #{clonename}"
|
76
|
+
self.exec cmd
|
77
|
+
end
|
78
|
+
end
|
79
|
+
end
|
metadata
ADDED
@@ -0,0 +1,57 @@
|
|
1
|
+
--- !ruby/object:Gem::Specification
|
2
|
+
name: vagrant-zfs-box
|
3
|
+
version: !ruby/object:Gem::Version
|
4
|
+
version: 0.0.1
|
5
|
+
prerelease:
|
6
|
+
platform: ruby
|
7
|
+
authors:
|
8
|
+
- Lars Tobias Skjong-Borsting
|
9
|
+
autorequire:
|
10
|
+
bindir: bin
|
11
|
+
cert_chain: []
|
12
|
+
date: 2013-03-18 00:00:00.000000000 Z
|
13
|
+
dependencies: []
|
14
|
+
description: ZFS plugin that uses snapshots and clones to speed up box creation for
|
15
|
+
Vagrant 1.0
|
16
|
+
email: larstobi@relatime.no
|
17
|
+
executables: []
|
18
|
+
extensions: []
|
19
|
+
extra_rdoc_files: []
|
20
|
+
files:
|
21
|
+
- lib/vagrant/downloaders/file.rb
|
22
|
+
- lib/vagrant_init.rb
|
23
|
+
- lib/vagrant_zfs/zfs.rb
|
24
|
+
- lib/vagrant_zfs/version.rb
|
25
|
+
- lib/vagrant_zfs/actions/box/destroy.rb
|
26
|
+
- lib/vagrant_zfs/actions/box/unpackage.rb
|
27
|
+
- lib/vagrant_zfs/actions/vm/destroy.rb
|
28
|
+
- lib/vagrant_zfs/actions/vm/import.rb
|
29
|
+
- lib/vagrant_zfs/zfs_config.rb
|
30
|
+
- lib/vagrant_zfs/actions.rb
|
31
|
+
- lib/vagrant_zfs/vboxmanage.rb
|
32
|
+
- lib/vagrant_zfs.rb
|
33
|
+
homepage: http://rubygems.org/gems/vagrant-zfs-box
|
34
|
+
licenses: []
|
35
|
+
post_install_message:
|
36
|
+
rdoc_options: []
|
37
|
+
require_paths:
|
38
|
+
- lib
|
39
|
+
required_ruby_version: !ruby/object:Gem::Requirement
|
40
|
+
none: false
|
41
|
+
requirements:
|
42
|
+
- - ! '>='
|
43
|
+
- !ruby/object:Gem::Version
|
44
|
+
version: '0'
|
45
|
+
required_rubygems_version: !ruby/object:Gem::Requirement
|
46
|
+
none: false
|
47
|
+
requirements:
|
48
|
+
- - ! '>='
|
49
|
+
- !ruby/object:Gem::Version
|
50
|
+
version: '0'
|
51
|
+
requirements: []
|
52
|
+
rubyforge_project:
|
53
|
+
rubygems_version: 1.8.24
|
54
|
+
signing_key:
|
55
|
+
specification_version: 3
|
56
|
+
summary: ZFS plugin for Vagrant 1.0
|
57
|
+
test_files: []
|