Facts custimizados

Extiende Facter escribiendo tus propios facts customizados para proporcionar información a Puppet. Facts de Ruby Agregar facts customizados a Facter A veces necesitas poder escribir expresiones condicionales basadas en información específica del sitio o del entorno que no está disponible via Facter (o usar una variable que no está en

Recent Posts

Extiende Facter escribiendo tus propios facts customizados para proporcionar información a Puppet.

Facts de Ruby

Agregar facts customizados a Facter

A veces necesitas poder escribir expresiones condicionales basadas en información específica del sitio o del entorno que no está disponible via Facter (o usar una variable que no está en Facter en un template). Eso se puede lograr agregando un nuevo fact en Facter. Estos facts adicionales pueden ser distribuidos a los clientes de Puppet y estarán disponibles para ser usados en los manifiestos.

El concepto

Puedes agregar facts nuevos escribiendo un fragmento de código Ruby en el Puppet master. Entonces usamos Plugins en Módulos para distribuir nuestros facts al cliente.

Ejemplo

Digamos que necesitamos obtener la salida de uname -i para referirnos a un tipo específico de estación de trabajo; para hacerlo, creamos un fact. Comenzamos dándole un nombre al fact, en este caso, hardwareplatform, y creando nuestro nuevo fact en un archivo, hardwareplatform.rb, en el Puppet master:

# hardware_platform.rb

Facter.add("hardware_platform") do
      setcode do
            Facter::Util::Resolution.exec('/bin/uname -i')
      end
end

Nota: Antes de Facter 1.5.8, los valores que devolvía Facter::Util::Resolution.exec a menudo contenían saltos de línea. Si tu fact customizado también será usado por versiones anteriores de Facter, puede que necesites utilizar chomp para esos valores. En el ejemplo anterior, sería así: Facter::Util::Resolution.exec('/bin/uname- i').chomp.

Entonces usamos las instrucciones en la página de Plugins en Módulos para copiar el nuevo fact a un módulo y distribuirlo. Durante la próxima ejecución de Puppet, el valor del nuevo fact estará disponible para ser usado en tus manifiestos.

El mejor lugar para obtener ideas de cómo escribir tus propios facts customizados es mirar el código de facts ya existentes en Facter. Encontrarás muchos ejemplos de cómo interpretar diferentes tipos de información de sistema y devolver facts útiles.

Utilizar otros facts

Puedes escribir facts que utilicen otros facts accediendo a Facter.value(“algunfact”) o simplemente a Facter.algunfact. El primero devolverá valor nulo para facts desconocidos, el último tirará una excepción. Un ejemplo:

Facter.add("osfamily") do
  setcode do
    distid = Facter.value('lsbdistid')
    case distid
    when /RedHatEnterprise|CentOS|Fedora/
      "redhat"
    when "ubuntu"
      "debian"
    else
      distid
    end
  end
end

Carga de facts customizados

Facter ofrece algunos métodos para cargar facts:

  • $LOAD_PATH, o la ruta de carga de la biblioteca de ruby
  • La variable de entorno ‘FACTERLIB’
  • Facts distribuidos usando pluginsync

Puedes utilizar estos métodos de carga de facts para realizar cosas como pruebas locales de archivos antes de distribuirlos, o tener un conjunto específico de facts disponibles en determinadas máquinas.

Facter buscará subdirectorios llamados 'facter' en todos los directorios en la variable de ruby $LOADPATH, y cargará todos los archivos de ruby en esos directorios. Si tenías algún directorio en tu $LOADPATH como ~/lib/ruby, configúralo así:

{~/lib/ruby}
└── facter
    ├── rackspace.rb
    ├── system_load.rb
    └── users.rb

Facter intentará cargar ‘facter/system_load.rb’, ‘facter/users.rb’, y ‘facter/rackspace.rb’.

Facter también buscará en la variable de entorno FACTERLIB un conjunto de directorios delimitados por signos de dos puntos (:), e intentará cargar todos los archivos de Ruby en esos directorios. Esto te permite hacer algo así:

$ ls my_facts
system_load.rb
$ ls my_other_facts
users.rb
$ export FACTERLIB="./my_facts:./my_other_facts"
$ facter system_load users
system_load => 0.25
users => thomas,pat

Facter también puede cargar fácilmente los archivos de facts distribuidos usando pluginsync. Ejecutar facter –p cargará todos los facts que hayan sido distribuidos vía pluginsync; así que si estás utilizando muchos facts customizados dentro de Puppet, puedes utilizar fácilmente estos facts con un facter standalone.

Los facts pueden ser distribuidos a los clientes usando el método Plugins en módulos.

Configuración de facts

Los facts tienen algunas propiedades que puedes utilizar para customizar cómo son evaluados.

Facts restringidos

Una de las propiedades más utilizadas es la declaración confine, que restringe el fact para que sólo funcione en sistemas que coincidan con otro fact dado.

Un ejemplo de declaración de confine sería el siguiente:

Facter.add(:powerstates) do
  confine :kernel => "Linux"
  setcode do
    Facter::Util::Resolution.exec('cat /sys/power/states')
  end
end

Este fact utiliza sysfs en Linux para obtener una lista de estados de encendido disponibles en el sistema dado. Como esto es sólo una variable en los sistemas Linux, usamos la declaración confine para asegurarnos que este fact no se ejecute innecesariamente en los sistemas que no son compatibles con este tipo de enumeración.

Precedencia de facts

Otra propiedad de los facts es la del peso. Los facts con mayor peso se ejecutan antes, lo que te permite sustituir o proveer alternativas a los facts existentes, o asegurarte que esos facts sean evaluados en un orden específico. Por defecto, el peso de un fact es el número de restricciones para ese fact; por lo tanto, los facts más específicos son evaluados primero.

# Comprueba si este servidor ha marcado como un servidor postgres
Facter.add(:role) do
  has_weight 100
  setcode do
    if File.exist? "/etc/postgres_server"
      "postgres_server"
    end
  end
end

# Adivina si esto es un servidor por la presencia del binario pg_create
Facter.add(:role) do
  has_weight 50
  setcode do
    if File.exist? "/usr/sbin/pg_create"
      "postgres_server"
    end
  end
end

# Si este servidor no parece un servidor, debe ser una computadora de escritorio
Facter.add(:role) do
  setcode do
    "desktop"
  end
end

Tiempo de expiración

Si tienes facts que son poco confiables y puede que no terminen de ejecutarse, puedes utilizar la propiedad timeout. Si un fact es definido con un tiempo de expiración y la evaluación del bloque de código setcode excede ese tiempo, Facter interrumpirá la resolución de ese fact y seguirá adelante.

# Duerme
Facter.add(:sleep, :timeout => 10) do
  setcode do
      sleep 999999
  end
end

Visualización de Valores de Facts

[puppetdb]: Si tu o tus Puppet master(s) están configurados para utilizar PuppetDB y/o el servicio de inventario, puedes buscar y visualizar todos los facts de cada nodo, incluyendo los customizados. Mira los documentos de PuppetDB o del servicio de inventario para más información.

Distribución de facts legacy

Para versiones de Puppet anteriores a 0.24.0:

En versiones anteriores de Puppet, antes de 0.24.0, para distribuir facts customizados se utilizaba un método diferente llamado factsync. Puppet buscaba facts customizados en puppet:/ /$server/facts de forma predeterminada y tenías que ejecutar puppetd con la opción --factsync (o agregar factsync = true a puppetd.conf). Esto permitía sincronizar los archivos en el sistema local de archivos y cargarlos en puppetd.

Los facts se sincronizaban a un directorio local ($vardir/facts, por defecto) antes de que facter se ejecute, entonces estaban disponibles desde el principio. Si $factsource no estaba definida, la opción --factsync era equivalente a:

file { $factdir: source => "puppet://puppet/facts", recurse => true }

Luego de bajarlos, los facts eran cargados (o recargados) en la memoria.

Algunas opciones adicionales estaban disponibles para configurar este método:

Las siguientes opciones de línea de comandos o de archivos de configuración están disponibles (opciones por defecto a la vista):

  • factpath ($vardir/facts): Donde Puppet debe buscar facts. Los directorios deben estar separados por dos puntos (:), como cualquier variable de PATH normal. Esto está establecido por defecto con los mismos valores de factdest, pero puedes tener múltiples ubicaciones de facts (por ejemplo, puedes tener uno o más en NFS).
  • factdest ($vardir/facts): Donde Puppet debe almacenar facts que obtiene del servidor central.
  • factsource (puppet://$server/facts): Desde dónde obtener facts. El tipo estándar de archivo de Puppet es usado, con lo cual, aquí puede ser usada cualquier fuente de archivos válida.
  • factsync (false): Maneja si los facts deben ser sincronizados con el servidor central o no.
  • factsignore (.svn CVS): Qué facts ignorar cuando se obtienen facts

Recuerda que el enfoque descrito antes para factsync ahora es obsoleto y fue remplazado por el enfoque de plugins descrito en la página de Plugins en módulos.

Facts externos

Los facts externos están disponibles sólo en Facter 1.7 y versiones superiores

Qué son los facts externos?

Los facts externos proveen una manera de utilizar archivos ejecutables arbitrarios o scripts como facts, o establecer facts de forma estática con información estructurada. Si alguna vez quisiste escribir un fact customizado en Perl, C, o un archivo de texto de una línea, así es cómo se hace.

Ubicación de facts

En Unix/Linux:

/etc/facter/facts.d/ # Puppet Open Source
/etc/puppetlab/facter/facts.d/ # Puppet Enterprise

En Windows 2003:

C:\Documents and Settings\All Users\Application Data\Puppetlabs\facter\facts.d\

En Windows 2008:

C:\ProgramData\Puppetlabs\facter\facts.d\

Facts ejecutables – Unix

Los facts ejecutables en Unix funcionan colocando un archivo ejecutable en la ruta de facts externos mencionada más arriba.

Debes asegurarte que el script tenga el bit de ejecución seteado:

chmod +x /etc/facter/facts.d/my_fact_script.rb

Para que Facter pueda parsear la salida, el script debe devolver pares clave/valor en STDOUT, en el siguiente formato:

key1=value1
key2=value2
key3=value3

Utilizando este formato, un script único puede devolver múltiples facts.

Facts ejecutables – Windows

Los facts ejecutables en Windows funcionan colocando un archivo ejecutable en la ruta de facts externos para tu versión de Windows. A diferencia de Unix, la interface de facts externos espera que los scripts de Windows terminen con una extensión conocida. Al momento, las siguientes extensiones son compatibles:

  • .com y exe: ejecutables binarios
  • .bat: scripts batch
  • .ps1: scripts PowerShell

Como sucede con los facts de Unix, cada script debe devolver pares clave/valor en STDOUT, en el siguiente formato:

key1=value1
key2=value2
key3=value3

Utilizando este formato, un scrpt único puede devolver facts múltiples de una vez.

Permitir Scripts de PowerShell

Para que funcionen los scripts de PowerShell (scripts con extensión ps1), tienes que asegurarte que tengan las políticas de ejecución correctas.

Mira este artículo de Microsoft TechNet para más detalles acerca del impacto de cambiar las políticas de ejecución. Recomendamos entender cualquier implicancia de seguridad antes de realizar un cambio global de política de ejecución.

El mecanismo más simple y seguro que encontramos es cambiar la política de ejecución para que sólo aquellos scripts bajados de forma remota necesiten ser firmados. Puedes establecer esta política con:

Set-ExecutionPolicy RemoteSigned -Scope LocalMachine

Aquí, un ejemplo de script de PowerShell que devuelve facts utilizando el formato requerido:

Write-Host "key1=val1"
Write-Host "key2=val2"
Write-Host "key3=val3"

Deberías poder salvar y ejecutar este script PowerShell en la línea de comandos luego de cambiar la política de ejecución.

Facts de información estructurada

Facter puede parsear archivos de información estructurada almacenados en el directorio de facts externos y establecer facts basados en sus contenidos.

Los archivos de información estructurada deben utilizar uno de los tipos de información compatible y debe tener una extensión de archivo correcta. Al momento, Facter es compatible con las siguientes extensiones y tipos de información:

.yaml: Información YAML, en este formato:

---
key1: val1
key2: val2
key3: val3

.json: Información JSON, en este formato:

  {
      "key1": "val1",
      "key2": "val2",
      "key3": "val3"
  }

.txt: Pares clave/valor, en este formato:

  key1=value1
  key2=value2
  key3=value3

Como con los facts ejecutables, los archivos de información estructurada pueden establecer facts múltiples en simultáneo.

Identificación y solución de fallas (troubleshooting)

Si tu fact externo no aparece en la salida de Facter, ejecutar Facter en modo debug debería darte una razón significativa y decirte qué fact está causando el problema:

# facter --debug

Un ejemplo podría ser en los casos en que un fact devuelve caracteres inválidos. Digamos que has utilizado un signo guión (-) en lugar del signo igual (=) en tu script test.sh:

#!/bin/bash
echo "key1-value1"

Ejecutar facter --debug debería producir un mensaje de error útil:

...
Fact file /etc/facter/facter.d/sample.txt was parsed but returned an empty data set
...

Si estás interesado en averiguar dónde están los cuellos de botella, puedes ejecutar Facter en modo timing y te dirá cuánto tiempo tomará parsear tus facts externos:

facter --timing

La salida debe verse similar al timing de los facts Ruby, pero nombrará los facts externos con sus rutas completas. Por ejemplo:

$ facter --timing
kernel: 14.81ms
/usr/lib/facter/ext/abc.sh: 48.72ms
/usr/lib/facter/ext/foo.sh: 32.69ms
/usr/lib/facter/ext/full.json: 104.71ms
/usr/lib/facter/ext/sample.txt: 0.65ms
....

Facts externos y stdlib

Si encuentras que un fact externo no coincide con lo que has configurado en el directorio facter.d, asegúrate de que no has definido los mismos facts usando las capacidades de facts externos halladas en el módulo stdlib.

Desventajas

Si bien los facts externos proveen una forma mayormente similar para crear variables para Puppet, éstas tienen algunas desventajas:

  • Un fact externo no puede referirse internamente a otro fact. Sin embargo, debido al orden de parseo, puedes referirte a un fact externo desde un fact Ruby.
  • Los facts externos ejecutables son forkeados en lugar de ser ejecutados dentro del mismo proceso.
  • Aunque planeamos permitir la distribución de facts externos a través de la capacidad de pluginsync de Puppet, esto todavía no está disponible.