Mock¶
Mock toma un srpm y construye el paquete en un entorno chroot. Esto asegura que sus líneas BuildRequires son correctas, que no hay dependencias faltantes y que contruye limpiamente.
- Mock
Instalación¶
$ su -c "yum install mock"
Uso básico¶
Referencia rápida de usos.
Construcción en entorno por omisión
$ mock SRPMS/rubygem-rhc-0.90.7-1.fc16.src.rpm ...
Use -r para escoger la configuración deseada
$ mock -r fedora-16-x86_64 SRPMS/rubygem-rhc-0.90.7-1.fc16.src.rpm ...
Configuración¶
Cuando use mock puede utilizar la opción -r para seleccionar una configuración en particular. Si existe una configuración que los usuarios del sistema utilizarán normalmente, usted puede definir dicha configuración como la configuración por omisión con:
# cd /etc/mock # ln -s --force ESTACONFIG.cfg default.cfg
En el directorio /etc/mock encontrará muchos archivos de configuración usables:
# cd /etc/mock # ls default.cfg epel-6-x86_64.cfg fedora-15-sparc.cfg fedora-16-sparc.cfg fedora-devel-ppc64.cfg fedora-rawhide-sparc.cfg epel-4-i386.cfg fedora-14-i386.cfg fedora-15-x86_64.cfg fedora-16-x86_64.cfg fedora-devel-ppc.cfg fedora-rawhide-x86_64.cfg epel-4-ppc.cfg fedora-14-s390x.cfg fedora-16-arm.cfg fedora-4-i386-epel.cfg fedora-devel-x86_64.cfg logging.ini epel-4-x86_64.cfg fedora-14-x86_64.cfg fedora-16-i386.cfg fedora-4-ppc-epel.cfg fedora-rawhide-arm.cfg site-defaults.cfg epel-5-i386.cfg fedora-15-arm.cfg fedora-16-ppc64.cfg fedora-4-x86_64-epel.cfg fedora-rawhide-i386.cfg epel-5-ppc.cfg fedora-15-i386.cfg fedora-16-ppc.cfg fedora-5-i386-epel.cfg fedora-rawhide-ppc64.cfg epel-5-x86_64.cfg fedora-15-s390.cfg fedora-16-s390.cfg fedora-5-ppc-epel.cfg fedora-rawhide-ppc.cfg epel-6-i386.cfg fedora-15-s390x.cfg fedora-16-s390x.cfg fedora-5-x86_64-epel.cfg fedora-rawhide-s390x.cfg epel-6-ppc64.cfg fedora-15-sparc64.cfg fedora-16-sparc64.cfg fedora-devel-i386.cfg fedora-rawhide-sparc64.cfg # ln -s --force fedora-16-x86_64.cfg default.cfg
Uso de Mock fuera de su git sandbox¶
Agregue su nombre de usuario al grupo mock.
# usermod -a -G mock gomix
Ahora cámbiese al directorio donde tiene sus SRPMS:
$ cd ~/rpmbuild/SRPMS $ mock --rebuild fwsnort-1.6.1-1.fc16.src.rpm INFO: mock.py version 1.1.18 starting... State Changed: init plugins INFO: selinux disabled State Changed: start INFO: Start(fwsnort-1.6.1-1.fc16.src.rpm) Config(fedora-16-x86_64) State Changed: lock buildroot State Changed: clean State Changed: unlock buildroot State Changed: init State Changed: lock buildroot Mock Version: 1.1.18 INFO: Mock Version: 1.1.18 INFO: calling preinit hooks INFO: enabled root cache INFO: enabled yum cache State Changed: cleaning yum metadata INFO: enabled ccache State Changed: running yum State Changed: creating cache State Changed: unlock buildroot INFO: Installed packages: State Changed: setup State Changed: build INFO: Done(fwsnort-1.6.1-1.fc16.src.rpm) Config(default) 26 minutes 21 seconds INFO: Results and/or logs in: /var/lib/mock/fedora-16-x86_64/result State Changed: end
$ ls /var/lib/mock/fedora-16-x86_64/result/ build.log fwsnort-1.6.1-1.fc16.src.rpm state.log fwsnort-1.6.1-1.fc16.noarch.rpm root.log $ ls /var/lib/mock/fedora-16-x86_64/root/ bin boot builddir dev etc home lib lib64 media mnt opt proc root run sbin srv sys tmp usr var
La primera vez que ejecute mock tomará su tiempo, pero existen alternativas para acelerar, entre ellas el cache.
Caches Mock¶
Mock incluye tres tipos diferentes de cache:
- root cache
- yum cache
- ccache
Mire en /etc/mock/defaults.cfg para documentarse acerca de la configuración de cada uno de estos caches. Puede configurar el directorio donde se almacenan, la edad máxima de los caches, y para el ccache el uso máximo del disco para el cache.
Root cache¶
A partir de mock 0.5, mock puede automáticamente poner en cache el buildroot estandar para entorno en un archivo tar local (/var/cache/mock/$CONFIG/root_cache/*). Entonces mock puede desempacar este archivo tar y poblar el buildroot en vez de descargar los RPMs del buildroot cada vez. Después de desempacar el buildroot desde el root cache, mock ejecuta un yum update para asegurarse que el buildroot esté al día antes de instalar BuildRequires adicionales para la construcción del paquete.
$ ls /var/cache/mock/fedora-16-x86_64/root_cache/ cache.log cache.tar.gz rootcache.lock
El root cache está habilitado por omisión a partir de mock 0.8.x. Para deshabilitar vea la documentación en /etc/mock/defaults. El root cache puede deshabilitarse globalmente o por-chroot. Los root caches son automáticamente borrados y recreados cada 15 días para prevenir de que se queden demasiados atrasados.
Mantenga en mente que el root cache puede afectar la reproducibilidad de su contrucción, especialmente en entornos donde el conjunto base de RPMs se actualiza frecuentemente (ej. rawhide). Deshabilite el root cache en entornos donde la reproducibilidad es de mayor importancia.
yum cache¶
Por omisisón yum almacena los RPMs descargados en un directorio bajo /var/cache/yum. El yum cache incluye "bind mount" al chroot /var/cache/yum en un directorio común fuera del entorno chroot (tal como /var/cache/mock/$CONFIG/yum_cache/) en donde puede ser salvado y reusado por subsiguientes construcciones. Esto asegura que yum no tenga que descargar cada RPM una y otra vez desde la red para cada construcción. Esta funcionalidad está habilitada por omisión.
ccache¶
La herramienta ccache es un utilitario que envuelve las llamadas a los compiladores tales como gcc y pone en cache la salida. Cuando se le llama para compilar el mismo programa una segunda vez (con los mismos argumentos en la línea de comando y archivos encabezado), ccache sacará el resultado de la versión en el cache en vez de correr el compilador.
Removiendo el cache¶
Un motivo para remover el cache es:
- Dependencias que ya están en los repos (no consigo manera de refrescar aún)
... Getting requirements for rubygem-unicorn-4.1.1-1.fc16.src --> ruby-libs-1.8.7.357-1.fc16.x86_64 --> rubygems-1.8.11-1.fc16.noarch --> ruby-devel-1.8.7.357-1.fc16.x86_64 --> 1:rubygem-rack-1.3.0-2.fc16.noarch --> rubygem-kgio-2.7.0-3.fc16.x86_64 Error: No se ha encontrado ningún paquete para rubygem(raindrops) ...
Y efectivamente la dependencia sí se encuentra disponible en el repositorio correspondiente.
$ su -c "rm -rf /var/cache/mock/fedora-16-x86_64"
Instalando un paquete¶
Es posible que la dependencia que requiere no esté disponible en los repositorios correspondientes, necesitamos instalar ese paquete a mano en la jaula.
[makerpm@movix rpmbuild]$ mock --install RPMS/noarch/rubygem-tidy_ffi-
rubygem-tidy_ffi-0.1.3-1.fc16.noarch.rpm rubygem-tidy_ffi-doc-0.1.3-1.fc16.noarch.rpm
[makerpm@movix rpmbuild]$ mock --install RPMS/noarch/rubygem-tidy_ffi-0.1.3-1.fc16.noarch.rpm
INFO: mock.py version 1.1.18 starting...
State Changed: init plugins
INFO: selinux disabled
State Changed: start
Mock Version: 1.1.18
INFO: Mock Version: 1.1.18
State Changed: lock buildroot
INFO: installing package(s): RPMS/noarch/rubygem-tidy_ffi-0.1.3-1.fc16.noarch.rpm
INFO:
================================================================================
Paquete Arquitectura
Versión Repositorio Tamaño
================================================================================
Instalando:
rubygem-tidy_ffi
noarch 0.1.3-1.fc16 /rubygem-tidy_ffi-0.1.3-1.fc16.noarch 24 k
Instalando para las dependencias:
rubygem-ffi x86_64 1.0.9-2.fc16 fedora 977 k
Resumen de la transacción
================================================================================
Instalar 2 Packages
Tamaño total: 1.0 M
Tamaño total de la descarga: 977 k
Tamaño instalado: 1.0 M
Instalado:
rubygem-tidy_ffi.noarch 0:0.1.3-1.fc16
Dependencia(s) instalada(s):
rubygem-ffi.x86_64 0:1.0.9-2.fc16
State Changed: unlock buildroot
State Changed: end
Cuando algo sale mal¶
Precisamente este es el caso de uso interesante, identificar BRs.
$ mock --rebuild rubygem-unicorn-4.1.1-1.fc16.src.rpm INFO: mock.py version 1.1.18 starting... State Changed: init plugins INFO: selinux disabled State Changed: start INFO: Start(rubygem-unicorn-4.1.1-1.fc16.src.rpm) Config(fedora-16-x86_64) State Changed: lock buildroot State Changed: clean INFO: chroot (/var/lib/mock/fedora-16-x86_64) unlocked and deleted State Changed: unlock buildroot State Changed: init State Changed: lock buildroot Mock Version: 1.1.18 INFO: Mock Version: 1.1.18 INFO: calling preinit hooks INFO: enabled root cache State Changed: unpacking root cache INFO: enabled yum cache State Changed: cleaning yum metadata INFO: enabled ccache State Changed: running yum State Changed: unlock buildroot INFO: Installed packages: State Changed: setup State Changed: build ERROR: Exception(rubygem-unicorn-4.1.1-1.fc16.src.rpm) Config(fedora-16-x86_64) 1 minutes 56 seconds INFO: Results and/or logs in: /var/lib/mock/fedora-16-x86_64/result ERROR: Command failed. See logs for output. # ['bash', '--login', '-c', 'rpmbuild -bb --target x86_64 --nodeps builddir/build/SPECS/rubygem-unicorn.spec']
Los logs:
$ cd /var/lib/mock/fedora-16-x86_64/result/ $ ls build.log root.log state.log
Revisando el build.log, podemos encontrar lo siguiente:
...
+ gem install --local --install-dir /builddir/build/BUILDROOT/rubygem-unicorn-4.1.1-1.fc16.x86_64/usr/lib/ruby/gems/1.8 --force --rdoc /builddir/build/SOURCES/unicorn-4.1.1.gem
Building native extensions. This could take a while...
ERROR: Error installing /builddir/build/SOURCES/unicorn-4.1.1.gem:
ERROR: Failed to build gem native extension.
/usr/bin/ruby extconf.rb
mkmf.rb can't find header files for ruby at /usr/lib/ruby/ruby.h
...
Ahora podemos corregir nuestro spec agregando el BR necesario y volver a iterar nuevamente (ya nuestro cache mock debe estar en sitio funcionando y acelerando mucho estas construcciones mock).
... BuildRequires: ruby-devel ...
Nuevamente ha fallado, ahora veamos por qué.
build.log
+ gem install --local --install-dir /builddir/build/BUILDROOT/rubygem-unicorn-4.1.1-1.fc16.x86_64/usr/lib/ruby/gems/1.8 --force --rdoc /builddir/build/SOURCES
/unicorn-4.1.1.gem
Building native extensions. This could take a while...
..
.....
.
Successfully installed unicorn-4.1.1
1 gem installed
...
...
...
/builddir/build/BUILDROOT/rubygem-unicorn-4.1.1-1.fc16.x86_64/usr/lib/ruby/gems/1.8/gems/unicorn-4.1.1/ext/unicorn_http/Makefile:RUBYARCHDIR = /builddir/build/BUILDROOT/rubygem-unicorn-4.1.1-1.fc16.x86_64/usr/lib/ruby/gems/1.8/gems/unicorn-4.1.1/lib$(target_prefix)
Binary file /builddir/build/BUILDROOT/rubygem-unicorn-4.1.1-1.fc16.x86_64/usr/lib/ruby/gems/1.8/gems/unicorn-4.1.1/ext/unicorn_http/httpdate.o matches
Found '/builddir/build/BUILDROOT/rubygem-unicorn-4.1.1-1.fc16.x86_64' in installed files; aborting
Errores de construcción RPM:
error: Estado de salida erróneo de /var/tmp/rpm-tmp.ixeDWK (%install)
Estado de salida erróneo de /var/tmp/rpm-tmp.ixeDWK (%install)
Child returncode was: 1
EXCEPTION: Command failed. See logs for output.
# ['bash', '--login', '-c', 'rpmbuild -bb --target x86_64 --nodeps builddir/build/SPECS/rubygem-unicorn.sp
rpmbuild con mock¶
Hay casos en los que su paquete no construirá correctamente en su estación de trabajo, una posible razón es que algún sw instalado interfiere con la construcción del paquete, un ejemplo, es tener yard que es un sistema de documentación para Ruby pero que no se utiliza en el entorno de construcción Fedora estandar. El error que se obtiene en este escenario es el de archivos instalados pero no empaquetados. Hay varias opciones:
- Remover el elemento que interfiere
- Demasiado intrusivo, tal vez simplemente usted no puede remover dicho elemento de su instalación.
- Puede provocar una larga cadena de dependencias removidas.
- Usar una máquina virtual
- Pesado, puede tomar bastante tiempo montar todo el arreglo de sw necesario.
- Lento, tal vez su hardware no es lo potente que desearía para hacer esto.
- Usar mock
- Obvio que esta es la opción a escoger en caso de no poder usar VMs rápidamente.
- Aun si puede usar VMs, ¿para qué si mock resuelve fácilmente? Veamos cómo.
mock --installdeps, instalamos las dependencias de nuestro paquete en cuestión en la jaula chroot mock.
[gomix@movix rpmbuild]$ mock --installdeps SRPMS/rubygem-gstreamer-1.0.3-3.fc.src.rpm INFO: mock.py version 1.1.18 starting... State Changed: init plugins INFO: selinux disabled State Changed: start State Changed: lock buildroot State Changed: unlock buildroot State Changed: end
mock --shell, entramos con shell a dicha jaula chroot y trabajamos como si nada, fácil.
$ mock --shell INFO: mock.py version 1.1.18 starting... State Changed: init plugins INFO: selinux disabled State Changed: start State Changed: lock buildroot State Changed: shell <mock-chroot>[root@movix /]# ls bin boot builddir dev etc home lib lib64 media mnt opt proc root run sbin srv sys tmp usr var <mock-chroot>[root@movix /]# cd builddir/build/ <mock-chroot>[root@movix build]# ls BUILD BUILDROOT originals RPMS SOURCES SPECS SRPMS <mock-chroot>[root@movix build]# rpmbuild -bp SPECS/rubygem-gstreamer.spec Ejecutando(%prep): /bin/sh -e /var/tmp/rpm-tmp.KKyPvN + umask 022 + cd /builddir/build/BUILD + LANG=C + export LANG + unset DISPLAY + cd /builddir/build/BUILD + rm -rf rubygem-gstreamer-1.0.3 + /bin/mkdir -p rubygem-gstreamer-1.0.3 + cd rubygem-gstreamer-1.0.3 + /bin/chmod -Rf a+rX,u+w,g-w,o-w . ...
¿Cómo compartir sesión mock?¶
Si intenta por ejemplo hacer mock --shell y ya existe otra sesión mock para dicha configuración obtendrá algo como:
$ mock --shell INFO: mock.py version 1.1.19 starting... State Changed: init plugins INFO: selinux disabled State Changed: start State Changed: lock buildroot ERROR: Build root is locked by another process.
Para compartir esta sesión mock deberá poder desconecta la sesión terminal y/o conectar desde otros terminales, es decir, puede resolver con tmux y screen.
??¶
Limpiando el árbol chroot:
$ mock --clean INFO: mock.py version 1.1.18 starting... State Changed: init plugins INFO: selinux disabled State Changed: start State Changed: lock buildroot State Changed: clean INFO: chroot (/var/lib/mock/fedora-16-x86_64) unlocked and deleted State Changed: unlock buildroot State Changed: end
$ mock -r epel-5-x86_64 --clean INFO: mock.py version 1.1.18 starting... State Changed: init plugins INFO: selinux disabled State Changed: start State Changed: lock buildroot State Changed: clean INFO: chroot (/var/lib/mock/epel-5-x86_64) unlocked and deleted State Changed: unlock buildroot State Changed: end
Usando otras configuraciones¶
Inicializando la jaula¶
La opción --init combinada con -r nos inicializa la jaula con la configuración especificada.
$ mock -r epel-5-x86_64 --init INFO: mock.py version 1.1.18 starting... State Changed: init plugins INFO: selinux disabled State Changed: start State Changed: lock buildroot State Changed: clean State Changed: unlock buildroot State Changed: init State Changed: lock buildroot Mock Version: 1.1.18 INFO: Mock Version: 1.1.18 INFO: calling preinit hooks INFO: enabled root cache INFO: enabled yum cache State Changed: cleaning yum metadata INFO: enabled ccache State Changed: running yum State Changed: creating cache State Changed: unlock buildroot INFO: Installed packages: State Changed: end
EPEL-6 misma arch en mi Fedora 16¶
El caso de uso inicial es la construcción de un paquete que no tiene una dependencia satisfecha en epel6, es decir, estoy probando que mis condicionales en el spec funcionen.
...
%if %{?fedora}
BuildRequires: rubygem(bundler)
%endif
]$ mock -r epel-6-x86_64 rpmbuild/SRPMS/rubygem-state_machine-1.1.2-1.fc16.src.rpm INFO: mock.py version 1.1.18 starting... State Changed: init plugins INFO: selinux disabled State Changed: start INFO: Start(rpmbuild/SRPMS/rubygem-state_machine-1.1.2-1.fc16.src.rpm) Config(epel-6-x86_64) State Changed: lock buildroot State Changed: clean State Changed: unlock buildroot State Changed: init State Changed: lock buildroot Mock Version: 1.1.18 INFO: Mock Version: 1.1.18 INFO: calling preinit hooks INFO: enabled root cache INFO: enabled yum cache State Changed: cleaning yum metadata INFO: enabled ccache State Changed: running yum
EPEL-5 misma arch en mi Fedora 16¶
Mi caso de uso inicial es problema con paquete en EPEL-5, quiero emular el entorno correspondiente en mi máquina, manteniendo la arquitectura para ver si puedo depurar el problema.
$ mock -r epel-5-x86_64 --init ...
Aunque esto parece funcionar bien, no es así, la instalación de los paquetes la realiza el yum externo que si bien descarga los rpms correctos, una vez dentro de la jaula ya las herramientas rpm no funcionan debido a la diferencia de formatos, la base de datos rpm que se ha generado no es compatible con la versión de rpm en epel5.
Extracto de root.log típico:
DEBUG util.py:307: Executing command: ['rpm', '-q', '-a'] DEBUG util.py:257: error: no se pudo abrir índice Packages utilizando db3 - Argumento inválido (22) DEBUG util.py:257: error: no se puede abrir la base de datos Packages en /var/lib/rpm
Mi solución por ahora es, entrar a la jaula, remover la base de datos rpm y reconstruirla de cero con los paquetes descargados en el propio cache yum dentro de la jaula.
$ mock -r epel-5-x86_64 --shell <mock-chroot>[root@movix yum]# cd /var/lib/rpm/ <mock-chroot>[root@movix yum]# rm * <mock-chroot>[root@movix yum]# rpm --initdb <mock-chroot>[root@movix yum]# rpm --rebuilddb <mock-chroot>[root@movix rpm]# cd /var/cache/yum/ <mock-chroot>[root@movix rpm]# rpm -vhi core/packages/*rpm extras/packages/*rpages/buildsys-build-0.7-2.el5.noarch.rpm update/packages/*rpm ... # rpm -qa | head setup-2.5.58-7.el5 basesystem-8.0-5.1.1.el5.centos glibc-common-2.5-65.el5_7.1 zlib-1.2.3-4.el5 mktemp-1.5-23.2.2 elfutils-libelf-0.137-3.el5 libstdc++-4.1.2-51.el5 audit-libs-1.7.18-2.el5 perl-5.8.8-32.el5_7.6 libattr-2.4.32-1.1
Ya de ahí en adelante, mock ya no nos sirve de mucho.
[gomix@movix rpmbuild]$ mock -r epel-5-x86_64 --installdeps SRPMS/rubygem-kgio-2.7.0-3.fc16.src.rpm INFO: mock.py version 1.1.18 starting... State Changed: init plugins INFO: selinux disabled State Changed: start State Changed: lock buildroot ERROR: Command failed: # ['/usr/bin/yum', '--installroot', '/var/lib/mock/epel-5-x86_64/root/', 'resolvedep', 'ccache'] error: db4 error(22) de dbenv->open: Argumento inválido error: no se pudo abrir índice Packages utilizando db4 - Argumento inválido (22) error: no se puede abrir la base de datos Packages en /var/lib/mock/epel-5-x86_64/root/var/lib/rpm CRITICAL:yum.main: Error: rpmdb open failed
Antes de copiar el srpm, recuerde generar como:
[gomix@movix rpmbuild]$ rpmbuild-md5 -bs SPECS/rubygem-kgio.spec ..
Copie a la jaula y trabaje en ella.
[gomix@movix rpmbuild]$ su -c "cp SRPMS/rubygem-kgio-2.7.0-3.fc16.src.rpm /var/lib/mock/epel-5-x86_64/root/"
[gomix@movix rpmbuild]$ mock -r epel-5-x86_64 --shell
INFO: mock.py version 1.1.18 starting...
State Changed: init plugins
INFO: selinux disabled
State Changed: start
State Changed: lock buildroot
State Changed: shell
<mock-chroot>[root@movix build]# pwd
/builddir/build
<mock-chroot>[root@movix build]# ls
BUILD originals rubygem-kgio-2.7.0-3.fc16.src.rpm SPECS
BUILDROOT RPMS SOURCES SRPMS
<mock-chroot>[root@movix build]# rpm -i rubygem-kgio-2.7.0-3.fc16.src.rpm
...
<mock-chroot>[root@movix build]# rpmbuild -bi SPECS/rubygem-kgio.spec
...
...
...
Ejecutando(%check): /bin/sh -e /var/tmp/rpm-tmp.89266
+ umask 022
+ cd /builddir/build/BUILD
+ cd rubygem-kgio-2.7.0
+ cd /var/tmp/rubygem-kgio-2.7.0-3.el5.centos-root-root/usr/lib/ruby/gems/1.8/gems/kgio-2.7.0
+ RUBYOPT='-Ilib -I/var/tmp/rubygem-kgio-2.7.0-3.el5.centos-root-root/usr/lib64/ruby/site_ruby/1.8/x86_64-linux -Itest'
+ testrb test/test_accept_class.rb test/test_accept_flags.rb test/test_autopush.rb test/test_connect_fd_leak.rb test/test_cross_thread_close.rb test/test_default_wait.rb test/test_kgio_addr.rb test/test_no_dns_on_tcp_connect.rb test/test_peek.rb test/test_pipe_popen.rb test/test_pipe_read_write.rb test/test_poll.rb test/test_singleton_read_write.rb test/test_socketpair_read_write.rb test/test_tcp6_client_read_server_write.rb test/test_tcp_client_read_server_write.rb test/test_tcp_connect.rb test/test_tcp_server.rb test/test_tcp_server_read_client_write.rb test/test_tryopen.rb test/test_unix_client_read_server_write.rb test/test_unix_connect.rb test/test_unix_server.rb test/test_unix_server_read_client_write.rb
/usr/bin/ruby: symbol lookup error: /var/tmp/rubygem-kgio-2.7.0-3.el5.centos-root-root/usr/lib64/ruby/site_ruby/1.8/x86_64-linux/kgio_ext.so: undefined symbol: RARRAY_PTR
error: Estado de salida erróneo de /var/tmp/rpm-tmp.89266 (%check)
Errores de construcción RPM:
Estado de salida erróneo de /var/tmp/rpm-tmp.89266 (%check)
¡BINGO! Ya tengo reproducido exactamente el mismo error que me ha dado Koji, ahora toca resolverlo :) Al menos poner la jaula fue fácil con la ayuda de mock.