2/2: Introducción al uso de Puppet

2007-07-10 por Angel Abad, etiquetado como debian, monitorizacion, servidor

Artículo traducido de: http://www.debian-administration.org/articles/528

En nuestra anterior introducción a Puppet vimos como instalar el cliente y el servidor, también como configurar una pequeña red. Aquí demostraremos algunas de las cosas que podemos hacer con esa instalación.

En nuestra anterior introducción a la instalación de Puppet vimos un fichero manifest muy simple, llamado site.pp. Este es el fichero de configuración principal puesto por Puppet en cualquier host controlado y es usado para especificar que acciones llevar a cabo. (¿Qué es un fichero manifest? Es una lista de instrucciones a llevar a cabo en un lenguaje simple, por eso no se llama script o programa).

Algunas de las acciones que podemos llevar a cabo con Puppet son:

  • Instalar / Desinstalar / Actualizar paquetes Debian.
  • Copiar ficheros desde el servidor central.
  • Aplicar cambios de configuración.

La última vez vimos el siguiente fichero manifest (guardado en /etc/puppet/manifest/site.pp):

# control de permisos en sudo
class sudo {
  file { "/etc/sudoers":
    owner => root,
    group => root,
    mode => 440,
  }
}

node default {
  include sudo
}

En este ejemplo podemos ver las siguientes cosas:

  • Definición de clase simple con "class sudo ..".
  • El uso del objeto "file".
  • Definición de acciones a llevar a cabo en todos los hosts.

Podemos pasar por alto la definición de class, es fácilmente comprensible en la documentación de Puppet, pero la seccion file merece que la mencionemos.

El tipo file es uno de los tipos que Puppet entiende, en un sentido parecido a como CFEngine entiene el uso de las secciones copy:. Nos permite hacer cosas como:

  • Copiar ficheros desde el servidor central de Puppet.
  • Modificar permisos de arhcivos existentes.
  • Modificar el usuario y grupo de archivos existentes.

(La Puppet type reference muestra más tipos con ejemplos de muchos de ellos.)

Copiando ficheros

Se pueden copiar ficheros desde el servidor maestro con tipo file que hemos visto. Hacer una copia es muy similar a la modificación de permisos que vimos en el ejemplo anterior. Todo lo que tenemos que hacer es incluir la fuente del fichero, que debe estar en algún sitio de nuestro servidor maestro.

Anteriormente activamos el servidor Puppet, corriendo sobre el host vain.my.flat, para servir ficheros a los clientes desde el directorio /etc/puppet/files, así que continuaremos trabajando con este directorio.

Asumiendo que queremos que todos los hosts de la LAN reciban una copia de /etc/sudoers desde nuestro servidor central, escribiremos lo siguiente en /etc/puppet/manifest/site.pp:

#
# Copia de /etc/sudoers desde el servidor maestro
#
class sudo {
  file { "/etc/sudoers":
    owner => root,
    group => root,
    mode => 440,
    source => "puppet://vain.my.flat/files/etc/sudoers"
  }
}

node default {
  include sudo
}

Ahora sólo necesitamos colocar el fichero en el lugar correcto en el servidor maestro:

root@vain:~# mkdir -p /etc/puppet/files/etc/
root@vain:~# cp /etc/sudoers /etc/puppet/files/etc/

Esto asegurará que que el fichero sudoers estará disponible para compartir y puede ser instalado sobre todas las máquinas.

Si quiere ejecutar una acción después de copiar el fichero, pero sólo si este ha sido modificado, puede hacer algo como esto:

class aptsetup {
  file { "/etc/apt/sources.list":
    owner => root, group => root, mode => 644
    source => "puppet://puppet/files/etc/apt/sources.list.etch"
  }

  exec { subscribe-echo:
    command   => "/usr/bin/apt-get -q -q update",
    logoutput   => false,
    refreshonly => true,
    subscribe   => file["/etc/apt/sources.list"]
  }
}

