Merge branch 'main' into docs/ui-readmes

main
Digimer 1 year ago committed by GitHub
commit 4976ba251a
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
  1. 1
      Anvil/Tools.pm
  2. 187
      Anvil/Tools/Database.pm
  3. 87
      Anvil/Tools/Network.pm
  4. 675
      Anvil/Tools/Server.pm
  5. 4
      Anvil/Tools/Storage.pm
  6. 2
      cgi-bin/set_power
  7. 1
      man/Makefile.am
  8. 57
      man/anvil-manage-host.8
  9. 2
      man/anvil-manage-server-storage.8
  10. 39
      man/anvil-manage-server-system.8
  11. 38
      man/striker-boot-machine.8
  12. 37
      man/striker-show-jobs.8
  13. 15
      ocf/alteeve/server
  14. 4
      scancore-agents/scan-apc-pdu/scan-apc-pdu
  15. 1
      scancore-agents/scan-cluster/scan-cluster
  16. 8
      scancore-agents/scan-server/scan-server
  17. 21
      share/words.xml
  18. 2
      striker-ui-api/out/index.js
  19. 1091
      striker-ui-api/package-lock.json
  20. 7
      striker-ui-api/src/lib/buildCondition.ts
  21. 2
      striker-ui-api/src/lib/request_handlers/anvil/buildAnvilSummary.ts
  22. 7
      striker-ui-api/src/lib/request_handlers/anvil/buildQueryAnvilDetail.ts
  23. 8
      striker-ui-api/src/lib/request_handlers/anvil/getAnvilCpu.ts
  24. 4
      striker-ui-api/src/lib/request_handlers/anvil/getAnvilDetail.ts
  25. 5
      striker-ui-api/src/lib/request_handlers/anvil/getAnvilMemory.ts
  26. 6
      striker-ui-api/src/lib/request_handlers/anvil/getAnvilSummary.ts
  27. 3
      striker-ui-api/src/lib/request_handlers/file/buildQueryFileDetail.ts
  28. 3
      striker-ui-api/src/lib/request_handlers/file/getFile.ts
  29. 7
      striker-ui-api/src/lib/request_handlers/host/buildQueryHostDetail.ts
  30. 6
      striker-ui-api/src/lib/request_handlers/host/getHost.ts
  31. 8
      striker-ui-api/src/lib/request_handlers/server/createServer.ts
  32. 8
      striker-ui-api/src/lib/request_handlers/server/deleteServer.ts
  33. 506
      striker-ui/package-lock.json
  34. 2
      striker-ui/package.json
  35. 1
      tools/Makefile.am
  36. 8
      tools/anvil-daemon
  37. 80
      tools/anvil-delete-server
  38. 10
      tools/anvil-join-anvil
  39. 14
      tools/anvil-manage-files
  40. 119
      tools/anvil-manage-host
  41. 2
      tools/anvil-manage-keys
  42. 1
      tools/anvil-manage-server-storage
  43. 688
      tools/anvil-manage-server-system
  44. 8
      tools/scancore
  45. 147
      tools/striker-boot-machine
  46. 2
      tools/striker-db-report
  47. 2
      tools/striker-file-manager
  48. 54
      tools/striker-get-screenshots
  49. 2
      tools/striker-manage-install-target
  50. 5
      tools/striker-manage-peers
  51. 2
      tools/striker-scan-network
  52. 287
      tools/striker-show-jobs

@ -1115,6 +1115,7 @@ sub _set_paths
ifcfg => "/etc/sysconfig/network-scripts",
journald => "/var/log/journal",
libvirtd_definitions => "/etc/libvirt/qemu/",
opt_alteeve => "/opt/alteeve",
pgsql => "/var/lib/pgsql/",
resource_status => "/sys/kernel/debug/drbd/resources",
scan_agents => "/usr/sbin/scancore-agents",

@ -620,25 +620,26 @@ sub check_agent_data
}});
}
# Now check to see if a resync is required, it likely is.
if ($anvil->data->{sys}{database}{connections} > 1)
{
# The source is the agent
$anvil->Database->_find_behind_databases({
debug => $debug,
source => $agent,
tables => $tables,
});
}
# Hold if a lock has been requested.
$anvil->Database->locking({debug => $debug});
# Mark that we're now active.
$anvil->Database->mark_active({debug => $debug, set => 1});
# Sync the database, if needed.
$anvil->Database->resync_databases({debug => $debug});
### NOTE: Don't sync here, leave it for anvil-daemon to handle.
# # Now check to see if a resync is required, it likely is.
# if ($anvil->data->{sys}{database}{connections} > 1)
# {
# # The source is the agent
# $anvil->Database->_find_behind_databases({
# debug => $debug,
# source => $agent,
# tables => $tables,
# });
# }
#
# # Hold if a lock has been requested.
# $anvil->Database->locking({debug => $debug});
#
# # Mark that we're now active.
# $anvil->Database->mark_active({debug => $debug, set => 1});
#
# # Sync the database, if needed.
# $anvil->Database->resync_databases({debug => $debug, force });
}
}
@ -1199,10 +1200,6 @@ This module will return the number of databases that were successfully connected
Parameters;
=head3 all (optional, default 0)
If set, then the checks to see if a database is active or not is ignored. If the postgresql server is running, we will connect to it.
=head3 check_for_resync (optional, default 0)
If set to C<< 1 >>, and there are 2 or more databases available, a check will be make to see if the databases need to be resync'ed or not. This is also set if the command line switch C<< --resync-db >> is used.
@ -1287,7 +1284,6 @@ sub connect
my $debug = defined $parameter->{debug} ? $parameter->{debug} : 3;
$anvil->Log->entry({source => $THIS_FILE, line => __LINE__, level => $debug, key => "log_0125", variables => { method => "Database->connect()" }});
my $all = defined $parameter->{all} ? $parameter->{all} : 0;
my $check_if_configured = defined $parameter->{check_if_configured} ? $parameter->{check_if_configured} : 0;
my $db_uuid = defined $parameter->{db_uuid} ? $parameter->{db_uuid} : "";
my $check_for_resync = defined $parameter->{check_for_resync} ? $parameter->{check_for_resync} : 0;
@ -1299,7 +1295,6 @@ sub connect
my $tables = defined $parameter->{tables} ? $parameter->{tables} : "";
my $test_table = defined $parameter->{test_table} ? $parameter->{test_table} : $anvil->data->{sys}{database}{test_table};
$anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => $debug, list => {
all => $all,
check_if_configured => $check_if_configured,
db_uuid => $db_uuid,
check_for_resync => $check_for_resync,
@ -1619,24 +1614,17 @@ sub connect
uuid => $uuid,
}});
# Set this database handle as the one to use for reading, if no handle is yet set.
if (($is_local) or (not $anvil->data->{sys}{database}{read_uuid}) or (not $anvil->Database->read))
# Only the first database to connect will be "Active". This is the database used for
# reads and the DB that will deal with resyncs
if (not $anvil->data->{sys}{database}{primary_db})
{
$anvil->data->{sys}{database}{primary_db} = $uuid;
$anvil->data->{sys}{database}{read_uuid} = $uuid;
$anvil->Database->read({set => $dbh});
$anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => $debug, list => {
'anvil->Database->read' => $anvil->Database->read,
"sys::database::primary_db" => $anvil->data->{sys}{database}{primary_db},
"sys::database::read_uuid" => $anvil->data->{sys}{database}{read_uuid},
}});
}
# Only the first database to connect will be "Active". What this means will expand
# over time. As of now, only the active DB will do resyncs.
if (not $anvil->data->{sys}{database}{active_uuid})
{
$anvil->data->{sys}{database}{active_uuid} = $uuid;
$anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => $debug, list => {
"sys::database::active_uuid" => $anvil->data->{sys}{database}{active_uuid},
'anvil->Database->read' => $anvil->Database->read,
}});
}
@ -1695,13 +1683,10 @@ sub connect
}
$anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => $debug, list => {
"sys::database::read_uuid" => $anvil->data->{sys}{database}{read_uuid},
"cache::database_handle::${uuid}" => $anvil->data->{cache}{database_handle}{$uuid},
}});
# Before I continue, see if this database is inactive (unless 'all' is set).
if (not $all)
{
# Before I continue, see if this database is inactive.
my ($active_value, undef, undef) = $anvil->Database->read_variable({
debug => $debug,
uuid => $uuid,
@ -1741,10 +1726,18 @@ sub connect
if ($anvil->data->{sys}{database}{read_uuid} eq $uuid)
{
$anvil->data->{sys}{database}{read_uuid} = "";
$anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => $debug, list => { "sys::database::read_uuid" => $anvil->data->{sys}{database}{read_uuid} }});
$anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => $debug, list => {
"sys::database::read_uuid" => $anvil->data->{sys}{database}{read_uuid},
}});
}
next;
if ($anvil->data->{sys}{database}{primary_db} eq $uuid)
{
$anvil->data->{sys}{database}{primary_db} = "";
$anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => $debug, list => {
"sys::database::primary_db" => $anvil->data->{sys}{database}{primary_db},
}});
}
next;
}
}
@ -1765,10 +1758,7 @@ sub connect
{
$anvil->Database->refresh_timestamp({debug => $debug});
}
$anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => $debug, list => {
"sys::database::read_uuid" => $anvil->data->{sys}{database}{read_uuid},
'anvil->Database->read' => $anvil->Database->read,
"sys::database::timestamp" => $anvil->data->{sys}{database}{timestamp},
}});
@ -1779,10 +1769,6 @@ sub connect
# Before we try to connect, see if this is a local database and, if so, make sure it's setup.
if ($is_local)
{
# If we're being called with 'all', don't set active as we could be just checking if
# we're active or not.
if (not $all)
{
# If we're a striker, set the variable saying we're active if we need to.
my ($active_value, undef, undef) = $anvil->Database->read_variable({
@ -1805,7 +1791,6 @@ sub connect
});
}
}
}
# If this isn't a local database, read the target's Anvil! version (if available) and make
# sure it matches ours. If it doesn't, skip this database.
else
@ -1836,7 +1821,7 @@ sub connect
# Delete the information about this database. We'll try again on next
# ->connect().
$anvil->data->{sys}{database}{active_uuid} = "" if $anvil->data->{sys}{database}{read_active} eq $uuid;
$anvil->data->{sys}{database}{primary_db} = "" if $anvil->data->{sys}{database}{read_active} eq $uuid;
$anvil->data->{sys}{database}{read_uuid} = "" if $anvil->data->{sys}{database}{read_uuid} eq $uuid;
$anvil->data->{sys}{database}{connections}--;
delete $anvil->data->{database}{$uuid};
@ -2013,9 +1998,6 @@ sub connect
}
}
my $total = tv_interval ($start_time, [gettimeofday]);
#print "Total runtime: [".$total."]\n";
# Do I have any connections? Don't die, if not, just return.
$anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => $debug, list => { "sys::database::connections" => $anvil->data->{sys}{database}{connections} }});
if (not $anvil->data->{sys}{database}{connections})
@ -2151,46 +2133,34 @@ sub connect
return($anvil->data->{sys}{database}{connections});
}
if (exists $anvil->data->{'log'}{scan_agent})
{
my $agent = $anvil->data->{'log'}{scan_agent};
$anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => $debug, list => { agent => $agent }});
if (exists $anvil->data->{scan_agent}{$agent}{last_db_count})
{
$anvil->data->{sys}{database}{last_db_count} = $anvil->data->{scan_agent}{$agent}{last_db_count};
# If 'check_for_resync' is set to '2', then only check if we're primary.
$anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => $debug, list => {
"sys::database::last_db_count" => $anvil->data->{sys}{database}{last_db_count},
"sys::database::primary_db" => $anvil->data->{sys}{database}{primary_db},
"sys::host_uuid" => $anvil->data->{sys}{host_uuid},
check_for_resync => $check_for_resync,
}});
}
}
# If we have a previous count and the new count is higher, resync.
if (not exists $anvil->data->{sys}{database}{last_db_count})
if ($check_for_resync == 2)
{
$anvil->data->{sys}{database}{last_db_count} = 0;
}
# If "last_db_count" is the lower than the current number of connections, check for a resync.
$anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => $debug, list => {
"sys::database::last_db_count" => $anvil->data->{sys}{database}{last_db_count},
"sys::database::connections" => $anvil->data->{sys}{database}{connections},
}});
if ($anvil->data->{sys}{database}{connections} > $anvil->data->{sys}{database}{last_db_count})
if ($anvil->data->{sys}{database}{primary_db} eq $anvil->data->{sys}{host_uuid})
{
# We're primary.
$check_for_resync = 1;
$anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => $debug, list => { check_for_resync => $check_for_resync }});
}
else
{
# We're not primary
$check_for_resync = 0;
$anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => $debug, list => { check_for_resync => $check_for_resync }});
}
}
# Check for behind databases only if there are 2+ DBs, we're the active DB, and we're set to do so.
$anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => $debug, list => {
"sys::database::connections" => $anvil->data->{sys}{database}{connections},
"sys::database::active_uuid" => $anvil->data->{sys}{database}{active_uuid},
"sys::host_uuid" => $anvil->data->{sys}{host_uuid},
check_for_resync => $check_for_resync,
}});
if (($anvil->data->{sys}{database}{connections} > 1) &&
(($anvil->data->{sys}{database}{active_uuid} eq $anvil->data->{sys}{host_uuid}) or
($check_for_resync)))
if (($anvil->data->{sys}{database}{connections} > 1) && ($check_for_resync))
{
$anvil->Database->_find_behind_databases({
debug => $debug,
@ -3580,7 +3550,7 @@ FROM
}});
}
# If this host is a node in an Anvil!, set the old 'file_location_anvil_uuid' to maintain
# If this host is an Anvil! subnode, set the old 'file_location_anvil_uuid' to maintain
# backwards compatibility.
if ((exists $anvil->data->{hosts}{host_uuid}{$file_location_host_uuid}) &&
($anvil->data->{hosts}{host_uuid}{$file_location_host_uuid}{anvil_uuid}))
@ -4769,7 +4739,7 @@ Jobs that reached 100% within this number of seconds ago will be included. If th
=head3 job_host_uuid (default $anvil->Get->host_uuid)
This is the host that we're getting a list of jobs from.
This is the host that we're getting a list of jobs from. If this is set to C<< all >>, all jobs are loaded from all hosts.
This method takes no parameters.
@ -4782,13 +4752,25 @@ sub get_jobs
my $debug = defined $parameter->{debug} ? $parameter->{debug} : 3;
my $return = [];
my $ended_within = defined $parameter->{ended_within} ? $parameter->{ended_within} : 300;
my $job_host_uuid = defined $parameter->{job_host_uuid} ? $parameter->{job_host_uuid} : $anvil->Get->host_uuid;
my $ended_within = defined $parameter->{ended_within} ? $parameter->{ended_within} : 0;
my $job_host_uuid = defined $parameter->{job_host_uuid} ? $parameter->{job_host_uuid} : "";
$anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => $debug, list => {
ended_within => $ended_within,
job_host_uuid => $job_host_uuid,
}});
if ($ended_within !~ /^\d+$/)
{
$ended_within = 300;
$anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => $debug, list => { ended_within => $ended_within }});
}
if (not $job_host_uuid)
{
$job_host_uuid = $anvil->Get->host_uuid;
$anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => $debug, list => { job_host_uuid => $job_host_uuid }});
}
if (exists $anvil->data->{jobs}{running})
{
delete $anvil->data->{jobs}{running};
@ -4811,11 +4793,18 @@ SELECT
job_title,
job_description,
job_status,
modified_date
job_host_uuid,
modified_date,
round(extract(epoch from modified_date))
FROM
jobs
jobs ";
if ($job_host_uuid ne "all")
{
$query .= "
WHERE
job_host_uuid = ".$anvil->Database->quote($job_host_uuid)."
job_host_uuid = ".$anvil->Database->quote($job_host_uuid);
}
$query .= "
;";
$anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => $debug, list => { query => $query }});
@ -4838,7 +4827,9 @@ WHERE
my $job_title = $row->[8];
my $job_description = $row->[9];
my $job_status = $row->[10];
my $modified_date = $row->[11];
my $job_host_uuid = $row->[11];
my $modified_date = $row->[12];
my $modified_date_unix = $row->[13];
my $now_time = time;
my $started_seconds_ago = $job_picked_up_at ? ($now_time - $job_picked_up_at) : 0;
my $updated_seconds_ago = $job_updated ? ($now_time - $job_updated) : 0;
@ -4853,8 +4844,10 @@ WHERE
job_progress => $job_progress,
job_title => $job_title,
job_description => $job_description,
job_host_uuid => $job_host_uuid,
job_status => $job_status,
modified_date => $modified_date,
modified_date_unix => $modified_date_unix,
now_time => $now_time,
started_seconds_ago => $started_seconds_ago,
updated_seconds_ago => $updated_seconds_ago,
@ -4879,7 +4872,9 @@ WHERE
job_title => $job_title,
job_description => $job_description,
job_status => $job_status,
job_host_uuid => $job_host_uuid,
modified_date => $modified_date,
modified_date_unix => $modified_date_unix,
};
$anvil->data->{jobs}{running}{$job_uuid}{job_command} = $job_command;
@ -4892,7 +4887,9 @@ WHERE
$anvil->data->{jobs}{running}{$job_uuid}{job_title} = $job_title;
$anvil->data->{jobs}{running}{$job_uuid}{job_description} = $job_description;
$anvil->data->{jobs}{running}{$job_uuid}{job_status} = $job_status;
$anvil->data->{jobs}{running}{$job_uuid}{job_host_uuid} = $job_host_uuid;
$anvil->data->{jobs}{running}{$job_uuid}{modified_date} = $modified_date;
$anvil->data->{jobs}{running}{$job_uuid}{modified_date_unix} = $modified_date_unix;
$anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => $debug, list => {
"jobs::running::${job_uuid}::job_command" => $anvil->data->{jobs}{running}{$job_uuid}{job_command},
"jobs::running::${job_uuid}::job_data" => $anvil->data->{jobs}{running}{$job_uuid}{job_data},
@ -4904,7 +4901,9 @@ WHERE
"jobs::running::${job_uuid}::job_title" => $anvil->data->{jobs}{running}{$job_uuid}{job_title},
"jobs::running::${job_uuid}::job_description" => $anvil->data->{jobs}{running}{$job_uuid}{job_description},
"jobs::running::${job_uuid}::job_status" => $anvil->data->{jobs}{running}{$job_uuid}{job_status},
"jobs::running::${job_uuid}::job_host_uuid" => $anvil->data->{jobs}{running}{$job_uuid}{job_host_uuid},
"jobs::running::${job_uuid}::modified_date" => $anvil->data->{jobs}{running}{$job_uuid}{modified_date},
"jobs::running::${job_uuid}::modified_date_unix" => $anvil->data->{jobs}{running}{$job_uuid}{modified_date},
}});
# Make it possible to sort by modified date for serial execution of similar jobs.
@ -4918,6 +4917,8 @@ WHERE
$anvil->data->{jobs}{modified_date}{$modified_date}{job_uuid}{$job_uuid}{job_title} = $job_title;
$anvil->data->{jobs}{modified_date}{$modified_date}{job_uuid}{$job_uuid}{job_description} = $job_description;
$anvil->data->{jobs}{modified_date}{$modified_date}{job_uuid}{$job_uuid}{job_status} = $job_status;
$anvil->data->{jobs}{modified_date}{$modified_date}{job_uuid}{$job_uuid}{job_host_uuid} = $job_host_uuid;
$anvil->data->{jobs}{modified_date}{$modified_date}{job_uuid}{$job_uuid}{modified_date_unix} = $modified_date_unix;
$anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => $debug, list => {
"jobs::modified_date::${modified_date}::job_uuid::${job_uuid}::job_command" => $anvil->data->{jobs}{modified_date}{$modified_date}{job_uuid}{$job_uuid}{job_command},
"jobs::modified_date::${modified_date}::job_uuid::${job_uuid}::job_data" => $anvil->data->{jobs}{modified_date}{$modified_date}{job_uuid}{$job_uuid}{job_data},
@ -4929,6 +4930,8 @@ WHERE
"jobs::modified_date::${modified_date}::job_uuid::${job_uuid}::job_title" => $anvil->data->{jobs}{modified_date}{$modified_date}{job_uuid}{$job_uuid}{job_title},
"jobs::modified_date::${modified_date}::job_uuid::${job_uuid}::job_description" => $anvil->data->{jobs}{modified_date}{$modified_date}{job_uuid}{$job_uuid}{job_description},
"jobs::modified_date::${modified_date}::job_uuid::${job_uuid}::job_status" => $anvil->data->{jobs}{modified_date}{$modified_date}{job_uuid}{$job_uuid}{job_status},
"jobs::modified_date::${modified_date}::job_uuid::${job_uuid}::job_host_uuid" => $anvil->data->{jobs}{modified_date}{$modified_date}{job_uuid}{$job_uuid}{job_host_uuid},
"jobs::modified_date::${modified_date}::job_uuid::${job_uuid}::modified_date_unix" => $anvil->data->{jobs}{modified_date}{$modified_date}{job_uuid}{$job_uuid}{modified_date_unix},
}});
}
@ -4951,7 +4954,9 @@ WHERE
job_title => $hash_ref->{job_title},
job_description => $hash_ref->{job_description},
job_status => $hash_ref->{job_status},
job_host_uuid => $hash_ref->{job_host_uuid},
modified_date => $hash_ref->{modified_date},
modified_date_unix => $hash_ref->{modified_date_unix},
}});
}
}

