Using exported resources
All our recipes up to this point have dealt with a single machine. It is possible with Puppet to have resources from one node affect another node. This interaction is managed with exported resources. Exported resources are just like any resource you might define for a node but instead of applying to the node on which they were created, they are exported for use by all nodes in the environment. Exported resources can be thought of as virtual resources that go one step further and exist beyond the node on which they were defined.
There are two actions with exported resources. When an exported resource is created, it is said to be defined. When all the exported resources are harvested, they are said to be collected. Defining exported resources is similar to virtual resources; the resource in question has two @
symbols prepended. For example, to define a file resource as external, use @@file
. Collecting resources is done with the space ship operator, <<| |>>
; this is thought to look like a spaceship. To collect the exported file resource (@@file
), you would use File <<| |>>
.
There are many examples that use exported resources; the most common one involves SSH host keys. Using exported resources, it is possible to have every machine that is running Puppet share their SSH host keys with the other connected nodes. The idea here is that each machine exports its own host key and then collects all the keys from the other machines. In our example, we will create two classes; first, a class that exports the SSH host key from every node. We will include this class in our base class. The second class will be a collector class, which collects the SSH host keys. We will apply this class to our Jumpboxes or SSH login servers.
Note
Jumpboxes are machines that have special firewall rules to allow them to log in to different locations.
Getting ready
To use exported resources, you will need to enable storeconfigs on your Puppet masters. It is possible to use exported resources with a masterless (decentralized) deployment; however, we will assume you are using a centralized model for this example. In Chapter 2, Puppet Infrastructure, we configured puppetdb using the puppetdb module from the forge. It is possible to use other backends if you desire; however, all of these except puppetdb are deprecated. More information is available at the following link: http://projects.puppetlabs.com/projects/puppet/wiki/Using_Stored_Configuration.
Ensure your Puppet masters are configured to use puppetdb as a storeconfigs container.
How to do it...
We'll create an ssh_host
class to export the ssh
keys of a host and ensure that it is included in our base class.
- Create the first class,
base::ssh_host
, which we will include in our base class:class base::ssh_host { @@sshkey{"$::fqdn": ensure => 'present', host_aliases => ["$::hostname","$::ipaddress"], key => $::sshdsakey, type => 'dsa', } }
- Remember to include this class from inside the base class definition:
class base { ... include ssh_host }
- Create a definition for
jumpbox
, either in a class or within the node definition forjumpbox
:node 'jumpbox' { Sshkey <<| |>> }
- Now run Puppet on a few nodes to create the exported resources. In my case, I ran Puppet on my Puppet server and my second example node (
node2
). Finally, run Puppet onjumpbox
to verify that the SSH host keys for our other nodes are collected:[root@jumpbox ~]# puppet agent -t Info: Caching catalog for jumpbox.example.com Info: Applying configuration version '1413176635' Notice: /Stage[main]/Main/Node[jumpbox]/Sshkey[node2.example.com]/ensure: created Notice: /Stage[main]/Main/Node[jumpbox]/Sshkey[puppet]/ensure: created Notice: Finished catalog run in 0.08 seconds
How it works...
We created an sshkey
resource for the node using the facter facts fqdn
, hostname
, ipaddress
, and sshdsakey
. We use the fqdn
as the title for our exported resource because each exported resource must have a unique name. We can assume the fqdn
of a node will be unique within our organization (although sometimes they may not be; Puppet can be good at finding out such things when you least expect it). We then go on to define aliases by which our node may be known. We use the hostname variable for one alias and the main IP address of the machine as the other. If you had other naming conventions for your nodes, you could include other aliases here. We assume that hosts are using DSA keys, so we use the sshdsakey
variable in our definition. In a large installation, you would wrap this definition in tests to ensure the DSA keys existed. You would also use the RSA keys if they existed as well.
With the sshkey
resource defined and exported, we then created a jumpbox
node definition. In this definition, we used the spaceship syntax Sshkey <<| |>>
to collect all defined exported sshkey
resources.
There's more...
When defining the exported resources, you can add tag attributes to the resource to create subsets of exported resources. For example, if you had a development and production area of your network, you could create different groups of sshkey
resources for each area as shown in the following code snippet:
@@sshkey{"$::fqdn": host_aliases => ["$::hostname","$::ipaddress"], key => $::sshdsakey, type => 'dsa', tag => "$::environment", }
You could then modify jumpbox
to only collect resources for production, for example, as follows:
Sshkey <<| tag == 'production' |>>
Two important things to remember when working with exported resources: first, every resource must have a unique name across your installation. Using the fqdn
domain name within the title is usually enough to keep your definitions unique. Second, any resource can be made virtual. Even defined types that you created may be exported. Exported resources can be used to achieve some fairly complex configurations that automatically adjust when machines change.
Note
One word of caution when working with an extremely large number of nodes (more than 5,000) is that exported resources can take a long time to collect and apply, particularly if each exported resource creates a file.