* Updated anvil-report-usage to accept the new '--machine' which reports the usage information in XML format.

* Added the anvil-report-usage.8 man page
* Updated anvil-update-system to enable scancore when the OS update is complete.

Signed-off-by: digimer <mkelly@alteeve.ca>
main
digimer 1 year ago
parent 583547af30
commit d07933a31c
  1. 1
      man/Makefile.am
  2. 36
      man/anvil-report-usage.8
  3. 206
      tools/anvil-report-usage
  4. 1
      tools/anvil-update-system

@ -22,6 +22,7 @@ dist_man8_MANS = \
anvil-manage-server.8 \
anvil-manage-server-storage.8 \
anvil-manage-storage-groups.8 \
anvil-report-usage.8 \
anvil-safe-start.8 \
anvil-safe-stop.8 \
anvil-shutdown-server.8 \

@ -0,0 +1,36 @@
.\" Manpage for the Anvil! tool to report the usage of servers and Anvil! nodes
.\" Contact mkelly@alteeve.com to report issues, concerns or suggestions.
.TH anvil-report-usage "8" "July 22 2023" "Anvil! Intelligent Availability™ Platform"
.SH NAME
anvil-report-usage \- This program reports the current resource usage of servers and the available resources remaining on Anvil! nodes
.SH SYNOPSIS
.B anvil-report-usage
\fI\,<command> \/\fR[\fI\,options\/\fR]
.SH DESCRIPTION
This program displays the resource utilization of servers and the resources available (used and free) on Anvil! nodes.
.TP
.TP
.SH OPTIONS
.TP
\-?, \-h, \fB\-\-help\fR
Show this man page.
.TP
\fB\-\-log-secure\fR
When logging, record sensitive data, like passwords.
.TP
\-v, \-vv, \-vvv
Set the log level to 1, 2 or 3 respectively. Be aware that level 3 generates a significant amount of log data.
.SS "Commands:"
.TP
\fB\-\-detailed\fR
.TP
This displays additional information about the resources used by servers on the node. This only matters for human-readable display, when using '\fB\-\-machine\fR', all data is reported.
.TP
\fB\-\-machine\fR
.TP
Outputs the data in a machine-parsable format
.IP
.SH AUTHOR
Written by Madison Kelly, Alteeve staff and the Anvil! project contributors.
.SH "REPORTING BUGS"
Report bugs to users@clusterlabs.org

