summaryrefslogtreecommitdiffstats
path: root/documentation/introduction.page
blob: 2d1cd680c7669c9c8ddbe532f4f5509999ba4d09 (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
---
inMenu: true
---
# Introduction

Puppet is a system configuration tool.  It has a library for managing the
system, a language for specifying the configuration you want, and a set of
clients and servers for communicating the configuration and other information.

The library is entirely responsible for all action, and the language is
entirely responsible for expressing configuration choices.  Everything is
developed so that the language operations can take place centrally on a single
server (or bank of servers), and all library operations will take place on each
individual client.  Thus, there is a clear demarcation between language
operations and library operations, as this document will mention.

# Setup

The vast majority of Puppet architectures will look like a star, with a
central server running `puppetmasterd`, and each client node running
`puppetd`, contacting that central server.  Your central manifest, which
contains the configuration for all of your nodes, needs to be on the central
server, most likely at `/etc/puppet/manifests/site.pp`.

Start the `puppetmasterd` daemon, and then tell your clients to contact that
server by specifying `-s <servername>` as arguments to `puppetd`, replacing
"<servername>" with the name of the server.  Alternatively, `puppetd` defaults
to looking for a server named "puppet", so you can just create a CNAME for
your server, so that it answers to "puppet".

It is a good idea to run both the server and client in verbose mode, enabled
with the `-v` flag, until you are sure everything is working.  As each new
client connects, you will need to run `puppetca --list` to list the
certificates waiting to be signed, and then `puppetca --sign <name>`,
replacing "<name>" with the name of the client whose certificate you want to
sign.  You can turn on autosigning by creating `/etc/puppet/autosign.conf` and
put the hosts, domains, or IP addresses or ranges that you want to sign in
there.

# Language

The language is declarative, and is modeled somewhat after cfengine's concept
of actions, action instances, and instance parameters.  Here is how a file
element would look in puppet:

    file { "/etc/passwd":
        owner => root,
        group => root,
        mode => 644
    }

Each instance of a low-level element like ``file`` must have a name parameter
defined, because that is how you uniquely refer to the element you are
managing.  Any string that doesn't match ``\w+`` or ``\d+`` needs to be quoted
(e.g., file names).

There are two ways for types to be available in the language:  They'll either
be ``primitive types`` included in the Puppet framework itself, or they'll be
``defined types`` resulting from definitions or server classes.

## Definitions

Because experience with cfengine showed that objects of different types are
often related, puppet focuses on making creation of associations between
objects of any type easier than making many objects of the same type.  The
fundamental unit of association is a 'definition':

    # currently, the variables don't have '$' attached in the definition prototype
    # this might change
    define sudo(source,group) {
        package { sudo:
            version => "1.6.7"
        }
        file { "/etc/sudoers":
            source => $source, # parameterization; copy the file from where?
            mode => 440 # the 'file' type converts this appropriately to
                        # octal
        }
        file { "/usr/sbin/sudo":
            owner => root,
            group => $group
        }
    }

A definition has its own scope, so variables defined within it are only
available within the definition itself.

This definition can now be treated as a type:

    sudo {
        group => root,
        source => "http://fileserver/files/sudoers?v=production"
    }

One significant difference between definitions and types is that types
generally have many associated parameters, most of which are optional, while a
given definition will (at this point) always require all parameters.  You can
manage as little or as much of a file as you want, for instance, but once you
wrap it in a definition you have to pass every specified parameter to instances
of the definition.

It is appropriate to think of definitions as declarative functions; referring
to the name of a definition results in the associated declarative code being
executed with the provided parameters.

I will likely soon add the ability to provide defaults to definition
parameters; any other feature requests are welcome.

## Classes

In addition to definitions, the language supports server classes.  Classes are
different from definitions in two fundamental ways:  They do not (currently)
support parameterization, and sub classes can override base classes.

Classes can be called using the same syntax as definitions, although always
without arguments and usually without names, but they are generally called
with the ``include`` keyword, which is more flexible in that it supports
variable interpolation and conditional expressions:

    class base {
        include sudo
    }

    class server inherits base {
        include ssh
    }

    case $hostname {
        myhost: { include server }
        default: { include base }
    }

    include $operatingsystem


## Variables

Because it is assumed that strings will be used far more than variables, simple
strings don't have be quoted or otherwise marked, but variables must have the
``$`` attached:

    $group = "root"

    file { "/etc/sudoers":
        group => $group
    }

Strings and booleans (``true`` and ``false``) are the only data types; even
numbers are converted to strings.  Arrays are supported, although their
behaviour has not been characterized for all cases.  One particular use of
arrays is for implicit iteration:

    $files = ["/etc/passwd","/etc/group","/etc/fstab"]

    file { $files:
        owner => root,
        group => root
    }

This implicitly iterates across the file list and performs all of the
appropriate checks.

Currently, ``puppet`` collects as much information as it can (using the
``Facter`` library) and sets all of it as top-level variables.  So, you can
expect variables like ``$operatingsystem`` and ``$ipaddress``.

Also, because ``puppet`` is a declarative language, reassigning a variable
within the same scope is currently an error.  The language is written such that
this could be disabled (please let me know if you need this feature), but it is
currently always enabled.  You can override defaults in a lower scope:

    $var = default

    define test {
        $var = override
        ...
    }

It is expected that parameter passing to definitions will be the primary
mechanism for variable assignment, so it seems unlikely that this limitation
will cause much trouble.

## Importing

Files can be imported using the ``import`` command:

    import "filename"

There is currently no search path or anything; files are looked for in the same
directory as the file doing the importing.  Each file should have its own
lexical scope, but I haven't yet figured out how to do that.

## Control Structures

There are currently two basic control structures, one meant to return a value
and the other just a normal 'if/elsif/else' structure.

### Selectors

One of the primary goals of Puppet is to simplify building a single
configuration that works across multiple machines and machine classes. One
mechanism for this is currently called a 'selector'; it is similar to the
trinary operator ``:?``:

    $value = $variable ? {
        value1 => setvalue1,
        value2 => setvalue2,
        default => other
    }

This sets the variable ``$value`` depending on the value of ``$variable``.  If
it is ``value1``, then ``$value`` gets set to ``setvalue1``, else the value
gets set to ``other``.

The brackets can be in either part of the expression, or not at all:

    $value = $variable ? "value1" => "setvalue1"

A selector that doesn't match a value is a compile error.

These structures are useful for simplistic abstraction across platforms:

    file { "/etc/sudoers":
        owner => root,
        group => $operatingsystem ? {
            SunOS => root,
            Linux => root,
            FreeBSD => wheel
        }
    }

Selectors can specify default values using the ``default`` keyword.

### Case Statements

Puppet currently supports a normal Case structure similar to so many other
languages:

    case $operatingsystem {
        solaris: { include sunos }
        debian: { include linux }
        default: { include $operatingsystem }
    }

As you can see, case statements also support defaults.

The difference between the case stateements and the selectors is that the
selectors just return values while the case statements execute arbitrary
Puppet code.

# Library

This section discusses some aspects of the internals of the Puppet library.
This information can be useful but is not critical for use and understanding
of Puppet.

The library is composed of two fundamental types of objects: Types and states
(yes, the terminology is atrocious).  States are things that can be configured
to change one aspect of an object (e.g., a file's owner), types are essentially
named collections of states.  So, there is a File type, and it is a collection
of all of the states available to modify files.

In addition to states, which necessarily modify 'the bits on disk', as it were,
types can also have non-state parameters which modify how that type instance
behaves:

    file { "/bin":
        owner => bin,
        recurse => true
    }

The ``recurse`` parameter to ``file`` does not modify the system itself, it
modifies how the ``file`` type manages ``/bin``.

Not all types as expressed in the language are types defined in the library;
some language types are actually definitions or server classes.  Types that
are defined in the language itself are termed ``primitive types`` or just
``primitives``, and types that generate other types are termed ``metatypes``.

At this point, all types have a unique name (within the current scope, but it
probably should actually be global).  This name is set using a class instance
variable: :

    # in the library
    Puppet::Type.newtype(:mytype)
        ...
    end

    # in the language
    mytype { "yay": ... }

The states similarly have unique names, although this uniqueness is only
per-type.  When a type is defined, all states and parameters are added using
class methods.  Here is the File type declaration:

    newstate(:ensure) do ... end
    newstate(:owner) do ... end
    newstate(:group) do ... end
    ...
    newparam(:path) do ... end

Lastly, each type must either provide a state or parameter of ':name', or it
must mark a parameter as the namevar so that the system knows what is
considered the name:

    newparam(:path) do 
        isnamevar
    end

With this declaration, ``file { "/tmp/file": }`` is basically equivalent to ``file { path => "/tmp/file" }``.

See [Creating a Puppet Type](creating-a-puppet-type.html) for more
information.