diff --git a/Anvil/Tools.pm b/Anvil/Tools.pm
index 7c0f0990..d9d3747e 100755
--- a/Anvil/Tools.pm
+++ b/Anvil/Tools.pm
@@ -846,6 +846,12 @@ sub _set_defaults
server => "",
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,
## we need to use a wider spread between the BCNs, SNs and IFNs than we had
## in v2.
diff --git a/Anvil/Tools/Storage.pm b/Anvil/Tools/Storage.pm
index bc9646b7..7cd74e63 100755
--- a/Anvil/Tools/Storage.pm
+++ b/Anvil/Tools/Storage.pm
@@ -383,7 +383,7 @@ sub change_mode
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.
diff --git a/anvil.conf b/anvil.conf
index cf128905..75c053cd 100644
--- a/anvil.conf
+++ b/anvil.conf
@@ -134,3 +134,22 @@
#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
+
diff --git a/html/skins/alteeve/images/bios-splash.jpg b/html/skins/alteeve/images/bios-splash.jpg
new file mode 100644
index 00000000..4046b5ba
Binary files /dev/null and b/html/skins/alteeve/images/bios-splash.jpg differ
diff --git a/html/skins/alteeve/pxe.txt b/html/skins/alteeve/pxe.txt
index 06aecca8..9c1a8112 100644
--- a/html/skins/alteeve/pxe.txt
+++ b/html/skins/alteeve/pxe.txt
@@ -23,6 +23,405 @@ subnet #!variable!network!# netmask 255.255.0.0 {
}
+
+
+### 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
+
+
+
# Tradional BIOS based PXE menu
#
@@ -89,7 +488,8 @@ TEXT HELP
#!string!message_0085!#
ENDTEXT
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
menu label #!string!message_0086!#
@@ -97,7 +497,7 @@ TEXT HELP
#!string!message_0087!#
ENDTEXT
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
menu label #!string!message_0088!#
@@ -105,7 +505,7 @@ TEXT HELP
#!string!message_0089!#
ENDTEXT
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
menu label #!string!message_0090!#
diff --git a/notes b/notes
index 676cde12..19f6febd 100644
--- a/notes
+++ b/notes
@@ -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
Firewall config stuff.
diff --git a/share/words.xml b/share/words.xml
index a8536a3f..32c4254f 100644
--- a/share/words.xml
+++ b/share/words.xml
@@ -197,7 +197,32 @@ NOTE: Please be patient!
Copying the syslinux files: [#!data!path::directories::syslinux!#/*] into the tftpboot directory: [#!data!path::directories::tftpboot!#].
The syslinux files from: [#!data!path::directories::syslinux!#] appear to already be in the tftpboot directory: [#!data!path::directories::tftpboot!#], skipping.
Checking that the "Install Target" function is configured and updated.
-
+
+ Finding install drive for a Striker dashboard.
+ Finding install drive for an Anvil! node.
+ Finding install drive for a DR (disaster recovery) host.
+
+[ Error ] - Target type not specified. Be sure that '\$type' is set to
+ 'striker', 'node' or 'dr' in the \%pre section of the kickstart
+ script.
+
+
+ {$path}{transport}."], of the size: [".$device->{$path}{size}." (".hr_size($device->{$path}{size}).")]]]>
+ {$path}{transport}."], of the size: [".$device->{$path}{size}." (".hr_size($device->{$path}{size}).")]]]>
+ {$use_drive}{size})."]]]>
+ {$use_drive}{size})."]]]>
+ {$use_drive}{size})."] (no platter drives found)]]>
+
+
+
+
+ Striker Dashboard
+ Anvil! Node
+ Dsaster Recovery (DR) Host
+
+
+
+
Starting: [#!variable!program!#].
diff --git a/tools/anvil-manage-install-target b/tools/anvil-manage-install-target
index 72c8309e..92a72a8a 100755
--- a/tools/anvil-manage-install-target
+++ b/tools/anvil-manage-install-target
@@ -16,6 +16,7 @@
# 2 = BCN IP not found, unable to configure yet.
# 3 = Failed to write or update a configuration file.
# 4 = Not a striker dashboard (or isn't yet).
+# 5 = Not running as the 'root' user.
#
# TODO:
# - 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->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();
$anvil->data->{host_os}{os_type} = $os_type;
$anvil->data->{host_os}{os_arch} = $os_arch;
@@ -191,8 +201,7 @@ sub setup_boot_environment
}
- ### PXE BIOD 'default' file.
- # Setup the BIOS boot menu.
+ ### PXE BIOS 'default' file.
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 }});
@@ -220,6 +229,62 @@ sub setup_boot_environment
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.
my $old_autoindex_conf = $anvil->Storage->read_file({file => $anvil->data->{path}{configs}{'autoindex.conf'}});
my $new_autoindex_conf = "";
@@ -403,6 +468,20 @@ sub setup_boot_environment
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);
}
@@ -457,6 +536,9 @@ sub update_install_source
{
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.
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}};