Merge pull request #497 from ClusterLabs/server-manage-system

Server manage system
main
Digimer 1 year ago committed by GitHub
commit 6697069d8a
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
  1. 1
      Anvil/Tools.pm
  2. 2
      Anvil/Tools/Database.pm
  3. 97
      Anvil/Tools/Network.pm
  4. 668
      Anvil/Tools/Server.pm
  5. 2
      Anvil/Tools/Storage.pm
  6. 2
      man/anvil-manage-server-storage.8
  7. 39
      man/anvil-manage-server-system.8
  8. 1
      ocf/alteeve/server
  9. 1
      scancore-agents/scan-cluster/scan-cluster
  10. 14
      share/words.xml
  11. 80
      tools/anvil-delete-server
  12. 10
      tools/anvil-join-anvil
  13. 14
      tools/anvil-manage-files
  14. 1
      tools/anvil-manage-server-storage
  15. 688
      tools/anvil-manage-server-system
  16. 2
      tools/striker-file-manager
  17. 42
      tools/striker-get-screenshots

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

@ -3580,7 +3580,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. # backwards compatibility.
if ((exists $anvil->data->{hosts}{host_uuid}{$file_location_host_uuid}) && if ((exists $anvil->data->{hosts}{host_uuid}{$file_location_host_uuid}) &&
($anvil->data->{hosts}{host_uuid}{$file_location_host_uuid}{anvil_uuid})) ($anvil->data->{hosts}{host_uuid}{$file_location_host_uuid}{anvil_uuid}))

@ -1525,6 +1525,20 @@ Parameters;
This is the target's C<< host_uuid >> that we're looking to contact. 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 =cut
sub find_target_ip sub find_target_ip
{ {
@ -1534,10 +1548,13 @@ sub find_target_ip
my $debug = defined $parameter->{debug} ? $parameter->{debug} : 3; 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()" }}); $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 $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 => { $anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => $debug, list => {
host_uuid => $host_uuid, host_uuid => $host_uuid,
networks => $networks,
test_access => $test_access,
}}); }});
if (not $host_uuid) if (not $host_uuid)
@ -1554,6 +1571,12 @@ sub find_target_ip
return(""); 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 $target_host_name = $anvil->data->{hosts}{host_uuid}{$host_uuid}{short_host_name};
my $short_host_name = $anvil->Get->short_host_name({debug => $debug}); my $short_host_name = $anvil->Get->short_host_name({debug => $debug});
$anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => $debug, list => { $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, short_host_name => $short_host_name,
}}); }});
$anvil->Network->load_ips({ my $target_ip = "";
debug => $debug, my $matches = $anvil->Network->find_access({
host_uuid => $anvil->Get->host_uuid,
host => $short_host_name,
clear => 1,
});
$anvil->Network->load_ips({
debug => $debug,
host_uuid => $host_uuid,
host => $target_host_name,
clear => 1,
});
my ($match) = $anvil->Network->find_matches({
debug => $debug, debug => $debug,
first => $short_host_name, target => $target_host_name,
second => $target_host_name,
source => $THIS_FILE,
line => __LINE__,
}); });
if ($match) $anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { matches => $matches }});
foreach my $preferred_network (split/,/, $networks)
{ {
# Yup! last if $target_ip;
my $match_found = 0; $anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { preferred_network => $preferred_network }});
foreach my $interface (sort {$a cmp $b} keys %{$match->{$target_host_name}}) foreach my $network_name (sort {$a cmp $b} keys %{$anvil->data->{network_access}})
{ {
$target_ip = $match->{$target_host_name}{$interface}{ip}; $anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { network_name => $network_name }});
$anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => $debug, list => { target_ip => $target_ip }}); if (($network_name !~ /^$preferred_network/) && ($preferred_network ne "any"))
last; {
next;
}
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)
{
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)
{
# 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); return($target_ip);

@ -7,6 +7,8 @@ use strict;
use warnings; use warnings;
use Scalar::Util qw(weaken isweak); use Scalar::Util qw(weaken isweak);
use Data::Dumper; use Data::Dumper;
use Text::Diff;
use Sys::Virt;
our $VERSION = "3.0.0"; our $VERSION = "3.0.0";
my $THIS_FILE = "Server.pm"; my $THIS_FILE = "Server.pm";
@ -14,16 +16,19 @@ my $THIS_FILE = "Server.pm";
### Methods; ### Methods;
# active_migrations # active_migrations
# boot_virsh # boot_virsh
# connect_to_virsh
# count_servers # count_servers
# find # find # To be replaced by Server->locate();
# find_processes # find_processes
# get_definition # get_definition
# get_runtime # get_runtime
# get_status # get_status
# locate
# map_network # map_network
# parse_definition
# migrate_virsh # migrate_virsh
# parse_definition
# shutdown_virsh # shutdown_virsh
# update_definition
=cut TODO =cut TODO
@ -293,6 +298,170 @@ WHERE
return($success); 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 =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 =head2 find
This will look on the local or a remote machine for the list of servers that are running. 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, target => $target,
}}); }});
# NOTE: We don't use 'Server->find' as the hassle of tracking hosts to target isn't worth it. ### TODO: Switch to using Server->locate()
# Get a list of servers.
my $shell_call = $anvil->data->{path}{exe}{setsid}." --wait ".$anvil->data->{path}{exe}{virsh}." list"; my $shell_call = $anvil->data->{path}{exe}{setsid}." --wait ".$anvil->data->{path}{exe}{virsh}." list";
my $output = ""; my $output = "";
if ($anvil->Network->is_local({host => $target})) 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 =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. 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. 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) =head3 definition (required)
This is the actual XML to be parsed. This is the actual XML to be parsed.
@ -2342,6 +2784,224 @@ WHERE
return($success); 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 # =head3
# #
# Private Functions; # Private Functions;

