Puppet, gestionnaire de configuration

Puppet ?

Puppet est ce que l’on peut appeler un gestionnaire de configuration. C’est un outil qui facilite le contrôle et la mise à jour de configurations tout en offrant la possibilité de faire abstraction de l’OS et de l’architecture concernée. Cette gestion de configuration passe par la définitions d’un ensemble de règles et de catégories, regroupant les différents acteurs de l’infrastructure cible et qui, rédigé dans un langage de déclaration propre à la solution, prend l'appellation de manifest.

Installation

Il existe 3 possibilités d'installer Puppet : les sources, les dépôts et GEM.

Installation depuis les sources

L'installation depuis les sources procède à une installation qui localiste :
  • le répertoire propre au fonctionnement du service puppet dans /home/puppet, puisque le lancement du service puppetmasterd --mkusers par défaut crée un utilisateur puppet standard chargé de faire tourner le daemon avec un home à l'endroit habituel
  • le répertoire propre à la configuration du service dans /etc/puppet
Petite récupération des sources. A ce jour, nous sommes en 2.6.4, mais le plus sûr moyen de bien faire les choses, c’est de wgetter le tar.gz latest, qui, comme son nom l’indique, pointe sur la dernière version de puppet.
$ wget http://www.puppetlabs.com/downloads/puppet/puppet-latest.tar.gz
$ tar zxf puppet-latest.tar.gz
$ cd puppet-2.6.4/
On tombe sur un README bien sympa qui nous indique les pré-requis à une bonne utilisation de Puppet.
$ cat README
Documentation (and detailed install instructions) can be found online at http://docs.puppetlabs.com/.Additional documentation can also be found at the Puppet Wiki:http://projects.puppetlabs.com/projects/puppet/wiki/
Generally, you need the following things installed:

* Ruby >= 1.8.1 (earlier releases might work but probably not)
* The Ruby OpenSSL library.  

For some reason, this often isn't included in the main ruby distributions.  You can test for it by running 'ruby -ropenssl -e "puts :yep"'.  If that errors out, you're missing the library.
If your distribution doesn't come with the necessary library (e.g., on Debian and Ubuntu you need to install libopenssl-ruby), then you'll probably have to compile Ruby yourself, since it's part of the standard library and not available separately.  You could probably just compile and install that onelibrary, though.

* The Ruby XMLRPC client and server libraries.

For some reason, this often isn't included in the main ruby distributions.  You can test for it by
running 'ruby -rxmlrpc/client -e "puts :yep"'.  If that errors out, you're missing the library.

* Facter => 1.5.1 You can get this from < http://puppetlabs.com/projects/facter >
Tests :
$ ruby -ropenssl -e "puts :yep"
yep
Ensuite, pas de ./configure, tout passe par Ruby !
$ ruby install.rb
Bien entendu, l’install s’arrête là, mais cela ne veut pas dire que c’est opérationnel ! Il faut notamment créer l'utilisateur responsable du lancement et du run du daemon :
$ puppetmasterd --mkusers

Installation depuis les dépôts

L'installation depuis les dépôts est plus confortable, quoique moins à jour le plus souvent. Elle génère certaines configurations. Pour information, après moultes tests, j'ai pris le confort de passer par ce type d'installation, c'est d'ailleurs pour cette raison que vous trouverez des références à /var/lib/puppet. A ce titre, il y a 2 répertoires clefs qui nous suivront tout au long du test de Puppet :
  • /etc/puppet/ : le répertoire de configuration du service puppetmasterd / puppetd, c'est à ce niveau que l'on retrouve le répertoire manifests et les différentes classes définies,
  • /var/lib/puppet/ : le répertoire contenant les données impliquées dans les gestions de configuration, concernant les clients (certificats, rapports), mais également là où ces derniers vont chercher l'information à mettre à jour.

Installation depuis les GEM

L'installation par GEM est simple et intuitive et s'aligne sur l'installation type de celle faite par les dépôts :
  • /var/lib/puppet pour les données relatives au fonctionnement du daemon,
  • /etc/puppet pour la configuration.
$ gem install facter

Successfully installed facter-1.5.8
1 gem installed
Installing ri documentation for facter-1.5.8...
Installing RDoc documentation for facter-1.5.8...
Could not find main page README
Could not find main page README
Could not find main page README
Could not find main page README

