Monitoreos en Nagios vía SNMP

Al utilizar Nagios para el monitoreo de nuestros servidores, los plugins que vienen por defecto trabajan en base al chequeo de un recurso mediante umbrales de valores para alertar.

Por ejemplo, si vamos a monitorear la memoria ram, no nos interesa el valor máximo que esta tiene, lo que si nos interesa es que nos alerte cuando estemos ocupando cerca del 90% ó 100% de la misma (umbrales). Pero hay casos en que igual necesitamos los valores de la memoria ram Ej: ram libre, ram usada, ram total. Para el caso podemos decirle a Nagios que nos muestre la información de un recurso mediante protocolo SNMP que puede ser trabajado con el plugins check_snmp. Para realizar esto, tenemos que realizar lo siguiente:

Configurar SNMP en el servidor a monitorear.

  • Instalamos los paquetes SNMP en el hosts

    1
    2
    
    [root@node1]$ yum install net-snmp -y
    [root@node1]$ vim /etc/snmp/snmpd.conf
    

  • Configuramos la comunidad en nuestro snmpd.conf
  • 1
    
    rocommunity public 10.10.0.0/24
    

    La ip corresponde a la red de los equipos, podemos ser mas restrictivos y colocar solo la dirección del servidor Nagios.

  • Finalmente subimos el servicio
  • 1
    
    [root@node1]$ service snmpd start && chkconfig snmpd on
    

    Configurando Nagios Server

    En este punto nos aseguramos de tener todo operativo respecto al servidor Nagios, los chequeos serán realizados desde el servidor Nagios hacia los Nagios client, con el comando check_snmp.

  • Definiendo nuevos comandos
  • Los comandos a utilizar no vienen por defecto en la plantilla commands.cfg por lo cual vamos a proceder a crearlos, adicionando los siguientes valores: memoria ram total, memoria ram libre, memoria ram usada

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    
    define command{
            command_name    snmp_RamSize
            command_line    $USER1$/check_snmp -o .1.3.6.1.4.1.2021.4.5.0 -H $HOSTADDRESS$ $ARG1$
    }
    
    define command{
            command_name    snmp_RamFree
            command_line    $USER1$/check_snmp -o .1.3.6.1.4.1.2021.4.11.0 -H $HOSTADDRESS$ $ARG1$
    }
    
    define command{
            command_name    snmp_RamUsed
            command_line    $USER1$/check_snmp -o .1.3.6.1.4.1.2021.4.6.0 -H $HOSTADDRESS$ $ARG1$
    }
    

    De lo anterior, la númeración .1.3.6.1.4.1.2021.4.6.0 representa el OIDs canal identificador de lo que vamos a monitorear. Dependiendo de lo que se desea monitorear es el OIDs respectivo, la lista de estos identificadores es larga y la puedes ver acá. Por ejemplo para la memoria ram/swap tenemos los siguientes registros.

    1
    2
    3
    4
    5
    6
    7
    8
    
    Total Swap Size: .1.3.6.1.4.1.2021.4.3.0
    Available Swap Space: .1.3.6.1.4.1.2021.4.4.0
    Total RAM in machine: .1.3.6.1.4.1.2021.4.5.0
    Total RAM used: .1.3.6.1.4.1.2021.4.6.0
    Total RAM Free: .1.3.6.1.4.1.2021.4.11.0
    Total RAM Shared: .1.3.6.1.4.1.2021.4.13.0
    Total RAM Buffered: .1.3.6.1.4.1.2021.4.14.0
    Total Cached Memory: .1.3.6.1.4.1.2021.4.15.0
    

  • Ahora, vamos a configurar nuestros chequeos dentro del archivo de cada hosts
  • 1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    27
    28
    29
    30
    31
    32
    
    define host {
      contact_groups                 vagrant-vm
      host_name                      node1.example.com
      hostgroups                     vagrant-vm
      alias                          node1
      address                        10.10.0.102
      use                            linux-server
    }
    
    define service{
      contact_groups                 vagrant-vm
            use                     generic-service
            host_name               node1.example.com
            service_description     RAM Size
            check_command           snmp_RamSize!-C public
    }
    
    define service{
      contact_groups                 vagrant-vm
            use                     generic-service
            host_name               node1.example.com
            service_description     RAM Free
            check_command           snmp_RamFree!-C public
    }
    
    define service{
            contact_groups                 vagrant-vm
            use                     generic-service
            host_name               node1.example.com
            service_description     RAM Used
            check_command           snmp_RamUsed!-C public
    }
    

    Acá, por cada chequeo que realizamos utilizamos nuestro comando respectivo (que monitorea vía snmp) y la comunidad del nuestro nodo.

  • Finalmente reiniciamos nuestro servidor nagios
  • 1
    
    [root@nagios servers]$ /etc/init.d/nagios restart
    

    Nos conectamos al webadmin del servidor Nagios para ver el estado de los servicios

    Referencias:

    Tip Docker: Transferir un contenedor con SSH

    Asi como van las cosas, parece que vamos a cambiar de nombre a IT Docker :).

    Por ahora les dejamos un tip de como copiar un contenedor de un host a otro utilizando ssh y con el estado en tiempo real de la transmisión. El comando que se sigue se ejecutó en OS X utilizando dos máquinas virtuales Vagrant:

    1
    
    docker save itlinux/carter-logstash | pv | ssh servidor 'DOCKER_HOST=tcp://192.168.59.103:2375 docker load'
    

    Vamos por parte:

    • docker save itlinux/carter-logstash, guarda la imagen, en este caso la “tira” a la salida estándar: la consola,
    • | pv, recibe los datos de la imagen en tiempo real y los muestra por pantalla,
    • | ssh servidor 'DOCKER_HOST=tcp://192.168.59.103:2375 docker load', envío por SSH la imagen que está siendo exportada por el primer paso al equipo servidor donde ejecuto docker load para que la importe.

    En mi caso esto resulta en lo siguiente:

    Automatizando pruebas de stress con JMeter y Ruby

    Una excelente forma de validar nuestras aplicaciones y sitios web consiste en someterlos a pruebas de carga para comprobar como se comportarán una vez que vean la luz de Internet.

    JMeter es una de las mejores herramientas Open Source para realizar pruebas de carga. Además de HTTP soporta protocolos como POP3, IMAP, FTP, etc. y también permite programar lo que llama Planes de Prueba que consisten en guíones de ejecución para las pruebas de stress.

    Con todo el poder y opciones que ofrece JMeter, también viene toda la dificultad de escribir los Planes de Prueba y también el hecho de que como desarrolladores o administradores preferimos la calidez de la consola que la frialdad de una GUI Java. Aquí es donde entra Ruby, y específicamente ruby-jmeter.

    ruby-jmeter es una gem que permite escribir planes de JMeter usando una DSL de Ruby y también nos deja ejecutar estos planes desde la línea de comandos sin necesidad de utilizar interfaz gráfica.

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    
    require 'ruby-jmeter'
    
    test do
      threads count: 60 do
        visit name: "google_search", url: "http://www.google.com/"
      end
    end.run(
      path: '/opt/jmeter/bin/',
      file: 'jmeter.jmx',
      log: 'jmeter.log',
      jtl: 'results.jtl',
      properties: 'jmeter.properties'
      )
    

    Del script anterior destacamos:

    • línea 4: cuantos usuarios queremos simular
    • línea 5: Un tag y la página a visitar
    • línea 8: El path donde está el ejecutable de JMeter
    • línea 11: El archivo con los resultados de las pruebas
    • línea 12: La configuración de JMeter, ajustado para que guarde el resultado en CVS y use como delimitador ,

    Un extracto del resultado del test, del archivo results.jtl, sería como sigue:

    1
    2
    3
    4
    5
    
    1411639664180,348,google_search,200,OK,ThreadGroup 1-3,text,true,129298,343
    1411639664525,327,google_search,200,OK,ThreadGroup 1-4,text,true,129298,320
    1411639665071,266,google_search,200,OK,ThreadGroup 1-5,text,true,129298,262
    1411639664335,353,google_search,200,OK,ThreadGroup 1-4,text,true,129298,320
    1411639665071,266,google_search,200,OK,ThreadGroup 1-5,text,true,129298,262
    

    El beneficio de poder programar las pruebas de stress con Ruby, o con otro lenguaje, es que estás se pueden automatizar y por ejemplo incluirlas en el proceso de liberación de las aplicaciones usando un sistema de integración continua.

    Otro beneficio es que al estar automatizadas, las pruebas si se harán, porque reconozcamos que a veces es una lata.

    En un próximo artículo revisaremos como extraer e interpretar la información del archivo results.jtl, creando resúmenes y gráficas.

    Shellshock: Grave vulnerabilidad en Bash afecta a Linux y otros *nixes

    El 24 de Septiembre de 2014 se dio a conocer una importante vulnerabilidad en Bash. Esta vulnerabilidad, llamada “Shellshock” y con los identificadores CVE-2014-6271 y CVE-2014-7169, permite ejecución remota de código.

    Lo que primero comenzó como una vulnerabilidad de ejecución local, se ha extendido y ahora existen formas de ejecutarla de forma remota. Recomendamos a todos que actualicen sus sistemas tan pronto sea posible.

    Existe una forma fácil de comprobar si tus sistemas son vulnerables. En una consola escribe lo siguiente:

    1
    
    env x='() { :;}; echo vulnerable' bash -c "echo es una prueba"
    

    Si tu sistema es vulnerable, la salida será:

    1
    2
    
    vulnerable
     this is a test
    

    A continuación dejamos un listado de enlaces donde podrás encontrar información específica a cada distribución:

    Si quieres saber como opera este bug te recomendamos el siguiente artículo de Ars Technica

    Debugueando un Cluster de Zimbra Collaboration

    A continuación los dejo con un cuento de como en IT Linux realizamos el arte llamado Resolución de Problemas, o Troubleshooting para los snobs, usando como ejemplo la historia de un cluster porfiado de Zimbra Collaboration.

    Algunos datos importantes de esta historia:

    • El software de cluster usado en Red Hat Cluster Suite
    • El sistema operativo RHEL 6
    • La versión 7 de Zimbra
    • Sistema en producción hace 4 años
    • Errores recién se presentaron este año y de forma muy aliatoria
    • Este trabajo realizó la única re-configuración que el cluster ha tenido en su historia

    Ahora los dejo con la historia.

    Utilizando Vagrant para hacer pruebas de Provisioning

    Una buena práctica a la hora de trabajar con Vagrant es que nos permite hacer lo que se demomina provisioning hacia nuestras máquinas virtuales una vez que las vallamos creando, configurar nuestros ambientes de esta forma nos da 2 ventajas importantes:

    1. Automatizar las configuraciones e instalación de software que tendrán cada uno de estos ambientes virtuales
    2. Evitar repetir las mismas tareas una y otra vez por cada ambiente virtual

    Por supuesto que si trabajar con provisioning no nos llama la atención nos podemos conectar hacia la máquina virtual mediante vagrant sshe instalar y configurar todo a mano. Pero hay que tener en claro que una de las gracias de estas herramientas y metodologías de trabajo es crear un ambiente de virtualziación en el menor tiempo posible, destruirlo (si fuera necesario) y volver a crearlo con solo un par de minutos. Vagrant nos permite trabajar con multiples opciones de provisioning, desde un simple script shell o herramientas mas avanzadas para la administración de systemas: Ansible, Chef, Puppet, dependiendo de nuestra abilidades y experiencias tomaremos el camino hacia una u otra opción.

    Para el caso del presente post vamos a realizar nuestro provisioning con Puppet. Bajo la combinación de estas dos herramientas tenemos dos opciones de trabajo

  • Mediante Puppet Apply
  • Nuestro manifiesto es declarado localmente en nuestro “ambiente” de virtualización en Vagrant y la máquina virtual leerá ese manifiesto para realizar lo declarado en el (no tenemos que tener un servidor Puppet Master).
  • Mediante Agent
  • Nos conectamos hacia un servidor Puppet para cargar nuestro manifiesto.

    Manos a la obra y veamos como funciona el Provisioning de Vagrant + Puppet

    Creamos nuestro path de trabajo

    1
    2
    3
    
    Miguel:VagrantVM$ mkdir Apache #Directorio donde alojaremos nuestra máquina virtual
    Miguel:Apache$ mkdir manifests #Directorio donde alojaremos nuestros manifiestos
    Miguel:Apache$ touch manifests/site.pp #Manifiesto para nuestra máquina virtual
    

    La máquina virtual que vamos a crear tiene que será un Centos 6 que viene el el agente Puppet pre-instalado en el. Para eso agregamos el siguiente box de Vagrant que utilizaremos como fuente de instalación base.

    1
    2
    
    Miguel:Apache$ vagrant box add  Centos6Puppet http://developer.nrel.gov/downloads/vagrant-boxes/CentOS-6.4-x86_64-v20131103.box
    ==> box: Successfully added box 'Centos6Puppet' (v0) for 'virtualbox'!
    

    Luego inicializamos nuesta nueva máquina virtual

    1
    2
    3
    
    Miguel:Apache$ vagrant init Centos6Puppet
    A `Vagrantfile` has been placed in this directory. You are now
    ready to `vagrant up` ....... for more information on using Vagrant.
    

    Ahora ya tenemos nuestro archivo de configuración Vagrantfile creado por defecto por Vagrant para nuestra nueva máquina virtual. Ahora, lo vamos a editar y agregar el apartado para configurar nuestro provisioning.

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    
    # -*- mode: ruby -*-
    # vi: set ft=ruby :
    
    # Vagrantfile API/syntax version. Don't touch unless you know what you're doing!
    VAGRANTFILE_API_VERSION = "2"
    
    Vagrant.configure(VAGRANTFILE_API_VERSION) do |config|
    >
    # VM setup 
       config.vm.define :www do |config|
          config.vm.box = "Centos6Puppet"
          config.vm.hostname  = "www.example.com"
      config.vm.network :public_network,  bridge: 'en1: Wi-Fi (AirPort)', ip: "192.168.1.37"
    # VBox setup
          config.vm.provider "virtualbox" do |vboxconfig|
            vboxconfig.name = "www.example.com"
          end
    # Puppet Provisioner setup
        config.vm.provision "puppet" do |puppetconfig|
            puppetconfig.manifests_path = "manifests"
            puppetconfig.manifest_file = "base.pp"
        end
     end
    
    end
    

    Entre las líneas nº 18 y nº 23 tenemos toda nuestra declaración de Puppet provisioner, todas las opciones a configurar con Puppet son variadas y las puedes ver en detalle acá, para nuestro caso solo utilizamos manifests_path donde se define la ruta que contendrá nuestros archivos de maniesto y manifest_file que es donde le pasamos el nombre de nuestro manifiesto. Nuestro manifiesto es sencillo y esta creado solo con la finalidad de entender el funcionamiento del provisioner, nuestro manifiesto puppet lo que hace es;

    1. Instalar el paquete Apache
    2. Subir el servicio
    3. Crear un index.html (que sacará desde nuestro equipo local)
    4. Crear una regla en el firewall para permitir el acceso al puerto 80

    El contenido de nuestro manifiesto base.pp es el siguiente

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    
    package {"httpd":
      ensure => present,
      notify => Service["httpd"], 
    }
    
    service {"httpd":
      ensure    => running,
      enable    => true,
      hasstatus => true,
          require   => Package["httpd"],
    }
    
    file {"apache-index":
            ensure  => present,
            require => Package['httpd'],
          path    => '/var/www/html/index.html',
            source  => "/vagrant/index.html",
      notify  => Service["httpd"],
    }
    
    exec {"firewall-rule-80":
            path    =>  "/bin/:/sbin/:/usr/bin/:/usr/sbin/",
      command => "iptables -I INPUT -p tcp --dport 80 -j ACCEPT",
    }
    

    Creamos nuestro index.html, esto tiene estar a la misma altura de nuestro Vagrantfile

    1
    2
    3
    4
    5
    6
    7
    8
    
    Miguel:Apache$ tree
    .
    ├── Vagrantfile
    ├── index.html
    └── manifests
        └── base.pp
    
    1 directory, 3 files
    

    Con todo lo anterior estamos listos para arrancar nuestra máquina virtual configurada con Puppet provisioner.

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    27
    28
    29
    30
    31
    
    Miguel:Apache$ vagrant up www --provision
    Bringing machine 'www' up with 'virtualbox' provider...
    ==> www: Clearing any previously set forwarded ports...
    ==> www: Clearing any previously set network interfaces...
    ==> www: Preparing network interfaces based on configuration...
        www: Adapter 1: nat
        www: Adapter 2: bridged
    ==> www: Forwarding ports...
        www: 22 => 2222 (adapter 1)
    ==> www: Booting VM...
    ==> www: Waiting for machine to boot. This may take a few minutes...
        www: SSH address: 127.0.0.1:2222
        www: SSH username: vagrant
        www: SSH auth method: private key
        www: Warning: Connection timeout. Retrying...
        www: Warning: Remote connection disconnect. Retrying...
    ==> www: Machine booted and ready!
    ==> www: Checking for guest additions in VM...
    ==> www: Setting hostname...
    ==> www: Configuring and enabling network interfaces...
    ==> www: Mounting shared folders...
        www: /vagrant => /Users/Miguel/VagrantVM/Apache
        www: /tmp/vagrant-puppet-2/manifests => /Users/Miguel/VagrantVM/Apache/manifests
    ==> www: Running provisioner: puppet...
    ==> www: Running Puppet with base.pp...
    ==> www: Notice: Compiled catalog for www.example.com in environment production in 0.56 seconds
    ==> www: Notice: /Stage[main]//Exec[firewall-rule-80]/returns: executed successfully
    ==> www: Notice: /Stage[main]//Package[httpd]/ensure: created
    ==> www: Notice: /Stage[main]//File[apache-index]/ensure: defined content as '{md5}0f25e63c5ca1dbb91163ad16c3ee4bde'
    ==> www: Notice: /Stage[main]//Service[httpd]/ensure: ensure changed 'stopped' to 'running'
    ==> www: Notice: Finished catalog run in 12.06 seconds
    

    Desde las líneas nº24 hasta 31 Vagrant ejecutó todo nuestro provisioner, el cual realizó todo lo declarado en nuestro manifiesto base.pp. Desde ahora no necesitarás realizar siempre las mismas tareas ya que nuestro manifiesto puede ser reutilizado en diversas máquinas virtuales que tengamos creadas o vallamos creando en un futuro.

    Encontrar las mejores herramientas para DevOps

    Para alcanzar la velocidad y agilidad ofrecida por DevOps - ¿Qué es DevOps? - necesitas elegir las herramientas correctas con las cuales podrás automatizar todas las tareas de desarrollo, producción y operación. De acuerdo al estudio realizado el 2013 por PuppetLabs, más del 80% de las organizaciones de alto desempeño que usan tecnología en aspectos claves de su negocio confían en herramientas de automatización para el manejo de su plataforma y pasos a producción de sus sistemas. Según esto, es probable que ya tengas muchas de las herramientas usadas en ambientes DevOps, ¿pero son las herramientas correctas para tu empresa?

    Toma un acercamiento estratégico

    No existe una única forma de seleccionar las herramientas correctas para tus necesidades. Los requerimientos de tu industria, departamento de TI, sistemas legados y flujos de trabajos son únicos a tu empresa. Y también es la manera para elegir las herramientas que usarán para maximizar los beneficios de DevOps.

    La clave es crear una estrategia centrada en lo que es importante para tu empresa. Si tu objetivo es la colaboración, las herramientas correctas pueden alentar a tu equipo a hacer las cosas correctamente. En un breve tiempo se darán cuenta de que el esfuerzo puesto al principio aprendiendo a utilizar nuevas herramientas, se verá recompenzado a no tener que lidiar con trabajo tedioso como puede ser la habilitación de ambientes de prueba y la revisión de código o configuraciones de servidores.

    Identificar los cuello de botella

    El primer paso es identificar los cuello de botella de tus flujo de trabajo que impiden que tu empresa pueda contar con una plataforma más estable y usar la tecnología más fácilmente para apoyar a al negocio.

    Hay dos caminos para identificar estos cuellos de botella. Primero: Pregunta! Pregunta a tu equipo en que parte las cosas se ponen lentas o problemáticas. Pídeles que generen un ranking según la severidad de estos cuellos de botella, y que identifiquen los que afectan a sistemas críticos.

    Pero esto no es todo. También deberás analizar los logs de tus sistemas. Aprender que tareas y servicios son usados más y tienen un peor desempeño, que sistemas son los más inestables, y suma y sigue. Esto te dará evidencia dura de que está funcionando bien en tu plataforma y empresa, donde esta peor, y que es lo que está fallando.

    Combina estos dos métodos para categorizar y comenzar la búsqueda de las herramientas que necesitan.

    Enfócate en categorías claves

    Las empresas más exitosas en implementar DevOps automatizan sólo utilizando herramientas en una pocas categorías claves, como por ejemplo:

    Administración de configuraciones. Cuando los aficionados de DevOps hablan de cosas como “automatización de infraestructura”, “infrastructura como código” e “infrastructura programable”, ellos se refieren a la administración de configuraciones. Esto es la mantención y el seguimiento de forma centralizada de cambios en la configuración de los sistemas y softwares, lo que permite realizar operaciones rápidamente y de forma segura sobre la plataforma. Las herramientas más conocidas en este ámbito son Ansible, CFEngine, Chef, Puppet y SaltStack. La real pregunta es que necesitan ustedes de un sistema de configuración? Por ejemplo usando Puppet puedes tener de forma inmediata un inventario de tu plataforma, mientras que está está trabajando como debe.

    Paso a Producción. Las herramientas para hacer deploys permiten que el paso a producción de sistemas, lo que es el corazón de continuous delivery, uno de los principales objetivos de DevOps. Capistrano, una librería de deploy, es la herramienta más popular en esta categoría. Otras herramientas importantes para automatizar los pasos a producción son Ansible, Fabric, y Jenkins. Nuevamente, lo importante es encontrar una herramienta que haga el seguimiento del historial de los sistemas y que esta información sea significativa para tu equipo.

    Monitoreo. En DevOps se requieren dos tipos de monitoreo. El primero tiene que ver con la disponibilidad de los servicios, y aquí Nagios es la herramienta más conocida, aunque [Sensu][http://sensuapp.org] está ganando terreno rápidamente. El otro tipo de monitoreo es sobre el desempeño de aplicaciones y dispositivos (CPU, Memoria, Disco, etc.), en este campo la recolección de estadísticas está gobernada por herramientas como statsd y collectd, mientras que para la visualización recomendamos sin lugar a dudas Grafana.

    Análisis de Logs. Si hay un espacio importante en nuestra actividad que ha sido dejado de lado por años, este es el análisis de los logs de nuestros sistemas y aplicaciones. Es en los logs donde encontramos la verdad de la salud de nuestra plataforma. Para la recoleción y transformación de logs en datos analisables la herramienta que se impone es Logstash la cual viene hoy con una consola gráfica de análisis excelente como es Kibana.

    Pruebas de configuraciones. Otro ámbito importante y que no es muy usual ver que se aplique es la automatización de pruebas de los servicios que dan nuestras plataformas TI. Por ejemplo revisar que desde Internet sólo estén habilitados ciertos puertos, o que ninguno de los servidores permita el acceso del usuario root utilizando ssh. Hoy gracias a Serverspec es ridículamente sencillo escribir estos test y así estar seguro de que nuestras configuraciones están correctas.

    Contar con el conjunto correcto de herramientas DevOps automatizará los trabajos de TI, entregará visibilidad en tiempo real del desempeño de sistemas y dispositivos, y te dará la seguridad de contar con una única fuente de información verídica. Más importantes que las capacidades individuales de cada herramienta, es como en conjunto pueden te ayudan en lograr los objetivos de tu empresa.

    Puppet creando usuarios desde Hiera

    En una entrada anterior habíamos escrito sobre como crear usuarios mediante Puppet. Bueno, ahora lo que veremos es este mismo proceso pero ahora la data será importada desde Hiera y aplicada a los nodos.

    Definiendo nuesta arquitectura de búsqueda en Hiera

    En nuestro archivo hiera.yaml nosotros creamos una nueva jerarquía de que se llama users esto con dos finalidades; 1. Tener mas limpio nuestro common.yaml ya que si son muchos usuarios se empezará a distorcionar el archivo 2. Manejar en un solo archivo las configuracones de cuentas de usuario. Por lo anterior nuestro hiera.yaml queda así:

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    
    ---
    :backends:
      - yaml
    :yaml:
      :datadir: /etc/puppet/hieradata
    :hierarchy:
      - "osystem/%{::osfamily}"
      - "nodes/%{::fqdn}"
      - users
      - common
    

    Y creamos nuestro users.yaml

    1
    
    [root@master puppet]$ touch hieradata/users.yaml
    

    Con las configuraciones realziadas a nivel de Hiera, ahora tenemos que tener nuestra clase. Para este caso, la clase que utilizaremos es la misma que que utilizamos en el link que figura arriba salvo que ahora tiene unos pequeños cambios.

  • Archivo init.pp
  • 1
    2
    3
    4
    5
    6
    
    [root@master puppet]# cat modules/users/manifests/init.pp 
    class users (
      $users = hiera('users')
    ){
      create_resources(users::add_user, $users)
    }
    

    Aquí como vemos tenemos el parámetro create_resources que nos permite tomar los valores que vienen dentro de un “hash” y adicionar esos valores dentro del manifiesto. Para el caso, nuestro hash viene en hiera('users'), lo pasamos a la variable $users y luego a la sub clase users::add_user

  • Archivo add_user.pp
  • 1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    27
    28
    29
    30
    31
    32
    33
    34
    35
    36
    37
    38
    39
    40
    41
    
    define users::add_user (
      $uid    = '',
      $user   = '',
      $realname = '',
      $shell = '',
      $groups = []
    ){
    
    include 'users::add_group'
    
        user { $user:
                uid    => $uid,
                managehome  => true,
          comment  => $realname,
          shell    => $shell,
          groups => $groups,
        }
    
        file { "/home/$user/":
            ensure  => directory,
            owner   => $user,
            mode    => 700,
            require => User[$user]
        }
    
        file { "/home/$user/.ssh":
                ensure  => directory,
                owner   => $user,
                mode    => 700,
                require => File["/home/$user/"]
        }
    
        file { "/home/$user/.ssh/authorized_keys":
                    ensure  => present,
                    source  => "puppet:///modules/users/$user.key",
                    owner   => $user,
                    mode    => 0600,
                    require => File["/home/$user"]
            }
    
    }
    

    Como se ve al comienzo del manifiesto se tomam los valores del hash de hiera y luego son volcados en sus respectivas variables, en la línea nº9 tenemos un include include 'users::add_group' que llama a la clase add_group.

  • Archivo add_group.pp
  • 1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    
    [root@master manifests]$ cat add_group.pp
    class users::add_group {
      group {"itlinux":
                    ensure => present,
            }
       group {"admin":
                    ensure => present,
            }
       group {"conta":
                    ensure => present,
            }
    }
    

    Lo que realiza este manifiesto es la definición de los grupos que pertenecerán los usuarios (un usuario puede pertenecer a muchos grupos que tenemos que definirlos acá, de lo contrario Puppet arrojará que el grupo no existe)

  • Archivo hiera users.yaml
  • Acá se definen todos los valores con los que se creara el usuario

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    
    [root@master hieradata]$ cat users.yaml
    ---
    classes: [ 'users' ]
    
    users:
      mcoa:
         uid:  9001
         user: 'mcoa'
         realname: 'Miguel Coa'
         shell:  '/bin/bash'
         groups: [itlinux, admin, conta]
      linux:
         uid:  9002
         user: 'linux'
         realname: 'Linux Puppet'
         shell:  '/bin/bash'
         groups: [itlinux]
    

    Podemos ocupar el comando hiera para chequear la información de la clase users que tenemos definida

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    
    [root@master puppet]$ hiera users ::fqdn=master.itlinux.cl
    {"mcoa"=>
      {"uid"=>9001,
       "groups"=>["itlinux", "admin", "conta"],
       "shell"=>"/bin/bash",
       "user"=>"mcoa",
       "realname"=>"Miguel Coa"},
    {"linux"=>
      {"uid"=>9002,
       "groups"=>["itlinux"],
       "user"=>"linux",
       "realname"=>"Linux Puppet",
       "shell"=>"/bin/zsh"},
    

    Para que las clases sean aplicadas por Hiera a cada uno de los nodos estamos utilizando la función hiera_include

    1
    2
    3
    4
    5
    
    [root@master manifests]$ cat nodes.pp
    
    node 'master.itlinux.cl' {
        hiera_include( 'classes')
    }
    

    Finalmente conectamos el agente puppet al servidor para cargar las configuraciones del manifiesto

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    
    [root@master puppet]$ puppet agent --test
    Info: Retrieving pluginfacts
    Info: Retrieving plugin
    Info: Caching catalog for master.itlinux.cl
    Info: Applying configuration version '1401306968'
    Notice: /Stage[main]/Users/Users::Add_user[mcoa]/User[mcoa]/ensure: created
    Notice: /Stage[main]/Users/Users::Add_user[mcoa]/File[/home/mcoa/.ssh]/ensure: created
    Notice: /Stage[main]/Users/Users::Add_user[mcoa]/File[/home/mcoa/.ssh/authorized_keys]/ensure: defined content as '{md5}d3d6f1310e9c2909c74568eb145e06d9'
    Notice: Finished catalog run in 1.23 seconds
    [root@master puppet]$
    

    Comprobamos la configuración del usuario

    1
    2
    
    [root@master puppet]$ id mcoa
    uid=9002(mcoa) gid=9002(mcoa) groups=9002(mcoa),9502(itlinux),9503(admin),10000(conta)
    

    Puppet y la creación de módulos con Hiera

    Primero que todo ¿Qué es Hiera?

    De las palabras de la documentación de Puppet:

    Hiera es una herramienta para consultar información del tipo clave/valor, desarrollado para mejorar Puppet y permitir guardar sin duplicación datos específicos de los nodos.

    En palabras un poco más simple, Hiera; es un componente (así como facter) que nos permite generar un grado de abstracción y portabilidad mayor al momento de configurar nuestros módulos. Ya que en archivos en formatos “yaml, json, mysql y otros” de forma jeráquica podemos almacenar información que luego será llamada por el módulo y “cargada” al manifiesto.

    Un par de aclaraciones de Hiera

    Hiera viene de forma nativa en las versiones de Puppet 3, si trabajas con versiones más antiguas tendras que instalar el paquete de Hiera o realizar un upgrade de Puppet. La información referente a la configuración de Hiera se carga y lee de forma jerárquica desde el archivo /etc/puppet/hiera.yaml y el contenido que tiene el archivo es similar al siguiente:

    1
    2
    3
    4
    5
    6
    
    ---
    :backends: yaml
    :yaml:
      :datadir: /var/lib/hiera
    :hierarchy: common
    :logger: console
    

    Vamos por líneas

    1. :backends: Define que tipo de backends (ficheros) leerá Hiera, pudiendo ser yaml, json, mysql, etc.
    2. :yaml: Indica la ruta en donde almacenaremos nuestros backends.
    3. :hierarchy: Indica cual será la jerárquia por la que buscará las variables para los nodos, las variables que toma son los valores de facter ::osfamily, ::fqdn, ::hostname, etc. El valor common, es el archivo común para todas las configuraciones de uso general.
    4. :logger: Permite generar log y dubug al funcionamiento de hiera.

    Una vez configurado el fichero hiera.yaml, tenemos que hacer un lik simbólico hacia /etc

    1
    
    [root@master ~]# ln -s /etc/puppet/hiera.yaml /etc/
    

    Por cada cambio que realizamos en el archivo hiera.yaml tenemos que reiniciar el servicio puppet para que tome los nuevos valores. Con lo anterior, ya estamos en condiciones de empezar a utilizar Hiera e integrarlo con Puppet. Para mayor detalle de las configuraciones que se pueden realizar en dicho archivo puedes echar un vistazo a la documentación oficial.

    Empecemos con nuestro ejemplo

    Vamos a instalar Apache en dos servidores uno que corre en Ubuntu y otro que corre en Centos, en donde toda la definición de variables para el proceso de instalación será declarada en Hiera.

  • Configuración archivo Hiera /etc/puppet/hiera.yaml será el siguiente:
  • 1
    2
    3
    4
    5
    6
    7
    8
    9
    
    [root@master ~]$ cat /etc/hiera.yaml
    ---
    :backends:
      - yaml
    :hierarchy:
      - %{osfamily}
      - common
    :yaml:
      :datadir: /etc/puppet/hieradata/
    

    Creamos el directorio donde almacenaremos nuestros archivos yaml

    1
    
    [root@master ~]$ mkdir /etc/puppet/hieradata/
    

    En :hierarchy: definimos que nuestra jerárquia por la que se va a buscar las variables, para el caso será %{osfamily}, osea a nivel de facter preguntará si el sistema operativo pertenece a la familia de RedHat (RedHat,Centos, Fedora) o Debian (Ubuntu, Debian) y a partir de eso actuará, donde dependiendo del %{osfamily} irá a leer los archivos RedHat.yaml y Debian.yaml (que crearemos más adelante) y finalmente irá a leer el archivo common.yaml donde están definidas las configuraciones globales (si es que las hay).

    Por ejemplo, en la siguiente imagen es posible ver otra facts y su orden jerárquico

    Creamos los archivos Debian.yaml, RedHat.yaml y common.yaml.

    1
    2
    
    [root@master puppet]$ ls hieradata/
    common.yaml  Debian.yaml  RedHat.yaml
    

    Nota En el caso de trabajar con nodos de forma directa, tendríamos que cambiar nuestro fact en hierarchy a algo como :hierarchy: %{::fqdn} o :hierarchy: %{::clientcert} y crear el fichero yaml node.example.com.yaml

    El contenido de los archivos Debian.yaml y RedHat.yaml es el siguiente

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    
    [root@master puppet]$ cat hieradata/RedHat.yaml
    ---
    apache_package_name: "httpd"
    apache_name_service: "httpd"
    apache_owner_name: "apache"
    apache_name_group: "apache"
    apache_dir_name: "/var/www/html/index.html"
    [root@master puppet]$ cat hieradata/Debian.yaml
    ---
    apache_package_name: "apache2"
    apache_name_service: "apache2"
    apache_owner_name: "www-data"
    apache_name_group: "www-data"
    apache_dir_name: "/var/www/index.html"
    [root@master puppet]# 
    

    Como sabemos el nombre del paquete apache difiere entre Debian y RedHat, por lo tanto se declaran las respectivas variables (nombre, grupo, usuario y directorio). Para comprobar el funcionamiento de las configuraciones realizadas podemos utilizar la herramienta de línea de comando de Hiera. En el siguente caso comprobaremos el valor de la variable apache_package_name que nos devolverá el valor definido para el fact que consultamos.

    1
    2
    3
    4
    
    [root@master puppet]$ hiera -c hiera.yaml apache_package_name osfamily=RedHat
    httpd
    [root@master puppet]$ hiera -c hiera.yaml apache_package_name osfamily=Debian
    apache2
    

    Cambio de tarjetas de red en Endian Firewall

    ¿Recuperaste un respaldo de Endian en otra máquina y ahora nada funciona?

    Entonces te topaste con el Bug 3311 cuyo problema es que el respaldo de Endian guarda el archivo /etc/businfotab y cuando ejecutas una recuperación en un equipo nuevo sobre-escribe este mismo archivo con los datos del equipo antiguo.

    1
    2
    3
    4
    5
    6
    
    root@gorgory:~ # cat /etc/businfotab
    # Generated by ethconfig
    eth0  00:12.0
    eth1  00:13.0
    eth2  00:14.0
    root@gorgory:~ #
    

    Como ves en el cuadro anterior, el contenido del archivo indica las posiciones de las tarjetas de red en el Bus PCI. Si recuperas el respaldo y reinicias el equipo puede que tu nuevo archivo se vea así:

    1
    2
    3
    4
    5
    6
    7
    8
    9
    
    root@gorgory:~ # cat /etc/businfotab
    # Generated by ethconfig
    eth0  00:12.0
    eth1  00:13.0
    eth2  00:14.0
    eth3  00:15.0
    eth4  00:16.0
    eth5  00:17.0
    root@gorgory:~ #
    

    ¿Cómo lo soluciono?

    La solución al problema es fácil, lo único que debes hacer es borrar las líneas eth0, eth1 y eth2 que representan las tarjetas del equipo antiguo y luego reemplazar las líneas que quedan por las tarjetas correspondientes al equipo nuevo. El archivo debería quedar más o menos así:

    1
    2
    3
    4
    5
    6
    
    root@gorgory:~ # cat /etc/businfotab
    # Generated by ethconfig
    eth0  00:15.0
    eth1  00:16.0
    eth2  00:17.0
    root@gorgory:~ #
    

    También te recomendamos que excluyas del respaldo el archivo /etc/businfotab, esto lo haces editando el archivo /var/efw/backup/exclude.system y agregando la línea del archivo, por ejemplo:

    1
    
    etc/businfotab
    

    Referencias