diff options
Diffstat (limited to 'pxe_wizard/drakpxe.old')
-rwxr-xr-x | pxe_wizard/drakpxe.old | 516 |
1 files changed, 516 insertions, 0 deletions
diff --git a/pxe_wizard/drakpxe.old b/pxe_wizard/drakpxe.old new file mode 100755 index 00000000..e055b6c1 --- /dev/null +++ b/pxe_wizard/drakpxe.old @@ -0,0 +1,516 @@ +#!/usr/bin/perl +# +# François Pons <fpons@mandrakesoft.com> +# +# Copyright 2003 MandrakeSoft +# +# This program is free software; you can redistribute it and/or modify +# it under the terms of the GNU General Public License version 2, as +# published by the Free Software Foundation. +# +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU General Public License for more details. +# +# You should have received a copy of the GNU General Public License +# along with this program; if not, write to the Free Software +# Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. +# + + +use lib qw(/usr/lib/libDrakX); + +use standalone; #- warning, standalone must be loaded very first, for 'explanations' + +use common; +use interactive; +use network; +use log; +use c; +use network::netconnect; + +$::isInstall and die "Not supported during install.\n"; + +$::Wizard_pix_up = "wiz_drakgw.png"; #- to change ? keep existing one, nobody will see (too late) ;-) +$::direct = grep { /-direct/ } @ARGV; + + +# +#my $sysconf_network = "/etc/sysconfig/network"; +#my $sysconf_dhcpd = "/etc/sysconfig/dhcpd"; +#my $rc_firewall_generic = "/etc/rc.d/rc.firewall"; +#my $rc_firewall_drakgw = "/etc/rc.d/rc.firewall.inet_sharing"; +#my $rc_firewall_24 = "/etc/rc.d/rc.firewall.inet_sharing-2.4"; +#my $masq_file = "/etc/shorewall/masq"; +#my $cups_conf = "/etc/cups/cupsd.conf"; +# +#my $shorewall = network::shorewall::read(); +# +#- get network configuration. +my $netc = {}; +my $intf = {}; +network::read_all_conf('', $netc, $intf); + +my $in = 'interactive'->vnew('su'); +$::Wizard_title = N("PXE Server Configuration"); + +!$::isEmbedded && $in->isa('interactive::gtk') and $::isWizard = 1; + +#pur_gtk_mode() if $::isEmbedded && $in->isa('interactive::gtk'); + +sub sys { system(@_) == 0 or log::l("[drakpxe] Warning, sys failed for $_[0]") } + +sub outpend { + log::explanations("modified file $_[0]"); + my $f = shift; local *F; open F, ">>$f" or die "outpend in file $f failed: $!\n"; print F foreach @_; +} + +sub start_daemons () { + log::explanations("Starting daemons"); + + system("/etc/rc.d/init.d/dhcpd status >/dev/null") == 0 and sys("/etc/rc.d/init.d/dhcpd stop"); + + sys("/etc/rc.d/init.d/$_ start >/dev/null"), sys("/sbin/chkconfig --level 345 $_ on") foreach 'httpd', 'dhcpd'; +} + +sub stop_daemons () { + log::explanations("Stopping daemons"); + foreach (qw(dhcpd httpd)) { + system("/etc/rc.d/init.d/$_ status >/dev/null 2>/dev/null") == 0 and sys("/etc/rc.d/init.d/$_ stop"); + } + sys("/sbin/chkconfig --level 345 $_ off") foreach 'dhcpd', 'httpd'; +} + +my $wait_configuring; + +sub quit_global { + my ($in, $exitcode) = @_; + $in->exit($exitcode); + goto begin +} + +sub fatal_quit ($) { + log::l("[drakpxe] FATAL: $_[0]"); + undef $wait_configuring; + $in->ask_warn('', $_[0]); + quit_global($in, -1); +} + +#my ($kernel_version) = c::kernel_version() =~ /(...)/; +#log::l("[drakgw] kernel_version $kernel_version"); +# +#$kernel_version >= 2.4 or fatal_quit(N("Sorry, we support only 2.4 kernels.")); + +begin: + +#- ********************************** +#- * 0th step: verify if we have multiple network interface. + +$::Wizard_no_previous = 1; + +$::direct or $in->ask_okcancel(N("Installation Server Configuration"), +N("You are about to configure your computer to install a PXE server as a DHCP server +and a TFTP server to build an installation server. +With that feature, other computers on your local network will be installable using this computer as source. + +Make sure you have configured your Network/Internet access using drakconnect before going any further. + +Note: you need a dedicated Network Adapter to set up a Local Area Network (LAN)."), 1) or quit_global($in, 0); + +undef $::Wizard_no_previous; + + +#- ********************************** +#- * 1st step: verify if we have multiple network interface. + +step_check_intf: + +my @intf = grep { exists $_->{NETWORK} } map { + unless ($_->{NETWORK}) { + foreach my $s (split "\n", `route`) { + print STDERR "$s\n"; + $s =~ /^(\S+)\s+\S+\s+$_->{NETMASK}\s+.*$_->{DEVICE}/ and $_->{NETWORK} = $1; + } + } $_ } values %$intf; +if (@intf < 1) { + #- no interface already configured found, ask user to configure. + $in->ask_warn(N("No network adapter on your system!"), + N("No ethernet network adapter has been detected on your system. Please run the hardware configuration tool.")); + quit_global($in, 0); +} elsif (@intf > 1) { + #- there are more than one interface, we need to choose one of them. + @intf = $in->ask_from_listf(N("Choose the network interface"), + N("Please choose which network interface will be used for the dhcp server."), + sub { N("Interface %s (on network %s)", $_[0]{DEVICE}, $_[0]{NETWORK}) }, + \@intf, + ) or goto begin; +} + + +#- ********************************** +#- * 3rd step: select installation directory to be used (if not present, next step +#- will be creation and copy from existing one). + +step_ip_range: + +#- read current configuration, or create a default suitable automatically. +my $dhcpd_conf = parse_dhcpd_conf("/etc/dhcpd.conf", {}, $netc, $intf[0]); + +#- get back default of ip. +my $pool; +foreach (@{$dhcpd_conf->{network}{pool}}) { + exists $_->{allow}{$dhcpd_conf->{class_PXE}} and $pool = $_, last; +} +my ($start_ip, $end_ip) = @{$pool || { start_ip => join('.', (split '\.', $intf[0]{NETWORK})[0..2], 16), + end_ip => join('.', (split '\.', $intf[0]{NETWORK})[0..2], 253) }}{qw(start_ip end_ip)}; + +#- it become too complicated to handle address range, so ask user directly. +$in->ask_from('DHCP Server Configuration', + N("The DHCP server will allow other computer to boot using PXE in the given range of address. + +The network address is %s using a netmask of %s. + +", @{$intf[0]}{qw(NETWORK NETMASK)}), [ { label => N("The DHCP start ip"), val => \$start_ip, type => 'entry' }, + { label => N("The DHCP end ip"), val => \$end_ip, type => 'entry' }, ]) + or goto begin; + + +#- ********************************** +#- * 3rd step: select installation directory to be used (if not present, next step +#- will be creation and copy from existing one). + +step_install_dir: + +my $dir = "/export"; #- TODO change according configuration? + +$in->ask_from('Choose the installation image directory', + N("Please indicate where the installation image will be available. + +If you do not have an existing directory, please copy the CD or DVD contents. + +"), + [ { label => N("Installation image directory"), val => \$dir, type => 'entry' }, ]) + or goto step_ip_range; + +unless (-d $dir && -e "$dir/VERSION" && -d "$dir/isolinux" && -d "$dir/Mandrake/base") { + $in->ask_warn(N("No image found"), + N("No CD or DVD image found, please copy the installation program and rpm files.")); + goto step_install_dir; +} + +#- ********************************** +#- * 4st step: ask user for auto installation file. + +step_auto_install: + +my $auto_inst_cfg = "Mandrake/base/auto_inst.cfg"; #- TODO change according configuration? +-e "$dir/$auto_inst_cfg" or $auto_inst_cfg = ''; + +$in->ask_from('Choose auto installation', + N("Please indicate where the auto_install.cfg file is located. + +Leave it blank if you do not want to set up automatic installation mode. + +"), + [ { label => N("Location of auto_install.cfg file"), val => \$auto_inst_cfg, type => 'entry' }, ]) + or goto step_install_dir; + +#- now install packages... +my %rpm2file = ('dhcp-server' => '/usr/sbin/dhcpd', + 'pxe' => '/usr/sbin/pxe', + 'tftp-server' => '/usr/sbin/in.tftpd', + if_(! -x '/usr/sbin/httpd' && ! -x '/usr/sbin/httpd-perl', 'apache2' => '/usr/sbin/httpd2')); + +#- first: try to install all in one step +my @needed_to_install = grep { !-e $rpm2file{$_} } keys %rpm2file; +@needed_to_install and $in->do_pkgs->install(@needed_to_install); +#- second: try one by one if failure detected +if (any { !-e $rpm2file{$_} } keys %rpm2file) { + foreach (keys %rpm2file) { + -e $rpm2file{$_} or $in->do_pkgs->install($_); + -e $rpm2file{$_} or fatal_quit(N("Problems installing package %s", $_)); + } +} + +#- check if a pool already exist allowing PXE, else create one wich will be correct. +if ($pool) { + @$pool{qw(start_ip end_ip)} = ($start_ip, $end_ip); +} else { + $pool = { start_ip => $start_ip, end_ip => $end_ip }; + foreach (keys %{$dhcpd_conf->{class}}) { + $pool->{$_ eq $dhcpd_conf->{class_PXE} || $_ eq 'Etherboot' ? 'allow' : 'deny'}{$_} = undef; + } + push @{$dhcpd_conf->{network}{pool}}, $pool; +} +build_dhcpd_conf($dhcpd_conf, "/etc/dhcpd.conf"); + +#- make kernel and initrd available for initrd. +mkdir "/var/lib/tftpboot/PXEClient/images"; +sys("cp", "-af", "$dir/isolinux/alt0", "/var/lib/tftpboot/PXEClient/images/"); + +my $pxelinux_cfg = parse_pxelinux_cfg("/var/lib/tftpboot/PXEClient/pxelinux.cfg/default"); +my $label; +foreach my $i (0..99) { + $label = undef; + foreach my $e (@{$pxelinux_cfg->{entry}}) { + $e->{label} eq "halt$i" and $label = "halt$i", last; + } + defined $label or $label = "halt$i", last; +} +my $server = $intf[0]{IPADDR} || $netc->{HOSTNAME}; +push @{$pxelinux_cfg->{entry}}, { label => $label, + kernel => "images/alt0/vmlinuz", + append => "initrd=images/alt0/all.rdz ramdisk=32000 vga=788 ".($auto_inst_cfg ? "kickstart=$auto_inst_cfg " : "")."automatic=method:http,network:dhcp,interface:eth0,dns:$netc->{dnsServer},server:$server,directory:$dir root=/dev/ram3" }; +build_pxelinux_cfg($pxelinux_cfg, "/var/lib/tftpboot/PXEClient/pxelinux.cfg/default"); + +#- make directory available for httpd. +log::explanations("Linking $dir in /var/www/html to make it available"); +system "mkdir", "-p", "/var/www/html/$dir"; +rmdir "/var/www/html/$dir"; +symlink $dir, "/var/www/html/$dir"; + +stop_daemons(); +start_daemons(); + +#- sub for reading/writing dhcpd.conf and pxelinux.cfg/default... +sub parse_dhcpd_conf { + my ($file, undef, $netc, $intf) = @_; + my (%dhcpd_conf, $pool); + local (*F, $_); + + #- fake reading configuration from dhcpd.conf file which is really too complex for this tools. + $dhcpd_conf{class_PXE} = 'PXE'; + $dhcpd_conf{class} = { PXE => undef, Etherboot => undef, known => undef }; + add2hash($dhcpd_conf{network} = { pool => [] }, $intf); + add2hash($dhcpd_conf{network}, $netc); + + if (open F, $file) { + while (<F>) { + if (/^\s*pool\s*{/ .. /}/) { + /^\s*range\s+(\S+)\s+(\S+)\s*;/ and ($pool->{start_ip}, $pool->{end_ip}) = ($1, $2); + /^\s*(allow|deny)\s+members\s+of\s+"([^"]*)"\s*;/ and $pool->{$1}{$2} = undef; + /}/ and do { push @{$dhcpd_conf{network}{pool}}, $pool; $pool = undef }; + } + } + close F; + } + + \%dhcpd_conf; +} + +sub build_dhcpd_conf { + my ($dhcpd_conf, $file) = @_; + local *F; + my $server = $dhcpd_conf->{network}{IPADDR} || $dhcpd_conf->{network}{HOSTNAME}; + open F, ">$file" or return; + log::explanations("Modified file $file"); + print F qq(# for explanation in french go to : http://www.delafond.org/traducmanfr/man/man5/dhcpd.conf.5.html +ddns-update-style none; +allow booting; +allow bootp; + +# Your dhcp server is not master on your network ! +#not authoritative; +# Your dhcpd server is master on your network ! +#authoritative; +not authoritative; + +#Interface where dhcpd is active +DHCPD_INTERFACE = "$dhcpd_conf->{network}{DEVICE}"; + +# Definition of PXE-specific options +# Code 1: Multicast IP address of bootfile +# Code 2: UDP port that client should monitor for MTFTP responses +# Code 3: UDP port that MTFTP servers are using to listen for MTFTP requests +# Code 4: Number of secondes a client must listen for activity before trying +# to start a new MTFTP transfer +# Code 5: Number of secondes a client must listen before trying to restart +# a MTFTP transfer + +# define Option for the PXE class +option space PXE; +option PXE.mtftp-ip code 1 = ip-address; +option PXE.mtftp-cport code 2 = unsigned integer 16; +option PXE.mtftp-sport code 3 = unsigned integer 16; +option PXE.mtftp-tmout code 4 = unsigned integer 8; +option PXE.mtftp-delay code 5 = unsigned integer 8; +option PXE.discovery-control code 6 = unsigned integer 8; +option PXE.discovery-mcast-addr code 7 = ip-address; + +#Define options for pxelinux +option space pxelinux; +option pxelinux.magic code 208 = string; +option pxelinux.configfile code 209 = text; +option pxelinux.pathprefix code 210 = text; +option pxelinux.reboottime code 211 = unsigned integer 32; +site-option-space "pxelinux"; +# These lines should be customized to your setup +#option pxelinux.configfile "configs/common"; +#option pxelinux.pathprefix "/pxelinux/files/"; +#filename "/pxelinux/pxelinux.bin"; + +option pxelinux.magic f1:00:74:7e; +option pxelinux.reboottime 30; +#if exists dhcp-parameter-request-list { + # Always send the PXELINUX options +# append dhcp-parameter-request-list 208, 209, 210, 211; +# append dhcp-parameter-request-list 208,211; +# } + +#Class that determine the options for Etherboot 5.x requests +class "Etherboot" { + +#if The vendor-class-identifier equal Etherboot-5.0 +match if substring (option vendor-class-identifier, 0, 9) = "Etherboot"; + +# filename define the file retrieve by the client, there nbgrub +# our tftp is chrooted so is just the path to the file +filename "/etherboot/nbgrub"; + +#Used by etherboot to detect a valid pxe dhcp server +option vendor-encapsulated-options 3c:09:45:74:68:65:72:62:6f:6f:74:ff; + +# Set the "vendor-class-identifier" field to "PXEClient" in dhcp answer +# if this field is not set the pxe client will ignore the answer ! +option vendor-class-identifier "Etherboot"; + +vendor-option-space PXE; +option PXE.mtftp-ip 0.0.0.0; + +# IP of you TFTP server +next-server $server; +} + + +# create the Class PXE +class "PXE" { +# if the "vendor-class-identifier" is set to "PXEClient" in the client dhcp request +match if substring(option vendor-class-identifier, 0, 9) = "PXEClient"; + +# filename define the file retrieve by the client, there pxelinux.0 +# our tftp is chrooted so is just the path to the file +# If you prefer use grub, use pxegrub compiled for your ethernet card. +#filename "/PXEClient/pxegrub"; +filename "/PXEClient/pxelinux.0"; + +# Set the "vendor-class-identifier" field to "PXEClient" in dhcp answer +# if this field is not set the pxe client will ignore the answer ! +option vendor-class-identifier "PXEClient"; + + +vendor-option-space PXE; +option PXE.mtftp-ip 0.0.0.0; + +# IP of you TFTP server +next-server $server; +} + +# the class know exist just for deny the response to other DHCP request +class "known" { + match hardware; + one-lease-per-client on; + ddns-updates on; + ddns-domainname = "$dhcpd_conf->{network}{DOMAINNAME}"; + option domain-name "$dhcpd_conf->{network}{DOMAINNAME}"; + option domain-name-servers $dhcpd_conf->{network}{dnsServer}; + ddns-hostname = pick-first-value(ddns-hostname, option host-name); + option fqdn.no-client-update on; + set vendor_class_identifier = option vendor-class-identifier; +} + +# Tags uses by setup_node_mac_to_dhcp +# TAG: NODE_LIST_BEGIN + +# TAG: NODE_LIST_END +shared-network "mynetwork" { + subnet $dhcpd_conf->{network}{NETWORK} netmask $dhcpd_conf->{network}{NETMASK} { + option subnet-mask $dhcpd_conf->{network}{NETMASK}; + option routers $dhcpd_conf->{network}{GATEWAY}; + default-lease-time 28800; + max-lease-time 86400; + option domain-name "$dhcpd_conf->{network}{DOMAINNAME}"; + option domain-name-servers $dhcpd_conf->{network}{dnsServer}; +# Used by clusterautosetup-client to find its server + next-server $server; + +); + foreach (@{$dhcpd_conf->{network}{pool}}) { + print F " pool { + range $_->{start_ip} $_->{end_ip}; +"; + print F " allow members of \"$_\";\n" foreach keys %{$_->{allow}}; + print F " deny members of \"$_\";\n" foreach keys %{$_->{deny}}; + print F " }\n"; + } +print F qq( + +# pool { +# range 192.168.200.200 192.168.200.254; +# give an address of the the pool for PXE client and deny the other +#allow members of "PXE"; +#deny members of "known"; +#allow members of "Etherboot"; +# } + } +} +); + close F; +} + +sub parse_pxelinux_cfg { + my ($file) = @_; + my (%pxelinux_cfg, $entry); + local (*F, $_); + + if (open F, $file) { + while (<F>) { + chomp; + s/#.*//; next if /^\s*$/; + if (/^\s*(PROMPT|DEFAULT|DISPLAY|TIMEOUT)\s+(.*)/i) { + $pxelinux_cfg{$1} = $2; + } elsif (/^\s*label\s+(.*)/i) { + $entry and push @{$pxelinux_cfg{entry}}, $entry; + $entry = { label => $1 }, + } elsif (/^\s*(LOCALBOOT|KERNEL|APPEND)\s+(.*)/i) { + $entry->{$1} = $2; + } else { + log::l("ignoring line in file $file due to parsing error"); + } + } + $entry and push @{$pxelinux_cfg{entry}}, $entry; + close F; + } + #- try to fix bad file (first version of drakpxe for example). + my %default_pxelinux_cfg = (PROMPT => 1, + DEFAULT => "local", + DISPLAY => "messages", + TIMEOUT => 50, + entry => [ { label => "local", + LOCALBOOT => 0 } ], + ); + foreach (qw(PROMPT DEFAULT DISPLAY TIMEOUT entry)) { + length $pxelinux_cfg{$_} > 0 or $pxelinux_cfg{$_} = $default_pxelinux_cfg{$_}; + } + \%pxelinux_cfg; +} + +sub build_pxelinux_cfg { + my ($pxelinux_cfg, $file) = @_; + local *F; + open F, ">$file" or return; + log::explanations("Modified file $file"); + foreach (keys %$pxelinux_cfg) { + /^entry$/ and next; + print F "$_ $pxelinux_cfg->{$_}\n"; + } + foreach my $e (@{$pxelinux_cfg->{entry}}) { + print F "label $e->{label}\n"; + foreach (keys %$e) { + /^label$/ and next; + print F " $_ $e->{$_}\n"; + } + } + close F; +} + |