Cloudevelops The Official Cloudevelops Blog

Creating a simple Puppet fact

Basically puppet fact is just ruby script that is executed by puppet and returns certain value depending on which host it is. So creating own facts is not so hard and can be useful when you want to select specific hosts with some similar attributes.

Let’s look at example of facter fact that shows file system type that current mount point is using:

 1 require 'facter'
 3 Facter.add("rootfs_type", :timeout => 120) do
 4   confine :osfamily => "Debian"
 6   setcode do
 7     dfoutput = Facter::Util::Resolution.exec('df -Tl /')
 8     rootfs_type = dfoutput.split(/\n+/)[1].split(" ")[1]
 9     rootfs_type
10   end
12 end

1: require 'facter' - used to add some facter specific functionality to our facter ruby script

3: Facter.add - used to define fact name with some additional parameters (like execution timeout)

4: we can limit fact execution to some specific OS family, release, codename, etc. with confine directive

6: setcode - statement is used to determine the fact’s value;

7: our simple fact use Facter::Util::Resolution.exec function that executes df system command and which is source of our informantion about filesystem type

8: code can contain or do anything that ruby can

Fetching other facts is also possible - with Facter.value(<facter name>) function.

Custom facts are stored at lib/facter/ directory of puppet module and are added to hosts with puppet installed during next puppetizing.

After all done we can check if our fact is available on puppetized host:

sudo facter -p rootfs_type

After that fact can be used as ordinary variable at any puppet module. For example we can create cron job that is created only on hosts with btrfs file system that relocate chunks with less than 5% of usage :

 1 if $::rootfs_type == 'btrfs' {
 2     cron {
 3       'btrfs-balance':
 4         ensure   => present,
 5         command  => '/sbin/btrfs fi balance start -dusage=5 /',
 6         user     => 'root',
 7         hour     => '0',
 8         minute   => '0',
 9         monthday => '1',
10     }
11   }

More about puppet facts:

Puppet Custom Facts Walkthrough

Just another way to get Let's Encrypt certificate with puppet and hiera for Nginx

Let’s Encrypt is a new certificate authority (CA) offering free and automated SSL/TLS certificates. Certificates issued by Let’s Encrypt are trusted by most browsers in production. As Let’s Encrypt client does not yet officially support NGINX (nginx plugin is in beta) we will use webroot plugin for getting it’s certificates. This post show puppet snippets that ease process of getting them upto simple including puppet module and defining all needed parameters at puppet hiera.

Assume we have puppet wrapper module that adds some organization specific functionality to danzilio/puppet-letsencrypt module.

Call create_resources at init class of our wrapper module to create domains from $base_domains_list with specified parameters:

class letsencrypt_base (
  $base_domains_list   = undef,
  if $base_domains_list {
    create_resources('letsencrypt_base::domain', $base_domains_list, {require => Class['letsencrypt']})

Example of hiera parameters at base_domains_list in json:

"letsencrypt_base::email": "<email>",
  "letsencrypt_base::base_domains_list": {
    "<domain that will use Let's Encrypt certificates>": {
      "plugin": "webroot",
      "vhost_name": "<vhost_name>",
      "webroot_paths": "<path to webroot dir>"

Defined resource example:

define letsencrypt_base::domain (
  $base_domain          = $name,
  $webroot_paths        = '/var/www/letsencrypt',
  $plugin               = 'webroot',
  $additional_args      = undef,
  $manage_cron          = false,
  $letsencrypt_command  = $letsencrypt::command,
  $vhost_name           = $base_domain

# request letsencrypt for certificates (will be stored at :/etc/letsencrypt/live/<domain name>/)
  letsencrypt::certonly { $base_domain:
    domains         => [$base_domain],
    plugin          => $plugin,
    webroot_paths   => [$webroot_paths],
    require         => File[$webroot_paths],
    manage_cron     => $manage_cron,
    additional_args => $additional_args

# Location for our domain. needed for confirmation that you are owner of domain.
# The Let’s Encrypt client running on  host creates a temporary file (a token) with the required information in it. The Let’s Encrypt validation server makes an HTTP request to retrieve the file and validates the token, which serves to verify that the DNS record for your domain resolves to the server running the Let’s Encrypt client.
  nginx::resource::location { $base_domain:
    ensure     => present,
    www_root   => $webroot_paths,
    location   => '/.well-known/acme-challenge',
    vhost      => $vhost_name,
    auth_basic => 'off',
    require    => File[$webroot_paths],

#create folder that will be used by letsencrypt
  file { $webroot_paths:
    ensure => 'directory',
    owner  => 'www-data',
    group  => 'www-data',
    mode   => '0755',


Modules used:

Let’s Encrypt puppet module

Nginx puppet module that location defined resource use

Nginx article about Let’s Encrypt

CLI magic

Today we would like to share some CLI magic. So for example instead of using this long bash spaghetti command:

ip=$(/sbin/ifconfig | grep "inet addr" | grep -v 127.0. | sed -r "s/.*addr:([^ ]+) .*/\1/") - here we want to find all IP addresses on target host.

You can just use this simple and clear basic command:

hostname -I

Check out man page for hostname command too: hostname