@ -1525,6 +1525,20 @@ Parameters;
This is the target's C<< host_uuid >> that we're looking to contact.
=head3 networks (optional, default 'bcn,mn,sn,ifn,any')
This is the comma-separated list of networks to search for access over. The order presented is the order searched. Valid values are;
* bcn (Back-Channel Network)
* mn (Migration Network)
* sn (Storage Network)
* ifn (Internet-Facing Network)
* any (Any other interface)
=head3 test_access (optional, default '0')
If set to C<< 1 >>, any matched IP will be tested. If this is set and the target can't be reached using that IP, it is skipped. If this is not set, the first match is returned.
=cut
sub find_target_ip
{
@ -1534,10 +1548,13 @@ sub find_target_ip
my $debug = defined $parameter->{debug} ? $parameter->{debug} : 3;
$anvil->Log->entry({source => $THIS_FILE, line => __LINE__, level => $debug, key => "log_0125", variables => { method => "Network->find_target_ip()" }});
my $target_ip = "";
my $host_uuid = defined $parameter->{host_uuid} ? $parameter->{host_uuid} : "";
my $networks = defined $parameter->{networks} ? $parameter->{networks} : "";
my $test_access = defined $parameter->{test_access} ? $parameter->{test_access} : 0;
$anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => $debug, list => {
host_uuid => $host_uuid,
networks => $networks,
test_access => $test_access,
}});
if (not $host_uuid)
@ -1554,6 +1571,12 @@ sub find_target_ip
return("");
}
if (not $networks)
{
$networks = "bcn,mn,sn,ifn,any";
$anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { networks => $networks }});
}
my $target_host_name = $anvil->data->{hosts}{host_uuid}{$host_uuid}{short_host_name};
my $short_host_name = $anvil->Get->short_host_name({debug => $debug});
$anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => $debug, list => {
@ -1561,38 +1584,52 @@ sub find_target_ip
short_host_name => $short_host_name,
}});
$anvil->Network->load_ips({
my $target_ip = "";
my $matches = $anvil->Network->find_access({
debug => $debug,
host_uuid => $anvil->Get->host_uuid,
host => $short_host_name,
clear => 1,
target => $target_host_name,
});
$anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { matches => $matches }});
$anvil->Network->load_ips({
debug => $debug,
host_uuid => $host_uuid,
host => $target_host_name,
clear => 1,
});
foreach my $preferred_network (split/,/, $networks)
{
last if $target_ip;
$anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { preferred_network => $preferred_network }});
foreach my $network_name (sort {$a cmp $b} keys %{$anvil->data->{network_access}})
{
$anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { network_name => $network_name }});
if (($network_name !~ /^$preferred_network/) && ($preferred_network ne "any"))
{
next;
}
my ($match) = $anvil->Network->find_matches({
debug => $debug,
first => $short_host_name,
second => $target_host_name,
source => $THIS_FILE,
line => __LINE__,
});
if ($match)
my $this_target_ip = $anvil->data->{network_access}{$network_name}{target_ip_address};
$anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { this_target_ip => $this_target_ip }});
if ($test_access)
{
# Yup!
my $match_found = 0;
foreach my $interface (sort {$a cmp $b} keys %{$match->{$target_host_name}})
my $access = $anvil->Remote->test_access({target => $this_target_ip});
$anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => {
's1:network_name' => $network_name,
's2:this_target_ip' => $this_target_ip,
's3:access' => $access,
}});
if ($access)
{
$target_ip = $match->{$target_host_name}{$interface}{ip};
$anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => $debug, list => { target_ip => $target_ip }});
# We can use this one.
$target_ip = $this_target_ip;
$anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { target_ip => $target_ip }});
last;
}
}
else
{
# We're done.
$target_ip = $this_target_ip;
$anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { target_ip => $target_ip }});
}
}
}
return($target_ip);

@ -7,6 +7,8 @@ use strict;
use warnings;
use Scalar::Util qw(weaken isweak);
use Data::Dumper;
use Text::Diff;
use Sys::Virt;
our $VERSION = "3.0.0";
my $THIS_FILE = "Server.pm";
@ -14,16 +16,19 @@ my $THIS_FILE = "Server.pm";
### Methods;
# active_migrations
# boot_virsh
# connect_to_virsh
# count_servers
# find
# find # To be replaced by Server->locate();
# find_processes
# get_definition
# get_runtime
# get_status
# locate
# map_network
# parse_definition
# migrate_virsh
# parse_definition
# shutdown_virsh
# update_definition
=cut TODO
@ -293,6 +298,170 @@ WHERE
return($success);
}
=head2 connect_to_libvirt
This creates a connection to the libvirtd daemon on the target host. The connection to the host will be stored in:
* libvirtd::<target>::connection
If the connection succeeds, C<< 0 >> will be returned. If the connection fails, C<< 1 >> will be returned.
parameters
=head3 server_name (optional)
If this is set to the name of a server, that server will be searched for and, if found, the handle to it will be stored in:
* libvirtd::<target>::server::<server_name>::connection
If the server is not found, that will be set to C<< 0 >>.
B<< Note >>: This can be set to C<< all >> and all servers we can connect to will be stored.
=head3 target (optional, default is the local short host name)
This is the target to connect to.
B<< Note >>: Don't use C<< localhost >>! If you do, it will be changed to the short host name. This is because C<< localhost >> is converted to C<< ::1 >> which can cause connection problems.
=head3 target_ip (optional)
If this is set, when building the URI, this IP or host name is used to connect. This allows the hash to use the C<< target >> name separately.
=cut
sub connect_to_libvirt
{
my $self = shift;
my $parameter = shift;
my $anvil = $self->parent;
my $debug = defined $parameter->{debug} ? $parameter->{debug} : 3;
$anvil->Log->entry({source => $THIS_FILE, line => __LINE__, level => $debug, key => "log_0125", variables => { method => "Server->connect_to_libvirt()" }});
my $server_name = defined $parameter->{server_name} ? $parameter->{server_name} : "";
my $target = defined $parameter->{target} ? $parameter->{target} : "";
my $target_ip = defined $parameter->{target_ip} ? $parameter->{target_ip} : "";
$anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => $debug, list => {
server_name => $server_name,
target => $target,
target_ip => $target_ip,
}});
if ((not $target)or ($target eq "localhost"))
{
# Change to the short host name.
$target = $anvil->Get->short_host_name;
$anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => $debug, list => { target => $target }});
}
if (not $target_ip)
{
$target_ip = $target;
$anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => $debug, list => { target_ip => $target_ip }});
}
# Does the handle already exist?
if ((exists $anvil->data->{libvirtd}{$target}) && (ref($anvil->data->{libvirtd}{$target}{connection}) eq "Sys::Virt"))
{
# Is this connection alive?
my $info = $anvil->data->{libvirtd}{$target}{connection}->get_node_info();
if (ref($info) eq "HASH")
{
# No need to connect.
$anvil->Log->entry({source => $THIS_FILE, line => __LINE__, level => 2, key => "log_0814", variables => { target => $target }});
}
else
{
# Stale connection.
$anvil->data->{libvirtd}{$target}{connection} = "";
}
}
else
{
$anvil->data->{libvirtd}{$target}{connection} = "";
}
# If we don't have a connection, try to establish one now.
if (not $anvil->data->{libvirtd}{$target}{connection})
{
my $uri = "qemu+ssh://".$target_ip."/system";
$anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { uri => $uri }});
# Test connect
eval { $anvil->data->{libvirtd}{$target}{connection} = Sys::Virt->new(uri => $uri); };
$anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => {
"libvirtd::${target}::connection" => $anvil->data->{libvirtd}{$target}{connection},
}});
if ($@)
{
# Throw an error, then clear the URI so that we just update the DB/on-disk definitions.
$anvil->data->{libvirtd}{$target}{connection} = 0;
$anvil->Log->entry({source => $THIS_FILE, line => __LINE__, level => 1, key => "warning_0162", variables => {
host_name => $target,
uri => $uri,
error => $@,
}});
return(1);
}
}
if (($server_name) && ($server_name ne "all"))
{
if (ref($anvil->data->{libvirtd}{$target}{server}{$server_name}{connection}) eq "Sys::Virt::Domain")
{
# If this connection still valid?
my $uuid = $anvil->data->{libvirtd}{$target}{server}{$server_name}{connection}->get_uuid_string();
if ($uuid)
{
# We're good.
$anvil->Log->entry({source => $THIS_FILE, line => __LINE__, level => 2, key => "log_0815", variables => { server_name => $server_name }});
return(0);
}
else
{
# Stale connection.
$anvil->data->{libvirtd}{$target}{server}{$server_name}{connection} = "";
}
}
else
{
$anvil->data->{libvirtd}{$target}{server}{$server_name}{connection} = "";
}
}
# If we have a server name, or if it's 'all', connect.
if ($server_name)
{
my $domain = "";
my @domains = $anvil->data->{libvirtd}{$target}{connection}->list_all_domains();
foreach my $domain_handle (@domains)
{
my $this_server_name = $domain_handle->get_name;
$anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => {
domain_handle => $domain_handle,
this_server_name => $this_server_name,
}});
if (($server_name ne "all") && ($this_server_name ne $server_name))
{
next;
}
$anvil->data->{libvirtd}{$target}{server}{$server_name}{connection} = $domain_handle;
$anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => {
"libvirtd::${target}::server::${server_name}::connection" => $anvil->data->{libvirtd}{$target}{server}{$server_name}{connection},
}});
last;
}
}
my $return = 0;
if (($server_name) && ($server_name ne "all") && (not $anvil->data->{libvirtd}{$target}{server}{$server_name}{connection}))
{
# Didn't find the server
return(1)
}
return(0);
}
=head2 count_servers
@ -361,6 +530,7 @@ pmsuspended - The domain has been suspended by guest power management, e.g. ente
}
### TODO: Phase this out in favor for Server->locate()
=head2 find
This will look on the local or a remote machine for the list of servers that are running.
@ -985,8 +1155,7 @@ sub map_network
target => $target,
}});
# NOTE: We don't use 'Server->find' as the hassle of tracking hosts to target isn't worth it.
# Get a list of servers.
### TODO: Switch to using Server->locate()
my $shell_call = $anvil->data->{path}{exe}{setsid}." --wait ".$anvil->data->{path}{exe}{virsh}." list";
my $output = "";
if ($anvil->Network->is_local({host => $target}))
@ -1059,6 +1228,275 @@ sub map_network
}
=head2 locate
B<< Note >>: This is meant to replace C<< Server->find >>.
This walks through all known and accessible subnodes and DR hosts looking for a server. If a specific server is searched for and it's found running, the C<< short_host_name >> is returned. If there is a problem, C<< !!error!! >> is returned.
If a specific requested server is found, or is being asked to search for all servers, the following data is stored;
* server_location::host::<short_host_name>::access = [0,1]
* server_location::host::<short_host_name>::server::<server_name>::status = <status>
* server_location::host::<short_host_name>::server::<server_name>::active_definition = <XML>
* server_location::host::<short_host_name>::server::<server_name>::inactive_definition = <XML>
* server_location::host::<short_host_name>::server::<server_name>::definition_diff = <diff>
* server_location::host::<short_host_name>::server::<server_name>::file_definition = <file_body>
* server_location::host::<short_host_name>::server::<server_name>::drbd_config = <file_body>
If the target was not accessible, C<< access >> is set to C<< 0 >>. This is meant to allow telling the difference between "we know there's no servers on that host" versus "we don't know what's there because we couldn't access it".
If the server is found to be C<< running >> or C<< paused >>, then C<< active_definition >> is set and, if there's a difference, that will be stored. In all other states, the inactive XML is stored.
The C<< status >> can be:
* unknown # The server was found, but it has an unknown state
* running # Server is running.
* blocked # Server is blocked (IO contention?).
* paused # Server is paused (migration target?).
* in shutdown # Server is shutting down.
* shut off # Server is shut off.
* crashed # Server is crashed!
* pmsuspended # Server is suspended.
If there is a problem, C<< !!error!! >> is returned. If the server is found on at least one host, C<< 0 >> is returned. If the server is not located anywhere, C<< 1 >> is returned.
If the server has a replicated storage (DRBD) config and/or a definition file, whether the server is found running or not, will be recorded. This can be used to see if the server has been configured to run there or not.
The connection to the host and to the server(s) is cached, for your use;
* server_location::host::<short_host_name>::connection = <Sys::Virt object>
* server_location::host::<short_host_name>::server::<server_name>::connection = <Sys::Virt::Domain object>
C<< Note >>: By design, servers are set to 'undefined' on subnodes, so when the server shuts off, it disappears from libvirtd. This is normal and expected.
Parameters;
=head3 server_name (required)
This is the name of the server being located. It can be set to C<< all >>, in which case all servers on all hosts are located.
=cut
sub locate
{
my $self = shift;
my $parameter = shift;
my $anvil = $self->parent;
my $debug = defined $parameter->{debug} ? $parameter->{debug} : 3;
$anvil->Log->entry({source => $THIS_FILE, line => __LINE__, level => $debug, key => "log_0125", variables => { method => "Server->locate()" }});
my $server_name = defined $parameter->{server_name} ? $parameter->{server_name} : "";
$anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => $debug, list => {
server_name => $server_name,
}});
if (not $server_name)
{
$anvil->Log->entry({source => $THIS_FILE, line => __LINE__, level => 0, priority => "err", key => "log_0020", variables => { method => "Server->locate()", parameter => "server_name" }});
return('!!error!!');
}
if (exists $anvil->data->{server_location}{host})
{
delete $anvil->data->{server_location}{host};
}
# This will be set if the server is found to be 'running' on a host.
my $server_host = "";
# Connect to all hosts.
$anvil->Database->get_hosts({debug => $debug});
foreach my $host_name (sort {$a cmp $b} keys %{$anvil->data->{sys}{hosts}{by_name}})
{
my $host_uuid = $anvil->data->{sys}{hosts}{by_name}{$host_name};
my $host_type = $anvil->data->{hosts}{host_uuid}{$host_uuid}{host_type};
my $short_host_name = $anvil->data->{hosts}{host_uuid}{$host_uuid}{short_host_name};
$anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => $debug, list => {
's1:host_name' => $host_name,
's2:host_uuid' => $host_uuid,
's3:host_type' => $host_type,
's4:short_host_name' => $short_host_name,
}});
next if $host_type eq "striker";
# This will switch to '1' if we connect to libvirtd.
$anvil->data->{server_location}{host}{$short_host_name}{access} = 0;
# What IP to use? Don't test access, it's too slow if there's several down hosts.
my $target_ip = $anvil->Network->find_target_ip({
debug => $debug,
host_uuid => $host_uuid,
networks => "bcn,mn,sn,ifn",
test_access => 0,
});
$anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => $debug, list => { target_ip => $target_ip }});
if ($target_ip)
{
# Try to connect to libvirtd.
$anvil->Server->connect_to_libvirt({
debug => $debug,
target => $short_host_name,
target_ip => $target_ip,
server_name => $server_name,
});
$anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => $debug, list => {
"libvirtd::${short_host_name}::connection" => $anvil->data->{libvirtd}{$short_host_name}{connection},
}});
if (ref($anvil->data->{libvirtd}{$short_host_name}{connection}) eq "Sys::Virt")
{
# We're connected! Collect the data on the requested server(s), if applicable.
$anvil->data->{server_location}{host}{$short_host_name}{access} = 1;
$anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => $debug, list => {
"server_location::host::${short_host_name}::access" => $anvil->data->{server_location}{host}{$short_host_name}{access},
}});
if ($server_name)
{
my $connection_handle = $anvil->data->{libvirtd}{$short_host_name}{connection};
$anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => $debug, list => { connection_handle => $connection_handle }});
foreach my $this_server_name (sort {$a cmp $b} keys %{$anvil->data->{libvirtd}{$short_host_name}{server}})
{
next if (ref($anvil->data->{libvirtd}{$short_host_name}{server}{$server_name}{connection}) ne "Sys::Virt::Domain");
if (($server_name eq "all") or ($server_name eq $this_server_name))
{
my $server_handle = $anvil->data->{libvirtd}{$short_host_name}{server}{$server_name}{connection};
$anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => $debug, list => { server_handle => $server_handle }});
# Get the server's state, then convert to a string
my ($state, $reason) = $server_handle->get_state();
$anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => $debug, list => {
'state' => $state,
reason => $reason,
}});
### Reasons are dependent on the state.
### See: https://libvirt.org/html/libvirt-libvirt-domain.html#virDomainShutdownReason
my $server_state = "unknown";
if ($state == 1) { $server_state = "running"; } # Server is running.
elsif ($state == 2) { $server_state = "blocked"; } # Server is blocked (IO contention?).
elsif ($state == 3) { $server_state = "paused"; } # Server is paused (migration target?).
elsif ($state == 4) { $server_state = "in shutdown"; } # Server is shutting down.
elsif ($state == 5) { $server_state = "shut off"; } # Server is shut off.
elsif ($state == 6) { $server_state = "crashed"; } # Server is crashed!
elsif ($state == 7) { $server_state = "pmsuspended"; } # Server is suspended.
$anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => $debug, list => { server_state => $server_state }});
# Get the persistent definition
my $inactive_definition = $server_handle->get_xml_description(Sys::Virt::Domain::XML_INACTIVE);
$anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => $debug, list => { inactive_definition => $inactive_definition }});
# Get the active definition, if applicable.
my $active_definition = "";
my $definition_diff = "";
if (($server_state eq "running") or ($server_state eq "paused"))
{
# Get the active definition
$active_definition = $server_handle->get_xml_description();
$anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => $debug, list => { active_definition => $active_definition }});
# Check for a diff.
$definition_diff = diff \$active_definition, \$inactive_definition, { STYLE => 'Unified' };
$anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => $debug, list => { definition_diff => $definition_diff }});
}
if ($server_state eq "running")
{
$server_host = $short_host_name;
$anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => $debug, list => { server_host => $server_host }});
}
# If it's running, record the host.
$anvil->data->{server_location}{host}{$short_host_name}{server}{$server_name}{status} = $server_state;
$anvil->data->{server_location}{host}{$short_host_name}{server}{$server_name}{active_definition} = $active_definition;
$anvil->data->{server_location}{host}{$short_host_name}{server}{$server_name}{inactive_definition} = $inactive_definition;
$anvil->data->{server_location}{host}{$short_host_name}{server}{$server_name}{definition_diff} = $definition_diff;
$anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => $debug, list => {
"server_location::host::${short_host_name}::server::${server_name}::status" => $anvil->data->{server_location}{host}{$short_host_name}{server}{$server_name}{status},
"server_location::host::${short_host_name}::server::${server_name}::active_definition" => $anvil->data->{server_location}{host}{$short_host_name}{server}{$server_name}{active_definition},
"server_location::host::${short_host_name}::server::${server_name}::inactive_definition" => $anvil->data->{server_location}{host}{$short_host_name}{server}{$server_name}{inactive_definition},
"server_location::host::${short_host_name}::server::${server_name}::definition_diff" => $anvil->data->{server_location}{host}{$short_host_name}{server}{$server_name}{definition_diff},
}});
}
}
# If we've connected to the host, see if the XML definition file
# and/or DRBD config file exist.
my $servers = [];
if ($server_name eq "all")
{
# Search for any server we can find.
$anvil->Database->get_servers();
foreach my $server_uuid (sort {$a cmp $b} keys %{$anvil->data->{servers}{server_uuid}})
{
next if $anvil->data->{servers}{server_uuid}{$server_uuid}{server_state} eq "DELETED";
my $this_server_name = $anvil->data->{servers}{server_uuid}{$server_uuid}{server_name};
$anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => $debug, list => {
server_uuid => $server_uuid,
this_server_name => $this_server_name,
}});
push @{$servers}, $this_server_name;
}
}
else
{
push @{$servers}, $server_name;
}
foreach my $this_server_name (sort {$a cmp $b} @{$servers})
{
# Look for the files for the specified server.
$anvil->data->{server_location}{host}{$short_host_name}{server}{$this_server_name}{file_definition} = "";
$anvil->data->{server_location}{host}{$short_host_name}{server}{$this_server_name}{drbd_config} = "";
# See if there's a definition file and/or a DRBD
# config file on this host.
my $definition_file = $anvil->data->{path}{directories}{shared}{definitions}."/".$this_server_name.".xml";
$anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => $debug, list => { definition_file => $definition_file }});
# Can I read the definition file?
my $definition_body = $anvil->Storage->read_file({
debug => $debug,
file => $definition_file,
target => $target_ip,
});
$anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { definition_body => $definition_body }});
if (($definition_body) && ($definition_body ne "!!error!!"))
{
$anvil->data->{server_location}{host}{$short_host_name}{server}{$this_server_name}{file_definition} = $definition_body;
$anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => $debug, list => {
"server_location::host::${short_host_name}::server::${this_server_name}::file_definition" => $anvil->data->{server_location}{host}{$short_host_name}{server}{$this_server_name}{file_definition},
}});
}
my $drbd_config_file = $anvil->data->{path}{directories}{drbd_resources}."/".$this_server_name.".res";
$anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => $debug, list => { drbd_config_file => $drbd_config_file }});
my $drbd_body = $anvil->Storage->read_file({
debug => $debug,
file => $drbd_config_file,
target => $target_ip,
});
$anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { drbd_body => $drbd_body }});
if (($drbd_body) && ($drbd_body ne "!!error!!"))
{
$anvil->data->{server_location}{host}{$short_host_name}{server}{$this_server_name}{drbd_config} = $drbd_body;
$anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => $debug, list => {
"server_location::host::${short_host_name}::server::${this_server_name}::drbd_config" => $anvil->data->{server_location}{host}{$short_host_name}{server}{$this_server_name}{drbd_config},
}});
}
}
}
}
}
}
return($server_host);
}
=head2 migrate_virsh
This will migrate (push or pull) a server from one node to another. If the migration was successful, C<< 1 >> is returned. Otherwise, C<< 0 >> is returned with a (hopefully) useful error being logged.
@ -1462,6 +1900,10 @@ The XML was dumped by C<< virsh >> from memory.
The XML was read from the C<< definitions >> database table.
=head4 C<< test >>
The XML is a test definition, and not actually from anywhere.
=head3 definition (required)
This is the actual XML to be parsed.
@ -2191,8 +2633,6 @@ sub shutdown_virsh
if ($shutdown)
{
$anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => $debug, list => { "sys::database::connections" => $anvil->data->{sys}{database}{connections} }});
if ($anvil->data->{sys}{database}{connections})
{
if ($anvil->data->{sys}{database}{connections})
{
my $anvil_uuid = $anvil->Cluster->get_anvil_uuid({debug => $debug});
@ -2230,7 +2670,6 @@ WHERE
}
}
}
}
$anvil->Log->entry({source => $THIS_FILE, line => __LINE__, 'print' => 1, level => 1, key => "log_0520", variables => { server => $server }});
my ($output, $return_code) = $anvil->System->call({
debug => $debug,
@ -2287,8 +2726,12 @@ WHERE
}});
# Mark it as stopped now. (if we have a server_uuid, we have a database connection)
$anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => $debug, list => { server_uuid => $server_uuid }});
if ($server_uuid)
{
$anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => $debug, list => {
"sys::database::connections" => $anvil->data->{sys}{database}{connections},
}});
if ($anvil->data->{sys}{database}{connections})
{
$anvil->Database->get_servers({debug => $debug});
@ -2342,6 +2785,224 @@ WHERE
return($success);
}
=head2 update_definition
This takes a new server XML definition and saves it in the database and writes it out to the on-disk files. If either subnode or DR host is inacessible, this still returns success as C<< scan-server >> will pick up the new definition when the server comes back online.
If there is a problem, C<< !!error!! >> is returned. If it is updated, C<< 0 >> is returned.
Parameters;
=head3 server (required)
This is the name or UUID of the server being updated.
=head3 new_definition_xml
This is the new XML definition file. It will be parsed and sanity checked.
=cut
sub update_definition
{
my $self = shift;
my $parameter = shift;
my $anvil = $self->parent;
my $debug = defined $parameter->{debug} ? $parameter->{debug} : 3;
$anvil->Log->entry({source => $THIS_FILE, line => __LINE__, level => $debug, key => "log_0125", variables => { method => "Server->update_definition()" }});
my $server = defined $parameter->{server} ? $parameter->{server} : "";
my $new_definition_xml = defined $parameter->{new_definition_xml} ? $parameter->{new_definition_xml} : 0;
$anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => $debug, list => {
server => $server,
new_definition_xml => $new_definition_xml,
}});
if (not $server)
{
$anvil->Log->entry({source => $THIS_FILE, line => __LINE__, level => 0, priority => "err", key => "log_0020", variables => { method => "Server->update_definition()", parameter => "server" }});
return('!!error!!');
}
if (not $new_definition_xml)
{
$anvil->Log->entry({source => $THIS_FILE, line => __LINE__, level => 0, priority => "err", key => "log_0020", variables => { method => "Server->update_definition()", parameter => "new_definition_xml" }});
return('!!error!!');
}
my ($server_name, $server_uuid) = $anvil->Get->server_from_switch({
debug => $debug,
server_string => $server,
});
$anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => {
server_name => $server_name,
server_uuid => $server_uuid,
}});
# Do we have a valid server UUID?
$anvil->Database->get_anvils({debug => $debug});
$anvil->Database->get_servers({debug => $debug});
if (not exists $anvil->data->{servers}{server_uuid}{$server_uuid})
{
# Invalid.
$anvil->Log->entry({source => $THIS_FILE, line => __LINE__, level => 0, priority => "err", key => "error_0463", variables => {
server => $server,
server_uuid => $server_uuid,
}});
return('!!error!!');
}
# Validate the new XML
my $short_host_name = $anvil->Get->short_host_name();
my $problem = $anvil->Server->parse_definition({
debug => 2,
target => $short_host_name,
server => $server_name,
source => "test",
definition => $new_definition_xml,
});
$anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { problem => $problem }});
if ($problem)
{
# Failed to parse.
$anvil->Log->entry({source => $THIS_FILE, line => __LINE__, level => 0, priority => "err", key => "error_0464", variables => {
server_name => $server_name,
xml => $new_definition_xml,
}});
return('!!error!!');
}
else
{
my $test_uuid = $anvil->data->{server}{$short_host_name}{$server_name}{test}{info}{uuid} // "";
if ((not $test_uuid) or ($test_uuid ne $server_uuid))
{
# Somehow the new XML is invalid.
$anvil->Log->entry({source => $THIS_FILE, line => __LINE__, level => 0, priority => "err", key => "error_0464", variables => {
server_name => $server_name,
xml => $new_definition_xml,
}});
return('!!error!!');
}
}
# Prep our variables.
my $anvil_uuid = $anvil->data->{servers}{server_uuid}{$server_uuid}{server_anvil_uuid};
my $definition_uuid = $anvil->data->{servers}{server_uuid}{$server_uuid}{server_definition_uuid};
my $db_definition_xml = $anvil->data->{servers}{server_uuid}{$server_uuid}{server_definition_xml};
my $node1_host_uuid = $anvil->data->{anvils}{anvil_uuid}{$anvil_uuid}{anvil_node1_host_uuid};
my $node1_host_name = $anvil->data->{hosts}{host_uuid}{$node1_host_uuid}{host_name};
my $node2_host_uuid = $anvil->data->{anvils}{anvil_uuid}{$anvil_uuid}{anvil_node2_host_uuid};
my $node2_host_name = $anvil->data->{hosts}{host_uuid}{$node2_host_uuid}{host_name};
$anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => {
anvil_uuid => $anvil_uuid,
definition_uuid => $definition_uuid,
db_definition_xml => $db_definition_xml,
node1_host_uuid => $node1_host_uuid,
node1_host_name => $node1_host_name,
node2_host_uuid => $node2_host_uuid,
node2_host_name => $node2_host_name,
}});
# Is there a difference between the new and DB definition?
my $db_difference = diff \$db_definition_xml, \$new_definition_xml, { STYLE => 'Unified' };
$anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { db_difference => $db_difference }});
if ($db_difference)
{
# Update the DB.
$anvil->Database->insert_or_update_server_definitions({
debug => $debug,
server_definition_uuid => $definition_uuid,
server_definition_server_uuid => $server_uuid,
server_definition_xml => $new_definition_xml,
});
}
# Look for definitions
my $hosts = [$node1_host_uuid, $node2_host_uuid];
foreach my $dr_host_name (sort {$a cmp $b} keys %{$anvil->data->{dr_links}{by_anvil_uuid}{$anvil_uuid}{dr_link_host_name}})
{
my $dr_link_uuid = $anvil->data->{dr_links}{by_anvil_uuid}{$anvil_uuid}{dr_link_host_name}{$dr_host_name}{dr_link_uuid};
my $dr_host_uuid = $anvil->data->{dr_links}{dr_link_uuid}{$dr_link_uuid}{dr_link_host_uuid};
$anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => $debug, list => {
's1:dr_host_name' => $dr_host_name,
's2:dr_host_uuid' => $dr_host_uuid,
's3:dr_link_uuid' => $dr_link_uuid,
}});
push @{$hosts}, $dr_host_uuid;
}
# Get the host UUIDs for the node this server is hosted by.
my $definition_file = $anvil->data->{path}{directories}{shared}{definitions}."/".$server_name.".xml";
$anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => $debug, list => { definition_file => $definition_file }});
foreach my $host_uuid (@{$hosts})
{
# Find a target_ip (local will be detected as local in the file read/write)
my $target_ip = $anvil->Network->find_target_ip({
debug => 2,
host_uuid => $host_uuid,
test_access => 1,
networks => "bcn,mn,sn,ifn,any",
});
$anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { target_ip => $target_ip }});
if ($target_ip)
{
# Read the old definition.
my $old_definition_xml = $anvil->Storage->read_file({
debug => $debug,
file => $definition_file,
target => $target_ip,
});
$anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { old_definition_xml => $old_definition_xml }});
### TODO: Handle when the definition file simply doesn't exist.
if ((not $old_definition_xml) or ($old_definition_xml eq "!!error!!") or ($old_definition_xml !~ /<domain/ms))
{
my $host_name = $anvil->data->{hosts}{host_uuid}{$host_uuid}{host_name};
$anvil->Log->entry({source => $THIS_FILE, line => __LINE__, level => 1, priority => "alert", key => "warning_0163", variables => {
server_name => $server_name,
host_name => $host_name,
file => $definition_file,
}});
}
else
{
my $file_difference = diff \$old_definition_xml, \$new_definition_xml, { STYLE => 'Unified' };
$anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { file_difference => $file_difference }});
if ($file_difference)
{
# Update
my $error = $anvil->Storage->write_file({
debug => $debug,
file => $definition_file,
body => $new_definition_xml,
backup => 1,
overwrite => 1,
mode => "0644",
group => "root",
user => "root",
target => $target_ip,
});
$anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { error => $error }});
if ($error)
{
my $host_name = $anvil->data->{hosts}{host_uuid}{$host_uuid}{host_name};
$anvil->Log->entry({source => $THIS_FILE, line => __LINE__, level => 1, priority => "alert", key => "warning_0164", variables => {
server_name => $server_name,
host_name => $host_name,
file => $definition_file,
}});
}
}
}
# If the server running or defined here?
}
}
return(0);
}
# =head3
#
# Private Functions;

