Merge pull request #86 from ClusterLabs/scancore-debugging

* Renamed tools/striker-purge-host to tools/striker-purge-target and …
main
digimer-bot 4 years ago committed by GitHub
commit 4382dc8370
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
  1. 2
      Anvil/Tools/Database.pm
  2. 10
      Anvil/Tools/ScanCore.pm
  3. 175
      notes
  4. 7
      ocf/alteeve/server
  5. 1
      share/words.xml
  6. 2
      tools/Makefile.am
  7. 329
      tools/striker-purge-host
  8. 381
      tools/striker-purge-target

@ -4633,7 +4633,7 @@ sub get_tables_from_schema
"sys::database::history_table::${table}" => $anvil->data->{sys}{database}{history_table}{$table}, "sys::database::history_table::${table}" => $anvil->data->{sys}{database}{history_table}{$table},
}}); }});
} }
if ($line =~ /CREATE TABLE (.*?) \(/i) elsif ($line =~ /CREATE TABLE (.*?) \(/i)
{ {
my $table = $1; my $table = $1;
$anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => $debug, list => { table => $table }}); $anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => $debug, list => { table => $table }});

@ -291,9 +291,15 @@ sub call_scan_agents
# If an agent takes a while to run, log it with higher verbosity # If an agent takes a while to run, log it with higher verbosity
my $runtime = (time - $start_time); my $runtime = (time - $start_time);
my $log_level = $runtime > 10 ? 1 : $debug; my $log_level = $debug;
my $string_key = "log_0557";
if ($runtime > 10)
{
$log_level = 1;
$string_key = "log_0621";
}
$anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => $debug, list => { output => $output, runtime => $runtime }}); $anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => $debug, list => { output => $output, runtime => $runtime }});
$anvil->Log->entry({source => $THIS_FILE, line => __LINE__, 'print' => 1, level => $log_level, key => "log_0557", variables => { $anvil->Log->entry({source => $THIS_FILE, line => __LINE__, 'print' => 1, level => $log_level, key => $string_key, variables => {
agent_name => $agent_name, agent_name => $agent_name,
runtime => $runtime, runtime => $runtime,
return_code => $return_code, return_code => $return_code,

175
notes

@ -974,7 +974,7 @@ OS10# configure terminal
OS10(config)# vlt-domain 1 OS10(config)# vlt-domain 1
OS10(conf-vlt-1)# vlt-mac 00:00:00:00:00:02 OS10(conf-vlt-1)# vlt-mac 00:00:00:00:00:02
# show vlt 1 mismatch OS10# show vlt 1 mismatch
(If no issues, VLT is OK) (If no issues, VLT is OK)
# See how I am and my role (* == switch you're on) # See how I am and my role (* == switch you're on)
@ -986,36 +986,47 @@ VLT Unit ID Role
=====] VLAN Config [======== =====] VLAN Config [========
OS10# configure terminal
zo-switch02# configure terminal OS10(config)# interface mgmt 1/1/1
zo-switch02(config)# interface vlan 100 OS10(conf-if-ma-1/1/1)# no ip address dhcp
zo-switch02(conf-if-vl-100)# description BCN1 OS10(conf-if-ma-1/1/1)# ip address 10.201.1.2/16
zo-switch02(conf-if-vl-100)# interface range ethernet 1/1/1-1/1/10 OS10(conf-if-ma-1/1/1)# no shutdown
zo-switch02(conf-range-eth1/1/1-1/1/10)# switchport access vlan 100 OS10(conf-if-ma-1/1/1)# exit
zo-switch02(conf-range-eth1/1/1-1/1/10)# exot OS10(config)# write memory
% Error: Unrecognized command. OS10(config)# hostname zo-switch01
zo-switch02(conf-range-eth1/1/1-1/1/10)# exit zo-switch01(config)# interface vlan 100
zo-switch02(config)# interface range ethernet 1/1/11-1/1/14 zo-switch01(conf-if-vl-100)# description BCN1
zo-switch02(conf-range-eth1/1/11-1/1/14)# switchport access vlan 200 zo-switch01(conf-if-vl-100)# interface range ethernet 1/1/1-1/1/10
zo-switch02(conf-range-eth1/1/11-1/1/14)# exit zo-switch01(conf-range-eth1/1/1-1/1/10)# switchport access vlan 100
zo-switch02(config)# interface range ethernet 1/1/15-1/1/24 zo-switch01(conf-range-eth1/1/1-1/1/10)# no shutdown
zo-switch02(conf-range-eth1/1/15-1/1/24)# switchport access vlan 300 zo-switch01(conf-range-eth1/1/1-1/1/10)# exit
ezo-switch02(conf-range-eth1/1/15-1/1/24)# exit zo-switch01(config)# interface vlan 200
zo-switch02(config)# show vlan zo-switch01(conf-if-vl-200)# description SN1
zo-switch01(conf-if-vl-200)# interface range ethernet 1/1/11-1/1/14
zo-switch01(conf-range-eth1/1/11-1/1/14)# switchport access vlan 200
zo-switch01(conf-range-eth1/1/11-1/1/14)# no shutdown
zo-switch01(conf-range-eth1/1/11-1/1/14)# exit
zo-switch01(config)# interface vlan 300
zo-switch01(conf-if-vl-300)# description IFN1
zo-switch01(conf-if-vl-300)# interface range ethernet 1/1/15-1/1/24
zo-switch01(conf-range-eth1/1/15-1/1/24)# switchport access vlan 300
zo-switch01(conf-range-eth1/1/15-1/1/24)# no shutdown
zo-switch01(conf-range-eth1/1/15-1/1/24)# exit
zo-switch01(config)# show vlan
Codes: * - Default VLAN, M - Management VLAN, R - Remote Port Mirroring VLANs, Codes: * - Default VLAN, M - Management VLAN, R - Remote Port Mirroring VLANs,
@ – Attached to Virtual Network, P - Primary, C - Community, I - Isolated @ - Attached to Virtual Network, P - Primary, C - Community, I - Isolated
Q: A - Access (Untagged), T - Tagged Q: A - Access (Untagged), T - Tagged
NUM Status Description Q Ports NUM Status Description Q Ports
* 1 Active A Eth1/1/27-1/1/30 * 1 Active A Eth1/1/27-1/1/30
A Po1000 A Po1000
100 Active BCN1 T Po1000 100 Active BCN1 T Po1000
A Eth1/1/1-1/1/10 A Eth1/1/1-1/1/10
200 Active T Po1000 200 Active SN1 T Po1000
A Eth1/1/11-1/1/14 A Eth1/1/11-1/1/14
300 Active T Po1000 300 Active IFN1 T Po1000
A Eth1/1/15-1/1/24 A Eth1/1/15-1/1/24
4094 Active T Po1000 4094 Active T Po1000
zo-switch01(config)# write memory
### Delete a VLAN: ### Delete a VLAN:
@ -1023,18 +1034,109 @@ zo-switch02(config)# no interface vlan 3400
zo-switch02(config)# show vlan zo-switch02(config)# show vlan
# Configure VLANs. === Firmware Update ===
OS10(config)# interface range vlan 100,200,300
OS10(conf-range-vl-100,200,300)# exit Download the firmware from the Dell digital locker. Once downloaded, extracted and the sum verified, copy the 'PKGS_OS10-Enterprise-xxx-installer-x86_64.bin' file to one of the striker's /var/lib/tftpboot/' directory and start the dhcpd service.
OS10(config)# interface range ethernet 1/1/1-1/1/10
OS10(conf-range-eth1/1/1-1/1/10)# switchport access vlan 100 ### NOTE: Use the striker NOT connected to the switch being upgraded! If necessary, move the uplink interfaces off of the switch to be upgraded!
OS10(conf-range-eth1/1/1-1/1/10)# exit Once ready, connect to the switch over serial port.
OS10(config)# interface range ethernet 1/1/11-1/1/14
OS10(conf-range-eth1/1/11-1/1/14)# switchport access vlan 200 ### WARNING: The firmware update completely resets the switch! Backup you config before hand, if necessary. Also, watch for the loss of VLANs causing switch loops when 2+ uplinks are connected!
OS10(conf-range-eth1/1/11-1/1/14)# exit
OS10(config)# interface range ethernet 1/1/15-1/1/24 # screen /dev/ttyUSB0 115200
OS10(conf-range-eth1/1/15-1/1/24)# switchport access vlan 300
OS10(conf-range-eth1/1/15-1/1/24)# exit # Reboot the switches;
reload <confirm with 'yes'>
When the grub boot menu appears, choose
+--------------------------------------------------------+
|*ONIE: Install OS |
| ONIE: Rescue |
| ONIE: Uninstall OS |
| ONIE: Update ONIE |
| ONIE: Embed ONIE |
| ONIE: Diag ONIE |
+--------------------------------------------------------+
# This will start a constant scan of IP addresses and local storage looking for the firmware. To stop this, type:
ONIE:/ # onie-discovery-stop
# Set the IP address so that we can talk to the striker with the firmware.
ONIE:/ # ifconfig eth0 10.201.1.1 netmask 255.255.0.0 up
ONIE:/ # ping 10.201.4.1
PING 10.201.4.1 (10.201.4.1): 56 data bytes
64 bytes from 10.201.4.1: seq=0 ttl=64 time=0.247 ms
64 bytes from 10.201.4.1: seq=1 ttl=64 time=0.506 ms
ONIE:/ # onie-nos-install tftp://10.201.4.1/PKGS_OS10-Enterprise-10.5.2.3.316stretch-installer-x86_64.bin
discover: installer mode detected.
Stopping: discover... done.
Info: Fetching tftp://10.201.4.1/PKGS_OS10-Enterprise-10.5.2.3.316stretch-installer-x86_64.bin ... <- This step takes a while
PKGS_OS10-Enterprise 100% |*******************************| 744M 0:00:00 ETA
ONIE: Executing installer: tftp://10.201.4.1/PKGS_OS10-Enterprise-10.5.2.3.316stretch-installer-x86_64.bin
Initializing installer ... OK
Verifying image checksum ... OK
OS10 Installer: machine: dellemc_s4100_c2338/s4128t
Fixing up partitions ... OK
Deleting logical volume CONFIG ... OK
Deleting logical volume SYSROOT1 ... OK
Deleting logical volume SYSROOT2 ... OK
Creating logical volume SYSROOT ... OK
Creating ext4 filesystem on SYSROOT ... OK
Extracting OS10 ... OK
Installing OS10 on primary volume ... OK <- This takes a long time, be patient
Setting up shared data ... OK
Synchronizing standby image ...
OS10 installation is complete.
Creating ext4 filesystem on sda4 ... OK
Installing GRUB-UEFI ... OK
Saving system information ... OK
Saving ONIE support information ... OK
ONIE: NOS install successful: tftp://10.201.4.1/PKGS_OS10-Enterprise-10.5.2.3.316stretch-installer-x86_64.bin
ONIE: Rebooting...
ONIE:/ # discover: installer mode detected.
Stopping: discover...start-stop-daemon: warning: killing process 2881: No such process
done.
Stopping: dropbear ssh daemon... done.
Stopping: telnetd... done.
Stopping: syslogd... done.
Info: Unmounting kernel filesystems
umount: can't umount /: Invalid argument
The system is going down NOW!
Sent SIGTERM to all processes
Sent SIGKILL tosd 4:0:0:0: [sda] Synchronizing SCSI cache
reboot: Restarting system
reboot: machine restart
### NOTE: The login prompt will appear before the system is ready to log in. The default username and password revert to 'admin' / 'admin', but this won't work for the first couple of minutes.
## OLD
zo-switch02# show version
Dell EMC Networking OS10 Enterprise
Copyright (c) 1999-2020 by Dell Inc. All Rights Reserved.
OS Version: 10.5.0.4
Build Version: 10.5.0.4.638
Build Time: 2020-01-30T21:08:56+0000
System Type: S4128T-ON
Architecture: x86_64
Up Time: 22:49:57
zo-switch02#
## New
zo-a01n01# show version
Dell EMC Networking OS10 Enterprise
Copyright (c) 1999-2021 by Dell Inc. All Rights Reserved.
OS Version: 10.5.2.3
Build Version: 10.5.2.3.316
Build Time: 2021-02-26T20:03:25+0000
System Type: S4128T-ON
Architecture: x86_64
==================================== ====================================
-=] Rename a resource (ex: srv09-few-tcpremote1 -> srv09-fea-tcpremote1) -=] Rename a resource (ex: srv09-few-tcpremote1 -> srv09-fea-tcpremote1)
@ -1074,3 +1176,10 @@ May 02 13:35:21 zo-a01n02.zennioptical.com setroubleshoot[5333]: SELinux is prev
# ausearch -c 'drbdsetup' --raw | audit2allow -M my-drbdsetup # ausearch -c 'drbdsetup' --raw | audit2allow -M my-drbdsetup
# semodule -X 300 -i my-drbdsetup.pp # semodule -X 300 -i my-drbdsetup.pp
If you believe that virsh should be allowed read access on the srv16-zo-psql-qa.xml file by default.
# ausearch -c 'virsh' --raw | audit2allow -M my-virsh
# semodule -X 300 -i my-virsh.pp

@ -97,8 +97,9 @@ $| = 1;
# in the loop as well to override defaults in code. # in the loop as well to override defaults in code.
my $anvil = Anvil::Tools->new(); my $anvil = Anvil::Tools->new();
# If we can connect to a database, we'll set/clear the 'migrating' flag during migrations # If we can connect to a database, we'll set/clear the 'migrating' flag during migrations. For timing reasons
$anvil->Database->connect(); # we don't let the RA do resyncs.
$anvil->Database->connect({no_resync => 1});
$anvil->Log->entry({source => $THIS_FILE, line => __LINE__, level => 3, secure => 0, key => "log_0132"}); $anvil->Log->entry({source => $THIS_FILE, line => __LINE__, level => 3, secure => 0, key => "log_0132"});
if (not $anvil->data->{sys}{database}{connections}) if (not $anvil->data->{sys}{database}{connections})
{ {
@ -155,7 +156,7 @@ $anvil->data->{environment}{OCF_RESKEY_CRM_meta_stop_drbd_resources} = 0;
$anvil->data->{switches}{migrate_to} = ""; # Sets 'meta_migrate_target' $anvil->data->{switches}{migrate_to} = ""; # Sets 'meta_migrate_target'
$anvil->data->{switches}{migrate_from} = ""; # Sets 'meta_migrate_source' When set without 'migrate_to', does a status check after migration $anvil->data->{switches}{migrate_from} = ""; # Sets 'meta_migrate_source' When set without 'migrate_to', does a status check after migration
$anvil->data->{switches}{server} = ""; # Sets 'name'. $anvil->data->{switches}{server} = ""; # Sets 'name'.
$anvil->Get->switches({debug => 2}); $anvil->Get->switches();
if ($anvil->data->{switches}{stop_drbd_resources}) if ($anvil->data->{switches}{stop_drbd_resources})
{ {

@ -1578,6 +1578,7 @@ The file: [#!variable!file!#] needs to be updated. The difference is:
<key name="log_0618">Successfully deleted the file: [#!variable!file!#] on the target: [#!variable!target!#].</key> <key name="log_0618">Successfully deleted the file: [#!variable!file!#] on the target: [#!variable!target!#].</key>
<key name="log_0619">The host: [#!variable!host_name!#] has shut down for thermal reasons: [#!variable!count!#] times. To prevent a frequent boot / thermal excursion / shutdown loop, we will wait: [#!variable!wait_for!#] before marking it's temperature as being OK again.</key> <key name="log_0619">The host: [#!variable!host_name!#] has shut down for thermal reasons: [#!variable!count!#] times. To prevent a frequent boot / thermal excursion / shutdown loop, we will wait: [#!variable!wait_for!#] before marking it's temperature as being OK again.</key>
<key name="log_0620">This host has been running for: [#!variable!uptime!#]. The cluster will not be started (uptime must be less than 10 minutes for 'anvil-safe-start' to be called automatically).</key> <key name="log_0620">This host has been running for: [#!variable!uptime!#]. The cluster will not be started (uptime must be less than 10 minutes for 'anvil-safe-start' to be called automatically).</key>
<key name="log_0621">- The Scan agent: [#!variable!agent_name!#] ran a bit long, exiting after: [#!variable!runtime!#] seconds with the return code: [#!variable!return_code!#].</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>

@ -40,7 +40,7 @@ dist_sbin_SCRIPTS = \
striker-parse-os-list \ striker-parse-os-list \
striker-parse-oui \ striker-parse-oui \
striker-prep-database \ striker-prep-database \
striker-purge-host \ striker-purge-target \
striker-scan-network \ striker-scan-network \
striker-auto-initialize-all striker-auto-initialize-all

@ -1,329 +0,0 @@
#!/usr/bin/perl
#
# This tool is meant to be run from the command line and lets a user purge all information about a given host
# from the databases.
#
# Exit codes;
# 0 = Normal exit.
# 1 = User's answer to which machine to purge was invalid.
# 2 = The passed-in (or selected) host UUID (no longer) exists.
# 3 = User did not confirm to proceed.
# 4 = Runaway loop detected.
#
use strict;
use warnings;
use Anvil::Tools;
use Data::Dumper;
use Curses::UI;
my $THIS_FILE = ($0 =~ /^.*\/(.*)$/)[0];
my $running_directory = ($0 =~ /^(.*?)\/$THIS_FILE$/)[0];
if (($running_directory =~ /^\./) && ($ENV{PWD}))
{
$running_directory =~ s/^\./$ENV{PWD}/;
}
# Turn off buffering so that the pinwheel will display while waiting for the SSH call(s) to complete.
$| = 1;
my $anvil = Anvil::Tools->new();
$anvil->Get->switches;
$anvil->Log->entry({source => $THIS_FILE, line => __LINE__, level => 2, secure => 0, key => "log_0115", variables => { program => $THIS_FILE }});
$anvil->Database->connect({debug => 3});
$anvil->Log->entry({source => $THIS_FILE, line => __LINE__, level => 2, secure => 0, key => "log_0132"});
# First, ask the user to select a host.
$anvil->data->{switches}{'host-uuid'} = "" if not defined $anvil->data->{switches}{'host-uuid'};
$anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { 'switches::host-uuid' => $anvil->data->{switches}{'host-uuid'} }});
$anvil->Database->get_hosts();
# Ask the user to pick a host.
pick_host($anvil);
# Ask the user to confirm.
confirm($anvil);
# If we're alive, purge.
purge($anvil);
$anvil->nice_exit({exit_code => 0});
#############################################################################################################
# Functions #
#############################################################################################################
sub purge
{
my ($anvil) = @_;
# Read in all constraints and create a hash of what depends on what, then delete anything referencing
# hosts without any further references. As each delete is done, delete it. Loop until all entries are
# gone.
die;
# Load all the known tables in the DB.
my $query = "SELECT schemaname||'.'||tablename AS table_name FROM pg_catalog.pg_tables WHERE schemaname = 'history' ORDER BY tablename ASC, schemaname ASC;";
$anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { query => $query }});
my $results = $anvil->Database->query({query => $query, source => $THIS_FILE, line => __LINE__});
my $count = @{$results};
$anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 3, list => {
results => $results,
count => $count,
}});
foreach my $row (@{$results})
{
my $table_name = $row->[0];
$anvil->data->{sql}{history_tables}{$table_name} = 1;
$anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 3, list => { "sql::history_tables::${table_name}" => $anvil->data->{sql}{history_tables}{$table_name} }});
}
undef $query;
undef $results;
undef $count;
### NOTE: Credit for this query goes to:
### - https://stackoverflow.com/questions/1152260/postgres-sql-to-list-table-foreign-keys
$query = "
SELECT
tc.table_schema||'.'||tc.table_name AS table,
kcu.column_name,
ccu.table_schema||'.'||ccu.table_name AS foreign_table,
ccu.column_name AS foreign_column_name
FROM
information_schema.table_constraints AS tc
JOIN information_schema.key_column_usage AS kcu
ON tc.constraint_name = kcu.constraint_name
AND tc.table_schema = kcu.table_schema
JOIN information_schema.constraint_column_usage AS ccu
ON ccu.constraint_name = tc.constraint_name
AND ccu.table_schema = tc.table_schema
WHERE
tc.constraint_type = 'FOREIGN KEY'
AND
ccu.column_name = 'host_uuid'
;";
$anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { query => $query }});
$results = $anvil->Database->query({query => $query, source => $THIS_FILE, line => __LINE__});
$count = @{$results};
$anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 3, list => {
results => $results,
count => $count,
}});
foreach my $row (@{$results})
{
my $table_name = $row->[0];
my $column_name = $row->[1];
my $foreign_table_name = $row->[2];
my $foreign_column_name = $row->[3];
$anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 3, list => {
's1:table_name' => $table_name,
's2:column_name' => $column_name,
's3:foreign_table_name' => $foreign_table_name,
's4:foreign_column_name' => $foreign_column_name,
}});
if (not exists $anvil->data->{sql}{table}{$table_name})
{
$anvil->data->{sql}{table}{$table_name}{column} = $column_name;
$anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 3, list => { "sql::table::${table_name}::column" => $anvil->data->{sql}{table}{$table_name}{column} }});
}
if (not exists $anvil->data->{sql}{table}{$foreign_table_name})
{
$anvil->data->{sql}{table}{$foreign_table_name}{column} = $foreign_column_name;
$anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 3, list => { "sql::table::${foreign_table_name}::column" => $anvil->data->{sql}{table}{$foreign_table_name}{column} }});
}
$anvil->data->{sql}{table}{$foreign_table_name}{referenced_by}{$table_name} = 1;
}
my $loops = 20;
my $loop = 0;
my $done = 0;
my $queries = [];
until($done)
{
$loop++;
foreach my $table_name (sort {$a cmp $b} keys %{$anvil->data->{sql}{table}})
{
my $count = exists $anvil->data->{sql}{table}{$table_name}{referenced_by} ? keys %{$anvil->data->{sql}{table}{$table_name}{referenced_by}} : 0;
#print "-- Table: [".$table_name."] is referenced by: [".$count."] foreign table(s);\n";
if (not $count)
{
# If there is a corresponding history table, delete it as well.
my $column = $anvil->data->{sql}{table}{$table_name}{column};
my $history_table = $table_name;
$history_table =~ s/^public\./history\./;
if (exists $anvil->data->{sql}{history_tables}{$history_table})
{
push @{$queries}, "DELETE FROM ".$history_table." WHERE ".$column." = ".$anvil->Database->quote($anvil->data->{switches}{'host-uuid'}).";";
}
# Now delete the public table entries.
push @{$queries}, "DELETE FROM ".$table_name." WHERE ".$column." = ".$anvil->Database->quote($anvil->data->{switches}{'host-uuid'}).";";
foreach my $foreign_table_name (sort {$a cmp $b} keys %{$anvil->data->{sql}{table}})
{
if (exists $anvil->data->{sql}{table}{$foreign_table_name}{referenced_by}{$table_name})
{
#print "-- Deleting: [".$foreign_table_name."] reference to: [".$table_name."]\n";
delete $anvil->data->{sql}{table}{$foreign_table_name}{referenced_by}{$table_name};
}
}
#print "-- Deleting hash entry for: [".$table_name."]\n";
delete $anvil->data->{sql}{table}{$table_name};
}
}
my $remaining = keys %{$anvil->data->{sql}{table}};
$anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { remaining => $remaining }});
if (not $remaining)
{
$done = 1;
}
elsif ($loop > $loops)
{
print "Run-away loop detected, aborting!\n";
$anvil->nice_exit({exit_code => 4});
}
}
# Do the deed.
$anvil->Database->write({debug => 2, query => $queries, source => $THIS_FILE, line => __LINE__});
my $host_uuid = $anvil->data->{switches}{'host-uuid'};
print $anvil->Words->string({key => "message_0176", variables => { host_name => $anvil->data->{hosts}{host_uuid}{$host_uuid}{host_name} }})."\n";
return(0);
}
sub confirm
{
my ($anvil) = @_;
# Normalize -y
$anvil->data->{switches}{'y'} = "" if not defined $anvil->data->{switches}{'y'};
$anvil->data->{switches}{'yes'} = "" if not defined $anvil->data->{switches}{'yes'};
$anvil->data->{switches}{'Y'} = "" if not defined $anvil->data->{switches}{'Y'};
$anvil->data->{switches}{'Yes'} = "" if not defined $anvil->data->{switches}{'Yes'};
$anvil->data->{switches}{'YES'} = "" if not defined $anvil->data->{switches}{'YES'};
if (not $anvil->data->{switches}{'y'})
{
if ($anvil->data->{switches}{'yes'}) { $anvil->data->{switches}{'y'} = $anvil->data->{switches}{'yes'}; }
elsif ($anvil->data->{switches}{'Y'}) { $anvil->data->{switches}{'y'} = $anvil->data->{switches}{'Y'}; }
elsif ($anvil->data->{switches}{'Yes'}) { $anvil->data->{switches}{'y'} = $anvil->data->{switches}{'Yes'}; }
elsif ($anvil->data->{switches}{'YES'}) { $anvil->data->{switches}{'y'} = $anvil->data->{switches}{'YES'}; }
}
# Ask to confirm, is sane and not -y
my $host_uuid = $anvil->data->{switches}{'host-uuid'};
if (not exists $anvil->data->{hosts}{host_uuid}{$host_uuid}{host_name})
{
print $anvil->Words->string({key => "error_0131", variables => { host_uuid => $host_uuid }})."\n\n";
$anvil->nice_exit({exit_code => 2});
}
else
{
print $anvil->Words->string({key => "message_0172"})."\n\n";
print $anvil->Words->string({key => "message_0173", variables => {
host_name => $anvil->data->{hosts}{host_uuid}{$host_uuid}{host_name},
host_uuid => $host_uuid,
}})."\n";
$anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 3, list => { 'switches::y' => $anvil->data->{switches}{'y'} }});
if ($anvil->data->{switches}{'y'} eq "#!SET!#")
{
# Already confirmed.
print $anvil->Words->string({key => "message_0023"})."\n\n";
return(0);
}
print $anvil->Words->string({key => "message_0021"})." ";
chomp(my $answer = <STDIN>);
if ($answer =~ /^y/i)
{
# Proceed.
print $anvil->Words->string({key => "message_0175"})."\n";
}
else
{
# Abort.
print $anvil->Words->string({key => "message_0022"})."\n";
$anvil->nice_exit({exit_code => 3});
}
}
return(0);
}
sub pick_host
{
my ($anvil) = @_;
return(0) if $anvil->data->{switches}{'host-uuid'};
# Get a list of hosts
my $i = 1;
my $select = {};
my $host_length = 0;
my $type_length = 0;
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 $anvil_name = defined $anvil->data->{hosts}{host_uuid}{$host_uuid}{anvil_name} ? $anvil->data->{hosts}{host_uuid}{$host_uuid}{anvil_name} : "";
my $say_type = $anvil->Words->string({key => "brand_0009"});
if ($host_type eq "striker") { $say_type = $anvil->Words->string({key => "brand_0003"}); }
elsif ($host_type eq "node") { $say_type = $anvil->Words->string({key => "brand_0007"}); }
elsif ($host_type eq "dr") { $say_type = $anvil->Words->string({key => "brand_0008"}); }
if (length($host_name) > $host_length) { $host_length = length($host_name); }
if (length($say_type) > $type_length) { $type_length = length($say_type); }
# This is used to build the menu.
$select->{$i}{host_uuid} = $host_uuid;
$select->{$i}{host_name} = $host_name;
$select->{$i}{host_type} = $host_type;
$select->{$i}{say_type} = $say_type;
$select->{$i}{anvil_name} = $anvil_name;
$anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 3, list => {
"${i}::host_uuid" => $select->{$i}{host_uuid},
"${i}::host_name" => $select->{$i}{host_name},
"${i}::host_type" => $select->{$i}{host_type},
"${i}::anvil_name" => $select->{$i}{anvil_name},
}});
$i++;
}
my $pad = $i > 9 ? 2 : 1;
print $anvil->Words->string({key => "message_0169"})."\n\n";
foreach my $i (sort {$a cmp $b} keys %{$select})
{
print " ".$anvil->Words->string({key => "message_0170", variables => {
key => sprintf("%".$pad."s", $i),
type => sprintf("%-".$type_length."s", $select->{$i}{say_type}),
host_name => sprintf("%-".$host_length."s", $select->{$i}{host_name}),
host_uuid => $select->{$i}{host_uuid},
}})."\n";
}
print "\n".$anvil->Words->string({key => "message_0171"})." ";
chomp(my $answer = <STDIN>);
if (not exists $select->{$answer}{host_name})
{
print "\n".$anvil->Words->string({key => "error_0130", variables => { answer => $answer }})."\n\n";
$anvil->nice_exit({exit_code => 1});
}
else
{
print "\n";
$anvil->data->{switches}{'host-uuid'} = $select->{$answer}{host_uuid};
}
return(0);
}

