Using defined types
In the previous example, we saw how to reduce redundant code by grouping identical resources into arrays. However, this technique is limited to resources where all the parameters are the same. When you have a set of resources that have some parameters in common, you need to use a defined type to group them together.
How to do it…
The following steps will show you how to create a definition:
- Add the following code to your manifest:
define tmpfile() { file { "/tmp/${name}": content => "Hello, world\n", } } tmpfile { ['a', 'b', 'c']: }
- Run Puppet:
[root@hiera-test ~]# vim tmp.pp [root@hiera-test ~]# puppet apply tmp.pp Notice: Compiled catalog for hiera-test.example.com in environment production in 0.11 seconds Notice: /Stage[main]/Main/Tmpfile[a]/File[/tmp/a]/ensure: defined content as '{md5}a7966bf58e23583c9a5a4059383ff850' Notice: /Stage[main]/Main/Tmpfile[b]/File[/tmp/b]/ensure: defined content as '{md5}a7966bf58e23583c9a5a4059383ff850' Notice: /Stage[main]/Main/Tmpfile[c]/File[/tmp/c]/ensure: defined content as '{md5}a7966bf58e23583c9a5a4059383ff850' Notice: Finished catalog run in 0.09 seconds [root@hiera-test ~]# cat /tmp/{a,b,c} Hello, world Hello, world Hello, world
How it works…
You can think of a defined type (introduced with the define
keyword) as a cookie-cutter. It describes a pattern that Puppet can use to create lots of similar resources. Any time you declare a tmpfile
instance in your manifest, Puppet will insert all the resources contained in the tmpfile
definition.
In our example, the definition of tmpfile
contains a single file
resource whose content is Hello, world\n
and whose path is /tmp/${name}
. If you declared an instance of tmpfile
with the name foo
:
tmpfile { 'foo': }
Puppet will create a file with the path /tmp/foo
. In other words, ${name}
in the definition will be replaced by the name
of any actual instance that Puppet is asked to create. It's almost as though we created a new kind of resource: tmpfile
, which has one parameter—its name
.
Just like with regular resources, we don't have to pass just one title; as in the preceding example, we can provide an array of titles and Puppet will create as many resources as required.
Tip
A word on name, the namevar: Every resource you create must have a unique name, the namevar. This is different than the title, which is how puppet refers to the resource internally (although they are often the same).
There's more…
In the example, we created a definition where the only parameter that varies between instances is the name
parameter. But we can add whatever parameters we want, so long as we declare them in the definition in parentheses after the name
parameter, as follows:
define tmpfile($greeting) { file { "/tmp/${name}": content => $greeting, } }
Next, pass values to them when we declare an instance of the resource:
tmpfile{ 'foo': greeting => "Good Morning\n", }
You can declare multiple parameters as a comma-separated list:
define webapp($domain,$path,$platform) { ... } webapp { 'mywizzoapp': domain => 'mywizzoapp.com', path => '/var/www/apps/mywizzoapp', platform => 'Rails', }
You can also declare default values for any parameters that aren't supplied, thus making them optional:
define tmpfile($greeting,$mode='0644') { ... }
This is a powerful technique for abstracting out everything that's common to certain resources, and keeping it in one place so that you don't repeat yourself. In the preceding example, there might be many inpidual resources contained within webapp
: packages, config files, source code checkouts, virtual hosts, and so on. But all of them are the same for every instance of webapp
except the parameters we provide. These might be referenced in a template, for example, to set the domain for a virtual host.
See also
- The Passing parameters to classes recipe, in this chapter