$ gem install puppet

Successfully installed puppet-2.6.4
1 gem installed
Installing ri documentation for puppet-2.6.4...
Installing RDoc documentation for puppet-2.6.4...
Could not find main page README
Could not find main page README
Could not find main page README
Could not find main page README
Et bien sûr, la désinstallation se fera de la même manière :
$ gem uninstall facter
Remove executables:
facter

in addition to the gem? [Yn]  Y
Removing facter

You have requested to uninstall the gem:
facter-1.5.8
puppet-2.6.4 depends on [facter (>= 1.5.1)]
If you remove this gems, one or more dependencies will not be met.
Continue with Uninstall? [Yn]  Y
Successfully uninstalled facter-1.5.8

$ gem uninstall puppet

Remove executables:
filebucket, pi, ralsh, puppet, puppetdoc, puppetd, puppetca, puppetrun, puppetmasterd, puppetqd

in addition to the gem? [Yn]  Y
Removing filebucket
Removing pi
Removing ralsh
Removing puppet
Removing puppetdoc
Removing puppetd
Removing puppetca
Removing puppetrun
Removing puppetmasterd
Removing puppetqd
Successfully uninstalled puppet-2.6.4

Pour avoir testé, je vous recommande tout de même, à numéro de version égale, de passer par GEM.

Lancement et génération de certificats SSL

Le lancement du daemon puppetmasterd suffit à créer l’arborescence /etc/puppet contenant les informations nécessaires niveau SSL et certificats, dont la CA (Certificate Autority) qui servira à signer les certificats des clients et du serveur.

Jetons un coup d’oeil au certificat crée, au hasard :
$ openssl x509 -text -in /etc/puppet/ssl/certs/ca.pem
Certificate:
Data:
Version: 3 (0x2)
Serial Number: 1 (0x1)
Signature Algorithm: sha1WithRSAEncryption
Issuer: CN=Puppet CA: pupppetserv
Validity
Not Before: Jan 13 15:35:22 2011 GMT
Not After : Jan 12 15:35:22 2016 GMT
Subject: CN=Puppet CA: puppetserv
Subject Public Key Info:
Public Key Algorithm: rsaEncryption
RSA Public Key: (1024 bit)
Modulus (1024 bit):
00:[...]
Exponent: 65537 (0x10001)
X509v3 extensions:
Netscape Comment:
Puppet Ruby/OpenSSL Generated Certificate
X509v3 Basic Constraints: critical
CA:TRUE
X509v3 Subject Key Identifier:
F4:82:CE:F1:07:ED:53:22:48:10:96:41:7C:00:60:37:B0:07:22:B3
X509v3 Key Usage:
Certificate Sign, CRL Sign
Signature Algorithm: sha1WithRSAEncryption
46:[...]
-----BEGIN CERTIFICATE----- [...]
Pour ceux qui ont suivi le tip sur les certificats x509, et les autres qui ont remarqué le champs CA, il est évident que ce certificat est bien celui de l’Autorité de Certification. Il a été crée sans intervention de notre part suite au lancement de puppetmasterd. Cette CA a permis ensuite de signer le certificat du serveur, également automatiquement crée et signé par la main du daemon.
$ openssl x509 -text -in /etc/puppet/ssl/certs/puppetserv.pem
Certificate:
Data:
Version: 3 (0x2)
Serial Number: 2 (0x2)
Signature Algorithm: sha1WithRSAEncryption
Issuer: CN=Puppet CA: puppetserv
Validity
Not Before: Jan 13 15:35:22 2011 GMT
Not After : Jan 12 15:35:22 2016 GMT
Subject: CN=puppetserv
Subject Public Key Info:
Public Key Algorithm: rsaEncryption
RSA Public Key: (1024 bit)
Modulus (1024 bit):
00:[...]
Exponent: 65537 (0x10001)
X509v3 extensions:
Netscape Comment:
Puppet Ruby/OpenSSL Generated Certificate
X509v3 Basic Constraints: critical
CA:FALSE
X509v3 Subject Key Identifier:
26:E0:36:4B:22:68:A8:F0:C2:D6:93:EF:4B:B6:23:73:71:C1:FA:8A
X509v3 Key Usage:
Digital Signature, Key Encipherment
X509v3 Extended Key Usage:
TLS Web Server Authentication, TLS Web Client Authentication, E-mail Protection
X509v3 Subject Alternative Name:
DNS:puppet, DNS:puppetserv, DNS:puppet
Signature Algorithm: sha1WithRSAEncryption
83:[...]
-----BEGIN CERTIFICATE----- [...]
Ce qui fait que vous avez à présent 2 certificats sur la machine : la CA et le certificat de la machine en elle-même. Ce qu’il y a d’important à retenir c'est que Puppet fonctionne en mode Client – Serveur. A ce titre, les certificats et clés générés sont propres à la machine. Ici, vu que l’on est sur le serveur, le contenu de /var/lib/puppet/.puppet/ssl/private_keys et /var/lib/puppet/.puppet/ssl/public_keys est identique à celui de ces mêmes répertoires sous /etc/puppet/ssl/. Sur le client, en revanche, c’est différent car spécifique au client. La seule entité commune aux clients et au Puppet Server est le ca.pem, situé sous /var/lib/puppet/.puppet/ssl/certs/.

