piątek, 18 kwietnia 2014

Cobbler i paczkowanie pod Debianem


  Cobbler to narzędzie automatyzujące proces instalacji systemów Linuksowych - zarówno maszyn fizycznych jak i wirtualnych. Rzecz nie do przecenienia w dużym środowisku a i w prywatnym laboratorium też się przyda. Jak to w opensource bywa, trzeba jednak zainwestować w niego trochę czasu i chęci.



  Cobbler jest projektem wspieranym mocno przez RedHat-a i obsługuje oprócz systemów typu RedHat i CentOS również Debiana, Ubuntu i SUSE. Jednak samo zainstalowanie i czasem użycie na czymś nie RedHat-o podobnym jest wyraźnie trudniejsze.

Uwaga:  Zmiany opisane poniżej, zostały już wprowadzone do Cobbler-a w wersji 2.6 lub nowszej. Cała instalacja Cobbler-a sprowadza się więc tylko do sciągnięcia źródła z github-a, zbudowania paczek dla debiana oraz ich instalacji.

  Pierwsza bariera jaką mamy do przeskoczenia to instalacja. Owszem, można ściągnąć źródła i wydać magiczne polecenie w rodzaju ./configure && make && make install, jednak każdy szanujący się admin natychmiast spaliłby się ze wstydu po takiej instalacji w środowisku produkcyjnym.

  Dodatkowo dochodzi jeszcze jeden problem. Cobbler składa się tak naprawdę z kilku komponentów. Jeden z nich o nazwie koan (od ang: kickstart-over-a-network) służy do instalacji maszyn wirtualnych na właściwej maszynie fizycznej. Wynika z tego, że na każdej maszynie fizycznej powinniśmy mieć możliwość użycia koan-a, ale instalowanie w tym celu całego Cobblera mija się z celem.

  Zróbmy więc to wszystko porządnie i jak należy, zaczynając od utworzenia paczki *.deb z oprogramowaniem. Kod źródłowy Cobblera jest przygotowany w taki sposób, że utworzenie paczki *.deb sprowadza się do wydania zaledwie kilku poleceń, tworzy jednak paczkę w rodzaju "wszystko w jedym". A nam jak już wiemy, to nie specjalnie pasuje.

  Zaczynamy więc kompletnie od zera i paczkujemy Cobblera w taki sposób, by w rezultacie powstały przynajmniej dwie paczki tj: właściwa z serwerem i druga zawierająca tylko koan. Na początek sciągamy źródła najnowszego stabilnego wydania - w tym momencie to wersja 2.6:

# wget https://github.com/cobbler/cobbler/archive/v2.6.0.tar.gz
# mv v2.6.0.tar.gz cobbler-2.6.0.tar.gz
# tar -zxf cobbler-2.6.0.tar.gz
# cd cobbler-2.6.0/

O tym jakie pakiety są wymagane do kompilacji i co trzeba jeszcze doinstalować możemy przeczytać tutaj. Jak już sobie powiedzieliśmy, musimy utworzyć paczkę od nowa więc na start usuwamy katalog debian.

# rm -rf debian
# mkdir debian
# cd debian

Teraz tworzymy odpowiednie pliki. Debian posiada w internecie dobrą dokumentacje, więc tutaj będę pomijał szczegóły typu co dokładnie każdy plik robi, jaką ma składnie itp. Na początek plik control opisujący tworzone przez nas pakiety, ich zależności itp:

# cat > control

Source: cobbler
Section: admin
Priority: optional
Maintainer: Jasper Poppe <jpoppe@ebay.com>
Build-Depends: debhelper (>= 7), python-cheetah, python-yaml, git-core, python
Standards-Version: 3.8.0
Homepage: https://fedoraproject.org/cobbler

Package: cobbler
Architecture: all
Depends: ${python:Depends}, python, apache2, libapache2-mod-python, python-support, python-yaml, python-netaddr, python-cheetah, debmirror, syslinux | syslinux-common
Suggests: rsync, tftpd-hpa, mkisofs, tftpd-hpa, dhcp3-server, createrepo
Description: Install server
 Cobbler is a network install server.  Cobbler
 supports PXE, virtualized installs, and
 reinstalling existing Linux machines.  The last two
 modes use a helper tool, 'koan', that
 integrates with cobbler.  Cobbler's advanced features
 include importing distributions from DVDs and rsync
 mirrors, kickstart templating, integrated yum
 mirroring, and built-in DHCP/DNS Management.  Cobbler has
 a Python and XMLRPC API for integration with other
 applications.  There is also a web interface.

