diff --git a/documentation/documentation/language/tutorial.page b/documentation/documentation/language/tutorial.page index ca3529e1f..461c92e70 100644 --- a/documentation/documentation/language/tutorial.page +++ b/documentation/documentation/language/tutorial.page @@ -1,176 +1,190 @@ --- inMenu: true title: Puppet Language Tutorial orderInfo: 30 --- # Elements and Organization The entire purpose of the Puppet language is to result in Puppet elements that directly model elements on each client being managed. Because different clients have different lists of elements, and some clients vary in the configuration of specific elements, Puppet's language supports various abstraction, selection, and overriding capabilities. # Naming For simple elements, we just specify the element type, name, and parameters: file { "/etc/passwd": owner => root, group => root, mode => 644 } Any machine on which this snippet is executed will use it to verify that the ``passwd`` file is configured as specified. The Puppet language treats the field before the colon as the name of the object, so in this case the name is ``/etc/passwd``, which works fine for this file since both the path and the details are essentially always the same on all systems. For files that vary across systems, it makes sense to create a *symbolic name* for your element: file { sshdconfig: path => $operatingsystem ? { solaris => "/usr/local/etc/ssh/sshd_config", default => "/etc/ssh/sshd_config" }, owner => root, group => root, mode => 644 } Here we create a symbolic name instead of using the path as the name, and now we can refer to that element by name elsewhere in the manifest: service { sshd: subscribe => File[sshdconfig] } This will cause the ``sshd`` service to get restarted when the ``sshdconfig`` file changes. It's important to note here that the language doesn't actually know anything about the objects it is managing; it knows the name and the type, and it has a list of parameters, but those parameters mean nothing in the language. If you provide a symbolic name to a given element, you should always use that single name, because otherwise the language will assume you are managing separate elements, which might result in an error in the library: file { sshdconfig: path => "/usr/local/etc/ssh/sshd_config", owner => root } file { "/usr/local/etc/ssh/sshd_config": owner => sshd } The Puppet parser does not know that these element specifications will attempt to manage the same element, because they have different names. This will result in an error on the client when the second element tries to instantiate and it is found to conflict with the first element. # Assignment Puppet has a declarative language, which means that its scoping and assignment rules are somewhat different than a normal imperative language. The primary difference is that you cannot change the value of a variable within a single scope, because that would rely on file order to determine the value of the variable. This will result in an error: $user = root file { "/etc/passwd": owner => $user } $user = bin file { "/bin": owner => $user, recurse => true } You will almost always find that you can avoid resetting variable values using the builtin [conditionals](structures.html#conditionals): $group = $operatingsystem ? { solaris => sysadmin, default => wheel } This is only one assignment, so no errors. +## Variable Interpolation + +Variables will get interpolated within double-quoted strings by default. You +can disable the interpolation by escaping the dollar sign: + + $str = "A string with a \$dollar sign in it" + +During interpolation, you can also surround your variable with curly braces if +necessary: + + $a = "something" + $b = "else" + $c = "${a}_${b}" + # Fact Variables (facts) In addition to variables that are manually assigned (as above), `puppet` also uses the [facter](/projects/facter/index.html) utility to glean information about the system. The facts gleaned by `facter` are made available as variables for use in `puppet`. You can get a full listing of variables that should be set by `puppet` from `facter` facts by running the `facter` command with no arguments, for instance: $ facter rubysitedir => /usr/lib/ruby/site_ruby/1.8 operatingsystemrelease => 8.8.0 hardwaremodel => Power Macintosh ipaddress => 10.10.10.52 kernelrelease => 8.8.0 facterversion => 1.3.3 operatingsystem => Darwin macaddress => 00:0d:de:ad:be:ef # Overriding Puppet provides a separate scope for every class and component, and scope trees are created as a manifest is parsed. Take the following configuration: class base { file { "/etc/issue": source => "puppet://server/module/common/issue" } } class sub inherits base { File["/etc/issue"] { source => "puppet://server/module/mysite/issue" } } This creates two distinct scopes, one for each class. The ``sub`` class overrides the specification of ``/etc/issue``, because it's in a lower scope, and when this manifest is applied, the latter location is used as the source for the file. This allows you to subclass a class and slightly change its behaviour. # Defaults Puppet elements are normally specified using a lower-case element type. You can specify default values for a given type using the capitalized form of the element type, though: Exec { path => "/usr/bin:/bin:/usr/sbin:/sbin" } import "classes/*.pp" node mynode { include $operatingsystem } The first statement in this snippet provides a default value for 'exec' elements, which require either fully qualified paths or a path in which to look for the executable. This way you can specify a single default path for your entire configuration, and then override that value as necessary. This can be used for any element type. For instance, CentOS defaults to using ``rpm`` for its package type, but you can easily change that to ``yum``: case $operatingsystem { centos: { Package { type => yum } } } ... *$Id$*