Hey,
I haven't had a chance to read carefully through all the thread so far and I hope to do tomorrow, but I thought it was worth sharing how I assumed this would work and what, coincidentally, looks roughly like the direction Greg was taking with Audrey.
Some notes first:
- A basic assumption we're making here is that a template should contain the packages needed for a service and the service definition just contains configuration in the form of a puppet manifest. So, the puppet manifest shouldn't cause new packages to be installed. That feels fairly arbitrary, but correct.
- We need to consider the template and service authors - at the most basic level, we'll have some documentation on conventions to follow and how to register the templates and services. Perhaps we might have a UI or rich tooling for this in future. But what does it mean to author a template or service?
- We need to bear in mind that puppet manifest, and configuration in general, is tied to the package versions in a template. It's not practical IMHO to assume that you can author a puppet manifest representing a service configuration and expect that to work with a wide range of templates.
So, here's how I assumed this would all work:
- A template author starts by taking a base template (which is basically an XMLified simple kickstart file) and including that in her new template
<template> <name>my_template</name> <include name="f14-x86_64-base.tmpl"/> </template>
- She adds further packages and configuration to the template, again similar in concept to editing a kickstart file
<template> ... <packages> <package name="emacs"/> </packages> <puppet manifest="my_template.pp"/> </template>
The puppet manifest is a standard puppet manifest.
- She then can create new service definitions, or re-use existing service definitions by other authors, and reference these
<template> ... <services> <service name="my_postfix"> <puppet manifest="my_postfix.pp"/> </service> </services> </template>
The puppet manifest for services conforms to a set of conventions:
1) Each service is defined by a single parameterized class
2) The class has an $enabled parameter which defaults to false
3) When $enabled is false, the packages required for enabling the service are installed, but nothing else
4) When $enabled is true, the necessary configuration to enable the service is applied using any further parameters to the class
5) The class includes documentation for the service and its parameters which can be show in the UI
- When a template is registered with Conductor, the parameters and docs are extracted from the puppet classes so that they can be exposed in the UI
- When a template is built, the puppet manifests for the services are included in a standard location and asserted with the default parameters. This causes the packages available for all services to be installed.
- When the template is instantiated, the user can select in the UI the services to enable and the parameters for each. When the instance starts, it contacts the config server for that information and runs the appropriate set of puppet classes with the appropriate parameters supplied via an "external node configuration" script
An example puppet manifest for a postfix service is below
Cheers, Mark.
class postfix($enabled = false, $relayhost = '') {
package { 'postfix': ensure => installed }
if $enabled { augeas { 'postfix_conf': context => '/files/etc/postfix/main.cf', changes => "set relayhost ${relayhost}", notify => Service['postfix'], require => Package['postfix'] }
exec { '/usr/sbin/alternatives --set mta /usr/sbin/sendmail.postfix': require => Package['postfix'] }
service { ['sendmail', 'exim']: enable => false, ensure => stopped }
service { 'postfix': enable => true, ensure => running, require => [ Service[sendmail, exim], Augeas[postfix_conf] ] } } }