Ruby: Friend or Foe

Ruby: Friend or Foe

Written: 2017-08-09
Author: Laura Macchi

Ruby is a relatively newer language, so you might not have any experience with it. Why use Ruby when there’s Bash, Perl, or Python…stuff gets done, so all good, right?

But you heard about this trendy topic- “configuration management” -and decided you wanted to be a part of it. You evaluated your options and decided on Puppet (of course!). So now you’re wondering…how much Ruby do you need to know in order to be effective in Puppet?

Puppet Language

Puppet has its own domain-specific language (DSL), used to describe the perfect state of your system resources. In order to create a user, the code looks like this:

user { 'laura':
  ensure => present,
  gid    => 'wheel',
  home   => '/home/laura',
}

Puppet provides a lot of resources out of the box and many more can be added by implementing modules from the Puppet Forge in your Puppet environments. All of those resources will be described using Puppet language.

Just like that, our systems are in their desired state. No Ruby needed.

But wait! I’ve heard you can create dynamic content, and that you need Ruby to do it. Is that so?

Templates

You’re in luck, my friend. Starting in Puppet 4, dynamic content can be generated using not only Ruby templates, but Puppet templates as well!

Let’s create some content for our motd file:

Welcome to <%= $facts['fqdn'] %>.
This is a <%= $facts['os']['name'] %> system.
Available interfaces are: : <%= join($facts['networking']['interfaces'].keys, ',') %>

When the above block gets parsed with the epp() function:

file { '/etc/motd':
  ensure => file,
  content => epp('motd/motd.epp'),
}

It will output something that looks like this:

Welcome to laura.puppet.net.
This is a CentOS system.
Available interfaces are: eth0,lo

That’s cool, but I see there you’re using facts, so let’s talk about facts. They’re done in Ruby, correct?

Facts

Facts can indeed be written in Ruby. Facts are going to, by default, be executed in all the nodes in the infrastructure. They need to be written in a language that every operating system in your farm can understand. Puppet runs on Ruby, so it is an easy way to guarantee the fact you’ve written will be understood by all your systems.

But what if I don’t want to learn Ruby? Puppet provides some alternatives for you:

  1. Structured data facts. Written in plain text, yaml or json, they allow you to extend your facts. As a disadvantage, these live on the node itself, so you’re in charge of distributing them and anyone with write access to the node can change the values.
  2. Executable facts. They allow you to write scripts in any language your nodes understand. They can be distributed from within a module (facts.d directory), but as a disadvantage, they only support strings as fact values.

Functions

In the motd example above, I used the stdlib functions keys() and join(). You can find a lot of functions included in Puppet and many more in stdlib and other modules on the Puppet Forge. But what if you need to create your own? Do you need to know Ruby?

With the addition of more complex language features in Puppet 4, we’ve added the ability to create functions in Puppet language. This example found in the Puppet documentation, shows a refactor of a Ruby function using Puppet language.

Conclusion

Puppet uses Ruby as its interpreter, so knowing your way around the language will allow you to extend the language by writing types, providers, puppet faces and other advanced extensions. Currently, Puppet provides mechanisms to allow you to only use Puppet language to customize your Puppet environment, as well as a lot of already written extensions found on the Forge, to spend less time learning Ruby and more time getting your systems to their desired state.