summaryrefslogtreecommitdiffstats
path: root/lib
diff options
context:
space:
mode:
authorAndrew Shafer <andrew@reductivelabs.com>2008-11-30 23:54:57 -0700
committerJames Turnbull <james@lovedthanlost.net>2008-12-01 18:35:16 +1100
commit0a40668b348d210cb6cb9e9c25320ccc981ae422 (patch)
tree0008a4efde25ec8459d31131731c8ee675068485 /lib
parent047e5d073c2362da95553c1778b9eb5176b0c05b (diff)
downloadpuppet-0a40668b348d210cb6cb9e9c25320ccc981ae422.tar.gz
puppet-0a40668b348d210cb6cb9e9c25320ccc981ae422.tar.xz
puppet-0a40668b348d210cb6cb9e9c25320ccc981ae422.zip
Feature #1783 - Add ZFS support
Types and providers to manage zfs and zpool
Diffstat (limited to 'lib')
-rw-r--r--lib/puppet/provider/zfs/solaris.rb56
-rw-r--r--lib/puppet/provider/zpool/solaris.rb112
-rwxr-xr-xlib/puppet/type/zfs.rb45
-rwxr-xr-xlib/puppet/type/zpool.rb60
4 files changed, 273 insertions, 0 deletions
diff --git a/lib/puppet/provider/zfs/solaris.rb b/lib/puppet/provider/zfs/solaris.rb
new file mode 100644
index 000000000..4d382cfad
--- /dev/null
+++ b/lib/puppet/provider/zfs/solaris.rb
@@ -0,0 +1,56 @@
+Puppet::Type.type(:zfs).provide(:solaris) do
+ desc "Provider for Solaris zfs."
+
+ commands :zfs => "/usr/sbin/zfs"
+ defaultfor :operatingsystem => :solaris
+
+ def add_properties
+ properties = []
+ Puppet::Type.type(:zfs).validproperties.each do |property|
+ next if property == :ensure
+ if value = @resource[property] and value != ""
+ properties << "-o" << "#{property}=#{value}"
+ end
+ end
+ properties
+ end
+
+ def arrayify_second_line_on_whitespace(text)
+ if second_line = text.split("\n")[1]
+ second_line.split("\s")
+ else
+ []
+ end
+ end
+
+ def create
+ zfs *([:create] + add_properties + [@resource[:name]])
+ end
+
+ def delete
+ zfs(:destroy, @resource[:name])
+ end
+
+ def exists?
+ if zfs(:list).split("\n").detect { |line| line.split("\s")[0] == @resource[:name] }
+ true
+ else
+ false
+ end
+ end
+
+ [:mountpoint, :compression, :copies, :quota, :reservation, :sharenfs, :snapdir].each do |field|
+ define_method(field) do
+ #special knowledge of format
+ #the command returns values in this format with the header
+ #NAME PROPERTY VALUE SOURCE
+ arrayify_second_line_on_whitespace(zfs(:get, field, @resource[:name]))[2]
+ end
+
+ define_method(field.to_s + "=") do |should|
+ zfs(:set, "#{field}=#{should}", @resource[:name])
+ end
+ end
+
+end
+
diff --git a/lib/puppet/provider/zpool/solaris.rb b/lib/puppet/provider/zpool/solaris.rb
new file mode 100644
index 000000000..d680a5f63
--- /dev/null
+++ b/lib/puppet/provider/zpool/solaris.rb
@@ -0,0 +1,112 @@
+Puppet::Type.type(:zpool).provide(:solaris) do
+ desc "Provider for Solaris zpool."
+
+ commands :zpool => "/usr/sbin/zpool"
+ defaultfor :operatingsystem => :solaris
+
+ def process_zpool_data(pool_array)
+ if pool_array == []
+ return Hash.new(:absent)
+ end
+ #get the name and get rid of it
+ pool = Hash.new([])
+ pool[:pool] = pool_array[0]
+ pool_array.shift
+
+ #order matters here :(
+ tmp = []
+
+ pool_array.reverse.each_with_index do |value, i|
+ case value
+ when "spares": pool[:spare] = tmp.reverse and tmp.clear
+ when "logs": pool[:log] = tmp.reverse and tmp.clear
+ when "mirror", "raidz1", "raidz2":
+ sym = value == "mirror" ? :mirror : :raidz
+ pool[sym].unshift(tmp.reverse.join(' '))
+ pool[:raid_parity] = "raidz2" if value == "raidz2"
+ tmp.clear
+ else
+ tmp << value
+ pool[:disk] = tmp.reverse if i == 0
+ end
+ end
+
+ pool
+ end
+
+ def get_pool_data
+ #this is all voodoo dependent on the output from zpool
+ zpool_data = %x{ zpool status #{@resource[:pool]}}.split("\n").select { |line| line.index("\t") == 0 }.collect { |l| l.strip.split("\s")[0] }
+ zpool_data.shift
+ zpool_data
+ end
+
+ def current_pool
+ unless (defined?(@current_pool) and @current_pool)
+ @current_pool = process_zpool_data(get_pool_data)
+ end
+ @current_pool
+ end
+
+ def flush
+ @current_pool= nil
+ end
+
+ #Adds log and spare
+ def build_named(name)
+ if prop = @resource[name.intern]
+ [name] + prop.collect { |p| p.split(' ') }.flatten
+ else
+ []
+ end
+ end
+
+ #query for parity and set the right string
+ def raidzarity
+ @resource[:raid_parity] ? @resource[:raid_parity] : "raidz1"
+ end
+
+ #handle mirror or raid
+ def handle_multi_arrays(prefix, array)
+ array.collect{ |a| [prefix] + a.split(' ') }.flatten
+ end
+
+ #builds up the vdevs for create command
+ def build_vdevs
+ if disk = @resource[:disk]
+ disk.collect { |d| d.split(' ') }.flatten
+ elsif mirror = @resource[:mirror]
+ handle_multi_arrays("mirror", mirror)
+ elsif raidz = @resource[:raidz]
+ handle_multi_arrays(raidzarity, raidz)
+ end
+ end
+
+ def create
+ zpool(*([:create, @resource[:pool]] + build_vdevs + build_named("spare") + build_named("log")))
+ end
+
+ def delete
+ zpool :destroy, @resource[:pool]
+ end
+
+ def exists?
+ if current_pool[:pool] == :absent
+ false
+ else
+ true
+ end
+ end
+
+ [:disk, :mirror, :raidz, :log, :spare].each do |field|
+ define_method(field) do
+ current_pool[field]
+ end
+
+ define_method(field.to_s + "=") do |should|
+ Puppet.warning "NO CHANGES BEING MADE: zpool %s does not match, should be '%s' currently is '%s'" % [field, should, current_pool[field]]
+ end
+ end
+
+end
+
diff --git a/lib/puppet/type/zfs.rb b/lib/puppet/type/zfs.rb
new file mode 100755
index 000000000..d3af3a461
--- /dev/null
+++ b/lib/puppet/type/zfs.rb
@@ -0,0 +1,45 @@
+module Puppet
+ newtype(:zfs) do
+ @doc = "Manage zfs. Create destroy and set properties on zfs instances."
+
+ ensurable
+
+ newparam(:name) do
+ desc "The full name for this filesystem. (including the zpool)"
+ end
+
+ newproperty(:mountpoint) do
+ desc "The mountpoint property."
+ end
+
+ newproperty(:compression) do
+ desc "The compression property."
+ end
+
+ newproperty(:copies) do
+ desc "The copies property."
+ end
+
+ newproperty(:quota) do
+ desc "The quota property."
+ end
+
+ newproperty(:reservation) do
+ desc "The reservation property."
+ end
+
+ newproperty(:sharenfs) do
+ desc "The sharenfs property."
+ end
+
+ newproperty(:snapdir) do
+ desc "The sharenfs property."
+ end
+
+ autorequire(:zpool) do
+ #strip the zpool off the zfs name and autorequire it
+ [@parameters[:name].value.split('/')[0]]
+ end
+ end
+end
+
diff --git a/lib/puppet/type/zpool.rb b/lib/puppet/type/zpool.rb
new file mode 100755
index 000000000..6d589a0fe
--- /dev/null
+++ b/lib/puppet/type/zpool.rb
@@ -0,0 +1,60 @@
+module Puppet
+ newtype(:zpool) do
+ @doc = "Manage zpools. Create and delete zpools. The provider WILL NOT SYNC, only report differences.
+
+ Supports vdevs with mirrors, raidz, logs and spares."
+
+ ensurable
+
+ newproperty(:disk, :array_matching => :all) do
+ desc "The disk(s) for this pool. Can be an array or space separated string"
+ end
+
+ newproperty(:mirror, :array_matching => :all) do
+ desc "List of all the devices to mirror for this pool. Each mirror should be a space separated string.
+ mirror => [\"disk1 disk2\", \"disk3 disk4\"]"
+
+ validate do |value|
+ if value.include?(",")
+ raise ArgumentError, "mirror names must be provided as string separated, not a comma-separated list"
+ end
+ end
+ end
+
+ newproperty(:raidz, :array_matching => :all) do
+ desc "List of all the devices to raid for this pool. Should be an array of space separated strings.
+ raidz => [\"disk1 disk2\", \"disk3 disk4\"]"
+
+ validate do |value|
+ if value.include?(",")
+ raise ArgumentError, "raid names must be provided as string separated, not a comma-separated list"
+ end
+ end
+ end
+
+ newproperty(:spare, :array_matching => :all) do
+ desc "Spare disk(s) for this pool."
+ end
+
+ newproperty(:log, :array_matching => :all) do
+ desc "Log disks for this pool. (doesn't support mirroring yet)"
+ end
+
+ newparam(:pool) do
+ desc "The name for this pool."
+ isnamevar
+ end
+
+ newparam(:raid_parity) do
+ desc "Determines parity when using raidz property."
+ end
+
+ validate do
+ has_should = [:disk, :mirror, :raidz].select { |prop| self.should(prop) }
+ if has_should.length > 1
+ self.fail "You cannot specify %s on this type (only one)" % has_should.join(" and ")
+ end
+ end
+ end
+end
+