Sistema de Generación - guadalinex-archive/guadalinex-v5 GitHub Wiki

###Vistazo general

El fin último del sistema de generación es producir los entregables de la distribución. Formalmente se compone de diversas unidades software que, conectadas entre ellas conforman un marco de trabajo integrado para facilitar sus labores al equipo de desarrollo.

Como hemos visto a lo largo de esta guía, el proceso de construcción de una distribución toma como unidad de desarrollo el paquete debian, y así pues el sistema de generación también está orientado a paquetes, contando con:

  • Un sistema de control de versiones: donde subir los paquetes fuente
  • Un repositorio de paquetes: que sirve de base a la distribución
  • Un generador de isos: que toma el repositorio para construir los medios entregables
  • Un sistema de integración continua: capaz de detectar eventos en subversion e iniciar la construcción del paquete

Gracias a este sistema, el desarrollador solo debe preocuparse de organizar los cambios en la distribución, mediante paquetes, y observar cómo se integran estos cambios en el sistema. El sistema de generación velará por:

  • Detección, guiado y monitorización de los cambios aplicados en los paquetes
  • Asegurar que todo cambio supera los controles de calidad
  • Correcta generación de los entregables

###Arquitectura

El sistema de generación está compuesto por diversos componentes software interconectados, de tal modo, que unos sirven de entrada a otros y viceversa. Podemos realizar una clasificación de los componentes en dos:

  • Infraestructura o base: Un sistema de control de versiones subversion y un repositorio de paquetes debian
  • Servicios de integración: Integración continua (testsys) y aplicativos para generación de imagen iso

Los componentes 'base' se tratan de servicios ampliamente usados en el mundo del software libre a los que simplemente aplicaremos unas configuraciones específicas recomendadas para su conexión con los servicios de integración.

Por otra parte, tanto testsys como los aplicativos para la generación de iso están basados en software de integración y generación ampliamente usados, a los que se les ha desarrollado una capa de abstracción para hacerlos más específicos.

Comentaremos a continuación la arquitectura de cada uno de los componentes. Véase Instalación para instrucciones de instalación y configuración de los componentes.

Control de versiones

Concretamente Subversion ha sido elegido como control de versiones para implementar este sistema de generación. Es aquí donde se albergarán los directorios con los paquetes y metapaquetes fuente de nuestra distribución.

La organización de directorios en subversion debe respetar los siguientes principios:

  • Rama para los metapaquetes:
    • Cada metapaquete fuente (gcs) debe contar con un subdirectorio propio
    • Todos los paquetes fuente deben situarse en un único directorio (Ej.: metapkgs/)
  • Rama para los paquetes fuente:
    • Cada paquete fuente de nuestra distribución debe contar con un subdirectorio propio
    • Todos los paquetes fuente deben situarse en un único directorio (Ej.: apps/)
    • Dentro de cada subdirectorio del paquete fuente debe aparecer un subdirectorio de desarrollo (Ej.: trunk/) y otro subdirectorio con las diversas congelaciones por las que haya pasado el paquete (Ej.: tags/)

En ejemplo de organización podría ser:

/
|-- apps
|   |-- casper-guada                           
|   |   |-- tags                               
|   |   |   |-- casper-guada-1.1               
|   |   |   |-- casper-guada-1.2               
|   |   |   |-- casper-guada-1.3               
|   |   `-- trunk                              
|   |-- dumphive                               
|   |   |-- tags                               
|   |   |   `-- dumphive-0.0.3-1               
|   |   `-- trunk                              
|   |-- escritorio-movistar                    
|   `-- tags                               
|       |   |-- escritorio-movistar-6.1        
|       |   `-- escritorio-movistar-6.5        
|       `-- trunk                              
|-- doc
|   `-- manuales                              
|       `-- instalacion.odt
`-- metapkgs                                                        
    |-- guadalinex-about                                            
    |   `-- gcs                                                     
    `-- guadalinex-artwork                                          
        `-- gcs                                                     

Notas: En este ejemplo

  • Hemos reservado los siguientes nombres: apps, metapkgs, trunk, tags (a posterior deberemos indicar estos nombres al sistema de integración testsys).
  • Cualquier otra rama será ignorada, como es el caso de doc/

