7.1.2. Resource Collections
There are two ways you can combine multiple resources: Classes and definitions. Classes are only interpreted once per node. Definitions on the other hand can be used as custom types and are meant to be interpreted more then once, each time with different parameters.
Classes are introduced by using the class keyword, and support a simple form of inheritence. Subclasses are allowed to override resources defined in parent classes.
class unix {
file { [
"/etc/passwd",
"/etc/group"
]:
owner => root,
group => root,
mode => 644
}
}
class freebsd inherits unix {
File["/etc/passwd"] {
group => "wheel"
}
File["/etc/group"] {
group => "wheel"
}
}
You can use the undef keyword when overriding a resource to make the child class act as if the value had never been set in the parent:
class freebsd inherits unix {
File["/etc/passwd"] {
group => undef
}
}
In this example, nodes which include the unix class will have the password file forced to group root, while nodes including freebsd would have the password file group ownership left unmodified.
It is also possible to add additional values to resource parameters using the +> operator:
class apache {
service { "apache":
require => Package["httpd"]
}
}
class apache-ssl inherits apache {
# host certificate is required for SSL to function
Service["apache"] {
require +> File["apache.pem"]
}
}
The above effectively makes the require parameter for the Service["apache"] resource in the apache-ssl class equal to [ Package["httpd"], File["apache.pem"] ].
You can add multiple values by separating each value with commas:
class apache {
service { "apache":
require => Package["httpd"]
}
}
class apache-ssl inherits apache {
Service["apache"] {
require +> [
File["apache.pem"],
File["/etc/httpd/conf/httpd.conf"]
]
}
}
The above would make the require parameter in the apache-ssl class equal to [ Package["httpd"], File["apache.pem"], File["/etc/httpd/conf/httpd.conf"] ].
Like resources, you can also require a class, like so:
class apache {
service { "apache":
require => Class["squid"]
}
}
In this case, the Class["squid"] will need to be applied successfully before the Service["apache"] resource is applied on the puppet.
Classes such as the apache class in one of the forementioned examples, sub-classed by the apache-ssl class, can also be defined within another class:
class apache {
service { "apache":
require => Package["httpd"]
}
class ssl inherits apache {
Service["apache"] {
require +> [
File["apache.pem"],
File["/etc/httpd/conf/httpd.conf"]
]
}
}
}
In this case, using the ssl subclass of apache would become include apache::ssl.
The main difference (operational wise) between the two styles is that if you make a module out of the first above mentioned classes, both classes would have to be in their own file, so as to facilitate automatic loading by puppet. If you do not do this, puppet cannot find the class(es) that have a different name from the name of the module. On its own there is nothing wrong with having each class in its own file, however with large modules this tends to generate a lot of files, something one may wish to avoid.
Definitions are very similar to classes, but are introduced with the define keyword, and do not allow inheritance. Definitions also take parameters, which classes do not.
class yum {
define repository($enable = true) {
file { "/etc/yum.repos.d/$name.repo":
mode => 644,
owner => "root",
group => "root",
backup => false,
links => follow,
source => $enable ? {
true => [
"puppet:///yum/$os/$osver/repos/$name.repo"
],
default => [
"puppet:///yum/$os/$osver/repos/$name.repo.disabled"
]
}
}
}
}
This definition can be used as follows:
node 'node1.example.com' {
yum::repository { "custom":
enable => true
}
}
Now, node1.example.com gets a file /etc/yum.repos.d/custom.repo from puppet:///yum/$os/$osver/repos/custom.repo.