* Created Cluster->delete_server(), which deletes a server resource from pacemaker (stopping it first, if needed).

* Fixed a bug in Cluster->parse_cib() when a server that is off wasn't setting 'status'.
* Renamed 'server::location::<server>::host' to '...::host_name' in several places.
* Got more work done on anvil-delete-server, up to the point where it calls the new Cluster->delete_server() method.
* Updated fence_pacemaker to call 'drbdadm adjust all' to dampen an issue where in-memory fence configs seem to change, preventing reconnection of the peer after it reboots from the fence. More testing needed on this issue.

Signed-off-by: Digimer <digimer@alteeve.ca>
main
Digimer 4 years ago
parent d9d347ce63
commit 549dbad635
  1. 1
      Anvil/Tools.pm
  2. 133
      Anvil/Tools/Cluster.pm
  3. 4
      Anvil/Tools/Database.pm
  4. 2
      Anvil/Tools/Get.pm
  5. 24
      Anvil/Tools/Server.pm
  6. 9
      notes
  7. 18
      ocf/alteeve/server
  8. 0
      scancore.README
  9. 0
      share/firewall.txt
  10. 32
      share/words.xml
  11. 449
      tools/anvil-delete-server
  12. 17
      tools/fence_pacemaker
  13. 2
      tools/test.pl

@ -1086,6 +1086,7 @@ sub _set_paths
'anvil-check-memory' => "/usr/sbin/anvil-check-memory",
'anvil-configure-host' => "/usr/sbin/anvil-configure-host",
'anvil-daemon' => "/usr/sbin/anvil-daemon",
'anvil-delete-server' => "/usr/sbin/anvil-delete-server",
'anvil-download-file' => "/usr/sbin/anvil-download-file",
'anvil-file-details' => "/usr/sbin/anvil-file-details",
'anvil-join-anvil' => "/usr/sbin/anvil-join-anvil",

