Exported resources
When we need to provide information to a host about resources present in another host, things in Puppet become trickier. This can be needed for example, for monitoring or backup solutions. The only official solution has been, for a long time, to use exported resources; resources declared in the catalog of a node (based on its facts and variables), but applied (collected) on another node. Some alternative approaches are now possible with PuppetDB, we will review them in Chapter 3, Introducing PuppetDB.
Resources are declared with the special @@
notation, which marks them as exported so that they are not applied to the node where they are declared:
@@host { $::fqdn: ip => $::ipaddress, } @@concat::fragment { "balance-fe-${::hostname}": target => '/etc/haproxy/haproxy.cfg', content => "server ${::hostname} ${::ipaddress} maxconn 5000", tag => "balance-fe", }
Once a catalog containing exported resources has been applied on a node and stored by the Puppet Master, the exported resources can be collected with the <<| |>>
operator, where it is possible to specify search queries:
Host <<| |>> Concat::Fragment <<| tag == "balance-fe" |>> Sshkey <<| |>> Nagios_service <<| |>>
In order to use exported resources, we need to enable on the Puppet Master the storeconfigs
option and specify the backend to be used. For a long time, the only available backend was Rails' active records, which typically used MySQL for data persistence. This solution was the best for its time, but suffered severe scaling limitations. Luckily, things have changed, a lot, with the introduction of PuppetDB, which is a fast and reliable storage solution for all the data generated by Puppet, including exported resources.
Virtual resources
Virtual resources define a desired state for a resource without adding it to the catalog. Like normal resources, they are applied only on the node where they are declared, but, as virtual resources, we can apply only a subset of the ones we have declared; they have also a similar usage syntax: we declare them with a single @
prefix (instead of the @@
used for exported resources), and we collect them with <| |>
(instead of <<| |>>
).
A useful and rather typical example involves user's management.
We can declare all our users in a single class, included by all our nodes:
class my_users { @user { 'al': […] tag => 'admins' } @user { 'matt': […] tag => 'developers' } @user { 'joe': [… tag => 'admins' } [ … ] }
These users are actually not created on the system; we can decide which ones we actually want on a specific node with a syntax like this:
User <| tag == admins |>It is equivalent to: realize(User['al'] , User['joe'])
Note that the realize
function needs to address resources with their name.