* Updated the database components to use the name 'anvil' and the user 'admin'. The 'database::user' and 'database::name' variables are still supported, but now hidden.

* Fixed a bug where some '$anvil->{}' variables should have been '$anvil->data->{}'.
* Started merging message keys on 'error_xxxx', 'warning_xxxx', etc.
* The anvil-configure-network now configures the network. Commented out, the tool can reconfigure the entire network without a reboot, but a current issue with the post-configured system refusing to use the allocated interface as the default gateway is to be reviewed at a future time. For now, a closing reboot will be issued.
* Started creating 'anvil-change-password' that will update passwords, including apache (and configure .htpasswd when needed).

Signed-off-by: Digimer <digimer@alteeve.ca>
main
Digimer 7 years ago
parent e4f7bcf661
commit a294c6c4fa
  1. 6
      Anvil/Tools.pm
  2. 72
      Anvil/Tools/Database.pm
  3. 46
      Anvil/Tools/System.pm
  4. 6
      Anvil/tools.conf
  5. 2
      README.md
  6. 17
      anvil.conf
  7. 10
      cgi-bin/home
  8. 5
      rpm/SOURCES/README
  9. 203
      rpm/SPECS/anvil.spec
  10. 21
      share/words.xml
  11. 91
      tools/anvil-change-password
  12. 274
      tools/anvil-configure-network
  13. 2
      tools/anvil-daemon
  14. 38
      tools/anvil-prep-database
  15. 2
      tools/anvil-update-states
  16. 4
      tools/anvil.sql

@ -678,6 +678,8 @@ sub _set_defaults
locking_reap_age => 300,
log_transactions => 0,
maximum_batch_size => 25000,
name => "anvil",
user => "admin",
},
host_type => "",
use_base2 => 1,
@ -769,12 +771,15 @@ sub _set_paths
gethostip => "/usr/bin/gethostip",
hostname => "/usr/bin/hostname",
hostnamectl => "/usr/bin/hostnamectl",
ifdown => "/sbin/ifdown",
ifup => "/sbin/ifup",
ip => "/usr/sbin/ip",
'iptables-save' => "/usr/sbin/iptables-save",
journalctl => "/usr/bin/journalctl",
logger => "/usr/bin/logger",
md5sum => "/usr/bin/md5sum",
'mkdir' => "/usr/bin/mkdir",
nmcli => "/bin/nmcli",
ping => "/usr/bin/ping",
pgrep => "/usr/bin/pgrep",
ps => "/usr/bin/ps",
@ -782,6 +787,7 @@ sub _set_paths
'postgresql-setup' => "/usr/bin/postgresql-setup",
pwd => "/usr/bin/pwd",
rsync => "/usr/bin/rsync",
'shutdown' => "/usr/sbin/shutdown",
su => "/usr/bin/su",
systemctl => "/usr/bin/systemctl",
touch => "/usr/bin/touch",