@ -776,7 +776,7 @@ sub check_files
} }
elsif ($file_location_ready) 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({ $anvil->Database->insert_or_update_file_locations({
debug => $debug, debug => $debug,
file_location_uuid => $file_location_uuid, file_location_uuid => $file_location_uuid,

@ -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. When not specified, if only one disk exists, it will be chosen automatically.
.TP .TP
\fB\-\-eject\fR \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 .TP
\fB\-\-job\-uuid\fR \fB\-\-job\-uuid\fR
This is the jobs -> job_uuid to execute. Generally this is only used by other programs. 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

@ -1080,6 +1080,7 @@ sub start_drbd_resource
return(0); 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. # This uses the DRBD information to find other peers and see if the server is running on them.
sub find_server sub find_server
{ {

@ -205,6 +205,7 @@ sub cib_cleanup
return(0); 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. # This looks for failed resource and, if found, tries to recover them.
sub check_resources sub check_resources
{ {

@ -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> 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_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 --> <!-- Files templates -->
<!-- NOTE: Translating these files requires an understanding of which lines are translatable --> <!-- NOTE: Translating these files requires an understanding of which lines are translatable -->
@ -1149,6 +1156,7 @@ resource #!variable!server!# {
<key name="header_0108">On Battery</key> <key name="header_0108">On Battery</key>
<key name="header_0109">Estimated Runtime</key> <key name="header_0109">Estimated Runtime</key>
<key name="header_0110">Last Updated</key> <key name="header_0110">Last Updated</key>
<key name="header_0111">Optical Disc</key>
<!-- Strings used by jobs --> <!-- Strings used by jobs -->
<key name="job_0001">Configure Network</key> <key name="job_0001">Configure Network</key>
@ -2613,6 +2621,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_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_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_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. --> <!-- 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> <key name="message_0001">The host name: [#!variable!target!#] does not resolve to an IP address.</key>
@ -3663,6 +3674,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_0046">- Server is crashed!</key>
<key name="unit_0047">- Server is suspended.</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_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 <!-- 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. are used when adding UPSes to the system for use in Install Manifests.
@ -3931,6 +3943,8 @@ We will try to proceed anyway.</key>
#!variable!error!# #!variable!error!#
==== ====
</key> </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> </language>
<!-- 日本語 --> <!-- 日本語 -->

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

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

@ -175,6 +175,9 @@ sub find_missing_files
# What am I? This will impact how missing files are found. # What am I? This will impact how missing files are found.
$anvil->Database->get_anvils(); $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 = " my $query = "
SELECT SELECT
file_uuid, file_uuid,
@ -237,16 +240,7 @@ ORDER BY
else else
{ {
# Check to see if we're supposed to have this file. # Check to see if we're supposed to have this file.
$anvil->Database->get_file_locations(); my $file_location_uuid = $anvil->data->{file_locations}{host_uuid}{$host_uuid}{file_uuid}{$file_uuid}{file_location_uuid};
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};
$anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { file_location_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; next if not $file_location_uuid;

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

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

@ -42,6 +42,9 @@ if ($anvil->data->{switches}{'job-uuid'})
$anvil->data->{job}{progress} = 1; $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? # Which subnodes are up?
$anvil->Database->get_hosts(); $anvil->Database->get_hosts();
$anvil->Database->get_dr_links(); $anvil->Database->get_dr_links();
@ -178,6 +181,29 @@ $anvil->nice_exit({exit_code => 0});
# Functions # # Functions #
############################################################################################################# #############################################################################################################
sub check_screenshot_directory
{
my ($anvil) = @_;
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 sub remove_old_screenshots
{ {
my ($anvil) = @_; my ($anvil) = @_;
@ -411,6 +437,14 @@ sub get_screenshots
'format' => "jpeg", '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 # Convert to png
@ -438,6 +472,14 @@ sub get_screenshots
'format' => "png", '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? # Delete the original PPM file?

Loading…
Cancel
Save