Friday, September 5, 2014

Build Puppet module to use Hiera lookup

Puppet can use Hiera to look up data. This helps you disentangle site-specific data from Puppet code, for easier code re-use and easier management of data that needs to differ across your node population

One typical example is IP address and NTP/DNS servers, the IP address is unique for each server and NTP/DNS is global. I built a linux-network test module to demonstrate the usage of Hiera
Hiera supports yaml and Json as backend by default, however you can write your  custom backend using Hiera API.

Define datadir in hiera.yaml
[root@server1 modules]# cat /etc/puppetlabs/puppet/hiera.yaml 
---
:backends:
  - yaml

:hierarchy:
  - defaults
  - "%{clientcert}"
  - "%{environment}"
  - global

:yaml:
# datadir is empty here, so hiera uses its defaults:
# - /var/lib/hiera on *nix
# - %CommonAppData%\PuppetLabs\hiera\var on Windows
# When specifying a datadir, make sure the directory exists.
  :datadir: /etc/puppetlabs/puppet/hieradata

Set all values in YAML file instead of manifest file
You can also add class name in YAML file, then assign class to node with hiera_include
[root@server1 modules]# cat /etc/puppetlabs/puppet/hieradata/global.yaml 
---
#
# ntp.conf
ntpservers: [10.1.1.11, 10.1.1.12]

#resolv.conf
domainname: example.com
searchdomain: [example1.com, example2.com]
nameservers: [10.1.1.13, 10.1.1.14]

[root@server1 modules]# cat /etc/puppetlabs/puppet/hieradata/server1.example.com.yaml 
eth1:
   device: eth1
   ipaddr: 172.16.1.2
   netmask: 255.255.255.0
   routes: ['192.168.1.0/24 via 172.16.1.254', '192.168.2.0/24 via 172.16.1.254']
   gateway: 172.16.1.254
eth3:
   device: eth3
   ipaddr: 172.16.1.3
   netmask: 255.255.255.0
   #routes: ['192.168.1.0/24 via 172.16.1.254', '192.168.2.0/24 via 172.16.1.254']
Execute the whole class or a function of the class in site.pp, the codes in site.pp become universal.
The site.pp manifest file is just generic code
[root@server1 modules]# cat /etc/puppetlabs/puppet/manifests/site.pp

node "server1" {
include "linux-network"
}

node "server2" {
linux-network::setinterface { 'eth1': }
}
linux-network module manifest files
[root@server1 modules]# cat ./linux-network/manifests/init.pp 
class linux-network {
 linux-network::setinterface { 'eth1': ; 'eth3': }
 linux-network::setroute { 'eth1': ; 'eth3':}

 linux-network::setconf_ntp {'ntp.conf':}
 linux-network::setconf_resolv {'resolv.conf':}
}

[root@server1 modules]# cat ./linux-network/manifests/setconf_ntp.pp 
define linux-network::setconf_ntp  ( ) {

$ntpservers=hiera_array('ntpservers')

file {"/etc/ntp.conf":
 ensure => present,
 owner => root,
 mode => 644,
 content => template("${module_name}/ntp.conf.erb")
 }
}

[root@server1 modules]# cat ./linux-network/manifests/setconf_resolv.pp 
define linux-network::setconf_resolv  ( ) {

$domainname=hiera('domainname')
$searchdomain=hiera_array('searchdomain')
$nameservers=hiera_array('nameservers')

file {"/etc/resolv.conf":
ensure => present,
owner => root,
mode => 644,
content => template("${module_name}/resolv.conf.erb")
 }
}

[root@server1 modules]# cat ./linux-network/manifests/setinterface.pp 
define linux-network::setinterface  ( ) {

$device=$title
$eth=hiera($device)
$ipaddr=$eth['ipaddr']
$netmask=$eth['netmask']
$gateway=$eth['gateway']

file {"/etc/sysconfig/network-scripts/ifcfg-$device":
 ensure => present,
 owner => root,
 mode => 644,
 content => template("${module_name}/ifcfg.erb")
 }

}

[root@server1 modules]# cat ./linux-network/manifests/setroute.pp 
define linux-network::setroute  ( ) {

$device=$title
$eth=hiera($device)
$routes=$eth['routes']

file {"/etc/sysconfig/network-scripts/route-$device":
ensure => present,
owner => root,
mode => 644,
content => template("${module_name}/route.erb")
 }
}
linux-network module template files
[root@server1 modules]# cat ./linux-network/templates/ifcfg.erb 
DEVICE=<%=@device %>
BOOTPROTO=static
ONBOOT=yes
USERCTL=no
IPADDR=<%=@ipaddr%>
NETMASK=<%=@netmask%>
<%- if @gateway =~ /(\d{1,3})\.(\d{1,3})\.(\d{1,3})\.(\d{1,3})/   -%>
GATEWAY=<%=@gateway %>
<%- end -%>

[root@server1 modules]# cat ./linux-network/templates/ntp.conf.erb 
 tinker panic 0
 restrict default kod nomodify notrap nopeer noquery
 restrict -6 default kod nomodify notrap nopeer noquery
 restrict 127.0.0.1 
 restrict -6 ::1
#
 <%- @ntpservers.each do |x| -%>
 server <%= x %>
<%- end  -%>
 driftfile /var/lib/ntp/drift

 [root@server1 modules]# cat ./linux-network/templates/resolv.conf.erb
#
# resolver configuration file...
#
options         timeout:1 attempts:8 rotate
domain       <%=@domainname %>
<%-  if !@searchdomain.empty?   -%>
search <%=@domainname  -%> <%=  @searchdomain.join(' ') %>
<%- end -%>
<%-  @nameservers.each do |  x | -%>
nameserver <%= x %>
<%- end -%>

[root@server1 modules]# cat ./linux-network/templates/route.erb 
<%- if defined?(@routes)   -%>
<%- @routes.each do | x | -%>
<%=x %>
<%- end -%>
<%- end -%>