Package: koan
Architecture: all
Depends: ${python:Depends}, python, python-support, python-yaml, python-netaddr, lvm2, libvirt-bin, virtinst, syslinux | syslinux-common
Suggests: rsync, tftpd-hpa, mkisofs, tftpd-hpa, dhcp3-server, createrepo, selinux-utils
Description: kickstart-over-a-network (koan)
 Koan stands for kickstart-over-a-network.
 It's a Cobbler helper tool that supports virtualized guests installs
 and reinstalling existing Linux machines.

^C

Oraz pozostałe pliki dla pakietu cobbler mówiące jakie pliki (tworzone po kompilacji i instalacji) wejdą w skład pakietu :

# cat > cobbler.dirs
usr/bin
usr/sbin
var/lib/cobbler/kickstarts
var/lib/cobbler/isos
etc/cobbler
etc/cobbler/power
etc/cobbler/pxe
etc/cobbler/reporting
etc/cobbler/zone_templates
var/log/cobbler/anamon
var/log/cobbler/kicklog
var/log/cobbler/syslog
var/log/cobbler/tasks
usr/share/cobbler
usr/share/cobbler/installer_templates
usr/share/man/man1
var/lib/cobbler/webui_sessions
var/lib/cobbler/webui_cache
^C


# cat > cobbler.docs
README
^C

