* Almost finished the first draft of the 'plan_partitions' kickstart (sub)script.

Signed-off-by: Digimer <digimer@alteeve.ca>
main
Digimer 6 years ago
parent 07c3b405ad
commit 702cb0f102
  1. 6
      Anvil/Tools/System.pm
  2. 2
      rpm/SPECS/anvil.spec
  3. 268
      scripts/plan_partitions

@ -266,9 +266,9 @@ sub call
while(<$file_handle>) while(<$file_handle>)
{ {
chomp; chomp;
my $line = $_; my $line = $_;
$line =~ s/\n$//; $line =~ s/\n$//;
$line =~ s/\r$//; $line =~ s/\r$//;
$anvil->Log->entry({source => $THIS_FILE, line => __LINE__, level => $debug, secure => $secure, key => "log_0017", variables => { line => $line }}); $anvil->Log->entry({source => $THIS_FILE, line => __LINE__, level => $debug, secure => $secure, key => "log_0017", variables => { line => $line }});
$output .= $line."\n"; $output .= $line."\n";
} }

@ -30,7 +30,9 @@ Requires: fence-agents-all
Requires: fence-agents-virsh Requires: fence-agents-virsh
Requires: firewalld Requires: firewalld
Requires: gpm Requires: gpm
Requires: hdparm
Requires: htop Requires: htop
Requires: lsscsi
Requires: mlocate Requires: mlocate
Requires: perl-Data-Dumper Requires: perl-Data-Dumper
Requires: perl-DBD-Pg Requires: perl-DBD-Pg

@ -0,0 +1,268 @@
#!/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.
#
use strict;
use warnings;
my $debug = 0;
my $type = defined $ARGV[0] ? $ARGV[0] : "";
#print "Type: [".$type."]\n";
if ($type =~ /striker/i)
{
print "Finding install drive for a Striker dashboard.\n";
$type = "striker";
}
elsif ($type =~ /node/i)
{
print "Finding install drive for an Anvil! node.\n";
$type = "node";
}
elsif ($type =~ /dr/i)
{
print "Finding install drive for a DR (disaster recovery) host.\n";
$type = "dr";
}
else
{
print "Error: Target type not specified.\n";
print "Usage: ".$0." [striker,node,dr]\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;
next if (($removable) or ($hotplug) or ($type ne "disk"));
$device->{$path} = {
type => $type,
size => $size,
transport => $transport,
rotational => $rotational,
};
if ($device->{$path}{rotational})
{
print "Analyzing platter drive: [".$path."], using the transport: [".$device->{$path}{transport}."], of the size: [".$device->{$path}{size}." (".hr_size($device->{$path}{size}).")]\n";
}
else
{
print "Analyzing solid-state drive: [".$path."], using the transport: [".$device->{$path}{transport}."], of the size: [".$device->{$path}{size}." (".hr_size($device->{$path}{size}).")]\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 "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);
}
# Finally, we've got our output.
my $partition_file = "/tmp/partition_plan";
my $partition_body = "";
if ($type eq "striker")
{
$partition_body = "
zerombr
clearpart --all --drives=".$use_drive."
ignoredisk --only-use=".$use_drive."
bootloader --location=mbr --driveorder=".$use_drive."
part /boot --fstype ext4 --size=1024 --asprimary --ondisk=".$use_drive."
part swap --fstype swap --size=4096 --asprimary --ondisk=".$use_drive."
part / --fstype ext4 --size=100 --asprimary --ondisk=".$use_drive." --grow
";
}
else
{
$partition_body = "
zerombr
clearpart --all --drives=".$use_drive."
ignoredisk --only-use=".$use_drive."
bootloader --location=mbr --driveorder=".$use_drive."
part /boot --fstype ext4 --size=1024 --asprimary --ondisk=".$use_drive."
part swap --fstype swap --size=4096 --asprimary --ondisk=".$use_drive."
part / --fstype ext4 --size=100 --asprimary --ondisk=".$use_drive."
";
}
print "Writing out the partition plan to: [".$partition_file."]\n";
#print __LINE__."; [ Debug ] - partition_body: [".$partition_body."]\n" if $debug;
print __LINE__."; [ Debug ] - partition_body: [".$partition_body."]\n";
exit(0);
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);
}
Loading…
Cancel
Save