@ -18,6 +18,7 @@ my $THIS_FILE = "Cluster.pm";
# assemble_storage_groups
# boot_server
# check_node_status
# delete_server
# get_anvil_name
# get_anvil_uuid
# get_peers
@ -187,7 +188,7 @@ sub add_server
# The host here is the full host name.
my $host_name = $anvil->Get->host_name();
my $server_state = $anvil->data->{server}{location}{$server_name}{status};
my $server_host = $anvil->data->{server}{location}{$server_name}{host};
my $server_host = $anvil->data->{server}{location}{$server_name}{host_name};
my $target_role = $server_state eq "running" ? "started" : "stopped";
$anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => {
host_name => $host_name,
@ -711,12 +712,118 @@ sub check_node_status
return($anvil->data->{cib}{parsed}{data}{node}{$node_name}{node_state}{ready});
}
=head2 delete_server
This takes a server (resource) name and deletes it from pacemaker. If there is a problem, C<< !!error!! >> is returned. Otherwise, C<< 0 >> is removed either once the resource is deleted, or if the resource didn't exist in the first place.
Parameters;
=head3 server_name (required)
This is the name of the resource to delete.
=cut
sub delete_server
{
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 => "Cluster->delete_server()" }});
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 => "Cluster->delete_server()", parameter => "server_name" }});
return('!!error!!');
}
my $problem = $anvil->Cluster->parse_cib({debug => $debug});
$anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => $debug, list => { problem => $problem }});
if ($problem)
{
$anvil->Log->entry({source => $THIS_FILE, line => __LINE__, level => 0, priority => "err", key => "error_0224", variables => { server_name => $server_name }});
return('!!error!!');
}
# Is this node fully in the cluster?
if (not $anvil->data->{cib}{parsed}{'local'}{ready})
{
$anvil->Log->entry({source => $THIS_FILE, line => __LINE__, level => 0, priority => "err", key => "error_0225", variables => { server_name => $server_name }});
return('!!error!!');
}
# Does the server exist in the config?
if (not exists $anvil->data->{cib}{parsed}{data}{server}{$server_name})
{
# The server is already gone.
$anvil->Log->entry({source => $THIS_FILE, line => __LINE__, level => 0, priority => "err", key => "error_0149", variables => { server_name => $server_name }});
return(0);
}
# Is the server running? If so, stop it first.
my $status = $anvil->data->{cib}{parsed}{data}{server}{$server_name}{status};
my $host = $anvil->data->{cib}{parsed}{data}{server}{$server_name}{host};
$anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => $debug, list => {
status => $status,
host => $host,
}});
# Stop the server
if ($status eq "running")
{
my $problem = $anvil->Cluster->shutdown_server({
server => $server_name,
'wait' => 1,
});
if ($problem)
{
# Failed to stop.
$anvil->Log->entry({source => $THIS_FILE, line => __LINE__, level => 0, priority => 'err', key => "error_0223", variables => { server_name => $server_name }});
return('!!error!!');
}
}
# Now delete the resource. Any constraints will be deleted automatically.
my ($output, $return_code) = $anvil->System->call({debug => $debug, shell_call => $anvil->data->{path}{exe}{pcs}." resource delete ".$server_name});
$anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => $debug, list => {
output => $output,
return_code => $return_code,
}});
if (not $return_code)
{
# Success!
$anvil->Log->entry({source => $THIS_FILE, line => __LINE__, level => 1, key => "log_0587", variables => { server_name => $server_name }});
return(0);
}
else
{
# Unexpected return code.
$anvil->Log->entry({source => $THIS_FILE, line => __LINE__, level => 0, priority => 'err', key => "error_0226", variables => {
server_name => $server_name,
return_code => $return_code,
output => $$output,
}});
return('!!error!!');
}
return(0);
}
=head2 get_anvil_name
This returns the C<< anvils >> -> C<< anvil_name >> for a given C<< anvil_uuid >>. If no C<< anvil_uuid >> is passed, a check is made to see if this host is in an Anvil! and, if so, the Anvil! name it's a member of is returned.
If not match is found, a blank string is returned.
my $anvil_name = $anvil->Cluster->get_anvil_name({anvil_uuid => "2ac4dbcb-25d2-44b2-ae07-59707b0551ca"});
Parameters;
=head3 anvil_uuid (optional, default Cluster->get_anvil_uuid)
@ -1405,7 +1512,7 @@ sub migrate_server
role => $role,
}});
if ($status eq "off")
if (($status eq "off") or ($status eq "stopped"))
{
# It's not running on either node, nothing to do.
$anvil->Log->entry({source => $THIS_FILE, line => __LINE__, level => 1, key => "warning_0061", variables => {
@ -2136,8 +2243,8 @@ sub parse_cib
});
foreach my $server (sort {$a cmp $b} keys %{$anvil->data->{crm_mon}{parsed}{'pacemaker-result'}{resources}{resource}})
{
my $host_name = $anvil->data->{crm_mon}{parsed}{'pacemaker-result'}{resources}{resource}{$server}{host}{node_name};
my $host_id = $anvil->data->{crm_mon}{parsed}{'pacemaker-result'}{resources}{resource}{$server}{host}{node_id};
my $host_name = defined $anvil->data->{crm_mon}{parsed}{'pacemaker-result'}{resources}{resource}{$server}{host}{node_name} ? $anvil->data->{crm_mon}{parsed}{'pacemaker-result'}{resources}{resource}{$server}{host}{node_name} : "";
my $host_id = defined $anvil->data->{crm_mon}{parsed}{'pacemaker-result'}{resources}{resource}{$server}{host}{node_id} ? $anvil->data->{crm_mon}{parsed}{'pacemaker-result'}{resources}{resource}{$server}{host}{node_id} : "";
my $role = $anvil->data->{crm_mon}{parsed}{'pacemaker-result'}{resources}{resource}{$server}{variables}{role};
my $active = $anvil->data->{crm_mon}{parsed}{'pacemaker-result'}{resources}{resource}{$server}{variables}{active} eq "true" ? 1 : 0;
my $blocked = $anvil->data->{crm_mon}{parsed}{'pacemaker-result'}{resources}{resource}{$server}{variables}{blocked} eq "true" ? 1 : 0;
@ -2152,7 +2259,7 @@ sub parse_cib
# Starting
# Migrating
# Stopping
$status = "running";
$status = $active ? "running" : "off";
# If the role is NOT 'migating', check to see if it's marked as such in the database.
if ($role ne "migrating")
@ -2207,7 +2314,7 @@ sub parse_cib
$anvil->data->{cib}{parsed}{data}{server}{$server}{failed} = $failed;
$anvil->data->{cib}{parsed}{data}{server}{$server}{managed} = $managed;
$anvil->data->{cib}{parsed}{data}{server}{$server}{orphaned} = $orphaned;
$anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => $debug, list => {
$anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => {
"cib::parsed::data::server::${server}::status" => $anvil->data->{cib}{parsed}{data}{server}{$server}{status},
"cib::parsed::data::server::${server}::host_name" => $anvil->data->{cib}{parsed}{data}{server}{$server}{host_name},
"cib::parsed::data::server::${server}::host_id" => $anvil->data->{cib}{parsed}{data}{server}{$server}{host_id},
@ -2227,7 +2334,7 @@ sub parse_cib
my $host_name = $anvil->data->{cib}{parsed}{data}{server}{$server}{host_name};
my $role = $anvil->data->{cib}{parsed}{data}{server}{$server}{role};
my $active = $anvil->data->{cib}{parsed}{data}{server}{$server}{active};
$anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => $debug, list => {
$anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => {
's1:server' => $server,
's2:status' => $status,
's2:host_name' => $host_name,
@ -2384,7 +2491,9 @@ sub parse_crm_mon
=head2 shutdown_server
This shuts down a server that is running on the Anvil! system.
This shuts down a server that is running on the Anvil! system. If there is a problem, C<< !!error!! >> is returned. On success, C<< 0 >> is returned.
B<< Note >>: If C<< wait >> is set to C<< 0 >>, then C<< 0 >> is returned once the shutdown is requested, not when it's actually turned off.
Parameters;
@ -2449,15 +2558,15 @@ sub shutdown_server
return('!!error!!');
}
# Is the server already running? If so, do nothing.
# Is the server already stopped? If so, do nothing.
my $status = $anvil->data->{cib}{parsed}{data}{server}{$server}{status};
my $host = $anvil->data->{cib}{parsed}{data}{server}{$server}{host};
my $host = defined $anvil->data->{cib}{parsed}{data}{server}{$server}{host} ? $anvil->data->{cib}{parsed}{data}{server}{$server}{host} : "";
$anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => $debug, list => {
status => $status,
host => $host,
}});
if ($status eq "off")
if (($status eq "off") or ($status eq "stopped"))
{
# Already off.
$anvil->Log->entry({source => $THIS_FILE, line => __LINE__, level => 2, key => "log_0548", variables => { server => $server }});
@ -2475,7 +2584,7 @@ sub shutdown_server
}
# Now shut down the server.
my ($output, $return_code) = $anvil->System->call({debug => 3, shell_call => $anvil->data->{path}{exe}{pcs}." resource disable ".$server});
my ($output, $return_code) = $anvil->System->call({debug => $debug, shell_call => $anvil->data->{path}{exe}{pcs}." resource disable ".$server});
$anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => $debug, list => {
output => $output,
return_code => $return_code,

@ -3863,6 +3863,10 @@ This loads all known servers from the database.
servers::server_uuid::<server_uuid>::server_updated_by_user
servers::server_uuid::<server_uuid>::server_boot_time
To simplify lookup of server UUIDs by server names, this hash is also set;
servers::anvil_uuid::<anvil_uuid>::server_name::<server_name>::server_uuid
This method takes no parameters.
=cut

@ -1283,6 +1283,8 @@ WHERE
This takes a host name and looks for a UUID from the C<< hosts >> table). If the entry is not found, an empty string is returned.
my $host_uuid = $anvil->Get->host_uuid_from_name({host_name => "an-a02n01.alteeve.com"});
Parameters;
=head3 host_name (required)

@ -145,7 +145,7 @@ sub boot_virsh
while($wait)
{
$anvil->Server->find({debug => $debug});
if ((exists $anvil->data->{server}{location}{$server}) && ($anvil->data->{server}{location}{$server}{host}))
if ((exists $anvil->data->{server}{location}{$server}) && ($anvil->data->{server}{location}{$server}{host_name}))
{
# Success!
$wait = 0;
@ -156,7 +156,7 @@ sub boot_virsh
}});
$anvil->Log->entry({source => $THIS_FILE, line => __LINE__, level => 1, key => "log_0421", variables => {
server => $server,
host => $anvil->data->{server}{location}{$server}{host},
host => $anvil->data->{server}{location}{$server}{host_name},
}});
$anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => $debug, list => { "sys::database::connections" => $anvil->data->{sys}{database}{connections} }});
@ -229,8 +229,8 @@ This will look on the local or a remote machine for the list of servers that are
The list is stored as;
server::location::<server>::status = <status>
server::location::<server>::host = <host_name>
server::location::<server_name>::status = <status>
server::location::<server_name>::host = <host_name>
Parameters;
@ -283,7 +283,7 @@ sub find
}
my $host_type = $anvil->Get->host_type({debug => $debug});
my $host = $anvil->Get->host_name;
my $host_name = $anvil->Get->host_name;
my $virsh_output = "";
my $return_code = "";
if ($anvil->Network->is_local({host => $target}))
@ -298,7 +298,7 @@ sub find
else
{
# Remote call.
($host, my $error, my $host_return_code) = $anvil->Remote->call({
($host_name, my $error, my $host_return_code) = $anvil->Remote->call({
debug => 2,
password => $password,
shell_call => $anvil->data->{path}{exe}{hostnamectl}." --static",
@ -306,7 +306,7 @@ sub find
remote_user => "root",
});
$anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => $debug, list => {
host => $host,
host_name => $host_name,
error => $error,
host_return_code => $host_return_code,
}});
@ -331,12 +331,12 @@ sub find
if ($line =~ /^\d+ (.*) (.*?)$/)
{
my $server = $1;
$anvil->data->{server}{location}{$server}{status} = $2;
$anvil->data->{server}{location}{$server}{host} = $host;
my $server_name = $1;
$anvil->data->{server}{location}{$server_name}{status} = $2;
$anvil->data->{server}{location}{$server_name}{host_name} = $host_name;
$anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => $debug, list => {
"server::location::${server}::status" => $anvil->data->{server}{location}{$server}{status},
"server::location::${server}::host" => $anvil->data->{server}{location}{$server}{host},
"server::location::${server_name}::status" => $anvil->data->{server}{location}{$server_name}{status},
"server::location::${server_name}::host_name" => $anvil->data->{server}{location}{$server_name}{host_name},
}});
}
}