Repositorio

Para el control del repositorio de paquetes vamos a usar la herramienta reprepro. Esta herramienta nos permite gestionar un repositorio de paquetes Debian de una forma sencilla y eficiente.

Los archivos de configuración del repositorio se sitúan en un directorio llamado conf. En la forja de Guadalinex V5 podemos encontrarlo en el directorio gensys/ftp/conf

Los ficheros que se encuentran en este directorio son:

  • distributions:
Codename: lobo
Components: main restricted universe multiverse
UDebComponents: main restricted
Architectures: i386
Update: - ubuntu guadalinex
DebOverride: override.lobo.deb
UDebOverride: override.lobo.udeb
SignWith: AAADDDDD

El Codename es el nombre interno de la distribución

Los componentes a utilizar serán main restricted universe multiverse, por si es necesario incluir paquetería derivada de la distribución madre. También definimos los componentes udeb que son los paquetes que utiliza el instalador, pero en este caso serán main restricted .

La arquitectura será i386 para que el el repositorio contenga binarios para arquitecturas basadas en x86.

El campo SignWith es la clave GPG que se utilizará para firmar el repositorio. Esta clave debe estar en el directorio .gpg del usuario que ejecute el comando reprepro.

El campo Updates nos permite hacer una fusión de varios repositorios externos. En este caso vamos a mezclar dos repositorios: el oficial de ubuntu y el que contiene la personalización de la distribución. El signo - resta prioridad al repositorio que precede, así un paquete con la misma versión en ambos repositorios se recogerá del que no precede el signo -.

  • updates:
Name: ubuntu
Method: http://gensys/hardy
Suite: hardy
Architectures: i386
FilterList: install paquetescorruptos

Name: guadalinex
Method: http://gensys/derivative
Suite: lobo
Architectures: i386

Este archivo contiene tantas secciones como repositorios tenga el campo Updates: del archivo distributions. En cada sección se incluyen los datos del repositorio correspondiente, donde el campo Name indica el nombre a usar para referenciarlo desde el fichero distributions

Una vez creados estos dos archivos ejecutaremos el siguiente comando en el directorio padre de conf:

reprepro -VVV export lobo
reprepro -VVV update lobo

Generación de entregables

Testsys

Testsys, el sistema de integración continua orientado a distribuciones, no es más que una capa de abstracción construida sobre BuildBot.

Una definición de integración continua puede ser:

"Conjunto de prácticas de ingeniería del software destinadas a acelerar/mejorar el proceso de desarrollo, implantación y detección de errores"

Testsys toma como unidad de procesamiento a los paquetes y metapaquetes a los cuales aplica la siguiente lógica:

  • Todo cambio llevado a cabo en un metapaquete es procesado. En tiempo de construcción debe obtenerse la revisión del subversion en la que se produjo el cambio y esta será la versión-revisión del paquete final.
  • Para los paquetes, solo los cambios llevados a cabo en el último tag son susceptibles de ser procesado, el resto de cambios se ignoran.

Testsys se construyó como una capa de abstracción/especialización de Buildbot. Éste es un sistema de integración continua, ampliamente utilizado en grandes proyectos de software libre como Gnome build.gnome.org o Python python.org/dev/buildbot. La misión de Buildbot es automatizar los ciclos de compilación/test/integración en el proceso de desarrollo de un software. Conozcamos ciertos fundamentos técnicos de Buildbot.

Buildbot

Buildbot consta de dos tipos de entidades: un único buildmaster y uno o más buildslaves conectados en topología estrella. El buildmaster toma las decisiones de qué, cómo y cuándo construir. Éste envía comandos para ser ejecutados por los esclavos, los cuales simplemente llevan a cabo la ejecución y devuelven el resultado. Es función del master gestionar toda la lógica.

El buildmaster es, generalmente, alimentado por los cambios producidos en un sistema de control de versiones, y en base a estos se toman las decisiones de descarga/compilación/testeo produciendose diversos mensajes de estado durante el proceso.

El master es configurado y mantenido por el administrador, quien es, generalmente, miembro de equipo de desarrollo del proyecto y es encargado de definir su comporamiento. Los esclavos pueden considerarse como 'tontos' (simplemente llevar a cabo operaciones enviadas por el master) y no necesitan mantenimiento ni responsable.

