Advanced Puppet Pattern

Version 16 (James Turnbull, 01/03/2012 09:51 am)

1 8 James Turnbull
# A More Advanced Puppet Pattern
2 1
3 9 James Turnbull
When we left off in the [[Simplest Puppet Install Pattern]], we had
4 1
two files, our site manifest and a class configuring the sudo
5 1
tool.
6 1
7 1
# Our initial site manifest
8 1
9 1
The site manifest, /etc/puppet/manifests/site.pp, contained:
10 1
11 1
    # /etc/puppet/manifests/site.pp
12 1
    
13 1
    node default {
14 1
        include sudo
15 1
    }
16 1
17 14 Nan Liu
In this case the default node only contains a single class: sudo.
18 1
19 1
# Our first class
20 1
21 1
The sudo class contained:
22 1
23 14 Nan Liu
    # /etc/puppet/modules/sudo/manifests/sudo.pp
24 1
    
25 1
    class sudo {
26 1
        file { "/etc/sudoers":
27 1
            owner => "root",
28 1
            group => "root",
29 1
            mode  => 440,
30 1
        }
31 1
    }
32 1
33 1
This simple class performs only one function: managing the
34 1
/etc/sudoers file.
35 1
36 1
This is a good start but Puppet is capable of a whole lot more so
37 1
let's expand on this initial example.
38 1
39 1
# Revision Control
40 1
41 1
Before we get too far along though, you'll notice we've got a
42 1
couple of configuration, .pp, files. As you configure more and more
43 1
resources you'll find yourself adding to this collection of files.
44 1
This collection of files also needs to be managed and we strongly
45 1
recommend you implement a
46 1
[revision control system](http://en.wikipedia.org/wiki/Revision_control),
47 1
such as Subversion or Git. You should place all your manifests and
48 1
potentially other aspects of your Puppet configuration under
49 1
revision control and preferably host your repository on another
50 1
system. The repository should be regularly backed up. This will
51 1
allow you to make changes to your manifests and configuration and
52 1
know you can safely roll them back or recreate an earlier state
53 1
without needing to re-write or edit a large number of files.
54 1
55 1
# Expanding The Sudo Module
56 1
57 16 James Turnbull
We've already got the core of our new sudo module from the [[Simplest Puppet Install Pattern]] so let's expand on the
58 1
functions it performs for us. First, we're going to have it handle
59 1
the installation of the sudo package and then we're going to use
60 1
Puppet's built-in file server to distribute a /etc/sudoers file for
61 1
us. This file will contain all a central sudo configuration that
62 1
all our nodes will use. Let's look at our updated sudo class now
63 1
re-invented as a module.
64 1
65 1
    # /etc/puppet/modules/sudo/manifests/init.pp
66 1
    
67 1
    class sudo {
68 1
    
69 1
        package { sudo: ensure => latest }
70 1
    
71 1
        file { "/etc/sudoers":
72 1
            owner   => root,
73 1
            group   => root,
74 1
            mode    => 440,
75 12 Igor Belayev
            source  => "puppet:///modules/sudo/sudoers",
76 1
            require => Package["sudo"],
77 1
        }
78 1
    }
79 1
80 1
First, we've added a new resource type, package, and told it to
81 1
install the sudo package and always ensure the package installed is
82 1
the latest version.
83 1
84 1
Next, we've updated our original file type resource to include a
85 1
few more attributes. Instead of now just managing a local file
86 1
we've added the source attribute that tells Puppet to look for our
87 1
/etc/sudoers file on Puppet's built-in file server. To make this
88 6 James Turnbull
work we need to refer back to our [[Module Organisation|module]] and add a
89 1
new location to hold this file and potentially other files we might
90 1
want to distribute with this module. First we make a directory to
91 1
hold the file:
92 1
93 1
    # mkdir /etc/puppet/modules/sudo/files
94 1
95 1
Then we copy in our new sudoers file:
96 1
97 1
    # cp /etc/sudoers /etc/puppet/modules/sudo/files/sudoers
98 1
99 1
We've just copied in an arbitrary sudoers file but you could create
100 1
your own and modify it to suit your environment. Now, when we look
101 1
at the source attribute, we can see it is constructed like this
102 1
puppet:///sudo/sudoers. The puppet tells Puppet that we're using
103 1
the internal file server. This works much like a normal protocol
104 1
prefix, like http:// or ftp:// (although Puppet only supports file
105 1
serving from its internal file server so far, in later releases
106 1
support for other sources will be supported). But notice we've got
107 1
an extra /. This isn't a mistake. Normally, the source attribute
108 1
would look like puppet://server\_name/module/file. Instead of
109 1
specifying the server name explicitly using the / tells Puppet to
110 1
look for the file on the Puppet master currently managing the node.
111 1
This makes our configuration a bit more portable. We've then
112 1
specified the module we want Puppet to look into the find the file,
113 1
sudo, and the name of the file to be sourced. Puppet knows from
114 1
this attribute that the sudoers file contained in the
115 1
/etc/puppet/modules/sudo/files/ directory is the file it needs to
116 1
source and send to the client.
117 1
118 1
Lastly, we've added a meta-parameter called require which allows us
119 1
to build a dependency. It says to Puppet that before it should do
120 1
anything with the /etc/sudoers file then it should ensure the
121 1
resource, Package["sudo"], has been processed. In this case this
122 1
means that the sudo package will always be installed before the
123 1
/etc/sudoers file is sourced and managed.
124 1
125 1
# Importing Modules
126 1
127 1
Modules need to be imported into Puppet to make use of them.
128 1
However, generally everything under the modulepath, in our case
129 1
/etc/puppet/modules/, is automatically imported into Puppet and is
130 1
available to be used. There are cases where you will need to
131 1
explicitly import modules (such as pretty much every module from
132 1
David Schmitt's [[Complete Configuration]] set). Since it never
133 1
hurts to import them explicitly anyway, let's go ahead and make a
134 1
file for that purpose:
135 1
136 1
    # /etc/puppet/manifests/modules.pp
137 1
    
138 1
    import "sudo"
139 1
140 1
# Node Definitions
141 1
142 1
Next, let's create some nodes that we'll apply our new module too.
143 1
We'll want to put node definitions into their own file, nodes.pp,
144 1
like so:
145 1
146 1
    # /etc/puppet/manifests/nodes.pp
147 1
    
148 1
    node basenode {
149 1
      include sudo
150 1
    }
151 1
    
152 1
    node 'web.example.com' inherits basenode {
153 1
    }
154 1
155 1
Here in our new nodes.pp file we've created two nodes: basenode and
156 1
web.example.com. The basenode we can use to store configuration we
157 1
intend to apply to all nodes (you don't have to do this - this is
158 1
just one style). We also created our first client node,
159 1
web.example.com, which inherits our first node, basenode, and hence
160 1
includes the sudo module.
161 1
162 1
In addition to individually specifying nodes in your manifests you
163 7 James Turnbull
can also make use of [[External Nodes]] or [[LDAP Nodes]] nodes to
164 1
store your node configurations.
165 1
166 1
# Updating site.pp
167 1
168 1
All this leads to some changes to the site.pp file.
169 1
170 1
    # /etc/puppet/manifests/site.pp
171 1
    
172 1
    import "nodes"
173 1
    
174 1
    # The filebucket option allows for file backups to the server
175 1
    filebucket { main: server => 'my.server.name' }
176 1
    
177 1
    # Set global defaults - including backing up all files to the main filebucket and adds a global path
178 1
    File { backup => main }
179 1
    Exec { path => "/usr/bin:/usr/sbin/:/bin:/sbin" }
180 1
181 11 Jeff Blaine
# Resulting Tree of /etc/puppet Files
182 10 Jeff Blaine
183 10 Jeff Blaine
                 |-modules.pp
184 10 Jeff Blaine
     |-manifests-|-nodes.pp
185 10 Jeff Blaine
     |           |-site.pp
186 10 Jeff Blaine
     |
187 10 Jeff Blaine
     |-modules---|-sudo-----------------|-files-----|-sudoers
188 10 Jeff Blaine
                                        |
189 10 Jeff Blaine
                                        |-manifests-|-init.pp
190 10 Jeff Blaine
             
191 10 Jeff Blaine
192 1
# What's Next?
193 1
194 1
At this point you should have a decent grasp on the basics. You'll
195 15 Todd Wells
want to read the [[Puppet Best Practice2]], [[Style Guide]], and
196 7 James Turnbull
[[Language Tutorial]], probably in that order.
197 1
198 1
To learn from other people's work, or simply incorporate it in your
199 1
own, you can look at [[Recipes]] and [[Puppet Modules]] .
200 1
201 1
It is also important to remember that the default Puppet server
202 1
uses an internal webrick web server. The webrick web server does
203 1
not scale very well and is not recommended for production use
204 1
beyond 10 to 20 nodes. It is recommend that you move your Puppet
205 1
server to Mongrel or Passenger. You can find instructions at
206 1
[[Using Mongrel]] and [[Using Passenger]] respectively.
207 1
208 1
For reference information, see [[Reference Index]] .