Resources
The fundamental building block in a Puppet configuration is called a resource, which is just an object that models some element on a computer. Each of these resources has a specific associated type, such as user or package, and each of these types has a fixed list of allowed parameters (there are also metaparameters, which all types accept).
All resources also have a name that identifies them uniquely.
Puppet provides a simple hash-like syntax for specifying resources; for instance, here is how you might specify that a file should exist:
file { "/etc/myfile":
content => "Some text",
mode => 644
}
Here we have the three key elements to any resource specification: The type (file), the name (/etc/file), and an attribute list (in this case, content and mode). Multiple attributes must be comma-separated, and trailing commas are acceptable.
Whitespace generally doesn't matter; your resource can be specified on one line, or split over several as above.
Multiple Resources
You can just specify multiple resources one after the other in your manifest:
package { sudo: ensure => installed }
file { "/etc/sudoers": mode => 440, owner => root }
If you have many resources of the same type, you can semicolon-separate them in one statement:
file {
"/etc/passwd": owner => root, mode => 644;
"/etc/shadow": owner => root, mode => 440;
}
Trailing semicolons are accepted, as you can see.
If you have multiple resources of the same type and with the same attribute list, you can use an array for the name:
package { [openssh, openssl]: ensure => installed }
Relationships
No resource lives in a vacuum -- resources usually work together to provide some needed functionality. Puppet provides some facilities for specifying that resources are related, and specifying these relationships provides some extra functionality.
There are two kinds of relationships in Puppet -- normal dependency, and reactive dependency -- and you can specify them from either end of the relationship. Because any resource can be related to any other resource, relationships are specified with metaparameters.
Normal dependency relationships are just used for ordering; as long as you do not create circular dependencies, Puppet guarantees that your resources will be configured in the order of their dependencies. For instance:
user { myuser: ensure => present }
file { "/tmp/file":
owner => myuser,
ensure => directory
require => User[myuser]
}
Notice how the dependency is specified -- this is called a `resource reference`, and is composed of the type and name of the related resource. Puppet operations on types are capitalized, and in this case you are essentially treating the type as a hash and looking an instance up by name.
Reactive dependencies provide the same ordering relationship as normal dependencies, and in addition the dependency attempts to react to any changes in required resources. Most resource types are not capable of reacting to anything (e.g., users do not need to be restarted, nor do files need to get refreshed), but this is an important functionality for resources like service.
Plain dependencies are specified using require and before, while reactive dependencies are specified using subscribe and notify.
It is important to always specify your relationships and not to depend on file order, because Puppet does a topological sort of all resources based on relationship, and resources are not guaranteed to stay in the same order in which they are specified.
Autorequire
The above example is actually redundant, because Puppet makes every attempt to automatically determine relationships. The file resource is smart enough to automatically list any associated users or groups as dependencies, for instance. In most cases, Puppet resources are smart enough to autorequire any directly related resources.
Syntax vs. Attributes
It is important to note that Puppet's interpreter only validates that attributes are valid for the associated type, it never interprets their values in any way. A resource specification that successfully compiles for a client may fail to pass validation on that client, for instance.