Puppet Notes

4 minute read

Puppet failed my “First 5 Minutes Test” (TM), so I feel obliged to write down what I expect from a software distribution to offer me during our first five minutes together.

The Good

What are my objectives and therefore, what do I want to know during the first 5 minutes I start working with a new software tool? Simple: I want to install it on my localhost and use it to do something simple, end-to-end.

In the case of Puppet I wanted to install it and use it to install OpenLDAP, which I had done the day before manually.

The Bad

Even Google doesn’t really help here… There doesn’t seem to be an official introduction-like tutorial that quickly glances over the concepts, simply states what is needed and why and where to get it. I had to look for non-official blogposts to collect pieces of information to get to …

The Ugly

What I got was:

  • download links to Virtual Machines
  • requirements for three host-networks
  • required DNS servers

Really?

First 5 Minutes…

$ sudo puppet resource group puppet ensure=present
group { 'puppet':
  ensure => 'present',
}
$ sudo puppet resource user puppet ensure=present gid=puppet shell='/sbin/nologin'
Notice: /User[puppet]/shell: defined 'shell' as '/sbin/nologin'
user { 'puppet':
  ensure => 'present',
  gid    => '495',
}
  • Create /Library/LaunchDaemons/com.puppetlabs.puppet.plist:
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE plist PUBLIC "-//Apple Computer//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
<plist version="1.0">
<dict>
    <key>Label</key>
    <string>com.puppetlabs.puppet</string>
    <key>OnDemand</key>
    <false/>
    <key>ProgramArguments</key>
    <array>
        <string>/usr/bin/puppet</string>
        <string>agent</string>
        <string>--no-daemonize</string>
        <string>--logdest</string>
        <string>syslog</string>
        <string>--color</string>
        <string>false</string>
    </array>
    <key>RunAtLoad</key>
    <true/>
    <key>ServiceDescription</key>
    <string>Puppet agent service</string>
    <key>ServiceIPC</key>
    <false/>
    <!-- added to log to own files, not system.log -->    
    <key>StandardErrorPath</key>
    <string>/var/log/puppet/puppet.err</string>
    <key>StandardOutPath</key>
    <string>/var/log/puppet/puppet.out</string>
</dict>
</plist>
$ sudo chown root:wheel /Library/LaunchDaemons/com.puppetlabs.puppet.plist
$ sudo chmod 644 /Library/LaunchDaemons/com.puppetlabs.puppet.plist
$ sudo mkdir /var/log/puppet
$ sudo chown puppet:puppet /var/log/puppet
$ sudo chmod 755 /var/log/puppet
[main]
dns_alt_names = playground.local
server=playground.local

[agent]
report=true
$ sudo puppet master --verbose --no-daemonize
Info: Creating a new SSL key for ca
Info: Creating a new SSL certificate request for ca
Info: Certificate Request fingerprint (SHA256): BC:FF:43:B5:5D:87:E7:FB:43:...
Notice: Signed certificate request for ca
Info: Creating a new certificate revocation list
Info: Creating a new SSL key for playground.local
Info: csr_attributes file loading from /etc/puppet/csr_attributes.yaml
Info: Creating a new SSL certificate request for playground.local
Info: Certificate Request fingerprint (SHA256): 69:A9:0D:A1:7D:C3:08:B4:83:...
Notice: playground.local has a waiting certificate request
Notice: Signed certificate request for playground.local
Notice: Removing file Puppet::SSL::CertificateRequest playground.local at '/etc/puppet/ssl/ca/requests/playground.local.pem'
Notice: Removing file Puppet::SSL::CertificateRequest playground.local at '/etc/puppet/ssl/certificate_requests/playground.local.pem'
Notice: Starting Puppet master version 3.7.4
^CNotice: Caught INT; calling stop
  • Create an (for now) empty site.pp:
$ sudo touch /etc/puppet/manifests/site.pp
  • Create /Library/LaunchDaemons/com.puppetlabs.puppetmaster.plist:
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE plist PUBLIC "-//Apple Computer//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
<plist version="1.0">
<dict>
    <key>Label</key>
    <string>com.puppetlabs.puppetmaster</string>
    <key>OnDemand</key>
    <false/>
    <key>ProgramArguments</key>
    <array>
        <string>/usr/bin/puppet</string>
        <string>master</string>
        <string>--verbose</string>
        <string>--no-daemonize</string>
    </array>
    <key>RunAtLoad</key>
    <true/>
    <key>ServiceDescription</key>
    <string>Puppetmaster service</string>
    <key>ServiceIPC</key>
    <false/>
    <!-- added to log to own files, not system.log -->    
    <key>StandardErrorPath</key>
    <string>/var/log/puppet/puppet.err</string>
    <key>StandardOutPath</key>
    <string>/var/log/puppet/puppet.out</string>
</dict>
</plist>
$ sudo chown root:wheel /Library/LaunchDaemons/com.puppetlabs.puppet.plist
$ sudo chmod 644 /Library/LaunchDaemons/com.puppetlabs.puppet.plist
  • Start master and agent …
$ sudo puppet resource service com.puppetlabs.puppet ensure=running enable=true
Notice: /Service[com.puppetlabs.puppet]/ensure: ensure changed 'stopped' to 'running'
service { 'com.puppetlabs.puppet':
  ensure => 'absent',
}

$ sudo puppet resource service com.puppetlabs.puppetmaster ensure=running Notice: /Service[com.puppetlabs.puppetmaster]/ensure: ensure changed 'stopped' to 'running'
service { 'com.puppetlabs.puppetmaster':
  ensure => 'absent',
}
  • To avoid error messages … create a dummy module foo and a fact.d directory in it:
$ sudo mkdir -p /etc/puppet/modules/foo/facts.d
  • test …
$ sudo puppet agent --test
Info: Retrieving pluginfacts
Notice: /File[/var/lib/puppet/facts.d]/group: group changed 'puppet' to 'wheel'
Info: Retrieving plugin
Notice: /File[/var/lib/puppet/lib]/group: group changed 'puppet' to 'wheel'
Info: Caching catalog for playground.local
Info: Applying configuration version '1423825915'
Notice: Finished catalog run in 0.01 seconds

The notices can safely be ignored. That’s puppet improving on its own configuration :-)

Installing OpenLDAP using Puppet

  • Prepare the module tree structure:
$ sudo mkdir -p /etc/puppet/modules/openldap/{facts.d,manifests}
  • Create /etc/puppet/modules/openldap/manifests/init.pp:
class openldap {
  package { 'openldap':
    ensure => installed,
    provider => 'macports'
  }
}
  • Configure the agent/client in /etc/puppet/manifests/site.pp:
node default { }

node 'playground.local' {
  include openldap
}
  • Now wait .. until the agent and master talk to each other and update the agent’s configuration, or trigger the update yourself:
$ sudo port uninstall openldap
--->  Deactivating openldap @2.4.40_0
--->  Cleaning openldap
--->  Uninstalling openldap @2.4.40_0
--->  Cleaning openldap

$ port contents openldap
Port openldap is not installed.

$ sudo puppet agent --test
Info: Retrieving pluginfacts
Info: Retrieving plugin
Info: Caching catalog for playground.local
Info: Applying configuration version '1423832966'
Notice: /Stage[main]/Openldap/Package[openldap]/ensure: created
Notice: Finished catalog run in 4.37 seconds

$ port contents openldap
Port openldap contains:
  /Library/LaunchDaemons/org.macports.slapd.plist
  /opt/local/bin/ldapadd
  /opt/local/bin/ldapcompare
  ...

Intermezzo

Puppet’s architecture with agents and master(s) makes sense, but if the end goal is to manage a single host, a more basic setup can be constructed, just with puppet and a manifest file.

Given openldap.pp, e.g. in ~/manifests:

package { 'openldap':
  ensure => installed,
  provider => 'macports'
}

We can simply use puppet apply

$ sudo puppet apply --test openldap.pp 
Notice: Compiled catalog for playground.local in environment production in 0.38 seconds
Info: Applying configuration version '1423833802'
Notice: /Stage[main]/Main/Package[openldap]/ensure: created
Notice: Finished catalog run in 3.23 seconds

Now add Git(Hub) in the mix … :-)

TODO

  • add configuration using templates + variables
  • start/stop service
  • add more background