@ -277,11 +277,12 @@ pcs property set stonith-enabled=true
# Create a new server resource, stopped, create the location constraint (higher == preferred), then start.
pcs resource create srv07-el6 ocf:alteeve:server name="srv07-el6" meta allow-migrate="true" target-role="stopped" op monitor interval="60" start timeout="INFINITY" on-fail="block" stop timeout="INFINITY" on-fail="block" migrate_to timeout="INFINITY"
pcs constraint location srv07-el6 prefers mk-a02n01=200 mk-a02n02=100
pcs resource enable srv07-el6
pcs resource create srv01-test ocf:alteeve:server name="srv01-test" meta allow-migrate="true" target-role="stopped" op monitor interval="60" start timeout="INFINITY" on-fail="block" stop timeout="INFINITY" on-fail="block" migrate_to timeout="INFINITY"
pcs constraint location srv01-test prefers mk-a02n01=200 mk-a02n02=100
pcs resource enable srv01-test
- or -
pcs resource update srv07-el6 ocf:alteeve:server name="srv07-el6" meta allow-migrate="true" target-role="stopped" op monitor interval="60" start timeout="INFINITY" on-fail="block" stop timeout="INFINITY" on-fail="block" migrate_to timeout="INFINITY"
pcs resource update srv01-test ocf:alteeve:server name="srv01-test" meta allow-migrate="true" target-role="stopped" op monitor interval="60" start timeout="INFINITY" on-fail="block" stop timeout="INFINITY" on-fail="block" migrate_to timeout="INFINITY"
# Test
stonith_admin --fence el8-a01n02 --verbose; crm_error $?

