* Started work on, but not at all finished, anvil-manage-server which will allow manipulation of a server's resources.

* Changed the alteeve repo RPM to the new cimmunity/enterprise repo
* Fixed a bug where 'fence_data::updated' was causing the fences web page to break.
* Fixed a bug in Database->insert_or_update_network_interfaces() where certain interfaces were being repeatedly added to the database.
* Fixed a bug in Database->_find_behind_databases() was marking DBs as behind even though they had less than 10 columns off.
* Fixed a bug in Get->host_name() where, if the host name was changed on disk but the environment variable was still the old name, it would cause the hostname to waffle back and forth and cause constant updated to /etc/hosts.

Signed-off-by: Digimer <digimer@alteeve.ca>
main
Digimer 4 years ago
parent ad4a1ecc78
commit fc0954d0c8
  1. 2
      Anvil/Tools.pm
  2. 8
      Anvil/Tools/Cluster.pm
  3. 27
      Anvil/Tools/Database.pm
  4. 10
      Anvil/Tools/Get.pm
  5. 11
      Anvil/Tools/ScanCore.pm
  6. 2
      Anvil/Tools/Server.pm
  7. 5
      Anvil/Tools/Striker.pm
  8. 18
      cgi-bin/striker
  9. 165
      notes
  10. 4
      share/Makefile.am
  11. 1
      share/words.xml
  12. 6
      tools/anvil-daemon
  13. 198
      tools/anvil-manage-server
  14. 42
      tools/anvil-manage-storage
  15. 1
      tools/anvil-safe-start
  16. 20
      tools/anvil-update-states
  17. 2
      tools/fence_delay

@ -1263,7 +1263,7 @@ sub _set_paths
urls => { urls => {
skins => "/skins", skins => "/skins",
oui_file => "http://standards.ieee.org/develop/regauth/oui/oui.txt", oui_file => "http://standards.ieee.org/develop/regauth/oui/oui.txt",
alteeve_repo => "https://www.alteeve.com/an-repo/el8/alteeve-el8-repo-latest.noarch.rpm", alteeve_repo => "https://www.alteeve.com/an-repo/m3/anvil-release-latest.noarch.rpm",
}, },
words => { words => {
'words.xml' => "/usr/share/anvil/words.xml", 'words.xml' => "/usr/share/anvil/words.xml",

@ -865,9 +865,9 @@ sub check_stonith_config
# Collecting fence data is expensive, so lets only load if needed. # Collecting fence data is expensive, so lets only load if needed.
my $update_fence_data = 1; my $update_fence_data = 1;
if ((exists $anvil->data->{fence_data}{updated}) && ($anvil->data->{fence_data}{updated})) if ((exists $anvil->data->{sys}{fence_data_updated}) && ($anvil->data->{sys}{fence_data_updated}))
{ {
my $age = time - $anvil->data->{fence_data}{updated}; my $age = time - $anvil->data->{sys}{fence_data_updated};
$anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => $debug, list => { age => $age }}); $anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => $debug, list => { age => $age }});
if ($age < 86400) if ($age < 86400)
{ {
@ -1634,9 +1634,9 @@ sub get_fence_methods
# Reading in fence data is expensive, so we only do it as needed. # Reading in fence data is expensive, so we only do it as needed.
my $update_fence_data = 1; my $update_fence_data = 1;
if ((exists $anvil->data->{fence_data}{updated}) && ($anvil->data->{fence_data}{updated})) if ((exists $anvil->data->{sys}{fence_data_updated}) && ($anvil->data->{sys}{fence_data_updated}))
{ {
my $age = time - $anvil->data->{fence_data}{updated}; my $age = time - $anvil->data->{sys}{fence_data_updated};
$anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => $debug, list => { age => $age }}); $anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => $debug, list => { age => $age }});
if ($age < 86400) if ($age < 86400)
{ {

@ -316,7 +316,7 @@ sub archive_database
=head2 check_file_locations =head2 check_file_locations
This method checks to see that there is a corresponding entry in C<< file_locations >> for all Anvil! systems and files in the database. Any that are found to be missing will be set to C<< file_location_active >> -> c<< falsa >>. This method checks to see that there is a corresponding entry in C<< file_locations >> for all Anvil! systems and files in the database. Any that are found to be missing will be set to C<< file_location_active >> -> c<< false >>.
This method takes no parameters. This method takes no parameters.
@ -8966,9 +8966,17 @@ AND
;"; ;";
$anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => $debug, list => { query => $query }}); $anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => $debug, list => { query => $query }});
$network_interface_uuid = $anvil->Database->query({uuid => $uuid, query => $query, source => $file ? $file." -> ".$THIS_FILE : $THIS_FILE, line => $line ? $line." -> ".__LINE__ : __LINE__})->[0]->[0]; my $results = $anvil->Database->query({uuid => $uuid, query => $query, source => $file ? $file." -> ".$THIS_FILE : $THIS_FILE, line => $line ? $line." -> ".__LINE__ : __LINE__});
$network_interface_uuid = "" if not defined $network_interface_uuid; my $count = @{$results};
$anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => $debug, list => { network_interface_uuid => $network_interface_uuid }}); $anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => $debug, list => {
results => $results,
count => $count,
}});
if ($count)
{
$network_interface_uuid = $results->[0]->[0];
$anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => $debug, list => { network_interface_uuid => $network_interface_uuid }});
}
if (($link_only) && (not $network_interface_uuid)) if (($link_only) && (not $network_interface_uuid))
{ {
@ -15459,6 +15467,9 @@ sub write
undef $query_set; undef $query_set;
} }
# Refresh the timestamp.
$anvil->Database->refresh_timestamp({debug => $debug});
return(0); return(0);
} }
@ -16099,11 +16110,11 @@ ORDER BY
uuid => $uuid, uuid => $uuid,
host => $anvil->Get->host_name_from_uuid({host_uuid => $uuid}), host => $anvil->Get->host_name_from_uuid({host_uuid => $uuid}),
}}); }});
}
# Mark it as behind. # Mark it as behind.
$anvil->Database->_mark_database_as_behind({debug => $debug, uuid => $uuid}); $anvil->Database->_mark_database_as_behind({debug => $debug, uuid => $uuid});
last; last;
}
} }
} }
last if $anvil->data->{sys}{database}{resync_needed}; last if $anvil->data->{sys}{database}{resync_needed};