@ -776,7 +776,7 @@ sub check_files
}
elsif ($file_location_ready)
{
# File doesn't exist but is marked as read, mark it as not ready.
# File doesn't exist but is marked as ready, mark it as not ready.
$anvil->Database->insert_or_update_file_locations({
debug => $debug,
file_location_uuid => $file_location_uuid,
@ -2744,7 +2744,7 @@ AND
This creates a directory (and any parent directories).
$anvil->Storage->make_directory({directory => "/foo/bar/baz", owner => "me", grou[ => "me", group => 755});
$anvil->Storage->make_directory({directory => "/foo/bar/baz", owner => "me", group => "me", mode => "0755"});
If it fails to create the directory, C<< 1 >> will be returned. Otherwise, C<< 0 >> will be returned.

@ -107,7 +107,7 @@ sub set_host_power
elsif (not $is_host_on && $on)
{
$anvil->Database->insert_or_update_jobs({
job_command => $anvil->data->{path}{directories}{tools}."/striker-boot-machine --host-uuid ".$host_uuid,
job_command => $anvil->data->{path}{directories}{tools}."/striker-boot-machine --host ".$host_uuid,
job_description => "job_0335",
job_name => "cgi-bin::set_power::on",
job_progress => 0,

@ -71,6 +71,7 @@ dist_man8_MANS = \
striker-purge-target.8 \
striker-scan-network.8 \
striker-show-db-counts.8 \
striker-show-jobs.8 \
striker-update-cluster.8 \
tool-fio-tester.8 \
unfence_pacemaker.8

@ -0,0 +1,57 @@
.\" Manpage for the Anvil! server boot program
.\" Contact mkelly@alteeve.com to report issues, concerns or suggestions.
.TH anvil-manage-host "8" "Octobober 12 2023" "Anvil! Intelligent Availability™ Platform"
.SH NAME
anvil-manage-host \- Tool used to check or set various configuration options for a host.
.SH SYNOPSIS
.B anvil-manage-host
\fI\,<command> \/\fR[\fI\,options\/\fR]
.SH DESCRIPTION
.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\-\-age\-out\-database\fR
This requests the database check for records that are too old and purge them.
.TP
\fB\-\-check\-configured\fR
Check to see if the host is marked as configured or yet.
.TP
\fB\-\-check\-database\fR
This checks to see if the database is enabled or not.
.TP
\fB\-\-check\-network\-mapping\fR
This reports if the host is currently in network mapping (this disables several features and watches the network states much more frequently)
.TP
\fB\-\-database\-active\fR
This enables the database on the local Striker dashboard.
.TP
\fB\-\-database\-inactive\fR
This disables the database on the local Striker dashboard.
.TP
\fB\-\-disable\-network\-mapping\fR
This disables the network mapping mode.
.TP
\fB\-\-enable\-network\-mapping\fR
This enables the network mapping mode.
.TP
\fB\-\-mark\-configured\fR
This marks the host as having been configured.
.TP
\fB\-\-resync\-database\fR
This forces a database resync if two or more strikers are online.
.IP
.SH AUTHOR
Written by Madison Kelly, Alteeve staff and the Anvil! project contributors.
.SH "REPORTING BUGS"
Report bugs to users@clusterlabs.org

@ -42,7 +42,7 @@ This is the disk being worked on. For optical disks, it's the drive that an opti
When not specified, if only one disk exists, it will be chosen automatically.
.TP
\fB\-\-eject\fR
This ejects the optical disc (ISO) in the drive specified by \fB\-\-disk\fR.
This ejects the optical disc (ISO) in the drive specified by \fB\-\-optical\fR.
.TP
\fB\-\-job\-uuid\fR
This is the jobs -> job_uuid to execute. Generally this is only used by other programs.

@ -0,0 +1,39 @@
.\" Manpage for the Anvil! server system manager
.\" Contact mkelly@alteeve.com to report issues, concerns or suggestions.
.TH anvil-manage-server-system "8" "August 30 2023" "Anvil! Intelligent Availability™ Platform"
.SH NAME
anvil-manage-server-system \- Tool used to manage the system configuration of a hosted server.
.SH SYNOPSIS
.B anvil-manage-server-system
\fI\,<command> \/\fR[\fI\,options\/\fR]
.SH DESCRIPTION
anvil-manage-server-system \- This tool is used to manage various system configuration components of hosted servers. Storage is NOT managed here, see 'anvil-manage-server-storage' for that.
.TP
When called without switches, the list of servers than can be worked on will be displayed.
.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\-\-boot\-menu\fR <yes,no>
.TP
When called without a value, it shows if the boot menu is enabled or not. If called with 'yes', it enables the boot menu. If called with 'no', the boot meny is disabled.
.TP
\fB\-\-job\-uuid\fR
This is the jobs -> job_uuid to execute. Generally this is only used by other programs.
.TP
\fB\-\-\fR
.IP
.SH AUTHOR
Written by Madison Kelly, Alteeve staff and the Anvil! project contributors.
.SH "REPORTING BUGS"
Report bugs to users@clusterlabs.org

@ -0,0 +1,38 @@
.\" Manpage for the Anvil! server boot program
.\" Contact mkelly@alteeve.com to report issues, concerns or suggestions.
.TH striker-boot-machine "8" "October 12 2023" "Anvil! Intelligent Availability™ Platform"
.SH NAME
striker-boot-machine \- Tool used to boot physical machines that have IPMI configuration information.
.SH SYNOPSIS
.B striker-boot-machine
\fI\,<command> \/\fR[\fI\,options\/\fR]
.SH DESCRIPTION
This tool is used to power up any machine in the cluster with IPMI configuration in the database. Typically this is subnodes and DR hosts, but could also be Striker dashboards if they have an IPMI BMC. If the server is found to already be om, it will NOT be booted again.
.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\-\-host\fR <name, UUID or 'all'>
This is the host name or UUID of the server to power on. If this is set to 'all', all machines that have IPMI configuration information will be checked, and if it's found to be off, it will be booted.
.TP
\fB\-\-host-uuid\fR <UUID>
This is effectively the same as \fB\-\-host\fR, but provides backwards compatibility. It's use is discouraged.
.TP
\fB\-\-job\-uuid\fR <uuid>
If this is set, the job will be processed.
.TP
Be aware that when this is used, if a server fails to boot, no further servers will be started.
.IP
.SH AUTHOR
Written by Madison Kelly, Alteeve staff and the Anvil! project contributors.
.SH "REPORTING BUGS"
Report bugs to users@clusterlabs.org

@ -0,0 +1,37 @@
.\" Manpage for the Anvil! server boot program
.\" Contact mkelly@alteeve.com to report issues, concerns or suggestions.
.TH striker-show-jobs "8" "October 18 2023" "Anvil! Intelligent Availability™ Platform"
.SH NAME
striker-show-jobs \- This shows the queued, running and (recently) completed jobs.
.SH SYNOPSIS
.B striker-show-jobs
\fI\,<command> \/\fR[\fI\,options\/\fR]
.SH DESCRIPTION
This shows information about jobs that are queued, running or completed within a set amount of time on the command line.
.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\-\-ended\-within\fR <seconds>
This allows viewing jobs that have already completed. This is the number of seconds (default '300') back in time that you want to see completed jobs. Jobs that completed more than this amount of time ago will be ignored.
.TP
\fB\-\-host\fR <name, UUID or 'all'>
This is the host name or UUID that you want to see jobs from. The default is 'all' and shows all machines in the Anvil! cluster.
.TP
Setting this to '0' will hide completed jobs.
\fB\-\-job\-uuid\fR <uuid>
This allows showing the details of only one specific job.
.IP
.SH AUTHOR
Written by Madison Kelly, Alteeve staff and the Anvil! project contributors.
.SH "REPORTING BUGS"
Report bugs to users@clusterlabs.org

@ -623,6 +623,13 @@ sub start_server
# Start the resource, if needed.
start_drbd_resource($anvil);
# Get a connection so that we can mark is as being in shutdown and shut off.
$anvil->Database->connect({
check_for_resync => 0,
retry => 0,
sensitive => 1,
});
# Still alive? Boot!
my ($success) = $anvil->Server->boot_virsh({debug => 2, server => $server});
$anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { success => $success }});
@ -1080,6 +1087,7 @@ sub start_drbd_resource
return(0);
}
### TODO: Rework this to use Server->connect_to_libvirtd and phase out Server->find().
# This uses the DRBD information to find other peers and see if the server is running on them.
sub find_server
{
@ -1173,6 +1181,13 @@ sub stop_server
$anvil->System->check_storage();
$anvil->Server->get_status({debug => 2, server => $server});
# Get a connection so that we can mark is as being in shutdown and shut off.
$anvil->Database->connect({
check_for_resync => 0,
retry => 0,
sensitive => 1,
});
$anvil->Log->entry({source => $THIS_FILE, line => __LINE__, level => 2, key => "log_0313", variables => { server => $server }});
my $success = $anvil->Server->shutdown_virsh({server => $server});
if (not $success)

@ -186,10 +186,10 @@ if ($anvil->data->{switches}{purge})
my $host_uuid = $anvil->Get->host_uuid();
$anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => {
host_uuid => $host_uuid,
"sys::database::active_uuid" => $anvil->data->{sys}{database}{active_uuid},
"sys::database::primary_db" => $anvil->data->{sys}{database}{primary_db},
"switches::force" => $anvil->data->{switches}{force},
}});
if ((not $anvil->data->{switches}{force}) && ($anvil->data->{sys}{database}{active_uuid} ne $host_uuid))
if ((not $anvil->data->{switches}{force}) && ($anvil->data->{sys}{database}{primary_db} ne $host_uuid))
{
# Don't run.
$anvil->Log->entry({source => $THIS_FILE, line => __LINE__, level => 2, key => "scan_apc_pdu_message_0041", variables => { program => $THIS_FILE }});

@ -205,6 +205,7 @@ sub cib_cleanup
return(0);
}
### TODO: Rework this to use Server->connect_to_libvirtd and phase out Server->find().
# This looks for failed resource and, if found, tries to recover them.
sub check_resources
{

@ -12,8 +12,7 @@
# 2 = libvirtd is not running.
#
# BUG:
# - Check that an update on disk is not overwritten by the old config still being in memory for a still-
# running VM (specifically, RAM updates)
# - Servers that are off, but not marked as such in the DB, needs to be updated. (See: line ~1105)
#
# TODO:
# - Move location constraints to the host node if the server is not on the preferred host (this happens after
@ -437,6 +436,11 @@ sub collect_data
my $server_state = get_server_state($anvil, $server_name);
$anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { server_state => $server_state }});
$anvil->data->{'scan-server'}{server_name}{$server_name}{server_state} = $server_state;
$anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => {
"scan-server::server_name::${server_name}::server_state" => $anvil->data->{'scan-server'}{server_name}{$server_name}{server_state},
}});
# This is set to 1 when we add a server, supressing detailed change checks as we'll have
# already registered an alert.
my $added = 0;

