DEPRECATION NOTICE:
This article is no longer relevant and exists for historical purposes only. The Ruby DSL was an experimental project that added the ability to write Puppet code in pure Ruby. It was never widely adopted and was eventually completely removed in Puppet 4.0.
The new Ruby DSL for Puppet (available in 2.6.0 and later) has introduced lots of interesting new ways you can articulate Puppet code. One of the more interesting new ways is the ability to mix and match Ruby code with the Puppet Ruby DSL. I'm going to show you an example of this using stand-alone Puppet and a CMDB in a MySQL database. This probably isn't something you'd do on a production host, rather you'd store this data in an external node classifier, but it shows what sort of extensibility is available.
I've assumed you've got Puppet installed on your host and that you've got a MySQL server running somewhere that we can add a database (and some data) to. We're going to start by installing the
mysql
gem that allows us to interact with MySQL databases in Ruby.
$ gem install mysql
You'll need the MySQL development libraries to install the gem. You can install these via your distribution's packaging system, on Ubuntu for example the
libmysqlclient-dev
package needs to be installed.
Next, we're going to sign into our MySQL server and create a database.
$ mysql -u root -p
mysql> create database cmdb;
mysql> use cmdb;
mysql> create table packages (id VARCHAR(2), name VARCHAR(40), version VARCHAR(20));
mysql> insert into packages values ( 1,"vim","2:7.2.330-1ubuntu4");
mysql> quit;
Here we've signed into MySQL, created a database called
cmdb
and a table called
packages
. We've then added just one package to our table:
vim
with a version of
2:7.2.330-1ubuntu4
.
Now that we've got our CMDB (you've hopefully got a more sophisticated one...) we can use its data in Puppet. To do we're going to write a Puppet manifest in the new Ruby DSL. Let's start by creating a new file to hold our manifest.
$ touch packages.rb
You'll notice rather than the usual
.pp
manifest file we've created a file with a Ruby or
.rb
suffix. This lets us and Puppet know that this is a Ruby DSL file. Now let's put some code into our
packages.rb
file:
require 'mysql'
hostclass :packages do
conn = Mysql.new('localhost', 'user', 'password', 'cmdb')
pkgs = conn.query('select * from packages')
pkgs.each_hash { |p| package p['name'], :ensure => p['version'] }
conn.close
end
node 'default' do
include 'packages'
end
You'll notice we've created something that looks just like a normal Ruby program.
First required the
mysql
gem and then created a new Puppet class, called packages, using the
hostclass
block. Inside this class we've connected to our MySQL server, passing it the server, username, password and the database to connect to. We've assumed our server is located locally but you could easily specify a remote MySQL server. We've then selected all the records in the
packages
table and added the values to a hash called
pkgs
.
Taking this hash we've iterated through it, passing the results to a block. Inside our block is some more Puppet Ruby DSL, this time we've defined some
package
resources:
package p['name'], :ensure => p['version']
Each resource uses the name of the name and version fields from the packages table to create a new package resource. This is the equivalent of creating a standard Puppet package resource like so:
package { "vim":
ensure => "2:7.2.330-1ubuntu4",
}
Lastly, we've closed the MySQL connection and specified that the
packages
class should be included in the
default
node.
Once we've saved this file we can use Puppet in stand-alone mode to run and install our packages:
$ puppet apply --verbose packages.rb
notice: /Stage[main]/Packages/Package[vim]/ensure: ensure changed 'purged' to '2:7.2.330-1ubuntu4'
notice: Finished catalog run in 0.51 seconds
Notice our results? Yep, Puppet happily installed the
vim
package at the required version. It did this by connecting to the MySQL database, retrieving the required data, creating a Puppet resource using the Ruby DSL, and then executing that resource and installing the package.
That's just a small example of how powerful the new Ruby DSL (in combination with the power of Ruby itself) can be!