From a89fb24adf494c2c0c98ebb8aef2ffb5e0b49c00 Mon Sep 17 00:00:00 2001 From: Digimer Date: Mon, 30 Apr 2018 11:43:30 -0400 Subject: [PATCH] * Changed the Storage->copy() 'target' parameter to 'target_file' to avoid confusion with the often-used 'target' parameter for connecting to remote machines. * Changed 'database::x::...' so that 'x' is now the database host's UUID instead of a simple integer. This will simplify sync'ing configs. Also removed default entries, and made it so that anvil-prep-database injects the local config during first setup. Renamed Database->get_local_id to get_local_uuid and changed the 'id' parameter to 'uuid'. Changed Database->initialize's 'id' parameter to 'host_uuid'. The Database->query, Database->write, Database->_mark_database_as_behind and Database->_find_behind_databases methods had their 'id' parameter changed to 'uuid'. * Added the 'remote_user' parameter to Get->anvil_version, System->ping and System->change_shell_user_password for conencting to remote targets. * Added the 'remote_user' parameter to all internal Remote->call uses. * Updated Storage->backup, Storage->copy_file, Storage->make_directory, Signed-off-by: Digimer --- Anvil/Tools.t | 12 +- Anvil/Tools/Database.pm | 572 ++++++++++++++++++------------------ Anvil/Tools/Get.pm | 32 +- Anvil/Tools/Remote.pm | 84 +++--- Anvil/Tools/Storage.pm | 594 ++++++++++++++++++++++++++++++-------- Anvil/Tools/System.pm | 75 +++-- anvil.conf | 101 +++---- rpm/SPECS/anvil.spec | 3 + share/words.xml | 56 ++-- tools/anvil-prep-database | 113 +++++++- 10 files changed, 1055 insertions(+), 587 deletions(-) diff --git a/Anvil/Tools.t b/Anvil/Tools.t index 44bd4a7d..6222c3ab 100755 --- a/Anvil/Tools.t +++ b/Anvil/Tools.t @@ -346,25 +346,25 @@ if (-e $copy_file) { unlink $copy_file or die "The test copy file: [$copy_file] exists (from a previous run?) and can't be removed. The error was: $!\n"; } -$anvil->Storage->copy_file({source => $test_file, target => $copy_file}); +$anvil->Storage->copy_file({source_file => $test_file, target_file => $copy_file}); if (-e $copy_file) { $copied_ok = 1; } is($copied_ok, "1", "Verifying that 'Storage->copy_file' was able to copy the test file."); -my $copy_rc = $anvil->Storage->copy_file({target => $copy_file}); +my $copy_rc = $anvil->Storage->copy_file({target_file => $copy_file}); is($copy_rc, "1", "Verifying that 'Storage->copy_file' returned '1' when no source file was passed."); $copy_rc = ""; -$copy_rc = $anvil->Storage->copy_file({source => $test_file}); +$copy_rc = $anvil->Storage->copy_file({source_file => $test_file}); is($copy_rc, "2", "Verifying that 'Storage->copy_file' returned '2' when no target file was passed."); $copy_rc = ""; -$copy_rc = $anvil->Storage->copy_file({source => $test_file, target => $copy_file}); +$copy_rc = $anvil->Storage->copy_file({source_file => $test_file, target_file => $copy_file}); is($copy_rc, "3", "Verifying that 'Storage->copy_file' returned '3' when the target file already exists."); $copy_rc = ""; -$copy_rc = $anvil->Storage->copy_file({source => $test_file, target => $copy_file, overwrite => 1}); +$copy_rc = $anvil->Storage->copy_file({source_file => $test_file, target_file => $copy_file, overwrite => 1}); is($copy_rc, "0", "Verifying that 'Storage->copy_file' returned '0' when the target file already exists and overwrite was set."); $copy_rc = ""; -$copy_rc = $anvil->Storage->copy_file({source => "/fake/file", target => $copy_file}); +$copy_rc = $anvil->Storage->copy_file({source_file => "/fake/file", target_file => $copy_file}); is($copy_rc, "4", "Verifying that 'Storage->copy_file' returned '4' when the target file is passed but doesn't exist."); # find my $test_path = $anvil->Storage->find({ file => "Anvil/Tools.t" }); diff --git a/Anvil/Tools/Database.pm b/Anvil/Tools/Database.pm index c41be015..59a209f8 100755 --- a/Anvil/Tools/Database.pm +++ b/Anvil/Tools/Database.pm @@ -20,7 +20,7 @@ my $THIS_FILE = "Database.pm"; # connect # disconnect # get_hosts -# get_local_id +# get_local_uuid # initialize # insert_or_update_hosts # insert_or_update_jobs @@ -58,8 +58,8 @@ Provides all methods related to managing and accessing databases. # Access to methods using '$anvil->Database->X'. # - # Example using 'get_local_id()'; - my $local_id = $anvil->Database->get_local_id; + # Example using 'get_local_uuid()'; + my $local_id = $anvil->Database->get_local_uuid; =head1 METHODS @@ -198,12 +198,6 @@ If the system is already configured, this method will do nothing, so it is safe If there is a problem, C<< !!error!! >> is returned. -Parameters; - -=head3 id (required) - -This is the ID of the local database in the local configuration file that will be used to configure the local system. - =cut sub configure_pgsql { @@ -213,14 +207,9 @@ sub configure_pgsql my $debug = defined $parameter->{debug} ? $parameter->{debug} : 3; $anvil->Log->entry({source => $THIS_FILE, line => __LINE__, level => $debug, key => "log_0125", variables => { method => "Database->configure_pgsql()" }}); - my $id = defined $parameter->{id} ? $parameter->{id} : ""; - $anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => $debug, list => { id => $id }}); - - if (not $id) - { - $anvil->Log->entry({source => $THIS_FILE, line => __LINE__, level => 0, priority => "err", key => "log_0020", variables => { method => "Database->configure_pgsql()", parameter => "id" }}); - return("!!error!!"); - } + # The local host_uuid is the ID of the local database, so get that. + my $uuid = $anvil->Get->host_uuid(); + $anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => $debug, list => { uuid => $uuid }}); # If we're not running with root access, return. if (($< != 0) && ($> != 0)) @@ -294,7 +283,10 @@ sub configure_pgsql $anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => $debug, list => { postgresql_backup => $postgresql_backup }}); if (not -e $postgresql_backup) { - $anvil->Storage->copy_file({source => $anvil->data->{path}{configs}{'postgresql.conf'}, target => $postgresql_backup}); + $anvil->Storage->copy_file({ + source_file => $anvil->data->{path}{configs}{'postgresql.conf'}, + target_file => $postgresql_backup, + }); } # Write the updated one. @@ -342,7 +334,10 @@ sub configure_pgsql $anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => $debug, list => { pg_hba_backup => $pg_hba_backup }}); if (not -e $pg_hba_backup) { - $anvil->Storage->copy_file({source => $anvil->data->{path}{configs}{'pg_hba.conf'}, target => $pg_hba_backup}); + $anvil->Storage->copy_file({ + source_file => $anvil->data->{path}{configs}{'pg_hba.conf'}, + target_file => $pg_hba_backup, + }); } # Write the new one. @@ -396,11 +391,11 @@ sub configure_pgsql my $created_pgpass = 0; $anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => $debug, secure => 1, list => { 'path::secure::postgres_pgpass' => $anvil->data->{path}{secure}{postgres_pgpass}, - "database::${id}::password" => $anvil->data->{database}{$id}{password}, + "database::${uuid}::password" => $anvil->data->{database}{$uuid}{password}, }}); - if ((not -e $anvil->data->{path}{secure}{postgres_pgpass}) && ($anvil->data->{database}{$id}{password})) + if ((not -e $anvil->data->{path}{secure}{postgres_pgpass}) && ($anvil->data->{database}{$uuid}{password})) { - my $body = "*:*:*:postgres:".$anvil->data->{database}{$id}{password}; + my $body = "*:*:*:postgres:".$anvil->data->{database}{$uuid}{password}; $anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => $debug, secure => 1, list => { body => $body }}); $anvil->Storage->write_file({ file => $anvil->data->{path}{secure}{postgres_pgpass}, @@ -420,12 +415,12 @@ sub configure_pgsql # Does the database user exist? my $create_user = 1; - my $database_user = $anvil->data->{database}{$id}{user} ? $anvil->data->{database}{$id}{user} : $anvil->data->{sys}{database}{user}; + my $database_user = $anvil->data->{database}{$uuid}{user} ? $anvil->data->{database}{$uuid}{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) { # No database user defined - $anvil->Log->entry({source => $THIS_FILE, line => __LINE__, level => 0, priority => "err", key => "log_0099", variables => { id => $id }}); + $anvil->Log->entry({source => $THIS_FILE, line => __LINE__, level => 0, priority => "err", key => "log_0099", variables => { uuid => $uuid }}); return("!!error!!"); } 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__}); @@ -435,8 +430,8 @@ sub configure_pgsql if ($line =~ /^ $database_user\s+\|\s+(\d+)/) { # User exists already - my $id = $1; - $anvil->Log->entry({source => $THIS_FILE, line => __LINE__, level => $debug, key => "log_0060", variables => { user => $database_user, id => $id }}); + my $uuid = $1; + $anvil->Log->entry({source => $THIS_FILE, line => __LINE__, level => $debug, key => "log_0060", variables => { user => $database_user, uuid => $uuid }}); $create_user = 0; last; } @@ -454,8 +449,8 @@ sub configure_pgsql if ($line =~ /^ $database_user\s+\|\s+(\d+)/) { # Success! - my $id = $1; - $anvil->Log->entry({source => $THIS_FILE, line => __LINE__, level => $debug, key => "log_0095", variables => { user => $database_user, id => $id }}); + my $uuid = $1; + $anvil->Log->entry({source => $THIS_FILE, line => __LINE__, level => $debug, key => "log_0095", variables => { user => $database_user, uuid => $uuid }}); $user_exists = 1; last; } @@ -467,11 +462,11 @@ sub configure_pgsql } # Update/set the passwords. - if ($anvil->data->{database}{$id}{password}) + if ($anvil->data->{database}{$uuid}{password}) { 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}{$id}{password}."';\\\"\"", source => $THIS_FILE, line => __LINE__}); + 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}{$uuid}{password}."';\\\"\"", source => $THIS_FILE, line => __LINE__}); $anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => $debug, secure => 1, list => { update_output => $update_output }}); foreach my $line (split/\n/, $user_list) { @@ -487,7 +482,7 @@ sub configure_pgsql # Create the database, if needed. my $create_database = 1; - my $database_name = defined $anvil->data->{database}{$id}{name} ? $anvil->data->{database}{$id}{name} : $anvil->data->{sys}{database}{name}; + my $database_name = defined $anvil->data->{database}{$uuid}{name} ? $anvil->data->{database}{$uuid}{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__}); @@ -540,10 +535,10 @@ sub configure_pgsql } # Make sure the psql TCP port is open. - $anvil->data->{database}{$id}{port} = 5432 if not $anvil->data->{database}{$id}{port}; + $anvil->data->{database}{$uuid}{port} = 5432 if not $anvil->data->{database}{$uuid}{port}; my $port_status = $anvil->System->manage_firewall({ task => "open", - port_number => $anvil->data->{database}{$id}{port}, + port_number => $anvil->data->{database}{$uuid}{port}, }); $anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => $debug, list => { port_status => $port_status }}); @@ -654,7 +649,7 @@ sub connect # This will be used in a few cases where the local DB ID is needed (or the lack of it being set # showing we failed to connect to the local DB). - $anvil->data->{sys}{local_db_id} = ""; + $anvil->data->{sys}{local_db_uuid} = ""; # This will be set to '1' if either DB needs to be initialized or if the last_updated differs on any node. $anvil->data->{sys}{database}{resync_needed} = 0; @@ -664,14 +659,14 @@ sub connect my $connections = 0; my $failed_connections = []; my $successful_connections = []; - foreach my $id (sort {$a cmp $b} keys %{$anvil->data->{database}}) + foreach my $uuid (sort {$a cmp $b} keys %{$anvil->data->{database}}) { 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} : $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} : ""; + my $host = $anvil->data->{database}{$uuid}{host} ? $anvil->data->{database}{$uuid}{host} : ""; # This should fail + my $port = $anvil->data->{database}{$uuid}{port} ? $anvil->data->{database}{$uuid}{port} : 5432; + my $name = $anvil->data->{database}{$uuid}{name} ? $anvil->data->{database}{$uuid}{name} : $anvil->data->{sys}{database}{name}; + my $user = $anvil->data->{database}{$uuid}{user} ? $anvil->data->{database}{$uuid}{user} : $anvil->data->{sys}{database}{user}; + my $password = $anvil->data->{database}{$uuid}{password} ? $anvil->data->{database}{$uuid}{password} : ""; $anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => $debug, list => { host => $host, port => $port, @@ -681,9 +676,9 @@ sub connect }}); # If not set, we will always ping before connecting. - if ((not exists $anvil->data->{database}{$id}{ping}) or (not defined $anvil->data->{database}{$id}{ping})) + if ((not exists $anvil->data->{database}{$uuid}{ping}) or (not defined $anvil->data->{database}{$uuid}{ping})) { - $anvil->data->{database}{$id}{ping} = 1; + $anvil->data->{database}{$uuid}{ping} = 1; } # Make sure the user didn't specify the same target twice. @@ -706,7 +701,7 @@ sub connect # Log what we're doing. $anvil->Log->entry({source => $THIS_FILE, line => __LINE__, level => $debug, key => "log_0054", variables => { - id => $id, + uuid => $uuid, driver => $driver, host => $host, port => $port, @@ -720,16 +715,16 @@ sub connect # Assemble my connection string my $db_connect_string = "$driver:dbname=$name;host=$host;port=$port"; $anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => $debug, list => { - db_connect_string => $db_connect_string, - "database::${id}::ping" => $anvil->data->{database}{$id}{ping}, + db_connect_string => $db_connect_string, + "database::${uuid}::ping" => $anvil->data->{database}{$uuid}{ping}, }}); - if ($anvil->data->{database}{$id}{ping}) + if ($anvil->data->{database}{$uuid}{ping}) { # Can I ping? my ($pinged) = $anvil->System->ping({ ping => $host, count => 1, - timeout => $anvil->data->{database}{$id}{ping}, + timeout => $anvil->data->{database}{$uuid}{ping}, }); my $ping_time = tv_interval ($start_time, [gettimeofday]); @@ -738,14 +733,14 @@ sub connect $anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => $debug, list => { pinged => $pinged }}); if (not $pinged) { - # Didn't ping and 'database::::ping' not set. Record this + # Didn't ping and 'database::::ping' not set. Record this # in the failed connections array. $anvil->Log->entry({source => $THIS_FILE, line => __LINE__, level => 1, priority => "alert", key => "log_0063", variables => { host => $port ? $host.":".$port : $host, name => $name, - id => $id, + uuid => $uuid, }}); - push @{$failed_connections}, $id; + push @{$failed_connections}, $uuid; next; } } @@ -755,16 +750,16 @@ sub connect $anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => $debug, list => { is_local => $is_local }}); if ($is_local) { - $anvil->data->{sys}{read_db_id} = $id; - $anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => $debug, list => { "sys::read_db_id" => $anvil->data->{sys}{read_db_id} }}); + $anvil->data->{sys}{read_db_uuid} = $uuid; + $anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => $debug, list => { "sys::read_db_uuid" => $anvil->data->{sys}{read_db_uuid} }}); # Set it up (or update it) if needed. This method just returns if nothing is needed. - $anvil->Database->configure_pgsql({id => $id}); + $anvil->Database->configure_pgsql({uuid => $uuid}); } - elsif (not $anvil->data->{sys}{read_db_id}) + elsif (not $anvil->data->{sys}{read_db_uuid}) { - $anvil->data->{sys}{read_db_id} = $id; - $anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => $debug, list => { "sys::read_db_id" => $anvil->data->{sys}{read_db_id} }}); + $anvil->data->{sys}{read_db_uuid} = $uuid; + $anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => $debug, list => { "sys::read_db_uuid" => $anvil->data->{sys}{read_db_uuid} }}); } # If this isn't a local database, read the target's Anvil! version (if available) and make @@ -810,12 +805,12 @@ sub connect { # Something went wrong... $anvil->Log->entry({source => $THIS_FILE, line => __LINE__, level => 1, priority => "alert", key => "log_0064", variables => { - id => $id, + uuid => $uuid, host => $host, name => $name, }}); - push @{$failed_connections}, $id; + push @{$failed_connections}, $uuid; my $message_key = "log_0065"; my $variables = { dbi_error => $DBI::errstr }; if (not defined $DBI::errstr) @@ -831,13 +826,13 @@ sub connect elsif ($DBI::errstr =~ /no password supplied/) { $message_key = "log_0067"; - $variables = { id => $id }; + $variables = { uuid => $uuid }; } elsif ($DBI::errstr =~ /password authentication failed for user/) { $message_key = "log_0068"; $variables = { - id => $id, + uuid => $uuid, name => $name, host => $host, user => $user, @@ -867,14 +862,14 @@ sub connect { # Woot! $connections++; - push @{$successful_connections}, $id; - $anvil->data->{cache}{db_fh}{$id} = $dbh; + push @{$successful_connections}, $uuid; + $anvil->data->{cache}{db_fh}{$uuid} = $dbh; $anvil->Log->entry({source => $THIS_FILE, line => __LINE__, level => $debug, key => "log_0071", variables => { host => $host, port => $port, name => $name, - id => $id, + uuid => $uuid, }}); if (not $anvil->data->{sys}{use_db_fh}) @@ -889,7 +884,7 @@ sub connect my $query = "SELECT COUNT(*) FROM pg_catalog.pg_tables WHERE tablename=".$anvil->data->{sys}{use_db_fh}->quote($anvil->data->{defaults}{sql}{test_table})." AND schemaname='public';"; $anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => $debug, list => { query => $query }}); - my $count = $anvil->Database->query({id => $id, query => $query, source => $THIS_FILE, line => __LINE__})->[0]->[0]; + my $count = $anvil->Database->query({uuid => $uuid, query => $query, source => $THIS_FILE, line => __LINE__})->[0]->[0]; $anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => $debug, list => { count => $count }}); if ($count < 1) @@ -897,7 +892,7 @@ sub connect ### TODO: Create a version file/flag and don't sync with peers unless ### they are the same version. Back-port this to v2. # Need to load the database. - $anvil->Database->initialize({id => $id, sql_file => $anvil->data->{path}{sql}{'anvil.sql'}}); + $anvil->Database->initialize({uuid => $uuid, sql_file => $anvil->data->{path}{sql}{'anvil.sql'}}); } } @@ -905,42 +900,42 @@ sub connect my $query = "SELECT COUNT(*) FROM pg_catalog.pg_tables WHERE tablename=".$anvil->data->{sys}{use_db_fh}->quote($test_table)." AND schemaname='public';"; $anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => $debug, list => { query => $query }}); - my $count = $anvil->Database->query({id => $id, query => $query, source => $THIS_FILE, line => __LINE__})->[0]->[0]; + my $count = $anvil->Database->query({uuid => $uuid, query => $query, source => $THIS_FILE, line => __LINE__})->[0]->[0]; $anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => $debug, list => { count => $count }}); if ($count < 1) { # Need to load the database. - $anvil->Database->initialize({id => $id, sql_file => $sql_file}); + $anvil->Database->initialize({uuid => $uuid, sql_file => $sql_file}); } $anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => $debug, list => { - "sys::read_db_id" => $anvil->data->{sys}{read_db_id}, - "cache::db_fh::$id" => $anvil->data->{cache}{db_fh}{$id}, + "sys::read_db_uuid" => $anvil->data->{sys}{read_db_uuid}, + "cache::db_fh::$uuid" => $anvil->data->{cache}{db_fh}{$uuid}, }}); # Set the first ID to be the one I read from later. Alternatively, if this host is # local, use it. if (($host eq $anvil->_hostname) or ($host eq $anvil->_short_hostname) or - ($host eq "localhost") or - ($host eq "127.0.0.1") or - (not $anvil->data->{sys}{read_db_id})) + ($host eq "localhost") or + ($host eq "127.0.0.1") or + (not $anvil->data->{sys}{read_db_uuid})) { - $anvil->data->{sys}{read_db_id} = $id; - $anvil->data->{sys}{local_db_id} = $id; - $anvil->data->{sys}{use_db_fh} = $anvil->data->{cache}{db_fh}{$id}; + $anvil->data->{sys}{read_db_uuid} = $uuid; + $anvil->data->{sys}{local_db_uuid} = $uuid; + $anvil->data->{sys}{use_db_fh} = $anvil->data->{cache}{db_fh}{$uuid}; $anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => $debug, list => { - "sys::read_db_id" => $anvil->data->{sys}{read_db_id}, - "sys::use_db_fh" => $anvil->data->{sys}{use_db_fh} + "sys::read_db_uuid" => $anvil->data->{sys}{read_db_uuid}, + "sys::use_db_fh" => $anvil->data->{sys}{use_db_fh} }}); } # Get a time stamp for this run, if not yet gotten. $anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => $debug, list => { - "cache::db_fh::$id" => $anvil->data->{cache}{db_fh}{$id}, - "sys::db_timestamp" => $anvil->data->{sys}{db_timestamp}, + "cache::db_fh::$uuid" => $anvil->data->{cache}{db_fh}{$uuid}, + "sys::db_timestamp" => $anvil->data->{sys}{db_timestamp}, }}); # Pick a timestamp for this run, if we haven't yet. @@ -949,12 +944,12 @@ sub connect my $query = "SELECT cast(now() AS timestamp with time zone)::timestamptz(0);"; $anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => $debug, list => { query => $query }}); - $anvil->data->{sys}{db_timestamp} = $anvil->Database->query({id => $id, query => $query, source => $THIS_FILE, line => __LINE__})->[0]->[0]; + $anvil->data->{sys}{db_timestamp} = $anvil->Database->query({uuid => $uuid, query => $query, source => $THIS_FILE, line => __LINE__})->[0]->[0]; $anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => $debug, list => { "sys::db_timestamp" => $anvil->data->{sys}{db_timestamp} }}); } $anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => $debug, list => { - "sys::read_db_id" => $anvil->data->{sys}{read_db_id}, + "sys::read_db_uuid" => $anvil->data->{sys}{read_db_uuid}, "sys::use_db_fh" => $anvil->data->{sys}{use_db_fh}, "sys::db_timestamp" => $anvil->data->{sys}{db_timestamp}, }}); @@ -974,34 +969,34 @@ sub connect } # Report any failed DB connections - foreach my $id (@{$failed_connections}) + foreach my $uuid (@{$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} : "--"; + my $database_name = defined $anvil->data->{database}{$uuid}{name} ? $anvil->data->{database}{$uuid}{name} : "--"; + my $database_user = defined $anvil->data->{database}{$uuid}{user} ? $anvil->data->{database}{$uuid}{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" => $database_name, - "database::${id}::user" => $database_user, - "database::${id}::password" => $anvil->Log->secure ? $anvil->data->{database}{$id}{password} : "--", + "database::${uuid}::host" => $anvil->data->{database}{$uuid}{host}, + "database::${uuid}::port" => $anvil->data->{database}{$uuid}{port}, + "database::${uuid}::name" => $database_name, + "database::${uuid}::user" => $database_user, + "database::${uuid}::password" => $anvil->Log->secure ? $anvil->data->{database}{$uuid}{password} : "--", }}); - # Copy my alert hash before I delete the id. + # Copy my alert hash before I delete the uuid. my $error_array = []; # 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}." -> ".$database_name; - $anvil->Log->entry({source => $THIS_FILE, line => __LINE__, level => $debug, priority => "alert", key => "log_0092", variables => { server => $say_server, id => $id }}); + my $say_server = $anvil->data->{database}{$uuid}{host}.":".$anvil->data->{database}{$uuid}{port}." -> ".$database_name; + $anvil->Log->entry({source => $THIS_FILE, line => __LINE__, level => $debug, priority => "alert", key => "log_0092", variables => { server => $say_server, uuid => $uuid }}); # Delete it from the list of known databases for this run. - delete $anvil->data->{database}{$id}; + delete $anvil->data->{database}{$uuid}; # If I've not sent an alert about this DB loss before, send one now. my $set = $anvil->Alert->check_alert_sent({ type => "set", set_by => $THIS_FILE, - record_locator => $id, + record_locator => $uuid, name => "connect_to_db", modified_date => $anvil->data->{sys}{db_timestamp}, }); @@ -1033,26 +1028,26 @@ sub connect } # Send an 'all clear' message if a now-connected DB previously wasn't. - foreach my $id (@{$successful_connections}) + foreach my $uuid (@{$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} : "--"; + my $database_name = defined $anvil->data->{database}{$uuid}{name} ? $anvil->data->{database}{$uuid}{name} : "--"; + my $database_user = defined $anvil->data->{database}{$uuid}{user} ? $anvil->data->{database}{$uuid}{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" => $database_name, - "database::${id}::user" => $database_user, - "database::${id}::password" => $anvil->Log->secure ? $anvil->data->{database}{$id}{password} : "--", + "database::${uuid}::host" => $anvil->data->{database}{$uuid}{host}, + "database::${uuid}::port" => $anvil->data->{database}{$uuid}{port}, + "database::${uuid}::name" => $database_name, + "database::${uuid}::user" => $database_user, + "database::${uuid}::password" => $anvil->Log->secure ? $anvil->data->{database}{$uuid}{password} : "--", }}); ### TODO: Is this still an issue? If so, then we either need to require that the DB host ### matches the actual hostname (dumb) or find another way of mapping the host name. # Query to see if the newly connected host is in the DB yet. If it isn't, don't send an # alert as it'd cause a duplicate UUID error. -# my $query = "SELECT COUNT(*) FROM hosts WHERE host_name = ".$anvil->data->{sys}{use_db_fh}->quote($anvil->data->{database}{$id}{host}).";"; +# my $query = "SELECT COUNT(*) FROM hosts WHERE host_name = ".$anvil->data->{sys}{use_db_fh}->quote($anvil->data->{database}{$uuid}{host}).";"; # $anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => $debug, list => { query => $query }}); # -# my $count = $anvil->Database->query({id => $id, query => $query, source => $THIS_FILE, line => __LINE__})->[0]->[0]; +# my $count = $anvil->Database->query({uuid => $uuid, query => $query, source => $THIS_FILE, line => __LINE__})->[0]->[0]; # $anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => $debug, list => { count => $count }}); # # if ($count > 0) @@ -1060,7 +1055,7 @@ sub connect my $cleared = $anvil->Alert->check_alert_sent({ type => "clear", set_by => $THIS_FILE, - record_locator => $id, + record_locator => $uuid, name => "connect_to_db", modified_date => $anvil->data->{sys}{db_timestamp}, }); @@ -1073,8 +1068,8 @@ sub connect message_key => "cleared_log_0055", message_variables => { name => $database_name, - host => $anvil->data->{database}{$id}{host}, - port => defined $anvil->data->{database}{$id}{port} ? $anvil->data->{database}{$id}{port} : 5432, + host => $anvil->data->{database}{$uuid}{host}, + port => defined $anvil->data->{database}{$uuid}{port} ? $anvil->data->{database}{$uuid}{port} : 5432, }, }); } @@ -1134,10 +1129,10 @@ sub disconnect $anvil->Log->entry({source => $THIS_FILE, line => __LINE__, level => $debug, key => "log_0125", variables => { method => "Database->disconnect()" }}); my $marked_inactive = 0; - foreach my $id (sort {$a cmp $b} keys %{$anvil->data->{database}}) + foreach my $uuid (sort {$a cmp $b} keys %{$anvil->data->{database}}) { # Don't do anything if there isn't an active file handle for this DB. - next if ((not $anvil->data->{cache}{db_fh}{$id}) or ($anvil->data->{cache}{db_fh}{$id} !~ /^DBI::db=HASH/)); + next if ((not $anvil->data->{cache}{db_fh}{$uuid}) or ($anvil->data->{cache}{db_fh}{$uuid} !~ /^DBI::db=HASH/)); # Clear locks and mark that we're done running. if (not $marked_inactive) @@ -1147,14 +1142,14 @@ sub disconnect $marked_inactive = 1; } - $anvil->data->{cache}{db_fh}{$id}->disconnect; - delete $anvil->data->{cache}{db_fh}{$id}; + $anvil->data->{cache}{db_fh}{$uuid}->disconnect; + delete $anvil->data->{cache}{db_fh}{$uuid}; } # Delete the stored DB-related values. delete $anvil->data->{sys}{db_timestamp}; delete $anvil->data->{sys}{use_db_fh}; - delete $anvil->data->{sys}{read_db_id}; + delete $anvil->data->{sys}{read_db_uuid}; return(0); } @@ -1227,42 +1222,42 @@ FROM return($return); } -=head2 get_local_id +=head2 get_local_uuid -This returns the database ID from 'C<< anvil.conf >>' based on matching the 'C<< database::::host >>' to the local machine's host name or one of the active IP addresses on the host. +This returns the database UUID (usually the host's UUID) from C<< anvil.conf >> based on matching the C<< database::::host >> to the local machine's host name or one of the active IP addresses on the host. - # Get the local ID - my $local_id = $anvil->Database->get_local_id; +NOTE: This returns nothing if the local machine is not found as a configured database in C<< anvil.conf >>. This is a good way to check if the system has been setup yet. -This will return a blank string if no match is found. + # Get the local UUID + my $local_uuid = $anvil->Database->get_local_uuid; =cut -sub get_local_id +sub get_local_uuid { my $self = shift; my $parameter = shift; my $anvil = $self->parent; my $debug = defined $parameter->{debug} ? $parameter->{debug} : 3; - $anvil->Log->entry({source => $THIS_FILE, line => __LINE__, level => $debug, key => "log_0125", variables => { method => "Database->get_local_id()" }}); + $anvil->Log->entry({source => $THIS_FILE, line => __LINE__, level => $debug, key => "log_0125", variables => { method => "Database->get_local_uuid()" }}); - my $local_id = ""; + my $local_uuid = ""; my $network_details = $anvil->Get->network_details; - foreach my $id (sort {$a cmp $b} keys %{$anvil->data->{database}}) + foreach my $uuid (sort {$a cmp $b} keys %{$anvil->data->{database}}) { $anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => $debug, list => { "network_details->hostname" => $network_details->{hostname}, - "database::${id}::host" => $anvil->data->{database}{$id}{host}, + "database::${uuid}::host" => $anvil->data->{database}{$uuid}{host}, }}); - if ($network_details->{hostname} eq $anvil->data->{database}{$id}{host}) + if ($network_details->{hostname} eq $anvil->data->{database}{$uuid}{host}) { - $local_id = $id; - $anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => $debug, list => { local_id => $local_id }}); + $local_uuid = $uuid; + $anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => $debug, list => { local_uuid => $local_uuid }}); last; } } - $anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => $debug, list => { local_id => $local_id }}); - if (not $local_id) + $anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => $debug, list => { local_uuid => $local_uuid }}); + if (not $local_uuid) { foreach my $interface (sort {$a cmp $b} keys %{$network_details->{interface}}) { @@ -1272,24 +1267,24 @@ sub get_local_id ip_address => $ip_address, subnet_mask => $subnet_mask, }}); - foreach my $id (sort {$a cmp $b} keys %{$anvil->data->{database}}) + foreach my $uuid (sort {$a cmp $b} keys %{$anvil->data->{database}}) { $anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => $debug, list => { - ip_address => $ip_address, - "database::${id}::host" => $anvil->data->{database}{$id}{host}, + ip_address => $ip_address, + "database::${uuid}::host" => $anvil->data->{database}{$uuid}{host}, }}); - if ($ip_address eq $anvil->data->{database}{$id}{host}) + if ($ip_address eq $anvil->data->{database}{$uuid}{host}) { - $local_id = $id; - $anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => $debug, list => { local_id => $local_id }}); + $local_uuid = $uuid; + $anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => $debug, list => { local_uuid => $local_uuid }}); last; } } } } - $anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => $debug, list => { local_id => $local_id }}); - return($local_id); + $anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => $debug, list => { local_uuid => $local_uuid }}); + return($local_uuid); } =head2 initialize @@ -1305,36 +1300,30 @@ sub initialize my $debug = defined $parameter->{debug} ? $parameter->{debug} : 3; $anvil->Log->entry({source => $THIS_FILE, line => __LINE__, level => $debug, key => "log_0125", variables => { method => "Database->initialize()" }}); - my $id = $parameter->{id} ? $parameter->{id} : $anvil->data->{sys}{read_db_id}; + my $uuid = $anvil->Get->host_uuid; my $sql_file = $parameter->{sql_file} ? $parameter->{sql_file} : $anvil->data->{path}{sql}{'anvil.sql'}; my $success = 1; $anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => $debug, list => { - id => $id, + uuid => $uuid, sql_file => $sql_file, }}); # This just makes some logging cleaner below. - 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; + my $database_name = defined $anvil->data->{database}{$uuid}{name} ? $anvil->data->{database}{$uuid}{name} : $anvil->data->{sys}{database}{name}; + my $say_server = $anvil->data->{database}{$uuid}{host}.":".$anvil->data->{database}{$uuid}{port}." -> ".$database_name; $anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => $debug, list => { say_server => $say_server }}); - if (not $id) - { - # No database to talk to... - $anvil->Log->entry({source => $THIS_FILE, line => __LINE__, level => 0, priority => "err", key => "log_0077"}); - return(0); - } - elsif (not defined $anvil->data->{cache}{db_fh}{$id}) + if (not defined $anvil->data->{cache}{db_fh}{$uuid}) { # Database handle is gone. - $anvil->Log->entry({source => $THIS_FILE, line => __LINE__, level => 0, priority => "err", key => "log_0078", variables => { id => $id }}); + $anvil->Log->entry({source => $THIS_FILE, line => __LINE__, level => 0, priority => "err", key => "log_0078", variables => { uuid => $uuid }}); return(0); } if (not $sql_file) { $anvil->Log->entry({source => $THIS_FILE, line => __LINE__, level => 0, priority => "err", key => "log_0079", variables => { server => $say_server, - id => $id, + uuid => $uuid, }}); return(0); } @@ -1342,7 +1331,7 @@ sub initialize { $anvil->Log->entry({source => $THIS_FILE, line => __LINE__, level => 0, priority => "err", key => "log_0080", variables => { server => $say_server, - id => $id, + uuid => $uuid, sql_file => $sql_file, }}); return(0); @@ -1351,7 +1340,7 @@ sub initialize { $anvil->Log->entry({source => $THIS_FILE, line => __LINE__, level => 0, priority => "err", key => "log_0081", variables => { server => $say_server, - id => $id, + uuid => $uuid, sql_file => $sql_file, }}); return(0); @@ -1360,12 +1349,12 @@ sub initialize # Tell the user we need to initialize $anvil->Log->entry({source => $THIS_FILE, line => __LINE__, level => 1, key => "log_0082", variables => { server => $say_server, - id => $id, + uuid => $uuid, sql_file => $sql_file, }}); # Read in the SQL file and replace #!variable!name!# with the database owner name. - my $user = $anvil->data->{database}{$id}{user} ? $anvil->data->{database}{$id}{user} : $anvil->data->{sys}{database}{user}; + my $user = $anvil->data->{database}{$uuid}{user} ? $anvil->data->{database}{$uuid}{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}); @@ -1375,10 +1364,10 @@ sub initialize $anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => $debug, list => { "<< sql" => $sql }}); # Now that I am ready, disable autocommit, write and commit. - $anvil->Database->write({id => $id, query => $sql, source => $THIS_FILE, line => __LINE__}); + $anvil->Database->write({uuid => $uuid, query => $sql, source => $THIS_FILE, line => __LINE__}); - $anvil->data->{sys}{db_initialized}{$id} = 1; - $anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => $debug, list => { "sys::db_initialized::${id}" => $anvil->data->{sys}{db_initialized}{$id} }}); + $anvil->data->{sys}{db_initialized}{$uuid} = 1; + $anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => $debug, list => { "sys::db_initialized::${uuid}" => $anvil->data->{sys}{db_initialized}{$uuid} }}); # Mark that we need to update the DB. $anvil->data->{sys}{database}{resync_needed} = 1; @@ -1396,7 +1385,7 @@ If there is an error, an empty string is returned. Parameters; -=head3 id (optional) +=head3 uuid (optional) If set, only the corresponding database will be written to. @@ -1429,14 +1418,14 @@ sub insert_or_update_hosts my $debug = defined $parameter->{debug} ? $parameter->{debug} : 3; $anvil->Log->entry({source => $THIS_FILE, line => __LINE__, level => $debug, key => "log_0125", variables => { method => "Database->insert_or_update_hosts()" }}); - my $id = defined $parameter->{id} ? $parameter->{id} : ""; + my $uuid = defined $parameter->{uuid} ? $parameter->{uuid} : ""; my $file = defined $parameter->{file} ? $parameter->{file} : ""; my $line = defined $parameter->{line} ? $parameter->{line} : ""; my $host_name = defined $parameter->{host_name} ? $parameter->{host_name} : $anvil->_hostname; my $host_type = defined $parameter->{host_type} ? $parameter->{host_type} : $anvil->System->determine_host_type; my $host_uuid = defined $parameter->{host_uuid} ? $parameter->{host_uuid} : $anvil->Get->host_uuid; $anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => $debug, list => { - id => $id, + uuid => $uuid, file => $file, line => $line, host_name => $host_name, @@ -1471,7 +1460,7 @@ WHERE ;"; $anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => $debug, list => { query => $query }}); - my $results = $anvil->Database->query({query => $query, id => $id, source => $file ? $file : $THIS_FILE, line => $line ? $line : __LINE__}); + my $results = $anvil->Database->query({query => $query, uuid => $uuid, source => $file ? $file : $THIS_FILE, line => $line ? $line : __LINE__}); my $count = @{$results}; $anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => $debug, list => { results => $results, @@ -1506,7 +1495,7 @@ INSERT INTO "; $query =~ s/'NULL'/NULL/g; $anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => $debug, list => { query => $query }}); - $anvil->Database->write({query => $query, id => $id, source => $file ? $file : $THIS_FILE, line => $line ? $line : __LINE__}); + $anvil->Database->write({query => $query, uuid => $uuid, source => $file ? $file : $THIS_FILE, line => $line ? $line : __LINE__}); } elsif (($old_host_name ne $host_name) or ($old_host_type ne $host_type)) { @@ -1523,7 +1512,7 @@ WHERE ;"; $query =~ s/'NULL'/NULL/g; $anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => $debug, list => { query => $query }}); - $anvil->Database->write({query => $query, id => $id, source => $file ? $file : $THIS_FILE, line => $line ? $line : __LINE__}); + $anvil->Database->write({query => $query, uuid => $uuid, source => $file ? $file : $THIS_FILE, line => $line ? $line : __LINE__}); } $anvil->Log->entry({source => $THIS_FILE, line => __LINE__, level => $debug, key => "log_0126", variables => { method => "Database->insert_or_update_hosts()" }}); @@ -1539,7 +1528,7 @@ If there is an error, an empty string is returned. Parameters; -=head3 id (optional) +=head3 uuid (optional) If set, only the corresponding database will be written to. @@ -1622,7 +1611,7 @@ sub insert_or_update_jobs my $debug = defined $parameter->{debug} ? $parameter->{debug} : 3; $anvil->Log->entry({source => $THIS_FILE, line => __LINE__, level => $debug, key => "log_0125", variables => { method => "Database->insert_or_update_jobs()" }}); - my $id = defined $parameter->{id} ? $parameter->{id} : ""; + my $uuid = defined $parameter->{uuid} ? $parameter->{uuid} : ""; my $file = defined $parameter->{file} ? $parameter->{file} : ""; my $line = defined $parameter->{line} ? $parameter->{line} : ""; my $job_uuid = defined $parameter->{job_uuid} ? $parameter->{job_uuid} : ""; @@ -1639,7 +1628,7 @@ sub insert_or_update_jobs my $job_status = defined $parameter->{job_status} ? $parameter->{job_status} : ""; my $update_progress_only = defined $parameter->{update_progress_only} ? $parameter->{update_progress_only} : 0; $anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => $debug, list => { - id => $id, + uuid => $uuid, file => $file, line => $line, job_uuid => $job_uuid, @@ -1953,7 +1942,7 @@ If there is an error, an empty string is returned. Otherwise, the record's UUID Parameters; -=head3 id (optional) +=head3 uuid (optional) If set, only the corresponding database will be written to. @@ -2022,7 +2011,7 @@ sub insert_or_update_network_interfaces my $debug = defined $parameter->{debug} ? $parameter->{debug} : 3; $anvil->Log->entry({source => $THIS_FILE, line => __LINE__, level => $debug, key => "log_0125", variables => { method => "Database->insert_or_update_network_interfaces()" }}); - my $id = defined $parameter->{id} ? $parameter->{id} : ""; + my $uuid = defined $parameter->{uuid} ? $parameter->{uuid} : ""; my $file = defined $parameter->{file} ? $parameter->{file} : ""; my $line = defined $parameter->{line} ? $parameter->{line} : ""; my $network_interface_bond_uuid = defined $parameter->{network_interface_bond_uuid} ? $parameter->{network_interface_bond_uuid} : "--"; @@ -2038,7 +2027,7 @@ sub insert_or_update_network_interfaces my $network_interface_speed = defined $parameter->{network_interface_speed} ? $parameter->{network_interface_speed} : "--"; my $network_interface_uuid = defined $parameter->{network_interface_uuid} ? $parameter->{interface_uuid} : ""; $anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => $debug, list => { - id => $id, + uuid => $uuid, file => $file, line => $line, network_interface_bond_uuid => $network_interface_bond_uuid, @@ -2096,7 +2085,7 @@ WHERE "; $anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => $debug, list => { query => $query }}); - my $results = $anvil->Database->query({query => $query, id => $id, source => $file ? $file : $THIS_FILE, line => $line ? $line : __LINE__}); + my $results = $anvil->Database->query({query => $query, uuid => $uuid, source => $file ? $file : $THIS_FILE, line => $line ? $line : __LINE__}); my $count = @{$results}; $anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => $debug, list => { results => $results, @@ -2198,7 +2187,7 @@ WHERE ;"; $query =~ s/'NULL'/NULL/g; $anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => $debug, list => { query => $query }}); - $anvil->Database->write({query => $query, id => $id, source => $file ? $file : $THIS_FILE, line => $line ? $line : __LINE__}); + $anvil->Database->write({query => $query, uuid => $uuid, source => $file ? $file : $THIS_FILE, line => $line ? $line : __LINE__}); } else { @@ -2283,7 +2272,7 @@ INSERT INTO "; $query =~ s/'NULL'/NULL/g; $anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => $debug, list => { query => $query }}); - $anvil->Database->write({query => $query, id => $id, source => $file ? $file : $THIS_FILE, line => $line ? $line : __LINE__}); + $anvil->Database->write({query => $query, uuid => $uuid, source => $file ? $file : $THIS_FILE, line => $line ? $line : __LINE__}); } $anvil->Log->entry({source => $THIS_FILE, line => __LINE__, level => $debug, key => "log_0126", variables => { method => "Database->insert_or_update_network_interfaces()" }}); @@ -2299,7 +2288,7 @@ If there is an error, an empty string is returned. Parameters; -=head3 id (optional) +=head3 uuid (optional) If set, only the corresponding database will be written to. @@ -2336,7 +2325,7 @@ sub insert_or_update_states my $debug = defined $parameter->{debug} ? $parameter->{debug} : 3; $anvil->Log->entry({source => $THIS_FILE, line => __LINE__, level => $debug, key => "log_0125", variables => { method => "Database->insert_or_update_states()" }}); - my $id = defined $parameter->{id} ? $parameter->{id} : ""; + my $uuid = defined $parameter->{uuid} ? $parameter->{uuid} : ""; my $file = defined $parameter->{file} ? $parameter->{file} : ""; my $line = defined $parameter->{line} ? $parameter->{line} : ""; my $state_uuid = defined $parameter->{state_uuid} ? $parameter->{state_uuid} : ""; @@ -2344,7 +2333,7 @@ sub insert_or_update_states my $state_host_uuid = defined $parameter->{state_host_uuid} ? $parameter->{state_host_uuid} : $anvil->data->{sys}{host_uuid}; my $state_note = defined $parameter->{state_note} ? $parameter->{state_note} : "NULL"; $anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => $debug, list => { - id => $id, + uuid => $uuid, file => $file, line => $line, state_uuid => $state_uuid, @@ -2513,7 +2502,7 @@ If there is an error, C<< !!error!! >> is returned. Parameters; -=head3 id (optional) +=head3 uuid (optional) If set, only the corresponding database will be written to. @@ -2572,7 +2561,7 @@ sub insert_or_update_variables my $debug = defined $parameter->{debug} ? $parameter->{debug} : 3; $anvil->Log->entry({source => $THIS_FILE, line => __LINE__, level => $debug, key => "log_0125", variables => { method => "Database->insert_or_update_variables()" }}); - my $id = defined $parameter->{id} ? $parameter->{id} : ""; + my $uuid = defined $parameter->{uuid} ? $parameter->{uuid} : ""; my $file = defined $parameter->{file} ? $parameter->{file} : ""; my $line = defined $parameter->{line} ? $parameter->{line} : ""; my $variable_uuid = defined $parameter->{variable_uuid} ? $parameter->{variable_uuid} : ""; @@ -2586,7 +2575,7 @@ sub insert_or_update_variables my $update_value_only = defined $parameter->{update_value_only} ? $parameter->{update_value_only} : 1; my $log_level = defined $parameter->{log_level} ? $parameter->{log_level} : 3; # Undocumented for now. $anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => $log_level, list => { - id => $id, + uuid => $uuid, file => $file, line => $line, variable_uuid => $variable_uuid, @@ -3134,7 +3123,7 @@ sub mark_active $anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => $debug, list => { set => $set }}); # If I haven't connected to a database yet, why am I here? - if (not $anvil->data->{sys}{read_db_id}) + if (not $anvil->data->{sys}{read_db_uuid}) { return(0); } @@ -3195,9 +3184,9 @@ B: Do not sort the array references; They won't make any sense as the refe Parameters; -=head3 id (optional) +=head3 uuid (optional) -By default, the local database will be queried (if run on a machine with a database). Otherwise, the first database successfully connected to will be used for queries (as stored in C<< $anvil->data->{sys}{read_db_id} >>). +By default, the local database will be queried (if run on a machine with a database). Otherwise, the first database successfully connected to will be used for queries (as stored in C<< $anvil->data->{sys}{read_db_uuid} >>). If you want to read from a specific database, though, you can set this parameter to the ID of the database (C<< database::::host). If you specify a read from a database that isn't available, C<< !!error!! >> will be returned. @@ -3219,7 +3208,6 @@ If set, the query will be treated as containing sensitive data and will only be To help with logging the source of a query, C<< source >> can be set to the name of the script that requested the query. It is generally used along side C<< line >>. - =cut sub query { @@ -3229,14 +3217,14 @@ sub query my $debug = defined $parameter->{debug} ? $parameter->{debug} : 3; $anvil->Log->entry({source => $THIS_FILE, line => __LINE__, level => $debug, key => "log_0125", variables => { method => "Database->query()" }}); - my $id = $parameter->{id} ? $parameter->{id} : $anvil->data->{sys}{read_db_id}; + my $uuid = $parameter->{uuid} ? $parameter->{uuid} : $anvil->data->{sys}{read_db_uuid}; my $line = $parameter->{line} ? $parameter->{line} : __LINE__; my $query = $parameter->{query} ? $parameter->{query} : ""; my $secure = $parameter->{secure} ? $parameter->{secure} : 0; my $source = $parameter->{source} ? $parameter->{source} : $THIS_FILE; $anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => $debug, list => { - id => $id, - "cache::db_fh::${id}" => $anvil->data->{cache}{db_fh}{$id}, + uuid => $uuid, + "cache::db_fh::${uuid}" => $anvil->data->{cache}{db_fh}{$uuid}, line => $line, query => ((not $secure) or (($secure) && (not $anvil->Log->secure))) ? $query : "--", secure => $secure, @@ -3244,19 +3232,19 @@ sub query }}); # Make logging code a little cleaner - 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; + my $database_name = defined $anvil->data->{database}{$uuid}{name} ? $anvil->data->{database}{$uuid}{name} : $anvil->data->{sys}{database}{name}; + my $say_server = $anvil->data->{database}{$uuid}{host}.":".$anvil->data->{database}{$uuid}{port}." -> ".$database_name; - if (not $id) + if (not $uuid) { # No database to talk to... $anvil->Log->entry({source => $THIS_FILE, line => __LINE__, level => 0, priority => "err", key => "log_0072"}); return("!!error!!"); } - elsif (not defined $anvil->data->{cache}{db_fh}{$id}) + elsif (not defined $anvil->data->{cache}{db_fh}{$uuid}) { # Database handle is gone. - $anvil->Log->entry({source => $THIS_FILE, line => __LINE__, level => 0, priority => "err", key => "log_0073", variables => { id => $id }}); + $anvil->Log->entry({source => $THIS_FILE, line => __LINE__, level => 0, priority => "err", key => "log_0073", variables => { uuid => $uuid }}); return("!!error!!"); } if (not $query) @@ -3275,16 +3263,16 @@ sub query if ($anvil->data->{sys}{database}{log_transactions}) { $anvil->Log->entry({source => $source, line => $line, secure => $secure, level => 0, key => "log_0074", variables => { - id => $id, + uuid => $uuid, query => $query, }}); } # Test access to the DB before we do the actual query - $anvil->Database->_test_access({id => $id}); + $anvil->Database->_test_access({uuid => $uuid}); # Do the query. - my $DBreq = $anvil->data->{cache}{db_fh}{$id}->prepare($query) or $anvil->Log->entry({source => $THIS_FILE, line => __LINE__, level => 0, priority => "err", key => "log_0075", variables => { + my $DBreq = $anvil->data->{cache}{db_fh}{$uuid}->prepare($query) or $anvil->Log->entry({source => $THIS_FILE, line => __LINE__, level => 0, priority => "err", key => "log_0075", variables => { query => ((not $secure) or (($secure) && (not $anvil->Log->secure))) ? $query : "--", server => $say_server, db_error => $DBI::errstr, @@ -3330,7 +3318,7 @@ sub read_variable my $variable_name = $parameter->{variable_name} ? $parameter->{variable_name} : ""; my $variable_source_uuid = $parameter->{variable_source_uuid} ? $parameter->{variable_source_uuid} : "NULL"; my $variable_source_table = $parameter->{variable_source_table} ? $parameter->{variable_source_table} : "NULL"; - my $id = $parameter->{id} ? $parameter->{id} : $anvil->data->{sys}{read_db_id}; + my $uuid = $parameter->{uuid} ? $parameter->{uuid} : $anvil->data->{sys}{read_db_uuid}; $anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => $debug, list => { variable_uuid => $variable_uuid, variable_name => $variable_name, @@ -3379,7 +3367,7 @@ AND my $variable_value = ""; my $modified_date = ""; - my $results = $anvil->Database->query({id => $id, query => $query, source => $THIS_FILE, line => __LINE__}); + my $results = $anvil->Database->query({uuid => $uuid, query => $query, source => $THIS_FILE, line => __LINE__}); my $count = @{$results}; $anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => $debug, list => { results => $results, @@ -3491,11 +3479,11 @@ sub resync_databases } # Now read in the data from the different databases. - foreach my $id (sort {$a cmp $b} keys %{$anvil->data->{cache}{db_fh}}) + foreach my $uuid (sort {$a cmp $b} keys %{$anvil->data->{cache}{db_fh}}) { # ... - $anvil->data->{db_resync}{$id}{public}{sql} = []; - $anvil->data->{db_resync}{$id}{history}{sql} = []; + $anvil->data->{db_resync}{$uuid}{public}{sql} = []; + $anvil->data->{db_resync}{$uuid}{history}{sql} = []; # Read in the data, modified_date first as we'll need that for all entries we record. my $query = "SELECT modified_date AT time zone 'UTC', $uuid_column, "; @@ -3523,9 +3511,9 @@ sub resync_databases $query .= " WHERE ".$host_column." = ".$anvil->data->{sys}{use_db_fh}->quote($anvil->data->{sys}{host_uuid}); } $query .= " ORDER BY modified_date DESC;"; - $anvil->Log->entry({source => $THIS_FILE, line => __LINE__, level => $debug, key => "log_0074", variables => { id => $id, query => $query }}); + $anvil->Log->entry({source => $THIS_FILE, line => __LINE__, level => $debug, key => "log_0074", variables => { uuid => $uuid, query => $query }}); - my $results = $anvil->Database->query({id => $id, query => $query, source => $THIS_FILE, line => __LINE__}); + my $results = $anvil->Database->query({uuid => $uuid, query => $query, source => $THIS_FILE, line => __LINE__}); my $count = @{$results}; $anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => $debug, list => { results => $results, @@ -3546,7 +3534,7 @@ sub resync_databases my $not_null = $anvil->data->{sys}{database}{table}{$table}{column}{$column_name}{not_null}; my $data_type = $anvil->data->{sys}{database}{table}{$table}{column}{$column_name}{data_type}; $anvil->Log->variables({source => 2, line => __LINE__, level => $debug, list => { - "s1:id" => $id, + "s1:id" => $uuid, "s2:row_number" => $row_number, "s3:column_number" => $column_number, "s4:column_name" => $column_name, @@ -3576,11 +3564,11 @@ sub resync_databases # This is used to determine if a given entry needs to be # updated or inserted into the public schema - $anvil->data->{db_data}{$id}{$table}{$uuid_column}{$row_uuid}{'exists'} = 1; - $anvil->data->{db_data}{$id}{$table}{$uuid_column}{$row_uuid}{seen} = 0; + $anvil->data->{db_data}{$uuid}{$table}{$uuid_column}{$row_uuid}{'exists'} = 1; + $anvil->data->{db_data}{$uuid}{$table}{$uuid_column}{$row_uuid}{seen} = 0; $anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => $debug, list => { - "db_data::${id}::${table}::${uuid_column}::${row_uuid}::exists" => $anvil->data->{db_data}{$id}{$table}{$uuid_column}{$row_uuid}{'exists'}, - "db_data::${id}::${table}::${uuid_column}::${row_uuid}::seen" => $anvil->data->{db_data}{$id}{$table}{$uuid_column}{$row_uuid}{seen}, + "db_data::${uuid}::${table}::${uuid_column}::${row_uuid}::exists" => $anvil->data->{db_data}{$uuid}{$table}{$uuid_column}{$row_uuid}{'exists'}, + "db_data::${uuid}::${table}::${uuid_column}::${row_uuid}::seen" => $anvil->data->{db_data}{$uuid}{$table}{$uuid_column}{$row_uuid}{seen}, }}); next; } @@ -3591,10 +3579,10 @@ sub resync_databases # Record this in the unified and local hashes. # This table isn't restricted to given hosts. $anvil->data->{db_data}{unified}{$table}{modified_date}{$modified_date}{$uuid_column}{$row_uuid}{$column_name} = $column_value; - $anvil->data->{db_data}{$id}{$table}{modified_date}{$modified_date}{$uuid_column}{$row_uuid}{$column_name} = $column_value; + $anvil->data->{db_data}{$uuid}{$table}{modified_date}{$modified_date}{$uuid_column}{$row_uuid}{$column_name} = $column_value; $anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => $debug, list => { "db_data::unified::${table}::modified_date::${modified_date}::${uuid_column}::${row_uuid}::${column_name}" => $anvil->data->{db_data}{unified}{$table}{modified_date}{$modified_date}{$uuid_column}{$row_uuid}{$column_name}, - "db_data::${id}::${table}::modified_date::${modified_date}::${uuid_column}::${row_uuid}::${column_name}" => $anvil->data->{db_data}{$id}{$table}{modified_date}{$modified_date}{$uuid_column}{$row_uuid}{$column_name}, + "db_data::${uuid}::${table}::modified_date::${modified_date}::${uuid_column}::${row_uuid}::${column_name}" => $anvil->data->{db_data}{$uuid}{$table}{modified_date}{$modified_date}{$uuid_column}{$row_uuid}{$column_name}, }}); } } @@ -3609,9 +3597,9 @@ sub resync_databases { $anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => $debug, list => { row_uuid => $row_uuid }}); - foreach my $id (sort {$a cmp $b} keys %{$anvil->data->{cache}{db_fh}}) + foreach my $uuid (sort {$a cmp $b} keys %{$anvil->data->{cache}{db_fh}}) { - $anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => $debug, list => { id => $id }}); + $anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => $debug, list => { uuid => $uuid }}); # For each 'row_uuid' we see; # - Check if we've *seen* it before @@ -3622,27 +3610,27 @@ sub resync_databases # \- If we have seen, see if it exists at the current timestamp. # \- If not, _INSERT_ it into history schema. $anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => $debug, list => { - "db_data::${id}::${table}::${uuid_column}::${row_uuid}::seen" => $anvil->data->{db_data}{$id}{$table}{$uuid_column}{$row_uuid}{seen} + "db_data::${uuid}::${table}::${uuid_column}::${row_uuid}::seen" => $anvil->data->{db_data}{$uuid}{$table}{$uuid_column}{$row_uuid}{seen} }}); - if (not $anvil->data->{db_data}{$id}{$table}{$uuid_column}{$row_uuid}{seen}) + if (not $anvil->data->{db_data}{$uuid}{$table}{$uuid_column}{$row_uuid}{seen}) { # Mark this record as now having been seen. - $anvil->data->{db_data}{$id}{$table}{$uuid_column}{$row_uuid}{seen} = 1; + $anvil->data->{db_data}{$uuid}{$table}{$uuid_column}{$row_uuid}{seen} = 1; $anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => $debug, list => { - "db_data::${id}::${table}::${uuid_column}::${row_uuid}::seen" => $anvil->data->{db_data}{$id}{$table}{$uuid_column}{$row_uuid}{seen} + "db_data::${uuid}::${table}::${uuid_column}::${row_uuid}::seen" => $anvil->data->{db_data}{$uuid}{$table}{$uuid_column}{$row_uuid}{seen} }}); # Does it exist? $anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => $debug, list => { - "db_data::${id}::${table}::${uuid_column}::${row_uuid}::exists" => $anvil->data->{db_data}{$id}{$table}{$uuid_column}{$row_uuid}{'exists'} + "db_data::${uuid}::${table}::${uuid_column}::${row_uuid}::exists" => $anvil->data->{db_data}{$uuid}{$table}{$uuid_column}{$row_uuid}{'exists'} }}); - if ($anvil->data->{db_data}{$id}{$table}{$uuid_column}{$row_uuid}{'exists'}) + if ($anvil->data->{db_data}{$uuid}{$table}{$uuid_column}{$row_uuid}{'exists'}) { # It exists, but does it exist at this time stamp? $anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => $debug, list => { - "db_data::${id}::${table}::modified_date::${modified_date}::${uuid_column}::${row_uuid}" => $anvil->data->{db_data}{$id}{$table}{modified_date}{$modified_date}{$uuid_column}{$row_uuid}, + "db_data::${uuid}::${table}::modified_date::${modified_date}::${uuid_column}::${row_uuid}" => $anvil->data->{db_data}{$uuid}{$table}{modified_date}{$modified_date}{$uuid_column}{$row_uuid}, }}); - if (not $anvil->data->{db_data}{$id}{$table}{modified_date}{$modified_date}{$uuid_column}{$row_uuid}) + if (not $anvil->data->{db_data}{$uuid}{$table}{modified_date}{$modified_date}{$uuid_column}{$row_uuid}) { # No, so UPDATE it. We'll build the query now... my $query = "UPDATE public.$table SET "; @@ -3659,10 +3647,10 @@ sub resync_databases $query .= "$column_name = ".$column_value.", "; } $query .= "modified_date = ".$anvil->data->{sys}{use_db_fh}->quote($modified_date)."::timestamp AT TIME ZONE 'UTC' WHERE $uuid_column = ".$anvil->data->{sys}{use_db_fh}->quote($row_uuid).";"; - $anvil->Log->entry({source => $THIS_FILE, line => __LINE__, level => $debug, key => "log_0074", variables => { id => $id, query => $query }}); + $anvil->Log->entry({source => $THIS_FILE, line => __LINE__, level => $debug, key => "log_0074", variables => { uuid => $uuid, query => $query }}); # Now record the query in the array - push @{$anvil->data->{db_resync}{$id}{public}{sql}}, $query; + push @{$anvil->data->{db_resync}{$uuid}{public}{sql}}, $query; } # if not exists - timestamp } # if exists else @@ -3695,10 +3683,10 @@ sub resync_databases # Add the host column. $query = "INSERT INTO public.$table ($host_column, $uuid_column, ".$columns."modified_date) VALUES (".$anvil->data->{sys}{use_db_fh}->quote($anvil->data->{sys}{host_uuid}).", ".$anvil->data->{sys}{use_db_fh}->quote($row_uuid).", ".$values.$anvil->data->{sys}{use_db_fh}->quote($modified_date)."::timestamp AT TIME ZONE 'UTC');"; } - $anvil->Log->entry({source => $THIS_FILE, line => __LINE__, level => $debug, key => "log_0074", variables => { id => $id, query => $query }}); + $anvil->Log->entry({source => $THIS_FILE, line => __LINE__, level => $debug, key => "log_0074", variables => { uuid => $uuid, query => $query }}); # Now record the query in the array - push @{$anvil->data->{db_resync}{$id}{public}{sql}}, $query; + push @{$anvil->data->{db_resync}{$uuid}{public}{sql}}, $query; } # if not exists } # if not seen else @@ -3711,9 +3699,9 @@ sub resync_databases # question of whether the entry for the current # timestamp exists in the history schema. $anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => $debug, list => { - "db_data::${id}::${table}::modified_date::${modified_date}::${uuid_column}::${row_uuid}" => $anvil->data->{db_data}{$id}{$table}{modified_date}{$modified_date}{$uuid_column}{$row_uuid}, + "db_data::${uuid}::${table}::modified_date::${modified_date}::${uuid_column}::${row_uuid}" => $anvil->data->{db_data}{$uuid}{$table}{modified_date}{$modified_date}{$uuid_column}{$row_uuid}, }}); - if (not $anvil->data->{db_data}{$id}{$table}{modified_date}{$modified_date}{$uuid_column}{$row_uuid}) + if (not $anvil->data->{db_data}{$uuid}{$table}{modified_date}{$modified_date}{$uuid_column}{$row_uuid}) { # It hasn't been seen, so INSERT it. We need # to build entries for the column names and @@ -3743,10 +3731,10 @@ sub resync_databases # Add the host column. $query = "INSERT INTO history.$table ($host_column, $uuid_column, ".$columns."modified_date) VALUES (".$anvil->data->{sys}{use_db_fh}->quote($anvil->data->{sys}{host_uuid}).", ".$anvil->data->{sys}{use_db_fh}->quote($row_uuid).", ".$values.$anvil->data->{sys}{use_db_fh}->quote($modified_date)."::timestamp AT TIME ZONE 'UTC');"; } - $anvil->Log->entry({source => $THIS_FILE, line => __LINE__, level => $debug, key => "log_0074", variables => { id => $id, query => $query }}); + $anvil->Log->entry({source => $THIS_FILE, line => __LINE__, level => $debug, key => "log_0074", variables => { uuid => $uuid, query => $query }}); # Now record the query in the array - push @{$anvil->data->{db_resync}{$id}{history}{sql}}, $query; + push @{$anvil->data->{db_resync}{$uuid}{history}{sql}}, $query; } # if not exists - timestamp } # if seen } # foreach $id @@ -3757,20 +3745,20 @@ sub resync_databases delete $anvil->data->{db_data}; # Do the INSERTs now and then release the memory. - foreach my $id (sort {$a cmp $b} keys %{$anvil->data->{cache}{db_fh}}) + foreach my $uuid (sort {$a cmp $b} keys %{$anvil->data->{cache}{db_fh}}) { # Merge the queries for both schemas into one array, with public schema # queries being first, then delete the arrays holding them to free memory # before we start the resync. my $merged = []; - @{$merged} = (@{$anvil->data->{db_resync}{$id}{public}{sql}}, @{$anvil->data->{db_resync}{$id}{history}{sql}}); - undef $anvil->data->{db_resync}{$id}{public}{sql}; - undef $anvil->data->{db_resync}{$id}{history}{sql}; + @{$merged} = (@{$anvil->data->{db_resync}{$uuid}{public}{sql}}, @{$anvil->data->{db_resync}{$uuid}{history}{sql}}); + undef $anvil->data->{db_resync}{$uuid}{public}{sql}; + undef $anvil->data->{db_resync}{$uuid}{history}{sql}; # If the merged array has any entries, push them in. if (@{$merged} > 0) { - $anvil->Database->write({id => $id, query => $merged, source => $THIS_FILE, line => __LINE__}); + $anvil->Database->write({uuid => $uuid, query => $merged, source => $THIS_FILE, line => __LINE__}); undef $merged; } } @@ -3800,15 +3788,15 @@ sub write my $debug = defined $parameter->{debug} ? $parameter->{debug} : 3; $anvil->Log->entry({source => $THIS_FILE, line => __LINE__, level => $debug, key => "log_0125", variables => { method => "Database->write()" }}); - my $id = $parameter->{id} ? $parameter->{id} : ""; + my $uuid = $parameter->{uuid} ? $parameter->{uuid} : ""; my $line = $parameter->{line} ? $parameter->{line} : __LINE__; my $query = $parameter->{query} ? $parameter->{query} : ""; my $secure = $parameter->{secure} ? $parameter->{secure} : 0; my $source = $parameter->{source} ? $parameter->{source} : $THIS_FILE; my $reenter = $parameter->{reenter} ? $parameter->{reenter} : ""; $anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => $debug, list => { - id => $id, - "cache::db_fh::${id}" => $anvil->data->{cache}{db_fh}{$id}, + uuid => $uuid, + "cache::db_fh::${uuid}" => $anvil->data->{cache}{db_fh}{$uuid}, line => $line, query => ((not $secure) or (($secure) && (not $anvil->Log->secure))) ? $query : "--", secure => $secure, @@ -3817,9 +3805,9 @@ sub write }}); # Make logging code a little cleaner - 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"; + my $database_name = defined $anvil->data->{database}{$uuid}{name} ? $anvil->data->{database}{$uuid}{name} : $anvil->data->{sys}{database}{name}; + my $say_server = $uuid eq "" ? "#!string!log_0129!#" : $anvil->data->{database}{$uuid}{host}.":".$anvil->data->{database}{$uuid}{port}." -> ".$database_name; + #print "uuid: [$uuid], 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. if (not $query) @@ -3833,18 +3821,18 @@ sub write $anvil->Database->check_lock_age; # This array will hold either just the passed DB ID or all of them, if no ID was specified. - my @db_ids; - if ($id) + my @db_uuids; + if ($uuid) { - $anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => $debug, list => { id => $id }}); - push @db_ids, $id; + $anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => $debug, list => { uuid => $uuid }}); + push @db_uuids, $uuid; } else { - foreach my $id (sort {$a cmp $b} keys %{$anvil->data->{cache}{db_fh}}) + foreach my $uuid (sort {$a cmp $b} keys %{$anvil->data->{cache}{db_fh}}) { - $anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => $debug, list => { id => $id }}); - push @db_ids, $id; + $anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => $debug, list => { uuid => $uuid }}); + push @db_uuids, $uuid; } } @@ -3891,10 +3879,10 @@ sub write if ($i > $next) { # Commit this batch. - foreach my $id (@db_ids) + foreach my $uuid (@db_uuids) { # Commit this chunk to this DB. - $anvil->Database->write({id => $id, query => $query_set, source => $THIS_FILE, line => $line, reenter => 1}); + $anvil->Database->write({uuid => $uuid, query => $query_set, source => $THIS_FILE, line => $line, reenter => 1}); ### TODO: Rework this so that we exit here (so that we can ### send an alert) if the RAM use is too high. @@ -3924,21 +3912,21 @@ sub write { push @{$query_set}, $query; } - foreach my $id (@db_ids) + foreach my $uuid (@db_uuids) { # Test access to the DB before we do the actual query - $anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => $debug, list => { id => $id }}); - $anvil->Database->_test_access({id => $id}); + $anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => $debug, list => { uuid => $uuid }}); + $anvil->Database->_test_access({uuid => $uuid}); # Do the actual query(ies) $anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => $debug, list => { - id => $id, + uuid => $uuid, count => $count, }}); if ($count) { # More than one query, so start a transaction block. - $anvil->data->{cache}{db_fh}{$id}->begin_work; + $anvil->data->{cache}{db_fh}{$uuid}->begin_work; } foreach my $query (@{$query_set}) @@ -3946,19 +3934,19 @@ sub write if ($anvil->data->{sys}{database}{log_transactions}) { $anvil->Log->entry({source => $source, line => $line, secure => $secure, level => 0, key => "log_0083", variables => { - id => $id, + uuid => $uuid, query => $query, }}); } - if (not $anvil->data->{cache}{db_fh}{$id}) + if (not $anvil->data->{cache}{db_fh}{$uuid}) { - $anvil->Log->entry({source => $THIS_FILE, line => __LINE__, level => 0, priority => "err", key => "log_0089", variables => { id => $id }}); + $anvil->Log->entry({source => $THIS_FILE, line => __LINE__, level => 0, priority => "err", key => "log_0089", variables => { uuid => $uuid }}); next; } # Do the do. - $anvil->data->{cache}{db_fh}{$id}->do($query) or $anvil->Log->entry({source => $THIS_FILE, line => __LINE__, level => 0, priority => "err", key => "log_0090", variables => { + $anvil->data->{cache}{db_fh}{$uuid}->do($query) or $anvil->Log->entry({source => $THIS_FILE, line => __LINE__, level => 0, priority => "err", key => "log_0090", variables => { query => ((not $secure) or (($secure) && (not $anvil->Log->secure))) ? $query : "--", server => $say_server, db_error => $DBI::errstr, @@ -3969,7 +3957,7 @@ sub write if ($count) { # Commit the changes. - $anvil->data->{cache}{db_fh}{$id}->commit(); + $anvil->data->{cache}{db_fh}{$uuid}->commit(); } } @@ -4168,16 +4156,16 @@ sub _find_behind_databases # Look at all the databases and find the most recent time stamp (and the ID of the DB). my $source_updated_time = 0; - foreach my $id (sort {$a cmp $b} keys %{$anvil->data->{database}}) + foreach my $uuid (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} : "--"; + my $database_name = defined $anvil->data->{database}{$uuid}{name} ? $anvil->data->{database}{$uuid}{name} : "--"; + my $database_user = defined $anvil->data->{database}{$uuid}{user} ? $anvil->data->{database}{$uuid}{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" => $database_name, - "database::${id}::user" => $database_user, - "database::${id}::password" => $anvil->Log->secure ? $anvil->data->{database}{$id}{password} : "--", + "database::${uuid}::host" => $anvil->data->{database}{$uuid}{host}, + "database::${uuid}::port" => $anvil->data->{database}{$uuid}{port}, + "database::${uuid}::name" => $database_name, + "database::${uuid}::user" => $database_user, + "database::${uuid}::password" => $anvil->Log->secure ? $anvil->data->{database}{$uuid}{password} : "--", }}); # Loop through the tables in this DB. For each table, we'll record the most recent time @@ -4189,7 +4177,7 @@ sub _find_behind_databases my $query = "SELECT COUNT(*) FROM information_schema.tables WHERE table_type = 'BASE TABLE' AND table_schema = 'public' AND table_name = ".$anvil->data->{sys}{use_db_fh}->quote($table).";"; $anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => $debug, list => { query => $query }}); - my $count = $anvil->Database->query({id => $id, query => $query, source => $THIS_FILE, line => __LINE__})->[0]->[0]; + my $count = $anvil->Database->query({uuid => $uuid, query => $query, source => $THIS_FILE, line => __LINE__})->[0]->[0]; $anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => $debug, list => { count => $count }}); if ($count == 1) @@ -4201,7 +4189,7 @@ sub _find_behind_databases # See if there is a column that ends in '_host_uuid'. If there is, we'll use # it later to restrict resync activity to these columns with the local # 'sys::host_uuid'. - my $host_column = $anvil->Database->query({id => $id, query => $query, source => $THIS_FILE, line => __LINE__})->[0]->[0]; + my $host_column = $anvil->Database->query({uuid => $uuid, query => $query, source => $THIS_FILE, line => __LINE__})->[0]->[0]; $host_column = "" if not defined $host_column; $anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => $debug, list => { host_column => $host_column }}); @@ -4209,7 +4197,7 @@ sub _find_behind_databases $query = "SELECT COUNT(*) FROM information_schema.tables WHERE table_type = 'BASE TABLE' AND table_schema = 'history' AND table_name = ".$anvil->data->{sys}{use_db_fh}->quote($table).";"; $anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => $debug, list => { query => $query }}); - my $count = $anvil->Database->query({id => $id, query => $query, source => $THIS_FILE, line => __LINE__})->[0]->[0]; + my $count = $anvil->Database->query({uuid => $uuid, query => $query, source => $THIS_FILE, line => __LINE__})->[0]->[0]; $anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => $debug, list => { count => $count }}); my $schema = $count ? "history" : "public"; @@ -4229,29 +4217,29 @@ ORDER BY modified_date DESC ;"; $anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => $debug, list => { - id => $id, + uuid => $uuid, query => $query, }}); - my $last_updated = $anvil->Database->query({id => $id, query => $query, source => $THIS_FILE, line => __LINE__})->[0]->[0]; + my $last_updated = $anvil->Database->query({uuid => $uuid, query => $query, source => $THIS_FILE, line => __LINE__})->[0]->[0]; $last_updated = 0 if not defined $last_updated; # Record this table's last modified_date for later comparison. We'll also # record the schema and host column, if found, to save looking the same thing # up later if we do need a resync. - $anvil->data->{sys}{database}{table}{$table}{id}{$id}{last_updated} = $last_updated; + $anvil->data->{sys}{database}{table}{$table}{id}{$uuid}{last_updated} = $last_updated; $anvil->data->{sys}{database}{table}{$table}{schema} = $schema; $anvil->data->{sys}{database}{table}{$table}{host_column} = $host_column; $anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => $debug, list => { - "sys::database::table::${table}::id::${id}::last_updated" => $anvil->data->{sys}{database}{table}{$table}{id}{$id}{last_updated}, + "sys::database::table::${table}::id::${uuid}::last_updated" => $anvil->data->{sys}{database}{table}{$table}{id}{$uuid}{last_updated}, "sys::database::table::${table}::last_updated" => $anvil->data->{sys}{database}{table}{$table}{last_updated}, "sys::database::table::${table}::schema" => $anvil->data->{sys}{database}{table}{$table}{schema}, "sys::database::table::${table}::host_column" => $anvil->data->{sys}{database}{table}{$table}{host_column}, }}); - if ($anvil->data->{sys}{database}{table}{$table}{id}{$id}{last_updated} > $anvil->data->{sys}{database}{table}{$table}{last_updated}) + if ($anvil->data->{sys}{database}{table}{$table}{id}{$uuid}{last_updated} > $anvil->data->{sys}{database}{table}{$table}{last_updated}) { - $anvil->data->{sys}{database}{table}{$table}{last_updated} = $anvil->data->{sys}{database}{table}{$table}{id}{$id}{last_updated}; + $anvil->data->{sys}{database}{table}{$table}{last_updated} = $anvil->data->{sys}{database}{table}{$table}{id}{$uuid}{last_updated}; $anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => $debug, list => { "sys::database::table::${table}::last_updated" => $anvil->data->{sys}{database}{table}{$table}{last_updated}, }}); @@ -4267,18 +4255,18 @@ ORDER BY $anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => $debug, list => { "sys::database::table::${table}::last_updated" => $anvil->data->{sys}{database}{table}{$table}{last_updated}, }}); - foreach my $id (sort {$a cmp $b} keys %{$anvil->data->{sys}{database}{table}{$table}{id}}) + foreach my $uuid (sort {$a cmp $b} keys %{$anvil->data->{sys}{database}{table}{$table}{id}}) { $anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => $debug, list => { - "sys::database::table::${table}::id::${id}::last_updated" => $anvil->data->{sys}{database}{table}{$table}{id}{$id}{last_updated}, + "sys::database::table::${table}::id::${uuid}::last_updated" => $anvil->data->{sys}{database}{table}{$table}{id}{$uuid}{last_updated}, }}); - if ($anvil->data->{sys}{database}{table}{$table}{last_updated} > $anvil->data->{sys}{database}{table}{$table}{id}{$id}{last_updated}) + if ($anvil->data->{sys}{database}{table}{$table}{last_updated} > $anvil->data->{sys}{database}{table}{$table}{id}{$uuid}{last_updated}) { # Resync needed. - $anvil->Log->entry({source => $THIS_FILE, line => __LINE__, level => 1, priority => "alert", key => "log_0106", variables => { id => $id }}); + $anvil->Log->entry({source => $THIS_FILE, line => __LINE__, level => 1, priority => "alert", key => "log_0106", variables => { uuid => $uuid }}); # Mark it as behind. - $anvil->Database->_mark_database_as_behind({id => $id}); + $anvil->Database->_mark_database_as_behind({uuid => $uuid}); last; } } @@ -4307,31 +4295,31 @@ sub _mark_database_as_behind my $debug = defined $parameter->{debug} ? $parameter->{debug} : 3; $anvil->Log->entry({source => $THIS_FILE, line => __LINE__, level => $debug, key => "log_0125", variables => { method => "Database->_mark_database_as_behind()" }}); - my $id = $parameter->{id} ? $parameter->{id} : ""; - $anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => $debug, list => { id => $id }}); + my $uuid = $parameter->{uuid} ? $parameter->{uuid} : ""; + $anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => $debug, list => { uuid => $uuid }}); - $anvil->data->{sys}{database}{to_update}{$id}{behind} = 1; + $anvil->data->{sys}{database}{to_update}{$uuid}{behind} = 1; $anvil->data->{sys}{database}{resync_needed} = 1; $anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => $debug, list => { - "sys::database::to_update::${id}::behind" => $anvil->data->{sys}{database}{to_update}{$id}{behind}, + "sys::database::to_update::${uuid}::behind" => $anvil->data->{sys}{database}{to_update}{$uuid}{behind}, "sys::database::resync_needed" => $anvil->data->{sys}{database}{resync_needed}, }}); # We can't trust this database for reads, so switch to another database for reads if # necessary. $anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => $debug, list => { - id => $id, - "sys::read_db_id" => $anvil->data->{sys}{read_db_id}, + uuid => $uuid, + "sys::read_db_uuid" => $anvil->data->{sys}{read_db_uuid}, }}); - if ($id eq $anvil->data->{sys}{read_db_id}) + if ($uuid eq $anvil->data->{sys}{read_db_uuid}) { # Switch. - $anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => $debug, list => { ">> sys::read_db_id" => $anvil->data->{sys}{read_db_id} }}); - foreach my $this_id (sort {$a cmp $b} keys %{$anvil->data->{database}}) + $anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => $debug, list => { ">> sys::read_db_uuid" => $anvil->data->{sys}{read_db_uuid} }}); + foreach my $this_uuid (sort {$a cmp $b} keys %{$anvil->data->{database}}) { - next if $this_id eq $id; - $anvil->data->{sys}{read_db_id} = $this_id; - $anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => $debug, list => { "<< sys::read_db_id" => $anvil->data->{sys}{read_db_id} }}); + next if $this_uuid eq $uuid; + $anvil->data->{sys}{read_db_uuid} = $this_uuid; + $anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => $debug, list => { "<< sys::read_db_uuid" => $anvil->data->{sys}{read_db_uuid} }}); last; } } @@ -4354,18 +4342,18 @@ sub _test_access my $debug = defined $parameter->{debug} ? $parameter->{debug} : 3; $anvil->Log->entry({source => $THIS_FILE, line => __LINE__, level => $debug, key => "log_0125", variables => { method => "Database->_test_access()" }}); - my $id = $parameter->{id} ? $parameter->{id} : ""; - $anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => $debug, list => { id => $id }}); + my $uuid = $parameter->{uuid} ? $parameter->{uuid} : ""; + $anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => $debug, list => { uuid => $uuid }}); # Make logging code a little cleaner - 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; + my $database_name = defined $anvil->data->{database}{$uuid}{name} ? $anvil->data->{database}{$uuid}{name} : $anvil->data->{sys}{database}{name}; + my $say_server = $anvil->data->{database}{$uuid}{host}.":".$anvil->data->{database}{$uuid}{port}." -> ".$database_name; # Log our test $anvil->Log->entry({source => $THIS_FILE, line => __LINE__, level => $debug, key => "log_0087", variables => { server => $say_server }}); my $query = "SELECT 1"; - my $DBreq = $anvil->data->{cache}{db_fh}{$id}->prepare($query) or $anvil->Log->entry({source => $THIS_FILE, line => __LINE__, level => 0, priority => "err", key => "log_0075", variables => { + my $DBreq = $anvil->data->{cache}{db_fh}{$uuid}->prepare($query) or $anvil->Log->entry({source => $THIS_FILE, line => __LINE__, level => 0, priority => "err", key => "log_0075", variables => { query => $query, server => $say_server, db_error => $DBI::errstr, diff --git a/Anvil/Tools/Get.pm b/Anvil/Tools/Get.pm index 88382ce1..5f698708 100755 --- a/Anvil/Tools/Get.pm +++ b/Anvil/Tools/Get.pm @@ -101,6 +101,10 @@ This is the password to use when connecting to a remote machine. If not set, but This is the TCP port to use when connecting to a remote machine. If not set, but C<< target >> is, C<< 22 >> will be used. +=head3 remote_user (optional, default root) + +If C<< target >> is set, this will be the user we connect to the remote machine as. + =head3 target (optional) This is the IP or host name of the machine to read the version of. If this is not set, the local system's version is checked. @@ -113,14 +117,16 @@ sub anvil_version my $anvil = $self->parent; my $debug = defined $parameter->{debug} ? $parameter->{debug} : 3; - my $password = $parameter->{password} ? $parameter->{password} : ""; - my $port = $parameter->{port} ? $parameter->{port} : ""; - my $target = $parameter->{target} ? $parameter->{target} : "local"; - my $version = 0; + my $password = defined $parameter->{password} ? $parameter->{password} : ""; + my $port = defined $parameter->{port} ? $parameter->{port} : ""; + my $remote_user = defined $parameter->{remote_user} ? $parameter->{remote_user} : "root"; + my $target = defined $parameter->{target} ? $parameter->{target} : "local"; + my $version = 0; $anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => $debug, list => { - password => $anvil->Log->secure ? $password : "--", - port => $port, - target => $target, + password => $anvil->Log->secure ? $password : "--", + port => $port, + remote_user => $remote_user, + target => $target, }}); # Is this a local call or a remote call? @@ -135,12 +141,14 @@ else echo 0; fi; "; - $anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => $debug, list => { shell_call => $shell_call }}); + $anvil->Log->entry({source => $THIS_FILE, line => __LINE__, level => $debug, key => "log_0166", variables => { shell_call => $shell_call, target => $target, remote_user => $remote_user }}); my ($error, $output) = $anvil->Remote->call({ - shell_call => $shell_call, - target => $target, - port => $port, - password => $password, + debug => $debug, + shell_call => $shell_call, + target => $target, + port => $port, + password => $password, + remote_user => $remote_user, }); $anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => $debug, list => { error => $error }}); diff --git a/Anvil/Tools/Remote.pm b/Anvil/Tools/Remote.pm index edd00b9e..9180fe20 100755 --- a/Anvil/Tools/Remote.pm +++ b/Anvil/Tools/Remote.pm @@ -185,21 +185,21 @@ Example; # Call 'hostname' on a node. my ($error, $output) = $anvil->Remote->call({ - target => "an-a01n01.alteeve.com", - user => "admin", - password => "super secret password", - shell_call => "/usr/bin/hostname", + target => "an-a01n01.alteeve.com", + password => "super secret password", + remote_user => "admin", + shell_call => "/usr/bin/hostname", }); # Make a call with sensitive data that you want logged only if $anvil->Log->secure is set and close the # connection when done. my ($error, $output) = $anvil->Remote->call({ - target => "an-a01n01.alteeve.com", - user => "root", - password => "super secret password", - shell_call => "/usr/sbin/fence_ipmilan -a an-a01n02.ipmi -l admin -p \"super secret password\" -o status", - secure => 1, - 'close' => 1, + target => "an-a01n01.alteeve.com", + password => "super secret password", + remote_user => "root", + shell_call => "/usr/sbin/fence_ipmilan -a an-a01n02.ipmi -l admin -p \"super secret password\" -o status", + secure => 1, + 'close' => 1, }); If there is any problem connecting to the target, C<< $error >> will contain a translated string explaining what went wrong. Checking if this is B<< false >> is a good way to verify that the call succeeded. @@ -234,6 +234,10 @@ This is the TCP port to use when connecting to the C<< target >>. The default is B: See C<< target >> for optional port definition. +=head3 remote_user (optional, default root) + +This is the user account on the C<< target >> to connect as and to run the C<< shell_call >> as. The C<< password >> if so this user's account on the C<< target >>. + =head3 secure (optional, default C<< 0 >>) If set, the C<< shell_call >> is treated as containing sensitive data and will not be logged unless C<< $anvil->Log->secure >> is enabled. @@ -250,10 +254,6 @@ B: If the target matches an entry in '/etc/ssh/ssh_config', the port defin B: If the C<< target >> is presented in the format C<< target:port >>, the port will be separated from the target and used as the TCP port. If the C<< port >> parameter is set, however, the port split off the C<< target >> will be ignored. -=head3 user (optional, default 'root') - -This is the user account on the C<< target >> to connect as and to run the C<< shell_call >> as. The C<< password >> if so this user's account on the C<< target >>. - =cut sub call { @@ -283,23 +283,23 @@ sub call $anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => $log_level, list => { "cache::ssh_fh::${ssh_fh_key}" => $anvil->data->{cache}{ssh_fh}{$ssh_fh_key} }}); # Now pick up the rest of the variables. - my $close = defined $parameter->{'close'} ? $parameter->{'close'} : 0; - my $no_cache = defined $parameter->{no_cache} ? $parameter->{no_cache} : 0; - my $password = defined $parameter->{password} ? $parameter->{password} : $anvil->data->{sys}{root_password}; - my $secure = defined $parameter->{secure} ? $parameter->{secure} : 0; - my $shell_call = defined $parameter->{shell_call} ? $parameter->{shell_call} : ""; - my $user = defined $parameter->{user} ? $parameter->{user} : "root"; - my $start_time = time; - my $ssh_fh = $anvil->data->{cache}{ssh_fh}{$ssh_fh_key}; + my $close = defined $parameter->{'close'} ? $parameter->{'close'} : 0; + my $no_cache = defined $parameter->{no_cache} ? $parameter->{no_cache} : 0; + my $password = defined $parameter->{password} ? $parameter->{password} : $anvil->data->{sys}{root_password}; + my $secure = defined $parameter->{secure} ? $parameter->{secure} : 0; + my $shell_call = defined $parameter->{shell_call} ? $parameter->{shell_call} : ""; + my $remote_user = defined $parameter->{remote_user} ? $parameter->{remote_user} : "root"; + my $start_time = time; + my $ssh_fh = $anvil->data->{cache}{ssh_fh}{$ssh_fh_key}; # NOTE: The shell call might contain sensitive data, so we show '--' if 'secure' is set and $anvil->Log->secure is not. $anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => $log_level, list => { - 'close' => $close, - password => $anvil->Log->secure ? $password : "--", - secure => $secure, - shell_call => ((not $anvil->Log->secure) && ($secure)) ? "--" : $shell_call, - ssh_fh => $ssh_fh, - start_time => $start_time, - user => $user, + 'close' => $close, + password => $anvil->Log->secure ? $password : "--", + secure => $secure, + shell_call => ((not $anvil->Log->secure) && ($secure)) ? "--" : $shell_call, + ssh_fh => $ssh_fh, + start_time => $start_time, + remote_user => $remote_user, }}); if (not $shell_call) @@ -314,9 +314,9 @@ sub call $anvil->Log->entry({source => $THIS_FILE, line => __LINE__, level => 0, priority => "err", key => "log_0020", variables => { method => "Remote->call()", parameter => "target" }}); return("!!error!!"); } - if (not $user) + if (not $remote_user) { - $anvil->Log->entry({source => $THIS_FILE, line => __LINE__, level => 0, priority => "err", key => "log_0020", variables => { method => "Remote->call()", parameter => "user" }}); + $anvil->Log->entry({source => $THIS_FILE, line => __LINE__, level => 0, priority => "err", key => "log_0020", variables => { method => "Remote->call()", parameter => "remote_user" }}); return("!!error!!"); } @@ -424,11 +424,11 @@ sub call #print "[".$connect_time."] - Connection failed time to: [$target:$port]\n"; $anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 1, priority => "alert", list => { - user => $user, - target => $target, - port => $port, - shell_call => $shell_call, - error => $@, + remote_user => $remote_user, + target => $target, + port => $port, + shell_call => $shell_call, + error => $@, }}); # We'll now try to get a more useful message for the user and logs. @@ -442,9 +442,9 @@ sub call { $message_key = "message_0002"; $variables = { - target => $target, - port => $port, - user => $user, + target => $target, + port => $port, + remote_user => $remote_user, }; } elsif ($@ =~ /No route to host/) @@ -466,10 +466,10 @@ sub call if (not $error) { $anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => $log_level, list => { - user => $user, - password => $anvil->Log->secure ? $password : "--", + remote_user => $remote_user, + password => $anvil->Log->secure ? $password : "--", }}); - if (not $ssh_fh->auth_password($user, $password)) + if (not $ssh_fh->auth_password($remote_user, $password)) { # Can we log in without a password? my $user = getpwuid($<); diff --git a/Anvil/Tools/Storage.pm b/Anvil/Tools/Storage.pm index 44716a76..1d7a08b1 100755 --- a/Anvil/Tools/Storage.pm +++ b/Anvil/Tools/Storage.pm @@ -12,7 +12,7 @@ our $VERSION = "3.0.0"; my $THIS_FILE = "Storage.pm"; ### Methods; -# backup_file +# backup # change_mode # change_owner # check_md5sums @@ -96,6 +96,10 @@ This will create a copy of the file under the C<< path::directories::backups >> By default, a failure to backup will be fatal with return code C<< 1 >> for safety reasons. If the file is critical, you can set C<< fatal => 0 >> and an empty string will be returned on error. +This method can work on local and remote systems. + +If the backup failed, an empty string is returned. + Parameters; =head3 fatal (optional, default 1) @@ -106,6 +110,22 @@ If set to C<< 0 >>, any problem with the backup will be ignored and an empty str This is the path and file name of the file to be backed up. Fully paths must be used. +=head3 port (optional, default 22) + +If C<< target >> is set, this is the TCP port number used to connect to the remote machine. + +=head3 password (optional) + +If C<< target >> is set, this is the password used to log into the remote system as the C<< remote_user >>. If it is not set, an attempt to connect without a password will be made (though this will usually fail). + +=head3 target (optional) + +If set, the file will be backed up on the target machine. This must be either an IP address or a resolvable host name. + +=head3 remote_user (optional) + +If C<< target >> is set, this is the user account that will be used when connecting to the remote system. + =cut sub backup { @@ -114,15 +134,23 @@ sub backup my $anvil = $self->parent; my $debug = defined $parameter->{debug} ? $parameter->{debug} : 2; - my $fatal = defined $parameter->{fatal} ? $parameter->{fatal} : 1; - my $source_file = defined $parameter->{file} ? $parameter->{file} : ""; + my $fatal = defined $parameter->{fatal} ? $parameter->{fatal} : 1; + my $port = defined $parameter->{port} ? $parameter->{port} : ""; + my $password = defined $parameter->{password} ? $parameter->{password} : ""; + my $remote_user = defined $parameter->{remote_user} ? $parameter->{remote_user} : ""; + my $target = defined $parameter->{target} ? $parameter->{target} : ""; + my $source_file = defined $parameter->{file} ? $parameter->{file} : ""; $anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => $debug, list => { - source_file => $source_file, fatal => $fatal, + port => $port, + password => $anvil->Log->secure ? $password : "--", + target => $target, + remote_user => $remote_user, + source_file => $source_file, }}); + my $proceed = 0; my $target_file = ""; - if (not $source_file) { # No file passed in @@ -135,25 +163,103 @@ sub backup $anvil->Log->entry({source => $THIS_FILE, line => __LINE__, level => 0, priority => "err", key => "log_0150", variables => { source_file => $source_file }}); if ($fatal) { $anvil->nice_exit({code => 1}); } } - elsif (not -e $source_file) - { - # File doesn't exist. - $anvil->Log->entry({source => $THIS_FILE, line => __LINE__, level => 0, priority => "err", key => "log_0151", variables => { source_file => $source_file }}); - if ($fatal) { $anvil->nice_exit({code => 1}); } - } - elsif (not -f $source_file) + + if ($target) { - # Not a file - $anvil->Log->entry({source => $THIS_FILE, line => __LINE__, level => 0, priority => "err", key => "log_0153", variables => { source_file => $source_file }}); - if ($fatal) { $anvil->nice_exit({code => 1}); } + # Make sure the source file exists, is a file and can be read. + my $shell_call = " +if [ -e '".$source_file."' ]; + if [ -f '".$source_file."' ]; + then + if [ -r '".$source_file."' ]; + then + ".$anvil->data->{path}{exe}{echo}." 'ok' + else + ".$anvil->data->{path}{exe}{echo}." 'not readable' + fi + else + ".$anvil->data->{path}{exe}{echo}." 'not a file' + fi +else + ".$anvil->data->{path}{exe}{echo}." 'not found' +fi"; + $anvil->Log->entry({source => $THIS_FILE, line => __LINE__, level => $debug, key => "log_0166", variables => { shell_call => $shell_call, target => $target, remote_user => $remote_user }}); + my ($error, $output) = $anvil->Remote->call({ + debug => $debug, + target => $target, + user => $remote_user, + password => $password, + remote_user => $remote_user, + shell_call => $shell_call, + }); + if (not $error) + { + # No error. Did the file exist? + $anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => $debug, list => { 'output->[0]' => $output->[0] }}); + if ($output->[0] eq "not found") + { + # File doesn't exist. + $anvil->Log->entry({source => $THIS_FILE, line => __LINE__, level => 0, priority => "err", key => "log_0151", variables => { source_file => $source_file }}); + if ($fatal) { $anvil->nice_exit({code => 1}); } + } + elsif ($output->[0] eq "not a file") + { + # Not a file + $anvil->Log->entry({source => $THIS_FILE, line => __LINE__, level => 0, priority => "err", key => "log_0153", variables => { source_file => $source_file }}); + if ($fatal) { $anvil->nice_exit({code => 1}); } + } + elsif ($output->[0] eq "not readable") + { + # Can't read the file. + $anvil->Log->entry({source => $THIS_FILE, line => __LINE__, level => 0, priority => "err", key => "log_0152", variables => { source_file => $source_file }}); + if ($fatal) { $anvil->nice_exit({code => 1}); } + } + else + { + # We're good. + $proceed = 1; + $anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => $debug, list => { proceed => $proceed }}); + } + } + else + { + # Didn't connect? + $anvil->Log->entry({source => $THIS_FILE, line => __LINE__, level => 0, priority => "err", key => "log_0165", variables => { + target => $target, + source_file => $source_file, + }}); + if ($fatal) { $anvil->nice_exit({code => 1}); } + } } - elsif (not -r $source_file) + else { - # Can't read the file. - $anvil->Log->entry({source => $THIS_FILE, line => __LINE__, level => 0, priority => "err", key => "log_0152", variables => { source_file => $source_file }}); - if ($fatal) { $anvil->nice_exit({code => 1}); } + # Local file + if (not -e $source_file) + { + # File doesn't exist. + $anvil->Log->entry({source => $THIS_FILE, line => __LINE__, level => 0, priority => "err", key => "log_0151", variables => { source_file => $source_file }}); + if ($fatal) { $anvil->nice_exit({code => 1}); } + } + elsif (not -f $source_file) + { + # Not a file + $anvil->Log->entry({source => $THIS_FILE, line => __LINE__, level => 0, priority => "err", key => "log_0153", variables => { source_file => $source_file }}); + if ($fatal) { $anvil->nice_exit({code => 1}); } + } + elsif (not -r $source_file) + { + # Can't read the file. + $anvil->Log->entry({source => $THIS_FILE, line => __LINE__, level => 0, priority => "err", key => "log_0152", variables => { source_file => $source_file }}); + if ($fatal) { $anvil->nice_exit({code => 1}); } + } + else + { + $proceed = 1; + } } - else + + # Proceed? + if ($proceed) { # Proceed with the backup. We'll recreate the path my ($directory, $file) = ($source_file =~ /^(\/.*)\/(.*)$/); @@ -171,14 +277,22 @@ sub backup }}); # Backup! It will create the target directory, if needed. - $anvil->Storage->copy_file({ - source => $source_file, - target => $target_file, - debug => 2, + my $failed = $anvil->Storage->copy_file({ + debug => $debug, + source_file => $source_file, + target_file => $target_file, + password => $password, + target => $target, + remote_user => $remote_user, + source_file => $source_file, }); - # Log that the file was backed up. - $anvil->Log->entry({source => $THIS_FILE, line => __LINE__, level => 1, key => "log_0154", variables => { source_file => $source_file, target_file => $target_file }}); + $anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => $debug, list => { failed => $failed }}); + if (not $failed) + { + # Log that the file was backed up. + $anvil->Log->entry({source => $THIS_FILE, line => __LINE__, level => 1, key => "log_0154", variables => { source_file => $source_file, target_file => $target_file }}); + } } $anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => $debug, list => { target_file => $target_file }}); @@ -433,10 +547,12 @@ sub check_md5sums =head2 copy_file -This copies a file, with a few additional checks like creating the target directory if it doesn't exist, aborting if the file has already been backed up before, etc. +This copies a file, with a few additional checks like creating the target directory if it doesn't exist, aborting if the file has already been backed up before, etc. It can copy files on the local or a remote machine. # Example - $anvil->Storage->copy_file({source => "/some/file", target => "/another/directory/file"}); + $anvil->Storage->copy_file({source_file => "/some/file", target_file => "/another/directory/file"}); + +Returns C<< 0 >> on success, otherwise C<< 1 >>. Parameters; @@ -446,16 +562,32 @@ If this is set to 'C<< 1 >>', and if the target file exists, it will be replaced If this is not passed and the target exists, this module will return 'C<< 3 >>'. -=head3 source (required) +=head3 port (optional, default 22) + +If C<< target >> is set, this is the TCP port number used to connect to the remote machine. + +=head3 password (optional) + +If C<< target >> is set, this is the password used to log into the remote system as the C<< remote_user >>. If it is not set, an attempt to connect without a password will be made (though this will usually fail). + +=head3 source_file (required) This is the source file. If it isn't specified, 'C<< 1 >>' will be returned. If it doesn't exist, this method will return 'C<< 4 >>'. -=head3 target (required) +=head3 target (optional) + +If set, the file will be copied on the target machine. This must be either an IP address or a resolvable host name. -This is the target *B*, not the directory to put it in. The target file name can be different from the source file name. +=head3 target_file (required) + +This is the target B<< file >>, not the directory to put it in. The target file name can be different from the source file name. if this is not specified, 'C<< 2 >>' will be returned. +=head3 remote_user (optional, default root) + +If C<< target >> is set, this is the user account that will be used when connecting to the remote system. + =cut sub copy_file { @@ -464,63 +596,169 @@ sub copy_file my $anvil = $self->parent; my $debug = defined $parameter->{debug} ? $parameter->{debug} : 3; - my $overwrite = defined $parameter->{overwrite} ? $parameter->{overwrite} : 0; - my $source = defined $parameter->{source} ? $parameter->{source} : ""; - my $target = defined $parameter->{target} ? $parameter->{target} : ""; + my $overwrite = defined $parameter->{overwrite} ? $parameter->{overwrite} : 0; + my $password = defined $parameter->{password} ? $parameter->{password} : ""; + my $remote_user = defined $parameter->{remote_user} ? $parameter->{remote_user} : "root"; + my $source_file = defined $parameter->{source_file} ? $parameter->{source_file} : ""; + my $target_file = defined $parameter->{target_file} ? $parameter->{target_file} : ""; + my $target = defined $parameter->{target} ? $parameter->{target} : ""; $anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => $debug, list => { - overwrite => $overwrite, - source => $source, - target => $target, + overwrite => $overwrite, + password => $anvil->Log->secure ? $password : "--", + remote_user => $remote_user, + source_file => $source_file, + target_file => $target_file, + target => $target, }}); - if (not $source) + if (not $source_file) { # No source passed. - $anvil->Log->entry({source => $THIS_FILE, line => __LINE__, level => 0, priority => "err", key => "log_0020", variables => { method => "Storage->copy_file()", parameter => "source" }}); + $anvil->Log->entry({source => $THIS_FILE, line => __LINE__, level => 0, priority => "err", key => "log_0020", variables => { method => "Storage->copy_file()", parameter => "source_file" }}); return(1); } - elsif (not -e $source) - { - $anvil->Log->entry({source => $THIS_FILE, line => __LINE__, level => 0, priority => "err", key => "log_0052", variables => { source => $source }}); - return(4); - } - if (not $target) + if (not $target_file) { # No target passed. - $anvil->Log->entry({source => $THIS_FILE, line => __LINE__, level => 0, priority => "err", key => "log_0020", variables => { method => "Storage->copy_file()", parameter => "target" }}); + $anvil->Log->entry({source => $THIS_FILE, line => __LINE__, level => 0, priority => "err", key => "log_0020", variables => { method => "Storage->copy_file()", parameter => "target_file" }}); return(2); } - # If the target exists, abort - if ((-e $target) && (not $overwrite)) - { - # This isn't an error. - $anvil->Log->entry({source => $THIS_FILE, line => __LINE__, level => 1, key => "log_0046", variables => { - source => $source, - target => $target, - }}); - return(3); - } - - # Make sure the target directory exists and create it, if not. - my ($directory, $file) = ($target =~ /^(.*)\/(.*)$/); + my ($directory, $file) = ($target_file =~ /^(.*)\/(.*)$/); $anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => $debug, list => { directory => $directory, file => $file, }}); - if (not -e $directory) + + if ($target) { - $anvil->Storage->make_directory({ - directory => $directory, - group => $(, # Real UID - user => $<, # Real GID - mode => "0750", + # Copying on a remote system. + my $proceed = 1; + my $shell_call = " +if [ -e '".$source_file."' ]; + ".$anvil->data->{path}{exe}{echo}." 'source file exists' +else + ".$anvil->data->{path}{exe}{echo}." 'source file not found' +fi +if [ -d '".$target_file."' ]; + ".$anvil->data->{path}{exe}{echo}." 'target file exists' +elif [ -d '".$directory."' ]; + ".$anvil->data->{path}{exe}{echo}." 'target directory exists' +else + ".$anvil->data->{path}{exe}{echo}." 'target directory not found' +fi"; + $anvil->Log->entry({source => $THIS_FILE, line => __LINE__, level => $debug, key => "log_0166", variables => { shell_call => $shell_call, target => $target, remote_user => $remote_user }}); + my ($error, $output) = $anvil->Remote->call({ + debug => $debug, + target => $target, + user => $remote_user, + password => $password, + remote_user => $remote_user, + shell_call => $shell_call, }); + if ($error) + { + # Something went wrong. + $anvil->Log->entry({source => $THIS_FILE, line => __LINE__, level => 0, priority => "err", key => "log_0169", variables => { + source_file => $source_file, + target_file => $target_file, + error => $error, + output => $output, + target => $target, + remote_user => $remote_user, + }}); + return(1); + } + else + { + $anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => $debug, list => { + 'output->[0]' => $output->[0], + 'output->[1]' => $output->[1], + }}); + if ($output->[0] eq "source file not found") + { + $anvil->Log->entry({source => $THIS_FILE, line => __LINE__, level => 0, priority => "err", key => "log_0052", variables => { source_file => $source_file }}); + return(1); + } + if (($output->[0] eq "source file exists") && (not $overwrite)) + { + $anvil->Log->entry({source => $THIS_FILE, line => __LINE__, level => 1, key => "log_0046", variables => { + source_file => $source_file, + target_file => $target_file, + }}); + return(1); + } + if ($output->[1] eq "target directory not found") + { + my $failed = $anvil->Storage->make_directory({ + debug => $debug, + directory => $directory, + password => $password, + remote_user => $remote_user, + target => $target, + }); + $anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => $debug, list => { failed => $failed }}); + $anvil->Log->entry({source => $THIS_FILE, line => __LINE__, level => 1, key => "log_0170", variables => { + source_file => $source_file, + target_file => $target_file, + }}); + return(1); + } + + # Now backup the file. + my ($error, $output) = $anvil->Remote->call({ + debug => $debug, + target => $target, + user => $remote_user, + password => $password, + remote_user => $remote_user, + shell_call => $anvil->data->{path}{exe}{'cp'}." -af ".$source_file." ".$target_file, + }); + $anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => $debug, list => { output => $output }}); + } + } + else + { + # Copying locally + if (not -e $source_file) + { + $anvil->Log->entry({source => $THIS_FILE, line => __LINE__, level => 0, priority => "err", key => "log_0052", variables => { source_file => $source_file }}); + return(1); + } + + # If the target exists, abort + if ((-e $target_file) && (not $overwrite)) + { + # This isn't an error. + $anvil->Log->entry({source => $THIS_FILE, line => __LINE__, level => 1, key => "log_0046", variables => { + source_file => $source_file, + target_file => $target_file, + }}); + return(1); + } + + # Make sure the target directory exists and create it, if not. + if (not -e $directory) + { + my $failed = $anvil->Storage->make_directory({ + debug => $debug, + directory => $directory, + }); + $anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => $debug, list => { failed => $failed }}); + if ($failed) + { + $anvil->Log->entry({source => $THIS_FILE, line => __LINE__, level => 1, key => "log_0170", variables => { + source_file => $source_file, + target_file => $target_file, + }}); + return(1); + } + } + + # Now backup the file. + my $output = $anvil->System->call({debug => $debug, shell_call => $anvil->data->{path}{exe}{'cp'}." -af ".$source_file." ".$target_file}); + $anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => $debug, list => { output => $output }}); } - - # Now backup the file. - my $output = $anvil->System->call({shell_call => $anvil->data->{path}{exe}{'cp'}." -af $source $target"}); - $anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => $debug, list => { output => $output }}); return(0); } @@ -603,7 +841,7 @@ This creates a directory (and any parent directories). $anvil->Storage->make_directory({directory => "/foo/bar/baz", owner => "me", grou[ => "me", group => 755}); -If it fails to create the directory, an alert will be logged. +If it fails to create the directory, C<< 1 >> will be returned. Otherwise, C<< 0 >> will be returned. Parameters; @@ -619,6 +857,22 @@ This is the group name or group ID to set the ownership of the directory to. This is the numeric mode to set on the file. It expects four digits to cover the sticky bit, but will work with three digits. +=head3 password (optional) + +If C<< target >> is set, this is the password used to log into the remote system as the C<< remote_user >>. If it is not set, an attempt to connect without a password will be made (though this will usually fail). + +=head3 port (optional, default 22) + +If C<< target >> is set, this is the TCP port number used to connect to the remote machine. + +=head3 target (optional) + +If set, the directory will be created on this machine. This must be an IP address or a (resolvable) host name. + +=head3 remote_user (optional, default root) + +If C<< target >> is set, this is the user account that will be used when connecting to the remote system. + =head3 user (optional) This is the user name or user ID to set the ownership of the directory to. @@ -631,15 +885,24 @@ sub make_directory my $anvil = $self->parent; my $debug = defined $parameter->{debug} ? $parameter->{debug} : 3; - my $directory = defined $parameter->{directory} ? $parameter->{directory} : ""; - my $group = defined $parameter->{group} ? $parameter->{group} : ""; - my $mode = defined $parameter->{mode} ? $parameter->{mode} : ""; - my $user = defined $parameter->{user} ? $parameter->{user} : ""; + my $directory = defined $parameter->{directory} ? $parameter->{directory} : ""; + my $group = defined $parameter->{group} ? $parameter->{group} : ""; + my $mode = defined $parameter->{mode} ? $parameter->{mode} : ""; + my $password = defined $parameter->{password} ? $parameter->{password} : ""; + my $port = defined $parameter->{port} ? $parameter->{port} : 22; + my $remote_user = defined $parameter->{remote_user} ? $parameter->{remote_user} : "root"; + my $target = defined $parameter->{target} ? $parameter->{target} : ""; + my $user = defined $parameter->{user} ? $parameter->{user} : ""; + my $failed = 0; $anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => $debug, list => { - directory => $directory, - group => $group, - mode => $mode, - user => $user, + directory => $directory, + group => $group, + mode => $mode, + port => $port, + password => $anvil->Log->secure ? $password : "--", + remote_user => $remote_user, + target => $target, + user => $user, }}); # Make sure the user and group and just one digit or word. @@ -658,32 +921,109 @@ sub make_directory $working_directory .= "/$this_directory"; $working_directory =~ s/\/\//\//g; $anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => $debug, list => { working_directory => $working_directory }}); - if (not -e $working_directory) + + # Are we working locally or remotely? + if ($target) { - # Directory doesn't exist, so create it. - my $shell_call = $anvil->data->{path}{exe}{'mkdir'}." ".$working_directory; - $anvil->Log->entry({source => $THIS_FILE, line => __LINE__, level => $debug, key => "log_0011", variables => { shell_call => $shell_call }}); - open (my $file_handle, $shell_call." 2>&1 |") or $anvil->Log->entry({source => $THIS_FILE, line => __LINE__, level => 0, priority => "err", key => "log_0014", variables => { shell_call => $shell_call, error => $! }}); - while(<$file_handle>) + # Assemble the command + my $shell_call = " +if [ -d '".$working_directory."' ]; +then + ".$anvil->data->{path}{exe}{echo}." 'exists' +else + ".$anvil->data->{path}{exe}{'mkdir'}." $working_directory +"; + if ($mode) { - chomp; - my $line = $_; - $anvil->Log->entry({source => $THIS_FILE, line => __LINE__, level => $debug, key => "log_0017", variables => { line => $line }}); + $shell_call .= " ".$anvil->data->{path}{exe}{'chmod'}." ".$mode."\n"; } - close $file_handle; - - if ($mode) + if (($user) && ($group)) { - $anvil->Storage->change_mode({target => $working_directory, mode => $mode}); + $shell_call .= " ".$anvil->data->{path}{exe}{'chown'}." ".$user.":".$group."\n"; } - if (($user) or ($group)) + elsif ($user) + { + $shell_call .= " ".$anvil->data->{path}{exe}{'chown'}." ".$user.":\n"; + } + elsif ($group) + { + $shell_call .= " ".$anvil->data->{path}{exe}{'chown'}." :".$group."\n"; + } + $shell_call .= " + if [ -d '".$working_directory."' ]; + then + ".$anvil->data->{path}{exe}{echo}." 'created' + else + ".$anvil->data->{path}{exe}{echo}." 'failed to create' + fi; +fi;"; + $anvil->Log->entry({source => $THIS_FILE, line => __LINE__, level => $debug, key => "log_0166", variables => { shell_call => $shell_call, target => $target, remote_user => $remote_user }}); + my ($error, $output) = $anvil->Remote->call({ + debug => $debug, + target => $target, + user => $remote_user, + password => $password, + remote_user => $remote_user, + shell_call => $shell_call, + }); + $anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => $debug, list => { + error => $error, + output => $output, + }}); + if ($output->[0] eq "failed to create") { - $anvil->Storage->change_owner({target => $working_directory, user => $user, group => $group}); + $failed = 1; + $anvil->Log->entry({source => $THIS_FILE, line => __LINE__, level => 0, priority => "err", key => "log_0167", variables => { + directory => $working_directory, + error => $error, + output => $output, + target => $target, + remote_user => $remote_user, + }}); } } + else + { + # Locally. + if (not -e $working_directory) + { + # Directory doesn't exist, so create it. + my $error = ""; + my $shell_call = $anvil->data->{path}{exe}{'mkdir'}." ".$working_directory; + $anvil->Log->entry({source => $THIS_FILE, line => __LINE__, level => $debug, key => "log_0011", variables => { shell_call => $shell_call }}); + open (my $file_handle, $shell_call." 2>&1 |") or $anvil->Log->entry({source => $THIS_FILE, line => __LINE__, level => 0, priority => "err", key => "log_0014", variables => { shell_call => $shell_call, error => $! }}); + while(<$file_handle>) + { + chomp; + my $line = $_; + $anvil->Log->entry({source => $THIS_FILE, line => __LINE__, level => $debug, key => "log_0017", variables => { line => $line }}); + $error .= $line."\n"; + } + close $file_handle; + + if ($mode) + { + $anvil->Storage->change_mode({target => $working_directory, mode => $mode}); + } + if (($user) or ($group)) + { + $anvil->Storage->change_owner({target => $working_directory, user => $user, group => $group}); + } + + if (not -e $working_directory) + { + $failed = 1; + $anvil->Log->entry({source => $THIS_FILE, line => __LINE__, level => 0, priority => "err", key => "log_0168", variables => { + directory => $working_directory, + error => $error, + }}); + } + } + } + last if $failed; } - return(0); + return($failed); } =head2 read_config @@ -1512,7 +1852,7 @@ The file will be written locally in C<< /tmp/ >>, C<< $anvil->Storage This is the user name or user ID to set the ownership of the file to. -=head3 remote_user (optional) +=head3 remote_user (optional, default root) If C<< target >> is set, this is the user account that will be used when connecting to the remote system. @@ -1534,7 +1874,7 @@ sub write_file my $secure = defined $parameter->{secure} ? $parameter->{secure} : ""; my $target = defined $parameter->{target} ? $parameter->{target} : ""; my $user = defined $parameter->{user} ? $parameter->{user} : "root"; - my $remote_user = defined $parameter->{remote_user} ? $parameter->{remote_user} : ""; + my $remote_user = defined $parameter->{remote_user} ? $parameter->{remote_user} : "root"; $anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => $debug, secure => $secure, list => { body => $body, file => $file, @@ -1599,22 +1939,41 @@ then else ".$anvil->data->{path}{exe}{echo}." 'not found'; fi"; - $anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => $debug, list => { shell_call => $shell_call }}); + $anvil->Log->entry({source => $THIS_FILE, line => __LINE__, level => $debug, key => "log_0166", variables => { shell_call => $shell_call, target => $target, remote_user => $remote_user }}); ($error, my $output) = $anvil->Remote->call({ - target => $target, - user => $remote_user, - password => $password, - shell_call => $shell_call, + debug => $debug, + target => $target, + port => $port, + user => $remote_user, + password => $password, + remote_user => $remote_user, + shell_call => $shell_call, }); if (not $error) { # No error. Did the file exist? $anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => $debug, list => { 'output->[0]' => $output->[0] }}); - if (($output->[0] eq "exists") && (not $overwrite)) + if ($output->[0] eq "exists") { - # Abort, we're not allowed to overwrite. - $anvil->Log->entry({source => $THIS_FILE, line => __LINE__, level => 0, priority => "err", key => "log_0040", variables => { file => $file }}); - $error = 1; + if (not $overwrite) + { + # Abort, we're not allowed to overwrite. + $anvil->Log->entry({source => $THIS_FILE, line => __LINE__, level => 0, priority => "err", key => "log_0040", variables => { file => $file }}); + $error = 1; + } + } + else + { + # Back it up. + my $backup_file = $anvil->Storage->backup({ + file => $file, + debug => $debug, + target => $target, + port => $port, + user => $remote_user, + password => $password, + }); + $anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => $debug, list => { backup_file => $backup_file }}); } # Make sure the directory exists on the remote machine. In this case, we'll use 'mkdir -p' if it isn't. @@ -1627,12 +1986,14 @@ then else ".$anvil->data->{path}{exe}{echo}." 'not found'; fi"; - $anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => $debug, list => { shell_call => $shell_call }}); + $anvil->Log->entry({source => $THIS_FILE, line => __LINE__, level => $debug, key => "log_0166", variables => { shell_call => $shell_call, target => $target, remote_user => $remote_user }}); ($error, my $output) = $anvil->Remote->call({ - target => $target, - user => $remote_user, - password => $password, - shell_call => $shell_call, + debug => $debug, + target => $target, + user => $remote_user, + password => $password, + remote_user => $remote_user, + shell_call => $shell_call, }); $anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => $debug, list => { 'output->[0]' => $output->[0] }}); @@ -1640,12 +2001,14 @@ fi"; { # Create the directory my $shell_call = $anvil->data->{path}{exe}{'mkdir'}." -p ".$directory; - $anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => $debug, list => { shell_call => $shell_call }}); + $anvil->Log->entry({source => $THIS_FILE, line => __LINE__, level => $debug, key => "log_0166", variables => { shell_call => $shell_call, target => $target, remote_user => $remote_user }}); ($error, my $output) = $anvil->Remote->call({ - target => $target, - user => $remote_user, - password => $password, - shell_call => $shell_call, + debug => $debug, + target => $target, + user => $remote_user, + password => $password, + remote_user => $remote_user, + shell_call => $shell_call, }); } @@ -1708,6 +2071,7 @@ fi"; { # Don't pass the mode as the file's mode is likely not executable. $anvil->Storage->make_directory({ + debug => $debug, directory => $directory, group => $group, user => $user, diff --git a/Anvil/Tools/System.pm b/Anvil/Tools/System.pm index 09871c4e..4e409ab9 100755 --- a/Anvil/Tools/System.pm +++ b/Anvil/Tools/System.pm @@ -208,6 +208,10 @@ If you are changing the password of a user on a remote machine, this is the pass This is the TCP port number to use if connecting to a remote machine over SSH. Ignored if C<< target >> is not given. +=head3 remote_user (optional, default root) + +If C<< target >> is set and we're changing the password for a remote user, this is the user we B<< log into >> the remote machine as, B<< not >> the user whose password we will change. + =head3 target (optional) This is the IP address or (resolvable) host name of the target machine whose user account you want to change the password @@ -224,16 +228,18 @@ sub change_shell_user_password my $anvil = $self->parent; my $debug = defined $parameter->{debug} ? $parameter->{debug} : 3; - my $new_password = $parameter->{new_password} ? $parameter->{new_password} : ""; - my $password = $parameter->{password} ? $parameter->{password} : ""; - my $port = $parameter->{port} ? $parameter->{port} : ""; - my $target = $parameter->{target} ? $parameter->{target} : ""; - my $user = $parameter->{user} ? $parameter->{user} : ""; + my $new_password = defined $parameter->{new_password} ? $parameter->{new_password} : ""; + my $password = defined $parameter->{password} ? $parameter->{password} : ""; + my $port = defined $parameter->{port} ? $parameter->{port} : ""; + my $remote_user = defined $parameter->{remote_user} ? $parameter->{remote_user} : "root"; + my $target = defined $parameter->{target} ? $parameter->{target} : ""; + my $user = defined $parameter->{user} ? $parameter->{user} : ""; my $return_code = 255; $anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => $debug, secure => 0, list => { user => $user, target => $target, port => $port, + remote_user => $remote_user, new_password => $anvil->Log->secure ? $new_password : "--", password => $anvil->Log->secure ? $password : "--", }}); @@ -277,12 +283,14 @@ sub change_shell_user_password if ($target) { # Remote call. + $anvil->Log->entry({source => $THIS_FILE, line => __LINE__, level => $debug, key => "log_0166", variables => { shell_call => $shell_call, target => $target, remote_user => $remote_user }}); $output = $anvil->Remote->call({ - debug => $debug, - shell_call => $shell_call, - target => $target, - port => $port, - password => $password, + debug => $debug, + shell_call => $shell_call, + target => $target, + port => $port, + password => $password, + remote_user => $remote_user, }); $anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => $debug, list => { output => $output }}); } @@ -1169,6 +1177,10 @@ This is the port used to access a remote machine. This is used when pinging from B: See C<< Remote->call >> for additional information on specifying the SSH port as part of the target. +=head3 remote_user (optional, default root) + +If C<< target >> is set, this is the user we will use to log into the remote machine to run the actual ping. + =head3 target (optional) This is the host name or IP address of a remote machine that you want to run the ping on. This is used to test a remote machine's access to a given ping target. @@ -1192,22 +1204,24 @@ sub ping # print "[".$ping_time."] - Pinged: [$host]\n"; # If we were passed a target, try pinging from it instead of locally - my $count = $parameter->{count} ? $parameter->{count} : 1; # How many times to try to ping it? Will exit as soon as one succeeds - my $fragment = $parameter->{fragment} ? $parameter->{fragment} : 1; # Allow fragmented packets? Set to '0' to check MTU. - my $password = $parameter->{password} ? $parameter->{password} : ""; - my $payload = $parameter->{payload} ? $parameter->{payload} : 0; # The size of the ping payload. Use when checking MTU. - my $ping = $parameter->{ping} ? $parameter->{ping} : ""; - my $port = $parameter->{port} ? $parameter->{port} : ""; - my $target = $parameter->{target} ? $parameter->{target} : ""; - my $timeout = $parameter->{timeout} ? $parameter->{timeout} : 1; # This sets the 'timeout' delay. + my $count = defined $parameter->{count} ? $parameter->{count} : 1; # How many times to try to ping it? Will exit as soon as one succeeds + my $fragment = defined $parameter->{fragment} ? $parameter->{fragment} : 1; # Allow fragmented packets? Set to '0' to check MTU. + my $password = defined $parameter->{password} ? $parameter->{password} : ""; + my $payload = defined $parameter->{payload} ? $parameter->{payload} : 0; # The size of the ping payload. Use when checking MTU. + my $ping = defined $parameter->{ping} ? $parameter->{ping} : ""; + my $port = defined $parameter->{port} ? $parameter->{port} : ""; + my $remote_user = defined $parameter->{remote_user} ? $parameter->{remote_user} : "root"; + my $target = defined $parameter->{target} ? $parameter->{target} : ""; + my $timeout = defined $parameter->{timeout} ? $parameter->{timeout} : 1; # This sets the 'timeout' delay. $anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => $debug, list => { - count => $count, - fragment => $fragment, - payload => $payload, - password => $anvil->Log->secure ? $password : "--", - ping => $ping, - port => $port, - target => $target, + count => $count, + fragment => $fragment, + payload => $payload, + password => $anvil->Log->secure ? $password : "--", + ping => $ping, + port => $port, + remote_user => $remote_user, + target => $target, }}); # Was timeout specified as a simple integer? @@ -1259,11 +1273,14 @@ sub ping if (($target) && ($target ne "local") && ($target ne $anvil->_hostname) && ($target ne $anvil->_short_hostname)) { ### Remote calls + $anvil->Log->entry({source => $THIS_FILE, line => __LINE__, level => $debug, key => "log_0166", variables => { shell_call => $shell_call, target => $target, remote_user => $remote_user }}); $output = $anvil->Remote->call({ - shell_call => $shell_call, - target => $target, - port => $port, - password => $password, + debug => $debug, + shell_call => $shell_call, + target => $target, + port => $port, + password => $password, + remote_user => $remote_user, }); $anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => $debug, list => { output => $output }}); } diff --git a/anvil.conf b/anvil.conf index 5f5bc78a..8d6e7072 100644 --- a/anvil.conf +++ b/anvil.conf @@ -1,10 +1,11 @@ ### This is the main Anvil! configuration file. -# + +### Database # Database connections; # # Each Anvil! database is defined below using an incrementing counter as the second variable. The value of -# the second variable is not important, so long as it is unique. Generally, it's a simple incrementing -# intger. +# the second variable is the local 'host_uuid' (via: dmidecode --string system-uuid | perl -ne 'print lc'). +# This ensures that entries can be moved and copied without causing conflicts. # # There are six variables for each database definition; # host = This is the (resolvable) host name or IP address of the peer database. @@ -24,16 +25,51 @@ # 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::eec27c2f-2308-4b4f-bd81-24118b53f8a3::host = localhost +#database::eec27c2f-2308-4b4f-bd81-24118b53f8a3::port = 5432 +#database::eec27c2f-2308-4b4f-bd81-24118b53f8a3::password = Initial1 +#database::eec27c2f-2308-4b4f-bd81-24118b53f8a3::ping = 1 + +# Below are the databases configured for use by this system. Please be careful manually editing them. They +# are updated by Striker and changes can be overwritten. Please do not alter or remove the 'start db list' +# and 'end db list' comments below. +### start db list ### +### end db list ### + +# 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). +# +# When the number exceeds the trigger, the number of records that are archived is approximately (number of +# records above trigger + 'count'). This is not an exact number because a representative timestamp will be +# selected from the hostory schema at this count, and then any record equal to or older than the time stamp +# is removed. +# +# 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'. +#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 particularly large, the 'division' value is used to break up the +# archive job into "chunks". Generally speaking, the division should be greater than the count, and never be +# needed. However, if the archive process takes too long, or if the archive was triggered well above the +# trigger value, the division can help prevent using too much memory at once. If division is set to '0', +# archive jobs will never be divided. +# +# The archives are all stored in the specified directory using the name format +# '...bz2' and the archives are synced between dashboards for safe keeping. Archive +# files are never removed automatically. +# +# To disable auto-archiving entirely, set 'trigger' to '0'. +# +# 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 +sys::database::archive::directory = /usr/local/anvil/archives/ +sys::database::archive::division = 60000 +sys::database::archive::trigger = 100000 -database::1::host = 192.168.122.201 -database::1::port = 5432 -database::1::password = Initial1 -database::1::ping = 1 - -database::2::host = 192.168.122.202 -database::2::port = 5432 -database::2::password = Initial1 -database::2::ping = 1 # This is the schema for the Anvil! database. sys::database::schema = /usr/sbin/anvil/anvil.sql @@ -93,44 +129,3 @@ sys::database::schema = /usr/sbin/anvil/anvil.sql #defaults::template::html = alteeve -### Database - -# 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). -# -# When the number exceeds the trigger, the number of records that are archived -# is approximately (number of records above trigger + 'count'). This is not an -# exact number because a representative timestamp will be selected from the -# hostory schema at this count, and then any record equal to or older than the -# time stamp is removed. -# -# 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'. -#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 -# particularly large, the 'division' value is used to break up the archive job -# into "chunks". Generally speaking, the division should be greater than the -# count, and never be needed. However, if the archive process takes too long, -# or if the archive was triggered well above the trigger value, the division -# can help prevent using too much memory at once. If division is set to '0', -# archive jobs will never be divided. -# -# The archives are all stored in the specified -# directory using the name format '.
..bz2' and the -# archives are synced between dashboards for safe keeping. Archive files are -# never removed automatically. -# -# To disable auto-archiving entirely, set 'trigger' to '0'. -# -# 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 -sys::database::archive::directory = /usr/local/anvil/archives/ -sys::database::archive::division = 60000 -sys::database::archive::trigger = 100000 diff --git a/rpm/SPECS/anvil.spec b/rpm/SPECS/anvil.spec index 194f4b93..111b36c8 100644 --- a/rpm/SPECS/anvil.spec +++ b/rpm/SPECS/anvil.spec @@ -165,6 +165,9 @@ restorecon -rv %{buildroot}/%{_localstatedir}/www %post striker systemctl enable httpd.service systemctl start httpd.service +# Open access for Striker. The database will be opened after initial setup. +firewall-cmd --zone=public --add-service=http +firewall-cmd --zone=public --add-service=http --permanent %files core %doc README.md notes diff --git a/share/words.xml b/share/words.xml index f44a2867..7a08f877 100644 --- a/share/words.xml +++ b/share/words.xml @@ -98,16 +98,16 @@ It also has replacement variables: [#!variable!first!#] and [#!variable!second!# call() was called but 'shell_call' was not passed or was empty.]]> The host: [#!variable!host!#] has renewed its database lock. The host: [#!variable!host!#] is requesting a database lock. - copy_file() was asked to copy: [#!variable!source!#] to: [#!variable!target!#], but the target already exists and 'overwrite' wasn't specified, skipping.]]> + copy_file() was asked to copy: [#!variable!source_file!#] to: [#!variable!target_file!#], but the target already exists and 'overwrite' wasn't specified, skipping.]]> level() was passed an invalid log level: [#!variable!set!#]. Only '0', '1', '2', '3' or '4' are valid.]]> [ Error ] - There is a local database defined, but it does not appear to exist and we could not initialize the database server. Is 'postgresql-server' installed? change_owner() was asked to change the ownership of: [#!variable!target!#] which doesn't exist.]]> - copy_file() was called but the source file: [#!variable!source!#] doesn't exist.]]> + copy_file() was called but the source file: [#!variable!source_file!#] doesn't exist.]]> connect()' method tried to connect to the same database twice: [#!variable!target!#].]]> -Connecting to Database with configuration ID: [#!variable!id!#] +Connecting to Database with configuration ID: [#!variable!uuid!#] - driver: . [#!variable!driver!#] - host: ... [#!variable!host!#] - port: ... [#!variable!port!#] @@ -120,11 +120,11 @@ Connecting to Database with configuration ID: [#!variable!id!#] Updated: [#!variable!file!#] to require passwords for access. call() was called but the port: [#!variable!port!#] is invalid. It must be a digit between '1' and '65535'.]]> Started the PostgreSQL database server. - Database user: [#!variable!user!#] already exists with ID: [#!variable!id!#]. + Database user: [#!variable!user!#] already exists with ID: [#!variable!uuid!#]. users_home() was asked to find the home directory for the user: [#!variable!user!#], but was unable to do so.]]> SSH session opened without a password to: [#!variable!target!#]. - The database: [#!variable!host!# -> #!variable!name!#] with the ID: [#!variable!id!#] did not respond to pings and 'database::#!variable!id!#::ping' is not set to '0' in '#!data!path::configs::anvil.conf!#', skipping it. - [ Warning ] - The database: [#!variable!name!#] on host: [#!variable!host!#] with ID: [#!variable!id!#] can not be used, skipping it. + The database: [#!variable!host!# -> #!variable!name!#] with the ID: [#!variable!uuid!#] did not respond to pings and 'database::#!variable!uuid!#::ping' is not set to '0' in '#!data!path::configs::anvil.conf!#', skipping it. + [ Warning ] - The database: [#!variable!name!#] on host: [#!variable!host!#] with ID: [#!variable!uuid!#] can not be used, skipping it. The database connection error was: ---------- @@ -132,41 +132,41 @@ The database connection error was: ---------- Is the database server running on: [#!variable!target!#] and does the target's firewall allow connections on TCP port: [#!variable!port!#]? - ] in: [#!data!path::configs::anvil.conf!#].]]> + ] in: [#!data!path::configs::anvil.conf!#].]]> + database::#!variable!uuid!#::user = * If the user name is correct, please update: - database::#!variable!id!#::password = + database::#!variable!uuid!#::password = ]]> The connection to the database: [#!variable!name!#] on host: [#!variable!host!#:#!variable!port!#] was refused. Is the database server running? The connection to the database: [#!variable!name!#] on host: [#!variable!host!#:#!variable!port!#] failed because the name could not be translated to an IP address. Is this database server's host name in '/etc/hosts'? - Successfully Connected to the database: [#!variable!name!#] (id: [#!variable!id!#]) on host: [#!variable!host!#:#!variable!port!#]. - query() was called without a database ID to query and 'sys::read_db_id' doesn't contain a database ID, either. Are any databases available?]]> - query() was asked to query the database with ID: [#!variable!id!#] but there is no file handle open to the database. Was the connection lost?]]> - About to run: [#!variable!id!#]:[#!variable!query!#] + Successfully Connected to the database: [#!variable!name!#] (id: [#!variable!uuid!#]) on host: [#!variable!host!#:#!variable!port!#]. + query() was called without a database ID to query and 'sys::read_db_uuid' doesn't contain a database ID, either. Are any databases available?]]> + query() was asked to query the database with ID: [#!variable!uuid!#] but there is no file handle open to the database. Was the connection lost?]]> + About to run: [#!variable!uuid!#]:[#!variable!query!#] Log->secure' is not set.]]> Log->secure' is not set.]]> - initialize() was called without a database ID to query and 'sys::read_db_id' doesn't contain a database ID, either. Are any databases available?]]> - initialize() was asked to query the database with ID: [#!variable!id!#] but there is no file handle open to the database. Was the connection lost?]]> - initialize() was asked to initialize the database: [#!variable!server!#] (id: [#!variable!id!#]) but a core SQL file to load wasn't passed, and the 'database::#!variable!id!#::core_sql' variable isn't set. Unable to initialize without the core SQL file.]]> - initialize() was asked to initialize the database: [#!variable!server!#] (id: [#!variable!id!#]) but the core SQL file: [#!variable!sql_file!#] doesn't exist.]]> - initialize() was asked to initialize the database: [#!variable!server!#] (id: [#!variable!id!#]) but the core SQL file: [#!variable!sql_file!#] exist, but can't be read.]]> + initialize() was called without a database ID to query and 'sys::read_db_uuid' doesn't contain a database ID, either. Are any databases available?]]> + initialize() was asked to query the database with ID: [#!variable!uuid!#] but there is no file handle open to the database. Was the connection lost?]]> + initialize() was asked to initialize the database: [#!variable!server!#] (id: [#!variable!uuid!#]) but a core SQL file to load wasn't passed, and the 'database::#!variable!uuid!#::core_sql' variable isn't set. Unable to initialize without the core SQL file.]]> + initialize() was asked to initialize the database: [#!variable!server!#] (id: [#!variable!uuid!#]) but the core SQL file: [#!variable!sql_file!#] doesn't exist.]]> + initialize() was asked to initialize the database: [#!variable!server!#] (id: [#!variable!uuid!#]) but the core SQL file: [#!variable!sql_file!#] exist, but can't be read.]]> The database: [#!variable!server!#] needs to be initialized using: [#!variable!sql_file!#]. - About to record: [#!variable!id!#]:[#!variable!query!#] + About to record: [#!variable!uuid!#]:[#!variable!query!#] query() was asked to query the database: [#!variable!server!#] but no query was given.]]> write() was asked to write to the database: [#!variable!server!#] but no query was given.]]> check_memory() was called without a program name to check.]]> Testing access to the the database: [#!variable!server!#] prior to query or write. Program will exit if it fails. Access confirmed. - write() was asked to write to the database with ID: [#!variable!id!#] but there is no file handle open to the database. Was the connection lost?]]> + write() was asked to write to the database with ID: [#!variable!uuid!#] but there is no file handle open to the database. Was the connection lost?]]> Log->secure' is not set.]]> Failed to connect to any database. - + check_alert_sent() was called but the 'modified_date' parameter was not passed and/or 'sys::db_timestamp' is not set. Did the program fail to connect to any databases?]]> [ Error ] - Failed to start the Postgres server. Please check the system logs for details. - The database user: [#!variable!user!#] was created with ID: [#!variable!id!#]. + The database user: [#!variable!user!#] was created with ID: [#!variable!uuid!#]. [ Error ] - Failed to add the database user: [#!variable!user!#]! Unable to proceed. check_alert_sent() was called but the 'set' parameter was not passed or it is empty. It should be 'set' or 'clear'.]]> @@ -178,14 +178,14 @@ The database connection error was: - Name: ......... [#!variable!name!#] - Timestamp: .... [#!variable!modified_date!#] - [ Error ] - There is no Anvil! database user set for the local machine. Please check: [#!data!path::config::anvil.conf!#]'s DB entry: [#!variable!id!#]. + [ Error ] - There is no Anvil! database user set for the local machine. Please check: [#!data!path::config::anvil.conf!#]'s DB entry: [#!variable!uuid!#]. Database user: [#!variable!user!#] password has been set/updated. register_alert() was called but the 'title_key' parameter was not passed or it is empty and 'header' is enable (default).]]> I am not recording the alert with message_key: [#!variable!message_key!#] to the database because its log level was lower than any recipients. 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. - The database with ID: [#!variable!id!#] for: [#!variable!file!#] is behind. + The database with ID: [#!variable!uuid!#] for: [#!variable!file!#] is behind. Anvil! database: [#!variable!database!#] already exists. - The database with ID: [#!variable!id!#] is behind. A database esync will be requested. + The database with ID: [#!variable!uuid!#] is behind. A database esync will be requested. [ Warning ] - Failed to delete the temporary postgres password. 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'.]]> [ Error ] - Failed to create the Anvil! database: [#!variable!database!#] @@ -244,6 +244,12 @@ The database connection error was: read_file() tried to rsync the remote file: [#!variable!remote_file!#] to the local temporary file: [#!variable!local_file!#], but it did not arrive. There might be more information above.]]> The file: [#!variable!file!#] does not exist. read_config()' was called without a file name to read.]]> + The Storage->backup() method was asked to backup the file: [#!variable!source_file!#] on: [#!variable!target!#], but it looks like there was a problem connecting to the target. + About to run the shell command: [#!variable!shell_call!#] on: [#!variable!target!#] as: [#!variable!remote_user!#] + Failed to create the directory: [#!variable!directory!#] on: [#!variable!target!#] as: [#!variable!remote_user!#]. The error (if any) was: [#!variable!error!#] and the output (if any) was: [#!variable!output!#]. + Failed to create the directory: [#!variable!directory!#]. The error (if any) was: [#!variable!error!#]. + Failed to copy the file: [#!variable!source_file!#] to: [#!variable!target_file!#] on the target: [#!variable!target!#] as: [#!variable!remote_user!#]. The error (if any) was: [#!variable!error!#] and the output (if any) was: [#!variable!output!#]. + copy_file() was asked to copy: [#!variable!source_file!#] to: [#!variable!target_file!#], but the target's parent directory doesn't exist and we were unable to create it.]]> Test diff --git a/tools/anvil-prep-database b/tools/anvil-prep-database index 7a28861f..1f2f0bb4 100755 --- a/tools/anvil-prep-database +++ b/tools/anvil-prep-database @@ -36,9 +36,19 @@ $anvil->Get->switches; # Paths $anvil->Storage->read_config({file => $anvil->data->{path}{configs}{'anvil.conf'}}); -my $local_id = $anvil->Database->get_local_id; -$anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 3, list => { local_id => $local_id }}); -if ($local_id) +my $local_uuid = $anvil->Database->get_local_uuid; +$anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { local_uuid => $local_uuid }}); + +# If we didn't get the $local_uuid, then there is no entry for this system in anvil.conf yet, so we'll add it. +if (not $local_uuid) +{ + $local_uuid = add_to_local_config($anvil); + $anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { local_uuid => $local_uuid }}); +} +exit; + +# Now configure! +if ($local_uuid) { # Start checks my $running = $anvil->System->check_daemon({daemon => "postgresql"}); @@ -87,7 +97,10 @@ if ($local_id) # Setup postgresql.conf my $postgresql_backup = $anvil->data->{path}{directories}{backups}."/pgsql/postgresql.conf"; $anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { postgresql_backup => $postgresql_backup }}); - $anvil->Storage->copy_file({source => $anvil->data->{path}{configs}{'postgresql.conf'}, target => $postgresql_backup}); + $anvil->Storage->copy_file({ + source_file => $anvil->data->{path}{configs}{'postgresql.conf'}, + target_file => $postgresql_backup, + }); my $postgresql_conf = $anvil->Storage->read_file({file => $anvil->data->{path}{configs}{'postgresql.conf'}}); my $update_file = 1; @@ -126,7 +139,10 @@ if ($local_id) my $pg_hba_backup = $anvil->data->{path}{directories}{backups}."/pgsql/pg_hba.conf"; $anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { pg_hba_backup => $pg_hba_backup }}); - $anvil->Storage->copy_file({source => $anvil->data->{path}{configs}{'pg_hba.conf'}, target => $pg_hba_backup}); + $anvil->Storage->copy_file({ + source_file => $anvil->data->{path}{configs}{'pg_hba.conf'}, + target_file => $pg_hba_backup, + }); my $pg_hba_conf = $anvil->Storage->read_file({file => $anvil->data->{path}{configs}{'pg_hba.conf'}}); $update_file = 1; my $new_pg_hba_conf = ""; @@ -190,11 +206,11 @@ if ($local_id) my $created_pgpass = 0; $anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 3, secure => 1, list => { 'path::secure::postgres_pgpass' => $anvil->data->{path}{secure}{postgres_pgpass}, - "database::${local_id}::password" => $anvil->data->{database}{$local_id}{password}, + "database::${local_uuid}::password" => $anvil->data->{database}{$local_uuid}{password}, }}); - if ((not -e $anvil->data->{path}{secure}{postgres_pgpass}) && ($anvil->data->{database}{$local_id}{password})) + if ((not -e $anvil->data->{path}{secure}{postgres_pgpass}) && ($anvil->data->{database}{$local_uuid}{password})) { - my $body = "*:*:*:postgres:".$anvil->data->{database}{$local_id}{password}."\n"; + my $body = "*:*:*:postgres:".$anvil->data->{database}{$local_uuid}{password}."\n"; $anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 3, secure => 1, list => { body => $body }}); $anvil->Storage->write_file({ file => $anvil->data->{path}{secure}{postgres_pgpass}, @@ -214,12 +230,12 @@ if ($local_id) # Does the database user exist? my $create_user = 1; - my $database_user = $anvil->data->{database}{$local_id}{user} ? $anvil->data->{database}{$id}{user} : $anvil->data->{sys}{database}{user}; + my $database_user = $anvil->data->{database}{$local_uuid}{user} ? $anvil->data->{database}{$local_uuid}{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 }}); + $anvil->Log->entry({source => $THIS_FILE, line => __LINE__, level => 0, priority => "err", key => "log_0099", variables => { uuid => $local_uuid }}); exit(3); } 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__}); @@ -261,11 +277,11 @@ if ($local_id) } # Update/set the passwords. - if ($anvil->data->{database}{$local_id}{password}) + if ($anvil->data->{database}{$local_uuid}{password}) { 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__}); + 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_uuid}{password}."';\\\"\"", source => $THIS_FILE, line => __LINE__}); $anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 3, secure => 1, list => { update_output => $update_output }}); foreach my $line (split/\n/, $user_list) { @@ -281,7 +297,7 @@ if ($local_id) # Create the database, if needed. my $create_database = 1; - my $database_name = $anvil->data->{database}{$local_id}{name} ? $anvil->data->{database}{$local_id}{name} : $anvil->data->{sys}{database}{name}; + my $database_name = $anvil->data->{database}{$local_uuid}{name} ? $anvil->data->{database}{$local_uuid}{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__}); @@ -394,3 +410,74 @@ exit(0); ############################################################################################################# # Functions # ############################################################################################################# + +# This adds this machine to the local anvil.conf file. +sub add_to_local_config +{ + my ($anvil) = @_; + + my $host_uuid = $anvil->Get->host_uuid(); + my $local_uuid = ""; + my $anvil_conf_body = $anvil->Storage->read_file({file => $anvil->data->{path}{configs}{'anvil.conf'}}); + $anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 3, list => { + host_uuid => $host_uuid, + anvil_conf_body => $anvil_conf_body, + }}); + + # Setup the data we'll insert. The password will be changed after the user does the initial config. + my $insert = "database::".$host_uuid."::host = localhost\n"; + $insert .= "database::".$host_uuid."::port = 5432\n"; + $insert .= "database::".$host_uuid."::password = Initial1\n"; + $insert .= "database::".$host_uuid."::ping = 0\n\n"; + $anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { insert => $insert }}); + + # Now inject the config. + my $new_body = ""; + my $config_seen = 0; + my $test_line = "database::${host_uuid}::"; + foreach my $line (split/\n/, $anvil_conf_body) + { + $anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { line => $line }}); + if ($line =~ /^$test_line/) + { + # It's already configured, abort. + $config_seen = 1; + $local_uuid = $host_uuid; + $anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { + config_seen => $config_seen, + local_uuid => $local_uuid, + }}); + } + if ($line eq "### end db list ###") + { + $new_body .= $insert; + $anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { new_body => $new_body }}); + } + $new_body .= $line."\n"; + } + + # If we're here, we're ready to write it out. + if (not $config_seen) + { + # Backup the original + my $backup_file = $anvil->Storage->backup({file => $anvil->data->{path}{configs}{'anvil.conf'}}); + $anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { backup_file => $backup_file }}); + + # Now update! + $anvil->Storage->write_file({ + file => $anvil->data->{path}{configs}{'anvil.conf'}, + body => $new_body, + user => "admin", + group => "admin", + mode => "0644", + overwrite => 1, + }); + + # Record the local UUID for returning to the caller. + $local_uuid = $host_uuid; + $anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { local_uuid => $local_uuid }}); + } + + return($local_uuid); +} +