After deploying Rundeck, I set out a few todo’s for later. One of those was switching to the puppetdb_rundeck gem. After some manual testing, I found out that it actually worked as a drop-in replacement for the scripts that I had now. It even fixed the hostname issue. Only one drawback: it did not populate the tags automatically with the classes. On the other hand, that meant that I could customize the tags!

First things first: use the gem instead of the scripts I had. I could remove a lot of the code from my puppet profile for Rundeck. I only kept the Systemd unit file (slightly modified) and added a package requirement:

$sinatra_application = 'puppetdb-rundeck'
$sinatra_entrypoint = '/usr/local/bin/puppetdb_rundeck'
$sinatra_parameters = '--pdbhost localhost --pdbport 8080 --port 8144'

file { "/etc/systemd/system/${sinatra_application}.service":
	ensure => file,
	content => template('profile/sinatra.service.erb');
}

service { $sinatra_application:
	ensure  => running,
	enable  => true,
	require => [File["/etc/systemd/system/${sinatra_application}.service"], Package['puppetdb_rundeck']],
}

The content of templates/sinatra.service.erb:

[Unit]
Description=<%= @sinatra_application %> (sinatra)

[Service]
ExecStart=<%= @sinatra_entrypoint %> <%= @sinatra_parameters %>
ExecStop=/bin/kill -TERM $MAINPID

The new service was listening on the old service’s port, but the url was slightly different. This was the new url to put as the Rundeck project’s resource source: http://localhost:8144/api/yaml

Refreshing the node list gave me what I expected: the list of nodes, but without tags. Now providing some tags. In the same puppet module, I added a custom fact tags, which would be a comma-separated list of all the tags I wanted to have per node. I would use the classes like the old script did, and add some very specific ones. Since I use the “roles and profiles” pattern (and profiles mapped to classes), I wanted to add roles as tags. I went a little further with this, since I have also subroles, and servers have tiers too (test, quality and production). This is the full code:

File: lib/facter/tags.rb

Facter.add(:tags) do
  setcode do
    begin
      Facter.hostname
    rescue
      Facter.loadfacts()
    end

    hostname = Facter.value('hostname')

    classes_txt = "/var/lib/puppet/state/classes.txt"

    if File.exists?(classes_txt) then
      class_tags = File.read(classes_txt).split("\n").map do |line|
        line = line.chomp.to_s
      end - ["settings", "#{hostname}"]
    else
      class_tags = []
    end

    auto_tags = [
      Facter.value(:tier),
      Facter.value(:role),
      [Facter.value(:role), Facter.value(:subrole)].join('/'),
    ].compact

    tags = (class_tags + auto_tags).uniq.sort.join(",")
    tags
  end
end

Every puppet node running the new code will now publish a list of tags as a fact, which will be picked up by Rundeck.