Mise en opération

Configuration des services

Attaquons au niveau du coeur de Puppet et là où ça fait le plus mal :
ll /etc/puppet
total 15888
-rw-r--r-- 1 root root     2346 2011-03-24 11:20 auth.conf
drwxr-xr-x 3 root root     4096 2011-03-24 11:31 manifests/
-rw-r--r-- 1 root root     1051 2011-03-24 11:18 puppet.conf
Le /etc/puppet/auth.conf se présente comme suit : configuration auto-générée par l'installation, donc à priori pas optimale mais fonctionnelle en tout cas :)
path ~ ^/catalog/([^/]+)$
method find
allow $1

# allow all nodes to access the certificates services
path /certificate_revocation_list/ca
method find
allow *

# allow all nodes to store their reports
path /report
method save
allow *

# inconditionnally allow access to all files services
# which means in practice that fileserver.conf will
# still be used
path /file
allow *

### Unauthenticated ACL, for clients for which the current master doesn't
### have a valid certificate allow access to the master CA
path /certificate/ca
auth no
method find
allow *

path /certificate/
auth no
method find
allow *

path /certificate_request
auth no
method find, save
allow *

# this one is not stricly necessary, but it has the merit
# to show the default policy which is deny everything else
path /
auth any
/etc/puppet/puppet.conf a, quant à lui, fait l'objet de petites modifications, notamment au niveau de la section [master] qui a été entièrement rajoutée.
[main]
logdir = /var/log/puppet
rundir = /var/run/puppet
ssldir = $vardir/ssl
vardir = /var/lib/puppet
rundir = /var/run/puppet
confdir = /etc/puppet
factpath = $vardir/lib/facter
pluginsync = false
server = puppetserv
report = true
reports = log,store

[master]
templatedir = $vardir/templates
modulepath = $vardir/modules
libdir = $vardir/plugins
syslogfacility = user

[agent]
# The file in which puppetd stores a list of the classes
# associated with the retrieved configuratiion.  Can be loaded in
# the separate ``puppet`` executable using the ``--loadclasses`option.
# The default value is '$confdir/classes.txt'.
classfile = $vardir/classes.txt

# Where puppetd caches the local configuration.  An
# extension indicating the cache format is added automatically.
# The default value is '$confdir/localconfig'.
localconfig = $vardir/localconfig
A noter que vous n'êtes pas tenu de copier tel quel, car puppet met à disposition une option qui génèrera pour vous, en stdout, une configuration standard.
$ puppet --genconfig > /etc/puppet/puppet.conf

Premiers contacts Client / Serveur