@ -726,6 +726,13 @@ The creation of the new replicatedd disk is incomplete, manual intervention is r
====================
The creation of the new replicated disk is incomplete, manual intervention is required!]]></key>
<key name="error_0462"><![CDATA[The switch '--immediate' can not be used with '--server all'.]]></key>
<key name="error_0463"><![CDATA[Failed to translate the 'server' string: [#!variable!server!#] to a UUID: [#!variable!server_uuid!#].]]></key>
<key name="error_0464"><![CDATA[There was a problem parsing the new XML definition for the server: [#!variable!server_name!#]. Either the XML failed to parse, or the server's UUID doesn't match.
The XML that failed sanity check was:
========
#!variable!xml!#
========
]]></key>
<!-- Files templates -->
<!-- NOTE: Translating these files requires an understanding of which lines are translatable -->
@ -1149,6 +1156,10 @@ resource #!variable!server!# {
<key name="header_0108">On Battery</key>
<key name="header_0109">Estimated Runtime</key>
<key name="header_0110">Last Updated</key>
<key name="header_0111">Optical Disc</key>
<key name="header_0112">Queued Jobs</key>
<key name="header_0113">Jobs In Progress</key>
<key name="header_0114">Completed Jobs</key>
<!-- Strings used by jobs -->
<key name="job_0001">Configure Network</key>
@ -2613,6 +2624,9 @@ The file: [#!variable!file!#] needs to be updated. The difference is:
<key name="log_0811">- The host: [#!variable!host_name!#] is not configured, skipping it.</key>
<key name="log_0812">The file: [#!variable!full_path!#] is in the database multiple times. This could be an artifact from peering Strikers. Selecting an entry to remove...</key>
<key name="log_0813">Deleting the 'files' database entry for the file uuid: [#!variable!file_uuid!#].</key>
<key name="log_0814">There is an existing a functioning connection to: [#!variable!target!#], no need to reconnect.</key>
<key name="log_0815">There is an existing a functioning connection to the server: [#!variable!server_name!#], no need to reconnect.</key>
<key name="log_0816">Waiting for: [#!variable!delay!#] seconds.</key>
<!-- Messages for users (less technical than log entries), though sometimes used for logs, too. -->
<key name="message_0001">The host name: [#!variable!target!#] does not resolve to an IP address.</key>
@ -3161,6 +3175,10 @@ Proceed? [y/N]</key>
<key name="message_0350">Preparing to managing storage for a server.</key>
<key name="message_0351">Running checks before processing power request...</key>
<key name="message_0352">The job to: [#!variable!task!#] this host has been picked up.</key>
<key name="message_0353">This host is already configured to map the network.</key>
<key name="message_0354">This host is now configured to map the network.</key>
<key name="message_0355">This host is already NOT configured to map the network.</key>
<key name="message_0356">This host is no longer configured to map the network.</key>
<!-- Translate names (protocols, etc) -->
<key name="name_0001">Normal Password</key> <!-- none in mail-server -->
@ -3663,6 +3681,7 @@ Here we will inject 't_0006', which injects 't_0001' which has a variable: [#!st
<key name="unit_0046">- Server is crashed!</key>
<key name="unit_0047">- Server is suspended.</key>
<key name="unit_0048">- Server is in an unknown state (int: [#!variable!state!#]).</key>
<key name="unit_0049"><![CDATA[<ejected>]]></key>
<!-- These are special. These are used to describe the UPSes that ScanCore supports. These
are used when adding UPSes to the system for use in Install Manifests.
@ -3931,6 +3950,8 @@ We will try to proceed anyway.</key>
#!variable!error!#
====
</key>
<key name="warning_0163"><![CDATA[Failed to read the definition file: [#!variable!file!#] for the server: [#!variable!server_name!#] on the host: [#!variable!host_name!#]. If the host is online, it should update the next time scan-server runs.]]></key>
<key name="warning_0164"><![CDATA[Failed to update the definition file: [#!variable!file!#] for the server: [#!variable!server_name!#] on the host: [#!variable!host_name!#]. If the host is online, it should update the next time scan-server runs.]]></key>
</language>
<!-- 日本語 -->

File diff suppressed because one or more lines are too long

File diff suppressed because it is too large Load Diff

@ -33,6 +33,9 @@ export const buildUnknownIDCondition = (
};
export const buildKnownIDCondition = (
keys: string[] | '*' = '*',
keys: string[] | 'all' | '*' = 'all',
conditionPrefix: string,
) => (keys[0] === '*' ? '' : buildIDCondition(keys, conditionPrefix));
) =>
!(keys instanceof Array) || keys.some((v) => ['all', '*'].includes(v))
? ''
: buildIDCondition(keys, conditionPrefix);

@ -60,8 +60,6 @@ export const buildAnvilSummary = async ({
throw error;
}
if (!scounts.length) throw new Error(`No host server records found`);
for (const huuid of [n1uuid, n2uuid]) {
const {
host_uuid: {

@ -1,6 +1,10 @@
import { dSize } from 'format-data-size';
import { NODE_AND_DR_RESERVED_MEMORY_SIZE, OS_LIST_MAP } from '../../consts';
import {
DELETED,
NODE_AND_DR_RESERVED_MEMORY_SIZE,
OS_LIST_MAP,
} from '../../consts';
import join from '../../join';
import { stdoutVar } from '../../shell';
@ -99,6 +103,7 @@ const buildQueryAnvilDetail = ({
FROM server_definitions AS ser_def
) AS pos_ser_def
ON server_uuid = server_definition_server_uuid
WHERE ser.server_state != '${DELETED}'
${groupByPhrase}`;
};

@ -1,5 +1,7 @@
import { RequestHandler } from 'express';
import { DELETED } from '../../consts';
import { query } from '../../accessModule';
import { getShortHostName } from '../../disassembleHostName';
import { stderr } from '../../shell';
@ -72,7 +74,8 @@ export const getAnvilCpu: RequestHandler<AnvilDetailParamsDictionary> = async (
FROM servers AS a
JOIN server_definitions AS b
ON a.server_uuid = b.server_definition_server_uuid
WHERE a.server_anvil_uuid = '${anvilUuid}';`,
WHERE a.server_state != '${DELETED}'
AND a.server_anvil_uuid = '${anvilUuid}';`,
);
} catch (error) {
stderr(`Failed to get anvil ${anvilUuid} server cpu info; CAUSE: ${error}`);
@ -99,7 +102,8 @@ export const getAnvilCpu: RequestHandler<AnvilDetailParamsDictionary> = async (
const cores = Number(rCores);
const threads = Number(rThreads);
const vendor = model.replace(/^(\w+).*$/, '$1');
const matched = model.match(/amd|arm|intel|powerpc/i);
const vendor = matched ? matched[0] : model.replace(/^(\w+).*$/, '$1');
previous.hosts[uuid] = {
cores,

@ -34,9 +34,7 @@ export const getAnvilDetail: RequestHandler<
hosts,
});
} catch (error) {
stderr(
`Failed to get summary of anvil node pair ${anvilUuid}; CAUSE: ${error}`,
);
stderr(`Failed to get summary of anvil node ${anvilUuid}; CAUSE: ${error}`);
return response.status(500).send();
}

@ -1,7 +1,7 @@
import { RequestHandler } from 'express';
import { DataSizeUnit, dSize } from 'format-data-size';
import { NODE_AND_DR_RESERVED_MEMORY_SIZE } from '../../consts';
import { DELETED, NODE_AND_DR_RESERVED_MEMORY_SIZE } from '../../consts';
import { query } from '../../accessModule';
import { stderr } from '../../shell';
@ -88,7 +88,8 @@ export const getAnvilMemory: RequestHandler<
FROM server_definitions AS a
JOIN servers AS b
ON b.server_uuid = a.server_definition_server_uuid
WHERE server_anvil_uuid = '${anvilUuid}';`,
WHERE b.server_state != '${DELETED}'
AND b.server_anvil_uuid = '${anvilUuid}';`,
);
} catch (error) {
stderr(`Failed to get anvil ${anvilUuid} server info; CAUSE: ${error}`);

@ -23,11 +23,17 @@ export const getAnvilSummary: RequestHandler<unknown, AnvilSummary> = async (
const { anvil_uuid: alist } = anvils;
const result: AnvilSummary = { anvils: [] };
try {
for (const auuid of Object.keys(alist)) {
result.anvils.push(
await buildAnvilSummary({ anvils, anvilUuid: auuid, hosts }),
);
}
} catch (error) {
stderr(`Failed to get summary of anvil nodes; CAUSE: ${error}`);
return response.status(500).send();
}
response.json(result);
};

@ -46,5 +46,6 @@ export const buildQueryFileDetail = ({
JOIN hosts AS hos
ON fil_loc.file_location_host_uuid = hos.host_uuid
WHERE fil.file_type != '${DELETED}'
${condFileUUIDs};`;
${condFileUUIDs}
ORDER BY fil.file_name ASC;`;
};

@ -17,7 +17,8 @@ export const getFile: RequestHandler = buildGetRequestHandler((request) => {
file_type,
file_md5sum
FROM files
WHERE file_type != '${DELETED}';`;
WHERE file_type != '${DELETED}'
ORDER BY file_name ASC;`;
if (fileUUIDs) {
query = buildQueryFileDetail({

@ -42,7 +42,7 @@ const setCvar = (
export const buildQueryHostDetail: BuildQueryDetailFunction = ({
keys: hostUUIDs = '*',
} = {}) => {
const condHostUUIDs = buildKnownIDCondition(hostUUIDs, 'a.host_uuid');
const condHostUUIDs = buildKnownIDCondition(hostUUIDs, 'WHERE a.host_uuid');
stdout(`condHostUUIDs=[${condHostUUIDs}]`);
@ -74,8 +74,9 @@ export const buildQueryHostDetail: BuildQueryDetailFunction = ({
ON b.variable_name LIKE '%link%_mac%'
AND b.variable_value = c.network_interface_mac_address
AND a.host_uuid = c.network_interface_host_uuid
WHERE ${condHostUUIDs}
ORDER BY cvar_name ASC,
${condHostUUIDs}
ORDER BY a.host_name ASC,
cvar_name ASC,
b.variable_name ASC;`;
const afterQueryReturn: QueryResultModifierFunction =

@ -29,7 +29,8 @@ export const getHost = buildGetRequestHandler((request, buildQueryOptions) => {
hos.host_type,
hos.host_uuid
FROM hosts AS hos
${condition};`;
${condition}
ORDER BY hos.host_name ASC;`;
let afterQueryReturn: QueryResultModifierFunction | undefined =
buildQueryResultReducer<{ [hostUUID: string]: HostOverview }>(
(previous, [hostName, hostType, hostUUID]) => {
@ -48,6 +49,9 @@ export const getHost = buildGetRequestHandler((request, buildQueryOptions) => {
);
if (hostUUIDs) {
// TODO: the output of host detail is designed to only contain one
// host, correct it to support multiple hosts to allow selecting
// multiple hosts' detail.
({ query, afterQueryReturn } = buildQueryHostDetail({
keys: sanitize(hostUUIDs, 'string[]', {
modifierType: 'sql',

@ -1,7 +1,7 @@
import assert from 'assert';
import { RequestHandler } from 'express';
import { REP_UUID, SERVER_PATHS } from '../../consts';
import { DELETED, REP_UUID, SERVER_PATHS } from '../../consts';
import { OS_LIST_MAP } from '../../consts/OS_LIST';
import { job, query } from '../../accessModule';
@ -49,7 +49,11 @@ export const createServer: RequestHandler = async (request, response) => {
);
const [[serverNameCount]] = await query(
`SELECT COUNT(server_uuid) FROM servers WHERE server_name = '${serverName}'`,
`SELECT
COUNT(server_uuid)
FROM servers
WHERE server_state != '${DELETED}'
AND server_name = '${serverName}'`,
);
assert(

@ -1,7 +1,7 @@
import assert from 'assert';
import { RequestHandler } from 'express';
import { REP_UUID, SERVER_PATHS } from '../../consts';
import { DELETED, REP_UUID, SERVER_PATHS } from '../../consts';
import { job, query } from '../../accessModule';
import { sanitize } from '../../sanitize';
@ -39,7 +39,11 @@ export const deleteServer: RequestHandler<
);
const rows: [[string]] = await query(
`SELECT server_host_uuid FROM servers WHERE server_uuid = '${serverUuid}';`,
`SELECT
server_host_uuid
FROM servers
WHERE server_state != '${DELETED}'
AND server_uuid = '${serverUuid}';`,
);
assert.ok(rows.length, `Server ${serverUuid} not found`);

@ -25,7 +25,7 @@
"formik": "^2.4.3",
"lodash": "^4.17.21",
"netmask": "^2.0.2",
"next": "^12.1.0",
"next": "^13.5.4",
"pretty-bytes": "^5.6.0",
"react": "17.0.2",
"react-dom": "17.0.2",
@ -1444,9 +1444,9 @@
}
},
"node_modules/@next/env": {
"version": "12.1.0",
"resolved": "https://registry.npmjs.org/@next/env/-/env-12.1.0.tgz",
"integrity": "sha512-nrIgY6t17FQ9xxwH3jj0a6EOiQ/WDHUos35Hghtr+SWN/ntHIQ7UpuvSi0vaLzZVHQWaDupKI+liO5vANcDeTQ=="
"version": "13.5.4",
"resolved": "https://registry.npmjs.org/@next/env/-/env-13.5.4.tgz",
"integrity": "sha512-LGegJkMvRNw90WWphGJ3RMHMVplYcOfRWf2Be3td3sUa+1AaxmsYyANsA+znrGCBjXJNi4XAQlSoEfUxs/4kIQ=="
},
"node_modules/@next/eslint-plugin-next": {
"version": "11.1.4",
@ -1457,10 +1457,70 @@
"glob": "7.1.7"
}
},
"node_modules/@next/swc-darwin-arm64": {
"version": "13.5.4",
"resolved": "https://registry.npmjs.org/@next/swc-darwin-arm64/-/swc-darwin-arm64-13.5.4.tgz",
"integrity": "sha512-Df8SHuXgF1p+aonBMcDPEsaahNo2TCwuie7VXED4FVyECvdXfRT9unapm54NssV9tF3OQFKBFOdlje4T43VO0w==",
"cpu": [
"arm64"
],
"optional": true,
"os": [
"darwin"
],
"engines": {
"node": ">= 10"
}
},
"node_modules/@next/swc-darwin-x64": {
"version": "13.5.4",
"resolved": "https://registry.npmjs.org/@next/swc-darwin-x64/-/swc-darwin-x64-13.5.4.tgz",
"integrity": "sha512-siPuUwO45PnNRMeZnSa8n/Lye5ZX93IJom9wQRB5DEOdFrw0JjOMu1GINB8jAEdwa7Vdyn1oJ2xGNaQpdQQ9Pw==",
"cpu": [
"x64"
],
"optional": true,
"os": [
"darwin"
],
"engines": {
"node": ">= 10"
}
},
"node_modules/@next/swc-linux-arm64-gnu": {
"version": "13.5.4",
"resolved": "https://registry.npmjs.org/@next/swc-linux-arm64-gnu/-/swc-linux-arm64-gnu-13.5.4.tgz",
"integrity": "sha512-l/k/fvRP/zmB2jkFMfefmFkyZbDkYW0mRM/LB+tH5u9pB98WsHXC0WvDHlGCYp3CH/jlkJPL7gN8nkTQVrQ/2w==",
"cpu": [
"arm64"
],
"optional": true,
"os": [
"linux"
],
"engines": {
"node": ">= 10"
}
},
"node_modules/@next/swc-linux-arm64-musl": {
"version": "13.5.4",
"resolved": "https://registry.npmjs.org/@next/swc-linux-arm64-musl/-/swc-linux-arm64-musl-13.5.4.tgz",
"integrity": "sha512-YYGb7SlLkI+XqfQa8VPErljb7k9nUnhhRrVaOdfJNCaQnHBcvbT7cx/UjDQLdleJcfyg1Hkn5YSSIeVfjgmkTg==",
"cpu": [
"arm64"
],
"optional": true,
"os": [
"linux"
],
"engines": {
"node": ">= 10"
}
},
"node_modules/@next/swc-linux-x64-gnu": {
"version": "12.1.0",
"resolved": "https://registry.npmjs.org/@next/swc-linux-x64-gnu/-/swc-linux-x64-gnu-12.1.0.tgz",
"integrity": "sha512-OKO4R/digvrVuweSw/uBM4nSdyzsBV5EwkUeeG4KVpkIZEe64ZwRpnFB65bC6hGwxIBnTv5NMSnJ+0K/WmG78A==",
"version": "13.5.4",
"resolved": "https://registry.npmjs.org/@next/swc-linux-x64-gnu/-/swc-linux-x64-gnu-13.5.4.tgz",
"integrity": "sha512-uE61vyUSClnCH18YHjA8tE1prr/PBFlBFhxBZis4XBRJoR+txAky5d7gGNUIbQ8sZZ7LVkSVgm/5Fc7mwXmRAg==",
"cpu": [
"x64"
],
@ -1473,9 +1533,9 @@
}
},
"node_modules/@next/swc-linux-x64-musl": {
"version": "12.1.0",
"resolved": "https://registry.npmjs.org/@next/swc-linux-x64-musl/-/swc-linux-x64-musl-12.1.0.tgz",
"integrity": "sha512-JohhgAHZvOD3rQY7tlp7NlmvtvYHBYgY0x5ZCecUT6eCCcl9lv6iV3nfu82ErkxNk1H893fqH0FUpznZ/H3pSw==",
"version": "13.5.4",
"resolved": "https://registry.npmjs.org/@next/swc-linux-x64-musl/-/swc-linux-x64-musl-13.5.4.tgz",
"integrity": "sha512-qVEKFYML/GvJSy9CfYqAdUexA6M5AklYcQCW+8JECmkQHGoPxCf04iMh7CPR7wkHyWWK+XLt4Ja7hhsPJtSnhg==",
"cpu": [
"x64"
],
@ -1487,6 +1547,51 @@
"node": ">= 10"
}
},
"node_modules/@next/swc-win32-arm64-msvc": {
"version": "13.5.4",
"resolved": "https://registry.npmjs.org/@next/swc-win32-arm64-msvc/-/swc-win32-arm64-msvc-13.5.4.tgz",
"integrity": "sha512-mDSQfqxAlfpeZOLPxLymZkX0hYF3juN57W6vFHTvwKlnHfmh12Pt7hPIRLYIShk8uYRsKPtMTth/EzpwRI+u8w==",
"cpu": [
"arm64"
],
"optional": true,
"os": [
"win32"
],
"engines": {
"node": ">= 10"
}
},
"node_modules/@next/swc-win32-ia32-msvc": {
"version": "13.5.4",
"resolved": "https://registry.npmjs.org/@next/swc-win32-ia32-msvc/-/swc-win32-ia32-msvc-13.5.4.tgz",
"integrity": "sha512-aoqAT2XIekIWoriwzOmGFAvTtVY5O7JjV21giozBTP5c6uZhpvTWRbmHXbmsjZqY4HnEZQRXWkSAppsIBweKqw==",
"cpu": [
"ia32"
],
"optional": true,
"os": [
"win32"
],
"engines": {
"node": ">= 10"
}
},
"node_modules/@next/swc-win32-x64-msvc": {
"version": "13.5.4",
"resolved": "https://registry.npmjs.org/@next/swc-win32-x64-msvc/-/swc-win32-x64-msvc-13.5.4.tgz",
"integrity": "sha512-cyRvlAxwlddlqeB9xtPSfNSCRy8BOa4wtMo0IuI9P7Y0XT2qpDrpFKRyZ7kUngZis59mPVla5k8X1oOJ8RxDYg==",
"cpu": [
"x64"
],
"optional": true,
"os": [
"win32"
],
"engines": {
"node": ">= 10"
}
},
"node_modules/@nodelib/fs.scandir": {
"version": "2.1.5",
"resolved": "https://registry.npmjs.org/@nodelib/fs.scandir/-/fs.scandir-2.1.5.tgz",
@ -1542,6 +1647,14 @@
"integrity": "sha512-JLo+Y592QzIE+q7Dl2pMUtt4q8SKYI5jDrZxrozEQxnGVOyYE+GWK9eLkwTaeN9DDctlaRAQ3TBmzZ1qdLE30A==",
"dev": true
},
"node_modules/@swc/helpers": {
"version": "0.5.2",
"resolved": "https://registry.npmjs.org/@swc/helpers/-/helpers-0.5.2.tgz",
"integrity": "sha512-E4KcWTpoLHqwPHLxidpOqQbcrZVgi0rsmmZXUle1jXmJfuIf/UWpczUJ7MZZ5tlxytgJXyp0w4PGkkeLiuIdZw==",
"dependencies": {
"tslib": "^2.4.0"
}
},
"node_modules/@types/json-schema": {
"version": "7.0.9",
"resolved": "https://registry.npmjs.org/@types/json-schema/-/json-schema-7.0.9.tgz",
@ -2145,6 +2258,17 @@
"resolved": "https://registry.npmjs.org/buffer-from/-/buffer-from-0.1.2.tgz",
"integrity": "sha512-RiWIenusJsmI2KcvqQABB83tLxCByE3upSP8QU3rJDMVFGPWLvPQJt/O1Su9moRWeH7d+Q2HYb68f6+v+tw2vg=="
},
"node_modules/busboy": {
"version": "1.6.0",
"resolved": "https://registry.npmjs.org/busboy/-/busboy-1.6.0.tgz",
"integrity": "sha512-8SFQbg/0hQ9xy3UNTB0YEnsNBbWfhf7RtnzpL7TkBiTBRfrQ9Fxcnz7VJsleJpyp6rVLvXiuORqjlHi5q+PYuA==",
"dependencies": {
"streamsearch": "^1.1.0"
},
"engines": {
"node": ">=10.16.0"
}
},
"node_modules/call-bind": {
"version": "1.0.2",
"resolved": "https://registry.npmjs.org/call-bind/-/call-bind-1.0.2.tgz",
@ -2193,13 +2317,23 @@
}
},
"node_modules/caniuse-lite": {
"version": "1.0.30001312",
"resolved": "https://registry.npmjs.org/caniuse-lite/-/caniuse-lite-1.0.30001312.tgz",
"integrity": "sha512-Wiz1Psk2MEK0pX3rUzWaunLTZzqS2JYZFzNKqAiJGiuxIjRPLgV6+VDPOg6lQOUxmDwhTlh198JsTTi8Hzw6aQ==",
"funding": {
"version": "1.0.30001546",
"resolved": "https://registry.npmjs.org/caniuse-lite/-/caniuse-lite-1.0.30001546.tgz",
"integrity": "sha512-zvtSJwuQFpewSyRrI3AsftF6rM0X80mZkChIt1spBGEvRglCrjTniXvinc8JKRoqTwXAgvqTImaN9igfSMtUBw==",
"funding": [
{
"type": "opencollective",
"url": "https://opencollective.com/browserslist"
},
{
"type": "tidelift",
"url": "https://tidelift.com/funding/github/npm/caniuse-lite"
},
{
"type": "github",
"url": "https://github.com/sponsors/ai"
}
]
},
"node_modules/chalk": {
"version": "4.1.2",
@ -2254,6 +2388,11 @@
"url": "https://github.com/sponsors/sindresorhus"
}
},
"node_modules/client-only": {
"version": "0.0.1",
"resolved": "https://registry.npmjs.org/client-only/-/client-only-0.0.1.tgz",
"integrity": "sha512-IV3Ou0jSMzZrd3pZ48nLkT9DA7Ag1pnPzaiQhpW7c3RbcqqzvzzVu+L8gfqMp/8IM2MQtSiqaCxrrcfu8I8rMA=="
},
"node_modules/cliui": {
"version": "8.0.1",
"resolved": "https://registry.npmjs.org/cliui/-/cliui-8.0.1.tgz",
@ -3599,6 +3738,11 @@
"node": ">= 6"
}
},
"node_modules/glob-to-regexp": {
"version": "0.4.1",
"resolved": "https://registry.npmjs.org/glob-to-regexp/-/glob-to-regexp-0.4.1.tgz",
"integrity": "sha512-lkX1HJXwyMcprw/5YUZc2s7DrpAiHB21/V+E1rHUrVNokkvB6bqMzT0VfV6/86ZNabt1k14YOIaT7nDvOX3Iiw=="
},
"node_modules/global-dirs": {
"version": "0.1.1",
"resolved": "https://registry.npmjs.org/global-dirs/-/global-dirs-0.1.1.tgz",
@ -3649,8 +3793,7 @@
"node_modules/graceful-fs": {
"version": "4.2.11",
"resolved": "https://registry.npmjs.org/graceful-fs/-/graceful-fs-4.2.11.tgz",
"integrity": "sha512-RbJ5/jmFcNNCcDV5o9eTnBLJ/HszWV0P73bc+Ff4nS/rJj+YaS6IGyiOL0VoBYX+l1Wrl3k63h/KrH+nhJ0XvQ==",
"dev": true
"integrity": "sha512-RbJ5/jmFcNNCcDV5o9eTnBLJ/HszWV0P73bc+Ff4nS/rJj+YaS6IGyiOL0VoBYX+l1Wrl3k63h/KrH+nhJ0XvQ=="
},
"node_modules/hard-rejection": {
"version": "2.1.0",
@ -4796,9 +4939,15 @@
}
},
"node_modules/nanoid": {
"version": "3.3.1",
"resolved": "https://registry.npmjs.org/nanoid/-/nanoid-3.3.1.tgz",
"integrity": "sha512-n6Vs/3KGyxPQd6uO0eH4Bv0ojGSUvuLlIHtC3Y0kEO23YRge8H9x1GCzLn28YX0H66pMkxuaeESFq4tKISKwdw==",
"version": "3.3.6",
"resolved": "https://registry.npmjs.org/nanoid/-/nanoid-3.3.6.tgz",
"integrity": "sha512-BGcqMMJuToF7i1rt+2PWSNVnWIkGCU78jBG3RxO/bZlnZPK2Cmi2QaffxGO/2RvWi9sL+FAiRiXMgsyxQ1DIDA==",
"funding": [
{
"type": "github",
"url": "https://github.com/sponsors/ai"
}
],
"bin": {
"nanoid": "bin/nanoid.cjs"
},
@ -4821,47 +4970,43 @@
}
},
"node_modules/next": {
"version": "12.1.0",
"resolved": "https://registry.npmjs.org/next/-/next-12.1.0.tgz",
"integrity": "sha512-s885kWvnIlxsUFHq9UGyIyLiuD0G3BUC/xrH0CEnH5lHEWkwQcHOORgbDF0hbrW9vr/7am4ETfX4A7M6DjrE7Q==",
"dependencies": {
"@next/env": "12.1.0",
"caniuse-lite": "^1.0.30001283",
"postcss": "8.4.5",
"styled-jsx": "5.0.0",
"use-subscription": "1.5.1"
"version": "13.5.4",
"resolved": "https://registry.npmjs.org/next/-/next-13.5.4.tgz",
"integrity": "sha512-+93un5S779gho8y9ASQhb/bTkQF17FNQOtXLKAj3lsNgltEcF0C5PMLLncDmH+8X1EnJH1kbqAERa29nRXqhjA==",
"dependencies": {
"@next/env": "13.5.4",
"@swc/helpers": "0.5.2",
"busboy": "1.6.0",
"caniuse-lite": "^1.0.30001406",
"postcss": "8.4.31",
"styled-jsx": "5.1.1",
"watchpack": "2.4.0"
},
"bin": {
"next": "dist/bin/next"
},
"engines": {
"node": ">=12.22.0"
"node": ">=16.14.0"
},
"optionalDependencies": {
"@next/swc-android-arm64": "12.1.0",
"@next/swc-darwin-arm64": "12.1.0",
"@next/swc-darwin-x64": "12.1.0",
"@next/swc-linux-arm-gnueabihf": "12.1.0",
"@next/swc-linux-arm64-gnu": "12.1.0",
"@next/swc-linux-arm64-musl": "12.1.0",
"@next/swc-linux-x64-gnu": "12.1.0",
"@next/swc-linux-x64-musl": "12.1.0",
"@next/swc-win32-arm64-msvc": "12.1.0",
"@next/swc-win32-ia32-msvc": "12.1.0",
"@next/swc-win32-x64-msvc": "12.1.0"
"@next/swc-darwin-arm64": "13.5.4",
"@next/swc-darwin-x64": "13.5.4",
"@next/swc-linux-arm64-gnu": "13.5.4",
"@next/swc-linux-arm64-musl": "13.5.4",
"@next/swc-linux-x64-gnu": "13.5.4",
"@next/swc-linux-x64-musl": "13.5.4",
"@next/swc-win32-arm64-msvc": "13.5.4",
"@next/swc-win32-ia32-msvc": "13.5.4",
"@next/swc-win32-x64-msvc": "13.5.4"
},
"peerDependencies": {
"fibers": ">= 3.1.0",
"node-sass": "^6.0.0 || ^7.0.0",
"react": "^17.0.2 || ^18.0.0-0",
"react-dom": "^17.0.2 || ^18.0.0-0",
"@opentelemetry/api": "^1.1.0",
"react": "^18.2.0",
"react-dom": "^18.2.0",
"sass": "^1.3.0"
},
"peerDependenciesMeta": {
"fibers": {
"optional": true
},
"node-sass": {
"@opentelemetry/api": {
"optional": true
},
"sass": {
@ -5206,20 +5351,30 @@
}
},
"node_modules/postcss": {
"version": "8.4.5",
"resolved": "https://registry.npmjs.org/postcss/-/postcss-8.4.5.tgz",
"integrity": "sha512-jBDboWM8qpaqwkMwItqTQTiFikhs/67OYVvblFFTM7MrZjt6yMKd6r2kgXizEbTTljacm4NldIlZnhbjr84QYg==",
"version": "8.4.31",
"resolved": "https://registry.npmjs.org/postcss/-/postcss-8.4.31.tgz",
"integrity": "sha512-PS08Iboia9mts/2ygV3eLpY5ghnUcfLV/EXTOW1E2qYxJKGGBUtNjN76FYHnMs36RmARn41bC0AZmn+rR0OVpQ==",
"funding": [
{
"type": "opencollective",
"url": "https://opencollective.com/postcss/"
},
{
"type": "tidelift",
"url": "https://tidelift.com/funding/github/npm/postcss"
},
{
"type": "github",
"url": "https://github.com/sponsors/ai"
}
],
"dependencies": {
"nanoid": "^3.1.30",
"nanoid": "^3.3.6",
"picocolors": "^1.0.0",
"source-map-js": "^1.0.1"
"source-map-js": "^1.0.2"
},
"engines": {
"node": "^10 || ^12 || >=14"
},
"funding": {
"type": "opencollective",
"url": "https://opencollective.com/postcss/"
}
},
"node_modules/prelude-ls": {
@ -5897,6 +6052,14 @@
"integrity": "sha1-BOaSb2YolTVPPdAVIDYzuFcpfiw=",
"dev": true
},
"node_modules/streamsearch": {
"version": "1.1.0",
"resolved": "https://registry.npmjs.org/streamsearch/-/streamsearch-1.1.0.tgz",
"integrity": "sha512-Mcc5wHehp9aXz1ax6bZUyY5afg9u2rv5cqQI3mRrYkGC8rW2hM02jWuwjtL++LS5qinSyhj2QfLyNsuc+VsExg==",
"engines": {
"node": ">=10.0.0"
}
},
"node_modules/string_decoder": {
"version": "1.3.0",
"resolved": "https://registry.npmjs.org/string_decoder/-/string_decoder-1.3.0.tgz",
@ -6058,14 +6221,17 @@
}
},
"node_modules/styled-jsx": {
"version": "5.0.0",
"resolved": "https://registry.npmjs.org/styled-jsx/-/styled-jsx-5.0.0.tgz",
"integrity": "sha512-qUqsWoBquEdERe10EW8vLp3jT25s/ssG1/qX5gZ4wu15OZpmSMFI2v+fWlRhLfykA5rFtlJ1ME8A8pm/peV4WA==",
"version": "5.1.1",
"resolved": "https://registry.npmjs.org/styled-jsx/-/styled-jsx-5.1.1.tgz",
"integrity": "sha512-pW7uC1l4mBZ8ugbiZrcIsiIvVx1UmTfw7UkC3Um2tmfUq9Bhk8IiyEIPl6F8agHgjzku6j0xQEZbfA5uSgSaCw==",
"dependencies": {
"client-only": "0.0.1"
},
"engines": {
"node": ">= 12.0.0"
},
"peerDependencies": {
"react": ">= 16.8.0 || 17.x.x || 18.x.x"
"react": ">= 16.8.0 || 17.x.x || ^18.0.0-0"
},
"peerDependenciesMeta": {
"@babel/core": {
@ -6253,9 +6419,9 @@
}
},
"node_modules/tslib": {
"version": "2.3.1",
"resolved": "https://registry.npmjs.org/tslib/-/tslib-2.3.1.tgz",
"integrity": "sha512-77EbyPPpMz+FRFRuAFlWMtmgUWGe9UOG2Z25NqCwiIjRhOf5iKGuzSe5P2w1laq+FkRy4p+PCuVkJSGkzTEKVw=="
"version": "2.6.2",
"resolved": "https://registry.npmjs.org/tslib/-/tslib-2.6.2.tgz",
"integrity": "sha512-AEYxH93jGFPn/a2iVAwW87VuUIkR1FVUKB77NwMF7nBTDkDrrT/Hpt/IrCJ0QXhW27jTBDcf5ZY7w6RiqTMw2Q=="
},
"node_modules/tsutils": {
"version": "3.21.0",
@ -6348,17 +6514,6 @@
"punycode": "^2.1.0"
}
},
"node_modules/use-subscription": {
"version": "1.5.1",
"resolved": "https://registry.npmjs.org/use-subscription/-/use-subscription-1.5.1.tgz",
"integrity": "sha512-Xv2a1P/yReAjAbhylMfFplFKj9GssgTwN7RlcTxBujFQcloStWNDQdc4g4NRWH9xS4i/FDk04vQBptAXoF3VcA==",
"dependencies": {
"object-assign": "^4.1.1"
},
"peerDependencies": {
"react": "^16.8.0 || ^17.0.0"
}
},
"node_modules/util-deprecate": {
"version": "1.0.2",
"resolved": "https://registry.npmjs.org/util-deprecate/-/util-deprecate-1.0.2.tgz",
@ -6388,6 +6543,18 @@
"spdx-expression-parse": "^3.0.0"
}
},
"node_modules/watchpack": {
"version": "2.4.0",
"resolved": "https://registry.npmjs.org/watchpack/-/watchpack-2.4.0.tgz",
"integrity": "sha512-Lcvm7MGST/4fup+ifyKi2hjyIAwcdI4HRgtvTpIUxBRhB+RFtUh8XtDOxUfctVCnhVi+QQj49i91OyvzkJl6cg==",
"dependencies": {
"glob-to-regexp": "^0.4.1",
"graceful-fs": "^4.1.2"
},
"engines": {
"node": ">=10.13.0"
}
},
"node_modules/which": {
"version": "2.0.2",
"resolved": "https://registry.npmjs.org/which/-/which-2.0.2.tgz",
@ -7527,9 +7694,9 @@
}
},
"@next/env": {
"version": "12.1.0",
"resolved": "https://registry.npmjs.org/@next/env/-/env-12.1.0.tgz",
"integrity": "sha512-nrIgY6t17FQ9xxwH3jj0a6EOiQ/WDHUos35Hghtr+SWN/ntHIQ7UpuvSi0vaLzZVHQWaDupKI+liO5vANcDeTQ=="
"version": "13.5.4",
"resolved": "https://registry.npmjs.org/@next/env/-/env-13.5.4.tgz",
"integrity": "sha512-LGegJkMvRNw90WWphGJ3RMHMVplYcOfRWf2Be3td3sUa+1AaxmsYyANsA+znrGCBjXJNi4XAQlSoEfUxs/4kIQ=="
},
"@next/eslint-plugin-next": {
"version": "11.1.4",
@ -7540,16 +7707,58 @@
"glob": "7.1.7"
}
},
"@next/swc-darwin-arm64": {
"version": "13.5.4",
"resolved": "https://registry.npmjs.org/@next/swc-darwin-arm64/-/swc-darwin-arm64-13.5.4.tgz",
"integrity": "sha512-Df8SHuXgF1p+aonBMcDPEsaahNo2TCwuie7VXED4FVyECvdXfRT9unapm54NssV9tF3OQFKBFOdlje4T43VO0w==",
"optional": true
},
"@next/swc-darwin-x64": {
"version": "13.5.4",
"resolved": "https://registry.npmjs.org/@next/swc-darwin-x64/-/swc-darwin-x64-13.5.4.tgz",
"integrity": "sha512-siPuUwO45PnNRMeZnSa8n/Lye5ZX93IJom9wQRB5DEOdFrw0JjOMu1GINB8jAEdwa7Vdyn1oJ2xGNaQpdQQ9Pw==",
"optional": true
},
"@next/swc-linux-arm64-gnu": {
"version": "13.5.4",
"resolved": "https://registry.npmjs.org/@next/swc-linux-arm64-gnu/-/swc-linux-arm64-gnu-13.5.4.tgz",
"integrity": "sha512-l/k/fvRP/zmB2jkFMfefmFkyZbDkYW0mRM/LB+tH5u9pB98WsHXC0WvDHlGCYp3CH/jlkJPL7gN8nkTQVrQ/2w==",
"optional": true
},
"@next/swc-linux-arm64-musl": {
"version": "13.5.4",
"resolved": "https://registry.npmjs.org/@next/swc-linux-arm64-musl/-/swc-linux-arm64-musl-13.5.4.tgz",
"integrity": "sha512-YYGb7SlLkI+XqfQa8VPErljb7k9nUnhhRrVaOdfJNCaQnHBcvbT7cx/UjDQLdleJcfyg1Hkn5YSSIeVfjgmkTg==",
"optional": true
},
"@next/swc-linux-x64-gnu": {
"version": "12.1.0",
"resolved": "https://registry.npmjs.org/@next/swc-linux-x64-gnu/-/swc-linux-x64-gnu-12.1.0.tgz",
"integrity": "sha512-OKO4R/digvrVuweSw/uBM4nSdyzsBV5EwkUeeG4KVpkIZEe64ZwRpnFB65bC6hGwxIBnTv5NMSnJ+0K/WmG78A==",
"version": "13.5.4",
"resolved": "https://registry.npmjs.org/@next/swc-linux-x64-gnu/-/swc-linux-x64-gnu-13.5.4.tgz",
"integrity": "sha512-uE61vyUSClnCH18YHjA8tE1prr/PBFlBFhxBZis4XBRJoR+txAky5d7gGNUIbQ8sZZ7LVkSVgm/5Fc7mwXmRAg==",
"optional": true
},
"@next/swc-linux-x64-musl": {
"version": "12.1.0",
"resolved": "https://registry.npmjs.org/@next/swc-linux-x64-musl/-/swc-linux-x64-musl-12.1.0.tgz",
"integrity": "sha512-JohhgAHZvOD3rQY7tlp7NlmvtvYHBYgY0x5ZCecUT6eCCcl9lv6iV3nfu82ErkxNk1H893fqH0FUpznZ/H3pSw==",
"version": "13.5.4",
"resolved": "https://registry.npmjs.org/@next/swc-linux-x64-musl/-/swc-linux-x64-musl-13.5.4.tgz",
"integrity": "sha512-qVEKFYML/GvJSy9CfYqAdUexA6M5AklYcQCW+8JECmkQHGoPxCf04iMh7CPR7wkHyWWK+XLt4Ja7hhsPJtSnhg==",
"optional": true
},
"@next/swc-win32-arm64-msvc": {
"version": "13.5.4",
"resolved": "https://registry.npmjs.org/@next/swc-win32-arm64-msvc/-/swc-win32-arm64-msvc-13.5.4.tgz",
"integrity": "sha512-mDSQfqxAlfpeZOLPxLymZkX0hYF3juN57W6vFHTvwKlnHfmh12Pt7hPIRLYIShk8uYRsKPtMTth/EzpwRI+u8w==",
"optional": true
},
"@next/swc-win32-ia32-msvc": {
"version": "13.5.4",
"resolved": "https://registry.npmjs.org/@next/swc-win32-ia32-msvc/-/swc-win32-ia32-msvc-13.5.4.tgz",
"integrity": "sha512-aoqAT2XIekIWoriwzOmGFAvTtVY5O7JjV21giozBTP5c6uZhpvTWRbmHXbmsjZqY4HnEZQRXWkSAppsIBweKqw==",
"optional": true
},
"@next/swc-win32-x64-msvc": {
"version": "13.5.4",
"resolved": "https://registry.npmjs.org/@next/swc-win32-x64-msvc/-/swc-win32-x64-msvc-13.5.4.tgz",
"integrity": "sha512-cyRvlAxwlddlqeB9xtPSfNSCRy8BOa4wtMo0IuI9P7Y0XT2qpDrpFKRyZ7kUngZis59mPVla5k8X1oOJ8RxDYg==",
"optional": true
},
"@nodelib/fs.scandir": {
@ -7594,6 +7803,14 @@
"integrity": "sha512-JLo+Y592QzIE+q7Dl2pMUtt4q8SKYI5jDrZxrozEQxnGVOyYE+GWK9eLkwTaeN9DDctlaRAQ3TBmzZ1qdLE30A==",
"dev": true
},
"@swc/helpers": {
"version": "0.5.2",
"resolved": "https://registry.npmjs.org/@swc/helpers/-/helpers-0.5.2.tgz",
"integrity": "sha512-E4KcWTpoLHqwPHLxidpOqQbcrZVgi0rsmmZXUle1jXmJfuIf/UWpczUJ7MZZ5tlxytgJXyp0w4PGkkeLiuIdZw==",
"requires": {
"tslib": "^2.4.0"
}
},
"@types/json-schema": {
"version": "7.0.9",
"resolved": "https://registry.npmjs.org/@types/json-schema/-/json-schema-7.0.9.tgz",
@ -8034,6 +8251,14 @@
"resolved": "https://registry.npmjs.org/buffer-from/-/buffer-from-0.1.2.tgz",
"integrity": "sha512-RiWIenusJsmI2KcvqQABB83tLxCByE3upSP8QU3rJDMVFGPWLvPQJt/O1Su9moRWeH7d+Q2HYb68f6+v+tw2vg=="
},
"busboy": {
"version": "1.6.0",
"resolved": "https://registry.npmjs.org/busboy/-/busboy-1.6.0.tgz",
"integrity": "sha512-8SFQbg/0hQ9xy3UNTB0YEnsNBbWfhf7RtnzpL7TkBiTBRfrQ9Fxcnz7VJsleJpyp6rVLvXiuORqjlHi5q+PYuA==",
"requires": {
"streamsearch": "^1.1.0"
}
},
"call-bind": {
"version": "1.0.2",
"resolved": "https://registry.npmjs.org/call-bind/-/call-bind-1.0.2.tgz",
@ -8067,9 +8292,9 @@
}
},
"caniuse-lite": {
"version": "1.0.30001312",
"resolved": "https://registry.npmjs.org/caniuse-lite/-/caniuse-lite-1.0.30001312.tgz",
"integrity": "sha512-Wiz1Psk2MEK0pX3rUzWaunLTZzqS2JYZFzNKqAiJGiuxIjRPLgV6+VDPOg6lQOUxmDwhTlh198JsTTi8Hzw6aQ=="
"version": "1.0.30001546",
"resolved": "https://registry.npmjs.org/caniuse-lite/-/caniuse-lite-1.0.30001546.tgz",
"integrity": "sha512-zvtSJwuQFpewSyRrI3AsftF6rM0X80mZkChIt1spBGEvRglCrjTniXvinc8JKRoqTwXAgvqTImaN9igfSMtUBw=="
},
"chalk": {
"version": "4.1.2",
@ -8106,6 +8331,11 @@
"string-width": "^4.2.0"
}
},
"client-only": {
"version": "0.0.1",
"resolved": "https://registry.npmjs.org/client-only/-/client-only-0.0.1.tgz",
"integrity": "sha512-IV3Ou0jSMzZrd3pZ48nLkT9DA7Ag1pnPzaiQhpW7c3RbcqqzvzzVu+L8gfqMp/8IM2MQtSiqaCxrrcfu8I8rMA=="
},
"cliui": {
"version": "8.0.1",
"resolved": "https://registry.npmjs.org/cliui/-/cliui-8.0.1.tgz",
@ -9142,6 +9372,11 @@
"is-glob": "^4.0.1"
}
},
"glob-to-regexp": {
"version": "0.4.1",
"resolved": "https://registry.npmjs.org/glob-to-regexp/-/glob-to-regexp-0.4.1.tgz",
"integrity": "sha512-lkX1HJXwyMcprw/5YUZc2s7DrpAiHB21/V+E1rHUrVNokkvB6bqMzT0VfV6/86ZNabt1k14YOIaT7nDvOX3Iiw=="
},
"global-dirs": {
"version": "0.1.1",
"resolved": "https://registry.npmjs.org/global-dirs/-/global-dirs-0.1.1.tgz",
@ -9177,8 +9412,7 @@
"graceful-fs": {
"version": "4.2.11",
"resolved": "https://registry.npmjs.org/graceful-fs/-/graceful-fs-4.2.11.tgz",
"integrity": "sha512-RbJ5/jmFcNNCcDV5o9eTnBLJ/HszWV0P73bc+Ff4nS/rJj+YaS6IGyiOL0VoBYX+l1Wrl3k63h/KrH+nhJ0XvQ==",
"dev": true
"integrity": "sha512-RbJ5/jmFcNNCcDV5o9eTnBLJ/HszWV0P73bc+Ff4nS/rJj+YaS6IGyiOL0VoBYX+l1Wrl3k63h/KrH+nhJ0XvQ=="
},
"hard-rejection": {
"version": "2.1.0",
@ -10065,9 +10299,9 @@
}
},
"nanoid": {
"version": "3.3.1",
"resolved": "https://registry.npmjs.org/nanoid/-/nanoid-3.3.1.tgz",
"integrity": "sha512-n6Vs/3KGyxPQd6uO0eH4Bv0ojGSUvuLlIHtC3Y0kEO23YRge8H9x1GCzLn28YX0H66pMkxuaeESFq4tKISKwdw=="
"version": "3.3.6",
"resolved": "https://registry.npmjs.org/nanoid/-/nanoid-3.3.6.tgz",
"integrity": "sha512-BGcqMMJuToF7i1rt+2PWSNVnWIkGCU78jBG3RxO/bZlnZPK2Cmi2QaffxGO/2RvWi9sL+FAiRiXMgsyxQ1DIDA=="
},
"natural-compare": {
"version": "1.4.0",
@ -10081,26 +10315,26 @@
"integrity": "sha512-dBpDMdxv9Irdq66304OLfEmQ9tbNRFnFTuZiLo+bD+r332bBmMJ8GBLXklIXXgxd3+v9+KUnZaUR5PJMa75Gsg=="
},
"next": {
"version": "12.1.0",
"resolved": "https://registry.npmjs.org/next/-/next-12.1.0.tgz",
"integrity": "sha512-s885kWvnIlxsUFHq9UGyIyLiuD0G3BUC/xrH0CEnH5lHEWkwQcHOORgbDF0hbrW9vr/7am4ETfX4A7M6DjrE7Q==",
"requires": {
"@next/env": "12.1.0",
"@next/swc-android-arm64": "12.1.0",
"@next/swc-darwin-arm64": "12.1.0",
"@next/swc-darwin-x64": "12.1.0",
"@next/swc-linux-arm-gnueabihf": "12.1.0",
"@next/swc-linux-arm64-gnu": "12.1.0",
"@next/swc-linux-arm64-musl": "12.1.0",
"@next/swc-linux-x64-gnu": "12.1.0",
"@next/swc-linux-x64-musl": "12.1.0",
"@next/swc-win32-arm64-msvc": "12.1.0",
"@next/swc-win32-ia32-msvc": "12.1.0",
"@next/swc-win32-x64-msvc": "12.1.0",
"caniuse-lite": "^1.0.30001283",
"postcss": "8.4.5",
"styled-jsx": "5.0.0",
"use-subscription": "1.5.1"
"version": "13.5.4",
"resolved": "https://registry.npmjs.org/next/-/next-13.5.4.tgz",
"integrity": "sha512-+93un5S779gho8y9ASQhb/bTkQF17FNQOtXLKAj3lsNgltEcF0C5PMLLncDmH+8X1EnJH1kbqAERa29nRXqhjA==",
"requires": {
"@next/env": "13.5.4",
"@next/swc-darwin-arm64": "13.5.4",
"@next/swc-darwin-x64": "13.5.4",
"@next/swc-linux-arm64-gnu": "13.5.4",
"@next/swc-linux-arm64-musl": "13.5.4",
"@next/swc-linux-x64-gnu": "13.5.4",
"@next/swc-linux-x64-musl": "13.5.4",
"@next/swc-win32-arm64-msvc": "13.5.4",
"@next/swc-win32-ia32-msvc": "13.5.4",
"@next/swc-win32-x64-msvc": "13.5.4",
"@swc/helpers": "0.5.2",
"busboy": "1.6.0",
"caniuse-lite": "^1.0.30001406",
"postcss": "8.4.31",
"styled-jsx": "5.1.1",
"watchpack": "2.4.0"
}
},
"node-releases": {
@ -10341,13 +10575,13 @@
}
},
"postcss": {
"version": "8.4.5",
"resolved": "https://registry.npmjs.org/postcss/-/postcss-8.4.5.tgz",
"integrity": "sha512-jBDboWM8qpaqwkMwItqTQTiFikhs/67OYVvblFFTM7MrZjt6yMKd6r2kgXizEbTTljacm4NldIlZnhbjr84QYg==",
"version": "8.4.31",
"resolved": "https://registry.npmjs.org/postcss/-/postcss-8.4.31.tgz",
"integrity": "sha512-PS08Iboia9mts/2ygV3eLpY5ghnUcfLV/EXTOW1E2qYxJKGGBUtNjN76FYHnMs36RmARn41bC0AZmn+rR0OVpQ==",
"requires": {
"nanoid": "^3.1.30",
"nanoid": "^3.3.6",
"picocolors": "^1.0.0",
"source-map-js": "^1.0.1"
"source-map-js": "^1.0.2"
}
},
"prelude-ls": {
@ -10839,6 +11073,11 @@
"integrity": "sha1-BOaSb2YolTVPPdAVIDYzuFcpfiw=",
"dev": true
},
"streamsearch": {
"version": "1.1.0",
"resolved": "https://registry.npmjs.org/streamsearch/-/streamsearch-1.1.0.tgz",
"integrity": "sha512-Mcc5wHehp9aXz1ax6bZUyY5afg9u2rv5cqQI3mRrYkGC8rW2hM02jWuwjtL++LS5qinSyhj2QfLyNsuc+VsExg=="
},
"string_decoder": {
"version": "1.3.0",
"resolved": "https://registry.npmjs.org/string_decoder/-/string_decoder-1.3.0.tgz",
@ -10965,10 +11204,12 @@
"dev": true
},
"styled-jsx": {
"version": "5.0.0",
"resolved": "https://registry.npmjs.org/styled-jsx/-/styled-jsx-5.0.0.tgz",
"integrity": "sha512-qUqsWoBquEdERe10EW8vLp3jT25s/ssG1/qX5gZ4wu15OZpmSMFI2v+fWlRhLfykA5rFtlJ1ME8A8pm/peV4WA==",
"requires": {}
"version": "5.1.1",
"resolved": "https://registry.npmjs.org/styled-jsx/-/styled-jsx-5.1.1.tgz",
"integrity": "sha512-pW7uC1l4mBZ8ugbiZrcIsiIvVx1UmTfw7UkC3Um2tmfUq9Bhk8IiyEIPl6F8agHgjzku6j0xQEZbfA5uSgSaCw==",
"requires": {
"client-only": "0.0.1"
}
},
"stylis": {
"version": "4.0.13",
@ -11113,9 +11354,9 @@
}
},
"tslib": {
"version": "2.3.1",
"resolved": "https://registry.npmjs.org/tslib/-/tslib-2.3.1.tgz",
"integrity": "sha512-77EbyPPpMz+FRFRuAFlWMtmgUWGe9UOG2Z25NqCwiIjRhOf5iKGuzSe5P2w1laq+FkRy4p+PCuVkJSGkzTEKVw=="
"version": "2.6.2",
"resolved": "https://registry.npmjs.org/tslib/-/tslib-2.6.2.tgz",
"integrity": "sha512-AEYxH93jGFPn/a2iVAwW87VuUIkR1FVUKB77NwMF7nBTDkDrrT/Hpt/IrCJ0QXhW27jTBDcf5ZY7w6RiqTMw2Q=="
},
"tsutils": {
"version": "3.21.0",
@ -11182,14 +11423,6 @@
"punycode": "^2.1.0"
}
},
"use-subscription": {
"version": "1.5.1",
"resolved": "https://registry.npmjs.org/use-subscription/-/use-subscription-1.5.1.tgz",
"integrity": "sha512-Xv2a1P/yReAjAbhylMfFplFKj9GssgTwN7RlcTxBujFQcloStWNDQdc4g4NRWH9xS4i/FDk04vQBptAXoF3VcA==",
"requires": {
"object-assign": "^4.1.1"
}
},
"util-deprecate": {
"version": "1.0.2",
"resolved": "https://registry.npmjs.org/util-deprecate/-/util-deprecate-1.0.2.tgz",
@ -11216,6 +11449,15 @@
"spdx-expression-parse": "^3.0.0"
}
},
"watchpack": {
"version": "2.4.0",
"resolved": "https://registry.npmjs.org/watchpack/-/watchpack-2.4.0.tgz",
"integrity": "sha512-Lcvm7MGST/4fup+ifyKi2hjyIAwcdI4HRgtvTpIUxBRhB+RFtUh8XtDOxUfctVCnhVi+QQj49i91OyvzkJl6cg==",
"requires": {
"glob-to-regexp": "^0.4.1",
"graceful-fs": "^4.1.2"
}
},
"which": {
"version": "2.0.2",
"resolved": "https://registry.npmjs.org/which/-/which-2.0.2.tgz",

@ -30,7 +30,7 @@
"formik": "^2.4.3",
"lodash": "^4.17.21",
"netmask": "^2.0.2",
"next": "^12.1.0",
"next": "^13.5.4",
"pretty-bytes": "^5.6.0",
"react": "17.0.2",
"react-dom": "17.0.2",

@ -68,6 +68,7 @@ dist_sbin_SCRIPTS = \
striker-purge-target \
striker-scan-network \
striker-show-db-counts \
striker-show-jobs \
striker-update-cluster
fencedir = ${FASEXECPREFIX}/sbin

@ -74,7 +74,7 @@ $anvil->System->wait_on_dnf();
# is to setup the database server.
$anvil->Database->connect({
check_if_configured => 1,
check_for_resync => 1,
check_for_resync => 2,
});
$anvil->Log->entry({source => $THIS_FILE, line => __LINE__, level => 1, key => "log_0132"});
@ -89,7 +89,7 @@ if (not $anvil->data->{sys}{database}{connections})
prep_database($anvil);
# Try connecting again
$anvil->Database->connect({check_if_configured => 1, check_for_resync => 1});
$anvil->Database->connect({check_if_configured => 1, check_for_resync => 2});
$anvil->Log->entry({source => $THIS_FILE, line => __LINE__, level => 1, key => "log_0132"});
if (not $anvil->data->{sys}{database}{connections})
{
@ -109,7 +109,7 @@ if (not $anvil->data->{sys}{database}{connections})
check_network($anvil);
$anvil->refresh();
$anvil->Database->connect({check_if_configured => 1, check_for_resync => 1});
$anvil->Database->connect({check_if_configured => 1, check_for_resync => 2});
$anvil->Log->entry({source => $THIS_FILE, line => __LINE__, level => 3, key => "log_0132"});
if (not $anvil->data->{sys}{database}{connections})
{
@ -203,7 +203,7 @@ while(1)
# If, so some reason, anvil.conf is lost, create it.
$anvil->System->_check_anvil_conf();
$anvil->Database->connect({check_if_configured => $check_if_database_is_configured, check_for_resync => 1});
$anvil->Database->connect({check_if_configured => $check_if_database_is_configured, check_for_resync => 2});
$anvil->Log->entry({source => $THIS_FILE, line => __LINE__, level => 3, key => "log_0132"});
# Mark that we don't want to check the database now.

@ -774,58 +774,66 @@ sub save_job
my $server_name = $anvil->data->{switches}{server_name};
my $server_uuid = $anvil->data->{switches}{server_uuid};
my $delete_uuid = $server_uuid;
push @{$hosts}, $anvil->data->{anvils}{anvil_uuid}{$anvil_uuid}{anvil_node1_host_uuid};
push @{$hosts}, $anvil->data->{anvils}{anvil_uuid}{$anvil_uuid}{anvil_node2_host_uuid};
if ($anvil->data->{anvils}{anvil_uuid}{$anvil_uuid}{anvil_dr1_host_uuid})
{
push @{$hosts}, $anvil->data->{anvils}{anvil_uuid}{$anvil_uuid}{anvil_dr1_host_uuid};
}
my $server_host = "";
foreach my $host_uuid (@{$hosts})
{
if ($host_uuid eq $anvil->Get->host_uuid)
$anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => {
anvil_uuid => $anvil_uuid,
server_name => $server_name,
server_uuid => $server_uuid,
delete_uuid => $delete_uuid,
}});
if ((not $server_name) && (exists $anvil->data->{servers}{server_uuid}{$server_uuid}) && ($anvil->data->{servers}{server_uuid}{$server_uuid}{server_name}))
{
# This is us.
$anvil->Server->find({refresh => 0});
$server_name = $anvil->data->{servers}{server_uuid}{$server_uuid}{server_name};
$anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { server_name => $server_name }});
}
else
{
# This is another machine.
my $target_ip = $anvil->Network->find_target_ip({host_uuid => $host_uuid});
$anvil->Server->find({
refresh => 0,
target => $target_ip,
password => $password,
# Find the server on hosts.
my $server_host_name = $anvil->Server->locate({
debug => 2,
server_name => $server_name,
});
}
}
$anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { server_host_name => $server_host_name }});
my $host_name = "";
my $host_uuid = "";
if (exists $anvil->data->{server}{location}{$server_name})
foreach my $short_host_name (sort {$a cmp $b} keys %{$anvil->data->{server_location}{host}})
{
my $status = $anvil->data->{server}{location}{$server_name}{status};
$host_name = $anvil->data->{server}{location}{$server_name}{host_name};
my $host_uuid = $anvil->Database->get_host_uuid_from_string({string => $short_host_name});
$anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => {
status => $status,
host_name => $host_name,
short_host_name => $short_host_name,
host_uuid => $host_uuid,
}});
if ($status eq "running")
my $exists = 0;
if (($anvil->data->{server_location}{host}{$short_host_name}{server}{$server_name}{file_definition}) or ($anvil->data->{server_location}{host}{$short_host_name}{server}{$server_name}{drbd_config}))
{
$host_uuid = $anvil->Get->host_uuid_from_name({host_name => $host_name});
$exists = 1;
}
$anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { 'exists' => $exists }});
if (($exists) or
($host_uuid eq $anvil->data->{anvils}{anvil_uuid}{$anvil_uuid}{anvil_node1_host_uuid}) or
($host_uuid eq $anvil->data->{anvils}{anvil_uuid}{$anvil_uuid}{anvil_node2_host_uuid}))
{
push @{$hosts}, $host_uuid;
$anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { host_uuid => $host_uuid }});
}
}
# If the server was found to be running, the host will be returned.
my $server_host_uuid = "";
if ($server_host_name)
{
$server_host_uuid = $anvil->Get->host_uuid_from_name({host_name => $server_host_name});
}
# Now, we'll do the delete, unless we see the server running elsewhere.
$anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { host_uuid => $host_uuid }});
$anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { server_host_uuid => $server_host_uuid }});
my $job_host_uuid = "";
if ($host_uuid)
if ($server_host_uuid)
{
$job_host_uuid = $host_uuid;
$job_host_uuid = $server_host_uuid;
$anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { job_host_uuid => $job_host_uuid }});
if ($host_uuid eq $anvil->Get->host_uuid)
if ($server_host_uuid eq $anvil->Get->host_uuid)
{
# Running here
print $anvil->Words->string({key => "message_0216"})."\n";
@ -833,7 +841,7 @@ sub save_job
else
{
# Running on a peer.
print $anvil->Words->string({key => "message_0214", variables => { host_name => $host_name }})."\n";
print $anvil->Words->string({key => "message_0214", variables => { host_name => $server_host_name }})."\n";
}
}
else

@ -298,6 +298,9 @@ sub configure_pacemaker
my $both_online = 0;
until($both_online)
{
$anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => {
'path::configs::corosync.conf' => $anvil->data->{path}{configs}{'corosync.conf'},
}});
if (-e $anvil->data->{path}{configs}{'corosync.conf'})
{
if (not $start_time)
@ -362,7 +365,12 @@ sub configure_pacemaker
# corosync.conf doesn't exist yet.
$anvil->Log->entry({source => $THIS_FILE, line => __LINE__, 'print' => 1, level => 1, key => "job_0107"});
}
sleep 5 if not $both_online;
if (not $both_online)
{
my $delay = 5;
$anvil->Log->entry({source => $THIS_FILE, line => __LINE__, level => 1, key => "log_0816", variables => { delay => $delay }});
sleep $delay;
}
}
}
else

@ -175,6 +175,9 @@ sub find_missing_files
# What am I? This will impact how missing files are found.
$anvil->Database->get_anvils();
my $host_uuid = $anvil->Get->host_uuid();
$anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { host_uuid => $host_uuid }});
my $query = "
SELECT
file_uuid,
@ -237,16 +240,7 @@ ORDER BY
else
{
# Check to see if we're supposed to have this file.
$anvil->Database->get_file_locations();
my $anvil_uuid = $anvil->Cluster->get_anvil_uuid();
$anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { anvil_uuid => $anvil_uuid }});
# Nothing to do if we're not in an Anvil! yet.
next if not $anvil_uuid;
# Do we have a file_location_uuid? If not, there will be soon but nothing to do until
# then.
my $file_location_uuid = $anvil->data->{anvils}{anvil_uuid}{$anvil_uuid}{file_uuid}{$file_uuid}{file_location_uuid};
my $file_location_uuid = $anvil->data->{file_locations}{host_uuid}{$host_uuid}{file_uuid}{$file_uuid}{file_location_uuid};
$anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { file_location_uuid => $file_location_uuid }});
next if not $file_location_uuid;

@ -28,15 +28,18 @@ $anvil->Get->switches({list => [
"age-out-database",
"check-configured",
"check-database",
"check-network-mapping",
"database-active",
"database-inactive",
"disable-network-mapping",
"enable-network-mapping",
"mark-configured",
"mark-unconfigured",
"resync-database"], 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({all => 1});
$anvil->Database->connect();
$anvil->Log->entry({source => $THIS_FILE, line => __LINE__, level => 2, secure => 0, key => "log_0132"});
if (not $anvil->data->{sys}{database}{connections})
{
@ -53,6 +56,10 @@ elsif (($anvil->data->{switches}{'database-active'}) or ($anvil->data->{switches
{
update_database($anvil);
}
elsif (($anvil->data->{switches}{'enable-network-mapping'}) or ($anvil->data->{switches}{'disable-network-mapping'}) or ($anvil->data->{switches}{'check-network-mapping'}))
{
update_network_mapping($anvil);
}
elsif ($anvil->data->{switches}{'age-out-database'})
{
age_out_data($anvil);
@ -156,7 +163,6 @@ sub update_database
variable_name => $variable_name,
}});
# Read if it's active or inactive yet.
my ($active_value, undef, undef) = $anvil->Database->read_variable({variable_name => "database::".$host_uuid."::active"});
$anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { active_value => $active_value }});
@ -224,6 +230,114 @@ sub update_database
return(0);
}
sub update_network_mapping
{
my ($anvil) = @_;
my $variable_name = "config::map_network";
my ($map_network_value, $map_network_uuid, $map_network_mtime, $map_network_modified_date) = $anvil->Database->read_variable({
variable_name => $variable_name,
variable_source_table => "hosts",
variable_source_uuid => $anvil->data->{sys}{host_uuid},
});
$anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => {
's1:variable_name' => $variable_name,
's2:map_network_value' => $map_network_value,
's3:map_network_mtime' => $map_network_mtime,
's4:map_network_modified_date' => $map_network_modified_date,
's5:map_network_uuid' => $map_network_uuid,
}});
if ($anvil->data->{switches}{'check-configured'})
{
# We'll run for a day (should be cancelled by the program when the user's done, so this
# shouldn't fire in practice).
my $expire_age = 86400;
my $map_network_age = 0;
if ($map_network_uuid)
{
$map_network_age = time - $map_network_mtime;
$anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 3, list => { map_network_age => $map_network_age }});
}
if ($map_network_value)
{
# How long ago was it set?
$anvil->data->{switches}{'clear-mapping'} = "" if not defined $anvil->data->{switches}{'clear-mapping'};
if (($map_network_age >= $expire_age) or ($anvil->data->{switches}{'clear-mapping'}))
{
# Clear it.
$anvil->Log->entry({source => $THIS_FILE, line => __LINE__, 'print' => 1, level => 1, key => "log_0470"});
$anvil->Database->insert_or_update_variables({
debug => 3,
variable_value => 0,
variable_uuid => $map_network_uuid,
update_value_only => 1,
});
}
else
{
# Mark it so we only track the network.
my $say_age = $anvil->Convert->add_commas({number => $expire_age});
my $timeout = $anvil->Convert->add_commas({number => ($expire_age - $map_network_age)});
$anvil->Log->entry({source => $THIS_FILE, line => __LINE__, level => 1, key => "log_0471", variables => {
age => $say_age,
timeout => $timeout,
}});
}
}
return(0);
}
if ($anvil->data->{switches}{'enable-network-mapping'})
{
if ($map_network_value)
{
# Nothing to do.
$anvil->Log->entry({source => $THIS_FILE, line => __LINE__, 'print' => 1, level => 1, key => "message_0353"});
}
else
{
# Enable network configuring.
my $variable_uuid = $anvil->Database->insert_or_update_variables({
variable_name => $variable_name,
variable_value => 1,
variable_default => "",
variable_description => "striker_0202",
variable_section => "config",
variable_source_uuid => $anvil->Get->host_uuid,
variable_source_table => "hosts",
});
$anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { variable_uuid => $variable_uuid }});
$anvil->Log->entry({source => $THIS_FILE, line => __LINE__, 'print' => 1, level => 1, key => "message_0354"});
}
}
if ($anvil->data->{switches}{'disable-network-mapping'})
{
if ($map_network_value)
{
# Disable network configuring.
my $variable_uuid = $anvil->Database->insert_or_update_variables({
variable_name => $variable_name,
variable_value => 0,
variable_default => "",
variable_description => "striker_0202",
variable_section => "config",
variable_source_uuid => $anvil->Get->host_uuid,
variable_source_table => "hosts",
});
$anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { variable_uuid => $variable_uuid }});
$anvil->Log->entry({source => $THIS_FILE, line => __LINE__, 'print' => 1, level => 1, key => "message_0356"});
}
else
{
# Nothing to do.
$anvil->Log->entry({source => $THIS_FILE, line => __LINE__, 'print' => 1, level => 1, key => "message_0355"});
}
}
return(0);
}
sub update_config
{
my ($anvil) = @_;
@ -292,6 +406,5 @@ sub update_config
}
}
return(0);
}

