"Después del juego es antes del juego"
Sepp Herberger

miércoles, 13 de mayo de 2015

Tarea puppet para instalación manual de paquetes

A veces tengo que instalar en un conjunto de ordenadores un paquete que no está en ninguno de los repositorios de Linux, ya que es una aplicación suelta (por ejemplo, Master PDF Editor)  o bien un paquete generado  por algún compañero o por mi mismo.
Una posible opción sería construir un repositorio privado dentro de la red del centro y meter dentro los paquetes que queramos, como cuenta aquí mi compañero Esteban Navas. Otra opción es hacer una tarea puppet que compruebe si el paquete está instalado con la versión correcta, y en caso  contrario descargue el paquete desde una ubicación fija y proceda a instalarlo. Este es el método que estoy utilizando,  definiendo un recurso puppet nuevo para realización de estas tareas:
root@servidor:/etc/puppet/modules/instala_paquete/manifests# cat init.pp 
define instala_paquete($version,$fichero) {

       exec { "descarga_$fichero":
           path => "/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin",
           command => "mkdir -p /root/descargas; wget -q http://servidor/ficheros/$fichero -O /root/descargas/$fichero",
           unless => "dpkg -l |grep $title | grep $version | grep ii",
           notify => Exec["instala_$fichero"]
       }

       exec { "instala_$fichero":
              path => "/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin",
              command => "dpkg -i --force-architecture /root/descargas/$fichero; apt-get -y -f install",
              refreshonly => true,
              require => Exec["descarga_$fichero"]
       }
}
El uso del recurso sería poner en la clase específica correspondiente algo como:
   ......
   instala_paquete {"master-pdf-editor":
                         version=>"2.2.15",
                         fichero=>"master-pdf-editor_2.2.15_i386.deb"
   }
   ......
Como se ve el primer parámetro es el nombre del paquete una vez instalado, el segundo la versión (utilizada para comparar con la versión instalada y actualizarlo si procede) y el último es el nombre del fichero .deb descargado. Dicho fichero .deb debemos ponerlo en la ruta http://servidor/ficheros/master-pdf-editor_2.2.15_i386.deb para que se pueda bajar antes de instalarse.
Por supuesto, podemos poner tantas invocaciones a instala_paquete como queramos dentro de las distintas clases puppet que usemos:
        .....
        instala_paquete {"autolabel":
                              version=>"0.1-1",
                              fichero=>"autolabel_0.1-1_all.deb"
              }
        .....
La tarea que define el recurso estará en la ruta: /etc/puppet/modules/instala_paquete/manifests/init.pp  y tendrá el directorio /etc/puppet/modules/instala_paquete/files vacío.
Bueno, pues con esto instalaremos paquetes sueltos de una forma elegante a la par que sencilla. Nos leemos.

Addenda 29-Mayo-2015: después de tener en producción la tarea varios días, me di cuenta de que ocasionalmente fallaba en la ejecución de puppet en los clientes donde ya estaba instalado el paquete. Después de varias pruebas comprobé que era porque si la ejecución de la tarea puppet coincidía en el tiempo con una operación sobre el sistema de paquetes (pkgsync, apt-get ... desde algun crontab o script, etc) evidentemente se produce un conflicto que finaliza con el fallo de la tarea.

La solución pasa por comprobar antes de ejecutar la instalación del paquete si hay o no otra operación en marcha. Para ello uso
lsof /var/lib/dpkg/lock
Que comprueba si el fichero /var/lib/dpkg/lock está siendo usado, señal de que hay un proceso trabajando sobre el sistema de paquetes. Por supuesto, es necesario que el paquete "lsof" esté instalado con antelación si no lo estaba. En mi caso lo hice poniendo dicho paquete en el musthave del pkgsync.

La tarea quedaría
define instala_paquete($version,$fichero) {

       exec { "descarga_$fichero":
           path => "/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin",
           command => "mkdir -p /root/descargas; wget -q http://servidor/ficheros/$fichero -O /root/descargas/$fichero",
           unless => "dpkg -l |grep $title | grep $version | grep ii",
           notify => Exec["instala_$fichero"]
       }

       exec { "instala_$fichero":
              path => "/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin",
              command => "lsof /var/lib/dpkg/lock || (dpkg -i --force-architecture /root/descargas/$fichero; apt-get -y -f install)",
              refreshonly => true,
              require => Exec["descarga_$fichero"]
       }
}
El operador || usado en el command del segundo exec indica que si el comando lsof falla (es decir, no se encuentra en uso /var/log/dpkg/lock), se ejecute el dpkg y apt-get posteriores. En caso de que lsof tenga éxito no se hace nada después.

De esta manera si he conseguido eliminar los fallos ocasionales en la ejecución de la tarea.

No hay comentarios:

Publicar un comentario