@ -0,0 +1,381 @@
#!/usr/bin/perl
#
# This is a tool that purges hosts or Anvil! systems from the ScanCore databases.
#
use strict;
use warnings;
use Anvil::Tools;
use Data::Dumper;
$| = 1;
my $THIS_FILE = ($0 =~ /^.*\/(.*)$/)[0];
my $running_directory = ($0 =~ /^(.*?)\/$THIS_FILE$/)[0];
if (($running_directory =~ /^\./) && ($ENV{PWD}))
{
$running_directory =~ s/^\./$ENV{PWD}/;
}
my $anvil = Anvil::Tools->new();
$anvil->Database->connect({debug => 3});
$anvil->Log->entry({source => $THIS_FILE, line => __LINE__, level => 2, secure => 0, key => "log_0132"});
if (not $anvil->data->{sys}{database}{connections})
{
# No databases, exit.
$anvil->Log->entry({source => $THIS_FILE, line => __LINE__, level => 0, 'print' => 1, priority => "err", key => "error_0003"});
$anvil->nice_exit({exit_code => 1});
}
$anvil->data->{switches}{'anvil'} = "";
$anvil->data->{switches}{'host'} = "";
$anvil->data->{switches}{'y'} = "";
$anvil->data->{switches}{'yes'} = "";
$anvil->Get->switches();
if ((not $anvil->data->{switches}{'anvil'}) && (not $anvil->data->{switches}{'host'}))
{
$anvil->Log->entry({source => $THIS_FILE, line => __LINE__, 'print' => 1, level => 1, key => "message_0240"});
$anvil->nice_exit({exit_code => 1});
}
$anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => {
"switches::anvil" => $anvil->data->{switches}{'anvil'},
"switches::host" => $anvil->data->{switches}{'host'},
"switches::y" => $anvil->data->{switches}{'y'},
"switches::yes" => $anvil->data->{switches}{'yes'},
}});
$anvil->data->{purge}{anvil_uuid} = "";
$anvil->data->{purge}{anvil_name} = "";
$anvil->data->{purge}{host_uuid} = "";
$anvil->data->{purge}{host_name} = "";
$anvil->data->{purge}{hosts} = [];
$anvil->Database->get_anvils();
$anvil->Database->get_hosts({include_deleted => 1});
my $vacuum = 0;
if ($anvil->data->{switches}{'anvil'})
{
my $anvil_name = "";
my $anvil_uuid = "";
if ($anvil->Validate->uuid({uuid => $anvil->data->{switches}{'anvil'}}))
{
$anvil_uuid = $anvil->data->{switches}{'anvil'};
$anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { anvil_uuid => $anvil_uuid }});
# Convert it to an Anvil! name.
$anvil->data->{purge}{anvil_uuid} = $anvil_uuid;
$anvil->data->{purge}{anvil_name} = exists $anvil->data->{anvils}{anvil_uuid}{$anvil_uuid} ? $anvil->data->{anvils}{anvil_uuid}{$anvil_uuid}{anvil_name} : "";
$anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => {
"purge::anvil_uuid" => $anvil->data->{purge}{anvil_uuid},
"purge::anvil_name" => $anvil->data->{purge}{anvil_name},
}});
if (not $anvil->data->{purge}{anvil_name})
{
# Bad anvil_uuid
$anvil->Log->entry({source => $THIS_FILE, line => __LINE__, 'print' => 1, level => 1, key => "error_0302", priority => "err", variables => { anvil_uuid => $anvil->data->{switches}{'anvil'} }});
$anvil->nice_exit({exit_code => 1});
}
}
else
{
# Look for the name.
$anvil_name = $anvil->data->{switches}{'anvil'};
$anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { anvil_name => $anvil_name }});
$anvil->data->{purge}{anvil_name} = $anvil_name;
$anvil->data->{purge}{anvil_uuid} = exists $anvil->data->{anvils}{anvil_name}{$anvil_name} ? $anvil->data->{anvils}{anvil_name}{$anvil_name}{anvil_uuid} : "";
$anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => {
"purge::anvil_uuid" => $anvil->data->{purge}{anvil_uuid},
"purge::anvil_name" => $anvil->data->{purge}{anvil_name},
}});
if (not $anvil->data->{purge}{anvil_uuid})
{
# Bad anvil name.
$anvil->Log->entry({source => $THIS_FILE, line => __LINE__, 'print' => 1, level => 1, key => "error_0302", priority => "err", variables => { anvil_uuid => $anvil->data->{switches}{'anvil'} }});
$anvil->nice_exit({exit_code => 1});
}
}
# Load the list of hosts.
$anvil_uuid = $anvil->data->{purge}{anvil_uuid};
push @{$anvil->data->{purge}{hosts}}, $anvil->data->{anvils}{anvil_uuid}{$anvil_uuid}{anvil_node1_host_uuid};
push @{$anvil->data->{purge}{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 @{$anvil->data->{purge}{hosts}}, $anvil->data->{anvils}{anvil_uuid}{$anvil_uuid}{anvil_dr1_host_uuid};
}
}
elsif($anvil->data->{switches}{'host'})
{
my $host_uuid = "";
my $host_name = "";
if ($anvil->Validate->uuid({uuid => $anvil->data->{switches}{'host'}}))
{
$host_uuid = $anvil->data->{switches}{'host'};
$anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { host_uuid => $host_uuid }});
# Convert it to an Anvil! name.
$anvil->data->{purge}{host_uuid} = $host_uuid;
$anvil->data->{purge}{host_name} = exists $anvil->data->{hosts}{host_uuid}{$host_uuid} ? $anvil->data->{hosts}{host_uuid}{$host_uuid}{host_name} : "";
$anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => {
"purge::host_uuid" => $anvil->data->{purge}{host_uuid},
"purge::host_name" => $anvil->data->{purge}{host_name},
}});
if (not $anvil->data->{purge}{host_name})
{
# Bad host_uuid
$anvil->Log->entry({source => $THIS_FILE, line => __LINE__, 'print' => 1, level => 1, key => "error_0303", priority => "err", variables => { host_uuid => $anvil->data->{switches}{'host'} }});
$anvil->nice_exit({exit_code => 1});
}
}
else
{
# Look for the name.
$host_name = $anvil->data->{switches}{'host'};
$anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { host_name => $host_name }});
$anvil->data->{purge}{host_name} = $host_name;
$anvil->data->{purge}{host_uuid} = $anvil->Get->host_uuid_from_name({host_name => $host_name});;
$anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => {
"purge::host_uuid" => $anvil->data->{purge}{host_uuid},
"purge::host_name" => $anvil->data->{purge}{host_name},
}});
if (not $anvil->data->{purge}{host_uuid})
{
# Bad anvil name.
$anvil->Log->entry({source => $THIS_FILE, line => __LINE__, 'print' => 1, level => 1, key => "error_0303", priority => "err", variables => { host_uuid => $anvil->data->{switches}{'host'} }});
$anvil->nice_exit({exit_code => 1});
}
}
push @{$anvil->data->{purge}{hosts}}, $anvil->data->{purge}{host_uuid};
}
else
{
$anvil->Log->entry({source => $THIS_FILE, line => __LINE__, 'print' => 1, level => 1, key => ""});
$anvil->nice_exit({exit_code => 1});
}
# Ask to confirm.
if (($anvil->data->{switches}{'y'}) or ($anvil->data->{switches}{'yes'}))
{
$anvil->Log->entry({source => $THIS_FILE, line => __LINE__, 'print' => 1, level => 1, key => "message_0241"});
}
else
{
if ($anvil->data->{purge}{anvil_name})
{
# Show the Anvil! and member hosts.
$anvil->Log->entry({source => $THIS_FILE, line => __LINE__, 'print' => 1, level => 1, key => "message_0243", variables => {
anvil_name => $anvil->data->{purge}{anvil_name},
anvil_uuid => $anvil->data->{purge}{anvil_uuid},
}});
my $anvil_uuid = $anvil->data->{purge}{anvil_uuid};
my $anvil_name = $anvil->data->{anvils}{anvil_uuid}{$anvil_uuid}{anvil_name};
my $node1_host_uuid = $anvil->data->{anvils}{anvil_uuid}{$anvil_uuid}{anvil_node1_host_uuid};
my $node2_host_uuid = $anvil->data->{anvils}{anvil_uuid}{$anvil_uuid}{anvil_node2_host_uuid};
$anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => {
anvil_uuid => $anvil_uuid,
anvil_name => $anvil_name,
node1_host_uuid => $node1_host_uuid,
}});
# Node 1;
$anvil->Log->entry({source => $THIS_FILE, line => __LINE__, 'print' => 1, level => 1, key => "message_0244", variables => {
host_name => $anvil->data->{hosts}{host_uuid}{$node1_host_uuid}{host_name},
host_uuid => $node1_host_uuid,
}});
# Node 2;
$anvil->Log->entry({source => $THIS_FILE, line => __LINE__, 'print' => 1, level => 1, key => "message_0244", variables => {
host_name => $anvil->data->{hosts}{host_uuid}{$node2_host_uuid}{host_name},
host_uuid => $node2_host_uuid,
}});
# DR, if set.
if ($anvil->data->{anvils}{anvil_uuid}{$anvil_uuid}{anvil_dr1_host_uuid})
{
my $dr1_host_uuid = $anvil->data->{anvils}{anvil_uuid}{$anvil_uuid}{anvil_dr1_host_uuid};
$anvil->Log->entry({source => $THIS_FILE, line => __LINE__, 'print' => 1, level => 1, key => "message_0244", variables => {
host_name => $anvil->data->{hosts}{host_uuid}{$dr1_host_uuid}{host_name},
host_uuid => $dr1_host_uuid,
}});
}
}
else
{
# Ask the user to confirm the host deletion.
$anvil->Log->entry({source => $THIS_FILE, line => __LINE__, 'print' => 1, level => 1, key => "message_0242", variables => {
host_name => $anvil->data->{purge}{host_name},
host_uuid => $anvil->data->{purge}{host_uuid},
}});
}
print $anvil->Words->string({key => "message_0021"})." ";
chomp(my $answer = <STDIN>);
if ((lc($answer) ne "y") && (lc($answer) ne "yes"))
{
print "\n".$anvil->Words->string({key => "message_0022"})."\n\n";
$anvil->nice_exit({exit_code => 1});
}
}
# List all database tables in reverse order with X_host_uuid tables
$anvil->Database->find_host_uuid_columns({search_column => "host_uuid", main_table => "hosts"});
# For each host
foreach my $host_uuid (@{$anvil->data->{purge}{hosts}})
{
my $host_name = $anvil->data->{hosts}{host_uuid}{$host_uuid}{host_name};
$anvil->Log->entry({source => $THIS_FILE, line => __LINE__, 'print' => 1, level => 1, key => "message_0245", variables => {
host_name => $host_name,
host_uuid => $host_uuid,
}});
my $queries = [];
foreach my $hash_ref (@{$anvil->data->{sys}{database}{uuid_tables}})
{
my $table = $hash_ref->{table};
my $host_uuid_column = $hash_ref->{host_uuid_column};
$anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => {
's1:table' => $table,
's2:host_uuid_column' => $host_uuid_column,
}});
if (($table eq "hosts") && ($anvil->data->{purge}{anvil_uuid}))
{
# Remove this host from the Anvil!
next if not $anvil->data->{purge}{anvil_uuid};
my $anvil_uuid = $anvil->data->{purge}{anvil_uuid};
my $host_key = "";
if ($host_uuid eq $anvil->data->{anvils}{anvil_uuid}{$anvil_uuid}{anvil_node1_host_uuid})
{
$host_key = "anvil_node1_host_uuid";
}
elsif ($host_uuid eq $anvil->data->{anvils}{anvil_uuid}{$anvil_uuid}{anvil_node2_host_uuid})
{
$host_key = "anvil_node2_host_uuid";
}
elsif ($host_uuid eq $anvil->data->{anvils}{anvil_uuid}{$anvil_uuid}{anvil_dr1_host_uuid})
{
$host_key = "anvil_dr1_host_uuid";
}
if ($host_key)
{
my $query = "
UPDATE
anvils
SET
".$host_key." = NULL,
modified_date = ".$anvil->Database->quote($anvil->data->{sys}{database}{timestamp})."
WHERE
anvil_uuid = ".$anvil->Database->quote($anvil_uuid)."
;";
$anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { query => $query }});
push @{$queries}, $query;
}
}
# Just delete the record normally.
if ($anvil->data->{sys}{database}{history_table}{$table})
{
my $query = "DELETE FROM history.".$table." WHERE ".$host_uuid_column." = ".$anvil->Database->quote($host_uuid).";";
$anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { query => $query }});
push @{$queries}, $query;
}
my $query = "DELETE FROM ".$table." WHERE ".$host_uuid_column." = ".$anvil->Database->quote($host_uuid).";";
$anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { query => $query }});
push @{$queries}, $query;
}
# Commit.
$anvil->Database->write({query => $queries, source => $THIS_FILE, line => __LINE__});
$vacuum = 1;
$anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { vacuum => $vacuum }});
}
# If we're deleting an Anvil!, clear it out now.
if ($anvil->data->{purge}{anvil_uuid})
{
# List all database tables in reverse order with X_host_uuid tables
$anvil->Database->find_host_uuid_columns({search_column => "anvil_uuid", main_table => "anvils"});
$anvil->Log->entry({source => $THIS_FILE, line => __LINE__, 'print' => 1, level => 1, key => "message_0246", variables => {
anvil_name => $anvil->data->{purge}{anvil_name},
anvil_uuid => $anvil->data->{purge}{anvil_uuid},
}});
my $queries = [];
foreach my $hash_ref (@{$anvil->data->{sys}{database}{uuid_tables}})
{
my $table = $hash_ref->{table};
my $host_uuid_column = $hash_ref->{host_uuid_column};
$anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => {
's1:table' => $table,
's2:host_uuid_column' => $host_uuid_column,
}});
# If the table is 'servers', we need to pull up the server_uuids and delete their definition
# file entries.
if ($table eq "servers")
{
my $query = "SELECT server_uuid FROM servers WHERE server_anvil_uuid = ".$anvil->Database->quote($anvil->data->{purge}{anvil_uuid}).";";
$anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { query => $query }});
my $results = $anvil->Database->query({query => $query, source => $THIS_FILE, line => __LINE__});
my $count = @{$results};
$anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => {
results => $results,
count => $count,
}});
foreach my $row (@{$results})
{
my $server_uuid = $row->[0];
$anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { server_uuid => $server_uuid }});
my $query = "DELETE FROM history.server_definitions WHERE server_definition_server_uuid = ".$anvil->Database->quote($server_uuid).";";
$anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { query => $query }});
push @{$queries}, $query;
$query = "DELETE FROM server_definitions WHERE server_definition_server_uuid = ".$anvil->Database->quote($server_uuid).";";
$anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { query => $query }});
push @{$queries}, $query;
}
}
if ($anvil->data->{sys}{database}{history_table}{$table})
{
my $query = "DELETE FROM history.".$table." WHERE ".$host_uuid_column." = ".$anvil->Database->quote($anvil->data->{purge}{anvil_uuid}).";";
$anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { query => $query }});
push @{$queries}, $query;
}
my $query = "DELETE FROM ".$table." WHERE ".$host_uuid_column." = ".$anvil->Database->quote($anvil->data->{purge}{anvil_uuid}).";";
$anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { query => $query }});
push @{$queries}, $query;
}
# Commit.
$anvil->Database->write({query => $queries, source => $THIS_FILE, line => __LINE__});
$vacuum = 1;
$anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { vacuum => $vacuum }});
}
# Vacuum the database
if ($vacuum)
{
$anvil->Log->entry({source => $THIS_FILE, line => __LINE__, 'print' => 1, level => 1, key => "log_0458"});
my $query = "VACUUM FULL;";
$anvil->Database->write({query => $query, source => $THIS_FILE, line => __LINE__});
}
$anvil->Log->entry({source => $THIS_FILE, line => __LINE__, 'print' => 1, level => 1, key => "message_0025"});
$anvil->nice_exit({exit_code => 0});
Loading…
Cancel
Save