Authors: Jeffrey McCune James Turnbull
We mentioned earlier that functions run on the Puppet master. This means we only have access to the resources and data available on the master, but this does include some quite useful information, most importantly fact data. You can look up and use the value of facts in your functions using thelookupvar
function, like so:
lookupvar(‘fqdn')
Replacefqdn
with the name of the fact whose value you wish to look up.
You can see how easy it is to create some very powerful functions in only a few lines of code. We recommend having a look at the existing functions (most of which are very succinct) as a way to get started on your first functions. Some of the common functions include tools to manipulate paths, regular expressions and substitutions, and functions to retrieve data from external sources. There are numerous examples (many on Github or searchable via Google) of functions that you can copy or adapt for your environment.
After you've created your function you should test that it works correctly. There are a couple of ways you can do this. Some basic testing of the function can be performed by executing the function file with Ruby, like so:
$ ruby –rpuppet sha512.rb
This loads the Puppet library (Puppet must be installed on the host) and then runs the file containing the function we created in
Listing 10-12
. This will allow us to determine whether the file parses without error. It does not tell us if the function performed correctly.
Tip
You can raise an error in your function usingraise Puppet::ParseError, "raise this error"
. Replace “raise this error” with the error text you'd like to raise.
We can also use the Ruby IRB (Interactive Ruby Shell) to confirm our function is properly defined, like so:
$ irb
irb> require 'puppet'
=> true
irb> require '/tmp/sha512.rb'
=> true
irb> Puppet::Parser::Functions.function(:sha512)
=> "function_sha512"
Here we've launchedirb
and then required Puppet and our new function. We then confirm that Puppet can see the new function and that it parses as a correct function.
The best way to test a function is to use it in a manifest, and the easiest way to do that is to add your functions to Puppet'slibdir
and run a stand-alone manifest. Assuming Puppet is installed, first find yourlibdir
:
$ sudo puppet –configprint | grep ‘libdir'
/var/lib/puppet/lib
Then create a directory to hold our functions:
$ sudo mkdir -p /var/lib/puppet/lib/puppet/parser/functions
Then copy in our function:
$ sudo cp sha512.rb /var/lib/puppet/lib/puppet/parser/functions
Then a manifest to execute our new function:
$ cat /tmp/sha.pp
$hash = sha512(“test”)
notify { $hash: }
And finally run the function:
$ puppet /tmp/sha.pp
notice:
ee26b0dd4af7e749aa1a8ee3c10ae9923f618980772e473f8819a5d4940e0db27ac185f8a0e1d5f84f88bc887fd67b143732c304cc5fa9ad8e6f57f50028a8ff
notice:
/Stage[main]//Notify[ee26b0dd4af7e749aa1a8ee3c10ae9923f618980772e473f8819a5d4940e0db27ac185f8a0e1d5f84f88bc887fd67b143732c304cc5fa9ad8e6f57f50028a8ff]/message: defined 'message' as
'ee26b0dd4af7e749aa1a8ee3c10ae9923f618980772e473f8819a5d4940e0db27ac185f8a0e1d5f84f88bc887fd67b143732c304cc5fa9ad8e6f57f50028a8ff'
We can see that ournotify
resource returned a 512-bit hash generated by oursha512
function.
Note
You can call a function from another function by prefixing the function to be called withfunction_
, for examplefunction_notice
.
In this chapter, you learned how to extend Puppet and Facter with your own custom types, providers, functions and facts. We demonstrated how to:
There are also a lot of examples of extensions and additions to Puppet that are available for you to add to your Puppet installation, or which can serve as examples of how to develop particular extensions. A good place to start looking for these is on GitHub (
http://www.github.com
).
http://puppetlabs.com/trac/puppet/wiki/AddingFacts
In
Chapter 10
, you learned about the puppet-module and cucumber-puppet tools. Both of these tools help automate the process of developing and testing Puppet modules. Similarly, Marionette Collective (MCollective) is an orchestration framework closely related to Puppet. Puppet excels at managing the state of your systems; however, the default 30-minute run interval of the Puppet agent makes it unsuitable for real-time command and control. MCollective addresses the need to execute commands in real-time on a large number of systems in a novel and unique manner. With MCollective, nodes are easily divided into collections based on information about the node itself rather than hostnames. The use of metadata means you don't need to maintain long lists of hostnames or IP addresses. All systems in the collection can report information about themselves in real-time on demand. Armed with this information, the overall population of machines can be divided into collectives. Procedures are carried out remotely against a collective rather than against a single machine.
MCollective was created to provide an API for the orchestration tasks that systems engineers and developers frequently need to perform. Command and control tools are numerous and effectively provide the same functionality of the Unix shell. Though powerful, the shell interface is not an ideal application-programming interface. In addition, commands dispatched to systems in this manner are difficult to manage using the same tools and processes that you manage code with. With a robust API, orchestration actions may be implemented as small agent plugins and treated like other pieces of code in a software development lifecycle. MCollective agents are testable, version-controlled, and consistently repeatable.
There are a number of problems and use cases that MCollective is particularly well-suited to address. Through the use of real-time messaging and metadata addressing, a number of tasks previously carried out with SSH or other deployment tools are more efficiently solved with MCollective. In particular, the following actions and questions are addressed extremely well with MCollective:
In addition to the actions MCollective already handles, it is quite straightforward to write custom agents in Ruby to carry out your own actions on all of your systems. The MCollective RPC framework alleviates much of the effort you would otherwise have to spend writing code to connect to your machines, issue commands to them, and handle logging and exceptions. If you need to take action on all
of your systems, MCollective agents distributed through Puppet are an excellent way to quickly tackle the problem.
MCollective takes advantage of modern technologies to handle communication between the nodes in a collective. In this chapter, you'll learn how to install the RabbitMQ message bus and connect MCollective servers to a message queue. Once that's installed, you'll also learn how integrate MCollective with Facter to provide a large amount of metadata that's useful to divide the population into collectives and then command them. In addition, you'll learn how Puppet works well with MCollective to orchestrate and reconfigure your nodes on demand and in a controlled manner. Plugins for MCollective provide these integrations with Puppet, specifically the Puppet Agent plugin and Puppet Commander plugin. Let's get started with the installation of the RabbitMQ messaging bus.
MCollective makes use of publish and subscription messaging techniques. These publications and subscriptions are often implemented using asynchronous messaging software such as ActiveMQ and RabbitMQ. The broad category of messaging software is often referred to as messaging middleware. MCollective is developed and tested with the Apache ActiveMQ middleware, however the requirement of Java and XML configuration files have driven increased attention and interest in the RabbitMQ middleware service.
MCollective sends and receives messages using the Stomp protocol. Any messaging middleware implementing a robust Stomp listener should work with MCollective. However, ActiveMQ and RabbitMQ are the two most widely deployed and tested middleware services used with MCollective. It is important to keep in mind that only one messaging service on one system is required to get started with MCollective. A single RabbitMQ server will easily support hundreds of connected MCollective server processes. Advanced configurations with multiple security zones and tens of thousands of nodes may consider deploying multiple, federated messaging services to scale with demand. In a multi-datacenter configuration, ActiveMQ is an excellent choice. ActiveMQ and MCollective have been deployed together across multiple data centers and geographic continents in redundant and reliable configurations.
It is worth noting that MCollective and RabbitMQ are not bundled with the distribution of Enterprise Linux or Debian and Ubuntu systems as of the writing of this book. However, both RabbitMQ and MCollective will be included in the Natty Narwhal release of Ubuntu, scheduled to be version 11.04 of the operating system. If you are running a Natty or a more recent version of Ubuntu, the easiest installation route will be to simply install the packages from the distribution repositories using aptitude.
MCOLLECTIVE MESSAGING ARCHITECTURE
MCollective employs asynchronous messaging middleware services to broadcast messages and collect responses from nodes. An overview of this messaging architecture is available online at:http://docs.puppetlabs.com/mcollective/reference/basic/messageflow.html
If you have multiple security zones or data centers, you may be interested in running multiple middleware servers to federate and distribute messaging requests. Information on this configuration with ActiveMQ is available online at:http://docs.puppetlabs.com/mcollective/reference/integration/activemq_clusters.html
In addition, general information about publish/subscribe middleware is available online at:http://en.wikipedia.org/wiki/Publish/subscribe
RabbitMQ is a message queue service implementing the Advanced Message Queuing Protocol, or AMQP. RabbitMQ is built using the OTP (Open Telecom Platform) and implemented in the Erlang language and runtime environment. To get started with RabbitMQ, first see how the Example.com operator installs and configures the Erlang runtime on each platform, then install and configure RabbitMQ and plugins required for MCollective. The information in this chapter is specific to RabbitMQ for ease of configuration and installation on both Debian and Enterprise Linux systems. While ActiveMQ is equally suitable to the task, many people find the XML configuration file more complex than the direct command line interface of RabbitMQ.
Note
Puppet modules to deploy and manage RabbitMQ are available online athttp://forge.puppetlabs.com/
andhttp://github.com/puppetlabs/puppetlabs-rabbitmq
. This Puppet module will help you bring a RabbitMQ server online quickly and easily using Puppet.
Debian and Ubuntu systems provide the Erlang runtime as precompiled binary packages. The operator installs Erlang before RabbitMQ using theaptitude install
command as shown in
Listing 11-1
.
Listing 11-1.
Installing Erlang on Debian
$ sudo aptitude install erlang
Setting up openjdk-6-jre-lib (6b18-1.8.3-2+squeeze1) ...
Setting up odbcinst1debian2 (2.2.14p2-1) ...
Setting up unixodbc (2.2.14p2-1) ...
Setting up erlang-odbc (1:14.a-dfsg-3) ...
Setting up erlang (1:14.a-dfsg-3) ...
Setting up erlang-jinterface (1:14.a-dfsg-3) ...
Setting up erlang-ic-java (1:14.a-dfsg-3) ...
Setting up icedtea-6-jre-cacao (6b18-1.8.3-2+squeeze1) ...
Setting up default-jre-headless (1:1.6-40) ...
Setting up ca-certificates-java (20100412) ...
creating /etc/ssl/certs/java/cacerts...
done.
On Debian-based systems, installation of the Erlang runtime is straightforward. The operator simply uses aptitude to install theerlang
package. Next, in
Listing 11-2
, the operator installs the RabbitMQ server package. This package is not available in the main Debian repositories, so the best way to install RabbitMQ is by adding the RabbitMQ repositories to the apt packaging system.
Listing 11-2.
Adding the RabbitMQ apt repository to Debian
$ sudo puppet resource file /etc/apt/sources.list.d/rabbitmq.list \
content="deb http://www.rabbitmq.com/debian/ testing main"
$ cd /tmp
$ wget http://www.rabbitmq.com/rabbitmq-signing-key-public.asc
$ sudo apt-key add rabbitmq-signing-key-public.asc
OK
$ sudo apt-get update
Get:1 http://www.rabbitmq.com testing Release.gpg [197 B]
Ign http://www.rabbitmq.com/debian/ testing/main Translation-en
Ign http://www.rabbitmq.com/debian/ testing/main Translation-en_US
Get:2 http://www.rabbitmq.com testing Release [8,033 B]
Hit http://debian.osuosl.org squeeze Release.gpg
Ign http://www.rabbitmq.com testing/main i386 Packages
Ign http://debian.osuosl.org/debian/ squeeze/main Translation-en
Hit http://www.rabbitmq.com testing/main i386 Packages
Ign http://debian.osuosl.org/debian/ squeeze/main Translation-en_US
Hit http://security.debian.org squeeze/updates Release.gpg
Hit http://debian.osuosl.org squeeze-updates Release.gpg
Ign http://debian.osuosl.org/debian/ squeeze-updates/main Translation-en
Ign http://security.debian.org/ squeeze/updates/main Translation-en
Ign http://debian.osuosl.org/debian/ squeeze-updates/main Translation-en_US
Ign http://security.debian.org/ squeeze/updates/main Translation-en_US
Hit http://debian.osuosl.org squeeze Release
Hit http://debian.osuosl.org squeeze-updates Release
Hit http://security.debian.org squeeze/updates Release
Hit http://debian.osuosl.org squeeze/main Sources
Hit http://debian.osuosl.org squeeze/main i386 Packages
Hit http://security.debian.org squeeze/updates/main Sources
Hit http://debian.osuosl.org squeeze-updates/main Sources
Hit http://security.debian.org squeeze/updates/main i386 Packages
Hit http://debian.osuosl.org squeeze-updates/main i386 Packages
Fetched 198 B in 0s (238 B/s)
Reading package lists... Done
In order to enable the RabbitMQ repository, the operator uses thepuppet resource
command to set the contents of the rabbitmq apt source file. If the version of Debian you are running does not have an/etc/apt/sources.list.d
directory, you'll need to append the line listed in the content attribute to the/etc/apt.sources.list
file instead of creating a new file.
Next, the operator downloads the RabbitMQ public key to verify the package signatures and adds this key to the apt package management system. Finally, the apt-get update command should not return any errors about verifying the authenticity of the package repository. If you receive any such errors, please make sure the RabbitMQ public key has been added successfully.
With the apt repository configured and updated, the RabbitMQ server software may be installed, as shown in
Listing 11-3
using a straightforwardaptitude install
command.
Listing 11-3.
Installing RabbitMQ on Debian
$ sudo aptitude install rabbitmq-server
The following NEW packages will be installed:
rabbitmq-server
0 packages upgraded, 1 newly installed, 0 to remove and 3 not upgraded.
Need to get 0 B/949 kB of archives. After unpacking 1,749 kB will be used.
Selecting previously deselected package rabbitmq-server.
(Reading database ... 40745 files and directories currently installed.)
Unpacking rabbitmq-server (from .../rabbitmq-server_2.3.1-1_all.deb) ...
Processing triggers for man-db ...
Setting up rabbitmq-server (2.3.1-1) ...
Starting rabbitmq-server: SUCCESS
rabbitmq-server.