* Added generation of kickstart files from a single template and made them more configurable by the user via anvil.conf.

* Made the PXE spash image come from the active skin.

Signed-off-by: Digimer <digimer@alteeve.ca>
main
Digimer 6 years ago
parent b815af03df
commit ea65fa08aa
  1. 6
      Anvil/Tools.pm
  2. 2
      Anvil/Tools/Storage.pm
  3. 19
      anvil.conf
  4. BIN
      html/skins/alteeve/images/bios-splash.jpg
  5. 406
      html/skins/alteeve/pxe.txt
  6. 2
      notes
  7. 27
      share/words.xml
  8. 86
      tools/anvil-manage-install-target

@ -846,6 +846,12 @@ sub _set_defaults
server => "", server => "",
tag => "anvil", tag => "anvil",
}, },
# NOTE: These are here to allow foreign users to override western defaults in anvil.conf.
kickstart => {
keyboard => "--vckeymap=us --xlayouts='us'",
password => "Initial1",
timezone => "Etc/GMT --isUtc",
},
## Network stuff... The second octet auto-increments to handle N-number of netowrks. As such, ## Network stuff... The second octet auto-increments to handle N-number of netowrks. As such,
## we need to use a wider spread between the BCNs, SNs and IFNs than we had ## we need to use a wider spread between the BCNs, SNs and IFNs than we had
## in v2. ## in v2.

@ -383,7 +383,7 @@ sub change_mode
This changes the owner and/or group of a file or directory. This changes the owner and/or group of a file or directory.
$anvil->Storage->change_owner({target => "/tmp/foo", mode => "0644"}); $anvil->Storage->change_owner({target => "/tmp/foo", user => "apache", group => "apache" });
If it fails to write the file, an alert will be logged and 'C<< 1 >>' will be returned. Otherwise, 'C<< 0 >>' will be returned. If it fails to write the file, an alert will be logged and 'C<< 1 >>' will be returned. Otherwise, 'C<< 0 >>' will be returned.

@ -134,3 +134,22 @@
#defaults::template::html = alteeve #defaults::template::html = alteeve
### Install Target options
# Note; Please see 'pxe.txt' for editable templates for 'dhcpd.conf', (tftpboot's BIOS) 'default' and the
# kickstart templates.
#
# This section allows for adapting certain installations of systems via the Install Target feature.
# Generally, these don't need to be edited.
#
# This controls the keyboard configuration. See:
# - https://docs.fedoraproject.org/en-US/fedora/f28/install-guide/appendixes/Kickstart_Syntax_Reference/#sect-kickstart-commands-keyboard
#kickstart::keyboard = --vckeymap=us --xlayouts='us'
#
# This sets the default password of newly stage-1 built machines. Generally, this shouldn't be change. It is
# recorded in plain text and it is used in the stage-2 configuration tools.
#kickstart::password = Initial1
#
# This is the system timezone to be set. Generally, it's recommended to leave the Anvil! machines to UTC, but
# you might want to change this is if you spend time working directly on the various Anvil! cluster machines.
#kickstart::timezone = Etc/GMT --isUtc

Binary file not shown.

After

Width:  |  Height:  |  Size: 474 KiB

