Puppet: System Administration Automated

Support

This page documents the standards for how to write common modules,as part of the Puppet Common Modules (PCM) project.

The Puppet Common Modules project is designed to provide a common architecture, documentation, language, and style for modules. Also included is a collection of common modules.

Module Standards:

  1. A single module should implement a specific functionality, service or application. As lak said "If i'd ask myself "is X up?" Then X should be a module."
  2. Modules should be independent, if at all possible. If a dependency is absolutely necessary, it must be clearly documented. The user should be able to download just the common module and any modules that s/he is interested in and have that work, with no other changes.
  3. Any function/fact/type/provider needed should be clearly specified and either in the Puppet core, the same module or in the common module.
  4. If one of the choices is "you can do that with a template", that's usually the right way.
  5. Operating system differences should be specified in variables in a case at the start of the module, as follows:
    class ssh::server {
      case $operatingsystem {
       "freebsd","openbsd": {
          $sshservice = "sshd"
        }
        debian: {
           $sshservice = "ssh"
        }
      }
      # use a constant title to facilitate stable relations
      service { "ssh::server":
        name => $sshservice,
        ensure => running,
        enable => true,
      }
    }
    
  6. Bigger operating system differences should be split out into their respective classes:
    class ssh::server::common {
      service { 'ssh::server': ... }
    }
    class ssh::server::debian inherits ssh::server::common {
      Service['ssh::server'] { name => 'ssh' }
    }
    class ssh::server {
      include "ssh::server::$operatingsystem"
    }
    
  7. The Style Guide must be followed.
  8. All modules must be completely documented, as per the Module Documentation Standards.

User's Best Practices:

  1. The standard modules should be downloaded and added at the end of the modulepath (i.e., modulepath = /etc/puppet/modules:/etc/puppet/common-modules)
  2. Override functionality from a module by extending the relevant class or by wrapping a define:
    # This class provides a extra layer of security by obscurity
    # through moving the sshd to a high port
    class ssh::server::extra_secure inherits ssh::server {
      Ssh::Conf['Port'] { value => 12345 }
    }
    
    # This define creates a apache::site for a specific customer
    define apache::customer_site($source) {
      apache::site { "cust_${name}": source => $source }
      # additional resources go here
    }
    
    

Naming Standard:

  1. If there is only one class in the module, it should be in init.pp and have the same name as the module.
  2. If there are are multiple classes in the module:
    1. Each (externally visible) class should be in a separate file, named after the class to facilitate autoloading.
    2. The base class that is inherited by the other classes (if any), should be called module::common.
    3. Other class names should describe the difference in function between the classes i.e., module::client and module::server.
    4. Each (externally visible) define be in a separate file, named after the class to facilitate autoloading. For groups of small and/or tightly related defines, putting them together into a single file might make sense. The module has to import that in the init.pp to facilitate autoloading.

Notes Needed:

  1. enough interested people with time
  2. a place to development, including bug tracker, release eng, etc
  3. some extensions to the puppet language, possibly (confine to os, for example)
  4. standards for modules
  5. a way to document modules (maybe comment style, maybe a puppet lang extension)
  6. we need way to do versioning on modules