@ -41,7 +41,7 @@ $anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list
'switches::job-uuid' => $anvil->data->{switches}{'job-uuid'},
}});
$anvil->Database->connect({check_for_resync => 1});
$anvil->Database->connect();
$anvil->Log->entry({source => $THIS_FILE, line => __LINE__, level => 2, secure => 0, key => "log_0132"});
if (not $anvil->data->{sys}{database}{connections})
{

@ -8,6 +8,7 @@
# 1 = No database connection.
#
# TODO:
# - Update the target_ip search to use the new Network->find_target_ip().
#
# USAGE:
# - Show

@ -0,0 +1,688 @@
#!/usr/bin/perl
#
# This program will manage servers; Changing RAM, CPU cores, Growing virtual disks, adding virtual disks,
# inserting and ejecting ISO images into virtual optical media.
#
# Exit codes;
# 0 = Normal exit.
# 1 = No database connection.
#
# TODO:
#
# USAGE:
# - Show
# - anvil-manage-server-storage --server srv01-fs37
#
use strict;
use warnings;
use Anvil::Tools;
require POSIX;
use Term::Cap;
use Text::Diff;
use Data::Dumper;
use Sys::Virt;
my $THIS_FILE = ($0 =~ /^.*\/(.*)$/)[0];
my $running_directory = ($0 =~ /^(.*?)\/$THIS_FILE$/)[0];
if (($running_directory =~ /^\./) && ($ENV{PWD}))
{
$running_directory =~ s/^\./$ENV{PWD}/;
}
# Turn off buffering so that the pinwheel will display while waiting for the SSH call(s) to complete.
$| = 1;
my $anvil = Anvil::Tools->new();
# Read switches (target ([user@]host[:port]) and the file with the target's password.
$anvil->Get->switches({list => [
"add",
"anvil",
"boot",
"boot-menu",
"confirm",
"disk",
"eject",
"job-uuid",
"grow",
"insert",
"optical",
"server",
"storage-group",
], 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 }});
# Connect to the database(s). If we have no connections, we'll proceed anyway as one of the 'run_once' tasks
# is to setup the database server.
$anvil->Database->connect();
$anvil->Log->entry({source => $THIS_FILE, line => __LINE__, level => 3, secure => 0, key => "log_0132"});
if (not $anvil->data->{sys}{database}{connections})
{
# No databases, update the job, sleep for a bit and then exit. The daemon will pick it up and try
# again after we exit.
$anvil->Log->entry({source => $THIS_FILE, line => __LINE__, 'print' => 1, level => 0, priority => "err", key => "error_0305"});
sleep 10;
$anvil->nice_exit({exit_code => 1});
}
if ($anvil->data->{switches}{'job-uuid'})
{
load_job($anvil);
}
$anvil->Database->get_hosts();
$anvil->Database->get_anvils();
$anvil->Database->get_servers();
if ($anvil->data->{switches}{anvil})
{
# Make sure they asked for a real anvil.
$anvil->Get->anvil_from_switch({string => $anvil->data->{switches}{anvil}});
$anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => {
"switches::anvil_name" => $anvil->data->{switches}{anvil_name},
"switches::anvil_uuid" => $anvil->data->{switches}{anvil_uuid},
}});
}
if (not $anvil->data->{switches}{server})
{
# Show the list of servers.
show_server_list($anvil);
$anvil->Log->entry({source => $THIS_FILE, line => __LINE__, 'print' => 1, level => 0, priority => "err", key => "error_0456"});
$anvil->Job->update_progress({
progress => 100,
message => "error_0456",
}) if $anvil->data->{switches}{'job-uuid'};
$anvil->nice_exit({exit_code => 0});
}
validate_server($anvil);
if ($anvil->data->{switches}{cpu})
{
#manage_cpu($anvil);
}
elsif ($anvil->data->{switches}{ram})
{
#manage_ram($anvil);
}
elsif ($anvil->data->{switches}{boot})
{
#manage_boot($anvil);
}
elsif ($anvil->data->{switches}{'boot-menu'})
{
manage_boot_menu($anvil);
}
else
{
show_server_details($anvil, 1);
}
$anvil->Job->update_progress({
progress => 100,
message => "job_0281",
}) if $anvil->data->{switches}{'job-uuid'};
$anvil->nice_exit({exit_code => 0});
#############################################################################################################
# Functions #
#############################################################################################################
sub connect_to_libvirt
{
my ($anvil) = @_;
my $short_host_name = $anvil->Get->short_host_name;
my $host_uuid = $anvil->Get->host_uuid;
my $server_name = $anvil->data->{switches}{server_name};
my $server_uuid = $anvil->data->{switches}{server_uuid};
$anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => {
's1:short_host_name' => $short_host_name,
's2:host_uuid' => $host_uuid,
's3:server_name' => $server_name,
's4:server_uuid' => $server_uuid,
}});
my $from_source = get_definition_source($anvil);
my $server_state = $anvil->data->{servers}{server_uuid}{$server_uuid}{server_state};
$anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => {
from_source => $from_source,
server_state => $server_state,
}});
# We'll make changes to the DB and on-disk definitions if the server isn't running. If it is, we'll
# update the live system as well.
my $uri = "";
if ($server_state eq "running")
{
if ($server_uuid eq $anvil->Get->host_uuid)
{
### NOTE: Don't use 'localhost', Sys::Virt translates it to '::1' which Net::OpenSSH
### breaks on.
# Connect to the local libvirtd API, and handle problems if not.
$uri = "qemu+ssh://".$short_host_name."/system";
$anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { uri => $uri }});
}
else
{
my $server_host_uuid = $anvil->data->{servers}{server_uuid}{$server_uuid}{server_host_uuid};
my $server_host_name = $anvil->Database->get_host_from_uuid({
short => 1,
host_uuid => $server_host_uuid,
});
$anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { server_host_name => $server_host_name }});
my $target_ip = $anvil->Network->find_target_ip({
debug => 2,
host_uuid => $server_host_uuid,
test_access => 1,
networks => "bcn,mn,sn,ifn,any",
});
$anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { target_ip => $target_ip }});
if ($target_ip)
{
# Connect using this URI
$uri = "qemu+ssh://".$target_ip."/system";
$anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { uri => $uri }});
}
}
}
my $connection = "";
$anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { uri => $uri }});
eval { $connection = Sys::Virt->new(uri => $uri); };
if ($@)
{
# Throw an error, then clear the URI so that we just update the DB/on-disk definitions.
$anvil->Log->entry({source => $THIS_FILE, line => __LINE__, level => 1, key => "warning_0162", variables => {
host_name => $short_host_name,
uri => $uri,
error => $@,
}});
return(1);
}
my $domain = "";
my @domains = $connection->list_all_domains();
foreach my $domain_handle (@domains)
{
my $this_server_name = $domain_handle->get_name;
next if $this_server_name ne $server_name;
$domain = $domain_handle;
last;
}
return($domain);
}
sub manage_boot_menu
{
my ($anvil) = @_;
my $short_host_name = $anvil->Get->short_host_name;
my $host_uuid = $anvil->Get->host_uuid;
my $server_name = $anvil->data->{switches}{server_name};
my $server_uuid = $anvil->data->{switches}{server_uuid};
my $server_host_uuid = $anvil->data->{servers}{server_uuid}{$server_uuid}{server_host_uuid};
$anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => {
's1:short_host_name' => $short_host_name,
's2:host_uuid' => $host_uuid,
's3:server_name' => $server_name,
's4:server_uuid' => $server_uuid,
's5:server_host_uuid' => $server_host_uuid,
}});
my $domain_handle = connect_to_libvirt($anvil);
my $from_source = get_definition_source($anvil);
my $server_state = $anvil->data->{servers}{server_uuid}{$server_uuid}{server_state};
$anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => {
domain_handle => $domain_handle,
from_source => $from_source,
server_state => $server_state,
}});
if ($server_state eq "running")
{
my $server_host_name = $anvil->Database->get_host_from_uuid({
short => 1,
host_uuid => $server_host_uuid,
});
}
my $say_yes = $anvil->Words->string({key => 'unit_0001'});
my $say_no = $anvil->Words->string({key => 'unit_0002'});
my $current_boot_menu = lc($anvil->data->{server}{$short_host_name}{$server_name}{$from_source}{info}{boot_menu});
my $say_old_boot_menu = $current_boot_menu eq "yes" ? $say_yes : $say_no;
my $new_boot_menu = $anvil->data->{switches}{'boot-menu'};
$anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => {
current_boot_menu => $current_boot_menu,
say_old_boot_menu => $say_old_boot_menu,
new_boot_menu => $new_boot_menu,
}});
if (($anvil->data->{switches}{'boot-menu'} eq "yes") or ($anvil->data->{switches}{'boot-menu'} eq "no"))
{
# We need to rewrite the boot menu manually.
my $new_definition = "";
my $in_os = 0;
my $bootmenu_seen = 0;
foreach my $line (split/\n/, $anvil->data->{servers}{server_uuid}{$server_uuid}{server_definition_xml})
{
$anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { line => $line }});
if ($line =~ /<os>/)
{
$in_os = 1;
$anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { in_os => $in_os }});
}
if ($in_os)
{
if ($line =~ /<bootmenu enable='(.*?)'\/>/)
{
my $old_value = $1;
$bootmenu_seen = 1;
$line =~ s/<bootmenu enable='.*?'\/>/<bootmenu enable='$new_boot_menu'\/>/;
$anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => {
old_value => $old_value,
bootmenu_seen => $bootmenu_seen,
line => $line,
}});
}
if ($line =~ /<\/os>/)
{
$in_os = 0;
if (not $bootmenu_seen)
{
# Insert it
$new_definition .= " <bootmenu enable='".$new_boot_menu."'\/>\n";
$anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { new_definition => $new_definition }});
}
}
}
$new_definition .= $line."\n";
}
$anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { new_definition => $new_definition }});
# Always call this, as a previous run may have only updated some definitions.
my $problem = $anvil->Server->update_definition({
debug => 2,
server => $server_uuid,
new_definition_xml => $new_definition,
});
$anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { problem => $problem }});
}
else
{
print "Boot Menu enabled: [".$say_old_boot_menu."]\n";
print "- You can change this using '--boot-menu off' or '--boot-menu on'.\n";
}
return(0);
}
sub show_server_details
{
my ($anvil, $show_nodes) = @_;
my $short_host_name = $anvil->Get->short_host_name;
my $host_uuid = $anvil->Get->host_uuid;
my $server_name = $anvil->data->{switches}{server_name};
$anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => {
's1:short_host_name' => $short_host_name,
's2:host_uuid' => $host_uuid,
's3:server_name' => $server_name,
's4:show_nodes' => $show_nodes,
}});
# Words we'll use.
my $say_yes = $anvil->Words->string({key => 'unit_0001'});
my $say_no = $anvil->Words->string({key => 'unit_0002'});
my $say_disk = $anvil->Words->string({key => 'header_0068'});
my $say_optical = $anvil->Words->string({key => 'header_0111'});
my $say_ejected = $anvil->Words->string({key => 'unit_0049'});
my $from_source = get_definition_source($anvil);
$anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { from_source => $from_source }});
# Boot stuff
my $say_boot_menu = lc($anvil->data->{server}{$short_host_name}{$server_name}{$from_source}{info}{boot_menu}) eq "yes" ? $say_yes : $say_no;
my $say_boot_device = lc($anvil->data->{server}{$short_host_name}{$server_name}{$from_source}{boot_order}{1}{device_type}) eq "cdrom" ? $say_optical : $say_disk;
my $boot_device = $anvil->data->{server}{$short_host_name}{$server_name}{$from_source}{boot_order}{1}{device_target};
$anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => {
say_boot_menu => $say_boot_menu,
say_boot_device => $say_boot_device,
boot_device => $boot_device,
}});
my $boot_order = [];
foreach my $sequence (sort {$a <=> $b} keys %{$anvil->data->{server}{$short_host_name}{$server_name}{$from_source}{boot_order}})
{
my $this_device_type = $anvil->data->{server}{$short_host_name}{$server_name}{$from_source}{boot_order}{$sequence}{device_type};
my $say_this_boot_device = lc($this_device_type) eq "cdrom" ? $say_optical : $say_disk;
my $this_boot_device = $anvil->data->{server}{$short_host_name}{$server_name}{$from_source}{boot_order}{$sequence}{device_target};
my $device_path = $anvil->data->{server}{$short_host_name}{$server_name}{$from_source}{device}{$this_device_type}{target}{$this_boot_device}{path} // "";
$anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => {
sequence => $sequence,
say_this_boot_device => $say_this_boot_device,
this_boot_device => $this_boot_device,
device_path => $device_path,
}});
if ((not $device_path) && (lc($this_device_type) eq "cdrom"))
{
$device_path = $say_ejected;
$anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { device_path => $device_path }});
}
push @{$boot_order}, $sequence."; ".$this_boot_device.", type: [".$say_this_boot_device."], path: [".$device_path."]";
}
print "Boot Menu enabled: [".$say_boot_menu."]\n";
print "Boot device:\n";
foreach my $say_other_boot (@{$boot_order})
{
print "- ".$say_other_boot."\n";
}
# CPU
my $cpu_sockets = $anvil->data->{server}{$short_host_name}{$server_name}{$from_source}{cpu}{sockets};
my $cpu_cores = $anvil->data->{server}{$short_host_name}{$server_name}{$from_source}{cpu}{cores};
my $cpu_total_cores = $cpu_sockets * $cpu_cores;
$anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => {
cpu_sockets => $cpu_sockets,
cpu_cores => $cpu_cores,
cpu_total_cores => $cpu_total_cores,
}});
print "CPU Total: [".$cpu_total_cores."]; Sockets: [".$cpu_sockets."], Cores per Socket: [".$cpu_cores."]\n";
# RAM
my $ram = $anvil->data->{server}{$short_host_name}{$server_name}{$from_source}{memory};
print "RAM: [".$anvil->Convert->bytes_to_human_readable({'bytes' => $ram})."] (".$anvil->Convert->add_commas({number => $ram})." Bytes)\n";
return(0);
}
sub get_definition_source
{
my ($anvil) = @_;
my $short_host_name = $anvil->Get->short_host_name;
my $server_name = $anvil->data->{switches}{server_name};
my $server_uuid = $anvil->data->{switches}{server_uuid};
my $server_state = $anvil->data->{servers}{server_uuid}{$server_uuid}{server_state};
my $server_host_uuid = $anvil->data->{servers}{server_uuid}{$server_uuid}{server_host_uuid};
my $from_source = "";
$anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => {
short_host_name => $short_host_name,
server_name => $server_name,
server_uuid => $server_uuid,
server_state => $server_state,
from_source => $from_source,
}});
$anvil->data->{server}{$short_host_name}{$server_name}{from_virsh} = "" if not exists $anvil->data->{server}{$short_host_name}{$server_name}{from_virsh};
$anvil->data->{server}{$short_host_name}{$server_name}{from_disk} = "" if not exists $anvil->data->{server}{$short_host_name}{$server_name}{from_disk};
$anvil->data->{server}{$short_host_name}{$server_name}{from_db} = "" if not exists $anvil->data->{server}{$short_host_name}{$server_name}{from_db};
$anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => {
"server::${short_host_name}::${server_name}::from_virsh" => $anvil->data->{server}{$short_host_name}{$server_name}{from_virsh},
"server::${short_host_name}::${server_name}::from_disk" => $anvil->data->{server}{$short_host_name}{$server_name}{from_disk},
"server::${short_host_name}::${server_name}::from_db" => $anvil->data->{server}{$short_host_name}{$server_name}{from_db},
}});
if (($server_state eq "running") &&
($server_host_uuid eq $anvil->Get->host_uuid()) &&
(exists $anvil->data->{server}{$short_host_name}{$server_name}{from_virsh}))
{
$from_source = "from_virsh";
$anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { from_source => $from_source }});
}
elsif (exists $anvil->data->{server}{$short_host_name}{$server_name}{from_disk})
{
$from_source = "from_disk";
$anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { from_source => $from_source }});
}
else
{
$from_source = "from_db";
$anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { from_source => $from_source }});
}
return($from_source);
}
sub show_server_list
{
my ($anvil) = @_;
# Loop through all Anvil! nodes, then all server in that Anvil!
foreach my $anvil_name (sort {$a cmp $b} keys %{$anvil->data->{anvils}{anvil_name}})
{
my $anvil_uuid = $anvil->data->{anvils}{anvil_name}{$anvil_name}{anvil_uuid};
my $anvil_description = $anvil->data->{anvils}{anvil_name}{$anvil_name}{anvil_description};
$anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => {
anvil_name => $anvil_name,
anvil_uuid => $anvil_uuid,
anvil_description => $anvil_description,
}});
if (($anvil->data->{switches}{anvil_uuid}) && ($anvil->data->{switches}{anvil_uuid} ne $anvil_uuid))
{
next;
}
print "\n".$anvil->Words->string({key => "message_0343", variables => {
anvil_name => $anvil_name,
anvil_uuid => $anvil_uuid,
anvil_description => $anvil_description,
}})."\n";
my $server_count = 0;
if (exists $anvil->data->{servers}{anvil_uuid}{$anvil_uuid}{server_name})
{
$server_count = keys %{$anvil->data->{servers}{anvil_uuid}{$anvil_uuid}{server_name}};
$anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { server_count => $server_count }});
}
if (not $server_count)
{
print $anvil->Words->string({key => "message_0344"})."\n";
}
else
{
foreach my $server_name (sort {$a cmp $b} keys %{$anvil->data->{servers}{anvil_uuid}{$anvil_uuid}{server_name}})
{
my $server_uuid = $anvil->data->{servers}{anvil_uuid}{$anvil_uuid}{server_name}{$server_name}{server_uuid};
my $server_state = $anvil->data->{servers}{server_uuid}{$server_uuid}{server_state};
$anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => {
server_name => $server_name,
server_uuid => $server_uuid,
server_state => $server_state,
}});
next if $server_state eq "DELETED";
print $anvil->Words->string({key => "message_0345", variables => {
server_name => $server_name,
server_uuid => $server_uuid,
}})."\n";
}
}
}
return(0);
}
sub validate_server
{
my ($anvil) = @_;
$anvil->Get->server_from_switch({
debug => 2,
string => $anvil->data->{switches}{server},
anvil_uuid => $anvil->data->{switches}{anvil_uuid},
});
$anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => {
"switches::server_name" => $anvil->data->{switches}{server_name},
"switches::server_uuid" => $anvil->data->{switches}{server_uuid},
}});
if (not $anvil->data->{switches}{server_uuid})
{
show_server_list($anvil);
my $variables = {
server => $anvil->data->{switches}{server},
anvil => $anvil->data->{switches}{anvil_name},
};
if ($anvil->data->{switches}{anvil_uuid})
{
# Not found on the requested Anvil! node.
$anvil->Log->entry({source => $THIS_FILE, line => __LINE__, 'print' => 1, level => 0, priority => "err", key => "error_0451", variables => $variables});
$anvil->Job->update_progress({
progress => 100,
message => "error_0451",
variables => $variables,
}) if $anvil->data->{switches}{'job-uuid'};
}
else
{
# Not found at all.
$anvil->Log->entry({source => $THIS_FILE, line => __LINE__, 'print' => 1, level => 0, priority => "err", key => "error_0452", variables => $variables});
$anvil->Job->update_progress({
progress => 100,
message => "error_0452",
variables => $variables,
}) if $anvil->data->{switches}{'job-uuid'};
}
$anvil->nice_exit({exit_code => 1});
}
my $variables = {
server_name => $anvil->data->{switches}{server_name},
server_uuid => $anvil->data->{switches}{server_uuid},
};
$anvil->Log->entry({source => $THIS_FILE, line => __LINE__, 'print' => 1, level => 1, key => "log_0802", variables => $variables});
$anvil->Job->update_progress({
progress => 2,
message => "log_0802",
variables => $variables,
}) if $anvil->data->{switches}{'job-uuid'};
my $short_host_name = $anvil->Get->short_host_name;
my $server_name = $anvil->data->{switches}{server_name};
my $server_uuid = $anvil->data->{switches}{server_uuid};
my $server_definition = $anvil->data->{servers}{server_uuid}{$server_uuid}{server_definition_xml};
my $server_host_uuid = $anvil->data->{servers}{server_uuid}{$server_uuid}{server_host_uuid};
my $server_state = $anvil->data->{servers}{server_uuid}{$server_uuid}{server_state};
my $anvil_uuid = $anvil->data->{servers}{server_uuid}{$server_uuid}{server_anvil_uuid};
$anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => {
's1:short_host_name' => $short_host_name,
's2:server_name' => $server_name,
's3:server_uuid' => $server_uuid,
's4:server_definition' => $server_definition,
's5:server_host_uuid' => $server_host_uuid,
's6:server_state' => $server_state,
's7:anvil_uuid' => $anvil_uuid,
}});
if (not $anvil->data->{switches}{anvil_uuid})
{
$anvil->data->{switches}{anvil_uuid} = $anvil_uuid;
$anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => {
's1:switches::anvil_uuid' => $anvil->data->{switches}{anvil_uuid},
}});
}
if ($server_state eq "DELETED")
{
# The server has been deleted
my $variables = { server => $server_name };
$anvil->Log->entry({source => $THIS_FILE, line => __LINE__, 'print' => 1, level => 0, priority => "err", key => "error_0453", variables => $variables});
$anvil->Job->update_progress({
progress => 100,
message => "error_0453",
variables => $variables,
}) if $anvil->data->{switches}{'job-uuid'};
$anvil->nice_exit({exit_code => 1});
}
# Parse the definition.
$anvil->Server->parse_definition({
debug => 3,
host => $short_host_name,
server => $server_name,
source => "from_db",
definition => $server_definition,
});
# Can we read the XML definition?
$anvil->Server->get_status({
debug => 2,
server => $server_name,
host => $short_host_name,
});
if (not $anvil->data->{server}{$short_host_name}{$server_name}{from_virsh}{xml})
{
# The server isn't actually running... Not here anyway.
if ($server_state eq "running")
{
my $server_host_name = $anvil->Database->get_host_from_uuid({
short => 1,
host_uuid => $server_host_uuid,
});
my $variables = {
server => $server_name,
host_name => $server_host_name,
};
$anvil->Log->entry({source => $THIS_FILE, line => __LINE__, 'print' => 1, level => 0, priority => "err", key => "error_0454", variables => $variables});
$anvil->Job->update_progress({
progress => 100,
message => "error_0454",
variables => $variables,
}) if $anvil->data->{switches}{'job-uuid'};
$anvil->nice_exit({exit_code => 1});
}
}
return(0);
}
sub load_job
{
my ($anvil) = @_;
$anvil->Job->clear({
debug => 2,
job_uuid => $anvil->data->{switches}{'job-uuid'},
});
$anvil->Job->get_job_details({
debug => 2,
job_uuid => $anvil->data->{switches}{'job-uuid'},
});
$anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => {
'jobs::job_data' => $anvil->data->{jobs}{job_data},
}});
foreach my $line (split/\n/, $anvil->data->{jobs}{job_data})
{
my ($variable, $value) = ($line =~ /^(.*)=(.*)$/);
$value =~ s/^"(.*)\"/$1/;
$value =~ s/^'(.*)\'/$1/;
$anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => {
's1:line' => $line,
's2:variable' => $variable,
's3:value' => $value,
}});
$anvil->data->{switches}{$variable} = $value;
$anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => {
"switches::${variable}" => $anvil->data->{switches}{$variable},
}});
}
$anvil->Job->update_progress({
progress => 1,
job_picked_up_by => $$,
job_picked_up_at => time,
message => "message_0350",
});
return(0);
}