@ -689,7 +689,7 @@ sub start_server
# WTF?
$anvil->Log->entry({source => $THIS_FILE, line => __LINE__, level => 0, priority => "err", key => "log_0310", variables => {
server => $server,
'state' => defined $anvil->data->{server}{location}{$server}{host} ? $anvil->data->{server}{location}{$server}{host} : "#!string!unit_0003!#",
'state' => defined $anvil->data->{server}{location}{$server}{host_name} ? $anvil->data->{server}{location}{$server}{host_name} : "#!string!unit_0003!#",
}});
$anvil->nice_exit({exit_code => 6});
}
@ -902,19 +902,19 @@ sub find_server
foreach my $this_server (sort {$a cmp $b} keys %{$anvil->data->{server}{location}})
{
my $status = $anvil->data->{server}{location}{$this_server}{status};
my $host = $anvil->data->{server}{location}{$this_server}{host};
my $host = $anvil->data->{server}{location}{$this_server}{host_name};
$anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => {
this_server => $this_server,
status => $status,
host => $host,
}});
}
if ((exists $anvil->data->{server}{location}{$server}) && ($anvil->data->{server}{location}{$server}{host}))
if ((exists $anvil->data->{server}{location}{$server}) && ($anvil->data->{server}{location}{$server}{host_name}))
{
# The server is running. If it is running here, exit with success. If it's running elsewhere,
# exit with a failure.
my $status = $anvil->data->{server}{location}{$server}{status};
my $host = $anvil->data->{server}{location}{$server}{host};
my $host = $anvil->data->{server}{location}{$server}{host_name};
$anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => {
status => $status,
host => $host,
@ -1254,7 +1254,7 @@ sub migrate_server
# Find the server
$anvil->Server->find({debug => 3});
my $server_host = defined $anvil->data->{server}{location}{$server}{host} ? $anvil->data->{server}{location}{$server}{host} : "";
my $server_host = defined $anvil->data->{server}{location}{$server}{host_name} ? $anvil->data->{server}{location}{$server}{host_name} : "";
my $server_status = defined $anvil->data->{server}{location}{$server}{status} ? $anvil->data->{server}{location}{$server}{status} : "";
$anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => {
server_host => $server_host,
@ -1266,7 +1266,7 @@ sub migrate_server
{
# Maybe...
$anvil->Server->find({debug => 3, target => $target});
$server_host = defined $anvil->data->{server}{location}{$server}{host} ? $anvil->data->{server}{location}{$server}{host} : "";
$server_host = defined $anvil->data->{server}{location}{$server}{host_name} ? $anvil->data->{server}{location}{$server}{host_name} : "";
$server_status = defined $anvil->data->{server}{location}{$server}{status} ? $anvil->data->{server}{location}{$server}{status} : "";
$anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => {
server_host => $server_host,
@ -1404,7 +1404,7 @@ sub migrate_server
$anvil->Server->find({debug => 2});
$anvil->Server->find({debug => 2, target => $meta_on_node, refresh => 0});
my $host = defined $anvil->data->{server}{location}{$server}{host} ? $anvil->data->{server}{location}{$server}{host} : "";
my $host = defined $anvil->data->{server}{location}{$server}{host_name} ? $anvil->data->{server}{location}{$server}{host_name} : "";
my $short_host = ($host =~ /^(.*?)\..*$/)[0];
my $status = defined $anvil->data->{server}{location}{$server}{status} ? $anvil->data->{server}{location}{$server}{status} : "";
$anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => {
@ -1415,7 +1415,7 @@ sub migrate_server
}});
# Convert the host to a short name, in case the node's name is the short version.
my $server_host = defined $anvil->data->{server}{location}{$server}{host} ? $anvil->data->{server}{location}{$server}{host} : "";
my $server_host = defined $anvil->data->{server}{location}{$server}{host_name} ? $anvil->data->{server}{location}{$server}{host_name} : "";
my $server_status = defined $anvil->data->{server}{location}{$server}{status} ? $anvil->data->{server}{location}{$server}{status} : "";
$anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => {
server_host => $server_host,
@ -1567,7 +1567,7 @@ sub validate_storage
}});
my $local_host = $anvil->Get->short_host_name();
my $xml_source = "from_disk";
if ($anvil->data->{server}{$local_host}{$server}{from_virsh}{host})
if ($anvil->data->{server}{$local_host}{$server}{from_virsh}{host_name})
{
$xml_source = "from_virsh";
}

@ -298,6 +298,18 @@ Output (if any):
<key name="error_0213">Failed to add the server: [#!variable!server_name!#] because it appears to already exist in the cluster.</key>
<key name="error_0214">Failed to add the server: [#!variable!server_name!#]. After the commands to add it ran, it was still not found in the cluster.</key>
<key name="error_0215">It looks like something went wrong while adding the server to the cluster. There should be more information in the logs.</key>
<key name="error_0216">It looks like something went wrong while removing the server from the cluster. There should be more information in the logs.</key>
<key name="error_0217">This host is not an Anvil! node or DR host, unable to delete servers.</key>
<key name="error_0218">Unable to connect to any databases, unable to continue.</key>
<key name="error_0219">Unable to find the server uuid to delete from the job UUID: [#!variable!job_uuid!#].</key>
<key name="error_0220">Unable to find a server name to match the server UUID: [#!variable!server_uuid!#].</key>
<key name="error_0221">The server: [#!variable!server_name!#] is already marked as DELETED.</key>
<key name="error_0222">The cluster does not appear to be running, unable to delete a server at this time. We'll sleep for a bit and then exit, and the try again.</key>
<key name="error_0223">The server: [#!variable!server_name!#] appears to have failed to stop.</key>
<key name="error_0224">Unable to delete the server resource: [#!variable!server_name!#] as the cluster isn't running or there was a problem parsing the cluster CIB.</key>
<key name="error_0225">Unable to delete the server resource: [#!variable!server_name!#] as this node is not (yet) a full member of the cluster.</key>
<key name="error_0226">It looks like to removal of the server resource: [#!variable!server_name!#] failed. The return code should have been '0', but: [#!variable!return_code!#] was returned. The 'pcs' command output, if any, was: [#!variable!output!#].</key>
<key name="error_0227">It looks like to removal of the server resource: [#!variable!server_name!#] failed. Unsafe to proceed with the removal of the server. Please check the logs for more information.</key>
<!-- Files templates -->
<!-- NOTE: Translating these files requires an understanding of which likes are translatable -->
@ -623,6 +635,10 @@ It should be provisioned in the next minute or two.</key>
<key name="job_0205">As we're the peer, we're now going to wait for the new server definition to be added to the database, then write it out to disk.</key>
<key name="job_0206">The definition file: [#!variable!file!#] has been saved.</key>
<key name="job_0207">Preparing to add the server to the central cluster manager.</key>
<key name="job_0208">Deleting a server</key>
<key name="job_0209">This deletes a server from an Anvil! system.</key>
<key name="job_0210">Asking pacemaker to stop the server: [#!variable!server_name!#].</key>
<key name="job_0211">The server: [#!variable!server_name!#] is now stopped in pacemaker.</key>
<!-- Log entries -->
<key name="log_0001">Starting: [#!variable!program!#].</key>
@ -1299,6 +1315,11 @@ The file: [#!variable!file!#] needs to be updated. The difference is:
<key name="log_0580">The LV(s) behind the resource: [#!variable!resource!#] have been forced to primary to initialize the resource.</key>
<key name="log_0581">Asked to validate that the server: [#!variable!server!#] is able to run.</key>
<key name="log_0582">We've been asked to stop the server: [#!variable!server!#].</key>
<key name="log_0583">The server: [#!variable!server_name!#] is already off.</key>
<key name="log_0584">The request to stop: [#!variable!server_name!#] has been sent. We'll now check periodically waiting for it to stop.</key>
<key name="log_0585">The server: [#!variable!server_name!#]'s current status is: [#!variable!status!#].</key>
<key name="log_0586">The server: [#!variable!server_name!#] is now off.</key>
<key name="log_0587">The server: [#!variable!server_name!#] has been removed from Pacemaker.</key>
<!-- Messages for users (less technical than log entries), though sometimes used for logs, too. -->
<key name="message_0001">The host name: [#!variable!target!#] does not resolve to an IP address.</key>
@ -1600,6 +1621,17 @@ About to try to download aproximately: [#!variable!packages!#] packages needed t
<key name="message_0204">Processing an uploaded file.</key>
<key name="message_0205">Processing a file mode check.</key>
<key name="message_0206">Proceed? [Y/n]</key> <!-- Default no is message_0021 -->
<key name="message_0207">Preparing to provision a new server.</key>
<key name="message_0208">-=] Listing servers on the Anvil! [#!variable!anvil_name!#].</key>
<key name="message_0209">(No servers found).</key>
<key name="message_0210">Which server would you like to delete?</key>
<key name="message_0211">- Please enter the server name or the number beside the server that you wish to delete. Press 'ctrl + c' to cancel.</key>
<key name="message_0212">[ WARNING ] - This is an irreversible action!
Are you sure that you want to delete the server: [#!variable!server_name!#]? [Type 'Yes'] </key>
<key name="message_0213">Searching to see if the server is running...</key>
<key name="message_0214">The server is running on the host: [#!variable!host_name!#], assigning the job to it.</key>
<key name="message_0215">The server is not running anywhere, assigning the job to this host.</key>
<key name="message_0216">The server is running here, assigning the job to this host.</key>
<!-- Success messages shown to the user -->
<key name="ok_0001">Saved the mail server information successfully!</key>

@ -32,24 +32,86 @@ $anvil->Log->entry({source => $THIS_FILE, line => __LINE__, level => 2, secure =
# Read switches (target ([user@]host[:port]) and the file with the target's password. If the password is
# passed directly, it will be used. Otherwise, the password will be read from the database.
$anvil->data->{switches}{'anvil-uuid'} = "";
$anvil->data->{switches}{'anvil-name'} = "";
$anvil->data->{switches}{'job-uuid'} = "";
$anvil->data->{switches}{'server-name'} = "";
$anvil->data->{switches}{'server-uuid'} = "";
$anvil->Get->switches;
$anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => {
'switches::anvil-uuid' => $anvil->data->{switches}{'anvil-uuid'},
'switches::anvil-name' => $anvil->data->{switches}{'anvil-name'},
'switches::job-uuid' => $anvil->data->{switches}{'job-uuid'},
'switches::server-name' => $anvil->data->{switches}{'server-name'},
'switches::server-uuid' => $anvil->data->{switches}{'server-uuid'},
}});
$anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { 'switches::job-uuid' => $anvil->data->{switches}{'job-uuid'} }});
$anvil->Database->connect();
$anvil->Log->entry({source => $THIS_FILE, line => __LINE__, level => 3, secure => 0, key => "log_0132"});
if (not $anvil->data->{sys}{database}{connections})
{
# No databases, update the job, sleep for a bit and then exit. The daemon will pick it up and try
# again after we exit.
$anvil->Log->entry({source => $THIS_FILE, line => __LINE__, 'print' => 1, level => 0, priority => "err", key => "error_0218"});
sleep 10;
$anvil->nice_exit({exit_code => 1});
}
### NOTE: This must be run on a Node or DR host and will only delete servers on the same Anvil!.
# This job is loaded on the node hosting the VM, or the primary node is the server isn't running. The first
# node to get this job will shut the server down and remove it from the cluster using 'pcs'. Once off and
# removed from the cluster, the server is marked as 'DELETED' and then a job is registered with the peer node
# and, if available, the DR host. At this point, the job acts the same regardless of the host. The DRBD
# resource will stopped and then have it's metadata wiped, The LV backing the device will be deleted next.
$anvil->data->{sys}{anvil_uuid} = $anvil->Cluster->get_anvil_uuid({debug => 2});
$anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { 'sys::anvil_uuid' => $anvil->data->{sys}{anvil_uuid} }});
# If we don't have a job UUID, try to find one.
if (not $anvil->data->{switches}{'job-uuid'})
{
# Load the job data.
$anvil->data->{switches}{'job-uuid'} = $anvil->Job->get_job_uuid({program => $THIS_FILE});
$anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { "switches::job-uuid" => $anvil->data->{switches}{'job-uuid'} }});
}
# If we still don't have a job-uuit, go into interactive mode.
if ($anvil->data->{switches}{'job-uuid'})
{
# Load the job data.
$anvil->Job->clear();
$anvil->Job->get_job_details();
$anvil->Job->update_progress({
progress => 1,
job_picked_up_by => $$,
job_picked_up_at => time,
message => "message_0207",
});
# Are we in an Anvil! system?
if (not $anvil->data->{sys}{anvil_uuid})
{
# We're not in an Anvil!.
if ($anvil->data->{switches}{'job-uuid'})
{
# Mark the job as failed.
$anvil->Job->update_progress({
progress => 100,
message => "error_0217",
job_status => "failed",
});
}
# Log an exit.
$anvil->Log->entry({source => $THIS_FILE, line => __LINE__, 'print' => 1, level => 0, priority => 'err', key => "error_0217"});
$anvil->nice_exit({exit_code => 1});
}
# Job data will be in $anvil->data->{jobs}{job_data}
run_jobs($anvil);
}
else
{
if (not $anvil->data->{sys}{anvil_uuid})
{
# We can't do anything, exit.
$anvil->Log->entry({source => $THIS_FILE, line => __LINE__, 'print' => 1, level => 0, priority => 'err', key => "error_0217"});
$anvil->nice_exit({exit_code => 1});
}
# Interactive!
ask_for_server($anvil);
}
$anvil->nice_exit({exit_code => 0});
@ -58,3 +120,368 @@ $anvil->nice_exit({exit_code => 0});
# Functions #
#############################################################################################################
# This actually provisions a VM.
sub run_jobs
{
my ($anvil) = @_;
# This parses the jobs::job_data intp variables.
parse_job_data($anvil);
if (not $anvil->data->{job}{peer_mode})
{
# Remove the server from pacemaker (stopping it, if necessary).
remove_from_pacemaker($anvil);
# Now parse the DRBD resources under this server. We'll log into the peers (if any) that are
# connected and down their DRBD resources under this server).
}
return(0);
}
# This checks to see if the server is running and, if so, stops it. Once stopped, the resource is deleted.
sub remove_from_pacemaker
{
my ($anvil) = @_;
my $server_uuid = $anvil->data->{job}{server_uuid};
my $server_name = $anvil->data->{servers}{server_uuid}{$server_uuid}{server_name};
# Sanity checks passed
$anvil->Job->update_progress({
progress => 10,
message => "job_0210,!!server_name!".$server_name."!!",
});
$anvil->Log->entry({source => $THIS_FILE, line => __LINE__, level => 2, key => "job_0210", variables => { server_name => $server_name }});
my $problem = $anvil->Cluster->shutdown_server({
debug => 2,
server => $server_name,
'wait' => 1,
});
$anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { problem => $problem }});
if ($problem)
{
# Failed to stop.
$anvil->Job->update_progress({
progress => 100,
message => "error_0223,!!server_name!".$server_name."!!",
job_status => "failed",
});
$anvil->Log->entry({source => $THIS_FILE, line => __LINE__, level => 0, priority => 'err', key => "error_0223", variables => { server_name => $server_name }});
$anvil->nice_exit({exit_code => 1});
}
# Server is off now.
$anvil->Job->update_progress({
progress => 20,
message => "job_0211,!!server_name!".$server_name."!!",
});
$anvil->Log->entry({source => $THIS_FILE, line => __LINE__, level => 2, key => "job_0211", variables => { server_name => $server_name }});
# Delete the resource.
$problem = $anvil->Cluster->delete_server({debug => 2, server_name => $server_name});
$anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { problem => $problem }});
if ($problem)
{
# Something went wrong
$anvil->Job->update_progress({
progress => 100,
message => "error_0227,!!server_name!".$server_name."!!",
job_status => "failed",
});
$anvil->Log->entry({source => $THIS_FILE, line => __LINE__, level => 0, priority => 'err', key => "error_0227", variables => { server_name => $server_name }});
$anvil->nice_exit({exit_code => 1});
}
return(0);
}
# This parses and verifies the job data
sub parse_job_data
{
my ($anvil) = @_;
$anvil->data->{job}{server_uuid} = "";
$anvil->data->{job}{peer_mode} = 0;
foreach my $line (split/\n/, $anvil->data->{jobs}{job_data})
{
$anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { line => $line }});
if ($line =~ /server_uuid=(.*)$/)
{
$anvil->data->{job}{server_uuid} = $1;
$anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { 'job::server_uuid' => $anvil->data->{job}{server_uuid} }});
}
if ($line =~ /peer_mode=true$/)
{
$anvil->data->{job}{peer_mode} = 1;
$anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { 'job::peer_mode' => $anvil->data->{job}{peer_mode} }});
}
}
# Did we get a server UUID?
if (not $anvil->data->{job}{server_uuid})
{
$anvil->Job->update_progress({
progress => 100,
message => "error_0219,!!job_uuid!".$anvil->data->{switches}{'job-uuid'}."!!",
job_status => "failed",
});
$anvil->Log->entry({source => $THIS_FILE, line => __LINE__, level => 0, priority => 'err', key => "error_0219", variables => { job_uuid => $anvil->data->{switches}{'job-uuid'} }});
$anvil->nice_exit({exit_code => 1});
}
# Does the server UUID match to a server?
$anvil->Database->get_servers();
my $server_uuid = $anvil->data->{job}{server_uuid};
if (not exists $anvil->data->{servers}{server_uuid}{$server_uuid})
{
# Server UUID is invalid
$anvil->Job->update_progress({
progress => 100,
message => "error_0220,!!server_uuid!".$server_uuid."!!",
job_status => "failed",
});
$anvil->Log->entry({source => $THIS_FILE, line => __LINE__, level => 0, priority => 'err', key => "error_0220", variables => { server_uuid => $server_uuid }});
$anvil->nice_exit({exit_code => 1});
}
elsif ($anvil->data->{servers}{server_uuid}{$server_uuid}{server_state} eq "DELETED")
{
# The server is already gone.
my $server_name = $anvil->data->{servers}{server_uuid}{$server_uuid}{server_name};
$anvil->Job->update_progress({
progress => 100,
message => "error_0221,!!server_name!".$server_name."!!",
});
$anvil->Log->entry({source => $THIS_FILE, line => __LINE__, level => 0, priority => 'err', key => "error_0221", variables => { server_name => $server_name }});
$anvil->nice_exit({exit_code => 1});
}
my $problem = $anvil->Cluster->parse_cib({debug => 2});
$anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { problem => $problem }});
if ($problem)
{
# The cluster isn't running, sleep and exit.
$anvil->Job->update_progress({
progress => 0,
message => "error_0222",
});
$anvil->Log->entry({source => $THIS_FILE, line => __LINE__, level => 0, priority => 'err', key => "error_0222"});
sleep 10;
$anvil->nice_exit({exit_code => 1});
}
return(0);
}
# This will ask the user to select a server.
sub ask_for_server
{
my ($anvil) = @_;
my $termios = new POSIX::Termios;
$termios->getattr;
my $ospeed = $termios->getospeed;
my $terminal = Tgetent Term::Cap { TERM => undef, OSPEED => $ospeed };
$terminal->Trequire(qw/ce ku kd/);
my $anvil_uuid = $anvil->data->{sys}{anvil_uuid};
my $anvil_name = $anvil->Cluster->get_anvil_name({anvil_uuid => $anvil_uuid});
my $retry = 0;
my $delete_uuid = "";
while(1)
{
print $terminal->Tputs('cl');
$anvil->Database->get_servers();
my $servers = [];
my $position = 0;
my $server_list = "";
print $anvil->Words->string({key => "message_0208", variables => { anvil_name => $anvil_name }})."\n";
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 => {
's1:server_name' => $server_name,
's2:server_uuid' => $server_uuid,
's3:server_state' => $server_state,
}});
next if $server_state eq "DELETED";
# We want to start the list at '1', so we'll bump the position before generating an entry,
# and subtract 1 from the user's answer later.
$servers->[$position] = $server_uuid;
$position++;
$server_list .= $position.") ".$server_name."\n";
}
if (not $position)
{
# No servers on this Anvil!.
print $anvil->Words->string({key => "message_0209"})."\n";
$anvil->nice_exit({exit_code => 0});
}
print $server_list."\n";;
if ($retry)
{
print $anvil->Words->string({key => "message_0211"})."\n\n";
}
print $anvil->Words->string({key => "message_0210"})." ";
my $answer = <STDIN>;
chomp $answer;
$anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { answer => $answer }});
if ($answer =~ /\D/)
{
# Did the user type the name?
if ((exists $anvil->data->{servers}{anvil_uuid}{$anvil_uuid}{server_name}{$answer}) && ($anvil->data->{servers}{anvil_uuid}{$anvil_uuid}{server_name}{$answer}{server_uuid}))
{
# Specified by name.
$delete_uuid = $anvil->data->{servers}{anvil_uuid}{$anvil_uuid}{server_name}{$answer}{server_uuid};
$anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { delete_uuid => $delete_uuid }});
}
}
elsif ($answer =~ /^\d+$/)
{
my $index = $answer - 1;
$anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { 'index' => $index }});
if ((exists $servers->[$index]) && ($servers->[$index]))
{
$delete_uuid = $servers->[$index];
$anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { delete_uuid => $delete_uuid }});
}
}
if ($delete_uuid)
{
last;
}
else
{
$retry = 1;
}
}
# Ask the user to confirm.
my $server_name = $anvil->data->{servers}{server_uuid}{$delete_uuid}{server_name};
$anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => {
delete_uuid => $delete_uuid,
server_name => $server_name,
}});
print "\n".$anvil->Words->string({key => "message_0212", variables => { server_name => $server_name }})." ";
my $answer = <STDIN>;
chomp $answer;
$anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { answer => $answer }});
if (lc($answer) eq "yes")
{
### Save the job!
# Is the server running?
print $anvil->Words->string({key => "message_0213"})."\n";
$anvil->Database->get_anvils();
my $hosts = [];
my $password = $anvil->data->{anvils}{anvil_uuid}{$anvil_uuid}{anvil_password};
push @{$hosts}, $anvil->data->{anvils}{anvil_uuid}{$anvil_uuid}{anvil_node1_host_uuid};
push @{$hosts}, $anvil->data->{anvils}{anvil_uuid}{$anvil_uuid}{anvil_node2_host_uuid};
if ($anvil->data->{anvils}{anvil_uuid}{$anvil_uuid}{anvil_dr1_host_uuid})
{
push @{$hosts}, $anvil->data->{anvils}{anvil_uuid}{$anvil_uuid}{anvil_dr1_host_uuid};
}
my $server_host = "";
foreach my $host_uuid (@{$hosts})
{
if ($host_uuid eq $anvil->Get->host_uuid)
{
# This is us.
$anvil->Server->find({refresh => 0});
}
else
{
# This is another machine.
my $target_ip = $anvil->Network->find_target_ip({host_uuid => $host_uuid});
$anvil->Server->find({
refresh => 0,
target => $target_ip,
password => $password,
});
}
}
my $host_name = "";
my $host_uuid = "";
if (exists $anvil->data->{server}{location}{$server_name})
{
my $status = $anvil->data->{server}{location}{$server_name}{status};
$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.
$anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { host_uuid => $host_uuid }});
my $job_host_uuid = "";
if ($host_uuid)
{
$job_host_uuid = $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)
{
# Running here
print $anvil->Words->string({key => "message_0216"})."\n";
}
else
{
# Running on a peer.
print $anvil->Words->string({key => "message_0214", variables => { host_name => $host_name }})."\n";
}
}
else
{
$job_host_uuid = $anvil->Get->host_uuid();
$anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { job_host_uuid => $job_host_uuid }});
print $anvil->Words->string({key => "message_0215"})."\n";
}
my ($job_uuid) = $anvil->Database->insert_or_update_jobs({
debug => 2,
job_command => $anvil->data->{path}{exe}{'anvil-delete-server'},
job_data => "server_uuid=".$delete_uuid,
job_name => "server::delete",
job_title => "job_0208",
job_description => "job_0209",
job_progress => 0,
job_host_uuid => $job_host_uuid,
});
$anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { job_uuid => $job_uuid }});
$anvil->nice_exit({exit_code => 0});
}
else
{
# Abort.
print $anvil->Words->string({key => "message_0022"})."\n";
$anvil->nice_exit({exit_code => 0});
}
return(0);
}