@ -1337,10 +1337,11 @@ sub host_name
my $anvil = $self->parent; my $anvil = $self->parent;
my $host_name = ""; my $host_name = "";
if ($ENV{HOSTNAME}) # NOTE: Don't use 'ENV{HOSTNAME}'! It lags behind changes made by 'hostnamectl'.
if ($anvil->data->{sys}{host_name})
{ {
# We have an environment variable, so use it. # We have an environment variable, so use it.
$host_name = $ENV{HOSTNAME}; $host_name = $anvil->data->{sys}{host_name};
} }
else else
{ {
@ -1358,6 +1359,11 @@ sub host_name
print "Failed to query the hostname using 'hostnamectl --static' and failed to read the content of: [".$anvil->data->{path}{configs}{hostname}."]. Something is very wrong, exiting.\n"; print "Failed to query the hostname using 'hostnamectl --static' and failed to read the content of: [".$anvil->data->{path}{configs}{hostname}."]. Something is very wrong, exiting.\n";
} }
} }
else
{
# Cache the answer
$anvil->data->{sys}{host_name} = $host_name;
}
} }
return($host_name); return($host_name);

@ -2138,9 +2138,12 @@ LIMIT 1;";
# Read in the unified fence data, if it's not already loaded. # Read in the unified fence data, if it's not already loaded.
my $update_fence_data = 1; my $update_fence_data = 1;
if ($anvil->data->{fence_data}{updated}) $anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => $debug, list => {
"sys::fence_data_updated" => $anvil->data->{sys}{fence_data_updated},
}});
if ($anvil->data->{sys}{fence_data_updated})
{ {
my $age = time - $anvil->data->{fence_data}{updated}; my $age = time - $anvil->data->{sys}{fence_data_updated};
$anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => $debug, list => { age => $age }}); $anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => $debug, list => { age => $age }});
if ($age < 86400) if ($age < 86400)
{ {
@ -2283,6 +2286,10 @@ LIMIT 1;";
foreach my $this_switch (sort {$a cmp $b} keys %{$anvil->data->{fence_data}{$agent}{switch}}) foreach my $this_switch (sort {$a cmp $b} keys %{$anvil->data->{fence_data}{$agent}{switch}})
{ {
my $this_name = $anvil->data->{fence_data}{$agent}{switch}{$this_switch}{name}; my $this_name = $anvil->data->{fence_data}{$agent}{switch}{$this_switch}{name};
$anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => {
this_switch => $this_switch,
this_name => $this_name,
}});
if ($stdin_name eq $this_name) if ($stdin_name eq $this_name)
{ {
$switch = $this_switch; $switch = $this_switch;

@ -1687,7 +1687,7 @@ sub parse_definition
$anvil->data->{server}{$target}{$server}{device}{$device_path}{target} = $device_target; $anvil->data->{server}{$target}{$server}{device}{$device_path}{target} = $device_target;
$anvil->data->{server}{$target}{$server}{resource}{$resource} = 1; $anvil->data->{server}{$target}{$server}{resource}{$resource} = 1;
$anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => $debug, list => { $anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => $debug, list => {
host => $host, host => $host,
"server::${target}::${server}::device::${device_path}::on_lv" => $anvil->data->{server}{$target}{$server}{device}{$device_path}{on_lv}, "server::${target}::${server}::device::${device_path}::on_lv" => $anvil->data->{server}{$target}{$server}{device}{$device_path}{on_lv},
"server::${target}::${server}::device::${device_path}::resource" => $anvil->data->{server}{$target}{$server}{device}{$device_path}{resource}, "server::${target}::${server}::device::${device_path}::resource" => $anvil->data->{server}{$target}{$server}{device}{$device_path}{resource},
"server::${target}::${server}::device::${device_path}::target" => $anvil->data->{server}{$target}{$server}{device}{$device_path}{target}, "server::${target}::${server}::device::${device_path}::target" => $anvil->data->{server}{$target}{$server}{device}{$device_path}{target},

@ -461,7 +461,10 @@ sub get_fence_data
# ScanCore will load this to check nodes that are not accessible. To reduce load, as this is an # ScanCore will load this to check nodes that are not accessible. To reduce load, as this is an
# expensive call, this time is set so a caller can decide if the data should be updated. # expensive call, this time is set so a caller can decide if the data should be updated.
$anvil->data->{fence_data}{updated} = time; $anvil->data->{sys}{fence_data_updated} = time;
$anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => $debug, list => {
"sys::fence_data_updated" => $anvil->data->{sys}{fence_data_updated},
}});
return(0); return(0);
} }

@ -4773,6 +4773,13 @@ sub process_fences
$anvil->data->{fence_data}{$fence_agent}{parameters}{fence_name}{description} = "#!string!striker_0223!#"; $anvil->data->{fence_data}{$fence_agent}{parameters}{fence_name}{description} = "#!string!striker_0223!#";
$anvil->data->{fence_data}{$fence_agent}{parameters}{fence_name}{content_type} = "string"; $anvil->data->{fence_data}{$fence_agent}{parameters}{fence_name}{content_type} = "string";
$anvil->data->{fence_data}{$fence_agent}{parameters}{fence_name}{'default'} = ""; $anvil->data->{fence_data}{$fence_agent}{parameters}{fence_name}{'default'} = "";
$anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => {
"fence_data::${fence_agent}::parameters::fence_name::unique" => $anvil->data->{fence_data}{$fence_agent}{parameters}{fence_name}{unique},
"fence_data::${fence_agent}::parameters::fence_name::required" => $anvil->data->{fence_data}{$fence_agent}{parameters}{fence_name}{required},
"fence_data::${fence_agent}::parameters::fence_name::description" => $anvil->data->{fence_data}{$fence_agent}{parameters}{fence_name}{description},
"fence_data::${fence_agent}::parameters::fence_name::content_type" => $anvil->data->{fence_data}{$fence_agent}{parameters}{fence_name}{content_type},
"fence_data::${fence_agent}::parameters::fence_name::default" => $anvil->data->{fence_data}{$fence_agent}{parameters}{fence_name}{'default'},
}});
# Walk through the list of options # Walk through the list of options
my $option_form = ""; my $option_form = "";
@ -4872,6 +4879,11 @@ sub process_fences
my $fence_name_seen = 0; my $fence_name_seen = 0;
foreach my $name ("fence_name", sort {$a cmp $b} keys %{$anvil->data->{fence_data}{$fence_agent}{parameters}}) foreach my $name ("fence_name", sort {$a cmp $b} keys %{$anvil->data->{fence_data}{$fence_agent}{parameters}})
{ {
$anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => {
fence_agent => $fence_agent,
name => $name,
}});
# We don't show deprecated or replaced options. # We don't show deprecated or replaced options.
next if $anvil->data->{fence_data}{$fence_agent}{parameters}{$name}{replacement}; next if $anvil->data->{fence_data}{$fence_agent}{parameters}{$name}{replacement};
next if $anvil->data->{fence_data}{$fence_agent}{parameters}{$name}{deprecated}; next if $anvil->data->{fence_data}{$fence_agent}{parameters}{$name}{deprecated};
@ -4881,6 +4893,7 @@ sub process_fences
if ($name eq "fence_name") if ($name eq "fence_name")
{ {
$fence_name_seen = 1; $fence_name_seen = 1;
$anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { fence_name_seen => $fence_name_seen }});
} }
my $option_key = $name."_".$i; my $option_key = $name."_".$i;
@ -4903,6 +4916,7 @@ sub process_fences
$anvil->data->{cgi}{$option_key}{alert} = "" if not defined $anvil->data->{cgi}{$option_key}{alert}; $anvil->data->{cgi}{$option_key}{alert} = "" if not defined $anvil->data->{cgi}{$option_key}{alert};
$anvil->data->{cgi}{$option_key}{value} = $default if not defined $anvil->data->{cgi}{$option_key}{value}; $anvil->data->{cgi}{$option_key}{value} = $default if not defined $anvil->data->{cgi}{$option_key}{value};
$anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 3, list => { $anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 3, list => {
"cgi::".$option_key."::alert" => $anvil->data->{cgi}{$option_key}{alert},
"cgi::".$option_key."::value" => $anvil->data->{cgi}{$option_key}{value}, "cgi::".$option_key."::value" => $anvil->data->{cgi}{$option_key}{value},
}}); }});
@ -5187,6 +5201,7 @@ sub show_fence_config_main_menu
foreach my $fence_agent (sort {$a cmp $b} keys %{$anvil->data->{fence_data}}) foreach my $fence_agent (sort {$a cmp $b} keys %{$anvil->data->{fence_data}})
{ {
# We don't care about IPMI-based fence agents here. # We don't care about IPMI-based fence agents here.
$anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 3, list => { fence_agent => $fence_agent }});
next if $fence_agent eq "fence_drac5"; next if $fence_agent eq "fence_drac5";
next if $fence_agent eq "fence_idrac"; next if $fence_agent eq "fence_idrac";
next if $fence_agent =~ /^fence_ilo/; next if $fence_agent =~ /^fence_ilo/;
@ -5198,6 +5213,7 @@ sub show_fence_config_main_menu
push @{$agents}, $fence_agent; push @{$agents}, $fence_agent;
my $agent_description = format_fence_description($anvil, $fence_agent, $anvil->data->{fence_data}{$fence_agent}{description}); my $agent_description = format_fence_description($anvil, $fence_agent, $anvil->data->{fence_data}{$fence_agent}{description});
$anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 3, list => { agent_description => $agent_description }});
$description_form .= $anvil->Template->get({file => "anvil.html", name => "fence-agent-description", variables => { $description_form .= $anvil->Template->get({file => "anvil.html", name => "fence-agent-description", variables => {
name => $fence_agent, name => $fence_agent,
@ -8300,7 +8316,7 @@ sub config_step1
# If we don't have an organization name, prefix, domain name or sequence number, try to parse it from # If we don't have an organization name, prefix, domain name or sequence number, try to parse it from
# the current static and pretty host_names. # the current static and pretty host_names.
my ($traditional_host_name, $descriptive_host_name) = $anvil->System->host_name(); my ($traditional_host_name, $descriptive_host_name) = $anvil->System->host_name({debug => 2});
$anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { $anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => {
traditional_host_name => $traditional_host_name, traditional_host_name => $traditional_host_name,
descriptive_host_name => $descriptive_host_name, descriptive_host_name => $descriptive_host_name,

165
notes

@ -1138,6 +1138,171 @@ Architecture: x86_64
====================================
Configure a pair of Dell N-Series switch pair (OS6)
# Using the micro-USB serial interface;
screen /dev/ttyUSB0 115200
console>enable
console#
# Assemble the stack
Port 1 -> 2, 2 -> 1
The stack auto-forms.
# Set management IP address
console#configure terminal
console(config)#interface out-of-band
console(config-if)#ip address 10.201.1.1 255.255.0.0
console(config-if)#exit
# Set a web user and password (obviously, use a better password)
console(config)#no passwords min-length
console(config)#username admin password admin privilege 15
# You should now be able to connect to the web interface
# Show interfaces
console(config)#show interfaces configuration
Port Description Duplex Speed Neg MTU Admin
State
--------- ------------------------------ ------ ------- ---- ----- -----
Gi1/0/1 N/A Unknown Auto 1518 Up
Gi1/0/2 N/A Unknown Auto 1518 Up
Gi1/0/3 Full 100 Auto 1518 Up
Gi1/0/4 Full 100 Auto 1518 Up
Gi1/0/5 N/A Unknown Auto 1518 Up
Gi1/0/6 N/A Unknown Auto 1518 Up
Gi1/0/7 N/A Unknown Auto 1518 Up
Gi1/0/8 N/A Unknown Auto 1518 Up
Gi1/0/9 N/A Unknown Auto 1518 Up
Gi1/0/10 Full 1000 Auto 1518 Up
Gi1/0/11 N/A Unknown Auto 1518 Up
Gi1/0/12 N/A Unknown Auto 1518 Up
Gi1/0/13 N/A Unknown Auto 1518 Up
Gi1/0/14 N/A Unknown Auto 1518 Up
Gi1/0/15 N/A Unknown Auto 1518 Up
Gi1/0/16 N/A Unknown Auto 1518 Up
Gi1/0/17 N/A Unknown Auto 1518 Up
Gi1/0/18 N/A Unknown Auto 1518 Up
Gi1/0/19 N/A Unknown Auto 1518 Up
Gi1/0/20 N/A Unknown Auto 1518 Up
Gi1/0/21 N/A Unknown Auto 1518 Up
Gi1/0/22 N/A Unknown Auto 1518 Up
Gi1/0/23 N/A Unknown Auto 1518 Up
Gi1/0/24 Full 1000 Auto 1518 Up
Tw1/0/1 Full 25000 Off 1518 Up
Tw1/0/2 Full 25000 Off 1518 Up
Tw1/0/3 Full 25000 Off 1518 Up
Tw1/0/4 Full 25000 Off 1518 Up
Fo1/0/1 Full 40000 Off 1518 Up
Fo1/0/2 Full 40000 Off 1518 Up
Gi2/0/1 N/A Unknown Auto 1518 Up
Gi2/0/2 N/A Unknown Auto 1518 Up
Gi2/0/3 N/A Unknown Auto 1518 Up
Gi2/0/4 N/A Unknown Auto 1518 Up
Gi2/0/5 Full 100 Auto 1518 Up
Gi2/0/6 Full 100 Auto 1518 Up
Gi2/0/7 Full 1000 Auto 1518 Up
Gi2/0/8 Full 1000 Auto 1518 Up
Gi2/0/9 N/A Unknown Auto 1518 Up
Gi2/0/10 N/A Unknown Auto 1518 Up
Gi2/0/11 N/A Unknown Auto 1518 Up
Gi2/0/12 N/A Unknown Auto 1518 Up
Gi2/0/13 N/A Unknown Auto 1518 Up
Gi2/0/14 N/A Unknown Auto 1518 Up
Gi2/0/15 N/A Unknown Auto 1518 Up
Gi2/0/16 N/A Unknown Auto 1518 Up
Gi2/0/17 N/A Unknown Auto 1518 Up
Gi2/0/18 N/A Unknown Auto 1518 Up
Gi2/0/19 N/A Unknown Auto 1518 Up
Gi2/0/20 N/A Unknown Auto 1518 Up
Gi2/0/21 N/A Unknown Auto 1518 Up
Gi2/0/22 N/A Unknown Auto 1518 Up
Gi2/0/23 N/A Unknown Auto 1518 Up
Gi2/0/24 N/A Unknown Auto 1518 Up
Tw2/0/1 Full 25000 Off 1518 Up
Tw2/0/2 Full 25000 Off 1518 Up
Tw2/0/3 Full 25000 Off 1518 Up
Tw2/0/4 Full 25000 Off 1518 Up
Fo2/0/1 Full 40000 Off 1518 Up
Fo2/0/2 Full 40000 Off 1518 Up
Oob Type Admin
State
--- ------------------------------ -----
oob Out-Of-Band Up
# Configure VLANs
console(config)#vlan 200
console(config-vlan200)#name SN
# Form the stack;
# Firmware update
console#copy tftp://10.201.4.1/N2200v6.6.3.10.stk backup
====
Transfer Mode.................................. TFTP
Server IP Address.............................. 10.201.4.1
Source File Path............................... ./
Source Filename................................ N2200v6.6.3.10.stk
Data Type...................................... Code
Destination Filename........................... backup
Management access will be blocked for the duration of the transfer
Are you sure you want to start? (y/n) y
File transfer in progress. Management access will be blocked for the duration of the transfer. Please wait...
TFTP Code transfer starting...
40602956 bytes transferred
Attempting to send the STK file to other units in the stack...
File transfer operation completed successfully.
====
console#show version
Machine Description............... Dell EMC Networking Switch
System Model ID................... N2224X-ON
Machine Type...................... Dell EMC Networking N2224X-ON
Serial Number..................... TH0X621WCET000A800GV
Manufacturer...................... 0xbc00
Burned In MAC Address............. 8C47.BE75.9D0F
System Object ID.................. 1.3.6.1.4.1.674.10895.3097
SOC Version....................... BCM56172_B0
HW Version........................ 2
CPLD Version...................... 260
Image File........................ N2200v6.6.1.1
Software Capability............... Stack Limit = 12, VLAN Limit = 4093
unit active backup current-active next-active
---- ----------- ----------- -------------- --------------
1 6.6.1.1 6.6.3.10 6.6.1.1 6.6.1.1
2 6.6.1.1 6.6.3.10 6.6.1.1 6.6.1.1
console#boot system backup
Activating image backup ..
console#reload
Are you sure you want to reload the stack? (y/n) y
<reboots switches, upgrades, reboots again>
==================================== ====================================
-=] Rename a resource (ex: srv09-few-tcpremote1 -> srv09-fea-tcpremote1) -=] Rename a resource (ex: srv09-few-tcpremote1 -> srv09-fea-tcpremote1)
1. pacemaker - 1. pacemaker -

@ -4,5 +4,5 @@ sharedir = ${datarootdir}/anvil
dist_share_DATA = \ dist_share_DATA = \
anvil.sql \ anvil.sql \
words.xml \ firewall.txt \
firewall.txt words.xml

@ -1921,6 +1921,7 @@ Are you sure that you want to delete the server: [#!variable!server_name!#]? [Ty
<key name="message_0244">- Host name: [#!variable!host_name!#] (host UUID: [#!variable!host_uuid!#]:</key> <key name="message_0244">- Host name: [#!variable!host_name!#] (host UUID: [#!variable!host_uuid!#]:</key>
<key name="message_0245">Now purging: [#!variable!host_name!#] (host UUID: [#!variable!host_uuid!#]:</key> <key name="message_0245">Now purging: [#!variable!host_name!#] (host UUID: [#!variable!host_uuid!#]:</key>
<key name="message_0246">Purging the Anvil!: [#!variable!anvil_name!#] (UUID: [#!variable!anvil_uuid!#]:</key> <key name="message_0246">Purging the Anvil!: [#!variable!anvil_name!#] (UUID: [#!variable!anvil_uuid!#]:</key>
<key name="message_0247"><![CDATA[Please specify which server you want to manage with '--server <name_or_uuid>'. Available servers on this Anvil! system;]]></key>
<!-- Success messages shown to the user --> <!-- Success messages shown to the user -->
<key name="ok_0001">Saved the mail server information successfully!</key> <key name="ok_0001">Saved the mail server information successfully!</key>

@ -781,9 +781,11 @@ AND
# Update our status # Update our status
$anvil->Log->entry({source => $THIS_FILE, line => __LINE__, 'print' => 1, level => 2, key => "log_0572"}); $anvil->Log->entry({source => $THIS_FILE, line => __LINE__, 'print' => 1, level => 2, key => "log_0572"});
$anvil->Database->get_hosts({debug => 3}); $anvil->Database->get_hosts({debug => 2});
my $host_uuid = $anvil->Get->host_uuid(); my $host_uuid = $anvil->Get->host_uuid({debug => 2});
$anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 3, list => { host_uuid => $host_uuid }});
$anvil->Database->insert_or_update_hosts({ $anvil->Database->insert_or_update_hosts({
debug => 2,
host_ipmi => $anvil->data->{hosts}{host_uuid}{$host_uuid}{host_ipmi}, host_ipmi => $anvil->data->{hosts}{host_uuid}{$host_uuid}{host_ipmi},
host_key => $anvil->data->{hosts}{host_uuid}{$host_uuid}{host_key}, host_key => $anvil->data->{hosts}{host_uuid}{$host_uuid}{host_key},
host_name => $anvil->data->{hosts}{host_uuid}{$host_uuid}{host_name}, host_name => $anvil->data->{hosts}{host_uuid}{$host_uuid}{host_name},

@ -0,0 +1,198 @@
#!/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:
#
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->data->{switches}{'boot'} = ""; # This is a comma-separated list of ordered boot devices
$anvil->data->{switches}{'cores'} = ""; # This sets the server to use this number of CPU cores.
$anvil->data->{switches}{'drive'} = ""; # drive being modified (insert/eject ISO, growing drive)
$anvil->data->{switches}{'eject'} = ""; # This will eject whatever ISO (if any) in the '--drive'.
$anvil->data->{switches}{'expand-to'} = ""; # When the drive is a disk (backed by a DRBD resource), this is the new desired size to grow to.
$anvil->data->{switches}{'insert'} = ""; # This is the ISO to insert into the --drive
$anvil->data->{switches}{'job-uuid'} = "";
$anvil->data->{switches}{'ram'} = ""; # This is the amount of RAM to set the server to use.
$anvil->data->{switches}{'server'} = ""; # server name or uuid
$anvil->data->{switches}{'y'} = ""; # Don't prompt for confirmation. Only useful when there isn't a job UUID.
$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::boot' => $anvil->data->{switches}{'boot'},
'switches::cores' => $anvil->data->{switches}{'cores'},
'switches::drive' => $anvil->data->{switches}{'drive'},
'switches::eject' => $anvil->data->{switches}{'eject'},
'switches::expand-to' => $anvil->data->{switches}{'expand-to'},
'switches::insert' => $anvil->data->{switches}{'insert'},
'switches::job-uuid' => $anvil->data->{switches}{'job-uuid'},
'switches::ram' => $anvil->data->{switches}{'ram'},
'switches::server' => $anvil->data->{switches}{'server'},
'switches::y' => $anvil->data->{switches}{'y'},
}});
# 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 => 2, secure => 0, key => "log_0132"});
# Make sure we're in an Anvil!
$anvil->data->{sys}{anvil_uuid} = $anvil->Cluster->get_anvil_uuid();
$anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => {
'sys::anvil_uuid' => $anvil->data->{sys}{anvil_uuid},
}});
if (not $anvil->data->{sys}{anvil_uuid})
{
$anvil->Log->entry({source => $THIS_FILE, line => __LINE__, 'print' => 1, level => 0, priority => "err", key => "error_0260"});
$anvil->Job->update_progress({progress => 100, message => "error_0260"});
$anvil->nice_exit({exit_code => 1});
}
# Load servers and resources.
$anvil->Database->get_servers();
$anvil->DRBD->gather_data({debug => 2});
$anvil->Get->available_resources({
debug => 2,
anvil_uuid => $anvil->data->{sys}{anvil_uuid},
});
# Do we have a server (name or UUID)?
if ($anvil->Validate->uuid({uuid => $anvil->data->{switches}{server}}))
{
$anvil->data->{sys}{server_uuid} = $anvil->data->{switches}{server};
$anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => {
"sys::server_uuid" => $anvil->data->{sys}{server_uuid},
}});
# Find the server name
my $server_uuid = $anvil->data->{sys}{server_uuid};
if (exists $anvil->data->{servers}{server_uuid}{$server_uuid})
{
$anvil->data->{sys}{server_name} = $anvil->data->{servers}{server_uuid}{$server_uuid}{server_name};
$anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => {
"sys::server_name" => $anvil->data->{sys}{server_name},
}});
}
}
elsif ($anvil->data->{switches}{server})
{
$anvil->data->{sys}{server_name} = $anvil->data->{switches}{server};
$anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => {
"sys::server_name" => $anvil->data->{sys}{server_name},
}});
# Get the server UUID.
my $anvil_uuid = $anvil->data->{sys}{anvil_uuid};
my $server_name = $anvil->data->{sys}{server_name};
if (exists $anvil->data->{servers}{anvil_uuid}{$anvil_uuid}{server_name}{$server_name})
{
$anvil->data->{sys}{server_uuid} = $anvil->data->{servers}{anvil_uuid}{$anvil_uuid}{server_name}{$server_name}{server_uuid};
$anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => {
"sys::server_uuid" => $anvil->data->{sys}{server_uuid},
}});
}
}
# Do we have a valid server?
if ((not $anvil->data->{sys}{server_name}) or (not $anvil->data->{sys}{server_uuid}))
{
$anvil->Log->entry({source => $THIS_FILE, line => __LINE__, 'print' => 1, level => 0, key => "message_0247"});
my $anvil_uuid = $anvil->data->{sys}{anvil_uuid};
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};
print "- ".$server_name." (".$server_uuid.")\n";
}
}
# Show the server's existing stats.
show_stats($anvil);
$anvil->nice_exit({exit_code => 0});
#############################################################################################################
# Functions #
#############################################################################################################
sub show_stats
{
my ($anvil) = @_;
# Load the server's details.
my $server_xml = $anvil->Server->get_definition({server_uuid => $anvil->data->{sys}{server_uuid}});
my $server_name = $anvil->data->{sys}{server_name};
my $short_host_name = $anvil->Get->short_host_name();
$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_xml' => $server_xml,
}});
$anvil->Server->parse_definition({
debug => 2,
source => "from_db",
definition => $server_xml,
server => $server_name,
});
my $cpu_cores = $anvil->data->{server}{$short_host_name}{$server_name}{from_db}{cpu}{total_cores};
my $ram_bytes = $anvil->data->{server}{$short_host_name}{$server_name}{from_db}{memory};
my $say_ram = $anvil->Convert->bytes_to_human_readable({'bytes' => $ram_bytes});
print "Cores: [".$cpu_cores."], RAM: [".$say_ram."] (".$ram_bytes." bytes)\n";
# Show disks
foreach my $device ("disk", "cdrom")
{
print "- Device: [".$device."]\n";
foreach my $device_target (sort {$a cmp $b} keys %{$anvil->data->{server}{$short_host_name}{$server_name}{from_db}{device}{$device}{target}})
{
my $boot_order = $anvil->data->{server}{$short_host_name}{$server_name}{from_db}{device}{$device}{target}{$device_target}{boot_order};
my $type = $anvil->data->{server}{$short_host_name}{$server_name}{from_db}{device}{$device}{target}{$device_target}{type};
my $device_bus = $anvil->data->{server}{$short_host_name}{$server_name}{from_db}{device}{$device}{target}{$device_target}{device_bus};
my $path = $anvil->data->{server}{$short_host_name}{$server_name}{from_db}{device}{$device}{target}{$device_target}{path};
print " - Target: [".$device_target."], type: [".$type."], boot order: [".$boot_order."], bus: [".$device_bus."]\n";
print " - Path: [".$path."]\n";
if ($device eq "disk")
{
# Pull the size
my $volume = ($path =~ /\/(\d+)$/)[0];
print " - Volume: [".$volume."]\n";
foreach my $host_name (sort {$a cmp $b} keys %{$anvil->data->{new}{resource}{$server_name}{host}})
{
my $host_uuid = $anvil->Get->host_uuid_from_name({host_name => $host_name});
my $device_path = $anvil->data->{new}{resource}{$server_name}{host}{$host_name}{volume}{$volume}{device_path};
my $backing_disk = $anvil->data->{new}{resource}{$server_name}{host}{$host_name}{volume}{$volume}{backing_disk};
print " - Host: [".$host_name."] (".$host_uuid."), path: [".$device_path."], backing disk: [".$backing_disk."]\n";
}
}
else
{
}
}
}
return(0);
}

