anvil/html/skins/alteeve/pxe.txt
Digimer e8efbab343 * The work on PXE / UEFI support is broken, and will be set aside for the time being. The commit here is working to getting things fixed, but it's taking too much time away from more pressing issues.
* This commit includes two unrelated test files for UI work, cgi-bin/get_anvil_status and cgi-bin/get_anvils.

Signed-off-by: Digimer <digimer@alteeve.ca>
2021-02-16 17:32:43 -05:00

964 lines
33 KiB
Plaintext

<!-- start dhcpd_conf -->
### Global options
option domain-name "#!variable!domain!#";
option domain-name-servers #!variable!dns!#;
authoritative;
ddns-update-style none;
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;
option architecture-type code 93 = unsigned integer 16;
# refer to RFC4758 for possible arch option values
option arch code 93 = unsigned integer 16;
subnet #!variable!network!# netmask 255.255.0.0 {
default-lease-time 600;
max-lease-time 1200;
range #!variable!range!#;
option routers #!variable!router!#;
class "pxeclients" {
match if substring (option vendor-class-identifier, 0, 9) = "PXEClient";
next-server #!variable!router!#;
if option arch = 00:07 {
filename "BOOTX64.efi";
} else {
filename "pxelinux.0";
}
}
}
<!-- end dhcpd_conf -->
<!-- start kickstart -->
### Alteeve's Niche! Inc. - Anvil! Intelligent Availability(tm) Platform
# License: GPLv2
# 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!host_name!#
# 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
@^minimal-environment
#alteeve-el8-repo
#createrepo
#dhcp-server
#firefox
gcc
#gdm
#gnome-terminal
#httpd
#nmap
#perl-CGI
perl-Data-Dumper
#perl-interpreter
perl-NetAddr-IP
#postgresql-server
rsync
#syslinux
#syslinux-nonlinux
#tftp-server
vim
#virt-manager
%end
%addon com_redhat_kdump --disable --reserve-mb='auto'
%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
#############################################################################################################
# %post, --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/
echo 'Writing out the initial /etc/issue script.'
reset
cat << EOF > /mnt/sysimage/usr/sbin/anvil-update-issue
#!/usr/bin/perl
#
# This parses the current IP addresses on the local system and writes them to /etc/issue so that they're seen
# by a user at the login prompt. This is meant to be useful during the initialization and setup stages, so
# it's expected to run before the Anvil::Tools module is installed. As such, it doesn't use those modules.
#
use strict;
use warnings;
use IO::Handle;
# Turn off buffering so that the pinwheel will display while waiting for the SSH call(s) to complete.
\$| = 1;
my \$THIS_FILE = (\$0 =~ /^.*\/(.*)\$/)[0];
my \$running_directory = (\$0 =~ /^(.*?)\/\$THIS_FILE\$/)[0];
if ((\$running_directory =~ /^\./) && (\$ENV{PWD}))
{
\$running_directory =~ s/^\./\$ENV{PWD}/;
}
my \$shell_call = "/usr/sbin/ip addr list";
my \$new_issue = '\S
Kernel \r on an \m
';
my \$ips = {};
my \$interface = "";
open (my \$file_handle, \$shell_call." 2>&1 |") or die "Failed to call: [".\$shell_call."], error was: [".\$!."]\n";
while(<\$file_handle>)
{
chomp;
my \$line = \$_;
\$line =~ s/\n\$//;
\$line =~ s/\r\$//;
if (\$line =~ /^\d+: (.*?): </)
{
\$interface = \$1;
}
next if not \$interface;
next if \$interface eq "lo";
if (\$line =~ / inet (\d+\.\d+\.\d+\.\d+\/\d+) /)
{
my \$ip = \$1;
\$ips->{\$interface} = \$ip;
}
}
close \$file_handle;
if (keys %{\$ips})
{
\$new_issue .= "\nActive IPs:\n";
foreach my \$interface (sort {\$a cmp \$b} keys %{\$ips})
{
\$new_issue .= "- ".\$interface.": ".\$ips->{\$interface}."\n";
}
\$new_issue .= "\n";
}
# Read in the current issue file and see if there is any difference.
my \$old_issue = "";
my \$issue_file = "/etc/issue";
open (\$file_handle, "<", \$issue_file) or die "Failed to read: [".\$issue_file."], error was: [".\$!."]\n";
while(<\$file_handle>)
{
### NOTE: Don't chop this, we want to record exactly what we read
\$old_issue .= \$_;
}
close \$file_handle;
my \$update = \$new_issue eq \$old_issue ? 0 : 1;
if (\$update)
{
open (my \$file_handle, ">", \$issue_file) or die "Failed to write: [".\$issue_file."], the error was: [".\$!."]\n";
print \$file_handle \$new_issue;
close \$file_handle;
}
exit(0);
EOF
chmod 755 /mnt/sysimage/usr/sbin/anvil-update-issue
# Add this to crontab.
cat << EOF > /mnt/sysimage/var/spool/cron/root
MAILTO=""
* * * * * /usr/sbin/anvil-update-issue >> /var/log/anvil.cron 2>&1
EOF
chown 0:0 /mnt/sysimage/var/spool/cron/root
chmod 0600 /mnt/sysimage/var/spool/cron/root
echo 'Writing out the initial /etc/issue script.'
reset
cat << EOF > /mnt/sysimage/etc/NetworkManager/dispatcher.d/ifup-local
#!/usr/bin/bash
#
# Make sure that we update /etc/issue as soon as the network is up, before the
# logic in shown to the user after boot.
/usr/sbin/anvil-update-issue
EOF
chmod +x /mnt/sysimage/etc/NetworkManager/dispatcher.d/ifup-local
cat << EOF > /mnt/sysimage/#!variable!repo_file!#
#!variable!repo_body!#
EOF
%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.
# - #!variable!debug!#
# - #!variable!type!#
%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 say, 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 = 0;
### NOTE: This must be set to 'striker', 'node' or 'dr'! Wither set '$type' or use the appropriate argument.
my $type = "#!variable!type!#";
if ((defined $ARGV[0]) && ((lc($ARGV[0]) eq "striker") or (lc($ARGV[0]) eq "node") or (lc($ARGV[0]) eq "dr")))
{
$type = $ARGV[0];
}
if ($type =~ /striker/i)
{
print "-=] Finding install drive(s) for a Striker dashboard.\n";
$type = "striker";
}
elsif ($type =~ /node/i)
{
print "-=] Finding install drive(s) for an Anvil! node.\n";
$type = "node";
}
elsif ($type =~ /dr/i)
{
print "-=] Finding install drive(s) for a DR (disaster recovery) host.\n";
$type = "dr";
}
else
{
print "
[ Error ] - Target type not specified!
Usage: ".$0." {striker,node,dr}
";
exit(1);
}
my $device = {};
# We might want to add HCTL (Host:Channel:Target:Lun for SCSI) and/or SUBSYSTEMS later
my $drives = {};
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,
};
my $hr_size = hr_size($device->{$path}{size});
$device->{$path}{hr_size} = $hr_size;
if ($device->{$path}{rotational})
{
if (not $device->{$path}{transport})
{
print "Analyzing platter or virtual drive: [".$path."] of the size: [".$device->{$path}{size}." (".$device->{$path}{hr_size}.")]\n";
}
else
{
print "Analyzing platter drive: [".$path."], using the transport: [".$device->{$path}{transport}."], of the size: [".$device->{$path}{size}." (".$device->{$path}{hr_size}.")]\n";
}
}
else
{
print "Analyzing solid-state drive: [".$path."], using the transport: [".$device->{$path}{transport}."], of the size: [".$device->{$path}{size}." (".$device->{$path}{hr_size}.")]\n";
}
if (not exists $drives->{by_hr_size}{$hr_size})
{
$drives->{by_hr_size}{$hr_size} = [];
}
push @{$drives->{by_hr_size}{$hr_size}}, $path;
}
### 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 "Selected the largest disk: [".$use_drive."], which has a capacity of: [".hr_size($device->{$use_drive}{size})."]\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 "Selected the smallest platter drive: [".$use_drive."], which has a capacity of: [".hr_size($device->{$use_drive}{size})."]\n";
}
else
{
print "Selected the smallest solid-state drive: [".$use_drive."], which has a capacity of: [".hr_size($device->{$use_drive}{size})."] (no platter drives found)\n";
}
}
}
# Did we find a disk to use?
if (not $use_drive)
{
print "[ Error ] - Failed to find any fixed drives (platter or USB, not removable) to install onto. Unable to proceed.\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;
}
}
### NOTE: RAID 0 is not RAID (literally or in this case). So '0' means 'no raid'
# If I have 2+ drives of the same size as 'use_drive', I will create a RAID array.
my $raid_level = 0;
my $hr_size = $device->{$use_drive}{hr_size};
my $count = @{$drives->{by_hr_size}{$hr_size}};
print __LINE__."; [ Debug ] - Drives of size: [".$hr_size."]: [".$count."].\n" if $debug;
if ($count == 0)
{
$raid_level = 0;
}
elsif ($count == 2)
{
$raid_level = 1;
}
elsif ($count == 4)
{
$raid_level = 10;
}
elsif (($count == 3) or ($count == 5))
{
$raid_level = 5;
}
elsif ($count > 5)
{
$raid_level = 6;
}
my $say_use_drive = $use_drive;
if (not $raid_level)
{
print "Building a standard partition layout for: [".$use_drive."] which is: [".$hr_size."]\n";
}
else
{
print "Building a software RAID level: [".$raid_level."] array using the: [".$count."x] [".$hr_size."] drives;\n";
$say_use_drive = "";
foreach my $path (sort {$a cmp $b} @{$drives->{by_hr_size}{$hr_size}})
{
print "- ".$path."\n";
$say_use_drive .= $path.",";
}
$say_use_drive =~ s/,$//;
}
### NOTE: kickstart sizes are in MiB
# Prepare some variables
my $swap_size = 8192;
my $root_size = 0;
my $vg_name = $type."_".$id;
# If this machine has a small size, we'll cut back the swap and root sizes.
my $per_disk_space = sprintf("%.2f", ($device->{$use_drive}{size} /= (2 ** 20)));
my $available_space = $per_disk_space;
print __LINE__."; [ Debug ] - per_disk_space: [".$per_disk_space." (".hr_size($per_disk_space * (2**20)).")], available_space: [".$available_space." (".hr_size($available_space * (2**20)).")]\n" if $debug;
if ($raid_level == 10)
{
# Total == 2 x single disk
$available_space *= 2;
print __LINE__."; [ Debug ] - available_space: [".$available_space."]\n" if $debug;
}
elsif ($raid_level == 5)
{
# Total == count x Disks - 1
$available_space = ($per_disk_space * $count) - $per_disk_space;
print __LINE__."; [ Debug ] - available_space: [".$available_space."]\n" if $debug;
}
elsif ($raid_level == 6)
{
# Total == count x Disks - 2
$available_space = ($per_disk_space * $count) - ($per_disk_space * 2);
print __LINE__."; [ Debug ] - available_space: [".$available_space."]\n" if $debug;
}
# Now, how much space is available after taking some for BIOSBOOT and /boot ?
$available_space -= 2;
print __LINE__."; [ Debug ] - available_space: [".$available_space." (".hr_size($available_space * (2**20)).")]\n" if $debug;
if ($available_space < 40960)
{
# Not enough space for the standard layout.
$swap_size = 4096;
print __LINE__."; [ Debug ] - swap_size: [".$swap_size."]\n" if $debug;
}
# The left over space is for '/' (we'll shorten this up to 40GiB for nodes and DR hosts next)
$root_size = $available_space - $swap_size;
print __LINE__."; [ Debug ] - root_size: [".$root_size."]\n" if $debug;
print __LINE__."; [ Debug ] - type: [".$type."], root_size: [".$root_size."]\n" if $debug;
if (($type ne "striker") && ($root_size > 40960))
{
$root_size = 40960;
print __LINE__."; [ Debug ] - root_size: [".$root_size."]\n" if $debug;
}
# Round down to an event integer.
$root_size =~ s/\.\d+$//;
print __LINE__."; Assigning: [".hr_size($swap_size * (2**20))." (".$swap_size." MiB)], root_size: [".hr_size($root_size * (2**20))." (".$root_size.") MiB]\n" if $debug;
# Build the partition file.
my $partition_file = "/tmp/plan_partitions.out";
my $partition_body = "ignoredisk --only-use=".$say_use_drive."
clearpart --none --initlabel";
if (not $raid_level)
{
# Finally, we've got our output.
$partition_body .= "
# Disk partitioning information
part biosboot --fstype=\"biosboot\" --ondisk=".$use_drive." --size=2
part /boot --fstype=\"xfs\" --ondisk=".$use_drive." --size=1024
part /boot/efi --fstype=\"efi\" --ondisk=".$use_drive." --size=600 --fsoptions=\"umask=0077,shortname=winnt\"
part pv.01 --fstype=lvmpv --ondisk=".$use_drive." --size=100 --grow
# LVM Volume groups
volgroup ".$vg_name." --pesize=4096 pv.01
# LVM logical volumes
logvol swap --fstype=swap --size=".$swap_size." --name=lv_swap --vgname=".$vg_name."
logvol / --fstype=xfs --size=100 --grow --maxsize=".$root_size." --name=lv_root --vgname=".$vg_name."
";
}
else
{
$partition_body .= "
# biosboot
";
for (my $i = 0; $i < $count; $i++)
{
$partition_body .= "part biosboot --fstype=\"biosboot\" --ondisk=".$drives->{by_hr_size}{$hr_size}->[$i]." --size=2 \n";
$partition_body .= "part /boot/efi --fstype=\"efi\" --ondisk=".$drives->{by_hr_size}{$hr_size}->[$i]." --size=600 --fsoptions=\"umask=0077,shortname=winnt\" \n";
$partition_body .= "part /boot --fstype=\"xfs\" --ondisk=".$drives->{by_hr_size}{$hr_size}->[$i]." --size=1024 \n";
}
$partition_body .= "
# LVM PV
";
my $say_raid = "";
for (my $i = 0; $i < $count; $i++)
{
my $disk_number = $i + 1;
$partition_body .= "part raid.1".$disk_number." --size 100 --grow --ondisk=".$drives->{by_hr_size}{$hr_size}->[$i]."\n";
$say_raid .= "raid.1".$disk_number." ";
}
$partition_body .= "raid pv.01 --fstype=xfs --device=pv.01 --level=RAID".$raid_level." ".$say_raid."
# LVM Volume groups
volgroup ".$vg_name." pv.01
# LVM logical volumes
logvol swap --fstype=swap --size=".$swap_size." --name=lv_swap --vgname=".$vg_name."
logvol / --fstype=xfs --size=100 --grow --maxsize=".$root_size." --name=lv_root --vgname=".$vg_name."
";
}
### NOTE: This shouldn't be needed... See: https://bugzilla.redhat.com/show_bug.cgi?id=1654902
# Wipe out the start of each disk so that the install doesn't puke if it sees, for example, an mdadm
# signature on the sole disk being used as an install target.
foreach my $path (split/,/, $say_use_drive)
{
print "[ NOTE ] - Wiping the boot sector of: [".$path."] and configuring it for a GPT label.\n";
my $dd_out = system_call("/bin/dd bs=5120 count=1 if=/dev/zero of=".$path." oflag=dsync");
print __LINE__."; [ Debug ] - dd output:
================================================================================
".$dd_out."
================================================================================\n" if $debug;
my $partprobe_out = system_call("/sbin/partprobe --summary ".$path);
print __LINE__."; [ Debug ] - partprobe summary.
================================================================================
".$partprobe_out."
================================================================================\n" if $debug;
my $partx_out = system_call("/sbin/partx --update --verbose ".$path);
print __LINE__."; [ Debug ] - parted print output showing new layout.
================================================================================
".$partx_out."
================================================================================\n" if $debug;
}
# Flush things out. The article says to blindly sleep 30, but it says to do so to make sure udev, partx and
# others have updated. We're forcing the issue, which should be faster and safer.
system_call("/bin/sync");
system_call("/sbin/udevadm settle");
# Write out the file.
print __LINE__."; [ Debug ] - partition_body:
================================================================================
".$partition_body."
================================================================================\n";
print "Writing out the partition plan to: [".$partition_file."]\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 "Completed successfully, exiting.\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 -->
# Tradional BIOS based PXE menu
#
# Notes:
# - Use the 'vmlinuz' and 'initrd.img' from the Netinstall ISO. The others don't find the NIC, so can't net
# install.
#
# Use the high-colour menu system.
default vesamenu.c32
# Time out and use the default menu option. Defined as tenths of a second.
TIMEOUT 6000
# Prompt the user. Set to '1' to automatically choose the default option. This
# is really meant for files matched to MAC addresses.
PROMPT 0
# Set the boot menu to be 1024x768 with a nice background image. Be careful to
# ensure that all your user's can see this resolution! Default is 640x480.
MENU RESOLUTION 1024 768
# The background image
MENU BACKGROUND splash.jpg
MENU TITLE #!string!message_0080!#
# Below, the hash (#) character is replaced with the countdown timer. The
# '{,s}' allows for pluralizing a word and is used when the value is >= '2'.
MENU AUTOBOOT #!string!message_0081!#
MENU TABMSG #!string!message_0082!#
MENU NOTABMSG #!string!message_0083!#
# The following options set the various colours used in the menu. All possible
# options are specified except for F# help options. The colour is expressed as
# two hex characters between '00' and 'ff' for alpha, red, green and blue
# respectively (#AARRGGBB).
# Format is: MENU COLOR <Item> <ANSI Seq.> <foreground> <background> <shadow type>
MENU COLOR screen 0 #00000000 #00000000 std # background colour not covered by the splash image
MENU COLOR border 0 #bbd02724 #ee000000 std # The wire-frame border
MENU COLOR title 0 #fff2f2f2 #ee000000 std # Menu title text
MENU COLOR sel 0 #fff2f2f2 #ee000000 std # Selected menu option
MENU COLOR hotsel 0 #fffff2f2 #ee000000 std # The selected hotkey (set with ^ in MENU LABEL)
MENU COLOR unsel 0 #ffc2c2c2 #ee000000 std # Unselected menu options
MENU COLOR hotkey 0 #ffffc2c2 #ee000000 std # Unselected hotkeys (set with ^ in MENU LABEL)
MENU COLOR tabmsg 0 #c0a2a2a2 #00000000 std # Tab text
MENU COLOR timeout_msg 0 #ffc2c2c2 #00000000 std # Timout text
MENU COLOR timeout 0 #ffffc2c2 #00000000 std # Timout counter
MENU COLOR disabled 0 #80515151 #ee000000 std # Disabled menu options, including SEPARATORs
MENU COLOR cmdmark 0 #c0444444 #ee000000 std # Command line marker - The '> ' on the left when editing an option
MENU COLOR cmdline 0 #c0f2f2f2 #ee000000 std # Command line - The text being edited
# Options below haven't been tested, descriptions may be lacking.
MENU COLOR scrollbar 0 #407f7f7f #00000000 std # Scroll bar
MENU COLOR pwdborder 0 #80d02724 #20ffffff std # Password box wire-frame border
MENU COLOR pwdheader 0 #80f7f7f7 #20ffffff std # Password box header
MENU COLOR pwdentry 0 #80f2f2f2 #20ffffff std # Password entry field
MENU COLOR help 0 #c0f2f2f2 #c0000000 std # Help text, if set via 'TEXT HELP ... ENDTEXT'
### NOTE: inst.repo is the image of the install media, looks for .treeinfo
label striker
menu label ^1. #!string!message_0084!#
TEXT HELP
#!string!message_0085!#
ENDTEXT
kernel #!data!host_os::os_type!#/vmlinuz
# NOTE: add ' rd.debug' below for debugging
append initrd=#!data!host_os::os_type!#/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.gpt inst.sshd
label node
menu label ^2. #!string!message_0086!#
TEXT HELP
#!string!message_0087!#
ENDTEXT
kernel #!data!host_os::os_type!#/vmlinuz
append initrd=#!data!host_os::os_type!#/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.gpt inst.sshd
label node
menu label ^3. #!string!message_0088!#
TEXT HELP
#!string!message_0089!#
ENDTEXT
kernel #!data!host_os::os_type!#/vmlinuz
append initrd=#!data!host_os::os_type!#/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.gpt inst.sshd
label rescue
menu label ^4. #!string!message_0090!#
TEXT HELP
#!string!message_0091!#
ENDTEXT
kernel #!data!host_os::os_type!#/vmlinuz
append initrd=#!data!host_os::os_type!#/initrd.img ip=dhcp root=live:#!variable!base_url!#/LiveOS/squashfs.img rescue inst.repo=#!variable!base_url!#/os/ ip=dhcp inst.sshd
label #!data!host_os::os_type!#
menu label ^5. #!string!message_0092!#
TEXT HELP
#!string!message_0093!#
ENDTEXT
kernel #!data!host_os::os_type!#/vmlinuz
append initrd=#!data!host_os::os_type!#/initrd.img root=live:#!variable!base_url!#/images/install.img inst.repo=#!variable!base_url!#/os/ ip=dhcp inst.gpt inst.sshd
label next
menu default
menu label ^6. #!string!message_0094!#
localboot 0xffff
<!-- end tftp_bios -->
<!-- start tftp_grub -->
set default="1"
function load_video {
insmod efi_gop
insmod efi_uga
insmod video_bochs
insmod video_cirrus
insmod all_video
}
load_video
set gfxpayload=keep
insmod gzio
insmod part_gpt
insmod ext2
set timeout=60
### END /etc/grub.d/00_header ###
search --no-floppy --set=root -l 'RHEL-8-3-0-BaseOS-x86_64'
### BEGIN /etc/grub.d/10_linux ###
menuentry 'Install #!variable!say_os!# 8' --class fedora --class gnu-linux --class gnu --class os {
linuxefi #!data!host_os::os_type!#/vmlinuz ip=dhcp inst.repo=#!variable!base_url!#/os/
initrdefi #!data!host_os::os_type!#/initrd.img
}
menuentry '#!string!message_0084!#' --class #!data!host_os::os_type!# --class gnu-linux --class gnu --class os {
linuxefi #!data!host_os::os_type!#/vmlinuz ip=dhcp inst.repo=#!variable!base_url!#/os/ inst.ks=#!variable!base_url!#/kickstart/striker.ks inst.gpt inst.sshd
initrdefi #!data!host_os::os_type!#/initrd.img
}
<!-- end tftp_grub -->
<!-- start tftp_uefi -->
set timeout="-1"
set default="1"
function load_video {
insmod efi_gop
insmod efi_uga
insmod video_bochs
insmod video_cirrus
insmod all_video
}
load_video
set gfxpayload=keep
insmod gzio
menuentry 'Install RHEL 8' --class rhel --class gnu-linux --class gnu --class os {
linuxefi #!data!host_os::os_type!#/vmlinuz ip=dhcp inst.repo=#!variable!base_url!#/#!data!host_os::os_type!#/#!data!host_os::os_arch!#/iso/
initrdefi #!data!host_os::os_type!#/initrd.img
}
menuentry '#!string!message_0084!#' --class #!data!host_os::os_type!# --class gnu-linux --class gnu --class os { inst.ks=#!variable!base_url!#/kickstart/striker.ks inst.gpt inst.sshd
linuxefi #!data!host_os::os_type!#/vmlinuz ip=dhcp inst.repo=#!variable!base_url!#/#!data!host_os::os_type!#/#!data!host_os::os_arch!#/iso/
initrdefi #!data!host_os::os_type!#/initrd.img
}
<!-- end tftp_uefi -->
<!-- start temp -->
label node
menu label ^2. #!string!message_0086!#
TEXT HELP
#!string!message_0087!#
ENDTEXT
kernel #!data!host_os::os_type!#/vmlinuz
append initrd=#!data!host_os::os_type!#/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.gpt inst.sshd
label node
menu label ^3. #!string!message_0088!#
TEXT HELP
#!string!message_0089!#
ENDTEXT
kernel #!data!host_os::os_type!#/vmlinuz
append initrd=#!data!host_os::os_type!#/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.gpt inst.sshd
label rescue
menu label ^4. #!string!message_0090!#
TEXT HELP
#!string!message_0091!#
ENDTEXT
kernel #!data!host_os::os_type!#/vmlinuz
append initrd=#!data!host_os::os_type!#/initrd.img ip=dhcp root=live:#!variable!base_url!#/LiveOS/squashfs.img rescue inst.repo=#!variable!base_url!#/os/ ip=dhcp inst.sshd
label #!data!host_os::os_type!#
menu label ^5. #!string!message_0092!#
TEXT HELP
#!string!message_0093!#
ENDTEXT
kernel #!data!host_os::os_type!#/vmlinuz
append initrd=#!data!host_os::os_type!#/initrd.img root=live:#!variable!base_url!#/images/install.img inst.repo=#!variable!base_url!#/os/ ip=dhcp inst.gpt inst.sshd
label next
menu default
menu label ^6. #!string!message_0094!#
localboot 0xffff
<!-- end temp -->