Los buildslaves pueden residir en la misma máquina que el buildmaster o en diferentes máquinas de diferentes arquitecturas inclusive, de tal forma que se podría ordenar una compilación en varias arquitecturas de un mismo software fácilmente. La comunicación buildmaster <-> buildslave se realiza por sockets TCP y pueden vivir tras un firewall o NAT ya que son los esclavos los encargados de conectarse al maestro y no al revés.

El buildmaster consiste de diversos componentes:

  • ChangeSource: Encargado de escuchar/recibir el log cambios producido en el sistema de control de versiones (vcs)
  • Scheduler: Colectan los cambios del vcs, los gestiona y empaqueta en Builders para su construcción en los esclavos
  • Builder: Un builder conoce la secuencia de pasos a llevar a cabo con el código, por ejemplo, obtener desde vcs, compilar, testear y subir el ejecutable por FTP a un directorio.
  • BuildStep: Cada uno de los pasos de un Builder.

Bajo este esquema puede ahora comprenderse cómo buildmaster ordena a los buildslaves: Les envía lo que hay que hacer organizado en Builders. Este es un ejemplo de la interfaz de Buildbot:

Cada columna representa las sucesivas ejecuciones a lo largo del tiempo de cada Builder. Cada sección de un Build (ejecución de un Builder) representa un Buildstep. Si se hace click en el título de la columna aparece una ventana de información acerca de en qué buildslave se está ejecutando ese builder y qué evento en el vcs disparó la ejecución de éste.

Buildbot orientado a distros: Testsys

Existen diversas dificultades para el uso de Buildbot en nuestro sistema de generación. El principal cambio de paradigma que supone la adaptación de Buildbot para nuestro sistema de generación es que:

  • Mientras Buildbot está orientado a código, el sistema de generación está orientado a paquetes/metapaquetes fuente.
  • Los eventos que disparan la construcción de un metapaquete (siempre) y un paquete (último tag) son distintos.
  • La secuencia de construcción/testeo/integración misma para los paquetes, y otra distinta para los metapaquetes.
  • No solo hay que construir código, también hay que generar entregables (iso, repositorio)

Conceptualmente el esquema de arquitectura de Testsys es el siguiente:

Contamos con un buildmaster llamado gv5master y dos buildslaves llamados PkgBuilderBot (construcción de paquetes) y GensysBot (generación de entregables). Formalmente se auto-genera un Builder para cada paquete/metapaquete fuente a procesar. Los Builder del tipo paquete ejecutan una serie de pasos (BuildSteps) y los metapkgs otros.

Construcción de paquetes

El maestro gestiona toda la lógica de detección de eventos en svn, distingue si el cambio se ha realizado en un un paquete o metapaquete produciendo un Builder de tipo appBuilder o metapkgBuilder respectivamente. El Builder resultante es ordenado para su ejecución en el esclavo PkgBuilderBot. La construcción de un paquete o metapaquete puede ordenarse también bajo demanda desde la interfaz web.

El appBuilder lo forman un grupo de BuildSteps ordenados para:

  • Realizar un checkout del svn
  • Construir el paquete con la herramienta debuild
  • Observar los warning y errors anunciados por Lintian.
  • Ejecutar los tests unitarios del paquete (si hubieran)
  • Subir los ficheros resultantes a /var/mirror/pkgs

El metapkgBuilder ejecuta la siguiente sucesión de BuildSteps:

  • Realizar checkout del svn
  • Construir el paquete con la herramienta GCS
  • Ejecutar los tests unitarios del paquete (si hubieran)
  • Subir los ficheros resultantes a /var/mirror/pkgs

Nota: Mediante configuración se puede forzar a Testsys para que declare todo el Build como nulo si se producen errores en Lintian o cualquiera de los test unitarios.

Generación de los entregables

Existe un Scheduler programado ala nightly-build para la generación de los entregables (repositorio e iso). Este Scheduler puede también ser ejecutado bajo demanda desde la interfaz web.

El Builder de generación de entregables se alimenta de un repositorio intermedio que se genera con el contenido de /var/mirror/pkgs y el repositorio de la distrubución padre. (Véase Generación de entregables para más información).

