Table of Contents
xml2hostconf is a utility for central configuration and automatic installation of a network of Linux computers. Right now Fedora, Centos, Debian and Ubuntu are supported. Instead of inventing new installation/updating/syncing methods it uses the functionality already present in rpm, yum, anaconda (kickstart), dpkg, preseed, dhcpd and pxelinux. xml2hostconf generates appropriate configuration files for the above mentioned programs and let them do the work. xml2hostconf is written in the scripting languages XSLT and Python.
xml2hostconf differs from other installation frameworks in the sense that it lets the client setup be defined as generated configuration RPM- or DEB-packages, consisting of configuration files and dependencies to "normal" application RPM- or DEB-packages and possibly some post-installation commands. This gives the benefit that already installed machines will be kept in sync with the central configuration. Hence, you don't have to reinstall a machine to bring it to the state of defined at the central configuration server. The commands "yum update" or "apt-get dist-upgrade" pulls the current configuration to the client.
The fastest way to understand how xml2hostconf works is by looking at its configuration file ( see Example 1, “main.xml example” ). You could then take a look at the generated Section 7, “Generated output examples”
The primary URL for this document is http://xml2hostconf.sourceforge.net
Download the software from the sourceforge project page. The latest version of xml2hostconf is 3.0.1.
There are three ways to install xml2hostconf: RPM, DEB or directly from source.
First install the requirements. If you are on a Fedora machine, do this
[root@fedora ~]# yum install libxml2 libxslt python httpd mod_ssl tftp-server dhcp syslinux createrepo cmake
On an Ubuntu machine do this
[root@ubuntu ~]# apt-get install libxml2 libxslt1.1 python apache2 tftpd dhcp3-server syslinux createrepo dpkg-dev rpm cmake
You need cmake version 2.6 or greater. As of 21 May 2008, Ubuntu 8.04 has an older cmake version and you need to download a newer one directly from the cmake homepage.
If you are only interested in generating some configuration RPMs or configuration DEBs then you won't need the PXE installation machinery in xml2hostconf. You could then skip installing the dhcp-, apache- and the tftp-server.
To test xml2hostconf you might want to install it under /tmp/install
[user@ubuntu ~]$ cd /tmp [user@ubuntu tmp]$ tar xfz xml2hostconf-3.0.1.tar.gz [user@ubuntu tmp]$ mkdir build install [user@ubuntu tmp]$ cd build [user@ubuntu build ]$ cmake -DCMAKE_INSTALL_PREFIX=/tmp/install /tmp/xml2hostconf-3.0.1 && make && make install
First install the requirements
[root@fedora ~]# yum install libxml2 libxslt python httpd mod_ssl tftp-server dhcp syslinux createrepo
Now download the latest xml2hostconf RPM and then install it
[root@fedora ~]# rpm -Uvh xml2hostconf-3.0.1-1.rpm
Right now files to be served by apache are placed here:
/usr/lib/xml2hostconf/cgi-bin/install.cgi
/var/cache/xml2hostconf/server/httpd_docroot
SELINUX might block apache from reading these files if it is activated. ( Todo: check this ).
First install the requirements
[root@ubuntu ~]# apt-get install libxml2 libxslt1.1 python apache2 tftpd dhcp3-server syslinux createrepo dpkg-dev rpm cmake
Now download the latest xml2hostconf DEB and then install it
[root@fedora ~]# dpkg -i xml2hostconf-3.0.1-1.deb
To configure apache you need to create a configuration file with this content
ScriptAlias /xml2hostconf-cgi-bin/ //usr/lib/xml2hostconf/cgi-bin/ Alias /xml2hostconf/ //var/cache/xml2hostconf/server/httpd_docroot/ <Directory //var/cache/xml2hostconf/server/httpd_docroot> Order Deny,Allow Deny from all AllowOverride None Options None </Directory> <Directory //var/cache/xml2hostconf/server/httpd_docroot/repos> Options FollowSymLinks AllowOverride AuthConfig Limit Options </Directory> <Directory //usr/lib/xml2hostconf/cgi-bin> Options ExecCGI </Directory>
On Ubuntu the file should be named /etc/apache2/conf.d/xml2hostconf.conf
and on Fedora/CentOS/RHEL /etc/httpd/conf/conf.d/xml2hostconf.conf
The best way to test xml2hostconf out is to test it on a subnet that belongs to you and where there is no other dhcp server running.
Warning | |
---|---|
Don't run xml2hostconf on a computer at your home that got its ip address from your ISP's dhcp server. The problem is that xml2hostconf uses its own dhcp server and this dhcp server might interfer with any other dhcp server on the same subnet. |
If you would mirror the Linux repository (i.e. one of Ubuntu/Debian/Fedora/CentOS) to the xml2hostconf server, you would be able to test xml2hostconf out on a subnet totally disconnected from the internet. But the following instructions are meant for a situation where the subnet has access to the internet ( and therefore the Fedora mirror repositories on the internet ).
In the following installation instructions our xml2hostconf server has the hostname earth.example.org. First let us try out one of the example configurations
[root@earth ~]# cp -r /usr/share/doc/xml2hostconf/example_conf/ubuntu/* /etc/xml2hostconf
You need to download some kernel files for the PXE installation. For example the i386 files for Fedora Core 9 and Ubuntu 8.04.
[root@earth ~]# grep -A 4 "<distribution " /tmp/t2/usr/share/doc/xml2hostconf/example_conf/ubuntu/main.xml <distribution id="ubuntu8.04"> <pxelinux> label install kernel /ubuntu-8.04.linux.<repl-arch/> append initrd=/ubuntu-8.04.initrd.<repl-arch/>.gz auto url=<repl-install-conf-file-url/> locale=en_EN console-setup/layoutcode=se netcfg/get_hostname= netcfg/choose_interface=eth0 <repl-extra-kernel-flags/> --
The kernel files to boot over PXE need be placed in /tftpboot
[user@fedora ~]$ wget -O /tmp/fedora-9-vmlinuz.i386 --quiet http://www.ftp.funet.fi/pub/mirrors/fedora.redhat.com/pub/fedora/linux/releases/9/Fedora/i386/os/images/pxeboot/vmlinuz [user@fedora ~]$ wget -O /tmp/fedora-9-initrd.img.i386 --quiet http://www.ftp.funet.fi/pub/mirrors/fedora.redhat.com/pub/fedora/linux/releases/9/Fedora/i386/os/images/pxeboot/initrd.img [user@fedora ~]$ su - Password: [root@fedora ~]# cp /tmp/fedora-9-vmlinuz.i386 /tmp/fedora-9-initrd.img.i386 /tftpboot/
[user@fedora ~]$ wget -O /tmp/ubuntu-8.10.vmlinuz.i386 --quiet http://ftp.sunet.se/pub/os/Linux/distributions/ubuntu/ubuntu/dists/hardy/main/installer-i386/current/images/netboot/ubuntu-installer/i386/vmlinuz [user@fedora ~]$ wget -O /tmp/ubuntu-8.10.initrd.gz.i386 --quiet http://ftp.sunet.se/pub/os/Linux/distributions/ubuntu/ubuntu/dists/hardy/main/installer-i386/current/images/netboot/ubuntu-installer/i386/initrd.gz [user@fedora ~]$ su - Password: [root@fedora ~]# cp /tmp/ubuntu-8.10.vmlinuz.i386 /tmp/ubuntu-8.10.initrd.gz.i386 /tftpboot/
The bootloader file is here specified as /pxelinux.0
[root@earth ~]# grep "pxelinux-file" /etc/xml2hostconf/main.xml <dhcp pxelinux-file="/pxelinux.0">
On both Fedora and Ubuntu the file pxelinux.0
is found at /usr/lib/syslinux/pxelinux.0
but we need to copy it to /tftpboot
.
[root@earth ~]# cp /usr/lib/syslinux/pxelinux.0 /tftpboot/
Now we need to adjust the firewall for the xml2hostconf server. We need to open up some ports for httpd, tftpd and dhcpd. On a Fedora machine, you do
[root@earth ~]# system-config-securitylevel-tui -q -p http:tcp -p https:tcp -p ssh:tcp -p tftp:udp -p bootps:udp
A good idea is to limit access for this machine to just computers on the same subnet. TODO: write documenation here about how to do that.
Now let us specify information for a client computer in /etc/xml2hostconf/main.xml
. First we need to know the MAC address of the client computer's network card.
This can found out by booting the client computer with a Linux live cd ( e.g. a Ubuntu cd ), and then opening a terminal window and typing
$ /sbin/ifconfig | grep HWadd eth0 Link encap:Ethernet HWaddr 00:00:1C:B5:F0:D3
Here we see that the MAC address is 00:00:1C:B5:F0:D3.
Alternatively we could have found out the same information by looking in the /var/log/messages
of a dhcp server if we let the client computer try to boot up with
a pxe network boot on the same subnet.
We also need to give the client computer a hostname and an IP address. In this example we give it the hostname "jupiter" and
the IP address 192.168.0.4. This matches the values in /etc/xml2hostconf/main.xml
.
[root@earth ~]# grep "<computer " /etc/xml2hostconf/main.xml <computer arch="i386" location="room A2:76" name="jupiter" IPv4-address="192.168.0.4" ethernet-hardware-address="00:00:1C:B5:F0:D3" pxe-boots="yes">
Now make sure your subnet IP settings match those found in /etc/xml2hostconf/main.xml
The subnet here is 192.168.0.0/25 and therefore the broadcast address is 192.168.0.127. The default gateway in the subnet is 192.168.0.1.
[root@earth ~]# grep "option broadcast-address" /etc/xml2hostconf/main.xml option broadcast-address 192.168.0.127; [root@earth ~]# grep "option routers" /etc/xml2hostconf/main.xml option routers 192.168.0.1;
The command you will be using is /usr/bin/xml2hostconf
. It understands these arguments:
xml2hostconf rpm
generate rpm packages and create repos
xml2hostconf deb
generate deb packages and create repos
xml2hostconf install-conf-file
generate kickstart and preseed files
xml2hostconf pxelinux
generate pxelinux files
xml2hostconf dhcp
generate the file /etc/dhcpd.conf
xml2hostconf validate
validate the configuration file /etc/xml2hostconf/main.xml
Tip | |
---|---|
A good idea is to frequently do "make validate" when you edit a configuration file. Then you know your configuration file follows the schema specified by the XML Schema file. |
Now you are ready to generate the files for the httpd, dhcpd and tftp daemons. Run these commands:
[root@earth ~]# xml2hostconf rpm && xml2hostconf install-conf-file && xml2hostconf pxelinux && xml2hostconf dhcp
Now you need to restart the dhcpd daemon.
[root@earth ~]# /etc/init.d/dhcpd restart
First make sure the client computer has a boot order in its BIOS where it first tries to PXE boot over the network. Then we need to place a trigger
file in the directory /var/cache/xml2hostconf/server/httpd_docroot/install/hosts_to_be_installed/
to make the clients kickstart/preseed file available for download.
[root@earth ~]# touch /var/cache/xml2hostconf/server/httpd_docroot/install/hosts_to_be_installed/jupiter.example.org
When you have setup the xml2hostconf correctly, the client computer will pxe boot up with the following message printed on screen.
Boot: Type "install" to install the computer "jupiter.example.org" ( data on harddrive will be lost ). Or just wait to boot from hard drive.
Ok, now type install
and the client will be installed.
The file /var/cache/xml2hostconf/server/httpd_docroot/install/hosts_to_be_installed/jupiter.example.org
will be removed when the kickstart/preseed file gets downloaded. In the processing phase of downloading the kickstart/preseed file the trigger file is moved to a temporary directory /var/cache/xml2hostconf/server/httpd_docroot/install/processing/
. If the install.cgi downloading script would fail in the middle, then the file /var/cache/xml2hostconf/server/httpd_docroot/install/processing/jupiter.example.org
would block further installations of jupiter, so you may have to erase such a file manually if that would happen.
If a client that's going to be installed and a install server doesn't share a common secret, there is no way to install the client securely if you can't trust the network. So providing the vmlinuz and initrd and kickstart file over the network is not recommended if your security demands are very high. You could though still use xml2hostconf to generate the files but transfering the boot medium in a more secure way ( e.g. going to the computer with an usb stick with the files, or going with the computer to a secure network and there PXE boot).
Second best if you still want to use PXE to install your computers is to open up for a one-time download restricted to the IP address of the client computer. This time frame is open as long there is a install trigger file i.e. /var/cache/xml2hostconf/server/httpd_docroot/install/hosts_to_be_installed/jupiter.example.org
. If a phony computer would download the install files the trigger file will be removed and such an event would be noticed be the xml2hostconf administrator because the real client would not be able to download the install files. An intruder would then have gained information about the clients configuration files, but if a password server ( e.g. kerberos server ) is used the intruder has no immediate way to log in to the client computer by way of the information he gained.
The configuration RPMs are protected on the xml2hostconf behind https and passwords ( i.e. htpasswd ). The installed client have
its own xml2hostconf repo on the xml2hostconf server with a password that is generated out of /dev/urandom
when the kickstart file gets downloaded. To make it even more secure you could change /dev/urandom
to /dev/random
but this has the disadvantage that reading from /dev/random
may block if there is not enough random entropy collected by the kernel.
[root@jupiter ~]# cat /etc/yum.repos.d/xml2hostconf.repo [xml2hostconf] name=xml2hostconf baseurl=https://jupiter.example.org:IXGxS6Gf0awyum307jrlADAw2kISaa@earth.example.org/xml2hostconf/repos/jupiter.example.org gpgcheck=0 enabled=1
Right now yum or actually the underlying python library urlgrabber has no verifying of the peer in https. Hopefully this feature will be implemented soon.
The main configuration file /etc/xml2hostconf/main.xml
is the file where all configuration data resides. All files to be included in the generated rpm/deb packages reside in subdirectories
of the directory /etc/xml2hostconf/shippingfiles
.
Warning | |
---|---|
Do not include files linked to shared libraries in a rpm package by means of /root/software/rpmdebs/rpmdeb/files/file ( xpath syntax ). The rpm software sees the libraries as dependencies and might give the generated rpm package problematic dependencies. For instance I managed to generate an uninstallable rpm package that had dependencies on some files that already were installed. The whole idea with xml2hostconf is to ship configuration files by means of rpm packages so this problem should not cause any trouble under normal usage ... |
The xml elements having a name starting with repl- will substituted with an appropriate text by xml2hostconf.
Table 1. explanation of some xml elements in /etc/xml2hostconf/main.xml
xpath | description |
---|---|
/root/software/rpmdebs/rpmdeb/files/file | represents a file that should be included in a generated rpm/deb package. The attribute |
/root/software/dhcp | text for dhcpd.conf |
/root/software/textsubsts/textsubst | defines a textsubstitution |
/root/software/distributions/distribution | defines a distribution ( i.e fc2, rh9 ... ) |
Example 1. main.xml example
The file /usr/share/doc/xml2hostconf/example_conf/ubuntu/main.xml
is an exampel of how the
main configuration /etc/xml2hostconf/main.xml
could look like.
<?xml version="1.0" encoding="UTF-8"?> <root> <hardware> <computers> <computer arch="i386" location="room A2:76" name="jupiter.example.org" IPv4-address="192.168.0.4" ethernet-hardware-address="00:00:1C:B5:F0:D3" pxe-boots="yes"> <config rpmdeb-ref="host-jupiter" distribution-ref="ubuntu8.04" extra-kernel-flags="" extra-pxelinux-cfg=""> <customize textsubst-ref="ubuntu-partitioning" type-ref="desktop"/> </config> <hard-drives> <hard-drive name="sda"/> </hard-drives> <computer-extrainfo/> <hw-support-history> <issue date="2004-09-03" comment="The cpu fan was broken. I replaced it."/> </hw-support-history> </computer> </computers> </hardware> <software xml2hostconf-server="earth.example.org"> <rpmdebs> <rpmdeb id="host-jupiter" release="1"> <dependencies> <dependency name="firefox"/> <dependency name="rhytmbox"/> <dependency name="testconf"/> </dependencies> <files> </files> <install-commands> <!-- Some deb packages need aske questions during installation. You can answer them in advance with the command "debconf-set-selections" from the packages debconf-utils . <install-command type="pre-install" cmdline="echo perlindex perlindex/removeindexonpurge boolean true | debconf-set-selections"/> --> </install-commands> </rpmdeb> <rpmdeb id="testconf" release="1"> <dependencies> </dependencies> <files> <file owner="root" group="root" permissions="600" path="/etc/testfile" type="copy-out-file"/> </files> <install-commands> </install-commands> </rpmdeb> </rpmdebs> <dhcp pxelinux-file="/pxelinux.0"> <![CDATA[ ddns-update-style none; default-lease-time 2592000; max-lease-time 2592000; option subnet-mask 255.255.255.128; option broadcast-address 192.168.0.127; option routers 192.168.0.1; option domain-name-servers ns.example.org; option domain-name "example.org"; option pxelinuxmagic code 208 = string; option pxelinuxconfigfile code 209 = text; option pxelinuxpathprefix code 210 = text; option pxelinuxreboottime code 211 = unsigned integer 32; # This tells the client to use the hostname in this file. use-host-decl-names on; ]]><repl-generated-hosts/> </dhcp> <pxelinux> <cfg> <repl-extra-pxelinux-cfg/> default local prompt 1 timeout 50 display <repl-pxelinux-msg/> label local localboot 0 label memtest kernel /memtest86+-1.26 <repl-distribution-install/> </cfg> <msg> <repl-print-mode text="yes" graphics="no" serial="yes"/>Found pxelinux config for the computer "<repl-hostname/>" <repl-print-mode text="no" graphics="no" serial="yes"/> Type "install" to install the computer "<repl-hostname/>" ( data on harddrive will be lost ). Or just wait to boot from hard drive. <repl-end-of-file/></msg> </pxelinux> <distributions> <distribution id="ubuntu8.04"> <pxelinux> label install kernel /ubuntu-8.04.linux.<repl-arch/> append initrd=/ubuntu-8.04.initrd.<repl-arch/>.gz auto url=<repl-install-conf-file-url/> locale=en_EN console-setup/layoutcode=se netcfg/get_hostname= netcfg/choose_interface=eth0 <repl-extra-kernel-flags/> -- </pxelinux> <install-conf-file><![CDATA[ d-i mirror/country string enter information manually d-i mirror/protocol string http d-i mirror/http/hostname string ftp.sunet.se d-i mirror/http/directory string /pub/os/Linux/distributions/ubuntu/ubuntu d-i mirror/http/proxy string d-i time/zone string Europe/Stockholm d-i clock-setup/utc boolean true ### Extra repositorys d-i apt-setup/local0/repository string https://]]><repl-hostname/>:<repl-url-password/><![CDATA[@earth.example.org/xml2hostconf/repos/deb/]]><repl-hostname/><![CDATA[/ ./ d-i apt-setup/local0/source boolean false d-i passwd/user-fullname string tmpuser d-i passwd/username string tmpuser d-i passwd/user-password password jRLEEfaWs2dsm d-i passwd/user-password-again password jRLEEfaWs2dsm ]]><repl-textsubst idref="ubuntu-partitioning"/><![CDATA[ grub-installer grub-installer/only_debian boolean true d-i grub-installer/bootdev string (hd0,0) tasksel tasksel/first multiselect ubuntu-desktop popularity-contest popularity-contest/participate boolean false ### Install extra packages d-i pkgsel/include string apt-transport-https inkscape d-i preseed/late_command string in-target apt-get update; in-target apt-get install -y --force-yes ]]><repl-rpmdeb/><![CDATA[ ; in-target apt-get dist-upgrade -y ### Finishing up the first stage install d-i finish-install/reboot_in_progress note ]]></install-conf-file> </distribution> </distributions> <textsubsts> <textsubst id="ubuntu-partitioning"> <default></default> <type id="desktop"> d-i partman-auto/disk string <repl-disk nr="1"/> d-i partman-auto/method string regular d-i partman-auto/expert_recipe string \ boot-root :: \ 100 100 100 ext3 \ $primary{ } $bootable{ } \ method{ format } format{ } \ use_filesystem{ } filesystem{ ext3 } \ mountpoint{ /boot } \ . \ 25000 25000 25000 ext3 \ $primary{ } \ method{ format } format{ } \ use_filesystem{ } filesystem{ ext3 } \ mountpoint{ / } \ . \ 2300 2300 2300 ext3 \ $primary{ } \ method{ format } format{ } \ use_filesystem{ } filesystem{ ext3 } \ mountpoint{ /var/cache/afs } \ . \ 500 10000 1000000000 ext3 \ method{ format } format{ } \ use_filesystem{ } filesystem{ ext3 } \ mountpoint{ /scratch } \ . \ 2048 2048 2048 linux-swap \ method{ swap } format{ } \ . d-i partman/confirm_write_new_label boolean true d-i partman/choose_partition select Finish partitioning and write changes to disk d-i partman/confirm boolean true </type> </textsubst> </textsubsts> </software> </root>
The schema to be followed is specified as XML Schema in /usr/lib/xml2hostconf/schema/main.xsd
<?xml version="1.0" encoding="UTF-8"?> <xs:schema xmlns:xs="http://www.w3.org/2001/XMLSchema" elementFormDefault="qualified"> <xs:simpleType name="rpmdeb-name"> <xs:restriction base="xs:string"> <xs:pattern value="[a-z,A-Z,0-9]+[a-z,A-Z,0-9,\-]*"/> </xs:restriction> </xs:simpleType> <xs:element name="root"> <xs:complexType> <xs:sequence> <xs:element ref="hardware"/> <xs:element ref="software"/> </xs:sequence> </xs:complexType> <xs:key name="distribution-key"> <xs:selector xpath="software/distributions/distribution"/> <xs:field xpath="@id"/> </xs:key> <xs:keyref name="distribution-ref" refer="distribution-key"> <xs:selector xpath="hardware/computers/computer/config"/> <xs:field xpath="@distribution-ref"/> </xs:keyref> <xs:key name="rpmdeb-key"> <xs:selector xpath="software/rpmdebs/rpmdeb"/> <xs:field xpath="@id"/> </xs:key> <xs:keyref name="rpmdeb-ref" refer="rpmdeb-key"> <xs:selector xpath="hardware/computers/computer/config"/> <xs:field xpath="@rpmdeb-ref"/> </xs:keyref> <xs:key name="textsubst-key"> <xs:selector xpath="software/textsubsts/textsubst"/> <xs:field xpath="@id"/> </xs:key> <xs:keyref name="textsubst-ref" refer="textsubst-key"> <xs:selector xpath="software/distributions/distribution/install-conf-file/repl-textsubst"/> <xs:field xpath="@idref"/> </xs:keyref> <xs:keyref name="textsubst-ref2" refer="textsubst-key"> <xs:selector xpath="hardware/computers/computer/config/customize"/> <xs:field xpath="@textsubst-ref"/> </xs:keyref> <xs:key name="type-key"> <xs:selector xpath="software/textsubsts/textsubst/type"/> <xs:field xpath="@id"/> </xs:key> <xs:keyref name="type-ref" refer="type-key"> <xs:selector xpath="hardware/computers/computer/config/customize"/> <xs:field xpath="@type-ref"/> </xs:keyref> </xs:element> <xs:element name="hardware"> <xs:complexType> <xs:sequence> <xs:element ref="computers"/> </xs:sequence> </xs:complexType> </xs:element> <xs:element name="computers"> <xs:complexType> <xs:sequence> <xs:element minOccurs="0" maxOccurs="unbounded" ref="computer"/> </xs:sequence> </xs:complexType> </xs:element> <xs:element name="computer"> <xs:complexType> <xs:sequence> <xs:element ref="config"/> <xs:element ref="hard-drives"/> <xs:element ref="computer-extrainfo"/> <xs:element ref="hw-support-history"/> </xs:sequence> <xs:attribute name="location" use="required"/> <xs:attribute name="name" use="required"/> <xs:attribute name="arch" use="required"/> <xs:attribute name="ethernet-hardware-address" use="required"/> <xs:attribute name="IPv4-address" use="required"/> <xs:attribute name="pxe-boots" use="required"> <xs:simpleType> <xs:restriction base="xs:token"> <xs:enumeration value="yes"/> <xs:enumeration value="no"/> <xs:enumeration value="not_checked"/> </xs:restriction> </xs:simpleType> </xs:attribute> <xs:attribute name="guarantee-expiration-date"/> </xs:complexType> </xs:element> <xs:element name="computer-extrainfo"> <xs:complexType> <xs:sequence> <xs:any processContents="lax" minOccurs="0" maxOccurs="unbounded" /> </xs:sequence> </xs:complexType> </xs:element> <xs:element name="config"> <xs:complexType> <xs:sequence> <xs:element minOccurs="0" maxOccurs="unbounded" ref="customize"/> </xs:sequence> <xs:attribute name="distribution-ref" use="required"/> <xs:attribute name="rpmdeb-ref" use="required" type="rpmdeb-name"/> <xs:attribute name="extra-kernel-flags"/> <xs:attribute name="extra-pxelinux-cfg"/> </xs:complexType> </xs:element> <xs:element name="customize"> <xs:complexType> <xs:attribute name="textsubst-ref" use="required"/> <xs:attribute name="type-ref" use="required"/> </xs:complexType> </xs:element> <xs:element name="hard-drives"> <xs:complexType> <xs:sequence> <xs:element maxOccurs="unbounded" ref="hard-drive"/> </xs:sequence> </xs:complexType> </xs:element> <xs:element name="hard-drive"> <xs:complexType> <xs:attribute name="name" use="required"> <xs:simpleType> <xs:restriction base="xs:token"> <xs:enumeration value="hda"/> <xs:enumeration value="hdb"/> <xs:enumeration value="hdc"/> <xs:enumeration value="hdd"/> <xs:enumeration value="hde"/> <xs:enumeration value="hdf"/> <xs:enumeration value="hdg"/> <xs:enumeration value="hdh"/> <xs:enumeration value="hdi"/> <xs:enumeration value="hdj"/> <xs:enumeration value="hdk"/> <xs:enumeration value="hdl"/> <xs:enumeration value="hdm"/> <xs:enumeration value="hdn"/> <xs:enumeration value="hdo"/> <xs:enumeration value="hdp"/> <xs:enumeration value="hdq"/> <xs:enumeration value="hdr"/> <xs:enumeration value="hds"/> <xs:enumeration value="hdt"/> <xs:enumeration value="sda"/> <xs:enumeration value="sdb"/> <xs:enumeration value="sdc"/> <xs:enumeration value="sdd"/> <xs:enumeration value="sde"/> <xs:enumeration value="sdf"/> <xs:enumeration value="sdg"/> <xs:enumeration value="sdh"/> <xs:enumeration value="sdi"/> <xs:enumeration value="sdj"/> <xs:enumeration value="sdk"/> <xs:enumeration value="sdl"/> <xs:enumeration value="sdm"/> <xs:enumeration value="sdn"/> <xs:enumeration value="sdo"/> <xs:enumeration value="sdp"/> <xs:enumeration value="sdq"/> <xs:enumeration value="sdr"/> <xs:enumeration value="sds"/> <xs:enumeration value="sdt"/> </xs:restriction> </xs:simpleType> </xs:attribute> </xs:complexType> </xs:element> <xs:element name="hw-support-history"> <xs:complexType> <xs:sequence> <xs:element minOccurs="0" maxOccurs="unbounded" ref="issue"/> </xs:sequence> </xs:complexType> </xs:element> <xs:element name="issue"> <xs:complexType> <xs:attribute name="comment" use="required"/> <xs:attribute name="date" use="required"/> </xs:complexType> </xs:element> <xs:element name="software"> <xs:complexType> <xs:sequence> <xs:element ref="rpmdebs"/> <xs:element ref="dhcp"/> <xs:element name="pxelinux"> <xs:complexType> <xs:sequence> <xs:element ref="cfg"/> <xs:element ref="msg"/> </xs:sequence> </xs:complexType> </xs:element> <xs:element ref="distributions"/> <xs:element ref="textsubsts"/> </xs:sequence> <xs:attribute name="xml2hostconf-server" use="required"/> </xs:complexType> </xs:element> <xs:element name="rpmdebs"> <xs:complexType> <xs:sequence> <xs:element minOccurs="0" maxOccurs="unbounded" ref="rpmdeb"/> </xs:sequence> </xs:complexType> </xs:element> <xs:element name="rpmdeb"> <xs:complexType> <xs:sequence> <xs:element ref="dependencies"/> <xs:element ref="files"/> <xs:element ref="install-commands"/> </xs:sequence> <xs:attribute name="id" use="required" type="rpmdeb-name"/> <xs:attribute name="release" use="required"/> <xs:attribute name="description"/> </xs:complexType> </xs:element> <xs:element name="dependencies"> <xs:complexType> <xs:sequence> <xs:element minOccurs="0" maxOccurs="unbounded" ref="dependency"/> </xs:sequence> </xs:complexType> </xs:element> <xs:element name="dependency"> <xs:complexType> <xs:attribute name="name" use="required"/> </xs:complexType> </xs:element> <xs:element name="files"> <xs:complexType> <xs:sequence> <xs:element minOccurs="0" maxOccurs="unbounded" ref="file"/> </xs:sequence> </xs:complexType> </xs:element> <xs:element name="file"> <xs:complexType> <xs:attribute name="owner" use="required"/> <xs:attribute name="group" use="required"/> <xs:attribute name="permissions" use="required"/> <xs:attribute name="path" use="required"/> <xs:attribute name="type" use="required"> <xs:simpleType> <xs:restriction base="xs:token"> <xs:enumeration value="file"/> <xs:enumeration value="dir"/> <xs:enumeration value="copy-out-file"/> </xs:restriction> </xs:simpleType> </xs:attribute> </xs:complexType> </xs:element> <xs:element name="install-commands"> <xs:complexType> <xs:sequence> <xs:element minOccurs="0" maxOccurs="unbounded" ref="install-command"/> </xs:sequence> </xs:complexType> </xs:element> <xs:element name="install-command"> <xs:complexType> <xs:attribute name="type" use="required"> <xs:simpleType> <xs:restriction base="xs:token"> <xs:enumeration value="pre-install"/> <xs:enumeration value="post-install"/> <xs:enumeration value="pre-uninstall"/> <xs:enumeration value="post-uninstall"/> </xs:restriction> </xs:simpleType> </xs:attribute> <xs:attribute name="cmdline" use="required"/> </xs:complexType> </xs:element> <xs:element name="dhcp"> <xs:complexType mixed="true"> <xs:sequence> <xs:element ref="repl-generated-hosts"/> </xs:sequence> <xs:attribute name="pxelinux-file" use="required"/> </xs:complexType> </xs:element> <xs:element name="repl-generated-hosts"> <xs:complexType/> </xs:element> <xs:element name="cfg"> <xs:complexType mixed="true"> <xs:choice minOccurs="0" maxOccurs="unbounded"> <xs:element ref="repl-extra-pxelinux-cfg"/> <xs:element ref="repl-pxelinux-msg"/> <xs:element ref="repl-distribution-install"/> </xs:choice> </xs:complexType> </xs:element> <xs:element name="repl-extra-pxelinux-cfg"> <xs:complexType/> </xs:element> <xs:element name="repl-pxelinux-msg"> <xs:complexType/> </xs:element> <xs:element name="repl-distribution-install"> <xs:complexType/> </xs:element> <xs:element name="msg"> <xs:complexType mixed="true"> <xs:choice minOccurs="0" maxOccurs="unbounded"> <xs:element ref="repl-set-colors"/> <xs:element ref="repl-display-graphics"/> <xs:element ref="repl-end-of-file"/> <xs:element ref="repl-clear-screen"/> <xs:element ref="repl-return-to-text-mode"/> <xs:element ref="repl-print-mode"/> <xs:element ref="repl-hostname"/> </xs:choice> </xs:complexType> </xs:element> <xs:element name="repl-set-colors"> <xs:complexType> <xs:attribute name="foreground" use="required"> <xs:simpleType> <xs:restriction base="xs:token"> <xs:enumeration value="black"/> <xs:enumeration value="dark blue"/> <xs:enumeration value="dark green"/> <xs:enumeration value="dark cyan"/> <xs:enumeration value="dark red"/> <xs:enumeration value="dark purple"/> <xs:enumeration value="brown"/> <xs:enumeration value="light grey"/> <xs:enumeration value="dark grey"/> <xs:enumeration value="bright blue"/> <xs:enumeration value="bright green"/> <xs:enumeration value="bright cyan"/> <xs:enumeration value="bright red"/> <xs:enumeration value="bright purple"/> <xs:enumeration value="yellow"/> <xs:enumeration value="white"/> </xs:restriction> </xs:simpleType> </xs:attribute> <xs:attribute name="background" use="required"> <xs:simpleType> <xs:restriction base="xs:token"> <xs:enumeration value="black"/> <xs:enumeration value="dark blue"/> <xs:enumeration value="dark green"/> <xs:enumeration value="dark cyan"/> <xs:enumeration value="dark red"/> <xs:enumeration value="dark purple"/> <xs:enumeration value="brown"/> <xs:enumeration value="light grey"/> <xs:enumeration value="dark grey"/> <xs:enumeration value="bright blue"/> <xs:enumeration value="bright green"/> <xs:enumeration value="bright cyan"/> <xs:enumeration value="bright red"/> <xs:enumeration value="bright purple"/> <xs:enumeration value="yellow"/> <xs:enumeration value="white"/> </xs:restriction> </xs:simpleType> </xs:attribute> </xs:complexType> </xs:element> <xs:element name="repl-display-graphics"> <xs:complexType> <xs:attribute name="file" use="required"/> </xs:complexType> </xs:element> <xs:element name="repl-end-of-file"> <xs:complexType/> </xs:element> <xs:element name="repl-clear-screen"> <xs:complexType/> </xs:element> <xs:element name="repl-return-to-text-mode"> <xs:complexType/> </xs:element> <xs:element name="repl-print-mode"> <xs:complexType> <xs:attribute name="graphics" use="required"> <xs:simpleType> <xs:restriction base="xs:token"> <xs:enumeration value="yes"/> <xs:enumeration value="no"/> </xs:restriction> </xs:simpleType> </xs:attribute> <xs:attribute name="text" use="required"> <xs:simpleType> <xs:restriction base="xs:token"> <xs:enumeration value="yes"/> <xs:enumeration value="no"/> </xs:restriction> </xs:simpleType> </xs:attribute> <xs:attribute name="serial" use="required"> <xs:simpleType> <xs:restriction base="xs:token"> <xs:enumeration value="yes"/> <xs:enumeration value="no"/> </xs:restriction> </xs:simpleType> </xs:attribute> </xs:complexType> </xs:element> <xs:element name="repl-hostname"> <xs:complexType/> </xs:element> <xs:element name="distributions"> <xs:complexType> <xs:sequence> <xs:element minOccurs="0" maxOccurs="unbounded" ref="distribution"/> </xs:sequence> </xs:complexType> </xs:element> <xs:element name="distribution"> <xs:complexType> <xs:sequence> <xs:element name="pxelinux"> <xs:complexType mixed="true"> <xs:choice minOccurs="0" maxOccurs="unbounded"> <xs:element ref="repl-install-conf-file-url"/> <xs:element ref="repl-arch"/> <xs:element ref="repl-extra-kernel-flags"/> </xs:choice> </xs:complexType> </xs:element> <xs:element ref="install-conf-file"/> </xs:sequence> <xs:attribute name="id" use="required"/> </xs:complexType> </xs:element> <xs:element name="repl-install-conf-file-url"> <xs:complexType/> </xs:element> <xs:element name="repl-arch"> <xs:complexType/> </xs:element> <xs:element name="repl-extra-kernel-flags"> <xs:complexType/> </xs:element> <xs:element name="install-conf-file"> <xs:complexType mixed="true"> <xs:choice minOccurs="0" maxOccurs="unbounded"> <xs:element ref="repl-rpmdeb"/> <xs:element ref="repl-arch"/> <xs:element ref="repl-url-password"/> <xs:element ref="repl-hostname"/> <xs:element ref="repl-textsubst"/> </xs:choice> </xs:complexType> </xs:element> <xs:element name="repl-rpmdeb"> <xs:complexType/> </xs:element> <xs:element name="repl-url-password"> <xs:complexType/> </xs:element> <xs:element name="repl-textsubst"> <xs:complexType> <xs:attribute name="idref" use="required"/> </xs:complexType> </xs:element> <xs:element name="textsubsts"> <xs:complexType> <xs:sequence> <xs:element minOccurs="0" maxOccurs="unbounded" ref="textsubst"/> </xs:sequence> </xs:complexType> </xs:element> <xs:element name="textsubst"> <xs:complexType> <xs:sequence> <xs:element ref="default"/> <xs:element minOccurs="0" maxOccurs="unbounded" ref="type"/> </xs:sequence> <xs:attribute name="id" use="required"/> </xs:complexType> </xs:element> <xs:element name="default" type="xs:string"/> <xs:element name="type"> <xs:complexType mixed="true"> <xs:sequence> <xs:element minOccurs="0" maxOccurs="unbounded" ref="repl-disk"/> </xs:sequence> <xs:attribute name="id" use="required"/> </xs:complexType> </xs:element> <xs:element name="repl-disk"> <xs:complexType> <xs:attribute name="nr" use="required" type="xs:integer"/> </xs:complexType> </xs:element> </xs:schema>
Here comes some examples of how the generated output may look like. They were generated out of the example configuration /usr/share/doc/xml2hostconf/example_conf/ubuntu
[root@earth ~]# cp -r /usr/share/doc/xml2hostconf/example_conf/ubuntu/* /etc/xml2hostconf
[root@earth ~]# /usr/bin/xml2hostconf dhcp
Example of generated /etc/dhcpd.conf
ddns-update-style none; default-lease-time 2592000; max-lease-time 2592000; option subnet-mask 255.255.255.128; option broadcast-address 192.168.0.127; option routers 192.168.0.1; option domain-name-servers ns.example.org; option domain-name "example.org"; option pxelinuxmagic code 208 = string; option pxelinuxconfigfile code 209 = text; option pxelinuxpathprefix code 210 = text; option pxelinuxreboottime code 211 = unsigned integer 32; # This tells the client to use the hostname in this file. use-host-decl-names on; group { filename "/pxelinux.0"; if exists dhcp-parameter-request-list { # Always send the PXELINUX options (specified in hexadecimal) option dhcp-parameter-request-list = concat(option dhcp-parameter-request-list,d0,d1,d2,d3); } option pxelinuxmagic f1:00:74:7e; option pxelinuxpathprefix "/"; option pxelinuxreboottime 0; host jupiter.example.org { hardware ethernet 00:00:1C:B5:F0:D3; fixed-address 192.168.0.4; option pxelinuxconfigfile "xml2hostconf/pxelinux/pxelinux.cfg/01-00-00-1C-B5-F0-D3"; } }
[root@earth ~]# /usr/bin/xml2hostconf pxelinux
Here is a example of a pxelinux configuration file: /tftpboot/xml2hostconf/pxelinux/pxelinux.cfg/01-00-00-1C-B5-F0-D3
default local prompt 1 timeout 50 display /xml2hostconf/pxelinux/msg/jupiter.example.org.msg label local localboot 0 label memtest kernel /memtest86+-1.26 label install kernel /ubuntu-8.04.linux.i386 append initrd=/ubuntu-8.04.initrd.i386.gz auto url=http://earth.example.org/xml2hostconf-cgi-bin/install.cgi?hostname=jupiter.example.org locale=en_EN console-setup/layoutcode=se netcfg/get_hostname= netcfg/choose_interface=eth0 --
Here is a example of a preseed file: /var/cache/xml2hostconf/server/httpd_docroot/install/conf/192.168.0.4-jupiter.example.org
<?xml version="1.0" encoding="UTF-8"?> <root> d-i mirror/country string enter information manually d-i mirror/protocol string http d-i mirror/http/hostname string ftp.sunet.se d-i mirror/http/directory string /pub/os/Linux/distributions/ubuntu/ubuntu d-i mirror/http/proxy string d-i time/zone string Europe/Stockholm d-i clock-setup/utc boolean true ### Extra repositorys d-i apt-setup/local0/repository string https://jupiter.example.org:<repl-url-password/>@earth.example.org/xml2hostconf/repos/deb/jupiter.example.org/ ./ d-i apt-setup/local0/source boolean false d-i passwd/user-fullname string tmpuser d-i passwd/username string tmpuser d-i passwd/user-password password jRLEEfaWs2dsm d-i passwd/user-password-again password jRLEEfaWs2dsm d-i partman-auto/disk string sda d-i partman-auto/method string regular d-i partman-auto/expert_recipe string \ boot-root :: \ 100 100 100 ext3 \ $primary{ } $bootable{ } \ method{ format } format{ } \ use_filesystem{ } filesystem{ ext3 } \ mountpoint{ /boot } \ . \ 25000 25000 25000 ext3 \ $primary{ } \ method{ format } format{ } \ use_filesystem{ } filesystem{ ext3 } \ mountpoint{ / } \ . \ 2300 2300 2300 ext3 \ $primary{ } \ method{ format } format{ } \ use_filesystem{ } filesystem{ ext3 } \ mountpoint{ /var/cache/afs } \ . \ 500 10000 1000000000 ext3 \ method{ format } format{ } \ use_filesystem{ } filesystem{ ext3 } \ mountpoint{ /scratch } \ . \ 2048 2048 2048 linux-swap \ method{ swap } format{ } \ . d-i partman/confirm_write_new_label boolean true d-i partman/choose_partition select Finish partitioning and write changes to disk d-i partman/confirm boolean true grub-installer grub-installer/only_debian boolean true d-i grub-installer/bootdev string (hd0,0) tasksel tasksel/first multiselect ubuntu-desktop popularity-contest popularity-contest/participate boolean false ### Install extra packages d-i pkgsel/include string apt-transport-https inkscape d-i preseed/late_command string in-target apt-get update; in-target apt-get install -y --force-yes host-jupiter ; in-target apt-get dist-upgrade -y ### Finishing up the first stage install d-i finish-install/reboot_in_progress note </root>
When the client fetches this file, the install.cgi will remove the xml and it will replace xml element "repl-url-password" with a newly generated password.
[root@earth ~]# /usr/bin/xml2hostconf rpm /etc/xml2hostconf/main.xml validates Executing(%prep): /bin/sh -e /var/tmp/rpm-tmp.27263 + umask 022 + cd /var/cache/xml2hostconf/server/rpm_topdir/BUILD + cd /var/cache/xml2hostconf/server/rpm_topdir/BUILD + rm -rf host-jupiter-1.0 + /bin/mkdir -p host-jupiter-1.0 + cd host-jupiter-1.0 + exit 0 Executing(%install): /bin/sh -e /var/tmp/rpm-tmp.27263 + umask 022 + cd /var/cache/xml2hostconf/server/rpm_topdir/BUILD + cd host-jupiter-1.0 + rm -rf /var/cache/xml2hostconf/server/httpd_docroot/rpm_buildroot + mkdir -p /var/cache/xml2hostconf/server/httpd_docroot/rpm_buildroot/var/cache/xml2hostconf/client/copy_out_files/host-jupiter + /usr/lib/rpm/brp-compress + /usr/lib/rpm/brp-strip + /usr/lib/rpm/brp-strip-static-archive + /usr/lib/rpm/brp-strip-comment-note Processing files: host-jupiter-1.0-1 Checking for unpackaged file(s): /usr/lib/rpm/check-files /var/cache/xml2hostconf/server/httpd_docroot/rpm_buildroot Wrote: /var/cache/xml2hostconf/server/httpd_docroot/rpm/noarch/host-jupiter-1.0-1.noarch.rpm Executing(%prep): /bin/sh -e /var/tmp/rpm-tmp.27263 + umask 022 + cd /var/cache/xml2hostconf/server/rpm_topdir/BUILD + cd /var/cache/xml2hostconf/server/rpm_topdir/BUILD + rm -rf testconf-1.0 + /bin/mkdir -p testconf-1.0 + cd testconf-1.0 + exit 0 Executing(%install): /bin/sh -e /var/tmp/rpm-tmp.27263 + umask 022 + cd /var/cache/xml2hostconf/server/rpm_topdir/BUILD + cd testconf-1.0 + rm -rf /var/cache/xml2hostconf/server/httpd_docroot/rpm_buildroot + mkdir -p /var/cache/xml2hostconf/server/httpd_docroot/rpm_buildroot/var/cache/xml2hostconf/client/copy_out_files/testconf + /usr/bin/install -D /etc/xml2hostconf/shippingfiles/testconf/etc/testfile /var/cache/xml2hostconf/server/httpd_docroot/rpm_buildroot//var/cache/xml2hostconf/client/copy_out_files/testconf/etc/testfile + /usr/lib/rpm/brp-compress + /usr/lib/rpm/brp-strip + /usr/lib/rpm/brp-strip-static-archive + /usr/lib/rpm/brp-strip-comment-note Processing files: testconf-1.0-1 Requires(interp): /bin/sh /bin/sh /bin/sh /bin/sh Requires(rpmlib): rpmlib(CompressedFileNames) <= 3.0.4-1 rpmlib(PayloadFilesHavePrefix) <= 4.0-1 Requires(pre): /bin/sh Requires(post): /bin/sh Requires(preun): /bin/sh Requires(postun): /bin/sh Checking for unpackaged file(s): /usr/lib/rpm/check-files /var/cache/xml2hostconf/server/httpd_docroot/rpm_buildroot Wrote: /var/cache/xml2hostconf/server/httpd_docroot/rpm/noarch/testconf-1.0-1.noarch.rpm 2/2 - host-jupiter-1.0-1.noarch.rpm Saving Primary metadata Saving file lists metadata Saving other metadata
[root@earth ~]# ls -1 /var/cache/xml2hostconf/server/httpd_docroot/rpm/noarch/ host-jupiter-1.0-1.noarch.rpm testconf-1.0-1.noarch.rpm
/var/cache/xml2hostconf/server/httpd_docroot/rpm/noarch/
[root@earth ~]# /usr/bin/xml2hostconf deb /etc/xml2hostconf/main.xml validates dpkg-deb: building package `host-jupiter' in `/var/cache/xml2hostconf/server/httpd_docroot/deb/host-jupiter.deb'. dpkg-deb: building package `testconf' in `/var/cache/xml2hostconf/server/httpd_docroot/deb/testconf.deb'. ** Packages in archive but missing from override file: ** host-jupiter testconf Wrote 2 entries to output Packages file.
The generated configuration DEB packages are placed in the directory /var/cache/xml2hostconf/server/httpd_docroot/deb
[root@earth ~]# ls -1 /var/cache/xml2hostconf/server/httpd_docroot/deb/ host-jupiter.deb testconf.deb