@ -156,7 +156,7 @@ sub check_lock_age
$anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => $debug, list => { "sys::database::local_lock_active" => $anvil->data->{sys}{database}{local_lock_active} }});
}
# If I have an active lock, check its age and also update the ScanCore lock file.
# If I have an active lock, check its age and also update the Anvil! lock file.
my $renewed = 0;
$anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => $debug, list => { "sys::database::local_lock_active" => $anvil->data->{sys}{database}{local_lock_active} }});
if ($anvil->data->{sys}{database}{local_lock_active})
@ -420,7 +420,7 @@ sub configure_pgsql
# Does the database user exist?
my $create_user = 1;
my $database_user = $anvil->data->{database}{$id}{user};
my $database_user = $anvil->data->{database}{$id}{user} ? $anvil->data->{database}{$id}{user} : $anvil->data->{sys}{database}{user};
$anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => $debug, list => { database_user => $database_user }});
if (not $database_user)
{
@ -487,8 +487,8 @@ sub configure_pgsql
# Create the database, if needed.
my $create_database = 1;
my $database_name = $anvil->data->{database}{$id}{name};
$anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => $debug, list => { "database::${id}::name" => $anvil->data->{database}{$id}{name} }});
my $database_name = defined $anvil->data->{database}{$id}{name} ? $anvil->data->{database}{$id}{name} : $anvil->data->{sys}{database}{name};
$anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => $debug, list => { database_name => $database_name }});
my $database_list = $anvil->System->call({shell_call => $anvil->data->{path}{exe}{su}." - postgres -c \"".$anvil->data->{path}{exe}{psql}." template1 -c 'SELECT datname FROM pg_catalog.pg_database;'\"", source => $THIS_FILE, line => __LINE__});
$anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => $debug, list => { database_list => $database_list }});
@ -556,15 +556,11 @@ This method tries to connect to all databases it knows of. To define databases f
database::1::host = an-striker01.alteeve.com
database::1::port = 5432
database::1::name = scancore
database::1::user = admin
database::1::password = Initial1
database::1::ping = 0.25
database::2::host = an-striker02.alteeve.com
database::2::port = 5432
database::2::name = scancore
database::2::user = admin
database::2::password = Initial1
database::2::ping = 0.25
@ -673,8 +669,8 @@ sub connect
my $driver = "DBI:Pg";
my $host = $anvil->data->{database}{$id}{host} ? $anvil->data->{database}{$id}{host} : ""; # This should fail
my $port = $anvil->data->{database}{$id}{port} ? $anvil->data->{database}{$id}{port} : 5432;
my $name = $anvil->data->{database}{$id}{name} ? $anvil->data->{database}{$id}{name} : ""; # This should fail
my $user = $anvil->data->{database}{$id}{user} ? $anvil->data->{database}{$id}{user} : ""; # This should fail
my $name = $anvil->data->{database}{$id}{name} ? $anvil->data->{database}{$id}{name} : $anvil->data->{sys}{database}{name};
my $user = $anvil->data->{database}{$id}{user} ? $anvil->data->{database}{$id}{user} : $anvil->data->{sys}{database}{user};
my $password = $anvil->data->{database}{$id}{password} ? $anvil->data->{database}{$id}{password} : "";
$anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => $debug, list => {
host => $host,
@ -980,11 +976,13 @@ sub connect
# Report any failed DB connections
foreach my $id (@{$failed_connections})
{
my $database_name = defined $anvil->data->{database}{$id}{name} ? $anvil->data->{database}{$id}{name} : "--";
my $database_user = defined $anvil->data->{database}{$id}{user} ? $anvil->data->{database}{$id}{user} : "--";
$anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => $debug, list => {
"database::${id}::host" => $anvil->data->{database}{$id}{host},
"database::${id}::port" => $anvil->data->{database}{$id}{port},
"database::${id}::name" => $anvil->data->{database}{$id}{name},
"database::${id}::user" => $anvil->data->{database}{$id}{user},
"database::${id}::name" => $database_name,
"database::${id}::user" => $database_user,
"database::${id}::password" => $anvil->Log->secure ? $anvil->data->{database}{$id}{password} : "--",
}});
@ -993,7 +991,7 @@ sub connect
# Delete this DB so that we don't try to use it later. This is a quiet alert because the
# original connection error was likely logged.
my $say_server = $anvil->data->{database}{$id}{host}.":".$anvil->data->{database}{$id}{port}." -> ".$anvil->data->{database}{$id}{name};
my $say_server = $anvil->data->{database}{$id}{host}.":".$anvil->data->{database}{$id}{port}." -> ".$database_name;
$anvil->Log->entry({source => $THIS_FILE, line => __LINE__, level => $debug, priority => "alert", key => "log_0092", variables => { server => $say_server, id => $id }});
# Delete it from the list of known databases for this run.
@ -1037,11 +1035,13 @@ sub connect
# Send an 'all clear' message if a now-connected DB previously wasn't.
foreach my $id (@{$successful_connections})
{
my $database_name = defined $anvil->data->{database}{$id}{name} ? $anvil->data->{database}{$id}{name} : "--";
my $database_user = defined $anvil->data->{database}{$id}{user} ? $anvil->data->{database}{$id}{user} : "--";
$anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => $debug, list => {
"database::${id}::host" => $anvil->data->{database}{$id}{host},
"database::${id}::port" => $anvil->data->{database}{$id}{port},
"database::${id}::name" => $anvil->data->{database}{$id}{name},
"database::${id}::user" => $anvil->data->{database}{$id}{user},
"database::${id}::name" => $database_name,
"database::${id}::user" => $database_user,
"database::${id}::password" => $anvil->Log->secure ? $anvil->data->{database}{$id}{password} : "--",
}});
@ -1068,13 +1068,13 @@ sub connect
{
$anvil->Alert->register_alert({
level => "warning",
agent_name => "ScanCore",
agent_name => "Anvil!",
title_key => "an_title_0006",
message_key => "cleared_log_0055",
message_variables => {
name => $anvil->data->{database}{$id}{name},
name => $database_name,
host => $anvil->data->{database}{$id}{host},
port => $anvil->data->{database}{$id}{port} ? $anvil->data->{database}{$id}{port} : 5432,
port => defined $anvil->data->{database}{$id}{port} ? $anvil->data->{database}{$id}{port} : 5432,
},
});
}
@ -1314,7 +1314,8 @@ sub initialize
}});
# This just makes some logging cleaner below.
my $say_server = $anvil->data->{database}{$id}{host}.":".$anvil->data->{database}{$id}{port}." -> ".$anvil->data->{database}{$id}{name};
my $database_name = defined $anvil->data->{database}{$id}{name} ? $anvil->data->{database}{$id}{name} : $anvil->data->{sys}{database}{name};
my $say_server = $anvil->data->{database}{$id}{host}.":".$anvil->data->{database}{$id}{port}." -> ".$database_name;
$anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => $debug, list => { say_server => $say_server }});
if (not $id)
@ -1364,7 +1365,7 @@ sub initialize
}});
# Read in the SQL file and replace #!variable!name!# with the database owner name.
my $user = $anvil->data->{database}{$id}{user};
my $user = $anvil->data->{database}{$id}{user} ? $anvil->data->{database}{$id}{user} : $anvil->data->{sys}{database}{user};
$anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => $debug, list => { user => $user }});
my $sql = $anvil->Storage->read_file({file => $sql_file});
@ -2970,7 +2971,7 @@ sub locking
if ($lock_value)
{
my $variable_uuid = $anvil->ScanCore->insert_or_update_variables({
my $variable_uuid = $anvil->Database->insert_or_update_variables({
variable_name => $variable_name,
variable_value => "",
update_value_only => 1,
@ -2993,7 +2994,7 @@ sub locking
if ($renew)
{
# Yup, do it.
my $variable_uuid = $anvil->ScanCore->insert_or_update_variables({
my $variable_uuid = $anvil->Database->insert_or_update_variables({
variable_name => $variable_name,
variable_value => $variable_value,
update_value_only => 1,
@ -3055,7 +3056,7 @@ sub locking
if ($current_time > $timeout_time)
{
# The lock is stale.
my $variable_uuid = $anvil->ScanCore->insert_or_update_variables({
my $variable_uuid = $anvil->Database->insert_or_update_variables({
variable_name => $variable_name,
variable_value => "",
update_value_only => 1,
@ -3083,7 +3084,7 @@ sub locking
if ($request)
{
# Yup, do it.
my $variable_uuid = $anvil->ScanCore->insert_or_update_variables({
my $variable_uuid = $anvil->Database->insert_or_update_variables({
variable_name => $variable_name,
variable_value => $variable_value,
update_value_only => 1,
@ -3163,7 +3164,7 @@ If an error occurs, C<< !!error!! >> will be returned.
For example, given the query;
scancore=# SELECT host_uuid, host_name, host_type FROM hosts ORDER BY host_name ASC;
anvil=# SELECT host_uuid, host_name, host_type FROM hosts ORDER BY host_name ASC;
host_uuid | host_name | host_type
--------------------------------------+--------------------------+-----------
e27fc9a0-2656-4aaf-80e6-fedb3c339037 | an-a01n01.alteeve.com | node
@ -3243,7 +3244,8 @@ sub query
}});
# Make logging code a little cleaner
my $say_server = $anvil->data->{database}{$id}{host}.":".$anvil->data->{database}{$id}{port}." -> ".$anvil->data->{database}{$id}{name};
my $database_name = defined $anvil->data->{database}{$id}{name} ? $anvil->data->{database}{$id}{name} : $anvil->data->{sys}{database}{name};
my $say_server = $anvil->data->{database}{$id}{host}.":".$anvil->data->{database}{$id}{port}." -> ".$database_name;
if (not $id)
{
@ -3448,10 +3450,10 @@ sub resync_databases
{
$column2 = $1."_uuid";
}
my $query = "SELECT column_name FROM information_schema.columns WHERE table_catalog = 'scancore' AND table_schema = 'public' AND table_name = ".$anvil->data->{sys}{use_db_fh}->quote($table)." AND data_type = 'uuid' AND is_nullable = 'NO' AND column_name = ".$anvil->data->{sys}{use_db_fh}->quote($column1).";";
my $query = "SELECT column_name FROM information_schema.columns WHERE table_catalog = ".$anvil->data->{sys}{use_db_fh}->quote($anvil->data->{sys}{database}{name})." AND table_schema = 'public' AND table_name = ".$anvil->data->{sys}{use_db_fh}->quote($table)." AND data_type = 'uuid' AND is_nullable = 'NO' AND column_name = ".$anvil->data->{sys}{use_db_fh}->quote($column1).";";
if ($column2)
{
$query = "SELECT column_name FROM information_schema.columns WHERE table_catalog = 'scancore' AND table_schema = 'public' AND table_name = ".$anvil->data->{sys}{use_db_fh}->quote($table)." AND data_type = 'uuid' AND is_nullable = 'NO' AND (column_name = ".$anvil->data->{sys}{use_db_fh}->quote($column1)." OR column_name = ".$anvil->data->{sys}{use_db_fh}->quote($column2).");";
$query = "SELECT column_name FROM information_schema.columns WHERE table_catalog = ".$anvil->data->{sys}{use_db_fh}->quote($anvil->data->{sys}{database}{name})." AND table_schema = 'public' AND table_name = ".$anvil->data->{sys}{use_db_fh}->quote($table)." AND data_type = 'uuid' AND is_nullable = 'NO' AND (column_name = ".$anvil->data->{sys}{use_db_fh}->quote($column1)." OR column_name = ".$anvil->data->{sys}{use_db_fh}->quote($column2).");";
}
$anvil->Log->entry({source => $THIS_FILE, line => __LINE__, level => $debug, key => "log_0124", variables => { query => $query }});
my $uuid_column = $anvil->Database->query({query => $query, source => $THIS_FILE, line => __LINE__})->[0]->[0];
@ -3780,7 +3782,7 @@ sub resync_databases
# Show columns;
# SELECT table_catalog, table_schema, table_name, column_name, column_default, is_nullable, data_type FROM information_schema.columns WHERE table_schema = 'public' AND table_name = 'alerts';
# psql -E scancore <<-- LOVE <3
# psql -E anvil <<-- LOVE <3
return(0);
}
@ -3815,7 +3817,8 @@ sub write
}});
# Make logging code a little cleaner
my $say_server = $id eq "" ? "#!string!log_0129!#" : $anvil->data->{database}{$id}{host}.":".$anvil->data->{database}{$id}{port}." -> ".$anvil->data->{database}{$id}{name};
my $database_name = defined $anvil->data->{database}{$id}{name} ? $anvil->data->{database}{$id}{name} : $anvil->data->{sys}{database}{name};
my $say_server = $id eq "" ? "#!string!log_0129!#" : $anvil->data->{database}{$id}{host}.":".$anvil->data->{database}{$id}{port}." -> ".$database_name;
#print "id: [$id], say_server: [$say_server]\n";
# We don't check if ID is set here because not being set simply means to write to all available DBs.
@ -4167,11 +4170,13 @@ sub _find_behind_databases
my $source_updated_time = 0;
foreach my $id (sort {$a cmp $b} keys %{$anvil->data->{database}})
{
my $database_name = defined $anvil->data->{database}{$id}{name} ? $anvil->data->{database}{$id}{name} : "--";
my $database_user = defined $anvil->data->{database}{$id}{user} ? $anvil->data->{database}{$id}{user} : "--";
$anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => $debug, list => {
"database::${id}::host" => $anvil->data->{database}{$id}{host},
"database::${id}::port" => $anvil->data->{database}{$id}{port},
"database::${id}::name" => $anvil->data->{database}{$id}{name},
"database::${id}::user" => $anvil->data->{database}{$id}{user},
"database::${id}::name" => $database_name,
"database::${id}::user" => $database_user,
"database::${id}::password" => $anvil->Log->secure ? $anvil->data->{database}{$id}{password} : "--",
}});
@ -4353,7 +4358,8 @@ sub _test_access
$anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => $debug, list => { id => $id }});
# Make logging code a little cleaner
my $say_server = $anvil->data->{database}{$id}{host}.":".$anvil->data->{database}{$id}{port}." -> ".$anvil->data->{database}{$id}{name};
my $database_name = defined $anvil->data->{database}{$id}{name} ? $anvil->data->{database}{$id}{name} : $anvil->data->{sys}{database}{name};
my $say_server = $anvil->data->{database}{$id}{host}.":".$anvil->data->{database}{$id}{port}." -> ".$database_name;
# Log our test
$anvil->Log->entry({source => $THIS_FILE, line => __LINE__, level => $debug, key => "log_0087", variables => { server => $say_server }});

@ -382,7 +382,7 @@ sub get_ips
my $self = shift;
my $parameter = shift;
my $anvil = $self->parent;
my $debug = defined $parameter->{debug} ? $parameter->{debug} : 2;
my $debug = defined $parameter->{debug} ? $parameter->{debug} : 3;
$anvil->Log->entry({source => $THIS_FILE, line => __LINE__, level => $debug, key => "log_0125", variables => { method => "System->get_ips()" }});
my $in_iface = "";
@ -427,7 +427,7 @@ sub get_ips
my $mac = $1;
$anvil->data->{sys}{networks}{$in_iface}{mac} = $mac;
$anvil->data->{sys}{mac}{$mac}{iface} = $in_iface;
$anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => $debug, list => {
$anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => {
"sys::networks::${in_iface}::mac" => $anvil->data->{sys}{networks}{$in_iface}{mac},
"sys::mac::${mac}::iface" => $anvil->data->{sys}{mac}{$mac}{iface},
}});
@ -889,9 +889,9 @@ sub pids
}});
# If we stored this data before, delete it as it is now stale.
if (exists $anvil->{pids})
if (exists $anvil->data->{pids})
{
delete $anvil->{pids};
delete $anvil->data->{pids};
}
my $my_pid = $$;
my $pids = [];
@ -947,26 +947,26 @@ sub pids
}
# Store by PID
$anvil->{pids}{$pid}{user} = $user;
$anvil->{pids}{$pid}{cpu} = $cpu;
$anvil->{pids}{$pid}{memory} = $memory;
$anvil->{pids}{$pid}{virtual_memory_size} = $virtual_memory_size;
$anvil->{pids}{$pid}{resident_set_size} = $resident_set_size;
$anvil->{pids}{$pid}{control_terminal} = $control_terminal;
$anvil->{pids}{$pid}{state_codes} = $state_codes;
$anvil->{pids}{$pid}{start_time} = $start_time;
$anvil->{pids}{$pid}{'time'} = $time;
$anvil->{pids}{$pid}{command} = $command;
$anvil->data->{pids}{$pid}{user} = $user;
$anvil->data->{pids}{$pid}{cpu} = $cpu;
$anvil->data->{pids}{$pid}{memory} = $memory;
$anvil->data->{pids}{$pid}{virtual_memory_size} = $virtual_memory_size;
$anvil->data->{pids}{$pid}{resident_set_size} = $resident_set_size;
$anvil->data->{pids}{$pid}{control_terminal} = $control_terminal;
$anvil->data->{pids}{$pid}{state_codes} = $state_codes;
$anvil->data->{pids}{$pid}{start_time} = $start_time;
$anvil->data->{pids}{$pid}{'time'} = $time;
$anvil->data->{pids}{$pid}{command} = $command;
$anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => $debug, list => {
"pids::${pid}::cpu" => $anvil->{pids}{$pid}{cpu},
"pids::${pid}::memory" => $anvil->{pids}{$pid}{memory},
"pids::${pid}::virtual_memory_size" => $anvil->{pids}{$pid}{virtual_memory_size},
"pids::${pid}::resident_set_size" => $anvil->{pids}{$pid}{resident_set_size},
"pids::${pid}::control_terminal" => $anvil->{pids}{$pid}{control_terminal},
"pids::${pid}::state_codes" => $anvil->{pids}{$pid}{state_codes},
"pids::${pid}::start_time" => $anvil->{pids}{$pid}{start_time},
"pids::${pid}::time" => $anvil->{pids}{$pid}{'time'},
"pids::${pid}::command" => $anvil->{pids}{$pid}{command},
"pids::${pid}::cpu" => $anvil->data->{pids}{$pid}{cpu},
"pids::${pid}::memory" => $anvil->data->{pids}{$pid}{memory},
"pids::${pid}::virtual_memory_size" => $anvil->data->{pids}{$pid}{virtual_memory_size},
"pids::${pid}::resident_set_size" => $anvil->data->{pids}{$pid}{resident_set_size},
"pids::${pid}::control_terminal" => $anvil->data->{pids}{$pid}{control_terminal},
"pids::${pid}::state_codes" => $anvil->data->{pids}{$pid}{state_codes},
"pids::${pid}::start_time" => $anvil->data->{pids}{$pid}{start_time},
"pids::${pid}::time" => $anvil->data->{pids}{$pid}{'time'},
"pids::${pid}::command" => $anvil->data->{pids}{$pid}{command},
}});
if ($command =~ /$program_name/)

@ -43,7 +43,7 @@
### Database
# To keep ScanCore's database growth in check, an auto-archive mechanism is
# To keep Anvil!'s database growth in check, an auto-archive mechanism is
# used by some agents where, at the end of each scan, the number of records in
# the history schema for a given table are counted (restricted to the agent's
# host, when appropriate).
@ -57,7 +57,7 @@
# To protect against the potential of using too much disk space, archives are
# off by default. Under normal behaviour, old records are simple removed. To
# enable the archive function, set this to '1'.
#scancore::archive::save_to_disk = 1
#sys::database::archive::save_to_disk = 1
#
# When archiving to disk is enabled, to protect against large memory use or
# long archive times in the case where the number of records to archive are
@ -75,7 +75,7 @@
#
# To disable auto-archiving entirely, set 'trigger' to '0'.
#
# NOTE: If the archive directory doesn't exist, ScanCore will create it
# NOTE: If the archive directory doesn't exist, Anvil! will create it
# automatically the first time it is needed.
sys::database::archive::compress = 1
sys::database::archive::count = 50000

@ -6,5 +6,5 @@ Major components;
* The "Striker" Web interface
* Tools for Striker dashboards, Anvil! nodes and DR targets
This project is being designed for RHEL7, Pacemaker, DRBD v9 and corosync.
This project is being designed for RHEL 7, Pacemaker, DRBD v9, Corosync 3 and Kronosnet.

@ -1,4 +1,4 @@
### This is the main Striker (and ScanCore) configuration file.
### This is the main Anvil! configuration file.
#
# Database connections;
#
@ -9,8 +9,6 @@
# There are six variables for each database definition;
# host = This is the (resolvable) host name or IP address of the peer database.
# port = This is the TCP port used to connect to the database. By default, it is 5432
# name = This is the name of the database itself. By default (and almost always), it is 'scancore'.
# user = This is the user that owns the database. By default (and almost always), it is 'admin'.
# password = This is the password used to connect to the database.
# NOTE: Do not directly change the database password. Please use 'anvil-update-password' so that
# the WebUI, database, nodes and peers are all kept in sync.
@ -25,22 +23,19 @@
# offline, it will take about 3 seconds on average for the connection attempt to timeout. This
# might be necessary if the peer dashboard is behind a firewall/router or otherwise can't respond
# to ICMP pings.
# NOTE: The database is called 'anvil' and the database owner is 'admin'.
database::1::host = 192.168.122.201
database::1::port = 5432
database::1::name = scancore
database::1::user = admin
database::1::password = Initial1
database::1::ping = 1
database::2::host = 192.168.122.202
database::2::port = 5432
database::2::name = scancore
database::2::user = admin
database::2::password = Initial1
database::2::ping = 1
# This is the schema for the ScanCore database.
# This is the schema for the Anvil! database.
sys::database::schema = /usr/sbin/anvil/anvil.sql
# This puts a limit on how many queries (writes, generally) to make in a single batch transaction. This is
@ -100,7 +95,7 @@ sys::database::schema = /usr/sbin/anvil/anvil.sql
### Database
# To keep ScanCore's database growth in check, an auto-archive mechanism is
# To keep Anvil!'s database growth in check, an auto-archive mechanism is
# used by some agents where, at the end of each scan, the number of records in
# the history schema for a given table are counted (restricted to the agent's
# host, when appropriate).
@ -114,7 +109,7 @@ sys::database::schema = /usr/sbin/anvil/anvil.sql
# To protect against the potential of using too much disk space, archives are
# off by default. Under normal behaviour, old records are simple removed. To
# enable the archive function, set this to '1'.
#scancore::archive::save_to_disk = 1
#sys::database::archive::save_to_disk = 1
#
# When archiving to disk is enabled, to protect against large memory use or
# long archive times in the case where the number of records to archive are
@ -132,7 +127,7 @@ sys::database::schema = /usr/sbin/anvil/anvil.sql
#
# To disable auto-archiving entirely, set 'trigger' to '0'.
#
# NOTE: If the archive directory doesn't exist, ScanCore will create it
# NOTE: If the archive directory doesn't exist, Anvil! will create it
# automatically the first time it is needed.
sys::database::archive::compress = 1
sys::database::archive::count = 50000

@ -39,7 +39,7 @@ $anvil->Storage->read_config({file => "/etc/anvil/anvil.conf"});
if (not $anvil->Get->host_uuid)
{
# Too early, exit.
print $anvil->Words->string({key => "striker_error_0002"});
print $anvil->Words->string({key => "error_0002"});
$anvil->nice_exit({exit_code => 1});
}
@ -51,7 +51,7 @@ $anvil->Log->entry({source => $THIS_FILE, line => __LINE__, level => 2, key => "
if (not $connections)
{
# No databases, exit.
print $anvil->Words->string({key => "striker_error_0003"});
print $anvil->Words->string({key => "error_0003"});
$anvil->nice_exit({exit_code => 2});
}
@ -1060,7 +1060,7 @@ sub sanity_check_step2
$anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 1, list => { sane => $sane, "cgi::gateway::alert" => $anvil->data->{cgi}{gateway}{alert} }});
# Explain the problem
$anvil->data->{form}{error_massage} = $anvil->Template->get({file => "main.html", name => "error_message", variables => { error_message => $anvil->Words->string({key => "striker_error_0004"}) }});
$anvil->data->{form}{error_massage} = $anvil->Template->get({file => "main.html", name => "error_message", variables => { error_message => $anvil->Words->string({key => "error_0004"}) }});
}
}
@ -1212,7 +1212,7 @@ sub sanity_check_step1
if ($interface_count < $required_interfaces_for_single)
{
# Build the error message.
my $say_message = $anvil->Words->string({key => "striker_error_0001", variables => {
my $say_message = $anvil->Words->string({key => "error_0001", variables => {
interface_count => $interface_count,
required_interfaces_for_single => $required_interfaces_for_single,
}});
@ -1376,7 +1376,7 @@ sub get_network_details
### TODO: Daemonize this or solve selinux issues
### Refresh the network.xml
#$anvil->System->call({shell_call => $anvil->data->{path}{exe}{'scancore-update-states'}});
#$anvil->System->call({shell_call => $anvil->data->{path}{exe}{'anvil-update-states'}});
# Now read the network.xml
my $file = $anvil->data->{path}{directories}{html}."/status/network.xml";

@ -0,0 +1,5 @@
The 'master.tar.gz' file from the anvil github repo:
https://github.com/digimer/anvil should be stored in this directory when
building the .spec file.
* wget -c https://github.com/digimer/anvil/archive/master.zip

@ -0,0 +1,203 @@
%define debug_package %{nil}
Name: anvil
Version: 3.0
Release: 3%{?dist}
Summary: Alteeve Anvil! complete package.
License: GPLv2+
URL: https://github.com/digimer/anvil
Source0: https://github.com/digimer/anvil/archive/master.tar.gz
BuildArch: noarch
%description
This package generates the anvil-core, anvil-striker, anvil-node and anvil-dr
RPM's. The 'core' RPM is common to all machines in an Anvil! cluster, with the
other three used for each machine, given its roll.
WARNING: This is an alpha-stage project. Many features are missing and this
should not be used for anything other than development purposes! The
first stable release will be 3.1. Anything 3.0 is UNSTABLE.
%package core
Summary: Alteeve's Anvil! Core package
Requires: bash-completion
Requires: bind-utils
Requires: fence-agents-all
Requires: fence-agents-virsh
Requires: firewalld
Requires: gpm
Requires: mlocate
Requires: perl-Data-Dumper
Requires: perl-DBD-Pg
Requires: perl-DBI
Requires: perl-JSON
Requires: perl-Log-Journald
Requires: perl-Net-SSH2
Requires: perl-NetAddr-IP
Requires: perl-XML-Simple
Requires: postgresql-contrib
Requires: postgresql-plperl
Requires: rsync
Requires: screen
Requires: vim
# iptables-services conflicts with firewalld
Conflicts: iptables-services
# We handle interface naming
Conflicts: biosdevname
%description core
Common base libraries required for the Anvil! system.
%package striker
Summary: Alteeve's Anvil! Striker dashboard package
BuildRequires: httpd
Requires: anvil-core
Requires: httpd
Requires: nmap
Requires: perl-CGI
Requires: postgresql-server
# A Striker dashboard is not allowed to host servers or be a migration target.
# So the node and dr packages can not be installed.
Conflicts: anvil-node
Conflicts: anvil-dr
%description striker
Web interface of the Striker dashboard for Alteeve Anvil! systems
%package node
Summary: Alteeve's Anvil! node package
Requires: anvil-core
Requires: bridge-utils
Requires: drbd
Requires: drbd-bash-completion
Requires: drbd-kernel
Requires: drbd-utils
Requires: kernel-doc
Requires: kmod-drbd
Requires: libvirt
Requires: libvirt-daemon
Requires: libvirt-daemon-driver-qemu
Requires: libvirt-daemon-kvm
Requires: libvirt-docs
Requires: pacemaker
Requires: pcs
Requires: qemu-kvm
Requires: qemu-kvm-common
Requires: qemu-kvm-tools
Requires: virt-install
# A node is allowed to host servers and be a live migration target. It is not
# allowed to host a database or be a DR host.
Conflicts: anvil-striker
Conflicts: anvil-dr
%description node
Provides support for active node in an Anvil! pair.
NOTE: On RHEL proper, this requires the node had the "High-Availability
Add-on".
NOTE: LINBIT customers must have access to the LINBIT repositories configured.
%package dr
Summary: Alteeve's Anvil! DR host package
Requires: anvil-core
Requires: bridge-utils
Requires: drbd
Requires: drbd-bash-completion
Requires: drbd-kernel
Requires: drbd-utils
Requires: kernel-doc
Requires: kmod-drbd
Requires: libvirt
Requires: libvirt-daemon
Requires: libvirt-daemon-driver-qemu
Requires: libvirt-daemon-kvm
Requires: libvirt-docs
Requires: qemu-kvm
Requires: qemu-kvm-common
Requires: qemu-kvm-tools
Requires: virt-install
# A DR host is not allowed to be a live-migration target or host a database.
Conflicts: anvil-striker
Conflicts: anvil-node
%description dr
Provides support for asynchronous disaster recovery hosts in an Anvil! cluster.
%prep
%autosetup -n anvil-master
%build
%install
rm -rf $RPM_BUILD_ROOT
mkdir -p %{buildroot}/%{_sbindir}/anvil/
mkdir -p %{buildroot}/%{_sysconfdir}/anvil/
mkdir -p %{buildroot}/%{_localstatedir}/www/
install -d -p Anvil %{buildroot}/%{_datadir}/perl5/
install -d -p html %{buildroot}/%{_localstatedir}/www/
install -d -p cgi-bin %{buildroot}/%{_localstatedir}/www/
install -d -p units/ %{buildroot}/usr/lib/systemd/system/
install -d -p tools/ %{buildroot}/%{_sbindir}/
cp -R -p Anvil %{buildroot}/%{_datadir}/perl5/
cp -R -p html %{buildroot}/%{_localstatedir}/www/
cp -R -p cgi-bin %{buildroot}/%{_localstatedir}/www/
cp -R -p units/* %{buildroot}/usr/lib/systemd/system/
cp -R -p tools/* %{buildroot}/%{_sbindir}
cp -R -p anvil.conf %{buildroot}/%{_sysconfdir}/anvil/
cp -R -p anvil.version %{buildroot}/%{_sysconfdir}/anvil/
mv %{buildroot}/%{_sbindir}/anvil.sql %{buildroot}/%{_datadir}/anvil.sql
mv %{buildroot}/%{_sbindir}/snmp-models.json %{buildroot}/%{_sysconfdir}/anvil/snmp-models.json
sed -i "1s/^.*$/%{version}/" %{buildroot}/%{_sysconfdir}/anvil/anvil.version
%post
restorecon -rv %{buildroot}/%{_localstatedir}/www
%post striker
systemctl enable httpd.service
systemctl start httpd.service
%files core
%doc README.md notes
%config(noreplace) %{_sysconfdir}/anvil/anvil.conf
%config(noreplace) %{_datadir}/anvil.sql
%{_usr}/lib/*
%{_sbindir}/*
%{_sysconfdir}/anvil/anvil.version
%{_datadir}/perl5/*
%files striker
%attr(0775, apache, root) %{_localstatedir}/www/*/*
%{_sysconfdir}/anvil/snmp-models.json
%ghost %{_sysconfdir}/anvil/snmp-vendors.txt
%files node
#<placeholder for node specific files>
%files dr
#<placeholder for node specific files>
%changelog
* Sun Mar 18 2018 Madison Kelly <mkelly@alteeve.ca> 3.0-3
- Changed the 'Obsoletes' to 'Conflicts'.
* Sat Mar 17 2018 Madison Kelly <mkelly@alteeve.ca> 3.0-2
- Added a post task to striker to enable/start apache.
* Wed Mar 14 2018 Madison Kelly <mkelly@alteeve.ca> 3.0-1
- Dropped the 'a' from the version.
- Expanded the list of requirements.
- Added the 'node' and 'dr' packages.
* Fri Jan 26 2018 Matthew Marangoni <matthew.marangoni@senecacollege.ca> 3.0a-1
- Initial RPM release

@ -9,7 +9,7 @@ Author: Madison Kelly <mkelly@alteeve.ca>
<words>
<meta version="3.0.0" languages="en_CA,jp"/>
<!-- Canadian English -->
<language name="en_CA" long_name="Canadian English" description="Striker/ScanCore language file.">
<language name="en_CA" long_name="Canadian English" description="Anvil! language file.">
<!-- Alert titles -->
<key name="alert_title_0001">Debug</key>
@ -172,18 +172,18 @@ The database connection error was:
- Name: ......... [#!variable!name!#]
- Timestamp: .... [#!variable!modified_date!#]
</key>
<key name="log_0099">[ Error ] - There is no ScanCore database user set for the local machine. Please check: [#!data!path::config::anvil.conf!#]'s DB entry: [#!variable!id!#].</key>
<key name="log_0099">[ Error ] - There is no Anvil! database user set for the local machine. Please check: [#!data!path::config::anvil.conf!#]'s DB entry: [#!variable!id!#].</key>
<key name="log_0100">Database user: [#!variable!user!#] password has been set/updated.</key>
<key name="log_0101"><![CDATA[[ Error ] - The method Alert->register_alert() was called but the 'title_key' parameter was not passed or it is empty and 'header' is enable (default).]]></key>
<key name="log_0102">I am not recording the alert with message_key: [#!variable!message_key!#] to the database because its log level was lower than any recipients.</key>
<key name="log_0103">The local machine's UUID was not read properly. It should be stored in: [#!data!sys::host_uuid!#] and contain hexadecimal characters in the format: '012345-6789-abcd-ef01-23456789abcd' and usually matches the output of 'dmidecode --string system-uuid'. If this file exists and if there is a string in the file, please verify that it is structured correctly.</key>
<key name="log_0104">The database with ID: [#!variable!id!#] for: [#!variable!file!#] is behind.</key>
<key name="log_0105">ScanCore database: [#!variable!database!#] already exists.</key>
<key name="log_0105">Anvil! database: [#!variable!database!#] already exists.</key>
<key name="log_0106">The database with ID: [#!variable!id!#] is behind. A database esync will be requested.</key>
<key name="log_0107">[ Warning ] - Failed to delete the temporary postgres password.</key>
<key name="log_0108"><![CDATA[[ Error ] - The method Database->insert_or_update_states() was called but the 'state_host_uuid' parameter was not passed or it is empty. Normally this is set to 'sys::data_uuid'.]]></key>
<key name="log_0109">[ Error ] - Failed to create the ScanCore database: [#!variable!database!#]</key>
<key name="log_0110">ScanCore database: [#!variable!database!#] created.</key>
<key name="log_0109">[ Error ] - Failed to create the Anvil! database: [#!variable!database!#]</key>
<key name="log_0110">Anvil! database: [#!variable!database!#] created.</key>
<key name="log_0111">[ Warning ] - Failed to reload the Postgres server. Please check the system logs for details. The updated configuration is probably not active yet.</key>
<key name="log_0112">Reloaded the PostgreSQL database server.</key>
<key name="log_0113"><![CDATA[[ Note ] - The 'Database->configure_pgsql() method was called but the parent program is not running with root priviledges. Returning without doing anything.]]></key>
@ -319,10 +319,11 @@ Here we will inject 't_0006', which injects 't_0001' which has a variable: [#!st
<key name="striker_warning_0001">The IP address will change. You will need to reconnect after applying these changes.</key>
<!-- Errors -->
<key name="striker_error_0001">There are not enough network interfaces on this machine. You have: [#!variable!interface_count!#] interface(s), and you need at least: [#!variable!required_interfaces_for_single!#] interfaces to connect to the requested networks (one for Back-Channel and one for each Internet-Facing network).</key>
<key name="striker_error_0002">The local system UUID can't be read yet. This might be because the system is brand new and/or ScanCore hasn't run yet. Please try again in a minute.</key>
<key name="striker_error_0003">None of the databases are accessible, unable to proceed.</key>
<key name="striker_error_0004">The gateway address doesn't match any of your networks.</key>
<key name="error_0001">There are not enough network interfaces on this machine. You have: [#!variable!interface_count!#] interface(s), and you need at least: [#!variable!required_interfaces_for_single!#] interfaces to connect to the requested networks (one for Back-Channel and one for each Internet-Facing network).</key>
<key name="error_0002">The local system UUID can't be read yet. This might be because the system is brand new and/or ScanCore hasn't run yet. Please try again in a minute.</key>
<key name="error_0003">None of the databases are accessible, unable to proceed.</key>
<key name="error_0004">The gateway address doesn't match any of your networks.</key>
<key name="error_0005">This program must run with 'root' level privileges.</key>
<!-- These are works and strings used by javascript/jqery -->
<key name="js_0001">Up</key>
@ -331,7 +332,7 @@ Here we will inject 't_0006', which injects 't_0001' which has a variable: [#!st
</language>
<!-- 日本語 -->
<language name="jp" long_name="日本語" description="Striker/ScanCore language file.">
<language name="jp" long_name="日本語" description="Anvil! language file.">
<!-- Test words. Do NOT change unless you update 't/Words.t' or tests will needlessly fail. -->
<key name="t_0000">テスト</key>

@ -0,0 +1,91 @@
#!/usr/bin/perl
#
# This program sets/changes passwords on the Anvil! platform (nodes and dashboards).
#
# Exit codes;
# 0 = Normal exit.
# 1 = The program is not running as root.
# 2 = Failed to connect to database(s).
#
use strict;
use warnings;
use Data::Dumper;
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;
# Prevent a discrepency between UID/GID and EUID/EGID from throwing an error.
$< = $>;
$( = $);
my $anvil = Anvil::Tools->new();
$anvil->Log->level({set => 2});
$anvil->Log->secure({set => 0});
# Read switches
$anvil->Get->switches;
# Paths
$anvil->Storage->read_config({file => $anvil->data->{path}{config}{'anvil.conf'}});
# Make sure we're running as 'root'
# $< == real UID, $> == effective UID
if (($< != 0) && ($> != 0))
{
# Not root
print $anvil->Words->string({key => "error_0005"})."\n";
$anvil->nice_exit({code => 1});
}
# Connect
my $connections = $anvil->Database->connect();
$anvil->Log->entry({source => $THIS_FILE, line => __LINE__, level => 2, secure => 0, key => "log_0132", variables => { connections => $connections }});
if (not $connections)
{
# No databases, exit.
print $anvil->Words->string({key => "error_0003"});
$anvil->nice_exit({exit_code => 2});
}
### TODO: Check for access to all known Anvil! nodes and warn the user that they will have to manually update
### the password for us on any node we can't access
### NOTE: 'anvil' can be a name or UUID
# If we're called without an '--anvil' switch, then change the local password only.
if ($anvil->data->{switches}{anvil})
{
# Find the Anvil! and verify access to both nodes. If neither are accessible, abort.
}
else
{
### TODO: Support '--peers' to also update the peer dashboards.
# Updating just ourself
update_local_passwords($anvil);
}
$anvil->nice_exit({code => 0});
#############################################################################################################
# Functions #
#############################################################################################################
# This updates the local passwords.
sub update_local_passwords
{
my ($anvil) = @_;
# Update the local users.
# Update the database password.
return(0);
}

@ -4,8 +4,10 @@
#
# Exit codes;
# 0 = Normal exit.
# 1 = Job was already picked up by another running instance.
# 2 = The host name did not update properly.
# 1 = The program is not running as root.
# 2 = Failed to connect to database(s).
# 3 = Job was already picked up by another running instance.
# 4 = The host name did not update properly.
#
use strict;
@ -33,6 +35,15 @@ $anvil->Get->switches;
# Paths
$anvil->Storage->read_config({file => $anvil->data->{path}{config}{'anvil.conf'}});
# Make sure we're running as 'root'
# $< == real UID, $> == effective UID
if (($< != 0) && ($> != 0))
{
# Not root
print $anvil->Words->string({key => "error_0005"})."\n";
$anvil->nice_exit({code => 1});
}
# Connect
my $connections = $anvil->Database->connect({
sql_file => $anvil->data->{sys}{database}{schema},
@ -44,7 +55,7 @@ $anvil->Log->entry({source => $THIS_FILE, line => __LINE__, level => 3, key => "
if (not $connections)
{
# No databases, exit.
print $anvil->Words->string({key => "striker_error_0003"});
print $anvil->Words->string({key => "error_0003"});
$anvil->nice_exit({exit_code => 2});
}
@ -52,16 +63,32 @@ pickup_job_details($anvil);
reconfigure_network($anvil);
update_passwords($anvil);
# Set the passwords
my $password = $anvil->data->{variables}{form}{config_step2}{striker_password}{value};
$anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, secure => 1, list => { password => $password }});
### TODO: This is only until we can get the damn networking stable on reconfigure.
# Reboot.
#$anvil->System->call({shell_call => $anvil->data->{path}{exe}{'shutdown'}." --reboot now"});
$anvil->nice_exit({code => 0});
#############################################################################################################
# Functions #
#############################################################################################################
# This updates the passwords on the root user, admin user, database and apache user.
sub update_passwords
{
my ($anvil) = @_;
return(0);
}
# This does the work of reconfiguring the network
sub reconfigure_network
{
@ -93,31 +120,31 @@ sub reconfigure_network
if ($hostname eq $new_hostname)
{
# Success
$anvil->{job}{status} .= "message_0016,!!hostname!$new_hostname!!\n";
$anvil->data->{job}{status} .= "message_0016,!!hostname!$new_hostname!!\n";
$anvil->Database->insert_or_update_jobs({
job_uuid => $anvil->{job}{uuid},
job_uuid => $anvil->data->{job}{uuid},
update_progress_only => 1,
job_progress => 10,
job_status => $anvil->{job}{status},
job_status => $anvil->data->{job}{status},
});
$anvil->Log->entry({source => $THIS_FILE, line => __LINE__, level => 1, key => "message_0016", variables => { hostname => $new_hostname }});
}
else
{
# Failed
$anvil->{job}{status} .= "message_0017,!!hostname!$new_hostname!!,!!bad_hostname!$hostname!!\n";
$anvil->{job}{status} .= "failed\n";
$anvil->data->{job}{status} .= "message_0017,!!hostname!$new_hostname!!,!!bad_hostname!$hostname!!\n";
$anvil->data->{job}{status} .= "failed\n";
$anvil->Database->insert_or_update_jobs({
job_uuid => $anvil->{job}{uuid},
job_uuid => $anvil->data->{job}{uuid},
update_progress_only => 1,
job_progress => 100,
job_status => $anvil->{job}{status},
job_status => $anvil->data->{job}{status},
});
$anvil->Log->entry({source => $THIS_FILE, line => __LINE__, level => 0, key => "message_0017", variables => {
hostname => $new_hostname,
bad_hostname => $hostname,
}});
$anvil->nice_exit({code => 2});
$anvil->nice_exit({code => 4});
}
# Get the current list of IPs and MAC addresses.
@ -151,22 +178,30 @@ sub reconfigure_network
next if not $count;
foreach my $network_count (1..$count)
{
my $this_network = $network_type.$network_count;
my $link1_key = $this_network."_iface1_mac";
my $link2_key = $this_network."_iface2_mac";
my $subnet_key = $this_network."_subnet";
my $ip_key = $this_network."_ip";
my $is_gateway = $this_network eq $gateway_interface ? 1 : 0;
my $this_network = $network_type.$network_count;
my $link1_key = $this_network."_iface1_mac";
my $link2_key = $this_network."_iface2_mac";
my $subnet_key = $this_network."_subnet";
my $ip_key = $this_network."_ip";
my $is_gateway = $this_network eq $gateway_interface ? 1 : 0;
my $link1_mac = $anvil->data->{variables}{form}{config_step2}{$link1_key}{value};
my $link2_mac = $anvil->data->{variables}{form}{config_step2}{$link2_key}{value};
my $old_link1_iface = $anvil->data->{sys}{mac}{$link1_mac}{iface} ? $anvil->data->{sys}{mac}{$link1_mac}{iface} : "";
my $old_link2_iface = $anvil->data->{sys}{mac}{$link2_mac}{iface} ? $anvil->data->{sys}{mac}{$link2_mac}{iface} : "";
$anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => {
this_network => $this_network,
link1_key => $link1_key,
link2_key => $link2_key,
subnet_key => $subnet_key,
ip_key => $ip_key,
is_gateway => $is_gateway,
this_network => $this_network,
link1_key => $link1_key,
link2_key => $link2_key,
subnet_key => $subnet_key,
ip_key => $ip_key,
is_gateway => $is_gateway,
link1_mac => $link1_mac,
link2_mac => $link2_mac,
old_link1_iface => $old_link1_iface,
old_link2_iface => $old_link2_iface,
}});
# Skip if this doesn't exist or isn't a valid IPv$ address.
# Skip if this doesn't exist or isn't a valid IPv4 address.
next if not exists $anvil->data->{variables}{form}{config_step2}{$ip_key}{value};
if (($anvil->data->{variables}{form}{config_step2}{$ip_key}{value}) and (not $anvil->Validate->is_ipv4({ip => $anvil->data->{variables}{form}{config_step2}{$ip_key}{value}})))
{
@ -185,18 +220,10 @@ sub reconfigure_network
subnet => $subnet,
}});
if ((exists $anvil->data->{variables}{form}{config_step2}{$link2_key}{value}) && ($anvil->Validate->is_mac({mac => $anvil->data->{variables}{form}{config_step2}{$link2_key}{value}})))
if ($anvil->Validate->is_mac({mac => $link2_mac}))
{
# Bonded
my $link1_mac = $anvil->data->{variables}{form}{config_step2}{$link1_key}{value};
my $link2_mac = $anvil->data->{variables}{form}{config_step2}{$link2_key}{value};
$anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => {
link1_mac => $link1_mac,
link2_mac => $link2_mac,
}});
### TODO: Handle when bridges exist. Detect when the host is a node and/or have a "use as bridge" option?
# Build the configs.
# Bonded; Build the configs.
my $say_network = "";
my $say_interface = "";
my $interface_prefix = "";
@ -218,13 +245,16 @@ sub reconfigure_network
$say_interface = "ifn".$network_count;
$interface_prefix = "IFN";
}
my $say_defroute = $is_gateway ? "yes" : "no";
my $cidr = $anvil->Convert->cidr({subnet => $subnet});
my $bond_file = $anvil->data->{path}{directories}{ifcfg}."/ifcfg-".$interface_prefix."_".$network_count."_-_Bond_1";
my $new_link1_file = $anvil->data->{path}{directories}{ifcfg}."/ifcfg-".$interface_prefix."_".$network_count."_-_Link_1";
my $new_link2_file = $anvil->data->{path}{directories}{ifcfg}."/ifcfg-".$interface_prefix."_".$network_count."_-_Link_2";
my $old_link1_file = $new_link1_file;
my $old_link2_file = $new_link2_file;
my $say_defroute = $is_gateway ? "yes" : "no";
my $cidr = $anvil->Convert->cidr({subnet => $subnet});
my $bond_file = $anvil->data->{path}{directories}{ifcfg}."/ifcfg-".$interface_prefix."_".$network_count."_-_Bond_1";
my $new_link1_file = $anvil->data->{path}{directories}{ifcfg}."/ifcfg-".$interface_prefix."_".$network_count."_-_Link_1";
my $new_link2_file = $anvil->data->{path}{directories}{ifcfg}."/ifcfg-".$interface_prefix."_".$network_count."_-_Link_2";
my $old_link1_file = $new_link1_file;
my $old_link2_file = $new_link2_file;
my $new_bond_iface = $say_interface."_bond1";
my $new_link1_iface = $say_interface."_link1";
my $new_link2_iface = $say_interface."_link2";
if ((exists $anvil->data->{sys}{mac}{$link1_mac}{iface}) && ($anvil->data->{sys}{mac}{$link1_mac}{iface}))
{
$old_link1_file = $anvil->data->{path}{directories}{ifcfg}."/ifcfg-".$anvil->data->{sys}{mac}{$link1_mac}{iface};
@ -234,13 +264,16 @@ sub reconfigure_network
$old_link2_file = $anvil->data->{path}{directories}{ifcfg}."/ifcfg-".$anvil->data->{sys}{mac}{$link2_mac}{iface};
}
$anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => {
say_defroute => $say_defroute,
cidr => $cidr,
bond_file => $bond_file,
new_link2_file => $new_link2_file,
new_link1_file => $new_link1_file,
old_link1_file => $old_link1_file,
old_link2_file => $old_link2_file,
say_defroute => $say_defroute,
cidr => $cidr,
bond_file => $bond_file,
new_link1_file => $new_link1_file,
new_link2_file => $new_link2_file,
old_link1_file => $old_link1_file,
old_link2_file => $old_link2_file,
new_bond_iface => $new_bond_iface,
new_link1_iface => $new_link1_iface,
new_link2_iface => $new_link2_iface,
}});
# Gather (or create) UUIDs
@ -258,7 +291,7 @@ sub reconfigure_network
my $bond_config = "# $say_network - Bond 1\n";
$bond_config .= "UUID=\"".$bond_uuid."\"\n";
$bond_config .= "NAME=\"".$interface_prefix." ".$network_count." - Bond 1\"\n";
$bond_config .= "DEVICE=\"".$say_interface."_bond1\"\n";
$bond_config .= "DEVICE=\"".$new_bond_iface."\"\n";
$bond_config .= "BONDING_OPTS=\"mode=active-backup primary=".$say_interface."_link1 updelay=120000 downdelay=0 miimon=100 primary_reselect=better\"\n";
$bond_config .= "TYPE=\"Bond\"\n";
$bond_config .= "BONDING_MASTER=\"yes\"\n";
@ -282,7 +315,7 @@ sub reconfigure_network
$link1_config .= "HWADDR=\"".uc($link1_mac)."\"\n";
$link1_config .= "UUID=\"".$link1_uuid."\"\n";
$link1_config .= "NAME=\"".$interface_prefix." ".$network_count." - Link 1\"\n";
$link1_config .= "DEVICE=\"".$say_interface."_link1\"\n";
$link1_config .= "DEVICE=\"".$new_link1_iface."\"\n";
$link1_config .= "TYPE=\"Ethernet\"\n";
$link1_config .= "BOOTPROTO=\"none\"\n";
$link1_config .= "IPV6INIT=\"no\"\n";
@ -292,13 +325,13 @@ sub reconfigure_network
$link1_config .= "NM_CONTROLLED=\"yes\"\n";
$link1_config .= "SLAVE=\"yes\"\n";
$link1_config .= "MASTER=\"".$say_interface."_bond1\"\n";
$link1_config .= "ZONE=\"".$say_interface."";
$link1_config .= "ZONE=\"".$say_interface."\"";
my $link2_config = "# $say_network - Link 2\n";
$link2_config .= "HWADDR=\"".uc($link2_mac)."\"\n";
$link2_config .= "UUID=\"".$link2_uuid."\"\n";
$link2_config .= "NAME=\"".$interface_prefix." ".$network_count." - Link 2\"\n";
$link2_config .= "DEVICE=\"".$say_interface."_link2\"\n";
$link2_config .= "DEVICE=\"".$new_link2_iface."\"\n";
$link2_config .= "TYPE=\"Ethernet\"\n";
$link2_config .= "BOOTPROTO=\"none\"\n";
$link2_config .= "IPV6INIT=\"no\"\n";
@ -308,7 +341,7 @@ sub reconfigure_network
$link2_config .= "NM_CONTROLLED=\"yes\"\n";
$link2_config .= "SLAVE=\"yes\"\n";
$link2_config .= "MASTER=\"".$say_interface."_bond1\"\n";
$link2_config .= "ZONE=\"".$say_interface."";
$link2_config .= "ZONE=\"".$say_interface."\"";
$anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => {
bond_config => $bond_config,
@ -324,60 +357,80 @@ sub reconfigure_network
if (-e $new_link2_file) { $anvil->Storage->backup({file => $new_link1_file}); }
### Write out the new configs
# Bond
$anvil->Storage->write_file({
file => $bond_file,
body => $bond_config,
user => "root",
group => "root",
mode => 0644,
});
# Link 1
$anvil->Storage->write_file({
file => $new_link1_file,
body => $link1_config,
user => "root",
group => "root",
mode => 0644,
});
# Link 2
$anvil->Storage->write_file({
file => $new_link2_file,
body => $link2_config,
user => "root",
group => "root",
mode => 0644,
});
# Drop the old interfaces and remove their configs if the interface name has changed.
if ($old_link1_file ne $new_link1_file)
# Bond, Link 1 and Link 2
$anvil->Storage->write_file({file => $bond_file, body => $bond_config, user => "root", group => "root", mode => "0644"});
$anvil->Storage->write_file({file => $new_link1_file, body => $link1_config, user => "root", group => "root", mode => "0644"});
$anvil->Storage->write_file({file => $new_link2_file, body => $link2_config, user => "root", group => "root", mode => "0644"});
### NOTE: Everything except the unlink is disabled until we sort out the reload
# Shut down (and rename) Link 1
if ($old_link1_iface)
{
# Take down and rename the old link 1 interface
#print "Downing: ..... [$old_link1_iface]\n";
#$anvil->System->call({shell_call => $anvil->data->{path}{exe}{ifdown}." ".$old_link1_iface});
#print "Disconnecting: [$old_link1_iface]\n";
#$anvil->System->call({shell_call => $anvil->data->{path}{exe}{ip}." link set ".$old_link1_iface." down"});
}
if ($old_link1_iface ne $new_link1_iface)
{
# Doesn't match, unlink the old file.
$anvil->Log->entry({source => $THIS_FILE, line => __LINE__, level => 0, key => "log_0155", variables => { file => $old_link1_file }});
unlink $old_link1_file;
# Stop the old network interface and rename it.
my $old_iface = $anvil->data->{sys}{mac}{$link1_mac}{iface};
my $new_iface = $say_interface."_link1";
$anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => {
old_iface => $old_iface,
new_iface => $new_iface,
}});
### TODO: This isn't working for already-active interfaces... Says the new interface can't be found.
# Drop the old interface
$anvil->System->call({shell_call => $anvil->data->{path}{exe}{ip}." link set ".$old_iface." down"});
# Rename it
$anvil->System->call({shell_call => $anvil->data->{path}{exe}{ip}." link set ".$old_iface." name ".$new_iface});
#print "Renaming: .... [$old_link1_iface] -> [$new_link1_iface]\n";
#$anvil->System->call({shell_call => $anvil->data->{path}{exe}{ip}." link set ".$old_link1_iface." name ".$new_link1_iface});
# Bring up the interface with the new name
$anvil->System->call({shell_call => $anvil->data->{path}{exe}{ip}." link set ".$old_iface." up"});
# Unllnk the old one, if it exists.
if (-e $old_link1_file)
{
#print "Deleting: .... [$old_link1_file]\n";
unlink $old_link1_file;
}
}
# Drop the new link, too, in case it still has the old config
#print "Downing: ..... [$new_link1_iface]\n";
#$anvil->System->call({shell_call => $anvil->data->{path}{exe}{ifdown}." ".$new_link1_iface});
# Shut down (and rename) Link 2
if ($old_link2_iface)
{
# Take down and rename the old link 1 interface
#print "Downing: ..... [$old_link2_iface]\n";
#$anvil->System->call({shell_call => $anvil->data->{path}{exe}{ifdown}." ".$old_link2_iface});
#print "Disconnecting: [$old_link2_iface]\n";
#$anvil->System->call({shell_call => $anvil->data->{path}{exe}{ip}." link set ".$old_link2_iface." down"});
}
if ($old_link2_iface ne $new_link2_iface)
{
# Rename it
#print "Renaming ..... [$old_link2_iface] -> [$new_link2_iface]\n";
#$anvil->System->call({shell_call => $anvil->data->{path}{exe}{ip}." link set ".$old_link2_iface." name ".$new_link2_iface});
}
# Drop the new link, too, in case it still has the old config
#print "Downing: ..... [$new_link2_iface]\n";
#$anvil->System->call({shell_call => $anvil->data->{path}{exe}{ifdown}." ".$new_link2_iface});
# Start the bond.
#print "Uping: ....... [$new_bond_iface]\n";
#$anvil->System->call({shell_call => $anvil->data->{path}{exe}{ifup}." ".$new_bond_iface});
# Reconnect and up link 1
#print "Uping: ....... [$new_link1_iface]\n";
#$anvil->System->call({shell_call => $anvil->data->{path}{exe}{ifup}." ".$new_link1_iface});
#print "Reconnecting: [$new_link1_iface]\n";
#$anvil->System->call({shell_call => $anvil->data->{path}{exe}{ip}." link set ".$new_link1_iface." up"});
# Reconnect and up link 2
#print "Uping: ....... [$new_link2_iface]\n";
#$anvil->System->call({shell_call => $anvil->data->{path}{exe}{ifup}." ".$new_link2_iface});
#print "Reconnecting: [$new_link2_iface]\n";
#$anvil->System->call({shell_call => $anvil->data->{path}{exe}{ip}." link set ".$new_link2_iface." up"});
# Connect the bond (in case it isn't already)r
#print "Connecting: .. [$new_bond_iface]\n";
#$anvil->System->call({shell_call => $anvil->data->{path}{exe}{ip}." link set ".$new_bond_iface." up"});
}
elsif ((exists $anvil->data->{variables}{form}{config_step2}{$link1_key}{value}) && ($anvil->Validate->is_mac({mac => $anvil->data->{variables}{form}{config_step2}{$link1_key}{value}})))
{
# Single
# Single interface
my $link1_mac = $anvil->data->{variables}{form}{config_step2}{$link1_key}{value};
$anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { link1_mac => $link1_mac }});
}
@ -390,7 +443,12 @@ sub reconfigure_network
}
}
### TODO: This isn't working... The route table won't set the IFN as the default route properly and
### the IFN links seem to drop out and not return when trying to fix it. For now, we'll do a
### closing reboot which seems to always comes up OK.
# Reload the network
#print "reloading nmcli\n";
#$anvil->System->call({shell_call => $anvil->data->{path}{exe}{nmcli}." connection reload"});
return(0);
}
@ -492,11 +550,11 @@ LIMIT 1;";
$anvil->System->pids({ignore_me => 1});
# Is the PID that picked up the job still alive?
if (exists $anvil->{pids}{$job_picked_up_by})
if (exists $anvil->data->{pids}{$job_picked_up_by})
{
print Dumper $anvil->{pids}{$job_picked_up_by};
print Dumper $anvil->data->{pids}{$job_picked_up_by};
$anvil->Log->entry({source => $THIS_FILE, line => __LINE__, level => 1, key => "log_0146", variables => { pid => $job_picked_up_by }});
$anvil->nice_exit({code => 1});
$anvil->nice_exit({code => 3});
}
else
{
@ -541,7 +599,7 @@ AND
{
my $this_variable = $row->[0];
my $this_value = defined $row->[1] ? $row->[1] : "";
$anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 3, list => {
$anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => {
this_variable => $this_variable,
this_value => $this_value,
}});
@ -550,15 +608,15 @@ AND
}
# This will be used when updating the job
$anvil->{job}{uuid} = $job_uuid;
$anvil->{job}{status} = "message_0015\n";
$anvil->data->{job}{uuid} = $job_uuid;
$anvil->data->{job}{status} = "message_0015\n";
# Record that we've picked up this job.
$anvil->Database->insert_or_update_jobs({
job_uuid => $anvil->{job}{uuid},
job_uuid => $anvil->data->{job}{uuid},
update_progress_only => 1,
job_progress => 1,
job_status => $anvil->{job}{status},
job_status => $anvil->data->{job}{status},
});
return(0);

@ -94,7 +94,7 @@ sub keep_running
return(0);
}
# This calls 'scancore-update-states' which will scan the local machine's state (hardware and software) and
# This calls 'anvil-update-states' which will scan the local machine's state (hardware and software) and
# record write it out to an HTML file
sub update_state_file
{

@ -215,9 +215,9 @@ if ($local_id)
# Does the database user exist?
my $create_user = 1;
my $scancore_user = $anvil->data->{database}{$local_id}{user};
$anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 3, list => { scancore_user => $scancore_user }});
if (not $scancore_user)
my $database_user = $anvil->data->{database}{$local_id}{user} ? $anvil->data->{database}{$id}{user} : $anvil->data->{sys}{database}{user};
$anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 3, list => { database_user => $database_user }});
if (not $database_user)
{
# No database user defined
$anvil->Log->entry({source => $THIS_FILE, line => __LINE__, level => 0, priority => "err", key => "log_0099", variables => { id => $local_id }});
@ -227,11 +227,11 @@ if ($local_id)
$anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 3, list => { user_list => $user_list }});
foreach my $line (split/\n/, $user_list)
{
if ($line =~ /^ $scancore_user\s+\|\s+(\d+)/)
if ($line =~ /^ $database_user\s+\|\s+(\d+)/)
{
# User exists already
my $id = $1;
$anvil->Log->entry({source => $THIS_FILE, line => __LINE__, level => 3, key => "log_0060", variables => { user => $scancore_user, id => $id }});
$anvil->Log->entry({source => $THIS_FILE, line => __LINE__, level => 3, key => "log_0060", variables => { user => $database_user, id => $id }});
$create_user = 0;
last;
}
@ -240,31 +240,31 @@ if ($local_id)
if ($create_user)
{
# Create the user
my $create_output = $anvil->System->call({shell_call => $anvil->data->{path}{exe}{su}." - postgres -c \"".$anvil->data->{path}{exe}{createuser}." --no-superuser --createdb --no-createrole $scancore_user\"", source => $THIS_FILE, line => __LINE__});
my $create_output = $anvil->System->call({shell_call => $anvil->data->{path}{exe}{su}." - postgres -c \"".$anvil->data->{path}{exe}{createuser}." --no-superuser --createdb --no-createrole $database_user\"", source => $THIS_FILE, line => __LINE__});
my $user_list = $anvil->System->call({shell_call => $anvil->data->{path}{exe}{su}." - postgres -c \"".$anvil->data->{path}{exe}{psql}." template1 -c 'SELECT usename, usesysid FROM pg_catalog.pg_user;'\"", source => $THIS_FILE, line => __LINE__});
my $user_exists = 0;
$anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 3, list => { create_output => $create_output, user_list => $user_list }});
foreach my $line (split/\n/, $user_list)
{
if ($line =~ /^ $scancore_user\s+\|\s+(\d+)/)
if ($line =~ /^ $database_user\s+\|\s+(\d+)/)
{
# Success!
my $id = $1;
$anvil->Log->entry({source => $THIS_FILE, line => __LINE__, level => 3, key => "log_0095", variables => { user => $scancore_user, id => $id }});
$anvil->Log->entry({source => $THIS_FILE, line => __LINE__, level => 3, key => "log_0095", variables => { user => $database_user, id => $id }});
$user_exists = 1;
last;
}
}
if (not $user_exists)
{
$anvil->Log->entry({source => $THIS_FILE, line => __LINE__, level => 0, priority => "err", key => "log_0096", variables => { user => $scancore_user }});
$anvil->Log->entry({source => $THIS_FILE, line => __LINE__, level => 0, priority => "err", key => "log_0096", variables => { user => $database_user }});
exit(4);
}
# Update/set the passwords.
if ($anvil->data->{database}{$local_id}{password})
{
foreach my $user ("postgres", $scancore_user)
foreach my $user ("postgres", $database_user)
{
my $update_output = $anvil->System->call({secure => 1, shell_call => $anvil->data->{path}{exe}{su}." - postgres -c \"".$anvil->data->{path}{exe}{psql}." template1 -c \\\"ALTER ROLE $user WITH PASSWORD '".$anvil->data->{database}{$local_id}{password}."';\\\"\"", source => $THIS_FILE, line => __LINE__});
$anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 3, secure => 1, list => { update_output => $update_output }});
@ -281,18 +281,18 @@ if ($local_id)
}
# Create the database, if needed.
my $create_database = 1;
my $scancore_database = $anvil->data->{database}{$local_id}{name};
$anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 3, list => { "database::${local_id}::name" => $anvil->data->{database}{$local_id}{name} }});
my $create_database = 1;
my $database_name = $anvil->data->{database}{$local_id}{name} ? $anvil->data->{database}{$local_id}{name} : $anvil->data->{sys}{database}{name};
$anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 3, list => { database_name => $database_name }});
my $database_list = $anvil->System->call({shell_call => $anvil->data->{path}{exe}{su}." - postgres -c \"".$anvil->data->{path}{exe}{psql}." template1 -c 'SELECT datname FROM pg_catalog.pg_database;'\"", source => $THIS_FILE, line => __LINE__});
$anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 3, list => { database_list => $database_list }});
foreach my $line (split/\n/, $database_list)
{
if ($line =~ /^ $scancore_database$/)
if ($line =~ /^ $database_name$/)
{
# Database already exists.
$anvil->Log->entry({source => $THIS_FILE, line => __LINE__, level => 3, key => "log_0105", variables => { database => $scancore_database }});
$anvil->Log->entry({source => $THIS_FILE, line => __LINE__, level => 3, key => "log_0105", variables => { database => $database_name }});
$create_database = 0;
last;
}
@ -300,7 +300,7 @@ if ($local_id)
$anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 3, list => { create_database => $create_database }});
if ($create_database)
{
my $create_output = $anvil->System->call({shell_call => $anvil->data->{path}{exe}{su}." - postgres -c \"".$anvil->data->{path}{exe}{createdb}." --owner $scancore_user $scancore_database\"", source => $THIS_FILE, line => __LINE__});
my $create_output = $anvil->System->call({shell_call => $anvil->data->{path}{exe}{su}." - postgres -c \"".$anvil->data->{path}{exe}{createdb}." --owner ".$database_user." ".$database_name."\"", source => $THIS_FILE, line => __LINE__});
$anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 3, list => { create_output => $create_output }});
my $database_exists = 0;
@ -308,17 +308,17 @@ if ($local_id)
$anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 3, list => { database_list => $database_list }});
foreach my $line (split/\n/, $database_list)
{
if ($line =~ /^ $scancore_database$/)
if ($line =~ /^ $database_name$/)
{
# Database created
$anvil->Log->entry({source => $THIS_FILE, line => __LINE__, level => 3, key => "log_0110", variables => { database => $scancore_database }});
$anvil->Log->entry({source => $THIS_FILE, line => __LINE__, level => 3, key => "log_0110", variables => { database => $database_name }});
$database_exists = 1;
last;
}
}
if (not $database_exists)
{
$anvil->Log->entry({source => $THIS_FILE, line => __LINE__, level => 0, priority => "err", key => "log_0109", variables => { database => $scancore_database }});
$anvil->Log->entry({source => $THIS_FILE, line => __LINE__, level => 0, priority => "err", key => "log_0109", variables => { database => $database_name }});
exit(5);
}
}