# cat > cobbler.install
usr/bin/cobbler
usr/bin/cobblerd
usr/bin/cobbler-ext-nodes
usr/bin/ovz-install
usr/sbin/tftpd.py
usr/lib/python*/dist-packages/cobbler/*
usr/share/cobbler/*
var/lib/cobbler/*
usr/share/man/man1/cobbler.1.gz
etc/cobbler/*
etc/apache2/conf.d/*
etc/init.d/cobblerd
srv/www/cobbler/*
srv/www/cobbler_webui_content/*
^C


Skrypt post-instalacyjny ustawiający właściwe uprawnienia do kilku katalogów :

# cat > cobbler.postinst
#!/bin/sh

set -e

if [ "$1" = "configure" ] ; then
    chown www-data:www-data /var/lib/cobbler/webui_sessions
    chmod 0700 /var/lib/cobbler/webui_sessions
    chown www-data:www-data /var/lib/cobbler/webui_cache
    chmod 0700 /var/lib/cobbler/webui_sessions
fi
^C


Na końcu, plik z ustawieniami systemowego serwisu cobblerd, który będzie widoczny jako /etc/default/cobbler, już po instalacji paczki :

# cat > cobbler.default
# Defaults for cobbler initscript
# sourced by /etc/init.d/cobbler
# installed at /etc/default/cobbler by the maintainer scripts

#
# This is a POSIX shell fragment
#

# Additional options that are passed to the Daemon.
DAEMON_OPTS=""
^C


Teraz pliki opisujące pakiet koan :

# cat > koan.dirs
usr/bin
var/log/koan
var/spool/koan
var/lib/koan/config
^C

# cat > koan.install
usr/bin/koan
usr/lib/python*/dist-packages/koan/*
usr/share/man/man1/koan.1.gz
usr/bin/cobbler-register
usr/share/man/man1/cobbler-register.1.gz
^C

Na końcu pozostał jeszcze plik rules, będący czymś w rodzaju Makefile - za wyjątkiem tego, że opisuje jak utworzyć pakiet, a nie skompilować jego kod :

#  cat > rules
#!/usr/bin/make -f
# -*- makefile -*-

export DH_OPTIONS

# Verbose mode
#export DH_VERBOSE=1

%:
        dh $@ --with python2

override_dh_auto_build:
        python setup.py build

override_dh_auto_clean:
        dh_auto_clean
        rm -f docs/*.gz

override_dh_auto_test:
        nosetests cobbler/*.py || true

override_dh_auto_install:
        python setup.py install -f --install-layout=deb --root=$(CURDIR)/debian/tmp --install-data=/usr
^C


Oraz dwa magiczne pliki opisujące pod jaką wersje Debianowego systemu paczkującego tworzymy to wszystko:

# cat > compat
7
^C


# mkdir source
# cat > source/format
3.0 (quilt)
^C


Jeżeli paczkujecie jakiś inny progam to warto zapamiętać, że poleceniem dh_make --createorig, można wygenerować katalog debian wraz z szablonami plików potrzebnych do utworzenia pakietu. Wydaje się, że wszystko już gotowe. Tworzymy więc changelog poleceniem :

# cd ..
# debchange --create

Uruchomi się edytor w którym możemy opisać co właśnie zrobiliśmy, przykładowo:

cobbler (2.6.0-1) unstable; urgency=low

  * Initial release. Orginal package splitted into two: cobbler and koan.

 -- Adrian Brzeziński <adrbxx@gmail.com>  Fri, 18 Apr 2014 18:24:22 +0200


Po wyjściu z edytora, pojawi się plik debian/changelog. Wisienka na torcie to oczywiście zbudowanie paczek. Możemy użyć polecenia:

# pdebuild
# ls /var/cache/pbuilder/result/*.deb

lub

# dpkg-buildpackage
# ls ../*.deb

No i oczywiście instalujemy:

# dpkg -i *.deb

Wydawałoby się, że jesteśmy już szczęśliwi. Po drobnych poprawkach w plikach konfiguracyjnych apacha logujemy się do systemu wchodząc na adres http://maszyna_z_cobblerem/cobbler_web/ (domyślny login i hasło: cobbler/cobbler).  Niestety podczas pierwszej próby instalacji przy użyciu koan, zobaczycie błąd:

# koan --virt --static-interface eth0 --server cobbler.local  --system new_host.local
- looking for Cobbler at http://cobbler.local:80/cobbler_api
install_tree: http://cobbler.local/cblr/links/debian-7-x86_64
- ['rpm', '-q', 'virt-install']
<type 'exceptions.OSError'>
[Errno 2] No such file or directory
...


Po wydaniu głośnego jęku zawodu, czas zakasać znowu rękawy. Błąd jest generowany przez fragment kodu w pliku app.py wykonujący polecenie "rpm -q virt-install" i jest w sumie łatwy do poprawy. Musimy zatem utworzyć łatkę, którą nałożymy na oryginalny kod źródłowy. Dokładnie do tego celu służy narzędzie quilt. Dla chętnych tutaj jest opisany sposób posługiwania się quilt-em. Szybka konfiguracja:

# cat > ~/.quiltrc
QUILT_PATCHES=debian/patches
QUILT_NO_DIFF_INDEX=1
QUILT_NO_DIFF_TIMESTAMPS=1
QUILT_REFRESH_ARGS="-p ab"

^C

Teraz tworzymy łatkę i na początek nadajemy jej jakąś nazwę :

# quilt new 01_dont_check_vrit-install_with_rpm.patch
# quilt add koan/app.py

W tym miejscu nanosimy poprawki w pliku app.py - zmieniamy sposób w jaki jest wykrywana wersja virt-install, tak by nie używać do tego celu wywołania rpm. Następnie kończymy edycje łatki :

# quilt refresh
# quilt pop -a

Dodajemy do changelog-u informacje o zmianie:

# debchange -i

Wpisujemy coś w rodzaju "Fixed virt-install version check - support for non rpm based distributions" i kompilujemy ponownie pakiet:

# pdebuilt

Na dzisiaj to wszytko. W następnym wpisie postaram się pokazać w jaki sposób skonfigurować Cobblera do użycia wraz z Debianem.

Dla porządku załączam jeszcze plik z łatką:

--- a/koan/app.py
+++ b/koan/app.py
@@ -629,13 +629,9 @@
                 if not os.path.exists("/usr/bin/qemu-img"):
                     raise InfoException("qemu package needs to be installed")
                 # is libvirt new enough?
-                # Note: in some newer distros (like Fedora 19) the python-virtinst package has been
-                # subsumed into virt-install. If we don't have one check to see if we have the other.
-                rc, version_str = utils.subprocess_get_response(shlex.split('rpm -q virt-install'), True)
-                if rc != 0:
-                    rc, version_str = utils.subprocess_get_response(shlex.split('rpm -q python-virtinst'), True)
-                    if rc != 0 or version_str.find("virtinst-0.1") != -1 or version_str.find("virtinst-0.0") != -1:
-                        raise InfoException("need python-virtinst >= 0.2 or virt-install package to do installs for qemu/kvm (depending on your OS)")
+                rc, version_str = utils.subprocess_get_response(shlex.split('/usr/bin/virt-install --version'), True)
+                if rc != 0 or re.match('^0\.[01].*',version_str):
+                    raise InfoException("need python-virtinst >= 0.2 or virt-install package to do installs for qemu/kvm (depending on your OS)")

             # for vmware
             if self.virt_type == "vmware" or self.virt_type == "vmwarew":