@ -23,6 +23,405 @@ subnet #!variable!network!# netmask 255.255.0.0 {
} }
<!-- end dhcpd_conf --> <!-- end dhcpd_conf -->
<!-- start kickstart -->
### Alteeve's Niche! Inc. - Anvil! Intelligent Availability(tm) Platform
# License: GPLv2
# Built: #!variable!date!#
# Target: Network Install (PXE)
# OS: #!variable!os!#
# Machine: #!variable!say_type!#
# NOTE: Do no use any non-ASCII characters in this kickstart script.
# Install using text screens, most compatible with modest hardware, too.
text
### TODO: Might want to remove this for Striker.
# Agree to the eula
eula --agreed
# Don't run the "firstboot" tool, we should have everything configured.
firstboot --disable
# Reboot when the install is done.
reboot
# Install from the source Striker
url --url=#!variable!url!#
### TODO: These should be configurable eventually.
# Keyboard layouts
keyboard #!variable!keyboard!#
timezone #!variable!timezone!#
# NOTE: DON'T CHANGE THIS WITHOUT TESTING! The Anvil! code makes system calls and parses output. Changing
# this could alter what the program can parse. The language of the Anvil! itself (and this most things
# users will see) is controlled in /etc/anvil/anvil.conf
lang en_CA.UTF-8
# Network information
network --hostname=#!variable!hostname!#
# Root and admin passwords are '#!variable!password!#'
rootpw --plaintext #!variable!password!#
user --name=admin --password "#!variable!password!#" --plaintext --gecos "admin" --groups wheel
# TEMPORARY: Set selinux to permissive
#selinux --permissive
# Partitioning plan is generated by the %pre script.
%include /tmp/plan_partitions.out
%packages
@^server-product-environment
@server-hardware-support
%end
%addon com_redhat_kdump --disable --reserve-mb='128'
%end
%anaconda
pwpolicy root --minlen=6 --minquality=1 --notstrict --nochanges --notempty
pwpolicy user --minlen=6 --minquality=1 --notstrict --nochanges --emptyok
pwpolicy luks --minlen=6 --minquality=1 --notstrict --nochanges --notempty
%end
#############################################################################################################
# %ost, --nochroot scripts #
#############################################################################################################
### TODO: Might want to remove this pre-production. Useful for debugging until then.
# Record all the install logs for future reference.
%post --nochroot
echo 'Copying all the anaconda related log files to /root/install/'
mkdir -p /mnt/sysimage/root/install_logs/var
mkdir -p /mnt/sysimage/root/install_logs/run
rsync -av /tmp /mnt/sysimage/root/install_logs/
rsync -av /run/install /mnt/sysimage/root/install_logs/run/
rsync -av /var/log /mnt/sysimage/root/install_logs/var/
%end
#############################################################################################################
# %pre scripts #
#############################################################################################################
### This is the small anaconda-friendly perl program that looks at the
### available storage and chooses a drive to install on. Then it generates
### the kickstart partition instructions and records them in:
### /tmp/plan_partitions.out
### NOTE: This must be copied from 'scripts/plan_partitions', don't edit directly *EXCEPT* to set the '$type'
### just below, which *MUST* be set, or the script will fail.
%pre --interpreter /bin/perl
#!/bin/perl
#
# This script is designed to identify hard drives and decide where and how to partition it for installation
# during a kickstart install.
#
# Exit codes;
# 0 - Success
# 1 - Target type not specified.
# 2 - Failed to find a drive to install on.
#
# NOTE: This is restricted to what is available during an anaconda install session. That is to same, bare
# minimum.
# TODO: If multiple matching drives are found (same medium and size, build an appropriate RAID array.
# TODO: in pre, wipefs on all disks to clear old LVM and DRBD data
#
use strict;
use warnings;
# Set to '1' for verbose output
my $debug = #!variable!debug!#;
### NOTE: This must be set to 'striker', 'node' or 'dr' when incorporated into a kickstart %pre script!
my $type = "#!variable!type!#";
if ($type =~ /striker/i)
{
print "#!string!message_0103!#\n";
$type = "striker";
}
elsif ($type =~ /node/i)
{
print "#!string!message_0104!#\n";
$type = "node";
}
elsif ($type =~ /dr/i)
{
print "#!string!message_0105!#\n";
$type = "dr";
}
else
{
print "#!string!message_0106!#\n";
exit(1);
}
my $device = {};
# We might want to add HCTL (Host:Channel:Target:Lun for SCSI) and/or SUBSYSTEMS later
my $target = "";
my $lsblk = system_call("/bin/lsblk --bytes --paths --pairs --output NAME,RM,HOTPLUG,TYPE,SIZE,TRAN,ROTA");
foreach my $line (split/\n/, $lsblk)
{
### NOTE: If a drive has no transport, is not removable, but is hotplugable and the device path is
### mmcblk0, it is probably an SDCard. It doesn't seem to be a directly divinable state. We
### don't currently plan to use them, but it might come to pass later.
print __LINE__."; [ Debug ] - lsblk: [".$line."]\n" if $debug;
my ($path, $removable, $hotplug, $type, $size, $transport, $rotational) = ($line =~ /NAME="(.*?)" RM="(\d)" HOTPLUG="(\d)" TYPE="(.*?)" SIZE="(\d+)" TRAN="(.*?)" ROTA="(\d)"/);
print __LINE__."; [ Debug ] - Device: [".$path."], type: [".$type."], remvoable? [".$removable."], hotplug? [".$hotplug."], rotational? [".$rotational."], transport: [".$transport."], size: [".$size."]\n" if $debug;
# Skip 'zramX' devices
next if ($path =~ /^\/dev\/zram\d/);
# Skip removable disks and anything that just isn't a disk at all.
next if (($removable) or ($hotplug) or ($type ne "disk"));
$device->{$path} = {
type => $type,
size => $size,
transport => $transport,
rotational => $rotational,
};
if ($device->{$path}{rotational})
{
print "#!string!message_0107!#\n";
}
else
{
print "#!string!message_0108!#\n";
}
}
### Usage selection priority
# on Striker, we'll simply use whatever is the biggest avalable drive.
# on Node and DR, we'll prefer slowest first (rotational, sata before nvme/scsi), and smallest second.
my $use_drive = "";
if ($type eq "striker")
{
my $biggest_size = 0;
foreach my $path (sort {$a cmp $b} keys %{$device})
{
print __LINE__."; [ Debug ] - path: [".$path."], ${path}::size: [".$device->{$path}{size}." (".hr_size($device->{$path}{size}).")] < biggest_size: [".$biggest_size." (".hr_size($biggest_size).")]\n" if $debug;
if ($device->{$path}{size} > $biggest_size)
{
$biggest_size = $device->{$path}{size};
$use_drive = $path;
print __LINE__."; [ Debug ] - use_drive: [".$use_drive."], biggest_size: [".$biggest_size." (".hr_size($biggest_size).")]\n" if $debug;
}
}
if ($use_drive)
{
print "#!string!message_0109!#\n";
}
}
else
{
# Node and DR are handled the same
my $first_disk_seen = 0;
my $smallest_size = 0;
my $selected_is_platter = 0;
foreach my $path (sort {$a cmp $b} keys %{$device})
{
print __LINE__."; [ Debug ] - first_disk_seen: [".$first_disk_seen."], path: [".$path."], ${path}::rotational: [".$device->{$path}{rotational}."]\n" if $debug;
if (not $first_disk_seen)
{
# Select this one
$first_disk_seen = 1;
$use_drive = $path;
$smallest_size = $device->{$path}{size};
$selected_is_platter = $device->{$path}{rotational};
print __LINE__."; [ Debug ] - first_disk_seen: [".$first_disk_seen."], use_drive: [".$use_drive."], selected_is_platter: [".$selected_is_platter."], smallest_size: [".$smallest_size." (".hr_size($smallest_size).")]\n" if $debug;
}
elsif ($device->{$path}{rotational})
{
# This takes priority
print __LINE__."; [ Debug ] - selected_is_platter: [".$selected_is_platter."]\n" if $debug;
if ($selected_is_platter)
{
# Was the previously seen drive bigger?
print __LINE__."; [ Debug ] - ".$path."::size: [".$first_disk_seen." (".hr_size($first_disk_seen).")], smallest_size: [".$smallest_size." (".hr_size($smallest_size).")]\n" if $debug;
if ($device->{$path}{size} < $smallest_size)
{
# This is smaller, use it.
$use_drive = $path;
$smallest_size = $device->{$path}{size};
print __LINE__."; [ Debug ] - use_drive: [".$use_drive."], smallest_size: [".$smallest_size." (".hr_size($smallest_size).")]\n" if $debug;
}
}
else
{
# The previous drive is an SSD, so use this one regardless
$use_drive = $path;
$smallest_size = $device->{$path}{size};
$selected_is_platter = $device->{$path}{rotational};
print __LINE__."; [ Debug ] - use_drive: [".$use_drive."], selected_is_platter: [".$selected_is_platter."], smallest_size: [".$smallest_size." (".hr_size($smallest_size).")]\n" if $debug;
}
}
elsif (not $selected_is_platter)
{
# This is an SSD, but we haven't seen a platter drive yet, so use it if it is
# smaller.
print __LINE__."; [ Debug ] - ".$path."::size: [".$first_disk_seen." (".hr_size($first_disk_seen).")], smallest_size: [".$smallest_size." (".hr_size($smallest_size).")]\n" if $debug;
if ($device->{$path}{size} < $smallest_size)
{
# This is smaller, use it.
$use_drive = $path;
$smallest_size = $device->{$path}{size};
print __LINE__."; [ Debug ] - use_drive: [".$use_drive."], smallest_size: [".$smallest_size." (".hr_size($smallest_size).")]\n" if $debug;
}
}
}
# Did we find a drive?
if ($use_drive)
{
if ($selected_is_platter)
{
print "#!string!message_0110!#\n";
}
else
{
print "#!string!message_0111!#\n";
}
}
}
# Did we find a disk to use?
if (not $use_drive)
{
print "#!string!message_0112!#\n";
exit(2);
}
# Pick up a bit of a UUID to add to the volume group name.
my $id = time;
if ((-e "/sys/class/dmi/id/product_uuid") && (-r "/sys/class/dmi/id/product_uuid"))
{
# We should be able to read the system UUID. If so, we'll take the starting part of the string for
# the short ID.
my $uuid = "";
my $shell_call = "/sys/class/dmi/id/product_uuid";
print __LINE__."; [ Debug ] - shell_call: [".$shell_call."]\n" if $debug;
open (my $file_handle, "<", $shell_call) or die "Failed to read: [".$shell_call."], the error was: ".$!."\n";
while(<$file_handle>)
{
chomp;
$uuid = $_;
print __LINE__."; [ Debug ] - uuid: [".$uuid."]\n" if $debug;
}
close $file_handle;
if ($uuid =~ /^(\w+)-/)
{
$id = $1;
print __LINE__."; [ Debug ] - id: [".$id."]\n" if $debug;
}
}
# Finally, we've got our output.
my $say_grow = $type eq "striker" ? "--grow " : "";
my $vg_name = $type."_".$id;
my $partition_file = "/tmp/plan_partitions.out";
my $partition_body = "zerombr
clearpart --all --drives=".$use_drive."
ignoredisk --only-use=".$use_drive."
bootloader --location=mbr --driveorder=".$use_drive." --boot-drive=".$use_drive."
# Partitions
part biosboot --fstype=biosboot --size=1
part /boot --fstype=ext4 --size=1024 --asprimary --ondisk=".$use_drive."
part pv.01 --fstype=lvmpv --size=100 --asprimary --ondisk=".$use_drive." --grow
# LVM Volume groups
volgroup ".$vg_name." --pesize=4096 pv.01
# LVM logical volumes
logvol swap --fstype=swap --size=8188 --name=lv_swap --vgname=".$vg_name."
logvol / --fstype=xfs --size=40960 --name=lv_root --vgname=".$vg_name." ".$say_grow."
";
print __LINE__."; [ Debug ] - partition_body: [".$partition_body."]\n" if $debug;
print "#!string!message_0113!#\n";
# Write it to the temp file that the kickstart's %include will look for.
my $shell_call = $partition_file;
print __LINE__."; [ Debug ] - shell_call: [".$shell_call."]\n" if $debug;
open (my $file_handle, ">", $shell_call) or die "Failed to write: [".$shell_call."], the error was: ".$!."\n";
print $file_handle $partition_body;
close $file_handle;
print "#!string!message_0114!#\n";
# We're done.
exit(0);
### Functions
# Make the size easier to read for users
sub hr_size
{
my ($size) = @_;
my $hr_size = $size;
if ($size < 1023)
{
# Bytes
$hr_size .= " B";
}
elsif ($size < (2 ** 20))
{
# Kibibyte
$hr_size = sprintf("%.1f", ($size /= (2 ** 10)))." KiB";
}
elsif ($size < (2 ** 30))
{
# Mebibyte
$hr_size = sprintf("%.2f", ($size /= (2 ** 20)))." MiB";
}
elsif ($size < (2 ** 40))
{
# Gibibyte
$hr_size = sprintf("%.2f", ($size /= (2 ** 30)))." GiB";
}
elsif ($size < (2 ** 50))
{
# Tebibyte
$hr_size = sprintf("%.2f", ($size /= (2 ** 40)))." TiB";
}
else
{
# Pebibyte or higher
$hr_size = sprintf("%.3f", ($size /= (2 ** 40)))." PiB";
}
return($hr_size);
}
sub system_call
{
my ($command) = @_;
my $output = "";
open (my $file_handle, $command." 2>&1 |") or die "Failed to call: [".$command."], error was: [".$!."]\n";
while (<$file_handle>)
{
chomp;
my $line = $_;
$line =~ s/\n$//;
$line =~ s/\r$//;
$output .= $line."\n";
}
close $file_handle;
$output =~ s/\n$//s;
return($output);
}
%end
<!-- end kickstart -->
<!-- start tftp_bios --> <!-- start tftp_bios -->
# Tradional BIOS based PXE menu # Tradional BIOS based PXE menu
# #
@ -89,7 +488,8 @@ TEXT HELP
#!string!message_0085!# #!string!message_0085!#
ENDTEXT ENDTEXT
kernel fedora28/vmlinuz kernel fedora28/vmlinuz
append initrd=fedora28/initrd.img root=live:#!variable!base_url!#/os/images/install.img inst.stage2=#!variable!base_url!#/os/ ip=dhcp inst.ks=#!variable!base_url!#/kickstart/striker.ks inst.sshd rd.debug # NOTE: add ' rd.debug' below for debugging
append initrd=fedora28/initrd.img root=live:#!variable!base_url!#/os/images/install.img inst.stage2=#!variable!base_url!#/os/ ip=dhcp inst.ks=#!variable!base_url!#/kickstart/striker.ks inst.sshd
label node label node
menu label #!string!message_0086!# menu label #!string!message_0086!#
@ -97,7 +497,7 @@ TEXT HELP
#!string!message_0087!# #!string!message_0087!#
ENDTEXT ENDTEXT
kernel fedora28/vmlinuz kernel fedora28/vmlinuz
append initrd=fedora28/initrd.img root=live:#!variable!base_url!#/os/images/install.img inst.stage2=#!variable!base_url!#/os/ ip=dhcp inst.ks=#!variable!base_url!#/kickstart/node.ks inst.sshd rd.debug append initrd=fedora28/initrd.img root=live:#!variable!base_url!#/os/images/install.img inst.stage2=#!variable!base_url!#/os/ ip=dhcp inst.ks=#!variable!base_url!#/kickstart/node.ks inst.sshd
label node label node
menu label #!string!message_0088!# menu label #!string!message_0088!#
@ -105,7 +505,7 @@ TEXT HELP
#!string!message_0089!# #!string!message_0089!#
ENDTEXT ENDTEXT
kernel fedora28/vmlinuz kernel fedora28/vmlinuz
append initrd=fedora28/initrd.img root=live:#!variable!base_url!#/os/images/install.img inst.stage2=#!variable!base_url!#/os/ ip=dhcp inst.ks=#!variable!base_url!#/kickstart/dr.ks inst.sshd rd.debug append initrd=fedora28/initrd.img root=live:#!variable!base_url!#/os/images/install.img inst.stage2=#!variable!base_url!#/os/ ip=dhcp inst.ks=#!variable!base_url!#/kickstart/dr.ks inst.sshd
label rescue label rescue
menu label #!string!message_0090!# menu label #!string!message_0090!#

