When I began using puppet, I quickly realised that configuration data was best kept separate from puppet manifests. Initially, I used extlookup and kept configuration data in CSV files. Then complex data structures came to puppet and I now use hirea/hiera-puppet with configuration data stored in hierarchical YAML files (other hiera backends are available). This article describes how to define in YAML the resources that should be applied to a node.
I have been using the hiera_include function for some time to define which classes are applied to each node. Usage is fairly simple. I have this fragment in nodes.pp:
node default {hiera_include('classes')}
Then, in an hiera YAML file I have something like this:
classes: - role::monitoring - role::dns::master
At run time, the puppet classes role::monitoring and role::dns::master are applied to the node. Note, this could be in a node-specific config file, or something more generic that applied to several nodes.
This all works fine, but is limited to static classes. What if you have defined classes and you want to apply multiple instances of the same defined class on one node?
Let's suppose you have a puppet define that puts an apache website configuration on a node:
define apache::website::instance( $ListenIP, $ServerAlias = [], $config = '') {# clever code goes here to instantiate the apache vhost}You would use this define something like this:
apache::website::instance{'www.example.com': ListenIP => '1.2.3.4', ServerAlias => ['example.com', 'foo.example.com'], config => 'DocumentRoot /var/www/sites/example<Directory /var/www/sites/example/> AllowOverride None Options +Indexes</Directory>'}With the addition of a new custom puppet function it becomes possible to define the previous example in a YAML file.
Put the following content in $PUPPET_MODULE_DIR/custom/lib/puppet/parser/functions/hiera_resources.rb:
module Puppet::Parser::Functions newfunction(:hiera_resources, :type => :statement) do |args| raise Puppet::Error, "hiera_resources requires 1 argument; got #{args.length}" if args.length != 1 res_name = args[0][0] apps = function_hiera_hash([res_name, {}]) apps.each { | res_type, res_params | function_create_resources([res_type, res_params]) } endendAnd add this to nodes.pp:
node default { hiera_resources('resources')}Now, to create the resource as in the previous example, add this to the hiera config:
resources: apache::website::instance: 'www.example.com': ListenIP: '1.2.3.4' ServerAlias: - 'example.com' - 'foo.example.com' config: |- DocumentRoot /var/www/sites/example <Directory /var/www/sites/example/> AllowOverride None Options +Indexes </Directory>
You can now add resource to nodes dynamically by editing your hiera config!
Thanks to:
Comments