diff options
Diffstat (limited to 'lib')
-rw-r--r-- | lib/puppet/provider/zfs/solaris.rb | 56 | ||||
-rw-r--r-- | lib/puppet/provider/zpool/solaris.rb | 112 | ||||
-rwxr-xr-x | lib/puppet/type/zfs.rb | 45 | ||||
-rwxr-xr-x | lib/puppet/type/zpool.rb | 60 |
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 + |