Hello, On Mon, Feb 15, 2010 at 09:30:04AM -0800, Daniel Kerwin wrote: > i tried to write my first type and provider that should create logical > volumes. Seems like i'm missing something as i get nothing when i use > it: No errors and no logical volume :-(
This is not exactly what you're looking for, but I've written a simple LVM type and an associated provider a long time ago, I'm attaching it here together with a somewhat related "filesystem" type and provider. I've been meaning to clean them up, write tests and properly contribute to the project for literally years now. I guess if I don't take the opportunity to send it out now, the code might never see daylight. I hope someone finds it useful, and perhaps even give it some love. It's been quite a while since I used them, so I'm not sure if they work with modern puppet. -- Marcin Owsiany <mar...@owsiany.pl> http://marcin.owsiany.pl/ GnuPG: 1024D/60F41216 FE67 DA2D 0ACA FC5E 3F75 D6F6 3A0D 8AA0 60F4 1216 "Every program in development at MIT expands until it can read mail." -- Unknown -- You received this message because you are subscribed to the Google Groups "Puppet Users" group. To post to this group, send email to puppet-us...@googlegroups.com. To unsubscribe from this group, send email to puppet-users+unsubscr...@googlegroups.com. For more options, visit this group at http://groups.google.com/group/puppet-users?hl=en.
# Logical Volume type # Copyright 2007-2010 Marcin Owsiany <mar...@owsiany.pl> # License: LGPL require 'puppet' Puppet::Type.newtype(:lv) do @doc = "Logical volume device." ensurable newparam(:name) do isnamevar desc "The name of the logical volume." end newparam(:vgname) do desc "The name of the volume group containing this volume." isrequired end newproperty(:size) do desc "Size of the volume, in megabytes for now." isrequired validate do |value| unless value =~ /^[1-9]\d*$/ raise ArgumentError, "\"#{value}\" is not a valid size." end end end end
# LVM 2 provider for the Logical volume type. # Copyright 2007-2010 Marcin Owsiany <mar...@owsiany.pl> # License: LGPL require 'puppet' require 'puppet/provider/parsedfile' Puppet::Type.type(:lv).provide(:lvm2 ) do desc "Provides LVM2 backend for the logical volume type. Very simplistic so far." commands :lvs => "/sbin/lvs" commands :lvcreate => "/sbin/lvcreate" commands :lvremove => "/sbin/lvremove" commands :lvresize => "/sbin/lvresize" commands :lvreduce => "/sbin/lvreduce" mk_resource_methods def self.prefetch(resources) instances.each do |provider| if lv = resources[provider.name] and lv[:vgname] == provider.vgname lv.provider = provider end end end def self.instances providers = [] # XXX should set locale to C on invocation - how to do this in a generic and elegant way? cmd = "#{command(:lvs)} --noheadings --nosuffix --options vg_name,lv_name,lv_size --units m --separator :" execpipe(cmd) do |process| process.each do |line| vals = line.split(':').collect { |val| val.strip.sub(/,..$/, '') } p = new(:name => vals[1], :vgname => vals[0], :size => vals[2], :ensure => :present) providers << p end end providers end def exists? @property_hash[:ensure] == :present end def create lvcreate '--size', "#...@resource.should(:size)}m", '-n', @resource[:name], @resource[:vgname] end def destroy lvremove '--force', "#...@resource[:vgname]}/#...@resource[:name]}" end def size=(size) # Looks like you need to use two different utilities to allow noninteractive size manipulation if size > self.size lvresize '--size', "#{size}m", "#...@resource[:vgname]}/#...@resource[:name]}" else lvreduce '--force', '--size', "#{size}m", "#...@resource[:vgname]}/#...@resource[:name]}" end end end
# Filesystem type # Copyright 2007-2010 Marcin Owsiany <mar...@owsiany.pl> # License: LGPL require 'puppet' require 'pathname' Puppet::Type.newtype(:filesystem) do @doc = "Filesystem." ensurable newparam(:device) do isnamevar desc "Device name - absolute path or relative to /dev/." munge do |value| Pathname.new(value).absolute? ? value : '/dev/' + value end end newproperty(:type) do desc "Type of the filesystem. Supported so far: ext2, ext3, xfs." isrequired newvalue(:ext2) newvalue(:ext3) newvalue(:xfs) end newparam(:destroy) do desc "Whether to allow destructive filesystem conversions." newvalues(:never, :ok) defaultto(:never) end end
# mkfs provider for the filesystem type # Copyright 2007-2010 Marcin Owsiany <mar...@owsiany.pl> # License: LGPL require 'puppet' Puppet::Type.type(:filesystem).provide(:mkfs ) do desc "Provides a mkfs-based backend for the filesystem type. Very simple so far - does not support any filesystem options. Knows how to handle the following filesystems: ext2 ext3 xfs. Knows how to non-destructively convert between ext2 and ext3 and vice-versa." # HOWTO add new filesystem support: # - adjust the INITIAL_* constants if necessary # - add a new elsif to fs_name() # - add new elsif to type=() and probably some optional commands IFF # non-destructive type conversion is supported # - update embedded type and provider documentation # - add a new value to type property in filesystem.rb # Required: commands :mkfs => "/sbin/mkfs", :dd => "/bin/dd" # Only the ones for filesystems actually in use are required: commands :tune2fs => "/sbin/tune2fs" # The following constants depend on the maximum offset of supported # filesystems' marker stucture. # # Whatever amount of bytes the magic number checks will require. INITIAL_BYTES = 0x45f # How many 512-byte sectors to wipe when destroying a filesystem, and # require when prefetching. INITIAL_SECTORS = (INITIAL_BYTES.to_f / 512).ceil mk_resource_methods # # Helper methods.. may qualify for moving into util? # def self.fs_name(device) data = File.new(device).read(INITIAL_BYTES) if data == nil raise Puppet::Error, "reading #{device} returned EOF" elsif data.length != INITIAL_BYTES raise Puppet::Error, "reading #{INITIAL_BYTES} bytes of #{device} resulted in short read" end # The following magic number checks are based on GNU # file 4.17 rules database debug sprintf("#{device} linux offset: [%02X%02X]", data[0x438], data[0x439]) debug sprintf("#{device} XFS offset: [%02X%02X%02X%02X]", data[0], data[1], data[2], data[3]) if data[0x438] == 0x53 and data[0x439] == 0xEF debug sprintf("#{device} ext[23] offset: [%02X%02X%02X%02X]", data[0x45c], data[0x45d], data[0x45e], data[0x45f]) return (data[0x45c] & 4) == 0 ? :ext2 : :ext3 elsif data[0] == 0x58 and data[1] == 0x46 and data[2] == 0x53 and data[3] == 0x42 return :xfs else return nil end end def self.make_fs(type, device) mkfs '-t', type, device end def self.wipe_fs(device) dd "if=/dev/zero", "bs=512", "count=#{INITIAL_SECTORS}", "of=#{device}" end def self.create_hash(path) h = { :device => path, :ensure => :present } begin h[:type] = fs_name(path) rescue Exception => e notice "fetching filesystem type of device \"#{path}\" failed: #{e}" puts e.backtrace if Puppet[:trace] return nil end h end # I'm not sure it's a good idea to try and read ALL such devices, even # if they are not defined, as it may cause delays and possibly problems # with network block devices, floppies, solid state devices, etc.. # # But apparently this method is required, so the best I can think of is # make some blacklist, etc. def self.instances providers = [] lines = File.new('/proc/partitions').readlines.reject { |l| l.strip.empty? } lines[1..-1].each do |line| fields = line.split.collect { |v| v.strip } path = "/dev/#{fields[3]}" if fields[2].to_i < INITIAL_SECTORS debug "Device \"#{path}\" is too short, ignoring" next end providers << new(create_hash(path)) end providers end def self.prefetch(resources) # Assign any providers we know of to matching resources instances.each do |provider| if fs = resources[provider.device] fs.provider = provider end end # Fetch providers for resources which are defined but # instances() does not know about them resources.each do |name,resource| unless resource.provider.exists? if h = create_hash(resource[:device]) resource.provider = new(h) end end end end def exists? @property_hash[:ensure] == :present end def create self.class.make_fs(@resource.should(:type), @resource[:device]) end def destroy self.class.wipe_fs(@resource[:device]) end def type=(type) path = @resource[:device] debug "type is: #{self.type}; should be: #{type}" if self.type == :ext2 and type == :ext3 tune2fs '-O', 'has_journal', path elsif self.type == :ext3 and type == :ext2 tune2fs '-O', '^has_journal', path else raise Puppet::Error, "Destructive changing filesystem type \"#{self.type}\" to \"#{type}\" avoided (destroy...@resource[:destroy]})" unless @resource[:destroy] == :ok self.class.wipe_fs(path) self.class.make_fs(type, path) end end end