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

martes, 31 de octubre de 2017

Limpieza de portátiles de alumnos a principio de curso.

A principio de curso siempre tenemos que preparar los portátiles asignados a los alumnos, empezando por hacer una limpieza general de los mismos. Con los años hemos ido automatizando esto lo más posible para evitar tener que repetir una serie de tareas portátil a portátil.

Aparte de ejecutar puppet y pkgsync para actualizar convenientemente los portátiles, es recomendable borrar las credenciales cacheadas de antiguos usuarios, sus homes y las conexiones wifi creadas en el pasado por los alumnos. Este sería el script a ejecutar al inicio de curso:
# cat limpia_credenciales.sh

#!/bin/bash
#Curso 17-18. Version v1.

#Limpia credenciales cacheadas
for i in $(cc_dump | awk ' {print $3} '); do  cc_test -update any $i -  ; done

#Limpia conexiones wifi antiguas
rm /etc/NetworkManager/system-connections/*

#Limpia homes antiguos
rm -rf /home/alumnos/*

exit 0
Para ejecutarlo la forma mas sencilla es usar unas reglas puppet que aplicaríamos a los portátiles. En mi caso tengo un módulo puppet "omnibús" llamado xubuntu_portatil donde tengo varias pequeñas tareas de este tipo.

El esquema es el típico de estos casos: si no existe o ha cambiado, copiamos el script al portátil y lo ejecutamos.
class xubuntu_portatil {
  
  .......
  .......
  #Limpieza de credenciales a inicio de curso. El script se ejecuta una vez. Si queremos que se ejecute de nuevo
  #hay que cambiar el contenido (p.ej. la versión)

  file {"/root/scripts":
     ensure => directory,
     before => File["/root/scripts/limpia-credenciales.sh"],
  }

  file {"/root/scripts/limpia-credenciales.sh":
        owner=>root, group=>root, mode=>755,
        source=>"puppet:///modules/xubuntu_portatil/limpia-credenciales.sh",
        notify => Exec["limpia-credenciales"],
  }

  exec { "limpia-credenciales":
                        path => "/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin",
                        command => "/root/scripts/limpia-credenciales.sh",
                        require => File["/root/scripts/limpia-credenciales.sh"],
                        refreshonly => true,
  }
  .......
  .......

}
Cada vez que queramos hacer limpieza basta con cambiar algo (basta, por ejemplo, con cambiar la fecha o nº de versión de v1 a v2) en el script almacenado en el directorio "files" de nuestro módulo xubuntu_portatil y se copiará de nuevo y ejecutará.

domingo, 22 de octubre de 2017

rsync con sistemas de ficheros ntfs

Estoy haciendo backups de todas mis imágenes clonezilla a una máquina con partición de destino ntfs y me encuentro con que rsync copia de nuevo muchos ficheros que no han variado cada vez que lo lanzo.

Lo que hace rsync (a no ser que le pongamos el parámetro --checksum) es comparar la fecha de modificación y tamaño de cada fichero en origen y destino y si difiere algo sincroniza de nuevo el fichero. Eso en sistemas ext2/3/4 funciona sin problemas con:
# rsync -avP root@ip-origen:/mnt/partimag/* /mnt/partimag
Pero si uno o ambos sistemas de ficheros es ntfs (y seguramente también fat) no funciona. La causa es que la precisión o el formato de las fechas en ntfs es distinto al de ext2/3/4 y rsync se muestra confundido, considerando fechas distintas las que no lo son. La solución consiste en proporcionar una ventana de error de varios segundos para permitir conciliar bien las fechas:
# rsync -avP --modify-window=5 root@ip-origen:/mnt/partimag/*  /mnt/partimag
Con el ejemplo anterior doy 5 segundos de margen de error al comparar 2 fechas de modificación y tomar la decisión de que han cambiado. Por supuesto eso se puede afinar lo que haga falta en función de cada caso, aunque a mi con 5 segundos me ha ido bien.

lunes, 16 de octubre de 2017

En busca del musthave mínimo.

Como estos días he estado enredando con pkgsync no he podido evitar darme cuenta de que el musthave que tengo en todos los pc es bastante tocho. En su mayoría han sido generados con el script /root/scripts/generar_musthave.sh y por lo que veo tienen mucha redundancia.

Por ejemplo, tener en el musthave los paquetes libreoffice y libreoffice-writer es redundante. Las dependencias del primero implican tener instalado el segundo, por que solo con tener el primero en musthave es suficiente. Sobre las librerías (paquetes lib*) mejor ni hablar: casi todas se instalan de forma automática al cumplir las dependencias de otro paquete de rango superior.

El hecho de tener en musthave solo los paquetes importantes, y no sus dependencias, lo hacen mas manejable y menos susceptible a caer en el "pkgsync installation loop" (esté término me lo acabo de inventar). Este "loop" pasa cuando tenemos en el musthave paquetes que son excluyentes entre si y pkgsync resuelve esta situación esquizofrénica instalando y quitando grupos de paquetes en cada llamada de forma alternativa. Eso no debe ser así, ya que pkgsync debe comportarse de forma idempotente: si no tocamos ningún fichero (mayhave/musthave/maynothave/...) todas las llamadas de pkgsync deben quedar el sistema de paquetes como estaba, invariante.

Por esto y porque me apetecía me puse a mirar como reducir el tamaño del musthave para que esté lo mas puro y mínimo posible. Vamos a ver poco a poco lo que he encontrado:

Primero sacamos una lista ordenada con los paquetes instalados de forma no automática (de esta forma nos libramos de los paquetes tipo librería y otros dependientes). Es lo que se llama paquetes explícitos:
# paquetes_explicitos=$(aptitude search '~i !~M' -F '%p' --disable-columns | sort -u)
De estos paquetes los habrá que se han instalado desde /etc/pkgsync/musthave, también estarán los que se hayan instalado desde /etc/pkgsync/musthave.d por tareas independientes nuestras y, por último, los que se hayan instalado a mano y puesto en /etc/pkgsyc/mayhave para no ser desinstalados. Solo nos interesan los primeros (ya que lo que queremos es aligerar el etc/pkgsync/musthave inicial).
for i in $paquetes_explicitos
do
   echo -n "Paquete $i"
   if grep $i /etc/pkgsync/musthave > /dev/null
   then
        echo " ->instalado por musthave"
        echo $i >> musthave.new        
   else
      if grep $i /etc/pkgsync/mayhave > /dev/null
      then
          echo "  ->instalado por mayhave"
      else
          echo "  ->instalado por musthave.d"
      fi
   fi
done
sort -u -o musthave.new musthave.new
A la salida tenemos en musthave.new los paquetes explícitos que están en el /etc/pkgsync/musthave original. Con esto tenemos una selección bastante buena de paquetes, pero no es suficiente. Si miramos detenidamente en el musthave.new vemos que sigue habiendo redundancias. Hay que ir mas allá y limpiar todos los paquetes de musthave.new que dependan de otros paquetes que estén en ese mismo fichero.

Con el siguiente bucle que recorre musthave.new voy metiendo en musthave.deps todas las dependencias de cada paquete. Para ello uso el comando apt-rdepends (que saca las dependencias y sugerencias de un paquete), aplico un par de filtros para quedarme sólo con las dependencias y si aparece el propio paquete entre sus dependencias lo ignoro (por extraño que parezca, a veces sucede). Por último ordenamos la lista de paquetes dependientes y quitamos los repetidos usando "sort -u":
for i in $(cat musthave.new)
do
   #echo "Dependencias de $i"
   apt-rdepends $i |grep Depends: | awk ' { print $2 } ' | sed "/^${i}$/d" >> musthave.deps
done
sort -u -o musthave.deps musthave.deps
Una vez hecho esto, quitamos de musthave.new todos los paquetes que también estén en musthave.deps mediante "comm -23", borrando los paquetes redundantes y dejando el resultado en musthave.final:
comm -23 musthave.new  musthave.deps  > musthave.final
Todo el script junto queda:
# cat musthave-minimo
#!/bin/bash

if [ ! -f /usr/bin/apt-rdepends ]
then
    echo "Instalando apt-rdepends"
    apt-get install apt-rdepends
fi

cp /dev/null musthave.new
cp /dev/null musthave.deps

paquetes_explicitos=$(aptitude search '~i !~M' -F '%p' --disable-columns | sort -u)
for i in $paquetes_explicitos
do
   echo -n "Paquete $i"
   if grep $i /etc/pkgsync/musthave > /dev/null
   then
        echo " ->instalado por musthave"
        echo $i >> musthave.new        
   else
      if grep $i /etc/pkgsync/mayhave > /dev/null
      then
          echo "  ->instalado por mayhave"
      else
          echo "  ->instalado por musthave.d"
      fi
   fi
done
sort -u -o musthave.new musthave.new

num=1
total=$(wc -l  musthave.new)
for i in $(cat musthave.new)
do
   echo "Dependencias de $i: $num/$total"
   ((num++))
   apt-rdepends $i |grep Depends: | awk ' { print $2 } ' | sed "/^${i}$/d" >> musthave.deps 
done
sort -u -o musthave.deps musthave.deps
comm -23 musthave.new  musthave.deps  > musthave.final

exit 0
Una vez obtenido el musthave.final podemos compararlo con el musthave inicial y con mushave.new usando "wc -l". Veremos que el número de paquetes se ha reducido considerablemente. Esto es un ejemplo sobre un Ubuntu con la imagen LTSP:
# wc -l musthave*
 1837 musthave.deps
  174 musthave.final
 1285 musthave
  501 musthave.new
Como vemos pasamos de 1285 paquetes en el musthave generado con el script generar_musthave.sh a 174 en musthave.final, tras realizar las sucesivas purgas de paquetes dependientes.

Antes de aplicar musthave.final de forma general es conveniente hacer una copia de seguridad /etc/pkgsync/musthave, sobrescribir musthave.final sobre él y ejecutar pkgsync en modo simulación (no hace nada de verdad, simplemente te dice que ficheros quitaría y que ficheros instalaría), para calibrar si es inofensivo.
# cp /etc/pkgsync/musthave /etc/pkgsync/musthave.backup
# cp musthave.final /etc/pkgsync/musthave
# pkgsync -s
Normalmente nos dirá que quiere quitar algunos paquete secundarios raros que no parecen tener mayor importancia. Aquí entra en juego la pericia de cada cual a la hora de evaluar el riesgo de dejarle que quite esos paquetes, pero por mi experiencia y tras investigar el contenido los paquetes propuestos puedo decir que todas las veces me han salido paquetes anodinos, que ni sé que hacen ahí ni los voy a echar de menos cuando se vayan.

Una vez seguros de lo que queremos hacer cogemos aire, nos encomendamos a Odín y ejecutamos "pkgsync" sin mirar atrás. En el peor de los casos, siempre podemos volver a cargar la imagen con clonezilla ;-).

viernes, 13 de octubre de 2017

Cómo montar el pkgsync con control compartido usando puppet.

Cada vez que preparo un tipo nuevo de equipo y tengo que meterle pkgsync para mantener la coherencia de los paquetes de forma centralizada me toca re-estudiarme como está montado. Esta vez voy a apuntarlo aquí a modo de guía.

1. Cómo funciona el pkgsync en máquinas clientes.

Gracias a Esteban tenemos un pkgsync cada vez mas potente y versátil. En los repositorios tenemos la version 1.39:
# apt-cache policy pkgsync
pkgsync:
  Instalados: 1.39
  Candidato:  1.39
  Tabla de versión:
 *** 1.39 0
        500 http://linex.educarex.es/ubuntu/trusty/ trusty/linex amd64 Packages
        500 http://servidor/html/linex2/ubuntu/trusty/ trusty/linex amd64 Packages
        100 /var/lib/dpkg/status
        ....
Hace años que partimos de un pkgsync primitivo basado en solo 3 ficheros (/etc/pkgsync/mayhave, maynothave y musthave) que nos daba muchos problemas de competencia entre lo que nos imponían desde Mérida y lo que queríamos tener cada uno en nuestro centro (¿quién manda si hay un único mayhave?).

Gracias a las mejoras de Esteban hemos evolucionado a un sistema de soberanía compartida, donde hay una parte del mayhave (y compañía) controlada por Mérida y otra controlada por nosotros.

Por ello ahora tenemos tres orígenes de ficheros que se fusionan al ejecutar pkgsync en un único /etc/pkgsync/mayhave.all, el cual toma la función que tenía el antiguo y solitario /etc/pkgsync/mayhave. Estos 3 orígenes son:

  • /etc/pkgsync/mayhave: es controlado por Mérida mediante diversas tareas puestas en nuestro servidor puppet. Si lo modificamos será sobreescrito desde el Puppet Master of Our Universe de la Consejería.
  • /etc/pkgsync/mayhave.ies: es controlado por nosotros en nuestro servidor puppet. Para ello debemos tener una tarea hecha que lo controle.
  • /etc/pkgsync/mayhave.d/*: es como mayhave.ies, pero en este directorio podemos poner varios ficheros que se fusionarán con el resto. Es muy cómodo para hacer grupos de paquetes personalizados según el tipo de equipo (por ejemplo /etc/pkgsync/mayhave.d/mayhave.multimedia y poner dentro una lista de paquetes relacionados con multimedia). También debemos tener una tarea hecha por nosotros que controle estos ficheros.

Of course, esto relatado del mayhave se aplica de forma idéntica para musthave y maynothave.

2. Cómo se distribuyen los ficheros de pkgsync oficiales desde el servidor puppet.

Para evitar tener que ir equipo a equipo, los ficheros vistos en el apartado anterior tienen que controlarse desde el servidor puppet del centro. Hemos convenido en que los ficheros musthave/mayhave/maynothave son controlados desde Mérida por su puppet, mientras que los musthave.ies/mayhave.ies/maynothave.ies y los musthave.d/mayhave.d/maynothave.d están controlados por nosotros por nuestro puppet.

Los controlados por el servidor de la Consejería en Mérida se guardan en la ruta /etc/puppet/files/xubuntu del servidor principal del centro. Si vamos allí, veremos al menos estos ficheros:
mayhave.siatic.i386
musthave.hp360
musthave.infolab
musthave.siatic
musthave.siatic.i386
Para saber que se hace con ellos, busco en las tareas puppet:
root@servidor:/etc/puppet# grep -ir puppetinstituto/files/xubuntu/mayhave * 
manifests/classes/xubuntu/siatic.pp:        source => "puppet://puppetinstituto/files/xubuntu/mayhave.siatic.i386",

root@servidor:/etc/puppet# grep -ir puppetinstituto/files/xubuntu/musthave * 
manifests/classes/xubuntu/notebookHP.pp:        source => "puppet://puppetinstituto/files/xubuntu/musthave.hp360",
manifests/classes/xubuntu/siatic.pp:        source => "puppet://puppetinstituto/files/xubuntu/musthave.siatic.i386",
manifests/classes/xubuntu/infolab.pp:#        source => "puppet://puppetinstituto/files/xubuntu/musthave.infolab",
De lo visto podemos decir que:
  • musthave.hp360: es el musthave que se copia para tablets-portátiles hp360.
  • musthave.infolab: es el musthave para infolabs. Lo cierto es que a día de hoy no se usa, se comentó su inserción por un problema con las tarjetas nvidia y así permanece.
  • mayhave.siatic.i386, musthave.siatic.i386: son el mayhave/musthave que se copia a las Siatic con sistema de 64bits.
  • musthave.siatic: ya no se usa. En su día era el oficial de los siatics, pero había paquetes de xserver que daban problemas y se dejó de insertar.

Como vemos, no hay musthaves/mayhaves/maynothave oficiales para equipos ltsp, workstations, portátiles distintos a los hp360 ni para siatics de 64bits. Se entiende que todos estos equipos tienen un /etc/pkgsync/musthave que viene de serie en su respectiva imagen y de momento la Sección no contempla modificarlos por puppet ya que no hay tarea oficial que se ocupe de actualizarlos.

En el caso de las siatic 64bits ni siquiera traen un musthave inicialmente (lo cual hace que pkgsync no funcione ya que requiere de su existencia para trabajar) y si lo queremos debemos generarlo con el script que aparece en la imagen llamado /root/Primer_arranque/generar_musthave.sh (el cual también es una creación de Esteban).

Por lo general tampoco hay mayhaves y maynothave oficiales para ningún equipo, ya que de momento no ha surgido la necesidad de tenerlos de forma general en todos los centros.

3. Cómo distribuyo los ficheros de pkgsync particulares desde el servidor puppet.

Hasta aquí hemos visto la infraestructura común, ahora veremos como controlar por nuestra parte los mayhave/musthave/maynothave que son de nuestra competencia. Nada de esto lo tenemos por defecto en el servidor del centro y por tanto nos toca montar por nuestra cuenta el módulo puppet y los ficheros que distribuye.

En primer lugar aclarar los musthave.ies/mayhave.ies/maynothave.ies no los uso. Tuvieron su momento cuando teníamos Debian Wheezy pero ahora preferimos la solución mas elegante basada en los ficheros fragmentados a través de musthave.d/mayhave.d/maynothave.d. Si lo montamos bien, podremos tener un musthave general, que se aplica a todos los equipos, y un musthave por cada tipo-use2 de equipo.

En mi caso, en /etc/puppet/files/xubuntu tengo esta estructura de directorios creada:
├── mayhave.d
│   ├── mayhave.infolab
│   ├── mayhave.infolab.profesor
│   ├── mayhave.ltsp.profesor
│   ├── mayhave.notebookHP
│   ├── mayhave.portatil-alumno
│   ├── mayhave.siatic
│   ├── mayhave.workstation
│   ├── mayhave.workstation-i386
│   └── mayhave.xubuntu
├── maynothave.d
│   ├── maynothave.infolab
│   ├── maynothave.infolab.profesor
│   ├── maynothave.ltsp.profesor
│   ├── maynothave.notebookHP
│   ├── maynothave.portatil-alumno
│   ├── maynothave.siatic
│   ├── maynothave.workstation
│   ├── maynothave.workstation-i386
│   └── maynothave.xubuntu
└── musthave.d
    ├── musthave.infolab
    ├── musthave.infolab.profesor
    ├── musthave.ltsp.profesor
    ├── musthave.notebookHP
    ├── musthave.portatil-alumno
    ├── musthave.siatic
    ├── musthave.workstation
    ├── musthave.workstation-i386
    └── musthave.xubuntu
Los ficheros .xubuntu se copian a todo los equipos con ubuntu y los otros según los facter tipo (siatic, infolab, ltsp, workstation, etc) y use2 (profesor/alumno). Para ello uso la siguiente clase puppet basada en la original que compartieron mis compañeros del IES Téllez hace ya tiempo:
# cat /etc/puppet/modules/xubuntu_pkgsync/manifests/init.pp 

#Clase para control de los ficheros básicos para pkgsync de siatic, infolab y notebookHP
import "/etc/puppet/defines/*.pp"

class  xubuntu_pkgsync {

        case $use2 {
                "profesor":  { $esprofe=".profesor" }
                default: { $esprofe = "" }
        }

        #====================================================================================================================
        #Ficheros dependientes del tipo: Se pone un mayhave, musthave, maynothave personalizado en función del tipo y use2 (si es profesor) 

        case $tipo {

                "siatic", "infolab", "notebookHP", "ltsp", "workstation","portatil-alumno", "workstation-i386": {  
                        file { "mayhave.instituto":
                         path => "/etc/pkgsync/mayhave.d/mayhave.$tipo",
                         owner => root, group => root, mode => 644, 
                         source => "puppet:///files/xubuntu/mayhave.d/mayhave.${tipo}${esprofe}",
                         ensure => file,
                        }

                        file { "maynothave.instituto": 
                         path => "/etc/pkgsync/maynothave.d/maynothave.$tipo",
                         owner => root, group => root, mode => 644,
                         source => "puppet:///files/xubuntu/maynothave.d/maynothave.${tipo}${esprofe}",
                         ensure => file,
                        }

                        file { "musthave.instituto": 
                         path => "/etc/pkgsync/musthave.d/musthave.$tipo",
                         owner => root, group => root, mode => 644,
                         source => "puppet:///files/xubuntu/musthave.d/musthave.${tipo}${esprofe}",
                         ensure => file,
                        }
                }
                default: { }

        }

        #====================================================================================================================
        #Musthaves/maynothave/mayhave globales para todos los xubuntus controlados por mi

        # musthave global para todos los xubuntu
        file { "musthave.xubuntu":
                path => "/etc/pkgsync/musthave.d/musthave.xubuntu",
                owner => root, group => root, mode => 644,
                source => "puppet:///files/xubuntu/musthave.d/musthave.xubuntu",
                ensure => file,
        }

        # mayhave global para todos los xubuntu
                file { "mayhave.xubuntu":
                path => "/etc/pkgsync/mayhave.d/mayhave.xubuntu",
                owner => root, group => root, mode => 644,
                source => "puppet:///files/xubuntu/mayhave.d/mayhave.xubuntu",
                ensure => file,
        }

        # maynothave global para todos los xubuntu
        file { "maynothave.xubuntu":
                path => "/etc/pkgsync/maynothave.d/maynothave.xubuntu",
                owner => root, group => root, mode => 644,
                source => "puppet:///files/xubuntu/maynothave.d/maynothave.xubuntu",
                ensure => file,
        } 

        #====================================================================================================================
        #Ficheros mayhave/maynothave principales vacios por defecto si no existen.
        #El musthave debe ser creado por el administrador a mano. No se crea por defecto por su peligrosidad.

        # Por si no existen los ficheros, los creamos inicialmente a vacíos
        file { "mayhave.inicial": 
                path => "/etc/pkgsync/mayhave",
                owner => root, group => root, mode => 644,
                ensure => file,
        }

        file { "maynothave.inicial": 
                path => "/etc/pkgsync/maynothave",
                owner => root, group => root, mode => 644,
                ensure => file,
        }

        #El musthave no se crea por precaucion. Si existe el pkgsync se ejecutaría y puede destrozar el sistema de paquetes.
        #   cada /etc/pkgsync/musthave debe ser creado a mano por el administrador. Si no existe, pkgsync se aborta.

}
Y así es como lo tengo montado, utilizando los facter tipo y use2 para colocar los ficheros en las máquinas correspondientes. Los compañeros de Mérida tienen sus ficheros y yo tengo los míos.

Si quiero aplicar un paquete a todos los Ubuntu lo meto en el fichero *.xubuntu correspondiente. Si quiero aplicarlo a un tipo concreto (por ejemplo en los workstation de 64bits), lo meto en el fichero *.workstation correspondiente. En la siguiente ejecución de puppet en el cliente se copiarán los ficheros desde servidor:/etc/puppet/files/xubuntu y en la posterior ejecución de pkgsync se sincronizarán los paquetes de acuerdo con lo ordenado.

Como se ve, es una solución elegante que permite que trabajar colaborativamente sin machacarnos entre nosotros. Parlem.