DHCP mind-teaser – revealed
Ramasesem dator cu povestirea questului meu cu dhcp de acum cateva zile, si adineauri am cam terminat partile esentiale, asa ca povestesc mai jos, poate pescuieste cineva ceva interesant:
Atentie, o sa fie lung!
Mai intai datele problemei:
Am un server cu Xen pe care vreau sa fac si sa desfac masini virtuale, si ma intereseaza foarte tare sa le fac cat mai "hands-off" se poate. Pentru asta imi trebuie (evident) DHCP, dar ca sa definesc hosturi individuale, imi trebuie sa tin evidenta mac-ip-hostname si sa ma asigur ca nu le incurc. IP si hostname sa zicem ca imi trebuie pentru DNS si cfengine (sau puppet pentru cui ii place ruby), dar MAC-urile le-as tine doar pt. declaratiile in dhcpd.conf (mai ales ca le poate genera Xen in locul meu). Si atunci a fost momentul cand mi-am zis: trebuie sa se poata fara!
Stiam eu ca printre valorile transmise de pachetele DHCP (standardul le spune "optiuni", asa ca le voi nu mi si eu la fel in continuare) este si hostname-ul si mi-am zis ca sigur se poate ca serverul sa se ia nu dupa MAC-ul cererii ci dupa optiunea specificata in pachet. Am gasit ceva la http://www.miquels.cistron.nl/isc-dhcpd/ cum ca nu merge chiar direct, dar se poate. Am pregatit un config de dhcpd cam ca acolo (mai tarziu m-am prins ca agent.* sunt optiuni de dhcp-relay si ca voiam host-name), dar am realizat ca eu instalez cu debian-installer caruia nu stiu cum sa-i zic hostname. Dupa ce am cautat prin manual la pagina gresita si m-am facut de ras pe Freenode am gasit netcfg/dhcp_hostname. Fabulos!
Stupoare! Nu se intampla nimic! Dupa ce m-am dat cu tcpdump si wireshark pe pachete (btw, wireshark e spectaculos cand vrei sa interpretezi un pachet si nu stii pe de rost protocolul si in care din cele tzshpe RFC-uri e ce-ti trebuie), am constatat ca nu apare nimic in plus in cererile dhcp si ca atare, isi ia adresa din pool-ul de "unknown". Dupa inca mai multe cautari prin sursele lui netcfg, m-am lamurit: trebuie lasat sa nu-si gaseasca adresa si abia dupa aceea ai optiunea sa cauti cu hostname-ul setat. Am mai dat preseed la intrebarile intermediare (o sa dau scripturile mai jos) si am scos pool-ul "liber" (mai tarziu l-am readaugat, excluzand insa clientii cu option-ul vendor="d-i"). Bun, acum mergea, dar nu se salva hostname-ul si in configul de dhcp final, ca sa mearga corect si dupa reboot. Cum tot aveam de gand sa rulez ceva scripturi de post-install, i-am trantit un sed si acum merge cum trebuie (cu inca un hack suplimentar in dhcpd.conf sa nu-l lase in pool, chiar daca nu mai are vendor "d-i")
Ramane sa vad cat de mult imi va simplifica sau complica viata ulterior
, deocamdata sunt convins ca pot genera partile din configurile dhcpd-ului si bind-ului direct din ceva baza de date cu ip-urile alocate. Includ mai jos partea practica.
### make-play.sh
#!/bin/bash
# scriptul pe care il folosesc deocamdata sa buildez masina virtuala numita play, in viitor numele masinii va fi un parametru
# folosesc libvirt pt. managementul masinilor virtuale asa ca e de fapt o singura comanda
# alta problema pe care o am deocamdata e ca trebuie sa-i fac eu in prealabil LV-ul, altfel nu prea vrea neinteractiv
# marea victorie e ca nu trebuie sa-i mai dau parametrul --mac, si-l genereaza singur, iar eu nu trebuie sa-l stiu
virt-install \
--name=play \
--paravirt \
--nographics \
--os-type=linux \
--ram=512 \
--disk path=/dev/vg0/lv-play\
--network bridge:xenbr0 \
--location=http://ftp.nb.lug.ro/debian/dists/lenny/main/installer-i386 \
--extra-args="auto=true priority=critical url=www netcfg/dhcp_hostname=play netcfg/dhcp_failed=true \
netcfg/dhcp_options=\"Retry network autoconfiguration with a DHCP hostname\""
In DNS am declarat play.example.com direct si reverse la 172.30.0.99, nu mai includ si zonele
### dhcpd.conf
ddns-update-style none;
option domain-name "example.com";
option domain-name-servers ns.example.com;
default-lease-time 600;
max-lease-time 7200;
authoritative;
log-facility local7;
subnet 172.30.0.0 netmask 255.255.255.0 {
option routers 172.30.0.1;
option domain-name "example.com";
option domain-name-servers 172.30.0.1;
pool {
deny members of "d-i";
deny members of "has-hostname";
range 172.30.0.101 172.30.0.120;
}
class "d-i" {
match if substring (option vendor-class-identifier, 0, 3) = "d-i";
}
class "has-hostname" {
match if option host-name != "";
}
# this will be machine generated
class "id-play" {
match if option host-name = "play";
}
pool {
allow members of "id-play";
range 172.30.0.99;
}
# ... until here
}
host other {
hardware ethernet 00:16:3E:C0:FF:EE;
fixed-address other.example.com;
}
Nota: inca nu-mi plac foarte tare scamatoriile facute cu clasele, dar pare sa functioneze corect.
### fisierul de preseed
# dat fiind ca am dat "url=www" in parametrii de boot, va fi cautat la adresa http://www/d-i/lenny/preseed.cfg,
# mai multe detalii in manualul installerului
# am cenzurat cateva chestii dar las in principiu si partile irelevante, poate sunt de ajutor
d-i debian-installer/locale string en_US
d-i console-keymaps-at/keymap select us
d-i netcfg/choose_interface select auto
d-i netcfg/disable_dhcp boolean false
d-i mirror/protocol string http
d-i mirror/country string manual
d-i mirror/http/hostname string ftp.nb.lug.ro
d-i mirror/http/directory string /debian
d-i mirror/http/proxy string
d-i clock-setup/utc boolean true
d-i time/zone string Europe/Bucharest
d-i clock-setup/ntp boolean true
d-i clock-setup/ntp-server string ro.pool.ntp.org
d-i partman-auto/method string regular
# urmatoarele 2 linii cred ca-s mostenite din alta parte, dar mi-e lene sa testez din nou sa vad daca fac ce cred eu
# si ca merge si fara, oricum partman e subiect de alt articol
d-i partman-lvm/device_remove_lvm boolean true
d-i partman-md/device_remove_md boolean true
d-i partman-lvm/confirm boolean true
d-i partman-auto/choose_recipe select atomic
d-i partman/confirm_write_new_label boolean true
d-i partman/choose_partition select finish
d-i partman/confirm boolean true
d-i passwd/make-user boolean false
#mereu ma chinui sa redescopar cum se cripteaza parola pt. aici, raspunsul e echo parola | mkpasswd -s -H MD5
d-i passwd/root-password-crypted password $1$tmw5No0e$WB458uiJB11YoEtfK0UkS1
tasksel tasksel/first multiselect standard
d-i pkgsel/include string openssh-server vim
popularity-contest popularity-contest/participate boolean true
d-i grub-installer/only_debian boolean true
d-i grub-installer/with_other_os boolean false
d-i finish-install/reboot_in_progress note
#aici downloadez si rulez un script in mediul instalat inainte de reboot
d-i preseed/late_command string \
cd /target; \
wget http://www/d-i/post-install; \
chmod +x ./post-install; \
chroot ./ ./post-install; \
rm -f ./post-install
### post-install
# ca sa fie in concordanta cu ce scrie mai sus, trebuie publicat la url-ul dat lui wget in late_command
# o sa fac eu mai multe chestii aici, deocamdata doar:
sed -i '/send host-name/s/^.*$/send host-name "'$(hostname -s)'";/' /etc/dhcp3/dhclient.conf
Succes si astept intrebari suplimentare (daca nu sunt active commenturile, pe email la rpetre AT gmail.com)