Avant tout, il faut penser, dans le cas où les machines ne sont pas exempt de firewall, à ouvrir le port 8140 côté serveur :
puppetserv $ iptables -A OUTPUT -p tcp -m state --state NEW,ESTABLISHED -s puppetserv --sport 8140 -d puppetcli -j ACCEPT
puppetserv $ iptables -A INPUT -p tcp -m state --state NEW,ESTABLISHED -s puppetcli -d puppetserv --dport 8140 -j ACCEPT
Et le port 8139 côté client :
puppetcli $ iptables -A OUTPUT -p tcp -m state --state NEW,ESTABLISHED -s puppetcli --sport 8139 -d puppetserv -j ACCEPT
puppetcli $ iptables -A INPUT -p tcp -m state --state NEW,ESTABLISHED -s puppetserv -d puppetcli --dport 8139 -j ACCEPT
Nous avons passé les contraintes techniques. Mais le problème, dans la mise à disposition de configurations propre au parc se situe notamment dans la confiance en les équipements connectés. Tout ça pour dire que lorsqu'un nouveau client interroge le catalogue de votre serveur puppet, le serveur, lui, ne lui sert pas tout tout de suite tout cuit dans le bec. On ne sait jamais, est-ce une machine qui a été renouvelée et qui a les accréditations nécessaires, ou est-ce un portable ramené par un invité qui veut avoir accès aux configurations du réseau ? C'est à cela que sert la base de certificat et la CA. Lors d'un premier contact, ça donne ça :
puppetcli $ puppetd --server puppetserv --waitforcert 60 --test
info: Creating a new SSL key for puppetcli
warning: peer certificate won't be verified in this SSL session
info: Caching certificate for ca
warning: peer certificate won't be verified in this SSL session
warning: peer certificate won't be verified in this SSL session
info: Creating a new SSL certificate request for puppetcli
info: Certificate Request fingerprint (md5): E9:D4:CE:29:18:C5:0D:58:C8:B7:89:CB:12:4E:4C:97
warning: peer certificate won't be verified in this SSL session
warning: peer certificate won't be verified in this SSL session
warning: peer certificate won't be verified in this SSL session
notice: Did not receive certificate
warning: peer certificate won't be verified in this SSL session
notice: Did not receive certificate
[...]
Donc, admettons que notre puppetcli est bien légitime. On va donc signer le certificat identifiant puppetcli, lui permettant par la même occasion d'accéder au catalogue de notre serveur puppetserv. Et du coup, sur le server puppet, un petit puppetca –list vous apprendra que l’on a sollicité -et qui- le service.
puppetserv $ puppetca -l
puppetcli
Attention ! Le nom que vous voyez apparaître est en fait une partie du DN (Distinguished Name) qui a été défini lors de la création du certificat. Il se peut tout-à-fait que ce nom ne soit pas pertinent (doublon, forgé, …). C’est justement pour cela qu’en soi, Puppet est un peu mieux pensé en terme de sécurité qu’un NFS : il n’est pas orienté client full trust. Evidemment, si vous gérez d’une main de fer votre parc, valider les certificats manuellement peut être harassant, c’est d’ailleurs pour cela que Puppet a aussi prévu le coup. Malgré tout, je vous encourage à le faire de cette façon, car après tout, c’est toute une configuration que l’on peut potentiellement récupérer, mieux vaut savoir qui au juste… Signons notre requête de certificat, puisqu’elle est légitime :
puppetserv $ puppetca -s puppetcli
notice: Signed certificate request for puppetcli
notice: Removing file Puppet::SSL::CertificateRequest puppetcli at '/etc/puppet/ssl/ca/requests/puppetcli.pem'
Le certificat signé, il est possible de voir ce qu’il contient :
puppetserv $ puppetca --print puppetcli
Certificate:
Data:
Version: 3 (0x2)
Serial Number: 3 (0x3)
Signature Algorithm: sha1WithRSAEncryption
Issuer: CN=Puppet CA: puppetserv
Validity
Not Before: Jan 19 13:14:48 2011 GMT
Not After : Jan 18 13:14:48 2016 GMT
Subject: CN=puppetcli
Subject Public Key Info:
Public Key Algorithm: rsaEncryption
RSA Public Key: (1024 bit)
Modulus (1024 bit):
00:[...]
Exponent: 65537 (0x10001)
X509v3 extensions:
Netscape Comment:
Puppet Ruby/OpenSSL Generated Certificate
X509v3 Basic Constraints: critical
CA:FALSE
X509v3 Subject Key Identifier:
9C:DE:CC:6C:1C:50:A3:A5:25:A1:CB:38:56:E9:F3:08:3E:5D:3C:FD
X509v3 Key Usage:
Digital Signature, Key Encipherment
X509v3 Extended Key Usage:
TLS Web Server Authentication, TLS Web Client Authentication, E-mail Protection
Signature Algorithm: sha1WithRSAEncryption [...]
Une fois signés, on les retrouve sous /var/lib/puppet/ssl/ca/signed/. Si on relance notre test sur le client, du coup, ça passe tout de suite mieux :
puppetcli $ puppetd --server puppetserv --waitforcert 60 --test
info: Caching certificate_revocation_list for ca
info: Caching catalog for puppetcli
info: Applying configuration version '1295861918'
info: Creating state file /var/lib/puppet/state/state.yaml
notice: Finished catalog run in 0.01 seconds
Et les logs du serveur le prouvent :
Mar 24 10:38:38 puppetserv puppet-master[3799]: Compiled catalog for puppetcli in environment production in 0.06 seconds