@ -525,6 +525,23 @@ sub check_peer_is_fenced
{
# The node is out.
to_log($conf, {message => "The node: [$node] has been fenced successfully.", 'line' => __LINE__, level => 1});
# Call 'drbdadm adjust all' as it seems like drbd's in-memory can change
# causing 'incompatible <fence option>' on return of the peer.
to_log($conf, {message => "Reloading DRBD config from disk to ensure in-memory and on-disk configs match.", 'line' => __LINE__, level => 1});
my $shell_call = $conf->{path}{exe}{drbdadm}." adjust all";
to_log($conf, {message => "Calling: [$shell_call]", 'line' => __LINE__, level => 2});
open (my $file_handle, $shell_call." 2>&1 |") or die "Failed to call: [".$shell_call."]. The error was: $!\n";
while(<$file_handle>)
{
# This should not generate output.
chomp;
my $line = $_;
to_log($conf, {message => "Output: [$line]", 'line' => __LINE__, level => 2});
}
close $file_handle;
to_log($conf, {message => "Fence completed successfully!", 'line' => __LINE__, level => 1});
exit(7);
}
else

@ -26,6 +26,6 @@ $anvil->Get->switches;
$anvil->Database->connect({debug => 3});
$anvil->Log->entry({source => $THIS_FILE, line => __LINE__, level => 2, key => "log_0132"});
$anvil->Cluster->add_server({server_name => "srv01-test"});
$anvil->Cluster->shutdown_server({server => "srv01-test"});
$anvil->nice_exit({exit_code => 0});

Loading…
Cancel
Save