You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
Most classes have to do slightly different things on different systems. You already know some ways to do that --- all of the modules you've written so far have switched their behaviors by looking up system facts. Let's say that they "investigate:" they expect some information to be in a specific place (in the case of facts, a top-scope variable), and go looking for it when they need it.
21
21
22
-
But this isn't always the best way to do it, and it starts to break down once you need to switch a module's behavior on information that doesn't map cleanly to system facts. Is this machine a database server? Is it supposed to be running your internal NTP server? These are almost more social distinctions than technical ones.
22
+
But this isn't always the best way to do it, and it starts to break down once you need to switch a module's behavior on information that doesn't map cleanly to system facts. Is this a database server? A local NTP server?
23
23
24
-
So you could still have your modules investigate; instead of looking at the standard set of system facts, you could just point them to an arbitrary variable and make sure it's filled if you plan on using that class.[^olderversions]
25
-
26
-
But it might be better to just tell the class what it needs to know when you declare it.
24
+
You could still have your modules investigate; instead of looking at the standard set of system facts, you could just point them to an arbitrary variable and make sure it's filled if you plan on using that class.[^olderversions] But it might be better to just tell the class what it needs to know when you declare it.
27
25
28
26
[^olderversions]: This was the only way to do things in older versions of Puppet, and later I'll go into more detail about how to do this sanely.
29
27
30
28
Passing Parameters
31
29
------------------
32
30
33
-
When defining a class, you can optionally give it a list of parameters.
31
+
When defining a class, you can give it a list of **parameters.**
32
+
33
+
{% highlight ruby %}
34
+
class mysql ($user, $port) { ... }
35
+
{% endhighlight %}
36
+
37
+
This is a doorway for passing information into the class. When you declare the class, those parameters appear as **resource attributes;** inside the definition, they appear as **local variables.**
notice: /Stage[main]/Paramclassexample/Notify[Value 2 is Something else.]/message: defined 'message' as 'Value 2 is Something else.'
50
+
notice: Value 1 is Something.
51
+
notice: /Stage[main]/Paramclassexample/Notify[Value 1 is Something.]/message: defined 'message' as 'Value 1 is Something.'
52
+
notice: Finished catalog run in 0.05 seconds
53
+
54
+
# puppet apply -e "class {'paramclassexample': value1 => 'Something',}"notice: Value 1 is Something.
55
+
notice: /Stage[main]/Paramclassexample/Notify[Value 1 is Something.]/message: defined 'message' as 'Value 1 is Something.'
56
+
notice: Value 2 is Default value.
57
+
notice: /Stage[main]/Paramclassexample/Notify[Value 2 is Default value.]/message: defined 'message' as 'Value 2 is Default value.'
58
+
notice: Finished catalog run in 0.05 seconds
59
+
60
+
(As shown above, you can give any parameter a default value, which makes it optional when you declare the class. Parameters without defaults are required.)
61
+
62
+
So what's the benefit of all this? In a word, it **[encapsulates][]** the class. You don't have to pick unique magic variable names to use as a dead drop, and it makes the behaviors that can vary much more legible at a glance.
63
+
64
+
But! This is probably going to be more clear with a more legit example.
So let's get back to our NTP module. The first thing we talked about wanting to vary was the set of servers, and we already did the heavy lifting back in the [templates](./templates.html) chapter, so that's the place to start:
34
72
35
73
{% highlight ruby %}
36
-
class mysql ($user, $port) {
74
+
class ntp ($servers = undef) {
37
75
...
76
+
{% endhighlight %}
77
+
78
+
And... that's all it takes, actually. This will work. If you declare the class with no attributes...
79
+
80
+
{% highlight ruby %}
81
+
class {'ntp':}
82
+
{% endhighlight %}
83
+
84
+
...it'll work the same way it used to. If you declare it with a `server` attribute containing an array of servers (with or without appended `iburst` and `dynamic` statements)...
The parameter list is a comma-separated list of variables and, optionally, their default values `($one = "a default value", $two, $three = "another default value")`. Parameters without defaults are required when you eventually declare the class, and parameters with defaults are optional. All of the parameters can be used as normal local variables throughout the class definition.
92
+
...it'll override the servers in the `ntp.conf` file. Nice. There _is_ a bit of trickery to notice: setting a variable or parameter to `undef` might seem odd, and we're only doing it because we want to be able to get the default servers without asking for them. (Remember, parameters can't be optional without an explicit default value.) Also, remember the business with the `$servers_real` variable? That was because the Puppet language won't let you re-assign a variable within a given scope. Since `$servers` is always going to be assigned before we can do anything in the class, we have to make a copy of it if we want to smartly handle default values like this.
42
93
43
-
Then, when you declare the class, declare each of the parameters as an attribute of the class resource:
94
+
What else could we make into a parameter? Well, let's say you have a mixed environment of physical and virtual machines, and some of them occasionally make the transition between VM and metal. Since NTP behaves weirdly under virtualization, you'd want it turned off on your virtual machines --- and you would have to manage it as a service resource to do that, because if you just didn't say anything about NTP (by not declaring the class, e.g.), it might actually still be running. So you could make an `ntp_disabled` class and declare that whenever you aren't declaring the `ntp` class... but it makes more sense to expose the service's attributes as class parameters. That way, when you move a formerly physical server into the cloud, you could just change its manifests to declare the class like this:
44
95
45
96
{% highlight ruby %}
46
-
class {'mysql':
47
-
user => 'mysql',
48
-
port => '3306',
97
+
class {'ntp':
98
+
ensure => stopped,
99
+
enable => false,
49
100
}
50
101
{% endhighlight %}
102
+
103
+
And you've probably already guessed how easy that is. Here's the complete class, with all of our modifications thus far: <!-- TODO: add puppetdoc to this. -->
Is there anything else we could do to this class? Well, yes: its behavior under anything but Debian, Ubuntu, CentOS, or RHEL is currently undefined, so it'd be nice to either fail gracefully or come up with some config templates we wouldn't mind being used under OS X or a BSD. And it might make sense to unify our two current templates; they're just based on the system defaults, and once you decide how NTP should be configured at your site, chances are it's going to look similar on any Linux. But as it stands, the module is pretty serviceable.
0 commit comments