From 0979402ecf9a9485206d1072a058ae54dd77130d Mon Sep 17 00:00:00 2001 From: Digimer Date: Thu, 7 Feb 2019 03:26:12 -0500 Subject: [PATCH] * Improved handling of failed connection attempts to remote machines in Remote->call(); * Started work of "Files" (replacement for the media library), including database tables, planned sync flow and web UI. * Added a check for the /mnt/shared directories and create them as needed in the periodic anvil-daemon checks. Signed-off-by: Digimer --- Anvil/Tools.pm | 6 +++++ Anvil/Tools/Database.pm | 4 ++- Anvil/Tools/Remote.pm | 33 ++++++++++++++++++++++-- cgi-bin/striker | 29 +++++++++++++++++++++ html/skins/alteeve/files.html | 24 ++++++++++++++++++ share/words.xml | 5 +++- tools/anvil-daemon | 47 +++++++++++++++++++++++++++++++---- tools/striker-configure-host | 24 ++++++++++-------- 8 files changed, 153 insertions(+), 19 deletions(-) create mode 100644 html/skins/alteeve/files.html diff --git a/Anvil/Tools.pm b/Anvil/Tools.pm index 730a9531..13509c7f 100644 --- a/Anvil/Tools.pm +++ b/Anvil/Tools.pm @@ -955,6 +955,12 @@ sub _set_paths html => "/var/www/html", ifcfg => "/etc/sysconfig/network-scripts", scan_agents => "/usr/sbin/scancore-agents", + shared => { + archives => "/mnt/shared/archives", + definitions => "/mnt/shared/definitions", + files => "/mnt/shared/files", + incoming => "/mnt/shared/incoming", + }, skins => "/var/www/html/skins", syslinux => "/usr/share/syslinux", tftpboot => "/var/lib/tftpboot", diff --git a/Anvil/Tools/Database.pm b/Anvil/Tools/Database.pm index 9eb632e4..2e3290fc 100644 --- a/Anvil/Tools/Database.pm +++ b/Anvil/Tools/Database.pm @@ -851,7 +851,9 @@ sub connect remote_version => $remote_version, local_version => $local_version, }}); - if ($remote_version ne $local_version) + # TODO: Periodically, we fail to get the remote version. For now, we proceed if + # everything else is OK. Might be better to pause a re-try... To be determined. + if (($remote_version) && ($remote_version ne $local_version)) { # Version doesn't match, $anvil->Log->entry({source => $THIS_FILE, line => __LINE__, level => 0, priority => "err", key => "log_0145", variables => { diff --git a/Anvil/Tools/Remote.pm b/Anvil/Tools/Remote.pm index 33188465..74c4f587 100644 --- a/Anvil/Tools/Remote.pm +++ b/Anvil/Tools/Remote.pm @@ -417,7 +417,33 @@ sub call target => $target, port => $port, }}); - if (not $ssh_fh->connect($target, $port)) + # Try ten times. 9 in the loop, last try after. + my $connected = 0; + for (1..9) + { + if ($ssh_fh->connect($target, $port)) + { + $connected = 1; + last; + } + else + { + # Sleep and try once more. + $ssh_fh->disconnect(); + $anvil->Log->entry({source => $THIS_FILE, line => __LINE__, level => 1, priority => "alert", key => "log_0101", variables => { + target => $target, + port => $port, + }}); + sleep 1; + $ssh_fh = Net::SSH2->new(timeout => 1000); + $anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 1, list => { + ssh_fh => $ssh_fh, + target => $target, + port => $port, + }}); + } + } + if ((not $connected) && (not $ssh_fh->connect($target, $port))) { # my $connect_time = tv_interval ($start_time, [gettimeofday]); #print "[".$connect_time."] - Connection failed time to: [$target:$port]\n"; @@ -432,7 +458,10 @@ sub call # We'll now try to get a more useful message for the user and logs. my $message_key = "message_0005"; - my $variables = { target => $target }; + my $variables = { + target => $target, + error => $@, + }; if ($@ =~ /Bad hostname/i) { $message_key = "message_0001"; diff --git a/cgi-bin/striker b/cgi-bin/striker index 0b35c765..3b4cea5b 100755 --- a/cgi-bin/striker +++ b/cgi-bin/striker @@ -250,6 +250,10 @@ sub process_task { process_anvil_menu($anvil); } + elsif ($anvil->data->{cgi}{files}{value}) + { + process_file_menu($anvil); + } elsif ($anvil->data->{cgi}{jobs}{value}) { process_jobs_menu($anvil); @@ -387,6 +391,31 @@ sub process_jobs_menu return(0); } +# This handles files. +sub process_file_menu +{ + my ($anvil) = @_; + + $anvil->data->{form}{refresh_link} = "striker?anvil=true"; + $anvil->data->{form}{back_link} = "?striker=true"; + $anvil->data->{cgi}{task}{value} = "" if not defined $anvil->data->{cgi}{task}{value}; + $anvil->data->{cgi}{action}{value} = "" if not defined $anvil->data->{cgi}{action}{value}; + + if ($anvil->data->{cgi}{task}{value} eq "upload") + { + #process_upload_page($anvil); + } + else + { + # The 'back' goes home + $anvil->data->{form}{back_link} = "?"; + $anvil->data->{form}{body} = $anvil->Template->get({file => "files.html", name => "main-menu", variables => { + }}); + } + + return(0); +} + # This handles the "Anvil" menu items. sub process_anvil_menu { diff --git a/html/skins/alteeve/files.html b/html/skins/alteeve/files.html new file mode 100644 index 00000000..849a02af --- /dev/null +++ b/html/skins/alteeve/files.html @@ -0,0 +1,24 @@ + + + + + + + + + + + + + + +
+   +
+ #!string!striker_0119!# +
+   +
+ Upload file. +
+ diff --git a/share/words.xml b/share/words.xml index 2b73c06d..48caed25 100644 --- a/share/words.xml +++ b/share/words.xml @@ -381,7 +381,7 @@ The database connection error was: [ 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. - #!free!# + Failed to connect to: [#!variable!target!#:#!variable!port!#], sleeping for a second and then trying again. 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 UUID: [#!variable!uuid!#] for: [#!variable!file!#] is behind. @@ -542,6 +542,8 @@ The md5sum of: [#!variable!file!#] has changed since the daemon started. Reading the scan agent: [#!variable!agent_name!#]'s words file: [#!variable!file!#]. Running the scan agent: [#!variable!agent_name!#] with a timeout of: [#!variable!timeout!#] seconds now... The database user is not 'admin'. Changing table and function ownerships to: [#!variable!database_user!#]. + [ Warning ] - The Storage->make_directory() method failed to create the directory: [#!variable!directory!#]. + [ Note ] - Created the directory: [#!variable!directory!#]. Test @@ -699,6 +701,7 @@ Here we will inject 't_0006', which injects 't_0001' which has a variable: [#!st Prepare a host for use as an Anvil! node or disaster recovery target. Initial host configuration. Prepare a new machine for use as an Anvil! node or DR (disaster recovery) host. This process will setup the repository, install the appropriate anvil packages and link it to the Anvil! databases on the Strikers you choose. + Anvil! File Manager. Configure Network diff --git a/tools/anvil-daemon b/tools/anvil-daemon index 6ce4111c..e7393fa1 100755 --- a/tools/anvil-daemon +++ b/tools/anvil-daemon @@ -28,7 +28,7 @@ # # This will prevent any pending jobs from being picked up and started in this run. Note that other job checks will still happen. # -# --refresh-jason +# --refresh-json # # This just updates the JSON files used by the web interface. It is the same as '--run-once --main-loop-only --no-start' # @@ -61,6 +61,8 @@ if (($running_directory =~ /^\./) && ($ENV{PWD})) # Turn off buffering so that the pinwheel will display while waiting for the SSH call(s) to complete. $| = 1; +# NOTE: Setting 'log_level' and 'log_secure' here will get overridden in the main lopp. Use the Log methods +# in the loop as well to override defaults in code. my $anvil = Anvil::Tools->new(); $anvil->Log->entry({source => $THIS_FILE, line => __LINE__, level => 3, secure => 0, key => "log_0115", variables => { program => $THIS_FILE }}); @@ -124,9 +126,9 @@ my $now_time = time; # Once a day, we'll refresh an Install Target's RPM repository (has no effect on non-Striker dashboards). $anvil->data->{timing}{minute_checks} = 60; $anvil->data->{timing}{repo_update_interval} = 86400; -$anvil->data->{timing}{next_minute_check} = $now_time + $anvil->data->{timing}{minute_checks}; +$anvil->data->{timing}{next_minute_check} = $now_time - 1; $anvil->data->{timing}{next_repo_check} = $now_time; # We want to run on daemon startup -$anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 1, list => { +$anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 3, list => { "s1:timing::minute_checks" => $anvil->data->{timing}{minute_checks}, "s2:timing::repo_update_interval" => $anvil->data->{timing}{repo_update_interval}, "s3:now_time" => $now_time, @@ -143,8 +145,9 @@ while(1) { # Reload defaults, re-read the config and then connect to the database(s) $anvil->_set_paths(); - $anvil->_set_defaults(); - $anvil->Storage->read_config(); + $anvil->_set_defaults(); # This reset the log level + $anvil->Storage->read_config(); # This reset the log level also + $anvil->Get->switches; # Re-read to let switches override again. $anvil->Words->read(); $anvil->Database->connect({check_if_configured => $check_if_database_is_configured}); $anvil->Log->entry({source => $THIS_FILE, line => __LINE__, level => 3, secure => 0, key => "log_0132"}); @@ -224,6 +227,40 @@ sub handle_periodic_tasks "s1:timing::minute_checks" => $anvil->data->{timing}{minute_checks}, "s2:timing::next_minute_check" => $anvil->data->{timing}{next_minute_check}, }}); + + # Make sure the shared directories. + foreach my $target (sort {$a cmp $b} keys %{$anvil->data->{path}{directories}{shared}}) + { + my $directory = $anvil->data->{path}{directories}{shared}{$target}; + $anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 3, list => { + target => $target, + directory => $directory, + }}); + if (not -e $anvil->data->{path}{directories}{shared}{$target}) + { + my $failed = $anvil->Storage->make_directory({ + directory => $directory, + group => "apache", + user => "apache", + mode => "0775", + }); + $anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 3, list => { failed => $failed }}); + if ($failed) + { + # Something went wrong. + $anvil->Log->entry({source => $THIS_FILE, line => __LINE__, level => 0, priority => "warn", key => "log_0254", variables => { + directory => $directory, + }}); + } + else + { + # Success + $anvil->Log->entry({source => $THIS_FILE, line => __LINE__, level => 1, key => "log_0255", variables => { + directory => $directory, + }}); + } + } + } } ### NOTE: We call it once/day, but this will also trigger on restart of anvil-daemon. As such, we diff --git a/tools/striker-configure-host b/tools/striker-configure-host index 8009cf3a..f796079e 100755 --- a/tools/striker-configure-host +++ b/tools/striker-configure-host @@ -61,7 +61,8 @@ $anvil->System->maintenance_mode({set => 1}); pickup_job_details($anvil); -reconfigure_network($anvil); +my ($reboot_needed) = reconfigure_network($anvil); +$anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, secure => 0, list => { reboot_needed => $reboot_needed }}); # Record that we've configured this machine. $anvil->Database->insert_or_update_variables({ @@ -87,17 +88,19 @@ $anvil->System->maintenance_mode({set => 0}); ### TODO: This is only until we can get the damn networking stable on reconfigure. # Set reboot needed so that things clean up properly on reboot. -$anvil->System->reboot_needed({set => 1}); -if (not $anvil->data->{switches}{'no-reboot'}) +if ($reboot_needed) { - # Reboot, after waiting a few seconds to let the user's browser pick up the last messages in - # jobs.json. We'll also log the user out, in case we were re-configuring. - sleep 5; - $anvil->Log->entry({source => $THIS_FILE, line => __LINE__, level => 1, key => "log_0215"}); - $anvil->Account->logout({debug => 2}); - $anvil->System->call({debug => 2, shell_call => $anvil->data->{path}{exe}{'anvil-manage-power'}." --reboot -y"}); + $anvil->System->reboot_needed({set => 1}); + if (not $anvil->data->{switches}{'no-reboot'}) + { + # Reboot, after waiting a few seconds to let the user's browser pick up the last messages in + # jobs.json. We'll also log the user out, in case we were re-configuring. + sleep 5; + $anvil->Log->entry({source => $THIS_FILE, line => __LINE__, level => 1, key => "log_0215"}); + $anvil->Account->logout({debug => 2}); + $anvil->System->call({debug => 2, shell_call => $anvil->data->{path}{exe}{'anvil-manage-power'}." --reboot -y"}); + } } - $anvil->nice_exit({code => 0}); @@ -171,6 +174,7 @@ sub reconfigure_network { my ($anvil) = @_; + my $reboot_needed = 0; my $prefix = $anvil->data->{variables}{form}{config_step1}{prefix}{value}; my $sequence = $anvil->data->{variables}{form}{config_step1}{sequence}{value}; my $domain = $anvil->data->{variables}{form}{config_step1}{domain}{value};