@ -1,42 +0,0 @@
#!/usr/bin/perl
#
# This program will manage storage; 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:
#
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->data->{switches}{'server'} = ""; # server name or uuid
$anvil->data->{switches}{'anvil'} = ""; # Only required for server name collisions
$anvil->data->{switches}{'drive'} = ""; # drive
$anvil->data->{switches}{'expand-to'} = "";
$anvil->data->{switches}{'insert-iso'} = "";
$anvil->data->{switches}{'eject-iso'} = "";
$anvil->data->{switches}{'show'} = "";
$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'},
}});

@ -35,7 +35,6 @@ if (($running_directory =~ /^\./) && ($ENV{PWD}))
$| = 1; $| = 1;
my $anvil = Anvil::Tools->new(); my $anvil = Anvil::Tools->new();
$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->entry({source => $THIS_FILE, line => __LINE__, 'print' => 1, level => 1, secure => 0, key => "log_0115", variables => { program => $THIS_FILE }});
# Make sure we're running as 'root' # Make sure we're running as 'root'

@ -464,7 +464,7 @@ sub update_network
# Skip if this isn't the device type we're working on. # Skip if this isn't the device type we're working on.
next if not defined $anvil->data->{network}{$local_host}{interface}{$interface}{type}; next if not defined $anvil->data->{network}{$local_host}{interface}{$interface}{type};
my $type = $anvil->data->{network}{$local_host}{interface}{$interface}{type}; my $type = $anvil->data->{network}{$local_host}{interface}{$interface}{type};
$anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 3, list => { $anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => {
's1:interface' => $interface, 's1:interface' => $interface,
's2:type' => $type, 's2:type' => $type,
's3:processing' => $processing, 's3:processing' => $processing,
@ -531,10 +531,10 @@ sub update_network
bridge_mtu => $mtu, bridge_mtu => $mtu,
bridge_stp_enabled => $bridge_stp_enabled, bridge_stp_enabled => $bridge_stp_enabled,
}); });
$anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 3, list => { bridge_uuid => $bridge_uuid }}); $anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { bridge_uuid => $bridge_uuid }});
$anvil->data->{bridge_by_name}{$interface} = $bridge_uuid; $anvil->data->{bridge_by_name}{$interface} = $bridge_uuid;
$anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 3, list => { "bridge_by_name::${interface}" => $anvil->data->{bridge_by_name}{$interface} }}); $anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { "bridge_by_name::${interface}" => $anvil->data->{bridge_by_name}{$interface} }});
if (($bridge_uuid) && ($ip_address)) if (($bridge_uuid) && ($ip_address))
{ {
my $ip_address_uuid = $anvil->Database->insert_or_update_ip_addresses({ my $ip_address_uuid = $anvil->Database->insert_or_update_ip_addresses({
@ -617,19 +617,19 @@ sub update_network
# Is this interface connected to a bridge? # Is this interface connected to a bridge?
my $network_interface_bridge_uuid = ""; my $network_interface_bridge_uuid = "";
my $network_interface_on_bridge = exists $anvil->data->{interface_to_bridge}{$interface} ? $anvil->data->{interface_to_bridge}{$interface} : ""; my $network_interface_on_bridge = exists $anvil->data->{interface_to_bridge}{$interface} ? $anvil->data->{interface_to_bridge}{$interface} : "";
$anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 3, list => { network_interface_on_bridge => $network_interface_on_bridge }}); $anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { network_interface_on_bridge => $network_interface_on_bridge }});
if ($network_interface_on_bridge) if ($network_interface_on_bridge)
{ {
$network_interface_bridge_uuid = $anvil->data->{bridge_by_name}{$network_interface_on_bridge}; $network_interface_bridge_uuid = $anvil->data->{bridge_by_name}{$network_interface_on_bridge};
$anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 3, list => { network_interface_bridge_uuid => $network_interface_bridge_uuid }}); $anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { network_interface_bridge_uuid => $network_interface_bridge_uuid }});
} }
my $say_bond_uuid = ""; my $say_bond_uuid = "";
$anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 3, list => { bond_master => $bond_master }}); $anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { bond_master => $bond_master }});
if (($bond_master) && ($anvil->data->{bond_by_name}{$bond_master})) if (($bond_master) && ($anvil->data->{bond_by_name}{$bond_master}))
{ {
$say_bond_uuid = $anvil->data->{bond_by_name}{$bond_master}; $say_bond_uuid = $anvil->data->{bond_by_name}{$bond_master};
$anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 3, list => { $anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => {
"bond_by_name::${bond_master}" => $anvil->data->{bond_by_name}{$bond_master}, "bond_by_name::${bond_master}" => $anvil->data->{bond_by_name}{$bond_master},
say_bond_uuid => $say_bond_uuid, say_bond_uuid => $say_bond_uuid,
}}); }});
@ -637,7 +637,7 @@ sub update_network
if ($anvil->data->{sys}{database}{connections}) if ($anvil->data->{sys}{database}{connections})
{ {
my $network_interface_uuid = $anvil->Database->insert_or_update_network_interfaces({ my $network_interface_uuid = $anvil->Database->insert_or_update_network_interfaces({
debug => 3, debug => 2,
file => $THIS_FILE, file => $THIS_FILE,
line => __LINE__, line => __LINE__,
network_interface_bond_uuid => $say_bond_uuid, network_interface_bond_uuid => $say_bond_uuid,
@ -651,10 +651,10 @@ sub update_network
network_interface_mtu => $mtu, network_interface_mtu => $mtu,
network_interface_speed => $speed, network_interface_speed => $speed,
}); });
$anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 3, list => { network_interface_uuid => $network_interface_uuid }}); $anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { network_interface_uuid => $network_interface_uuid }});
$anvil->data->{interface_by_name}{$interface} = $network_interface_uuid; $anvil->data->{interface_by_name}{$interface} = $network_interface_uuid;
$anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 3, list => { "interface_by_name::${interface}" => $anvil->data->{interface_by_name}{$interface} }}); $anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { "interface_by_name::${interface}" => $anvil->data->{interface_by_name}{$interface} }});
if (($network_interface_uuid) && ($ip_address)) if (($network_interface_uuid) && ($ip_address))
{ {
my $ip_address_uuid = $anvil->Database->insert_or_update_ip_addresses({ my $ip_address_uuid = $anvil->Database->insert_or_update_ip_addresses({

@ -100,7 +100,7 @@ if (($conf->{'system'}{action} eq "monitor") or ($conf->{'system'}{action} eq "l
do_wait($conf, $log); do_wait($conf, $log);
# Cleanup and exit. # Cleanup and exit.
do_exit($conf, $log, ); do_exit($conf, $log);
############################################################################### ###############################################################################

Loading…
Cancel
Save