You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
963 lines
33 KiB
963 lines
33 KiB
<!-- 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-release |
|
#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 -->
|
|
|