Une fois que la confirmation de la connexion entre le client et le server est tombée, il ne reste plus qu’à retrousser les manches et à créer notre propre manifest.

Manifest

Un manifest est un fichier en .pp, généralement situé sous /etc/puppet/manifests/ et énonçant les spécifications et les noeuds concernés par celles-ci. Ces spécifications sont organisées en structures et peuvent impliquer des classes, fichier contenant eux-même d'autres sous-ensemble de contraintes. Puppet a choisi un langage déclaratif, complètement distinct des langages de développement (Ruby, Perl, Python,…) et ce, pour une bonne raison : ces langages sont extrêmement riches et pourraient pousser à la mauvaise habitude de se retrousser les manches et de coder soi-même les choses à faire. Pour autant, le langage utilisé par Puppet n’en est pas moins très évolué et permet de moduler finement les définitions. Etant néophyte en la matière, je vais donc m’appuyer sur le tutorial officiel concernant le langage Puppet. Tout cela pour dire qu'il s'agit juste d'exemple simples, parfois étriqués, et qu'il est possible d'améliorer ces exemples et d'en faire des matrices robustes, facilement portables et réutilisables. Il est dit que puppet est capable de gérer plusieurs manifests, du moment que ceux-ci sont lisibles et portent l'extension .pp, mais dans tous les cas, le daemon va en tout premier lieu chercher le /etc/puppet/manifest/site.pp. S'il n'existe pas, et bien cela s'arrêtera là et rien ne sera fait. Maintenant que tout est dit -ou presque-, passons de suite à la pratique !

Validation de l'existence et permissions

Voici notre premier manifest, pas très impressionnant, fera un test de vérification d'existence ou création de fichier si le test est négatif et se calera dans un fichier /etc/puppet/manifest/testf.pp :
# /etc/puppet/manifest/testf.pp
# Create "/tmp/testfile" if it doesn't exist.
class testf {
file { "/tmp/testfile":
ensure => present,
mode   => 644,
owner  => "root",
group  => "root",
replace=> false,
}
}
Accessoirement, vous pouvez valider la syntaxe :
$ erb -x -T '-' -P /etc/puppet/manifests/testf.pp | ruby -c
Syntax OK Bien entendu, il faut stipuler que ce manifest doit être utilisé. Bon, ici, pour être sûr que ça fonctionne, j'ai mis le node à default. Il est bon de savoir que l'on peut distinguer les nodes (mais cela paraît évident :).
# /etc/puppet/manifest/site.pp
node default {
include testf
}
Petit test préalable : non rien n'est truqué sur puppetcli :
puppetcli $ ll /tmp/testfile
ls: ne peut accéder /tmp/testfile: Aucun fichier ou dossier de ce type
C'est parti : lancement du service sur puppetserv et sur puppetcli :
puppetserv $ puppetmasterd --no-daemonize -d
[...]
info: Caching node for puppetcli
debug: importing '/etc/puppet/manifests/testf.pp' in environment production
debug: Automatically imported testf from testf into production
notice: Compiled catalog for puppetcli in environment production in 0.03 seconds
info: //puppetcli/Puppet: Caching catalog for puppetcli
info: //puppetcli/Puppet: Applying configuration version '1301063287'
notice: //puppetcli//Stage[main]/Testf/File[/tmp/testfile]/ensure: created
puppetcli  $ puppet agent --test --server=puppetserv