@ -282,7 +282,7 @@ sub prepare_for_run
$anvil->Storage->read_config();
$anvil->Get->switches();
$anvil->Words->read();
$anvil->Database->connect({check_for_resync => 1});
$anvil->Database->connect();
$anvil->Log->entry({source => $THIS_FILE, line => __LINE__, 'print' => 1, level => 2, key => "log_0132"});
# See if the mail server needs to be updated.
@ -296,9 +296,7 @@ sub wait_for_database
{
my ($anvil) = @_;
# Don't check for resync here as we may need to load agent schemas. We'll check for resync in the
# main loop.
$anvil->Database->connect({check_for_resync => 0});
$anvil->Database->connect();
$anvil->Log->entry({source => $THIS_FILE, line => __LINE__, level => 2, key => "log_0132"});
if (not $anvil->data->{sys}{database}{connections})
{
@ -314,7 +312,7 @@ sub wait_for_database
$anvil->_set_paths();
$anvil->_set_defaults();
$anvil->Storage->read_config();
$anvil->Database->connect({check_for_resync => 0});
$anvil->Database->connect();
if ($anvil->data->{sys}{database}{connections})
{
# We're good

@ -26,16 +26,12 @@ $| = 1;
my $anvil = Anvil::Tools->new();
$anvil->data->{switches}{'job-uuid'} = "";
$anvil->data->{switches}{'host-uuid'} = "";
$anvil->data->{switches}{'host-name'} = "";
$anvil->Get->switches;
$anvil->Log->entry({source => $THIS_FILE, line => __LINE__, 'print' => 1, level => 1, secure => 0, key => "log_0115", variables => { program => $THIS_FILE }});
$anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => {
'switches::job-uuid' => $anvil->data->{switches}{'job-uuid'},
'switches::host-uuid' => $anvil->data->{switches}{'host-uuid'},
'switches::host-name' => $anvil->data->{switches}{'host-name'},
}});
$anvil->Get->switches({list => [
"host",
"host-uuid",
"job-uuid"], 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__, 'print' => 1, level => 2, secure => 0, key => "log_0115", variables => { program => $THIS_FILE }});
$anvil->Database->connect();
$anvil->Log->entry({source => $THIS_FILE, line => __LINE__, level => 3, secure => 0, key => "log_0132"});
@ -70,23 +66,34 @@ if ($anvil->data->{switches}{'job-uuid'})
'switches::host-uuid' => $anvil->data->{switches}{'host-uuid'},
}});
}
if ($line =~ /host-name=(.*?)$/)
if ($line =~ /host=(.*?)$/)
{
$anvil->data->{switches}{'host-name'} = $1;
$anvil->data->{switches}{host} = $1;
$anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => {
'switches::host-name' => $anvil->data->{switches}{'host-name'},
'switches::host' => $anvil->data->{switches}{host},
}});
}
}
}
# If we have a host name, but not a host-uuid, look up the host UUID.
if ((not $anvil->data->{switches}{'host-uuid'}) && ($anvil->data->{switches}{'host-name'}))
# Get the host info (copy host-uuid to host)
$anvil->data->{switches}{'host-name'} = "" if not defined $anvil->data->{switches}{'host-name'};
if ((not $anvil->data->{switches}{host}) && ($anvil->data->{switches}{'host-uuid'}))
{
$anvil->data->{switches}{host} = $anvil->data->{switches}{'host-uuid'};
$anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => {
'switches::host' => $anvil->data->{switches}{host},
}});
}
# If the host is 'all', don't translate to the host_uuid. Otherwise, look for the host_uuid from the host string
if ((not $anvil->data->{switches}{'host-uuid'}) && ($anvil->data->{switches}{host} ne "all"))
{
$anvil->data->{switches}{'host-uuid'} = $anvil->Get->host_uuid_from_name({host_name => $anvil->data->{switches}{'host-name'}});
$anvil->data->{switches}{'host-uuid'} = $anvil->Database->get_host_uuid_from_string({string => $anvil->data->{switches}{host}});
$anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => {
'switches::host-uuid' => $anvil->data->{switches}{'host-uuid'},
}});
# host name not found
if (not $anvil->data->{switches}{'host-uuid'})
{
@ -94,14 +101,11 @@ if ((not $anvil->data->{switches}{'host-uuid'}) && ($anvil->data->{switches}{'ho
$anvil->Job->update_progress({progress => 100, message => "error_0291,!!host_name!".$anvil->data->{switches}{'host-name'}."!!"});
$anvil->nice_exit({exit_code => 1});
}
}
# If we still don't have a host_uuid, we can't proceed.
if (not $anvil->data->{switches}{'host-uuid'})
{
$anvil->Log->entry({source => $THIS_FILE, line => __LINE__, 'print' => 1, level => 0, priority => "err", key => "error_0290"});
$anvil->Job->update_progress({progress => 100, message => "error_0290"});
$anvil->nice_exit({exit_code => 1});
$anvil->data->{switches}{'host-name'} = $anvil->Get->host_name_from_uuid({host_uuid => $anvil->data->{switches}{'host-uuid'}});
$anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => {
'switches::host-name' => $anvil->data->{switches}{'host-name'},
}});
}
find_boot_method($anvil);
@ -121,33 +125,73 @@ sub find_boot_method
$anvil->Database->get_hosts_info({debug => 2});
my $host_uuid = $anvil->data->{switches}{'host-uuid'};
my $host_name = $anvil->data->{machine}{host_uuid}{$host_uuid}{hosts}{host_name};
my $host_ipmi = $anvil->data->{machine}{host_uuid}{$host_uuid}{hosts}{host_ipmi};
my $hosts = [];
if ($anvil->data->{switches}{'host-uuid'})
{
push @{$hosts}, $anvil->data->{switches}{'host-name'};
}
elsif ($anvil->data->{switches}{host} eq "all")
{
$anvil->Database->get_hosts({debug => 2});
foreach my $host_name (sort {$a cmp $b} keys %{$anvil->data->{sys}{hosts}{by_name}})
{
my $host_uuid = $anvil->data->{sys}{hosts}{by_name}{$host_name};
my $host_ipmi = $anvil->data->{hosts}{host_uuid}{$host_uuid}{host_ipmi};
my $host_key = $anvil->data->{hosts}{host_uuid}{$host_uuid}{host_key};
$anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => {
's1:host_name' => $host_name,
's2:host_uuid' => $host_uuid,
's3:host_ipmi' => $anvil->Log->is_secure($host_ipmi),
}});
next if $host_key eq "DELETED";
next if not $host_ipmi;
push @{$hosts}, $host_name;
}
}
my $host_count = @{$hosts};
my $steps = int((80 / $host_count) / 3);
$anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => {
host_count => $host_count,
steps => $steps,
}});
$anvil->data->{sys}{progress} = 5;
foreach my $host_name (sort {$a cmp $b} @{$hosts})
{
my $host_uuid = $anvil->Database->get_host_uuid_from_string({string => $host_name});
my $host_ipmi = $anvil->data->{hosts}{host_uuid}{$host_uuid}{host_ipmi};
my $host_type = $anvil->data->{hosts}{host_uuid}{$host_uuid}{host_ipmi};
$anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => {
host_uuid => $host_uuid,
host_name => $host_name,
host_ipmi => $anvil->Log->is_secure($host_ipmi),
host_type => $host_type,
}});
$anvil->data->{sys}{progress} = 10;
$anvil->data->{sys}{progress} += $steps;
# If we have IPMI, that's the easiest method.
if ($host_ipmi)
{
# Got it.
$anvil->data->{sys}{progress} += $steps;
$anvil->Log->entry({source => $THIS_FILE, line => __LINE__, 'print' => 1, level => 0, key => "job_0327", variables => { host_name => $host_name }});
$anvil->Job->update_progress({progress => $anvil->data->{sys}{progress}+=10, message => "job_0327,!!host_name!".$host_name."!!"});
$anvil->Job->update_progress({progress => $anvil->data->{sys}{progress}, message => "job_0327,!!host_name!".$host_name."!!"});
# First, is the node already on?
my $shell_call = $host_ipmi." -o status";
$anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, secure => 1, list => { shell_call => $shell_call }});
call_fence_agent($anvil, $shell_call);
}
$anvil->data->{sys}{progress} += $steps;
my $problem = call_fence_agent($anvil, $shell_call, $anvil->data->{sys}{progress});
$anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, secure => 1, list => { problem => $problem }});
# If I am here, either there is no IPMI. Can we boot it using another fence method?
# Is the machine in an Anvil! system?
$anvil->data->{sys}{progress} += $steps;
if ($problem)
{
# If I am here, there is no IPMI. Can we boot it using another fence method?
# The machine would have to be in an Anvil! for this to work.
my $anvil_uuid = $anvil->Cluster->get_anvil_uuid({host_uuid => $host_uuid});
$anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { anvil_uuid => $anvil_uuid }});
if ($anvil_uuid)
@ -158,7 +202,7 @@ sub find_boot_method
host_name => $host_name,
anvil_name => $anvil_name,
}});
$anvil->Job->update_progress({progress => $anvil->data->{sys}{progress}+=10, message => "job_0331,!!host_name!".$host_name."!!,!!anvil_name!".$anvil_name."!!"});
$anvil->Job->update_progress({progress => $anvil->data->{sys}{progress}, message => "job_0331,!!host_name!".$host_name."!!,!!anvil_name!".$anvil_name."!!"});
$anvil->Cluster->get_fence_methods({host_uuid => $host_uuid});
foreach my $target_host_name (sort {$a cmp $b} keys %{$anvil->data->{fence_method}})
@ -175,23 +219,32 @@ sub find_boot_method
method => $method,
shell_call => $anvil->Log->is_secure($shell_call),
}});
call_fence_agent($anvil, $shell_call);
my $problem = call_fence_agent($anvil, $shell_call, $anvil->data->{sys}{progress});
$anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { problem => $problem }});
if ($problem)
{
$anvil->Log->entry({source => $THIS_FILE, line => __LINE__, 'print' => 1, level => 0, priority => "err", key => "error_0297"});
$anvil->Job->update_progress({progress => $anvil->data->{sys}{progress}, message => "error_0297"});
}
}
}
}
# If I hit here, we ran out of fence options and can't boot the machine.
$anvil->Log->entry({source => $THIS_FILE, line => __LINE__, 'print' => 1, level => 0, priority => "err", key => "error_0297"});
$anvil->Job->update_progress({progress => 100, message => "error_0297"});
$anvil->nice_exit({exit_code => 1});
}
else
{
# Nothing we can do to boot this machine.
$anvil->Log->entry({source => $THIS_FILE, line => __LINE__, 'print' => 1, level => 0, priority => "err", key => "error_0294"});
$anvil->Job->update_progress({progress => 100, message => "error_0294"});
$anvil->nice_exit({exit_code => 1});
$anvil->Job->update_progress({progress => $anvil->data->{sys}{progress}, message => "error_0294"});
}
}
}
}
# Done.
$anvil->Job->update_progress({progress => 100, message => "message_0025"});
$anvil->nice_exit({exit_code => 0});
return(0);
}
@ -199,7 +252,7 @@ sub find_boot_method
# This calls a fence agent and exits if it successfully boots the target
sub call_fence_agent
{
my ($anvil, $shell_call) = @_;
my ($anvil, $shell_call, $progress) = @_;
my ($output, $return_code) = $anvil->System->call({shell_call => $shell_call, secure => 1});
$anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => {
@ -212,14 +265,14 @@ sub call_fence_agent
# The machine is already on
$anvil->Log->entry({source => $THIS_FILE, line => __LINE__, 'print' => 1, level => 1, key => "job_0328"});
$anvil->Job->update_progress({progress => 100, message => "job_0328"});
$anvil->nice_exit({exit_code => 0});
return(0);
}
elsif ($return_code eq "1")
{
# Unable to connect to the fence device.
$anvil->Log->entry({source => $THIS_FILE, line => __LINE__, 'print' => 1, level => 0, priority => "err", key => "error_0293", variables => { output => $output }});
$anvil->Job->update_progress({progress => 100, message => "error_0293,!!output!".$output."!!"});
$anvil->nice_exit({exit_code => 1});
return(1);
}
elsif ($return_code eq "2")
{
@ -249,14 +302,14 @@ sub call_fence_agent
host_uuid => $anvil->data->{switches}{'host-uuid'},
host_status => "booting",
});
$anvil->nice_exit({exit_code => 0});
return(0);
}
else
{
# Failed.
$anvil->Log->entry({source => $THIS_FILE, line => __LINE__, 'print' => 1, level => 0, priority => "err", key => "error_0292", variables => { output => $output }});
$anvil->Job->update_progress({progress => 100, message => "error_0292,!!output!".$output."!!"});
$anvil->nice_exit({exit_code => 1});
return(1);
}
}

