Merge branch 'main' into daemon-management

main
Digimer 9 months ago committed by GitHub
commit 4fd12879c3
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
  1. 1
      Anvil/Tools.pm
  2. 5
      Anvil/Tools/Network.pm
  3. 52
      man/anvil-manage-server.8
  4. 142
      ocf/alteeve/server
  5. 13
      scancore-agents/scan-drbd/scan-drbd
  6. 4
      scancore-agents/scan-network/scan-network
  7. 85
      share/anvil.sql
  8. 7
      share/words.xml
  9. 2345
      tools/anvil-manage-server
  10. 190
      tools/fence_pacemaker
  11. 155
      tools/striker-get-screenshots

@ -1278,6 +1278,7 @@ sub _set_paths
ps => "/usr/bin/ps",
psql => "/usr/bin/psql",
pamtopng => "/usr/bin/pamtopng",
pngtopam => "/usr/bin/pngtopam",
pnmtojpeg => "/usr/bin/pnmtojpeg",
'postgresql-setup' => "/usr/bin/postgresql-setup",
postmap => "/usr/sbin/postmap",

@ -4445,6 +4445,9 @@ sub read_nmcli
}
}
# If I still don't have a device, ignore this.
next if not $device;
# Make it easy to look up a device's UUID by device or name.
$anvil->data->{nmcli}{$host}{name_to_uuid}{$name} = $uuid;
$anvil->data->{nmcli}{$host}{device_to_uuid}{$device} = $uuid;
@ -4704,7 +4707,7 @@ sub wait_for_network
next if $anvil->data->{network}{watch}{$interface_name}{ready};
my $uuid = $anvil->data->{network}{watch}{$interface_name}{uuid};
my $type = $anvil->data->{network}{watch}{$interface_name}{type};
my $state = $anvil->data->{nmcli}{$short_host_name}{uuid}{$uuid}{'state'};
my $state = defined $anvil->data->{nmcli}{$short_host_name}{uuid}{$uuid}{'state'} ? $anvil->data->{nmcli}{$short_host_name}{uuid}{$uuid}{'state'} : 0;
$anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => $debug, list => {
's1:interface_name' => $interface_name,
's2:type' => $type,

@ -1,13 +1,13 @@
.\" Manpage for the Alteeve! anvil-manage-server tool
.\" Contact mkelly@alteeve.com to report issues, concerns or suggestions.
.TH anvil-manage-server "8" "October 19 2022" "Anvil! Intelligent Availability™ Platform"
.TH anvil-manage-server "8" "Mar 21 2024" "Anvil! Intelligent Availability™ Platform"
.SH NAME
anvil-manage-server \- Tool used to manage a server running on an Anvil! cluster.
anvil-manage-server \- Tool used to manage a server, like resync'ing servers on a rebuilt host.
.SH SYNOPSIS
.B anvil-manage-server
\fI\,<command> \/\fR[\fI\,options\/\fR]
.SH DESCRIPTION
anvil-manage-server \- This tool allow the management of a server's hardware.
anvil-manage-server \- This tool allow the management of a server.
.TP
.SH OPTIONS
.TP
@ -25,49 +25,11 @@ Set the log level for this run to 1, 2 or 3 (higher == more verbose).
.TP
.SS "Commands:"
.TP
\-k, \fB\-\-anvil\fR <name or uuid>
If specified, and \fBserver\fR is not specified, this will list the servers running on the Anvil! system currently. If, in the unlikely event that two servers exist on different Anvil! systems but with the same name, this will help identify which server you want to work on.
\fB\-\-server\fR all, or <name or uuid>
This is the server to work on.
.TP
\-k, \fB\-\-server\fR <name or uuid>
.TP
\-k, \fB\-\-\fR <uuid>
.TP
\-k, \fB\-\-\fR <uuid>
.TP
\-k, \fB\-\-\fR <uuid>
.TP
\-k, \fB\-\-\fR <uuid>
.TP
\-k, \fB\-\-\fR <uuid>
.TP
\-k, \fB\-\-\fR <uuid>
.TP
\-k, \fB\-\-\fR <uuid>
.TP
\-k, \fB\-\-\fR <uuid>
.TP
\-k, \fB\-\-\fR <uuid>
$anvil->data->{switches}{boot} = ""; # This is a comma-separated list of ordered boot devices
$anvil->data->{switches}{cores} = ""; # This sets the server to use this number of CPU cores.
$anvil->data->{switches}{drive} = ""; # drive being modified (insert/eject ISO, growing drive)
$anvil->data->{switches}{eject} = ""; # This will eject whatever ISO (if any) in the '--drive'.
$anvil->data->{switches}{'expand-to'} = ""; # When the drive is a disk (backed by a DRBD resource), this is the new desired size to grow to.
$anvil->data->{switches}{insert} = ""; # This is the ISO to insert into the --drive
$anvil->data->{switches}{'job-uuid'} = "";
$anvil->data->{switches}{ram} = ""; # This is the amount of RAM to set the server to use.
$anvil->data->{switches}{server} = ""; # server name or uuid
$anvil->data->{switches}{y} = ""; # Don't prompt for confirmation. Only useful when there isn't a job UUID.
\fB\-\-resync\fR
This will check to see if the server is sync'ing on this host. If it is not, and if there are sufficient free resources, the server will be configured locally. This will create a local logical volume, which will be used to connect to the peer's replicated storage. The definition file will be written out, if needed. If '\fB\-\-server\fR' isn't used, all servers will be sync'ed (alphatically, stopping if there are insufficient resources).
.IP
.SH AUTHOR
Written by Madison Kelly, Alteeve staff and the Anvil! project contributors.

@ -1239,97 +1239,8 @@ sub server_status
$anvil->Log->entry({source => $THIS_FILE, line => __LINE__, level => 1, priority => "alert", key => "log_0331", variables => { timeout => $anvil->data->{environment}{OCF_RESKEY_CRM_meta_timeout} }});
}
# Is 'libvirtd' running? We'll wait up to half the timeout for it to start (in case it _just_ started)
# before timing out.
my $wait_until = time + ($anvil->data->{environment}{OCF_RESKEY_CRM_meta_timeout} / 2000); # Devide by 2000 to convert to seconds and total second halved.
my $look_for_pid = 0;
my $libvirtd_wait = 1;
my $warning_shown = 0;
while($libvirtd_wait)
{
my $running = $anvil->System->check_daemon({daemon => "libvirtd.service"});
$anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { running => $running }});
if ($running)
{
$libvirtd_wait = 0;
$anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { libvirtd_wait => $libvirtd_wait }});
}
else
{
# On EL8 and above, libvirtd starts on demand, so this error isn't
if (not $warning_shown)
{
$anvil->Log->entry({source => $THIS_FILE, line => __LINE__, level => 2, key => "log_0522", variables => { wait_time => ($wait_until - time) }});
$warning_shown = 1;
}
sleep 1;
if (time > $wait_until)
{
# Libvirtd isn't running, try to find the PID of the server (in case it's
# running and libvirtd isn't)
$anvil->Log->entry({source => $THIS_FILE, line => __LINE__, level => 2, priority => "alert", key => "warning_0057"});
$look_for_pid = 1;
$libvirtd_wait = 0;
$anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => {
look_for_pid => $look_for_pid,
libvirtd_wait => $libvirtd_wait,
}});
}
}
}
# If libvirtd wasn't running, we'll manually look for a PID.
if ($look_for_pid)
{
my $server_up = 0;
my $shell_call = $anvil->data->{path}{exe}{ps}." aux";
$anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { shell_call => $shell_call }});
my ($output, $return_code) = $anvil->System->call({shell_call => $shell_call});
$anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => {
output => $output,
return_code => $return_code,
}});
foreach my $line (split/\n/, $output)
{
next if $line !~ /qemu-kvm/;
$line = $anvil->Words->clean_spaces({ string => $line });
$anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { line => $line }});
if ($line =~ /guest=(.*?),/)
{
my $this_server = $1;
$anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { this_server => $this_server }});
if ($this_server eq $server)
{
# Found it.
$server_up = 1;
$anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { server_up => $server_up }});
last;
}
}
}
if ($server_up)
{
# The server is running. Exit with OCF_SUCCESS (rc 0);
$anvil->Log->entry({source => $THIS_FILE, line => __LINE__, level => 1, key => "log_0523"});
$anvil->nice_exit({exit_code => 0});
}
else
{
# The server is not running. Exit with OCF_NOT_RUNNING (rc: 7)
$anvil->Log->entry({source => $THIS_FILE, line => __LINE__, level => 1, key => "log_0524"});
$anvil->nice_exit({exit_code => 7});
}
}
else
{
# Parse the virsh state. If it's listed as 'crashed', return OCF_ERR_GENERIC (rc: 1). If it's
# 'in shutdown', 'loop' gets set to 1 and this will loop indefinitely. We don't put a timer
# on it, we let pacemaker handle that.
# libvirtd lists as disabled / stopped, but "starts" when called. So checking the daemon doesn't make
# sense. Given virsh might fail, if we don't find the server, we'll also look for it in 'ps'.
my $loop = 1;
while($loop)
{
@ -1343,6 +1254,8 @@ sub server_status
output => $output,
return_code => $return_code,
}});
if (not $return_code)
{
foreach my $line (split/\n/, $output)
{
$line = $anvil->Words->clean_spaces({ string => $line });
@ -1382,7 +1295,6 @@ pmsuspended - The domain has been suspended by guest power management, e.g. ente
$anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { loop => $loop }});
sleep 1;
last;
}
elsif ($state eq "shut off")
{
@ -1401,11 +1313,53 @@ pmsuspended - The domain has been suspended by guest power management, e.g. ente
}
}
}
}
# If it wasn't found at all, exit.
if (not $found)
if ((not $found) or ($return_code))
{
# Exit with OCF_NOT_RUNNING (rc: 7);
# If we've timed out, we'll look for it using it's PID.
my $server_up = 0;
my $shell_call = $anvil->data->{path}{exe}{ps}." aux";
$anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { shell_call => $shell_call }});
my ($output, $return_code) = $anvil->System->call({shell_call => $shell_call});
$anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => {
output => $output,
return_code => $return_code,
}});
foreach my $line (split/\n/, $output)
{
next if $line !~ /qemu-kvm/;
$line = $anvil->Words->clean_spaces({ string => $line });
$anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { line => $line }});
if ($line =~ /guest=(.*?),/)
{
my $this_server = $1;
$anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { this_server => $this_server }});
if ($this_server eq $server)
{
# Found it.
$server_up = 1;
$anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { server_up => $server_up }});
last;
}
}
}
# Did we find it by PID?
if ($server_up)
{
# The server is running. Exit with OCF_SUCCESS (rc 0);
$anvil->Log->entry({source => $THIS_FILE, line => __LINE__, level => 1, key => "log_0523"});
$anvil->nice_exit({exit_code => 0});
}
else
{
# The server is not running. Exit with OCF_NOT_RUNNING (rc: 7)
$anvil->Log->entry({source => $THIS_FILE, line => __LINE__, level => 1, key => "log_0526", variables => { server_name => $server }});
$anvil->nice_exit({exit_code => 7});
}

