Hi Gunnar,
> So taking that fact into account means one should refrain from using
> puppet for more complex administration work?
No not at all!! If this was the impression you gained from my post
then I really have to apologize. I think there is no configuration
management tool better placed than puppet today for managing complex
systems. And puppet is also maturing in other important areas (like
memory usage for instance). I wouldn't invest time into trying to
improve puppet if I wasn't fully committed to this tool. :-)
> Isn't there a possibility to somehow please both sides?
I for myself have established very rigid coding rules that work around
most of the issues I mentioned. As Luke already suspected I heavily
rely on definitions and use classes only in some very specific and
well defined situations.
Mainly I use *definitions* for any kind of configuration, also on node
level. By convention I use the node name as instance name for node-
level configuration. I thereby loose inheritance and instance
variables. The former is not important to me as I use only one single
Linux distribution on all of my nodes. IMO inheritance is only really
important when you work with different distributions at the same time.
And in most cases I can live without public class variables. I only
use them where I use classes and so far this revealed itself as being
very consistent anyway. I further disallow any usage of global
variables within definitions. This gives me full encapsulation.
NB: My system is a solution very specific to my needs and not a
general recommendation. Especially not if you use (or plan to use)
several Linux distributions.
I use *classes* only for one purpose: giving per-package namescope to
definitions and provide some way to document numbers as constants
(=scoped class variables)...
Distribution packages (not the puppet package type!) are my smallest
configuration unit. I have exactly one puppet module per Linux
distribution package, named after the package. This may again not be
appropriate if you use more than one distribution as package names
vary! In its init.pp this module contains exactly one class (named
after the package). The class contains exactly one definition always
named "state" that defines the per-node state of the package
(including dependencies, the package type instance and any service or
node-wide configuration coming with the package). The state-definition
takes those parameters that were global variables if I used classes as
recommended by the puppet documentation. To me encapsulation and
maintainability is more important than the (in my eyes) useless class/
definition distinction. That's why I deviate from puppet
recommendations here. Example apache2::state(...) .
Again scoped by the package class I have definitions of *package-
services* that define anything that is a "real" definition in the
sense of the puppet documentation and may be instantiated (=consumed)
by other package's state or service definitions. These are not the
services Luke speaks about but rather public interfaces to
configuration functionality offered by a specific Linux package.
Example: apache2::virtual-host(...)
I had (and still have) some troubles with encapsulating dependency
(require, before) and subscription (notify, subscribe) relationships.
But I found a workaround with global defaults that (by convention)
only appear within the types concerned and work in most cases. Some
few cross-definition dependencies still remain, but very few. I would
rather not like to post it here as it's too hacky for now and I'd
prefer it to mature a little bit first.
To group packages into "node aspects" (like "webserver", "desktop",
etc.) I use definitions again that use the node name as instance name.
This gives me the possibility to route variables from the global
context into my state- and package-service definitions without using
any global variable whatsoever.
Node definitions may not contain anything else than classes, "node
aspects" or global usage of package-services that cannot be attributed
to any specific "consuming" package (like the node's "zone" and
"interface" definition in my firewall configuration).
My node definitions typically look like this:
node "xyz" {
$node-name="xyz"
$node-ip="a.b.c.d"
$admin-user="xyz"
include sudo
sudo::state( "$node-name": admin-users => $admin-user, lecture =>
true, ... ) # this is a node-level package state definition
include ssh
ssh::state( "$node-name": allowed-users => $admin-user )
include shorewall
shorewall::state(...)
shorewall::interface( "$node-name": zone=>"net", interface=>"eth1" )
# this is a node-level package service
# similar use of package services will mainly occur within state
definitions or within package-service definitions that require other
packages' services
# package classes may provide public parameters like this $ssh::port
to be consumed by other packages (state or services) as well.
webserver { "$node-name": ip => $node-ip } # this is a node aspect
...
}
Now comes the definition of the node aspect:
define webserver($ip, $...) {
include apache2
apache2::state(ip => $ip, ...)
...
}
A packages' init.pp looks like this:
class apache2 {
# this is a scoped variable (or better scoped constant as I use
it!!) that
# will never be changed and may be used to self document numbers
# in other contexts like apache2::ssl-port rather than using them
hard-coded
ssl-port = 443
define state($ip, $...) {
package{...}
service{...}
file{... template() ...) etc...
...
}
define virtual-host($name, ...) {
}
}
Global defaults only appear in a global context (site.pp) where they
really describe something that is valid for the whole system (like
default file permissions or something like that).
I am quite happy with this solution now and it already revealed itself
as being quite flexible and a lot easier to maintain when I had to
refactor something.
I just didn't post my solution here as it is probably better placed in
a "Puppet Recipe" and above all it is not in line with Luke's
definition of class and definition usage and its respective
documentation. So I am afraid that I'd cause more confusion than help
others if posting this in another place.
If you follow the ongoing discussion you'll probably end up with a
more "official" recommendation that will be supported by the puppet
developers as well. (My current solution will definitely not be
"officially" supported.)
Florian
--~--~---------~--~----~------------~-------~--~----~
You received this message because you are subscribed to the Google Groups
"Puppet Developers" group.
To post to this group, send email to [email protected]
To unsubscribe from this group, send email to [EMAIL PROTECTED]
For more options, visit this group at
http://groups.google.com/group/puppet-dev?hl=en
-~----------~----~----~----~------~----~------~--~---