info: Caching catalog for puppetcli
info: Applying configuration version '1301063287'
notice: /Stage[main]/Testf/File[/tmp/testfile]/ensure: created
notice: Finished catalog run in 0.02 seconds
En 2 temps trois mouvements, notre fichier (vide) a été crée avec les permissions adéquates sur puppetcli :
puppetcli $ ll /tmp/testfile
-rw-r--r-- 1 root root 0 2011-03-25 15:28 /tmp/testfile
Pas très glorifiant, je sais, mais au moins, le premier contact avec le langage de Puppet n'a pas été douloureux. Rassurez-vous, il est possible de faire beaucoup plus efficace dans la matière !

Installation de package

Pour plus de clarté, nous avons crée /etc/puppet/manifest/classes, qui regroupera nos différentes classes. Pour pouvoir y faire appel, il faudra juste faire un import du dossier, histoire de. Voici un exemple de /etc/puppet/manifest/site.pp :
import "classes/*"
node default {
    include ntp
}
On crée notre /etc/puppet/manifest/classes/ntp.pp :
class ntp {
    package { "ntp":
               ensure => installed
    }
service { "ntpd":
           ensure => running,
        }
}
Relance du serveur, relance du service et du client :
puppetserv $ puppetmasterd --no-daemonize -d
[...]
info: Caching node for puppetcli
debug: importing '/etc/puppet/manifests/classes/ntp.pp' in environment production
debug: Automatically imported ntp from ntp into production
debug: Puppet::Type::Package::ProviderRpm: Executing '/bin/rpm --version'
debug: Puppet::Type::Package::ProviderYum: Executing '/bin/rpm --version'
debug: Puppet::Type::Package::ProviderUrpmi: Executing '/bin/rpm -ql rpm'
debug: Puppet::Type::Package::ProviderAptrpm: Executing '/bin/rpm -ql rpm'
notice: Compiled catalog for puppetcli in environment production in 0.62 seconds
info: //puppetcli/Puppet: Caching catalog for puppetcli
info: //puppetcli/Puppet: Applying configuration version '1300970060'
notice: //puppetcli//Stage[main]/Ntp/Package[ntp]/ensure: created
err: //puppetcli//Stage[main]/Ntp/Service[ntpd]/ensure: change from stopped to running failed: Could not start Service[ntpd]: Execution of '/sbin/service ntpd start' returned 1:  at /etc/puppet/manifests/ntp.pp:9
$puppetcli $ puppet agent --test --server=puppetserv
notice: Ignoring --listen on onetime run
info: Caching catalog for puppetcli
info: Applying configuration version '1300970060'
notice: /Stage[main]/Ntp/Package[ntp]/ensure: created
err: /Stage[main]/Ntp/Service[ntpd]/ensure: change from stopped to running failed: Could not start Service[ntpd]: Execution of '/sbin/service ntpd start' returned 1:  at /etc/puppet/manifests/ntp.pp:9
notice: Finished catalog run in 2.60 seconds
Et oui, pas de chance : le package ntpd de la distribution ne contient pas de matrice pour démarrer / arrêter le daemon depuis service. Une chose est sûre en tout cas, le package a bien été installé !

Reconfiguration

Puisque nous avons vu comment crée un fichier (vide), pourquoi ne pas tenter ce pour quoi puppet a été crée ? Une reconfiguration ! Même scénario : on prend la température avec un premier test extrêmement simple :
puppetserv $ cat /etc/puppet/manifests/classes/testc.pp

class testc {

$server = "puppetserv"

file { "/tmp/test.conf":
mode => 644,
owner => "root",
group => "root",
ensure => present,
source => "puppet://$server/files/test.conf"
}
}
L'arborescence puppet://puppetserv/files fait référence au répertoire /var/lib/puppet/files de puppetserv, du coup, on crée notre test.conf tel que :
puppetserv $ cat /var/lib/puppet/files/test.conf
bux
Et bien sûr, si ce n'est pas déjà fait, on crée / configure notre /etc/puppet/fileserver.conf , qui nous servira à définir qui a le droit d'accéder à quoi.
[files]
path /var/lib/puppet/files
allow puppetcli
On restart le service et on obtient après requête de puppetcli :
puppetserv $ puppetmasterd --no-daemonize -d