@ -22,7 +22,7 @@ if (($running_directory =~ /^\./) && ($ENV{PWD}))
my $anvil = Anvil::Tools->new();
$anvil->Database->connect({debug => 3, check_for_resync => 0});
$anvil->Database->connect();
$anvil->Log->entry({source => $THIS_FILE, line => __LINE__, level => 2, secure => 0, key => "log_0132"});
if (not $anvil->data->{sys}{database}{connections})
{

@ -3,6 +3,8 @@
# This is the command line user interface for managing files on /mnt/shared/files on Strikers and made
# available on Anvil! systems.
#
# NOTE: This program is incomplete!
#
use strict;
use warnings;

@ -42,6 +42,9 @@ if ($anvil->data->{switches}{'job-uuid'})
$anvil->data->{job}{progress} = 1;
# Make sure the directory we write screenshots to exists and has the proper ownership and mode.
check_screenshot_directory($anvil);
# Which subnodes are up?
$anvil->Database->get_hosts();
$anvil->Database->get_dr_links();
@ -178,6 +181,41 @@ $anvil->nice_exit({exit_code => 0});
# Functions #
#############################################################################################################
sub check_screenshot_directory
{
my ($anvil) = @_;
# Does the directory even exist?
if (not -d $anvil->data->{path}{directories}{screenshots})
{
$anvil->Storage->make_directory({
debug => 2,
directory => $anvil->data->{path}{directories}{screenshots},
owner => "striker-ui-api",
group => "striker-ui-api",
mode => "0755",
});
}
foreach my $directory ($anvil->data->{path}{directories}{opt_alteeve}, $anvil->data->{path}{directories}{screenshots})
{
$anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { directory => $directory }});
$anvil->Storage->change_owner({
debug => 2,
path => $directory,
user => "striker-ui-api",
group => "striker-ui-api",
});
$anvil->Storage->change_mode({
debug => 2,
path => $directory,
mode => "0755",
});
}
return(0);
}
sub remove_old_screenshots
{
my ($anvil) = @_;
@ -411,6 +449,14 @@ sub get_screenshots
'format' => "jpeg",
},
});
# Change the ownership
$anvil->Storage->change_owner({
debug => 2,
path => $jpg_file,
user => "striker-ui-api",
group => "striker-ui-api",
});
}
# Convert to png
@ -438,6 +484,14 @@ sub get_screenshots
'format' => "png",
},
});
# Change the ownership
$anvil->Storage->change_owner({
debug => 2,
path => $png_file,
user => "striker-ui-api",
group => "striker-ui-api",
});
}
# Delete the original PPM file?