@ -31,7 +31,7 @@ $anvil->Log->entry({source => $THIS_FILE, line => __LINE__, level => 3, key => "
if (not $connections)
{
# No databases, exit.
print $anvil->Words->string({key => "striker_error_0003"});
print $anvil->Words->string({key => "error_0003"});
$anvil->nice_exit({exit_code => 2});
}

@ -41,7 +41,7 @@ $$;
-- This stores information about the host machine. This is the master table that everything will be linked
-- to.
CREATE TABLE hosts (
host_uuid uuid not null primary key, -- This is the single most important record in ScanCore. Everything links back to here.
host_uuid uuid not null primary key, -- This is the single most important record in Anvil!. Everything links back to here.
host_name text not null,
host_type text not null, -- Either 'node' or 'dashboard'.
modified_date timestamp with time zone not null
@ -445,7 +445,7 @@ CREATE TABLE bonds (
bond_uuid uuid not null primary key,
bond_host_uuid uuid not null,
bond_name text not null,
bond_mode integer not null, -- This is the numerical bond type (will translate to the user's language in ScanCore)
bond_mode integer not null, -- This is the numerical bond type (will translate to the user's language in the Anvil!)
bond_mtu bigint,
bond_primary_slave text,
bond_primary_reselect text,

Loading…
Cancel
Save