info: Expiring the node cache of puppetcli
info: Not using expired node for puppetcli from cache; expired at Mon Mar 28 12:31:50 +0200 2011
info: Caching node for puppetcli
debug: importing '/etc/puppet/manifests/classes/testc.pp' in environment production
debug: Automatically imported testc from testc into production
notice: Compiled catalog for puppetcli in environment production in 0.03 seconds
info: mount[files]: allowing puppetcli access
info: //puppetcli/Puppet: Caching catalog for puppetcli
info: //puppetcli/Puppet: Applying configuration version '1301308370'
notice: //puppetcli//Stage[main]/Testc/File[/tmp/test.conf]/ensure: defined content as '{md5}62497e0a309b74243cd34c8c1522df32'
La requête en question :
puppetcli $ puppet agent --test --server=puppetserv
notice: Ignoring --listen on onetime run
info: Caching catalog for puppetcli
info: Applying configuration version '1301308370'
notice: /Stage[main]/Testc/File[/tmp/test.conf]/ensure: defined content as '{md5}62497e0a309b74243cd34c8c1522df32'
notice: Finished catalog run in 0.20 seconds
La mise à jour n'est pas plus compliquée, il suffit de mettre à jour la source et de relancer notre agent, qui se montrera un peu plus bavard :
puppetserv $  puppetmasterd --no-daemonize -d

info: Expiring the node cache of puppetcli
info: Not using expired node for puppetcli from cache; expired at Mon Mar 28 12:56:12 +0200 2011
info: Caching node for puppetcli
debug: importing '/etc/puppet/manifests/classes/testc.pp' in environment production
debug: Automatically imported testc from testc into production
notice: Compiled catalog for puppetcli in environment production in 0.03 seconds
info: mount[files]: allowing puppetcli access
info: //puppetcli/Puppet: Caching catalog for puppetcli
info: //puppetcli/Puppet: Applying configuration version '1301309832'
info: //puppetcli/Puppet: FileBucket adding /tmp/test.conf as {md5}62497e0a309b74243cd34c8c1522df32
info: //puppetcli//Stage[main]/Testc/File[/tmp/test.conf]: Filebucketed /tmp/test.conf to puppet with sum 62497e0a309b74243cd34c8c1522df32
notice: //puppetcli//Stage[main]/Testc/File[/tmp/test.conf]/content: content changed '{md5}62497e0a309b74243cd34c8c1522df32' to '{md5}2c5d3577c7dac561f657271be81606ac'
puppetcli $ puppet agent --test --server=puppetserv
notice: Ignoring --listen on onetime run
info: Caching catalog for puppetcli
info: Applying configuration version '1301309832'
--- /tmp/test.conf      2011-03-28 12:45:56.000000000 +0200
+++ /tmp/puppet-file20110328-4815-1x3q3jw-0     2011-03-28 12:57:12.000000000 +0200
@@ -1 +1,2 @@
-bux
+#!/bin/bash
+echo "Hello puppet :)" > /tmp/puppet.hello
info: FileBucket adding /tmp/test.conf as {md5}62497e0a309b74243cd34c8c1522df32
info: /Stage[main]/Testc/File[/tmp/test.conf]: Filebucketed /tmp/test.conf to puppet with sum 62497e0a309b74243cd34c8c1522df32
notice: /Stage[main]/Testc/File[/tmp/test.conf]/content: content changed '{md5}62497e0a309b74243cd34c8c1522df32' to '{md5}2c5d3577c7dac561f657271be81606ac'
notice: Finished catalog run in 0.25 seconds
Du coup, rien ne vous empêche de créer une classe httpd, à accommoder avec vos propres noms de packages, car certains ont des noms qui varient en fonction de la distribution. Voici le contenu de /etc/puppet/classes/httpd.pp :
$server = "puppetserv"

# The same as a file, except that the source is always taken
# relative to the /config module on the file server
define configfile(owner = root, group = root, mode = 644, source,
 backup = false, recurse = false, ensure = file) {
 file { $name:
 mode => $mode,
 owner => $owner,
 group => $group,
 backup => $backup,
 recurse => $recurse,
 ensure => $ensure,
 source => "puppet://$server/files/$source"
 }
}

class httpd {
  package { apache-base:
    ensure => latest
  }

  configfile { "/etc/httpd/conf/httpd.conf":
    source => "/httpd/httpd.conf",
    mode => 644,
    require => package["apache-base"]
  }