@ -1,3 +1,5 @@
NEXT; - Copy os/isolinux/* stuff from syslinux-nonlinux
dnf -y install perl-Net-Netmask perl-Text-Diff dnf-utils hdparm lsscsi createrepo dhcp kernel-core syslinux tftp-server dnf -y install perl-Net-Netmask perl-Text-Diff dnf-utils hdparm lsscsi createrepo dhcp kernel-core syslinux tftp-server
Firewall config stuff. Firewall config stuff.

@ -197,7 +197,32 @@ NOTE: Please be patient!
<key name="message_0100">Copying the syslinux files: [#!data!path::directories::syslinux!#/*] into the tftpboot directory: [#!data!path::directories::tftpboot!#].</key> <key name="message_0100">Copying the syslinux files: [#!data!path::directories::syslinux!#/*] into the tftpboot directory: [#!data!path::directories::tftpboot!#].</key>
<key name="message_0101">The syslinux files from: [#!data!path::directories::syslinux!#] appear to already be in the tftpboot directory: [#!data!path::directories::tftpboot!#], skipping.</key> <key name="message_0101">The syslinux files from: [#!data!path::directories::syslinux!#] appear to already be in the tftpboot directory: [#!data!path::directories::tftpboot!#], skipping.</key>
<key name="message_0102">Checking that the "Install Target" function is configured and updated.</key> <key name="message_0102">Checking that the "Install Target" function is configured and updated.</key>
<key name="message_0103"></key> <!-- The strings below are printed in bash, so be mindful of escaping characters. The strings are wrapped in double-quotes ("), so escape them with a back-slash (\") -->
<key name="message_0103">Finding install drive for a Striker dashboard.</key>
<key name="message_0104">Finding install drive for an Anvil! node.</key>
<key name="message_0105">Finding install drive for a DR (disaster recovery) host.</key>
<key name="message_0106">
[ Error ] - Target type not specified. Be sure that '\$type' is set to
'striker', 'node' or 'dr' in the \%pre section of the kickstart
script.
</key>
<!-- These are injected into the perl script in the kickstart files. Leave the string variables and function calls in place! -->
<key name="message_0107"><![CDATA[Analyzing platter drive: [".$path."], using the transport: [".$device->{$path}{transport}."], of the size: [".$device->{$path}{size}." (".hr_size($device->{$path}{size}).")]]]></key>
<key name="message_0108"><![CDATA[Analyzing solid-state drive: [".$path."], using the transport: [".$device->{$path}{transport}."], of the size: [".$device->{$path}{size}." (".hr_size($device->{$path}{size}).")]]]></key>
<key name="message_0109"><![CDATA[Selected the largest disk: [".$use_drive."], which has a capacity of: [".hr_size($device->{$use_drive}{size})."]]]></key>
<key name="message_0110"><![CDATA[Selected the smallest platter drive: [".$use_drive."], which has a capacity of: [".hr_size($device->{$use_drive}{size})."]]]></key>
<key name="message_0111"><![CDATA[Selected the smallest solid-state drive: [".$use_drive."], which has a capacity of: [".hr_size($device->{$use_drive}{size})."] (no platter drives found)]]></key>
<key name="message_0112"><![CDATA[[ Error ] - Failed to find any fixed drives (platter or USB, not removable) to install onto. Unable to proceed.]]></key>
<key name="message_0113"><![CDATA[Writing out the partition plan to: [".$partition_file."]]]></key>
<key name="message_0114"><![CDATA[Completed successfully, exiting.]]></key>
<!-- Above here are strings used in the kickstart scripts. Be sure to test kickstart installation after changing / translation between 'message_0103' and 'message_0114'. -->
<key name="message_0115">Striker Dashboard</key>
<key name="message_0116">Anvil! Node</key>
<key name="message_0117">Dsaster Recovery (DR) Host</key>
<key name="message_0118"></key>
<key name="message_0119"></key>
<key name="message_0120"></key>
<key name="message_0121"></key>
<!-- Log entries --> <!-- Log entries -->
<key name="log_0001">Starting: [#!variable!program!#].</key> <key name="log_0001">Starting: [#!variable!program!#].</key>

@ -16,6 +16,7 @@
# 2 = BCN IP not found, unable to configure yet. # 2 = BCN IP not found, unable to configure yet.
# 3 = Failed to write or update a configuration file. # 3 = Failed to write or update a configuration file.
# 4 = Not a striker dashboard (or isn't yet). # 4 = Not a striker dashboard (or isn't yet).
# 5 = Not running as the 'root' user.
# #
# TODO: # TODO:
# - Support building the install target by mounting the ISO and checking /mnt/shared/incoming for needed # - Support building the install target by mounting the ISO and checking /mnt/shared/incoming for needed
@ -47,6 +48,15 @@ $anvil->Log->entry({source => $THIS_FILE, line => __LINE__, level => 1, secure =
$anvil->data->{switches}{'y'} = ""; $anvil->data->{switches}{'y'} = "";
$anvil->Get->switches; $anvil->Get->switches;
# Make sure we're running as 'root'
# $< == real UID, $> == effective UID
if (($< != 0) && ($> != 0))
{
# Not root
$anvil->Log->entry({source => $THIS_FILE, line => __LINE__, level => 0, key => "error_0005"});
$anvil->nice_exit({code => 5});
}
my ($os_type, $os_arch) = $anvil->System->get_os_type(); my ($os_type, $os_arch) = $anvil->System->get_os_type();
$anvil->data->{host_os}{os_type} = $os_type; $anvil->data->{host_os}{os_type} = $os_type;
$anvil->data->{host_os}{os_arch} = $os_arch; $anvil->data->{host_os}{os_arch} = $os_arch;
@ -191,8 +201,7 @@ sub setup_boot_environment
} }
### PXE BIOD 'default' file. ### PXE BIOS 'default' file.
# Setup the BIOS boot menu.
my $bios_default_body = $anvil->Template->get({file => "pxe.txt", show_name => 0, name => "tftp_bios", variables => { base_url => $base_url }}); my $bios_default_body = $anvil->Template->get({file => "pxe.txt", show_name => 0, name => "tftp_bios", variables => { base_url => $base_url }});
$anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 3, list => { bios_default_body => $bios_default_body }}); $anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 3, list => { bios_default_body => $bios_default_body }});
@ -220,6 +229,62 @@ sub setup_boot_environment
print $anvil->Words->string({key => "message_0096", variables => { file => $anvil->data->{path}{configs}{pxe_default} }})."\n"; print $anvil->Words->string({key => "message_0096", variables => { file => $anvil->data->{path}{configs}{pxe_default} }})."\n";
} }
### Generate kickstart files.
foreach my $type ("striker", "node", "dr")
{
$anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { type => $type }});
my $say_type = "#!string!message_0115!#";
if ($type eq "node")
{
$say_type = "#!string!message_0116!#";
}
elsif ($type eq "dr")
{
$say_type = "#!string!message_0117!#";
}
my $kickstart_body = $anvil->Template->get({file => "pxe.txt", show_name => 0, name => "kickstart", variables => {
type => $type,
say_type => $say_type,
hostname => "new-".$type.".".$domain,
date => $anvil->Get->date_and_time({date_only => 1}),
os => $anvil->data->{host_os}{os_type},
url => $base_url."/os/",
keyboard => $anvil->data->{kickstart}{keyboard} ? $anvil->data->{kickstart}{keyboard} : $anvil->data->{defaults}{kickstart}{keyboard},
timezone => $anvil->data->{kickstart}{timezone} ? $anvil->data->{kickstart}{timezone} : $anvil->data->{defaults}{kickstart}{timezone},
password => $anvil->data->{kickstart}{password} ? $anvil->data->{kickstart}{password} : $anvil->data->{defaults}{kickstart}{password},
debug => 0, # This isn't the same as the rest of our code, just '1' or '0'.
}});
$anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { kickstart_body => $kickstart_body }});
# Return code if '1' means the file was changed, '2' indicates it didn't change. '0' means
# something went wrong.
my $kickstart_file = "/var/www/html/".$anvil->data->{host_os}{os_type}."/".$anvil->data->{host_os}{os_arch}."/kickstart/".$type.".ks";
my $kickstart_success = $anvil->Storage->update_file({
body => $kickstart_body,
file => $kickstart_file,
});
$anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { kickstart_success => $kickstart_success }});
if (not $kickstart_success)
{
# Failed.
print $anvil->Words->string({key => "error_0043", variables => { file => $kickstart_file }})."\n";
$anvil->nice_exit({code => 3});
}
elsif ($dhcpd_conf_success eq "1")
{
# Updated
$anvil->Storage->change_mode({target => $kickstart_file, mode => "0664"});
$anvil->Storage->change_owner({target => $kickstart_file, user => "apache", group => "apache" });
print $anvil->Words->string({key => "message_0097", variables => { file => $kickstart_file }})."\n";
}
elsif ($dhcpd_conf_success eq "2")
{
# Update not needed.
print $anvil->Words->string({key => "message_0096", variables => { file => $kickstart_file }})."\n";
}
}
# Configure apache to show hidden (dot) files. # Configure apache to show hidden (dot) files.
my $old_autoindex_conf = $anvil->Storage->read_file({file => $anvil->data->{path}{configs}{'autoindex.conf'}}); my $old_autoindex_conf = $anvil->Storage->read_file({file => $anvil->data->{path}{configs}{'autoindex.conf'}});
my $new_autoindex_conf = ""; my $new_autoindex_conf = "";
@ -403,6 +468,20 @@ sub setup_boot_environment
print $anvil->Words->string({key => "message_0101"})."\n"; print $anvil->Words->string({key => "message_0101"})."\n";
} }
### TODO: Add UEFI
# Copy the background splash image for the PXE boot images.
my $bios_splash = $anvil->data->{path}{directories}{skins}."/".$anvil->Template->skin."/images/bios-splash.jpg";
if (-e $bios_splash)
{
# We don't bother checking if this needs to be updated because rsync can figure it out more
# efficiently.
$anvil->Storage->rsync({
debug => 2,
source => $bios_splash,
destination => $anvil->data->{path}{directories}{tftpboot}."/splash.jpg",
});
}
return(0); return(0);
} }
@ -457,6 +536,9 @@ sub update_install_source
{ {
my ($anvil) = @_; my ($anvil) = @_;
### TODO: Make this only run once every 24 hours (track in the database;
### 'system::install-target::source-updated').
### TODO: Make sure this path exists. ### TODO: Make sure this path exists.
my $download_path = "/var/www/html/".$anvil->data->{host_os}{os_type}."/".$anvil->data->{host_os}{os_arch}."/os/Packages/"; my $download_path = "/var/www/html/".$anvil->data->{host_os}{os_type}."/".$anvil->data->{host_os}{os_arch}."/os/Packages/";
my $array_size = @{$anvil->data->{packages}}; my $array_size = @{$anvil->data->{packages}};

Loading…
Cancel
Save