Ficheros de configuración

Testsys lo componen una serie de ficheros-librerías base y un archivo de configuración llamado guadalinex.py donde se definen la url de subversion, rutas de salida de los paquetes construidos, hora del nightly-build, etcétera. Véase Instalación de Testsys.

###Instalación

La instalación del sistema de integración se reduce a la instalación y configuración de cada uno de sus componentes. Se recomienda dedicar una máquina, física, virtual o jaula (chroot), para la instalación del sistema de integración.

NOTA: Para el caso de la jaula se han detectado pequeños fenómenos extraños en Testsys a la hora de procesar la obtención de código mediante checkout del subversion.

Máquina hospedadora

Los requisitos hardware de la máquina no suelen ser demasiado elevados, pero vienen en función del consumo de recursos que se produzca durante las construcciones/compilaciones de los paquetes y la generación de la imágen iso.

En cuanto al software cabe un requisito base: Testsys debe instalarse en una máquina cuyo sistema operativo sea la distribución padre que vayamos a emplear para crear nuestra propia distribución. La causa fundamental es, que los paquetes/metapaquetes se construirán orientados a la distribución padre, y que las dependencias de construcción de nuestros paquetes fuente deben ajustarse a las versiones disponibles en la distribución padre.

El repositorio debe también ser instalado en esta máquina hospedadora. El subversion puede ir en otra máquina distinta.

Generación de entregables

Para la generación de entregables, haremos uso de gensys, el cual hace uso de lig para generar la imagen live.

Dependencias
  • lig
  • gensys
Procedimiento
Instalación y configuración de lig

La instalación de lig es más sencilla de lo que se puede imaginar. Basta con hacer un ckeckout del repo de apps/lig/trunk y realizar un enlace simbólico de su ejecutable en /var/opt/cdimage

Su configuración es tan sencilla como realizar una copia de su fichero conf a /etc/lig y personalizarlo con nuestras propias modificaciones.

Instalación y personalización de gensys

La instalación de gensys también es tan sencilla como hacer un checkout del directorio gensys del subversion en el directorio de trabajo del sistema de generación, por ejemplo en /var/opt/cdimage.

Personalizar gensys es tan sencillo como indicar el codename de la distribución en sus ficheros, en nuestro caso, reemplazaríamos lobo por el codename de la distro que queremos crear, los ficheros comunes a personalizar son:

  • gensys/etc/config
  • gensys/debian-cd/CONF.sh
  • gensys/ftp/reoverride.sh
  • gensys/ftp/conf/updates
  • gensys/ftp/conf/distributions
  • gensys/iso-publication
  • gensys/bin/find-live-filesystem
  • gensys/bin/anonftpsync

Testsys

Dependencias
  • Python 2.5
  • Python-twisted
  • Buildbot >= 0.7.7
  • Herramientas de generación: Lig, CD-Image, ?????
  • Herramientas de construcción de paquetes: debuild, devscripts, fakeroot, lintian, debhelper
Procedimiento

proc

Instalación de buildbot

instalacion

Se ha podido contrastar el funcionamiento de testsys bajo las versiones 0.7.7 y 0.7.8 de Buildbot. No se garantiza el funcionamiento en versiones superiores o inferiores.

A día de hoy Buildbot se encuentra disponible el los repositorios tanto de Debian como Ubuntu, no obstante, para las versiones soportadas, el tar.gz puede ser descargado desde la web oficial.

Una vez descargado el proceso de instalación es sencillo, dado que se trata de un paquete python standard-build:

user@host:/tmp$ tar zxf buildbot-0.7.8.tar.gz 
user@host:/tmp$ cd buildbot-0.7.8
user@host:/tmp$ python setup.py install