@ -17,11 +17,12 @@ if (($running_directory =~ /^\./) && ($ENV{PWD}))
my $anvil = Anvil::Tools->new();
$anvil->data->{switches}{detailed} = 0;
$anvil->Get->switches();
$anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => {
"switches::detailed" => $anvil->data->{switches}{detailed},
}});
# Read switches
$anvil->Get->switches({list => [
"detailed",
"machine"], man => $THIS_FILE});
$anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => $anvil->data->{switches}});
$anvil->Log->entry({source => $THIS_FILE, line => __LINE__, level => 2, key => "log_0115", variables => { program => $THIS_FILE }});
$anvil->Database->connect();
$anvil->Log->entry({source => $THIS_FILE, line => __LINE__, level => 1, key => "log_0132"});
@ -70,13 +71,15 @@ sub collect_anvil_data
"s2:anvil_uuid" => $anvil_uuid,
}});
$anvil->data->{anvil_data}{$anvil_name}{anvil_uuid} = $anvil_uuid;
$anvil->data->{anvil_data}{$anvil_name}{description} = $anvil->data->{anvils}{anvil_name}{$anvil_name}{anvil_description};
$anvil->data->{anvil_data}{$anvil_name}{node1_host_uuid} = $anvil->data->{anvils}{anvil_name}{$anvil_name}{anvil_node1_host_uuid};
$anvil->data->{anvil_data}{$anvil_name}{node2_host_uuid} = $anvil->data->{anvils}{anvil_name}{$anvil_name}{anvil_node2_host_uuid};
$anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => {
"s1:anvil_data::${anvil_name}::anvil_description" => $anvil->data->{anvil_data}{$anvil_name}{description},
"s2:anvil_data::${anvil_name}::node1_host_uuid" => $anvil->data->{anvil_data}{$anvil_name}{node1_host_uuid},
"s3:anvil_data::${anvil_name}::node2_host_uuid" => $anvil->data->{anvil_data}{$anvil_name}{node2_host_uuid},
"s1:anvil_data::${anvil_name}::anvil_uuid" => $anvil->data->{anvil_data}{$anvil_name}{anvil_uuid},
"s2:anvil_data::${anvil_name}::anvil_description" => $anvil->data->{anvil_data}{$anvil_name}{description},
"s3:anvil_data::${anvil_name}::node1_host_uuid" => $anvil->data->{anvil_data}{$anvil_name}{node1_host_uuid},
"s4:anvil_data::${anvil_name}::node2_host_uuid" => $anvil->data->{anvil_data}{$anvil_name}{node2_host_uuid},
}});
if (length($anvil_name) > $anvil->data->{longest}{anvil_name})
@ -141,15 +144,25 @@ sub collect_anvil_data
$bridges =~ s/, $//;
# Store
$anvil->data->{anvil_data}{$anvil_name}{cpu_cores} = $cpu_cores;
$anvil->data->{anvil_data}{$anvil_name}{cpu_threads} = $cpu_threads;
$anvil->data->{anvil_data}{$anvil_name}{cpu_string} = $say_cpu;
$anvil->data->{anvil_data}{$anvil_name}{ram_used_string} = $say_ram_hardware;
$anvil->data->{anvil_data}{$anvil_name}{ram_available} = $ram_available;
$anvil->data->{anvil_data}{$anvil_name}{ram_used} = $ram_used;
$anvil->data->{anvil_data}{$anvil_name}{ram_hardware} = $ram_hardware;
$anvil->data->{anvil_data}{$anvil_name}{ram_free_string} = $say_ram_available;
$anvil->data->{anvil_data}{$anvil_name}{bridge_string} = $bridges;
$anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => {
"s1:anvil_data::${anvil_name}::cpu_string" => $anvil->data->{anvil_data}{$anvil_name}{cpu_string},
"s2:anvil_data::${anvil_name}::ram_used_string" => $anvil->data->{anvil_data}{$anvil_name}{ram_used_string},
"s3:anvil_data::${anvil_name}::ram_free_string" => $anvil->data->{anvil_data}{$anvil_name}{ram_free_string},
"s4:anvil_data::${anvil_name}::bridge_string" => $anvil->data->{anvil_data}{$anvil_name}{bridge_string},
"s1:anvil_data::${anvil_name}::cpu_cores" => $anvil->data->{anvil_data}{$anvil_name}{cpu_cores},
"s2:anvil_data::${anvil_name}::cpu_threads" => $anvil->data->{anvil_data}{$anvil_name}{cpu_threads},
"s3:anvil_data::${anvil_name}::cpu_string" => $anvil->data->{anvil_data}{$anvil_name}{cpu_string},
"s4:anvil_data::${anvil_name}::ram_used_string" => $anvil->data->{anvil_data}{$anvil_name}{ram_used_string},
"s5:anvil_data::${anvil_name}::ram_available" => $anvil->data->{anvil_data}{$anvil_name}{ram_available},
"s6:anvil_data::${anvil_name}::ram_used" => $anvil->data->{anvil_data}{$anvil_name}{ram_used},
"s7:anvil_data::${anvil_name}::ram_hardware" => $anvil->data->{anvil_data}{$anvil_name}{ram_hardware},
"s8:anvil_data::${anvil_name}::ram_free_string" => $anvil->data->{anvil_data}{$anvil_name}{ram_free_string},
"s9:anvil_data::${anvil_name}::bridge_string" => $anvil->data->{anvil_data}{$anvil_name}{bridge_string},
}});
if (length($anvil->data->{anvil_data}{$anvil_name}{cpu_string}) > $anvil->data->{longest}{host_cpu_string})
@ -199,11 +212,17 @@ sub collect_anvil_data
's5:sg_used' => $anvil->Convert->add_commas({number => $sg_used})." (".$anvil->Convert->bytes_to_human_readable({'bytes' => $sg_used}).")",
}});
$anvil->data->{anvil_data}{$anvil_name}{storage_group}{$storage_group_name}{storage_group_uuid} = $storage_group_uuid;
$anvil->data->{anvil_data}{$anvil_name}{storage_group}{$storage_group_name}{used_size} = $sg_used;
$anvil->data->{anvil_data}{$anvil_name}{storage_group}{$storage_group_name}{free_size} = $free_size;
$anvil->data->{anvil_data}{$anvil_name}{storage_group}{$storage_group_name}{say_used_size} = $anvil->Convert->bytes_to_human_readable({'bytes' => $sg_used});
$anvil->data->{anvil_data}{$anvil_name}{storage_group}{$storage_group_name}{say_free_size} = $anvil->Convert->bytes_to_human_readable({'bytes' => $free_size});
$anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => {
"s1:anvil_data::${anvil_name}::storage_group::${storage_group_name}::say_used_size" => $anvil->data->{anvil_data}{$anvil_name}{storage_group}{$storage_group_name}{say_used_size},
"s2:anvil_data::${anvil_name}::storage_group::${storage_group_name}::say_free_size" => $anvil->data->{anvil_data}{$anvil_name}{storage_group}{$storage_group_name}{say_free_size},
"s1:anvil_data::${anvil_name}::storage_group::${storage_group_name}::storage_group_uuid" => $anvil->data->{anvil_data}{$anvil_name}{storage_group}{$storage_group_name}{storage_group_uuid},
"s2:anvil_data::${anvil_name}::storage_group::${storage_group_name}::used_size" => $anvil->data->{anvil_data}{$anvil_name}{storage_group}{$storage_group_name}{used_size},
"s3:anvil_data::${anvil_name}::storage_group::${storage_group_name}::free_size" => $anvil->data->{anvil_data}{$anvil_name}{storage_group}{$storage_group_name}{free_size},
"s4:anvil_data::${anvil_name}::storage_group::${storage_group_name}::say_used_size" => $anvil->data->{anvil_data}{$anvil_name}{storage_group}{$storage_group_name}{say_used_size},
"s5:anvil_data::${anvil_name}::storage_group::${storage_group_name}::say_free_size" => $anvil->data->{anvil_data}{$anvil_name}{storage_group}{$storage_group_name}{say_free_size},
}});
if (length($storage_group_name) > $anvil->data->{longest}{storage_group})
@ -237,6 +256,74 @@ sub show_anvils
{
my ($anvil) = @_;
if ($anvil->data->{switches}{machine})
{
show_anvils_machine($anvil);
}
else
{
show_anvils_human($anvil);
}
return(0);
}
sub show_anvils_machine
{
my ($anvil) = @_;
$anvil->data->{show}{xml} .= " <nodes>\n";
foreach my $anvil_name (sort {$a cmp $b} keys %{$anvil->data->{anvil_data}})
{
my $anvil_uuid = $anvil->data->{anvil_data}{$anvil_name}{anvil_uuid};
my $anvil_description = $anvil->data->{anvil_data}{$anvil_name}{description};
my $cpu_cores = $anvil->data->{anvil_data}{$anvil_name}{cpu_cores};
my $cpu_threads = $anvil->data->{anvil_data}{$anvil_name}{cpu_threads};
my $ram_available = $anvil->data->{anvil_data}{$anvil_name}{ram_available};
my $ram_available_hr = $anvil->Convert->bytes_to_human_readable({'bytes' => $ram_available});
my $ram_used = $anvil->data->{anvil_data}{$anvil_name}{ram_used};
my $ram_used_hr = $anvil->Convert->bytes_to_human_readable({'bytes' => $ram_used});
my $ram_hardware = $anvil->data->{anvil_data}{$anvil_name}{ram_hardware};
my $ram_hardware_hr = $anvil->Convert->bytes_to_human_readable({'bytes' => $ram_hardware});
my $bridge_string = $anvil->data->{anvil_data}{$anvil_name}{bridge_string};
$anvil->data->{show}{xml} .= " <node name=\"".$anvil_name."\" uuid=\"".$anvil_uuid."\" description=\"".$anvil_description."\">
<cpu cores=\"".$cpu_cores."\" threads=\"".$cpu_threads."\" />
<ram hardware=\"".$ram_hardware."\" hardware-hr=\"".$ram_available_hr."\" used=\"".$ram_used."\" used-hr=\"".$ram_used_hr."\" available=\"".$ram_available."\" available-hr=\"".$ram_available_hr."\" />
<bridges available=\"".$bridge_string."\" />
";
foreach my $storage_group_name (sort {$a cmp $b} keys %{$anvil->data->{anvil_data}{$anvil_name}{storage_group}})
{
my $storage_group_uuid = $anvil->data->{anvil_data}{$anvil_name}{storage_group}{$storage_group_name}{storage_group_uuid};
my $used_bytes = $anvil->data->{anvil_data}{$anvil_name}{storage_group}{$storage_group_name}{used_size};
my $free_bytes = $anvil->data->{anvil_data}{$anvil_name}{storage_group}{$storage_group_name}{free_size};
my $say_used_size = $anvil->data->{anvil_data}{$anvil_name}{storage_group}{$storage_group_name}{say_used_size};
my $say_free_size = $anvil->data->{anvil_data}{$anvil_name}{storage_group}{$storage_group_name}{say_free_size};
$anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => {
's1:storage_group_name' => $storage_group_name,
's2:storage_group_uuid' => $storage_group_uuid,
's3:used_bytes' => $used_bytes,
's4:free_bytes' => $free_bytes,
's5:say_used_size' => $say_used_size,
's6:say_free_size' => $say_free_size,
}});
$anvil->data->{show}{xml} .= " <storage-group name=\"".$storage_group_name."\" uuid=\"".$storage_group_uuid."\" used-bytes=\"".$used_bytes."\" used-hr=\"".$say_used_size."\" free-bytes=\"".$free_bytes."\" free-hr=\"".$say_free_size."\" />\n";
}
$anvil->data->{show}{xml} .= " </node>\n";
}
$anvil->data->{show}{xml} .= " </nodes>
</resources>
";
print $anvil->data->{show}{xml};
return(0);
}
sub show_anvils_human
{
my ($anvil) = @_;
my $anvil_header = $anvil->Words->string({key => "header_0081"});
my $longest_anvil_name = length($anvil_header) > $anvil->data->{longest}{anvil_name} ? length($anvil_header) : $anvil->data->{longest}{anvil_name};
my $description_header = $anvil->Words->string({key => "header_0074"});
@ -381,7 +468,6 @@ sub show_anvils
push @{$anvil->data->{display}{lines}}, $blank_lead.$storage_groups->[$i];
}
}
}
push @{$anvil->data->{display}{lines}}, $break_line;
@ -392,6 +478,96 @@ sub show_servers
{
my ($anvil) = @_;
if ($anvil->data->{switches}{machine})
{
show_servers_machine($anvil);
}
else
{
show_servers_human($anvil);
}
return(0);
}
sub show_servers_machine
{
my ($anvil) = @_;
$anvil->data->{show}{xml} = "<?xml version=\"1.0\" ?>
<resources>
<servers>\n";
foreach my $server_name (sort {$a cmp $b} keys %{$anvil->data->{server_data}})
{
foreach my $server_uuid (sort {$a cmp $b} keys %{$anvil->data->{server_data}{$server_name}{server_uuid}})
{
my $anvil_name = $anvil->data->{server_data}{$server_name}{server_uuid}{$server_uuid}{anvil_name};
my $anvil_uuid = $anvil->data->{server_data}{$server_name}{server_uuid}{$server_uuid}{anvil_uuid};
my $cpu_sockets = $anvil->data->{server_data}{$server_name}{server_uuid}{$server_uuid}{cpu}{sockets};
my $cpu_cores = $anvil->data->{server_data}{$server_name}{server_uuid}{$server_uuid}{cpu}{cores};
my $cpu_threads = $anvil->data->{server_data}{$server_name}{server_uuid}{$server_uuid}{cpu}{threads};
my $cpu_model = $anvil->data->{server_data}{$server_name}{server_uuid}{$server_uuid}{cpu}{model_name} ? $anvil->data->{server_data}{$server_name}{server_uuid}{$server_uuid}{cpu}{model_name} : "";
my $cpu_fallback = $anvil->data->{server_data}{$server_name}{server_uuid}{$server_uuid}{cpu}{model_fallback} ? $anvil->data->{server_data}{$server_name}{server_uuid}{$server_uuid}{cpu}{model_fallback} : "";
my $cpu_match = $anvil->data->{server_data}{$server_name}{server_uuid}{$server_uuid}{cpu}{match} ? $anvil->data->{server_data}{$server_name}{server_uuid}{$server_uuid}{cpu}{match} : "";
my $cpu_vendor = $anvil->data->{server_data}{$server_name}{server_uuid}{$server_uuid}{cpu}{vendor} ? $anvil->data->{server_data}{$server_name}{server_uuid}{$server_uuid}{cpu}{vendor} : "";
my $cpu_mode = $anvil->data->{server_data}{$server_name}{server_uuid}{$server_uuid}{cpu}{mode} ? $anvil->data->{server_data}{$server_name}{server_uuid}{$server_uuid}{cpu}{mode} : "";
my $ram_used = $anvil->data->{server_data}{$server_name}{server_uuid}{$server_uuid}{ram_used};
my $ram_used_hr = $anvil->data->{server_data}{$server_name}{server_uuid}{$server_uuid}{say_ram_used};
$anvil->data->{show}{xml} .= " <server name=\"".$server_name."\" uuid=\"".$server_uuid."\">
<anvil name=\"".$anvil_name."\" uuid=\"".$anvil_uuid."\" />
<cpu cores=\"".$cpu_cores."\" threads=\"".$cpu_threads."\" sockets=\"".$cpu_sockets."\" model=\"".$cpu_model."\" fallback=\"".$cpu_fallback."\" match=\"".$cpu_match."\" vendor=\"".$cpu_vendor."\" mode=\"".$cpu_mode."\" />
<ram used_bytes=\"".$ram_used."\" used_hr=\"".$ram_used_hr."\" />
";
foreach my $resource (sort {$a cmp $b} keys %{$anvil->data->{server_data}{$server_name}{server_uuid}{$server_uuid}{disk}})
{
$anvil->data->{show}{xml} .= " <storage resource=\"".$resource."\">\n";
foreach my $volume (sort {$a cmp $b} keys %{$anvil->data->{server_data}{$server_name}{server_uuid}{$server_uuid}{disk}{$resource}})
{
my $size = $anvil->data->{server_data}{$server_name}{server_uuid}{$server_uuid}{disk}{$resource}{$volume}{size};
my $say_size = $anvil->data->{server_data}{$server_name}{server_uuid}{$server_uuid}{disk}{$resource}{$volume}{say_size};
my $storage_group = $anvil->data->{server_data}{$server_name}{server_uuid}{$server_uuid}{disk}{$resource}{$volume}{storage_group};
$anvil->data->{show}{xml} .= " <volume number=\"".$volume."\" size-bytes=\"".$size."\" size-hr=\"".$say_size."\" storage-group=\"".$storage_group."\">\n";
foreach my $drbd_node (sort {$a cmp $b} keys %{$anvil->data->{server_data}{$server_name}{server_uuid}{$server_uuid}{disk}{$resource}{$volume}{node}})
{
my $drbd_path = $anvil->data->{server_data}{$server_name}{server_uuid}{$server_uuid}{disk}{$resource}{$volume}{node}{$drbd_node}{drbd_path};
my $drbd_path_by_res = $anvil->data->{server_data}{$server_name}{server_uuid}{$server_uuid}{disk}{$resource}{$volume}{node}{$drbd_node}{drbd_path_by_res};
my $drbd_minor = $anvil->data->{server_data}{$server_name}{server_uuid}{$server_uuid}{disk}{$resource}{$volume}{node}{$drbd_node}{drbd_minor};
my $meta_disk = $anvil->data->{server_data}{$server_name}{server_uuid}{$server_uuid}{disk}{$resource}{$volume}{node}{$drbd_node}{'meta-disk'};
my $backing_lv = $anvil->data->{server_data}{$server_name}{server_uuid}{$server_uuid}{disk}{$resource}{$volume}{node}{$drbd_node}{backing_lv};
my $node_host_uuid = $anvil->data->{server_data}{$server_name}{server_uuid}{$server_uuid}{disk}{$resource}{$volume}{node}{$drbd_node}{host_uuid};
$anvil->data->{show}{xml} .= " <subnode name=\"".$drbd_node."\" host-uuid=\"".$node_host_uuid."\" path=\"".$drbd_path."\" res-path=\"".$drbd_path_by_res."\" minor=\"".$drbd_minor."\" meta-data=\"".$meta_disk."\" lv=\"".$backing_lv."\" />\n";
}
$anvil->data->{show}{xml} .= " </volume>\n";
}
$anvil->data->{show}{xml} .= " </storage>\n";
}
foreach my $bridge (sort {$a cmp $b} keys %{$anvil->data->{server_data}{$server_name}{server_uuid}{$server_uuid}{net}})
{
$anvil->data->{show}{xml} .= " <network bridge=\"".$bridge."\">\n";
foreach my $alias (sort {$a cmp $b} keys %{$anvil->data->{server_data}{$server_name}{server_uuid}{$server_uuid}{net}{$bridge}})
{
foreach my $mac (sort {$a cmp $b} keys %{$anvil->data->{server_data}{$server_name}{server_uuid}{$server_uuid}{net}{$bridge}{$alias}})
{
my $model = $anvil->data->{server_data}{$server_name}{server_uuid}{$server_uuid}{net}{$bridge}{$alias}{$mac}{model};
my $ip = $anvil->data->{server_data}{$server_name}{server_uuid}{$server_uuid}{net}{$bridge}{$alias}{$mac}{ip};
$anvil->data->{show}{xml} .= " <mac alias=\"".$alias."\" address=\"".$mac."\" model=\"".$model."\" ip=\"".$ip."\" />\n";
}
}
$anvil->data->{show}{xml} .= " </network>
</server>\n";
}
$anvil->data->{show}{xml} .= " </server>\n";
}
}
return(0);
}
sub show_servers_human
{
my ($anvil) = @_;
my $server_header = $anvil->Words->string({key => "header_0065"});
my $longest_server_name = length($server_header) > $anvil->data->{longest}{server_name} ? length($server_header) : $anvil->data->{longest}{server_name};
my $anvil_header = $anvil->Words->string({key => "brand_0002"});

@ -124,6 +124,7 @@ if (not $anvil->data->{sys}{database}{connections})
# Start the anvil-daemon, the caller likely called without a DB because we're being updated by
# striker-update-cluster, and so there will be a job waiting for us.
$anvil->System->enable_daemon({now => 1, daemon => "anvil-daemon"});
$anvil->System->enable_daemon({now => 1, daemon => "scancore"});
$anvil->Database->connect;
$anvil->Log->entry({source => $THIS_FILE, line => __LINE__, level => 2, secure => 0, key => "log_0132"});

Loading…
Cancel
Save