Ahora con sólo poner "include aptsetup" en la definición de nuestro(s) nodo(s) recibirá una copia del fichero sources.list desde el servidor. Si éste fichero ha sido actualizado en el servidor, el host recibirá la copia nueva y automáticamente ejecutará "apt-get update".

Incluyendo clases

Como hemos visto hastat ahora todo se incluia en el fichero site.pp. De esta forma enseguida se volverá inmanejable, así que es recomendable dividir tu configuración en pequeños ficheros de clases.

Un site.pp podría ser como esta:

import "classes/*.pp"

node default {
  include sudoers
  include aptsetup
}

Ahora podemos crear los ficheros "/etc/puppet/manifest/classes/sudo.pp" y "/etc/puppet/manifest/classes/aptsetup.pp" con el contenido que vimos antes.

Definiendo los nodos

Algo aparente en nuestro ejemplo es que no hemos dividido la configuración para poder manjear situaciones más complicadas, como controlar cada host por separado. De momento sólo hemos visto el uso de "node defatul" que significa que las acciones serán llevadas a cabo en todos los hosts que usan este servidor.

Aqui tenemos un ejemplo mas complicado para el control de dos máquinas (etch-builder.my.flat and sid-builder.my.flat).

Cada máquina obitiene un sources.list apropiado para ella, y algunas cosas comunes son aplicadas a las dos maquinas. Y todas las demas máquinas se configuran sin nombre:

class sudo {
  file { "/etc/sudoers":
    owner  => root,
    group  => root,
    mode   => 440,
    source => "puppet://vain.my.flat/files/etc/sudoers"
  }
}

class common {
  # Remove upstream sources.list
  # We manage this in sources.list.d per distro
  tidy { "/etc/apt/sources.list":
    age => '0s',
  }
}

class etch {
  file{ "/etc/apt/sources.list.d/etch.list":
    mode   => 644,
    source => "puppet://vain.my.flat/files/etc/apt/sources.etch"
  }
}

class sid {
  file{ "/etc/apt/sources.list.d/sid.list":
    mode   => 644,
    source => "puppet://vain.my.flat/files/etc/apt/sources.sid"
  }
}

node default {
  # all host get these actions
  include sudo
}

node etch-builder inherits default {
  include common
  include etch
}
node sid-builder inherits default {
  include common
  include sid
}

Haciendo Puppet más parecido a CFEngine

Algunas acciones muy familiares para la gente de CFEngine no están presentes, como por ejemplo, DeleteLinesMatching y AppendIfNoSuchLine, que nos permiten una manipulación simple de ficheros de texto.

Gracias esta página del wiki de Puppet podremos encontrar soluciones simples para la mayoría de los casos.

Creamos el fichero /etc/puppet/manifests/classes/cfengine.pp con el siguiente contenido:

define append_if_no_such_line($file, $line, $refreshonly = 'false') {
  exec { "/bin/echo '$line' >> '$file'":
    unless      => "/bin/grep -Fxqe '$line' '$file'",
    path        => "/bin",
    refreshonly => $refreshonly,
  }
}

define delete_lines($file, $pattern) {
  exec { "sed -i -r -e '/$pattern/d' $file":
    path   => "/bin",
    onlyif => "/bin/grep -E '$pattern' '$file'",
  }
}

Ahora en su site.pp puede hacer lo siguiente:

import "classes/*.pp"

node default {
  delete_lines{ removecfengine:
    file    => "/etc/motd",
    pattern => "^.*CFEngine.*$" }

  append_if_no_such_line{ motd:
    file => "/etc/motd",
    line => "Configured with Puppet!"}
}

Cerramos la segunda parte de esta introducción a Puppet aquí, sólo hemos visto el principio de lo que Puppet puede hacer, así que si está interesado en aprender más le aconsejo que eche un vistazo en la documentación del wiki de Puppet.

El canal IRC es amigable y buen sitio para recibir ayuda!