initial commit of file from CVS for e-smith-base on Thu 26 Oct 11:24:52 BST 2023

This commit is contained in:
2023-10-26 11:24:52 +01:00
parent bbc22988a8
commit 9510d1a360
678 changed files with 22721 additions and 2 deletions

View File

@@ -0,0 +1,3 @@
package esmith::console::configure;
use esmith::console::configure;
return new esmith::console::configure;

View File

@@ -0,0 +1,303 @@
package esmith::console::manageDiskRedundancy;
use strict;
use warnings;
use esmith::console;
use Locale::gettext;
use Taint::Util;
use Data::Dumper;
use constant DEBUG_MANAGE_RAID => 0;
sub new
{
my $class = shift;
my $self = {
name => gettext("Manage disk redundancy"),
order => 45,
};
bless $self, $class;
return $self;
}
sub name
{
return $_[0]->{name};
}
sub order
{
return $_[0]->{order};
}
sub doit
{
my ($self, $console, $db) = @_;
my ($rc, $choice);
use POSIX qw(strftime);
SCAN:
my $today = strftime "%A %B %e, %Y %H:%M:%S", localtime;
my $title = gettext("Disk redundancy status as of") . " " . $today,
my $text = gettext("Current RAID status:") . "\n\n" .
join("", get_raid_status()) . "\n\n";
my %devices = get_raid_details();
warn $text if DEBUG_MANAGE_RAID;
warn "devices: " . Dumper(\%devices) . "\n" if DEBUG_MANAGE_RAID;
unless (scalar %devices)
{
$text = gettext("There are no RAID devices configured");
($rc, $choice) = $console->message_page(title => $title, text => $text);
return;
}
# Determine the status of each array
my @unclean = ();
my @recovering = ();
my @failed = ();
my %used_disks = ();
for my $dev (keys %devices)
{
$used_disks{$_}++ for (@{$devices{$dev}{UsedDisks}});
if ($devices{$dev}{FailedDevices} > 0) {
push @failed, "$dev => " . $devices{$dev}{FailedDevices};
}
if ($devices{$dev}{State} =~ /recovering|resync/) {
push @recovering, "$dev => " . $devices{$dev}{State};
next;
}
next if ($devices{$dev}{State} =~ /^(clean|active)\s*$/);
push @unclean, "$dev => " . $devices{$dev}{State};
}
warn "unclean: @unclean\n" if DEBUG_MANAGE_RAID;
warn "recovering: @recovering\n" if DEBUG_MANAGE_RAID;
warn "failed: @failed\n" if DEBUG_MANAGE_RAID;
warn "used_disks: " . Dumper(\%used_disks) . "\n" if DEBUG_MANAGE_RAID;
# Check for any spare disks we could add
my %free_disks = map {$_ => 1} get_disks();
delete $free_disks{$_} for keys %used_disks;
warn "free_disks: " . Dumper(\%free_disks) . "\n" if DEBUG_MANAGE_RAID;
# Report status and return if recovering
if (scalar @recovering)
{
$text .= gettext("A RAID resynchronization is in progress.");
($rc, $choice) = $console->message_page(title => $title, text => $text);
return;
}
# Report status and return if arrays are inconsistent
if ((scalar @unclean && scalar @unclean != scalar keys %devices) || (scalar @failed && scalar @failed != scalar keys %devices))
{
$text .= gettext("Only some of the RAID devices are unclean or contain failed disks.") .
"\n\n" .
gettext("Manual intervention may be required.") . "\n\n";
($rc, $choice) = $console->message_page(title => $title, text => $text);
return;
}
# Report status if arrays are clean and continue if a spare disk is available or there's only one disk in the system
unless (scalar @unclean || scalar @failed)
{
$text .= gettext("All RAID devices are in a clean state.");
($rc, $choice) = $console->message_page(title => $title, text => $text);
return unless scalar keys %free_disks > 0 || scalar keys %used_disks == 1;
}
# Report status if all arrays are dirty and continue
if ((scalar @unclean && scalar @unclean == scalar keys %devices) || (scalar @failed && scalar @failed == scalar keys %devices))
{
$text .= gettext("All RAID devices are in an unclean state or contain failed disks.");
($rc, $choice) = $console->message_page(title => $title, text => $text);
}
# Summarise disk assignments
my $disk_status = gettext("Current disk status:") . "\n\n";
$disk_status .= gettext("Installed disks") . ": " .
join(" ", get_disks()) . "\n";
$disk_status .= gettext("Used disks") . ": " .
join(" ", keys %used_disks) . "\n";
$disk_status .= gettext("Free disks") . ": " .
join(" ", keys %free_disks) . "\n";
# Spare disk scenarios
# Scenario 1 - single disk or degraded array with no spare - warn
if ((scalar @unclean || scalar @failed || scalar keys %used_disks == 1) && scalar keys %free_disks == 0)
{
$text = $disk_status .
"\n\n" .
gettext("To ensure continued redundancy, please shut down, install another drive of the same capacity and then return to this screen.");
($rc, $choice) = $console->message_page(title => $title, text => $text);
return;
}
# Scenario 2 - no spares and not degraded so something has gone wrong
if (scalar keys %free_disks == 0)
{
$text = $disk_status .
"\n\n" .
gettext("Your RAID devices are in an inconsistent state, and no spare drives were detected. You may need to manually remove a failed drive from your arrays using mdadm.");
($rc, $choice) = $console->message_page(title => $title, text => $text);
return;
}
# Scenario 3 - multiple spares
if (scalar keys %free_disks > 1)
{
$text = $disk_status .
"\n\n" .
gettext("Multiple spare drives have been detected. This utility can only add one drive at a time. Please either shut down and remove all but one of your spare drives, or configure your array manually.");
($rc, $choice) = $console->message_page(title => $title, text => $text);
return;
}
# Scenario 4 - single spare ready to add
$text = $disk_status .
"\n\n" .
gettext("There is an unused disk drive in your system. Do you want to add it to the existing RAID array(s)?") .
"\n\n" .
gettext("WARNING: ALL DATA ON THE NEW DISK WILL BE DESTROYED!") .
"\n";
($rc, $choice) = $console->yesno_page(title => $title, text => $text, defaultno => 1);
return unless ($rc == 0);
my @cmd = ("/sbin/e-smith/add_drive_to_raid", "-f", join("", keys %free_disks));
my $cmd_out = qx( @cmd 2>&1 );
untaint $cmd_out;
if ($? == 0) {
$text = "\nSuccessfully added /dev/" . join("", keys %free_disks) . " to RAID!";
} else {
$text = gettext("The command failed:") . " @cmd" .
"\n\n" . $cmd_out . "\n\n";
}
($rc, $choice) = $console->message_page(title => $title, text => $text);
goto SCAN;
}
sub get_raid_status
{
die gettext("Couldn't open") . " /proc/mdstat:$!\n"
unless (open(MDSTAT, "/proc/mdstat"));
my @mdstat;
while (<MDSTAT>)
{
push @mdstat, "$1\n" if (/(.*\w.*)/);
}
close MDSTAT;
return @mdstat;
}
sub get_raid_details
{
my @devices = ();
die gettext("Couldn't call") . " mdadm: $!\n"
unless open(MDADM, "/sbin/mdadm --detail --scan|");
while (<MDADM>)
{
push @devices, $1 if ( m:ARRAY (/dev/md/\w+): )
}
close MDADM;
my %devices;
for my $dev (@devices)
{
die gettext("Couldn't call") . " mdadm --detail $dev: $!\n"
unless open(MDADM, "/sbin/mdadm --detail $dev|");
while ( <MDADM> )
{
if ( /\s*(.*)\s+:\s+(\d+)\s+\(.*\)\s*/ )
{
my ($key, $value) = ($1, $2);
$key =~ s/\s//g;
# Allow for different mdadm output formats for DeviceSize
$key =~ s/UsedDevSize/DeviceSize/;
$devices{$dev}{$key} = $value;
}
elsif ( /\s*(.*)\s+:\s+(.*)\s*/ )
{
my ($key, $value) = ($1, $2);
$key =~ s/\s//g;
$devices{$dev}{$key} = $value;
}
if ( m:\s+(\d+)\s+(\d+)\s+(\d+).*/dev/([\w\/]+): )
{
$devices{$dev}{$1} = $_;
my $used_disk = $4;
if (/(rd|ida|cciss|i2o)\//) {
$used_disk =~ s/p\d+$//;
} else {
$used_disk =~ s/\d+//;
}
push (@{$devices{$dev}{UsedDisks}}, $used_disk);
}
}
close MDADM;
}
return %devices;
}
sub get_partitions
{
die gettext("Couldn't read") . " /proc/partitions: $!\n"
unless open (PARTITIONS, "/proc/partitions");
my %parts;
while (<PARTITIONS>)
{
if ( /\s+(\d+)\s+(\d+)\s+(\d+)\s+([\w\/]+)\s+/ )
{
my $name = $4;
$parts{$name}{major} = $1;
$parts{$name}{minor} = $2;
$parts{$name}{blocks} = $3;
}
}
close PARTITIONS;
return %parts;
}
sub get_disks
{
my %parts = get_partitions();
my @disks;
for (keys %parts)
{
push @disks, $_ unless (/[0-9]$/);
push @disks, $_ if (/(rd|ida|cciss|i2o)\// && ! /p\d+$/);
}
return @disks;
}
return new esmith::console::manageDiskRedundancy;

View File

@@ -0,0 +1,80 @@
package esmith::console::reboot;
use strict;
use warnings;
use esmith::console;
use Locale::gettext;
sub new
{
my $class = shift;
my $self = {
name => gettext("Reboot, reconfigure or shut down this server"),
order => 40,
};
bless $self, $class;
return $self;
}
sub name
{
return $_[0]->{name};
}
sub order
{
return $_[0]->{order};
}
sub doit
{
#------------------------------------------------------------
# REBOOT_SHUTDOWN:
#------------------------------------------------------------
my ($self, $console, $db) = @_;
my @args =
(
gettext("Reboot"), gettext("Reboot this server"),
gettext("Reconfigure"), gettext("Reconfigure this server"),
gettext("Shutdown"), gettext("Shutdown this server"),
);
my ($rc, $choice) = $console->menu_page
(
title => gettext("Reboot, reconfigure or shutdown this server"),
text =>
gettext("Please select whether you wish to reboot, reconfigure or shutdown. The process will start as soon as you make your selection.") .
"\n\n" .
gettext("If you have an older computer without power management, the shutdown process will perform a clean halt of all system services, but will not actually power off your computer. In this case, wait for the power down message and then shut off the power manually.") .
"\n\n" .
gettext("If you have changed your mind and do not want to reboot or shutdown, use the Tab key to select Cancel, then press Enter."),
argsref => \@args,
left => gettext("Cancel"),
right => gettext("OK"),
);
return unless ($rc == 0);
if ($choice eq gettext('Shutdown'))
{
system("/usr/bin/tput", "clear");
system("/sbin/e-smith/signal-event", "halt");
}
elsif ($choice eq gettext('Reboot'))
{
system("/usr/bin/tput", "clear");
system("/sbin/e-smith/signal-event", "reboot");
}
elsif ($choice eq gettext('Reconfigure'))
{
system("/usr/bin/tput", "clear");
system("/sbin/e-smith/signal-event", "post-upgrade");
system("/sbin/e-smith/signal-event", "reboot");
}
# A bit of a hack to avoid the console restarting before the
# reboot takes effect.
sleep(600);
}
return new esmith::console::reboot;

View File

@@ -0,0 +1,60 @@
package esmith::console::serverManager;
use strict;
use warnings;
use esmith::console;
use Locale::gettext;
sub new
{
my $class = shift;
my $self = {
name => gettext("Access server manager"),
order => 50,
};
bless $self, $class;
return $self;
}
sub name
{
return $_[0]->{name};
}
sub order
{
return $_[0]->{order};
}
sub doit
{
my ($self, $console, $db) = @_;
#------------------------------------------------------------
# MANAGER:
#------------------------------------------------------------
my $SystemName = $db->get_value('SystemName');
my ($rc, $choice) = $console->yesno_page
(
title => gettext("Access server manager"),
text =>
gettext("This option will start a text-mode browser to access the server manager from this console. Normally you would access the server manager from a web browser at the following url:") .
"\n\n" .
"http://${SystemName}/server-manager/" .
"\n\n" .
gettext("You should only proceed if you are comfortable using a text-mode browser. Note that you will be prompted for the administrator password in order to access the server manager.") .
"\n\n" .
gettext("NOTE: The 'q' key is used to quit from the text-mode browser.") .
"\n\n" .
gettext("Do you wish to proceed?"),
);
if ($rc == 0)
{
system(
"/usr/bin/links",
"http://localhost/server-manager"
);
}
$db->reload;
}
return new esmith::console::serverManager;

View File

@@ -0,0 +1,70 @@
package esmith::console::status;
use strict;
use warnings;
use esmith::console;
use Locale::gettext;
sub new
{
my $class = shift;
my $self = {
name => gettext("Check status of this server"),
order => 10,
};
bless $self, $class;
return $self;
}
sub name
{
return $_[0]->{name};
}
sub order
{
return $_[0]->{order};
}
sub doit
{
#------------------------------------------------------------
# STATUS:
#------------------------------------------------------------
my ($self, $console, $db) = @_;
use POSIX qw(strftime);
my $today = strftime "%A %B %e, %Y", localtime;
unless (open(UPTIME, "</proc/uptime"))
{
warn("Could not open /proc/uptime: $!");
return;
}
my $seconds = <UPTIME>;
close UPTIME or warn("Could not close /proc/uptime: $!");
# Select and untaint seconds
$seconds =~ /(\d+)/;
$seconds = $1;
my $days = int ($seconds / 86400);
$seconds = $seconds % 86400;
my $hours = int ($seconds / 3600);
$seconds = $seconds % 3600;
my $minutes = int ($seconds / 60);
$seconds = $seconds % 60;
my ($rc, $choice) = $console->screen
(
"--title", gettext("Status of this server as of") . " " . $today,
"--msgbox", gettext("This server has been running for") . " " .
$days . " " . gettext("days") . ", " .
$hours . " " . gettext("hours") . ", " .
$minutes . " " . gettext("minutes"),
7, esmith::console::SCREEN_COLUMNS
);
}
return new esmith::console::status;