  group { apache: gid => 48 }

  user { apache:
   comment => "Apache",
   uid => 48,
   gid => 48,
   home => "/var/www",
   shell => "/sbin/nologin"
  }

  service { httpd:
    ensure => running,
    subscribe => [ file["/etc/httpd/conf/httpd.conf"],
                   package["apache-base"] ]
  }
}
Cette classe permet de mettre en lumière une des richesses de puppet : la gestion des abonnements. Très clairement, lorsque le fichier de configuration /etc/httpd/conf/httpd.conf ou le package apache-base subit une modification, le service httpd est redémarré. Voici ce que l'on observe depuis notre serveur :
puppetserv $ puppetmasterd --no-daemonize -d

info: Expiring the node cache of puppetcli
info: Not using expired node for puppetcli from cache; expired at Mon Mar 28 14:44:21 +0200 2011
info: Caching node for puppetcli
debug: importing '/etc/puppet/manifests/classes/testc.pp' in environment production
debug: importing '/etc/puppet/manifests/classes/httpd.pp' in environment production
debug: Puppet::Type::Package::ProviderRpm: Executing '/bin/rpm --version'
debug: Puppet::Type::Package::ProviderYum: Executing '/bin/rpm --version'
debug: Puppet::Type::Package::ProviderUrpmi: Executing '/bin/rpm -ql rpm'
debug: Puppet::Type::Package::ProviderAptrpm: Executing '/bin/rpm -ql rpm'
notice: Compiled catalog for puppetcli in environment production in 0.57 seconds
info: mount[files]: allowing puppetcli access
info: //puppetcli/Puppet: Caching catalog for puppetcli
info: //puppetcli/Puppet: Applying configuration version '1301316321'
notice: //puppetcli//Stage[main]/Httpd/Package[apache-base]/ensure: created
info: //puppetcli//Stage[main]/Httpd/Package[apache-base]: Scheduling refresh of Service[httpd]
notice: //puppetcli//Stage[main]/Httpd/Configfile[/etc/httpd/conf/httpd.conf]/File[/etc/httpd/conf/httpd.conf]/content: content changed '{md5}0a95fb40c242024380e65bdc030aed91' to '{md5}adbb5f82e0e547e4b716ad6d57803ecd'
info: //puppetcli//Stage[main]/Httpd/Configfile[/etc/httpd/conf/httpd.conf]/File[/etc/httpd/conf/httpd.conf]: Scheduling refresh of Service[httpd]
info: //puppetcli//Stage[main]/Httpd/Service[httpd]/ensure: change from stopped to running succeded : Service[httpd] started
notice: //puppetcli//Stage[main]/Httpd/Service[httpd]: Triggered 'refresh' from 2 events
Notre client, lui, fait tranquillement son boulot et installe apache-base...
puppetcli $ puppet agent --test --server=puppetserv

[...]

notice: /Stage[main]/Httpd/Configfile[/etc/httpd/conf/httpd.conf]/File[/etc/httpd/conf/httpd.conf]/content: content changed '{md5}0a95fb40c242024380e65bdc030aed91' to '{md5}adbb5f82e0e547e4b716ad6d57803ecd'
info: /Stage[main]/Httpd/Configfile[/etc/httpd/conf/httpd.conf]/File[/etc/httpd/conf/httpd.conf]: Scheduling refresh of Service[httpd]
info: /Stage[main]/Httpd/Service[httpd]/ensure: change from stopped to running succeded : Service[httpd]: started
notice: /Stage[main]/Httpd/Service[httpd]: Triggered 'refresh' from 2 events
notice: Finished catalog run in 4.35 seconds
Notre puppetcli a maintenant apache-base d'installé, dans sa dernière version disponible sur les dépôts, et une configuration conforme à celle que nous avons créée et stockée sur le puppetserv; /var/lib/puppet/files/httpd/httpd.conf.

Conclusion

Bien entendu, ce n'est qu'un épluchage rapide d'une solution open source, très riche et modulable à souhait ! Je vais rester un moment dessus, histoire de tirer parti de l'outil, et je vous encourage vivement, vous aussi, à jouer avec vu tout ce qu'il permet de faire facilement, sans avoir à remalaxer toutes les configurations. Enjoy !
Vus : 3446
Publié par K-Tux : 59