Nous voulions tester notre code Puppet sur Debian 11 qui était alors dans l'état release candidate (RC).
Dans notre code (et dans Hiera), nous utilisons le fact os/release/major pour agir en fonction de la version d'un système Debian GNU/Linux.
Pour agir sur plusieurs versions en même temps, nous convertissons le fact, qui est une chaîne de caractères, en nombre (if (0 + $facts['os']['release']['major']) >= 9 { […] }
).
Or, quand une version de Debian est en RC, os/release/major ne contient pas un nombre mais un texte (« testing » ou « bullseye », je ne sais plus). Forcément, notre code échoue…
Facter permet d'utiliser des variables d'environnement pour créer un fact : FACTER_bonjour='Hello, World!' facter -p
.
On peut également surcharger un fact avec une variable d'environnement : FACTER_kernel='GuiGuiOS' facter -p
.
Le contenu surchargé est transmis à Puppet. Soit le code suivant :
Notify { $facts['kernel']:
}
puppet agent -t
affichera : « Notice: Linux ». FACTER_kernel='GuiGuiOS' puppet agent -t
affichera « GuiGuiOS ».
Mais cela ne fonctionne pas avec les facts structurés (tableaux, JSON, YAML). Reprenons notre fil rouge : surcharger os/release/major :
FACTER_os='{
architecture => "amd64",
distro => {
codename => "buster",
description => "Debian GNU/Linux 11 (bullseye)",
id => "Debian",
release => {
full => "11",
major => "11"
}
},
family => "Debian",
hardware => "x86_64",
name => "Debian",
release => {
full => "11.0",
major => "11",
minor => "11"
},
selinux => {
enabled => false
}
}' facter -p | grep major
Cela fonctionne. J'expliquerai à la fin pourquoi j'ai surchargé tout « os » alors qu'il est possible de surcharger uniquement os/release/major.
En revanche, Puppet n'en veut pas :
FACTER_os='{
architecture => "amd64",
distro => {
codename => "buster",
description => "Debian GNU/Linux 11 (bullseye)",
id => "Debian",
release => {
full => "11",
major => "11"
}
},
family => "Debian",
hardware => "x86_64",
name => "Debian",
release => {
full => "11.0",
major => "11",
minor => "11"
},
selinux => {
enabled => false
}
}' puppet agent -t
Résultat : « Error: Could not retrieve catalog from remote server: Error 500 on SERVER: Server Error: Evaluation Error: A substring operation does not accept a String as a character index. ».
On peut essayer de formater pour tout mettre sur une ligne ou de fournir un format JSON, ça ne fonctionne pas mieux. C'est connu.
On peut diffuser un fact personnalisé / externe via un module Puppet. Je n'ai pas envie car je veux juste faire un test sur une seule machine.
Un fact peut également être stocké en local sur une machine. L'emplacement des facts externes est mentionné dans la doc'.
Le dossier « /etc/facter/facts.d/ » n'existe pas, mais on peut le créer.
/etc/facter/facts.d/os.yaml
:
os:
architecture: "amd64"
distro:
codename: "bullseye"
description: "Debian GNU/Linux 11 bullseye"
id: "Debian"
release:
full: "11"
major: "11"
family: "Debian"
hardware: "x86_64"
name: "Debian"
release:
full: "11.0"
major: "11"
minor: "11"
selinux:
enabled: false
Cela fonctionne. \o/
Pour les masos, on peut aussi l'faire en JSON. /etc/facter/facts.d/os.json
:
{
"os": {
"architecture": "amd64",
"distro": {
"codename": "bullseye",
"description": "Debian GNU/Linux 11 bullseye",
"id": "Debian",
"release": {
"full": "11",
"major": "11"
}
},
"family": "Debian",
"hardware": "x86_64",
"name": "Debian",
"release": {
"full": "11.0",
"major": "11",
"minor": "11"
},
"selinux": {
"enabled": false
}
}
}
Il est possible de surcharger uniquement la variable désirée (os/release/major dans mon cas), mais je le déconseille : facter ne fusionnera pas ta variable avec le reste du fact structuré (dans mon cas, si je surcharge os/release/major, os/architecture ou os/distro ou os/release/full ou… n'existeront plus). Or, ton code ou un module peut vouloir récupérer un fact ignoré. Dans ce cas, l'exécution de puppet se terminera avec une erreur genre « Error 500 on SERVER: Server Error: Evaluation Error: Operator '[]' is not applicable to an Undef Value. ».