adrift on a cosmic ocean

Writings on various topics (mostly technical) from Oliver Hookins and Angela Collins. We have lived in Berlin since 2009, have two kids, and have far too little time to really justify having a blog.

Puppet - create a resource within a function using hash2resource

Posted by Oliver on the 26th of October, 2010 in category Tech
Tagged with: hash2resourcepuppet

I searched everywhere for an example of this but couldn't find one, so I stumbled through and got it working myself and am documenting it here in case it ever shows up on Google and helps someone. The premise is: you have some crazy variables that you want to turn into resources of some kind, but there's no way to do it using the declarative methods within Puppet. Most notably lacking is usually the for loop, and that's what I'll be hacking around to provide.

This slightly contrived example takes a bunch of variables which represent things we might to give to libvirt in order to create a storage pool. We have a fixed number of fields, but no limit to how many entities are created (so the arrays can be as long as we want). Perfect for the missing for loop to create:

modules/virtualization/plugins/puppet/parser/functions/storagepool_construct.rb:
module Puppet::Parser::Functions
    newfunction(:storagepool_construct, :type => :statement) do |args|
        # Hard-coded number of parameters
        args.length == 5 or raise Puppet::Errors.new("storagepool_construct takes 5 arguments!")

        # Process the parameters in this order:
        #  - storagepool_src_name
        #  - storagepool_type
        #  - storagepool_src_host
        #  - storagepool_src_path
        #  - storagepool_src_target
        if args[0].class == Array then
            (0..(args[0].length - 1)).each do |i|
                catalog.add_resource Puppet::Type.type(:file).hash2resource({:title => "/tmp/#{args[0][i]}", :content => "#{args[1][i]} #{args[2][i]} #{args[3][i]} #{args[4][i]}"})
            end
        elsif args[0].class == String then
            catalog.add_resource Puppet::Type.type(:file).hash2resource({:title => "/tmp/#{args[0]}", :content => "#{args[1]} #{args[2]} #{args[3]} #{args[4]}"})
        end
    end
end
modules/virtualization/manifests/storage.pp:
class virtualization::storage {
    storagepool_construct($storagepool_src_name, $storagepool_type, $storagepool_src_host, $storagepool_src_path, $storagepool_src_target)
}
modules/virtualization/test/storage.pp:
$storagepool_src_name = ['iscsi-host5', 'iscsi-host6']
$storagepool_type = ['iscsi', 'iscsi']
$storagepool_src_host = ['host5', 'host6']
$storagepool_src_path = ['iqn.2010-01.master:esitbi036lab', 'iqn.foo']
$storagepool_src_target = ['/dev/disk/by-path', '/dev/disk/by-path']

include virtualization::storage

So, we have a couple of test storagepools we want to set up. For the moment I'm just creating file resources as a proof of concept - the next step is to write a libvirt type and provider for storagepool creation. The output when we run Puppet on the test manifest is now as follows:

$ puppet -v --modulepath ../ test/storage.pp
info: Autoloaded module virtualization
info: Autoloaded file virtualization/storage from module virtualization
info: Applying configuration version '1288079226'
notice: /File[/tmp/iscsi-host6]/content: defined content as 'unknown checksum'
notice: /File[/tmp/iscsi-host5]/content: defined content as 'unknown checksum'

And that's how it is done - probably not in the best style, but it does work.

© 2010-2018 Oliver Hookins and Angela Collins