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
$ 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" yepEnsuite, pas de ./configure, tout passe par Ruby !
$ ruby install.rbBien 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 READMEEt 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.confLe /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/localconfigA 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 ACCEPTEt 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 ACCEPTNous 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 puppetcliAttention ! 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 secondsEt 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 -cSyntax 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 typeC'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 secondsEn 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/testfilePas 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 secondsEt 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 buxEt 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 puppetcliOn 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 secondsLa 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 secondsDu 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 eventsNotre 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 secondsNotre 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.