@ -100,6 +100,8 @@ find_changes($anvil);
check_config($anvil);
find_missing_resources($anvil);
fix_things($anvil);
# Shut down.
@ -110,6 +112,17 @@ $anvil->ScanCore->agent_shutdown({agent => $THIS_FILE});
# Functions #
#############################################################################################################
# If this node has been rebuilt, we'll need to add missing DRBD resources. This isn't done in
# anvil-join-anvil as the backing VG may not show free space if the user simply deleted the '/home'
# partition.
sub find_missing_resources
{
my ($anvil) = @_;
return(0);
}
# This looks for issues that we can fix, and if any are found, we try to fix them.
sub fix_things
{

@ -3162,6 +3162,10 @@ sub check_interfaces
network_interface_name => $network_interface_name,
new_nm_device => $new_nm_device,
}});
# If there's no device and no interface name, ignore it.
next if ((not $new_nm_name) && (not $new_nm_device));
my $network_interface_uuid = $anvil->Database->insert_or_update_network_interfaces({
debug => 2,
network_interface_nm_uuid => $new_nm_uuid,

@ -1183,91 +1183,6 @@ CREATE TRIGGER trigger_ip_addresses
FOR EACH ROW EXECUTE PROCEDURE history_ip_addresses();
/*
TODO - This will be added only if we need to use it if the existing network tables aren't sufficient
-- This stores information about network interfaces on hosts. It is mainly used to match a MAC address to a
-- host. Given that it is possible that network devices can move, the linkage to the host_uuid can change.
CREATE TABLE network_manager (
network_manager_uuid uuid not null primary key, -- Unlike most other tables, this UUID comes from nmcli itself, and so this matches what's displayed nmcli
network_manager_host_uuid uuid not null, -- The host_uuid for this interface
network_manager_device text not null, -- This is the nmcli "device" name
network_manager_name text not null, -- This is the nmcli "name" name
network_manager_mac text not null, -- This is the MAC address of the interface
network_manager_type text not null, -- This is the nmcli "type" string
network_manager_active text not null, -- This is the nmcli "active" field
network_manager_state text not null, -- This is the nmcli "state" field
network_manager_connected numeric not null, -- This is '0' if the connection is down, or a unix timestamp if it's up.
network_manager_mtu numeric not null, -- This is the MTU of the interface
modified_date timestamp with time zone not null,
FOREIGN KEY(network_manager_host_uuid) REFERENCES hosts(host_uuid)
);
ALTER TABLE network_manager OWNER TO admin;
CREATE TABLE history.network_manager (
history_id bigserial,
network_manager_uuid uuid not null,
network_manager_host_uuid uuid,
network_manager_mac_address text,
network_manager_name text,
network_manager_speed bigint,
network_manager_mtu bigint,
network_manager_link_state text,
network_manager_operational text,
network_manager_duplex text,
network_manager_medium text,
network_manager_bond_uuid uuid,
network_manager_bridge_uuid uuid,
modified_date timestamp with time zone not null
);
ALTER TABLE history.network_manager OWNER TO admin;
CREATE FUNCTION history_network_manager() RETURNS trigger
AS $$
DECLARE
history_network_manager RECORD;
BEGIN
SELECT INTO history_network_manager * FROM network_manager WHERE network_manager_uuid = new.network_manager_uuid;
INSERT INTO history.network_manager
(network_manager_uuid,
network_manager_host_uuid,
network_manager_mac_address,
network_manager_name,
network_manager_speed,
network_manager_mtu,
network_manager_link_state,
network_manager_operational,
network_manager_duplex,
network_manager_medium,
network_manager_bond_uuid,
network_manager_bridge_uuid,
modified_date)
VALUES
(history_network_manager.network_manager_uuid,
history_network_manager.network_manager_host_uuid,
history_network_manager.network_manager_mac_address,
history_network_manager.network_manager_name,
history_network_manager.network_manager_speed,
history_network_manager.network_manager_mtu,
history_network_manager.network_manager_link_state,
history_network_manager.network_manager_operational,
history_network_manager.network_manager_duplex,
history_network_manager.network_manager_medium,
history_network_manager.network_manager_bond_uuid,
history_network_manager.network_manager_bridge_uuid,
history_network_manager.modified_date);
RETURN NULL;
END;
$$
LANGUAGE plpgsql;
ALTER FUNCTION history_network_manager() OWNER TO admin;
CREATE TRIGGER trigger_network_manager
AFTER INSERT OR UPDATE ON network_manager
FOR EACH ROW EXECUTE PROCEDURE history_network_manager();
*/
-- This stores files made available to Anvil! systems and DR hosts.
CREATE TABLE files (
file_uuid uuid not null primary key,

@ -2377,10 +2377,10 @@ The file: [#!variable!file!#] needs to be updated. The difference is:
<key name="log_0520">The server: [#!variable!server!#] is indeed running. It will be shut down now.</key>
<key name="log_0521">Checking the status of the server: [#!variable!server!#].</key>
<key name="log_0522">The 'libvirtd' daemon is not running. It may be starting up, will wait: [#!variable!wait_time!#] seconds...</key>
<key name="log_0523">Found the server to be running using it's PID. The state of the server can't be determined, however. Please start the 'libvirtd' daemon!</key>
<key name="log_0523">Found the server to be running using it's PID. The state of the server can't be determined, however. There appears to be a problem with 'virsh'!</key>
<key name="log_0524">No PID for the server was found. It is not running on this host.</key>
<key name="log_0525">The server: [#!variable!server_name!#] is shutting down. Will wait for it to finish...</key>
<key name="log_0526">The server: [#!variable!server_name!#] is off.</key>
<key name="log_0526">The server: [#!variable!server_name!#] is off (not found in virsh or by PID).</key>
<key name="log_0527">The server: [#!variable!server_name!#] is running (state is: [#!variable!state!#]).</key>
<key name="log_0528">We've been asked to migrating the server: [#!variable!server!#] to: [#!variable!target_host!#].</key>
<key name="log_0529">Checking server state after: [#!variable!server!#] was migrated to this host.</key>
@ -2681,7 +2681,7 @@ The file: [#!variable!file!#] needs to be updated. The difference is:
<key name="log_0804">Connecting: [#!variable!host_name!#] via: [#!variable!target_ip!#]</key>
<key name="log_0805">Getting a screenshot from: [#!variable!server_name!#] (uuid: [#!variable!server_uuid!#]) from the host: [#!variable!host_name!#].</key>
<key name="log_0806">- Saving the screenshot: [#!variable!ppm_file!#].</key>
<key name="log_0807">- Converting: [#!variable!ppm_file!#] to:
<key name="log_0807">- Converting: [#!variable!source_file!#] to:
[#!variable!new_file!#]</key>
<key name="log_0808">Deleting screenshots older than: [#!variable!maximum_age!#].</key>
<key name="log_0809">- Deleting the server: [#!variable!server_name!#]'s screenshot: [#!variable!file!#].</key>
@ -4187,6 +4187,7 @@ We will try to proceed anyway.</key>
<key name="warning_0170">[ Warning ] - The attempt to boot: [#!variable!host_name!#] appears to have failed. The return code received was: [#!variable!return_code!#] (expected '0'). The output, if any, was: [#!variable!output!#].</key>
<key name="warning_0171">[ Warning ] - The daemon: [#!variable!daemon!#] appears to have failed! Attempting to restart it now.</key>
<key name="warning_0172">[ Warning ] - The line: [#!variable!line!#] that was going to be added to the hosts file is invalid, removing it.</key>
<key name="warning_0173">[ Warning ] - Failed to convert: [#!variable!source_file!#] to: [#!variable!new_file!#] (format: [#!variable!format!#]! Return code was: [#!variable!return_code!#], expected '0'.</key>
</language>
<!-- 日本語 -->

File diff suppressed because it is too large Load Diff

@ -80,6 +80,7 @@ my $conf = {
drbdadm => "/usr/sbin/drbdadm",
echo => "/usr/bin/echo",
getent => "/usr/bin/getent",
hostnamectl => "/usr/bin/hostnamectl",
logger => "/usr/bin/logger",
pcs => "/usr/sbin/pcs",
},
@ -296,6 +297,10 @@ sub create_constraint
if (lc($peer_rolee) ne "primary")
{
# Set the location constraint so that pacemaker doesn't migrate the server when it
# comes back up.
set_location_constraint($conf);
# We're good, fence is complete.
to_log($conf, {message => "Resource: [".$target_server."] has been fenced via location constraint successfully!", 'line' => __LINE__, level => 1});
@ -331,6 +336,175 @@ sub perform_fence
return(0);
}
# This sets a location contraint so the server prefers our node.
sub set_location_constraint
{
my ($conf) = @_;
# Get the host names.
my ($local_host, $peer_host) = get_hostname($conf);
my $server = $conf->{environment}{DRBD_RESOURCE};
to_log($conf, {message => "server: [".$server."], local_host: [".$local_host."], peer_host: [".$peer_host."]", 'line' => __LINE__, level => 2});
if ((not $local_host) or (not $peer_host))
{
# We can't update the constraints.
return(1);
}
to_log($conf, {message => "Setting the pacemaker location constraint so that: [".$server."] prefers this host.", 'line' => __LINE__, level => 1});
my $shell_call = $conf->{path}{exe}{pcs}." constraint location ".$server." prefers ".$local_host."=200 ".$peer_host."=100";
to_log($conf, {message => "Calling: [".$shell_call."]", 'line' => __LINE__, level => 2});
open (my $file_handle, $shell_call." 2>&1 |") or die "Failed to call: [".$shell_call."]. The error was: $!\n";
while(<$file_handle>)
{
# This should not generate output.
chomp;
my $line = $_;
to_log($conf, {message => "Output: [".$line."]", 'line' => __LINE__, level => 2});
}
close($file_handle);
return(0);
}
# This gets the local short hostname
sub get_hostname
{
my ($conf) = @_;
# This will store our name.
$conf->{cluster}{local_node} = "";
my $shell_call = $conf->{path}{exe}{hostnamectl}." --static";
to_log($conf, {message => "Calling: [".$shell_call."]", 'line' => __LINE__, level => 2});
open (my $file_handle, $shell_call." 2>&1 |") or die "Failed to call: [".$shell_call."]. The error was: $!\n";
while(<$file_handle>)
{
# This should not generate output.
chomp;
my $line = $_;
to_log($conf, {message => "Output: [".$line."]", 'line' => __LINE__, level => 2});
if ((not $line) or ($line =~ /\s/))
{
# We can't trust this, it could be an error like "Could not get property: Refusing
# activation, D-Bus is shutting down.".
last;
}
else
{
$conf->{cluster}{local_node} = $line;
to_log($conf, {message => "cluster::local_node: [".$conf->{cluster}{local_node}."]", 'line' => __LINE__, level => 2});
last;
}
}
# If we didn't get the host name, try reading /etc/hostname
if (not $conf->{cluster}{local_node})
{
# Try reading the config file name.
my $shell_call = "/etc/hostname";
to_log($conf, {message => "Reading: [".$shell_call."]", 'line' => __LINE__, level => 2});
open (my $file_handle, "<", $shell_call) or warn "Failed to read: [".$shell_call.", error was: [".$!."]";
while(<$file_handle>)
{
### NOTE: Don't chop this, we want to record exactly what we read
my $line = $_;
to_log($conf, {message => "line: [".$line."]", 'line' => __LINE__, level => 2});
if ((not $line) or ($line =~ /\s/))
{
# We can't trust this.
last;
}
else
{
$conf->{cluster}{local_node} = $line;
to_log($conf, {message => "cluster::local_node: [".$conf->{cluster}{local_node}."]", 'line' => __LINE__, level => 2});
last;
}
}
close $file_handle;
}
# If we still didn't get the hostname, try calling 'hostnamectl --transient'
if (not $conf->{cluster}{local_node})
{
my $shell_call = $conf->{path}{exe}{hostnamectl}." --transient";
to_log($conf, {message => "Calling: [".$shell_call."]", 'line' => __LINE__, level => 2});
open (my $file_handle, $shell_call." 2>&1 |") or die "Failed to call: [".$shell_call."]. The error was: $!\n";
while(<$file_handle>)
{
# This should not generate output.
chomp;
my $line = $_;
to_log($conf, {message => "Output: [".$line."]", 'line' => __LINE__, level => 2});
if ((not $line) or ($line =~ /\s/))
{
# We can't trust this, it could be an error like "Could not get property: Refusing
# activation, D-Bus is shutting down.".
last;
}
else
{
$conf->{cluster}{local_node} = $line;
to_log($conf, {message => "cluster::local_node: [".$conf->{cluster}{local_node}."]", 'line' => __LINE__, level => 2});
last;
}
}
}
# Make sure we've got a short hostname
$conf->{cluster}{local_node} =~ s/\..*$//;
to_log($conf, {message => "cluster::local_node: [".$conf->{cluster}{local_node}."]", 'line' => __LINE__, level => 2});
my $peer_host = $conf->{cluster}{target_node};
my $local_host = $conf->{cluster}{local_node};
to_log($conf, {message => "peer_host: [".$peer_host."], local_host: [".$local_host."]", 'line' => __LINE__, level => 2});
# Last, look through the pacemaker CIB to make sure we're going to use the names used in pacemaker.
if ((not exists $conf->{cluster}{cib}) or (not $conf->{cluster}{cib}))
{
read_cib($conf);
}
if ($conf->{cluster}{cib})
{
foreach my $line (split/\n/, $conf->{cluster}{cib})
{
to_log($conf, {message => "Output: [".$line."]", 'line' => __LINE__, level => 2});
if ($line =~ /<node .*>$/)
{
my $this_node_name = ($line =~ /uname="(.*?)"/)[0];
to_log($conf, {message => "this_node_name: [".$this_node_name."]", 'line' => __LINE__, level => 2});
if (($this_node_name eq $local_host) or ($this_node_name eq $peer_host))
{
# Name is accurate, we're good
next;
}
elsif ($this_node_name =~ /^$local_host\./)
{
# Update the host name
$conf->{cluster}{local_node} = $this_node_name;
to_log($conf, {message => "cluster::local_node: [".$conf->{cluster}{local_node}."]", 'line' => __LINE__, level => 2});
}
elsif ($this_node_name =~ /^$peer_host\./)
{
# Update the host name
$conf->{cluster}{target_node} = $this_node_name;
to_log($conf, {message => "cluster::target_node: [".$conf->{cluster}{target_node}."]", 'line' => __LINE__, level => 2});
}
}
}
}
to_log($conf, {message => "cluster::local_node: [".$conf->{cluster}{local_node}."], cluster::target_node: [".$conf->{cluster}{target_node}."]", 'line' => __LINE__, level => 2});
return($conf->{cluster}{local_node}, $conf->{cluster}{target_node});
}
# This reads the status of all resources. If we're not all UpToDate, check if the peer is. If the peer is,
# abort. If not, proceed (someone is gouig to have a bad day, but maybe some servers will live)
@ -537,6 +711,10 @@ sub identify_peer
to_log($conf, {message => "Checking the status of target node: [".$node."].", 'line' => __LINE__, level => 1});
if (($join eq "down") && ($expected eq "down"))
{
# Set the location constraint so that pacemaker doesn't migrate the
# server when it comes back up.
set_location_constraint($conf);
# The node is out.
to_log($conf, {message => "The node: [".$node."] is already down. No actual fence needed.", 'line' => __LINE__, level => 1});
exit(7);
@ -625,6 +803,9 @@ sub read_cib
exit(1);
}
# Cache the CIB.
$conf->{cluster}{cib} = $body;
return($body);
}
@ -738,8 +919,12 @@ sub check_peer_is_fenced
to_log($conf, {message => "Output: [".$line."]", 'line' => __LINE__, level => 2});
}
close $file_handle;
to_log($conf, {message => "Fence completed successfully!", 'line' => __LINE__, level => 1});
# Set the location constraint so that pacemaker doesn't migrate the server
# when it comes back up.
set_location_constraint($conf);
to_log($conf, {message => "Fence completed successfully!", 'line' => __LINE__, level => 1});
exit(7);
}
else
@ -814,7 +999,8 @@ sub to_log
# Build the message. We log the line
if (($conf->{'log'}{line_numbers}) && ($line))
{
$message = $line."; ".$message;
# Record the PID as well to make it easier to separate parallel runs.
$message = "[".$$."]:".$line."; ".$message;
}
my $priority_string = $facility;

@ -381,6 +381,8 @@ sub get_screenshots
my $unix_time = time;
my $file_name = "server-uuid_".$server_uuid."_timestamp-".$unix_time;
my $ppm_file = $anvil->data->{path}{directories}{screenshots}."/".$file_name.".ppm";
my $jpg_file = $anvil->data->{path}{directories}{screenshots}."/".$file_name.".jpg";
my $png_file = $anvil->data->{path}{directories}{screenshots}."/".$file_name.".png";
my $mimetype = $domain->screenshot($stream, 0);
my $screenshot = "";
my $screenshot_size = 0;
@ -393,13 +395,88 @@ sub get_screenshots
unix_time => $unix_time,
file_name => $file_name,
ppm_file => $ppm_file,
jpg_file => $jpg_file,
png_file => $png_file,
mimetype => $mimetype,
screenshot_size => $screenshot_size." (".$anvil->Convert->bytes_to_human_readable({'bytes' => $screenshot_size}).")",
}});
$stream->recv_all($handle_ss_chunk);
# Write out the screenshot.
### TODO: Delete this when EL8 support is dropped.
### TODO: When generating PNG, convert directly to JPEG
# On EL8, the mimetype is 'image/x-portable-pixmap'. On EL9, this is 'image/png'.
if ($mimetype eq "image/png")
{
# Write this out to png, and convert it to pmm.
$anvil->Storage->write_file({
debug => 2,
file => $png_file,
body => $screenshot,
mode => "0666",
binary => 1,
});
# Change the ownership
$anvil->Storage->change_owner({
debug => 2,
path => $png_file,
user => "striker-ui-api",
group => "striker-ui-api",
});
# Convert to PPM
my $shell_call = $anvil->data->{path}{exe}{pngtopam}." ".$png_file." > ".$ppm_file;
$anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { shell_call => $shell_call }});
my ($output, $return_code) = $anvil->System->call({shell_call => $shell_call});
$anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => {
output => $output,
return_code => $return_code,
}});
if ($return_code)
{
# Failed
$anvil->Job->update_progress({
progress => $anvil->data->{job}{progress} < 99 ? ++$anvil->data->{job}{progress} : $anvil->data->{job}{progress},
message => "warning_0173",
log_level => 1,
variables => {
source_file => $png_file,
new_file => $ppm_file,
'format' => "ppm",
return_code => $return_code,
},
});
unlink $ppm_file;
}
else
{
$anvil->Job->update_progress({
progress => $anvil->data->{job}{progress} < 99 ? ++$anvil->data->{job}{progress} : $anvil->data->{job}{progress},
message => "log_0807",
log_level => 2,
variables => {
source_file => $png_file,
new_file => $ppm_file,
'format' => "ppm",
},
});
# Change the ownership
$anvil->Storage->change_owner({
debug => 2,
path => $png_file,
user => "striker-ui-api",
group => "striker-ui-api",
});
}
}
else
{
# Write out ppm the screenshot.
$anvil->Storage->write_file({
debug => 2,
file => $ppm_file,
@ -407,12 +484,23 @@ sub get_screenshots
mode => "0666",
binary => 1,
});
print "Wrote ppm: [".$ppm_file."]\n";
# Change the ownership
$anvil->Storage->change_owner({
debug => 2,
path => $ppm_file,
user => "striker-ui-api",
group => "striker-ui-api",
});
$anvil->Job->update_progress({
progress => $anvil->data->{job}{progress} < 99 ? ++$anvil->data->{job}{progress} : $anvil->data->{job}{progress},
message => "log_0806",
log_level => 2,
variables => { ppm_file => $ppm_file },
});
}
### TODO: Make these user-configurable later.
my $make_jpeg = 1;
@ -425,26 +513,41 @@ sub get_screenshots
}});
# Convert to jpg
if ($make_jpeg)
if ((-e $ppm_file) && ($make_jpeg))
{
my $jpg_file = $anvil->data->{path}{directories}{screenshots}."/".$file_name.".jpg";
my $shell_call = $anvil->data->{path}{exe}{pnmtojpeg}." ".$ppm_file." > ".$jpg_file;
$anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => {
shell_call => $shell_call,
jpg_file => $jpg_file,
}});
$anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { shell_call => $shell_call }});
my ($output, $return_code) = $anvil->System->call({shell_call => $shell_call});
$anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => {
output => $output,
return_code => $return_code,
}});
if ($return_code)
{
# Failed
$anvil->Job->update_progress({
progress => $anvil->data->{job}{progress} < 99 ? ++$anvil->data->{job}{progress} : $anvil->data->{job}{progress},
message => "warning_0173",
log_level => 1,
variables => {
source_file => $ppm_file,
new_file => $jpg_file,
'format' => "jpeg",
return_code => $return_code,
},
});
unlink $jpg_file;
}
else
{
$anvil->Job->update_progress({
progress => $anvil->data->{job}{progress} < 99 ? ++$anvil->data->{job}{progress} : $anvil->data->{job}{progress},
message => "log_0807",
log_level => 2,
variables => {
ppm_file => $ppm_file,
source_file => $ppm_file,
new_file => $jpg_file,
'format' => "jpeg",
},
@ -458,28 +561,44 @@ sub get_screenshots
group => "striker-ui-api",
});
}
}
# Convert to png
if ($make_png)
if ((-e $ppm_file) && ($make_png) && (not -e $png_file))
{
my $png_file = $anvil->data->{path}{directories}{screenshots}."/".$file_name.".png";
my $shell_call = $anvil->data->{path}{exe}{pamtopng}." ".$ppm_file." > ".$png_file;
$anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => {
shell_call => $shell_call,
png_file => $png_file,
}});
$anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { shell_call => $shell_call }});
my ($output, $return_code) = $anvil->System->call({shell_call => $shell_call});
$anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => {
output => $output,
return_code => $return_code,
}});
if ($return_code)
{
# Failed
$anvil->Job->update_progress({
progress => $anvil->data->{job}{progress} < 99 ? ++$anvil->data->{job}{progress} : $anvil->data->{job}{progress},
message => "warning_0173",
log_level => 1,
variables => {
source_file => $ppm_file,
new_file => $png_file,
'format' => "png",
return_code => $return_code,
},
});
unlink $png_file;
}
else
{
$anvil->Job->update_progress({
progress => $anvil->data->{job}{progress} < 99 ? ++$anvil->data->{job}{progress} : $anvil->data->{job}{progress},
message => "log_0807",
log_level => 2,
variables => {
ppm_file => $ppm_file,
source_file => $ppm_file,
new_file => $png_file,
'format' => "png",
},
@ -493,6 +612,12 @@ sub get_screenshots
group => "striker-ui-api",
});
}
}
elsif ((not $make_png) && (-e $png_file))
{
# Remove the source png file
unlink $png_file;
}
# Delete the original PPM file?
if ($delete_ppm)

Loading…
Cancel
Save