@ -124,7 +124,7 @@ if ($anvil->data->{switches}{status})
}
# Connect to the database(s).
$anvil->Database->connect({check_for_resync => 1});
$anvil->Database->connect();
$anvil->Log->entry({source => $THIS_FILE, line => __LINE__, level => 3, secure => 0, key => "log_0132"});
if (not $anvil->data->{sys}{database}{connections})
{

@ -60,10 +60,7 @@ if (($< != 0) && ($> != 0))
}
# We'll try to connect in case we're adding additional peers.
$anvil->Database->connect({
debug => 3,
check_for_resync => 1,
});
$anvil->Database->connect();
$anvil->Log->entry({source => $THIS_FILE, line => __LINE__, level => 2, secure => 0, key => "log_0132"});
# Am I adding, editing or deleting?

@ -40,7 +40,7 @@ if (($< != 0) && ($> != 0))
$anvil->nice_exit({exit_code => 5});
}
$anvil->Database->connect({check_for_resync => 1});
$anvil->Database->connect();
$anvil->Log->entry({source => $THIS_FILE, line => __LINE__, level => 2, secure => 0, key => "log_0132"});
if (not $anvil->data->{sys}{database}{connections})
{

@ -0,0 +1,287 @@
#!/usr/bin/perl
#
# This program will boot a target machine using either it's IPMI interface, if available, or one of the
# (non-PDU) fence methods, if the target is in an Anvil! and we have a manifest for it.
#
# Exit codes;
# 0 = Normal exit.
# 1 = No database connection.
#
# TODO:
#
use strict;
use warnings;
use Anvil::Tools;
my $THIS_FILE = ($0 =~ /^.*\/(.*)$/)[0];
my $running_directory = ($0 =~ /^(.*?)\/$THIS_FILE$/)[0];
if (($running_directory =~ /^\./) && ($ENV{PWD}))
{
$running_directory =~ s/^\./$ENV{PWD}/;
}
# Turn off buffering so that the pinwheel will display while waiting for the SSH call(s) to complete.
$| = 1;
my $anvil = Anvil::Tools->new();
$anvil->Get->switches({list => [
"ended-within",
"host",
"job-uuid"], 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__, 'print' => 1, level => 2, secure => 0, key => "log_0115", variables => { program => $THIS_FILE }});
# Make sure we've got a
if (($anvil->data->{switches}{'ended-within'} eq "") or ($anvil->data->{switches}{'ended-within'} !~ /^\d+$/))
{
$anvil->data->{switches}{'ended-within'} = 300;
$anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => {
"switches::ended-within" => $anvil->data->{switches}{'ended-within'},
}});
}
$anvil->data->{show}{host_uuid} = "";
if (($anvil->data->{switches}{host}) && ($anvil->data->{switches}{host} ne "all"))
{
# Get the host_uuid
$anvil->data->{show}{host_uuid} = $anvil->Database->get_host_uuid_from_string({debug => 2, string => $anvil->data->{switches}{host}});
$anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => {
"show::host_uuid" => $anvil->data->{show}{host_uuid},
}});
}
$anvil->Database->connect();
$anvil->Log->entry({source => $THIS_FILE, line => __LINE__, level => 3, secure => 0, key => "log_0132"});
if (not $anvil->data->{sys}{database}{connections})
{
# No databases, update the job, sleep for a bit and then exit. The daemon will pick it up and try
# again after we exit.
$anvil->Log->entry({source => $THIS_FILE, line => __LINE__, 'print' => 1, level => 0, priority => "err", key => "error_0075"});
sleep 10;
$anvil->nice_exit({exit_code => 1});
}
show_jobs($anvil);
$anvil->nice_exit({exit_code => 0});
#############################################################################################################
# Functions #
#############################################################################################################
sub show_jobs
{
my ($anvil) = @_;
$anvil->Database->get_hosts({debug => 3});
$anvil->Database->get_jobs({
debug => 2,
job_host_uuid => $anvil->data->{show}{host_uuid} // "all",
ended_within => $anvil->data->{switches}{'ended-within'},
});
# Sort them into hosts, and then sort them by picked-up time (if we sorted by modified date, the
# display would jump all over the place)
# NOTE: Yes, I know, sorting on job_uuid doesn't make much sense but it means repeated runs are
# at least consistent in the logss.
my $jobs_found = 0;
foreach my $job_uuid (sort {$a cmp $b} keys %{$anvil->data->{jobs}{running}})
{
if (($anvil->data->{switches}{'job-uuid'}) && ($anvil->data->{switches}{'job-uuid'} ne $job_uuid))
{
next;
}
$jobs_found++;
my $job_command = $anvil->data->{jobs}{running}{$job_uuid}{job_command};
my $job_data = $anvil->data->{jobs}{running}{$job_uuid}{job_data};
my $job_picked_up_by = $anvil->data->{jobs}{running}{$job_uuid}{job_picked_up_by};
my $job_picked_up_at = $anvil->data->{jobs}{running}{$job_uuid}{job_picked_up_at};
my $job_updated = $anvil->data->{jobs}{running}{$job_uuid}{job_updated};
my $job_name = $anvil->data->{jobs}{running}{$job_uuid}{job_name};
my $job_progress = $anvil->data->{jobs}{running}{$job_uuid}{job_progress};
my $job_title = $anvil->data->{jobs}{running}{$job_uuid}{job_title};
my $job_description = $anvil->data->{jobs}{running}{$job_uuid}{job_description};
my $job_status = $anvil->data->{jobs}{running}{$job_uuid}{job_status};
my $job_host_uuid = $anvil->data->{jobs}{running}{$job_uuid}{job_host_uuid};
my $short_host_name = $anvil->data->{hosts}{host_uuid}{$job_host_uuid}{short_host_name} // "";
my $modified_date = $anvil->data->{jobs}{running}{$job_uuid}{modified_date};
my $modified_date_unix = $anvil->data->{jobs}{running}{$job_uuid}{modified_date_unix};
$anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => {
jobs_found => $jobs_found,
job_command => $job_command,
job_data => $job_data,
job_picked_up_by => $job_picked_up_by,
job_picked_up_at => $job_picked_up_at,
job_updated => $job_updated,
job_name => $job_name,
job_progress => $job_progress,
job_title => $job_title,
job_description => $job_description,
job_status => $job_status,
job_host_uuid => $job_host_uuid,
short_host_name => $short_host_name,
modified_date => $modified_date,
modified_date_unix => $modified_date_unix,
}});
# Turn the time stamps into strings and translate the job_title, job_description, and job_status
my $say_job_picked_up_at = $anvil->Get->date_and_time({use_time => $job_picked_up_at});
my $say_job_updated = $anvil->Get->date_and_time({use_time => $job_updated});
my $say_job_title = $anvil->Words->parse_banged_string({debug => 2, key_string => $job_title});
my $say_job_description = $anvil->Words->parse_banged_string({debug => 2, key_string => $job_description});
my $say_job_status = $anvil->Words->parse_banged_string({debug => 2, key_string => $job_status});
$anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => {
say_job_picked_up_at => $say_job_picked_up_at,
say_job_updated => $say_job_updated,
say_job_title => $say_job_title,
say_job_description => $say_job_description,
say_job_status => $say_job_status,
}});
my $sort_key = "queued";
if ($job_progress == 100)
{
# Finished
$sort_key = "completed";
}
elsif ($job_progress)
{
# Picked up
$sort_key = "in_progress";
}
if (not exists $anvil->data->{count}{$short_host_name}{$sort_key})
{
$anvil->data->{count}{$short_host_name}{$sort_key} = 1;
}
else
{
$anvil->data->{count}{$short_host_name}{$sort_key}++;
}
$anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => {
"count::${short_host_name}::${sort_key}" => $anvil->data->{count}{$short_host_name}{$sort_key},
}});
# Store
$anvil->data->{sorted_jobs}{$short_host_name}{$sort_key}{$job_picked_up_at}{job_uuid} = $job_uuid;
$anvil->data->{sorted_jobs}{$short_host_name}{$sort_key}{$job_picked_up_at}{job_command} = $job_command;
$anvil->data->{sorted_jobs}{$short_host_name}{$sort_key}{$job_picked_up_at}{job_data} = $job_data;
$anvil->data->{sorted_jobs}{$short_host_name}{$sort_key}{$job_picked_up_at}{job_picked_up_by} = $job_picked_up_by;
$anvil->data->{sorted_jobs}{$short_host_name}{$sort_key}{$job_picked_up_at}{job_updated} = $say_job_updated;
$anvil->data->{sorted_jobs}{$short_host_name}{$sort_key}{$job_picked_up_at}{job_picked_up_at} = $say_job_picked_up_at;
$anvil->data->{sorted_jobs}{$short_host_name}{$sort_key}{$job_picked_up_at}{job_name} = $job_name;
$anvil->data->{sorted_jobs}{$short_host_name}{$sort_key}{$job_picked_up_at}{job_progress} = $job_progress;
$anvil->data->{sorted_jobs}{$short_host_name}{$sort_key}{$job_picked_up_at}{job_title} = $say_job_title;
$anvil->data->{sorted_jobs}{$short_host_name}{$sort_key}{$job_picked_up_at}{job_description} = $say_job_description;
$anvil->data->{sorted_jobs}{$short_host_name}{$sort_key}{$job_picked_up_at}{job_status} = $say_job_status;
$anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => {
"sorted_jobs::${short_host_name}::${sort_key}::${job_picked_up_at}::job_uuid" => $anvil->data->{sorted_jobs}{$short_host_name}{$sort_key}{$job_picked_up_at}{job_uuid},
"sorted_jobs::${short_host_name}::${sort_key}::${job_picked_up_at}::job_command" => $anvil->data->{sorted_jobs}{$short_host_name}{$sort_key}{$job_picked_up_at}{job_command},
"sorted_jobs::${short_host_name}::${sort_key}::${job_picked_up_at}::job_data" => $anvil->data->{sorted_jobs}{$short_host_name}{$sort_key}{$job_picked_up_at}{job_data},
"sorted_jobs::${short_host_name}::${sort_key}::${job_picked_up_at}::job_picked_up_by" => $anvil->data->{sorted_jobs}{$short_host_name}{$sort_key}{$job_picked_up_at}{job_picked_up_by},
"sorted_jobs::${short_host_name}::${sort_key}::${job_picked_up_at}::job_updated" => $anvil->data->{sorted_jobs}{$short_host_name}{$sort_key}{$job_picked_up_at}{job_updated},
"sorted_jobs::${short_host_name}::${sort_key}::${job_picked_up_at}::job_picked_up_at" => $anvil->data->{sorted_jobs}{$short_host_name}{$sort_key}{$job_picked_up_at}{job_picked_up_at},
"sorted_jobs::${short_host_name}::${sort_key}::${job_picked_up_at}::job_name" => $anvil->data->{sorted_jobs}{$short_host_name}{$sort_key}{$job_picked_up_at}{job_name},
"sorted_jobs::${short_host_name}::${sort_key}::${job_picked_up_at}::job_progress" => $anvil->data->{sorted_jobs}{$short_host_name}{$sort_key}{$job_picked_up_at}{job_progress},
"sorted_jobs::${short_host_name}::${sort_key}::${job_picked_up_at}::job_title" => $anvil->data->{sorted_jobs}{$short_host_name}{$sort_key}{$job_picked_up_at}{job_title},
"sorted_jobs::${short_host_name}::${sort_key}::${job_picked_up_at}::job_description" => $anvil->data->{sorted_jobs}{$short_host_name}{$sort_key}{$job_picked_up_at}{job_description},
"sorted_jobs::${short_host_name}::${sort_key}::${job_picked_up_at}::job_status" => $anvil->data->{sorted_jobs}{$short_host_name}{$sort_key}{$job_picked_up_at}{job_status},
}});
}
if (($anvil->data->{switches}{'job-uuid'}) && (not $jobs_found))
{
print "The job: [".$anvil->data->{switches}{'job-uuid'}."] was not found.\n";
$anvil->nice_exit({exit_code => 1});
}
foreach my $short_host_name (sort {$a cmp $b} keys %{$anvil->data->{sorted_jobs}})
{
print "-=] Jobs on ".$short_host_name." [=------------------------------------------------\n";
foreach my $sort_key ("queued", "in_progress", "completed")
{
my $count = exists $anvil->data->{count}{$short_host_name}{$sort_key} // 0;
$anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => {
sort_key => $sort_key,
count => $count,
}});
next if not $count;
my $say_header = "";
if ($sort_key eq "queued")
{
$say_header = $anvil->Words->string({key => 'header_0112'});
}
elsif ($sort_key eq "in_progress")
{
$say_header = $anvil->Words->string({key => 'header_0113'});
}
elsif ($sort_key eq "completed")
{
$say_header = $anvil->Words->string({key => 'header_0114'});
}
$anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { say_header => $say_header }});
print "- ".$say_header."\n";
foreach my $job_picked_up_at (sort {$a cmp $b} keys %{$anvil->data->{sorted_jobs}{$short_host_name}{$sort_key}})
{
$anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { job_picked_up_at => $job_picked_up_at }});
my $job_uuid = $anvil->data->{sorted_jobs}{$short_host_name}{$sort_key}{$job_picked_up_at}{job_uuid};
my $job_command = $anvil->data->{sorted_jobs}{$short_host_name}{$sort_key}{$job_picked_up_at}{job_command};
my $job_data = $anvil->data->{sorted_jobs}{$short_host_name}{$sort_key}{$job_picked_up_at}{job_data};
my $job_picked_up_by = $anvil->data->{sorted_jobs}{$short_host_name}{$sort_key}{$job_picked_up_at}{job_picked_up_by};
my $say_job_updated = $anvil->data->{sorted_jobs}{$short_host_name}{$sort_key}{$job_picked_up_at}{job_updated};
my $say_job_picked_up_at = $anvil->data->{sorted_jobs}{$short_host_name}{$sort_key}{$job_picked_up_at}{job_picked_up_at};
my $job_name = $anvil->data->{sorted_jobs}{$short_host_name}{$sort_key}{$job_picked_up_at}{job_name};
my $job_progress = $anvil->data->{sorted_jobs}{$short_host_name}{$sort_key}{$job_picked_up_at}{job_progress};
my $say_job_title = $anvil->data->{sorted_jobs}{$short_host_name}{$sort_key}{$job_picked_up_at}{job_title};
my $say_job_description = $anvil->data->{sorted_jobs}{$short_host_name}{$sort_key}{$job_picked_up_at}{job_description};
my $say_job_status = $anvil->data->{sorted_jobs}{$short_host_name}{$sort_key}{$job_picked_up_at}{job_status};
$anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => {
job_uuid => $job_uuid,
job_command => $job_command,
job_data => $job_data,
job_picked_up_by => $job_picked_up_by,
say_job_updated => $say_job_updated,
say_job_picked_up_at => $say_job_picked_up_at,
job_name => $job_name,
job_progress => $job_progress,
say_job_title => $say_job_title,
say_job_description => $say_job_description,
say_job_status => $say_job_status,
}});
print "Job Name: [".$job_name."], UUID: [".$job_uuid."]\n";
if ($sort_key eq "queued")
{
print "- Command: [".$job_command."], <queued>\n";
}
elsif ($sort_key eq "completed")
{
print "- Command: [".$job_command."], Picked up at: [".$say_job_picked_up_at."], last updated: [".$say_job_updated."]\n";
}
else
{
print "- Command: [".$job_command."], Progress: [".$job_progress."\%] Picked up at: [".$say_job_picked_up_at."], last updated: [".$say_job_updated."], PID: [".$job_picked_up_by."]\n";
}
my $job_data_lines = (split/\n/, $job_data);
if ($job_data_lines > 1)
{
print "---] Job Data:\n";
print $job_data."\n";
print "----------------\n";
}
else
{
print "- Job Data: [".$job_data."]\n";
}
print "---] Job Status:\n";
print $say_job_status."\n";
print "--------------------------------------------------------------------------------\n";
}
}
}
return(0);
}
Loading…
Cancel
Save