A continuación elegimos un directorio donde albergar el maestros y los esclavos (véase Sistema-de-Generación#testsys para conocer qué significa esto). Por ejemplo sobre el directorio /var/testsys/:

  • Crear maestro:
user@host:/tmp$ buildbot create-master /var/testsys/gv5master
  • Crear pkgbuilderbot:
user@host:/tmp$ buildbot create-slave /var/testsys/pkgbuilderbot localhost:9989 pkgbuilderbot pkgbuilderbot
user@host:/tmp$ cp /var/testsys/pkgbuilderbot/Makefile.sample /var/testsys/pkgbuilderbot/Makefile
  • Crear gensysbot:
user@host:/tmp$ buildbot create-slave /var/testsys/gensysbot localhost:9989 gensysbot gensysbot
user@host:/tmp$ cp /var/testsys/gensysbot/Makefile.sample /var/testsys/gensysbot/Makefile
Instalación Testsys

En el momento en el que esta guía fue redactada, Testsys se trata simplemente de un conjunto de ficheros que reescriben ciertas funcionalidades de Buildbot, aportan nuevas features y un fichero de configuración. Por tanto, la instalación es tan sencilla como copiar dichos ficheros directamente sobre la raíz del maestro buildbot. Actualmente el código de Testsys reside en la forja de Guadalinex v5.

Tomando las rutas de instalación del maestro buildbot del ejemplo anterior, puede procederse a la instalación tal que así:

user@host:/$ cd /var/testsys/gv5master
user@host:/var/testsys/gv5master$ svn export --force http://forja.guadalinex.org/guadalinexv5/testsys/ .
Configuración

El fichero guadalinex.py contiene las variables de configuración necesarias para personalizar el sistema de generación: Cada variable del fichero está ampliamente documentada. Destacamos:

  • apps: Diccionario python con el listado de ramas de subversion a procesar para llevar a cabo la construcción del paquete fuente que alberga
  • metapkgs: Similar a apps pero para los metapaquetes construidos con gcs
  • svn: URL del repositorio subversion
  • gensys_time: Hora a la que comenzar el nightly-build de la iso de nuestra distribución
  • upload_dir: Directorio de salida de los paquetes fuente y binario resultante de la construcción de éstos.
  • raw_image: Directorio de salida de la iso

Adicionalmente, ciertas variables de identidad del proyecto como: Nombre del proyecto, URL oficial del proyecto o URL/Puerto de la interfaz web a Testsys pueden ser configuradas en el fichero master.cfg dentro de la sección PROJECT IDENTITY.

###Guía de uso

Arranque/Parada

Tomando las rutas de instalación de Testsys que hemos seguido en la (guia de instalación) esta sería la secuencia de inicio:

user@host:$ cd /var/testsys/pkgbuilderbot; make start
user@host:$ cd /var/testsys/gensysbot; make start
user@host:$ buildbot start /var/testsys/gv5master

Puede verse que se arrancan los esclavos y el maestro. El orden de arranque no importa realmente, la conectividad esclavo-maestro la inician los esclavos.

Para parar:

user@host:$ cd /var/testsys/pkgbuilderbot; make stop
user@host:$ cd /var/testsys/gensysbot; make stop
user@host:$ buildbot stop /var/testsys/gv5master

Añadir un nuevo paquete/metapaquete

Supone tres pasos:

  • Generar los directorios necesarios en subversion
  • Instalar las dependencias de construcción del paquete/metapaquete, en la máquina del sistema de generación.
  • Incluir paquete en Testsys
  • Realizar un commit correcto del primer tag (no necesario en metapaquetes)

Como ya se comentó en el apartado control de versiones, es necesario que cada paquete fuente esté alojado en un subdirectorio propio bajo un la rama de metapaquetes o paquetes según le corresponda. Si se trata de un paquete es necesario que el subdirectorio de éste contenga trunk/ y tags/, esto no es necesario para el metapaquete.

Suponiendo que los nombres de las ramas sean apps/ para paquetes y metapkgs/ para metapaquetes así se hospedarían en subversion nuestros paquetes iniciales ejemplo_pkg1 y el metapaquete ejemplo_metapkg1:

/
|-- apps/
|   `-- ejemplo_pkg1/
|      |-- tags/
|      `-- trunk/
|          `-- codigo
`-- metapkgs/
    `-- ejemplo_metapkg1/
        `-- codigo

A continuación se editaría el fichero guadalinex.py y ajustarían las variables apps y metapkgs:

# Lista de nombre de las apps. El nombre debe coincidir con la rama de 
#subversion que contiene la app. La inclusion en esta lista de una nueva app
#hace que buildbot la gestione automaticamente.
apps=[
        "ejemplo_pkg1",
]

# Lista de nombre de los metapkgs. El nombre debe coincidir con la rama de 
# subversion que contiene el metapkg. La inclusion en esta lista de un nuevo 
# metapkg hace que buildbot lo gestione automaticamente.
metapkgs = [
  "ejemplo_metapkg1",
]

Reiniciamos buildbot (Véase Arranque/Parada) y desde la interfaz web puede observarse las columnas respectivas a estos dos nuevos elementos.

Antes de realizar las primeras construcciones cabe asegurarse que las dependencias de construcción/compilación del paquete en cuestión están instaladas en la máquina que alberga al sistema de generación.

A partir de aquí, todo cambio producido en ejemplo_metapkg1 (vía subversion) disparará la construcción de éste y por cada nuevo tag de ejemplo_pkg1 que se lleve a commit disparará su construcción.

Construir bajo demanda

La construcción bajo demanda, de cada uno de los Builders, puede ser ordenada vía interfaz web. Es requisito necesario que, por lo menos una vez, el builder que vamos a construir bajo demanda haya sido ejecutado satisfactoriamente.

Para ello:

  • Hacer click sobre el build (franja amarilla de la secuencia de buildsteps)
  • Rellenar los campos de formulario sobre quién y porqué quiere realizar un rebuild
  • Hacer click sobre el botón rebuild para llevar a cabo la construcción bajo demanda
Force-build

Existe una opción especial de re-construcción que permite especificar tanto la rama a construir como la revisión de svn a utilizar llamado Force-Build. Se accede haciendo click sobre la columna de nuestro paquete/metapaquete. Es necesario rellenar cuatro campos de formulario: autor, motivo para forzar reconstrucción, rama y revisión de svn a construir.

En el campo "Branch to build" (rama a construir), en el caso de los paquetes basta especificarse el nombre del tag, y para metapaquetes debe escribirse "metapkgs/nombre_metapkg" donde "metapkg" es el nombre del directorio que alberta los metapaquetes y "nombre_metapkg" es el nombre del directorio del metapaquete concreto.

Proporcionando test unitarios para un paquete

Pueden incluirse test unitarios directamente en un paquete fuente que cumpla lo siguiente:

  • Debe existir un ejecutable llamado unittests que dispara la ejecución de los tests unitarios.
  • Dicho ejecutable debe devolver !=0 en caso de error.

El programador puede sentirse libre de utilizar la tecnología que desee para la implementación de los test unitarios siempre y cuando respete esos principios.

El comportamiento de Testsys por defecto ante un error en la ejecución de los test unitarios de un paquete es cancelar el Build. Esto puede ser modificado a través de la variable de configuración halt_on_unittest_error del archivo de configuración guadalinex.py

Si se desea modificar el nombre del ejecutable que dispara la ejecución de los test unitarios puede sustituirse, en el fichero master.cgf, la siguiente línea:

appfactory.addStep(Unittests(haltOnFailure=True))

Por:

appfactory.addStep(Unittests(haltOnFailure=True, command=["bash", "comando_a_ejecutar"]))

Este comportamiento será por igual para la ejecución de todo test unitario de todo paquete.

Cambiar la hora de generación de la iso

Existe una variable de configuración en el fichero guadalinex.py llamada gensys_time donde definir, en formato HH:MM, la hora de lanzamiento del Builder gensys.

Tras realizar estos cambios será necesario reiniciar Testsys, (véase Arranque/Parada).

Deshabilitar interfaz web read-only

La interfaz web por defecto de Testsys es operable por cualquier persona sin requerir autorización. Pueden existir casos en los que desee contar con una vista read-only de Testsys, por ejemplo para hacer público el estado del desarrollo de la distribución.

Dicha interfaz está habilitada por defecto a través del puerto 8011. Si se desea inhabilitar debe comentarse la siguiente línea del fichero master.cfg

c['status'].append(html.WebStatus(http_port=8011, allowForce=False))

Modificar el puerto de la interfaz web

Por defecto el puerto de acceso a la interfaz web de Testsys es el sugerido por defecto en Buildbot, esto es, el 8010. Puede modificarse dicho puerto desde el archivo master.cfg en la siguiente línea:

c['status'].append(html.WebStatus(http_port=8010, allowForce=True))