Author: arkurth
Date: Fri May 12 17:58:44 2017
New Revision: 1795001

URL: http://svn.apache.org/viewvc?rev=1795001&view=rev
Log:
VCL-919
Added dedicated utils.pm::database_update which returns the number of rows 
affected, including 0. Separated this from database_execute due to the numerous 
return type scenarios depending on the query type. Existing calls to 
database_execute for INSERT statements are unchanged. 
utils.pm::check_messages_need_validating is the only subroutine currently using 
database_update;

Renamed utils.pm::message_needs_validating to check_messages_need_validating 
and reworked it. It's now fully functional.

Changed the regex's used in DataStructure.pm::substitute_string_variables and 
get_invalid_substitution_identifiers to detect additional invalid patterns such 
as [], [ ], and [foo].

Added call to check_messages_need_validating in vcld.

Modified:
    vcl/trunk/managementnode/bin/vcld
    vcl/trunk/managementnode/lib/VCL/DataStructure.pm
    vcl/trunk/managementnode/lib/VCL/utils.pm

Modified: vcl/trunk/managementnode/bin/vcld
URL: 
http://svn.apache.org/viewvc/vcl/trunk/managementnode/bin/vcld?rev=1795001&r1=1795000&r2=1795001&view=diff
==============================================================================
--- vcl/trunk/managementnode/bin/vcld (original)
+++ vcl/trunk/managementnode/bin/vcld Fri May 12 17:58:44 2017
@@ -148,6 +148,10 @@ sub main () {
                delete $ENV{state};
                delete $ENV{data};
                
+               # Web site inserts into variable table whenever an admin or 
user message is modified
+               # Check if the variable exists, if so, validate all of the 
messages
+               check_messages_need_validating();
+               
                my $data_age_seconds = (time - 
$ENV{management_node_info}{$management_node_id}{RETRIEVAL_TIME});
                if ($data_age_seconds > 120 ) {
                        notify($ERRORS{'DEBUG'}, $LOGFILE, "retrieving 
management node info for '$management_node_id', cached data is stale: 
$data_age_seconds seconds old");
@@ -731,7 +735,7 @@ sub REAPER {
        my $child_exit_status = $? >> 8;
        my $signal_number = $? & 127;
        my $dumped_core = $? & 128;
-       notify($ERRORS{'DEBUG'}, 0, "REAPER called: signal: $signal, initial 
value of \$?: $status_save");
+       #notify($ERRORS{'DEBUG'}, 0, "REAPER called: signal: $signal, initial 
value of \$?: $status_save");
        
        # Wait for a child processes to die
        my $dead_pid = -1;

Modified: vcl/trunk/managementnode/lib/VCL/DataStructure.pm
URL: 
http://svn.apache.org/viewvc/vcl/trunk/managementnode/lib/VCL/DataStructure.pm?rev=1795001&r1=1795000&r2=1795001&view=diff
==============================================================================
--- vcl/trunk/managementnode/lib/VCL/DataStructure.pm (original)
+++ vcl/trunk/managementnode/lib/VCL/DataStructure.pm Fri May 12 17:58:44 2017
@@ -2588,7 +2588,7 @@ sub get_other_cluster_computer_public_ip
                $variable_identifier_regex with values from the DataStructure
                object. The default pattern used to locate sections to replace
                is:
-                  \[[a-z][a-z_]+[a-z]\]
+                  \[[^\]]*\]'
                
                Meaning, all patterns to replace are enclosed in square 
brackets.
                The text within the brackets must exactly match one of the keys
@@ -2624,7 +2624,7 @@ sub substitute_string_variables {
                return;
        }       
        if (!$variable_identifier_regex) {
-               $variable_identifier_regex = '\[[a-z][a-z_]+[a-z]\]';
+               $variable_identifier_regex = '\[[^\]]*\]';
        }
        
        my $output_string = $input_string;
@@ -2639,8 +2639,8 @@ sub substitute_string_variables {
        
        for my $input_substitute_section 
(remove_array_duplicates(@input_substitute_sections)) {
                # Remove brackets, etc from matching section: '[user_login_id]' 
--> 'user_login_id'
-               my ($subroutine_mapping_key) = $input_substitute_section =~ 
/^[^a-z]*([a-z][a-z_]+[a-z])[^a-z]*$/;
-               if (!$subroutine_mapping_key) {
+               my ($subroutine_mapping_key) = $input_substitute_section =~ 
/\[(.*)\]/;
+               if (!defined($subroutine_mapping_key)) {
                        notify($ERRORS{'CRITICAL'}, 0, "failed to extract 
subroutine mapping key from section of input string matching substitution 
identifier pattern '$variable_identifier_regex': '$input_substitute_section'");
                        next;
                }
@@ -2735,15 +2735,15 @@ sub get_invalid_substitution_identifiers
        
        my $variable_identifier_regex = shift;
        if (!$variable_identifier_regex) {
-               $variable_identifier_regex = '\[[a-z][a-z_]+[a-z]\]';
+               $variable_identifier_regex = '\[[^\]]*\]';
        }
        
        my @invalid_string_variable_identifiers;
        
        my @input_string_variable_identifiers = $input_string =~ 
/($variable_identifier_regex)/g;
        for my $input_string_variable_identifier 
(remove_array_duplicates(@input_string_variable_identifiers)) {
-               my ($subroutine_mapping_key) = 
$input_string_variable_identifier =~ /^[^a-z]*([a-z][a-z_]+[a-z])[^a-z]*$/;
-               if (defined($SUBROUTINE_MAPPINGS{$subroutine_mapping_key})) {
+               my ($subroutine_mapping_key) = 
$input_string_variable_identifier =~ /\[(.*)\]/;
+               if ($subroutine_mapping_key && 
defined($SUBROUTINE_MAPPINGS{$subroutine_mapping_key})) {
                        next;
                }
                elsif (exists(&$subroutine_mapping_key)) {
@@ -2757,13 +2757,13 @@ sub get_invalid_substitution_identifiers
                        next;
                }
                else {
-                       notify($ERRORS{'WARNING'}, 0, "neither mapping key not 
explicit subroutine exists in DataStructure.pm: $subroutine_mapping_key");
+                       notify($ERRORS{'OK'}, 0, "neither mapping key not 
explicit subroutine exists in DataStructure.pm: $subroutine_mapping_key");
                        push @invalid_string_variable_identifiers, 
$input_string_variable_identifier;
                }
        }
        
        if (@invalid_string_variable_identifiers) {
-               notify($ERRORS{'WARNING'}, 0, "input string contains invalid 
substitution identifiers: " . join(', ', @invalid_string_variable_identifiers) 
. "\ninput string:\n$input_string");
+               notify($ERRORS{'OK'}, 0, "input string contains invalid 
substitution identifiers: " . join(', ', @invalid_string_variable_identifiers));
        }
        return @invalid_string_variable_identifiers;
 }

Modified: vcl/trunk/managementnode/lib/VCL/utils.pm
URL: 
http://svn.apache.org/viewvc/vcl/trunk/managementnode/lib/VCL/utils.pm?rev=1795001&r1=1795000&r2=1795001&view=diff
==============================================================================
--- vcl/trunk/managementnode/lib/VCL/utils.pm (original)
+++ vcl/trunk/managementnode/lib/VCL/utils.pm Fri May 12 17:58:44 2017
@@ -97,6 +97,7 @@ our @EXPORT = qw(
        character_to_ascii_value
        check_blockrequest_time
        check_endtimenotice_interval
+       check_messages_need_validating
        check_ssh
        check_time
        clear_next_image_id
@@ -225,7 +226,6 @@ our @EXPORT = qw(
        known_hosts
        mail
        makedatestring
-       message_needs_validating
        nmap_port
        normalize_file_path
        notify
@@ -2847,7 +2847,13 @@ sub database_select {
 
        # Execute the statement handle
        if (!($select_handle->execute())) {
-               notify($ERRORS{'WARNING'}, 0, "could not execute statement on 
$database database, $select_statement\nerror: " . $dbh->errstr());
+               (my $select_statement_condensed = $select_statement) =~ 
s/[\n\s]+/ /g;
+               notify($ERRORS{'WARNING'}, 0, "failed to execute statement on 
$database database:\n$select_statement\n" .
+                       "---\n" .
+                       "copy/paste select 
statement:\n$select_statement_condensed\n" .
+                       "---\n" .
+                       "error: " . $dbh->errstr()
+               );
                $select_handle->finish;
                $dbh->disconnect if !defined $ENV{dbh};
                return ();
@@ -2869,9 +2875,7 @@ sub database_select {
  Parameters  : $sql_statement, $database (optional)
  Returns     : boolean
  Description : Executes an SQL statement. If $sql_statement is an INSERT
-               statement, the ID of the row inserted is returned. For other
-               statements such as UPDATE, the number of rows updated is
-               returned.
+               statement, the ID of the row inserted is returned.
 
 =cut
 
@@ -2917,7 +2921,7 @@ sub database_execute {
        }
        
        # Get the id of the last inserted record if this is an INSERT statement
-       if ($sql_statement =~ /insert/i) {
+       if ($sql_statement =~ /^\s*insert/i) {
                my $sql_insertid = $statement_handle->{'mysql_insertid'};
                my $sql_warning_count = 
$statement_handle->{'mysql_warning_count'};
                $statement_handle->finish;
@@ -2939,6 +2943,72 @@ sub database_execute {
 
 #//////////////////////////////////////////////////////////////////////////////
 
+=head2 database_update
+
+ Parameters  : $update_statement, $database (optional)
+ Returns     : boolean
+ Description : Executes an SQL UPDATE statement. Returns the number of rows
+               updated. 0 is returned if the statement was successfully 
executed
+               but no rows were updated. Undefined is returned if the statement
+               failed to execute.
+
+=cut
+
+sub database_update {
+       my ($update_statement, $database) = @_;
+       if (!$update_statement) {
+               notify($ERRORS{'WARNING'}, 0, "SQL UPDATE statement argument 
not supplied");
+               return;
+       }
+       elsif ($update_statement !~ /^\s*UPDATE\s/i) {
+               notify($ERRORS{'WARNING'}, 0, "invalid SQL UPDATE statement 
argument, it does not begin with 'UPDATE':\n$update_statement");
+               return;
+       }
+       
+       
+       my $dbh = getnewdbh($database);
+       if (!$dbh) {
+               sleep_uninterrupted(3);
+               $dbh = getnewdbh($database);
+               if (!$dbh) {
+                       notify($ERRORS{'WARNING'}, 0, "unable to obtain 
database handle, " . DBI::errstr());
+                       return;
+               }
+       }
+       
+       # Prepare the statement handle
+       my $statement_handle = $dbh->prepare($update_statement);
+       
+       # Check the statement handle
+       if (!$statement_handle) {
+               my $error_string = $dbh->errstr() || '<unknown error>';
+               notify($ERRORS{'WARNING'}, 0, "failed to prepare SQL UPDATE 
statement, $update_statement, $error_string");
+               $dbh->disconnect if !defined $ENV{dbh};
+               return;
+       }
+       
+       # Execute the statement handle
+       my $result = $statement_handle->execute();
+       
+       if (!defined($result)) {
+               my $error_string = $dbh->errstr() || '<unknown error>';
+               $statement_handle->finish;
+               $dbh->disconnect if !defined $ENV{dbh};
+               notify($ERRORS{'WARNING'}, 0, "failed to execute SQL UPDATE 
statement: $update_statement\nerror:\n$error_string");
+               return;
+       }
+       
+       my $updated_row_count = $statement_handle->rows;
+       $statement_handle->finish;
+       $dbh->disconnect if !defined $ENV{dbh};
+       
+       $update_statement =~ s/[\n\s]+/ /g;
+       notify($ERRORS{'DEBUG'}, 0, "returning number of rows affected by 
UPDATE statement: $updated_row_count\n$update_statement");
+       return $updated_row_count;
+}
+
+#//////////////////////////////////////////////////////////////////////////////
+
 =head2  get_request_info
 
  Parameters  : $request_id, $no_cache (optional)
@@ -15044,8 +15114,8 @@ sub get_collapsed_hash_reference {
 
  Parameters  : none
  Returns     : hash reference
- Description : Retrieves info for all adminmessage and usermessage entries from
-               the variable table. A hash is constructed. The keys are the
+ Description : Retrieves info for all 'adminmessage|' and 'usermessage|' 
entries
+               from the variable table. A hash is constructed. The keys are the
                variable.name values:
                {
                   "usermessage|endtime_reached|Global" => {
@@ -15074,7 +15144,7 @@ SELECT
 FROM
 variable
 WHERE
-variable.name REGEXP '^(admin|user)message'
+variable.name REGEXP '^(admin|user)message\\\\|'
 EOF
 
        my @rows = database_select($select_statement);
@@ -15086,13 +15156,13 @@ EOF
                delete $info->{$variable_name}{name};
        }
        
-       notify($ERRORS{'DEBUG'}, 0, "retrieved info for all admin and user 
messages from the variable table:\n" . format_data($info));
+       notify($ERRORS{'DEBUG'}, 0, "retrieved info for all admin and user 
messages from the variable table:\n" . join("\n", sort keys %$info));
        return $info;
 }
 
 #//////////////////////////////////////////////////////////////////////////////
 
-=head2 message_needs_validating
+=head2 check_messages_need_validating
 
  Parameters  : none
  Returns     : boolean
@@ -15108,59 +15178,53 @@ EOF
                  contained in variable.value for invalid substitution
                  identifiers (strings such as [request_foo] which don't
                  correspond to a function that DataStructure.pm implements)
-               * If any invalid identifiers are found, a
-                 'usermessage_invalid_fields' variable is added with a value
-                 containing a hash reference:
+                                       * If any invalid identifiers are found, 
an 'invalidfields' key is
+                                         added to variable.value containing a 
hash reference:
                      {
-                       "adminmessage|image_creation_started" => {
-                         "message" => [
-                           "[this_be_invalid_yo]"
-                         ]
-                       },
-                       "usermessage|endtime_reached|Local" => {
-                         "message" => [
-                           "[is_blah]"
-                         ],
-                         "subject" => [
-                           "[usr_login_id]"
-                         ]
-                       }
+                                                               "message" => [
+                                                                 "[is_blah]"
+                                                               ],
+                                                               "subject" => [
+                                                                 
"[usr_login_id]"
+                                                               ]
                      }
                
-               If no invalid fields are found, the 'usermessage_invalid_fields'
-               variable will be deleted if it was previously created.
-               
                After validating is complete, the 'usermessage_needs_validating'
                variable is deleted.
 
 =cut
 
-sub message_needs_validating {
+sub check_messages_need_validating {
        my $management_node_name = get_management_node_info()->{SHORTNAME} || 
hostname;
-       
        my $validate_variable_name = 'usermessage_needs_validating';
-       my $invalid_variable_name = 'usermessage_invalid_fields';
        
+       
#...........................................................................
+       # Check if any messages have been updated
        # Just get the id to minimize this query since it runs with every vcld 
daemon loop
        my $select_id_statement = <<EOF;
 SELECT
-id
+id,
+timestamp
 FROM
 variable
 WHERE
 variable.name = '$validate_variable_name'
 EOF
-       my @id_rows = database_select($select_id_statement);
-       if (!@id_rows) {
-               notify($ERRORS{'DEBUG'}, 0, "admin and user message variables 
to NOT need to be validated, $validate_variable_name variable does NOT exist in 
the database");
+       my @select_needs_validating_rows = 
database_select($select_id_statement);
+       if (!@select_needs_validating_rows) {
+               #notify($ERRORS{'DEBUG'}, 0, "admin and user message variables 
to NOT need to be validated, $validate_variable_name variable does NOT exist in 
the database");
                return 0;
        }
-       my $validate_variable_id = $id_rows[0]->{id};
-       notify($ERRORS{'DEBUG'}, 0, "$validate_variable_name variable exists in 
the database, ID: $validate_variable_id, attempting to update its value to 
'$management_node_name'");
+       my $validate_variable_id = $select_needs_validating_rows[0]->{id};
+       my $validate_variable_timestamp = 
$select_needs_validating_rows[0]->{timestamp};
+       notify($ERRORS{'DEBUG'}, 0, "$validate_variable_name variable exists in 
the database, ID: $validate_variable_id, attempting to update variable value to 
'$management_node_name'");
        
        
-       # Set the $validate_variable_name entry's variable.value to the 
management node name
-       my $update_statement = <<EOF;
+       
#...........................................................................
+       # Messages have been updated and need validation
+       # Try to allow only a single management node to processing the 
validation
+       # Set usermessage_needs_validating variable.value --> <management node 
name>
+       my $update_needs_validating_statement = <<EOF;
 UPDATE
 variable
 SET
@@ -15168,74 +15232,62 @@ value = '$management_node_name',
 timestamp = NOW()
 WHERE
 variable.id = $validate_variable_id
+AND variable.timestamp = '$validate_variable_timestamp'
 AND (
    variable.value = '1'
        OR variable.value = '$management_node_name'
 )
 EOF
-       my $update_result = database_execute($update_statement);
-       if ($update_result) {
-               notify($ERRORS{'OK'}, 0, "attempted to update value of 
$validate_variable_name variable (ID: $validate_variable_id) to 
'$management_node_name', verifying the update was successful");
-       }
-       else {
-               notify($ERRORS{'WARNING'}, 0, "failed to update value of 
$validate_variable_name variable (ID: $validate_variable_id) to 
'$management_node_name', another management node may have processed the 
verification and deleted the entry");
-               return;
-       }
-       
-       # Make sure the value was updated, database_execute returns true if the 
syntax is valid but 0 rows were updated
-       my $verify_statement = <<EOF;
-SELECT
-*
-FROM
-variable
-WHERE
-variable.id = $validate_variable_id
-EOF
-       my @verify_rows = database_select($verify_statement);
-       if (!@verify_rows) {
-               notify($ERRORS{'WARNING'}, 0, "failed to verify the value of 
$validate_variable_name variable (ID: $validate_variable_id) was updated to 
'$management_node_name', another management node may have processed the 
verification and deleted the entry");
+       my $updated_needs_validating_rows = 
database_update($update_needs_validating_statement);
+       if (!defined($updated_needs_validating_rows)) {
+               notify($ERRORS{'WARNING'}, 0, "failed to update value of 
$validate_variable_name variable (ID: $validate_variable_id) to 
'$management_node_name'");
                return;
        }
-       if ($verify_rows[0]->{value} && $verify_rows[0]->{value} eq 
$management_node_name) {
-               notify($ERRORS{'DEBUG'}, 0, "admin and user message variables 
need to be validated, updated value of $validate_variable_name variable to 
'$verify_rows[0]->{value}'");
-       }
-       else {
-               notify($ERRORS{'WARNING'}, 0, "failed to update the value of 
$validate_variable_name variable (ID: $validate_variable_id) to 
'$management_node_name', its current value is '$verify_rows[0]->{value}', 
another management node may have started processing the verification");
+       elsif (!$updated_needs_validating_rows) {
+               notify($ERRORS{'WARNING'}, 0, "no rows were affected in attempt 
to update value of $validate_variable_name variable (ID: $validate_variable_id) 
to '$management_node_name', another management node may have processed the 
verification and deleted the entry");
                return 0;
        }
+       notify($ERRORS{'OK'}, 0, "updated the value of $validate_variable_name 
variable to '$management_node_name'");
+       
        
+       
#...........................................................................
        # Check all of the admin and user messages
-       my $variable_info = get_message_variable_info();
-       my $invalid_info;
-       for my $variable_name (sort keys %$variable_info) {
-               my $yaml_string_value = $variable_info->{$variable_name}{value};
+       my $message_variable_info = get_message_variable_info();
+       for my $message_variable_name (sort keys %$message_variable_info) {
+               my $yaml_string_value = 
$message_variable_info->{$message_variable_name}{value};
                my $hash_reference_value = yaml_deserialize($yaml_string_value);
                if (!defined($hash_reference_value)) {
-                       notify($ERRORS{'WARNING'}, 0, "unable to validate 
'$variable_name' variable, YAML string could not be 
deserialized:\n$yaml_string_value");
+                       notify($ERRORS{'WARNING'}, 0, "unable to validate 
'$message_variable_name' variable, YAML string could not be 
deserialized:\n$yaml_string_value");
                        next;
                }
                elsif (!ref($hash_reference_value) || 
ref($hash_reference_value) ne 'HASH') {
-                       notify($ERRORS{'WARNING'}, 0, "unable to validate 
'$variable_name' variable, deserialized value is not a hash reference:\n" . 
format_data($hash_reference_value));
+                       notify($ERRORS{'WARNING'}, 0, "unable to validate 
'$message_variable_name' variable, deserialized value is not a hash 
reference:\n" . format_data($hash_reference_value));
                        next;
                }
                
+               my $invalid_message_info;
                for my $key ('subject', 'message', 'short_message') {
                        my $input_string = $hash_reference_value->{$key} || 
next;
-                       notify($ERRORS{'DEBUG'}, 0, "validating substitution 
identifiers contained in '$variable_name' $key");
+                       notify($ERRORS{'DEBUG'}, 0, "validating substitution 
identifiers contained in '$message_variable_name' $key");
                        my @invalid_substitution_identifiers = 
VCL::DataStructure::get_invalid_substitution_identifiers($input_string);
                        if (@invalid_substitution_identifiers) {
-                               $invalid_info->{$variable_name}{$key} = 
\@invalid_substitution_identifiers;
+                               $invalid_message_info->{$key} = 
\@invalid_substitution_identifiers;
                        }
                }
+               
+               if ($invalid_message_info) {
+                       notify($ERRORS{'WARNING'}, 0, "'$message_variable_name' 
variable's value contains invalid substitution identifiers, setting 
'invalidfields' key in variable.value to:\n" . 
format_data($invalid_message_info));
+                       $hash_reference_value->{invalidfields} = 
$invalid_message_info;
+                       set_variable($message_variable_name, 
$hash_reference_value);
+               }
+               elsif (defined($hash_reference_value->{invalidfields})) {
+                       # No invalid identifiers were found, 'invalidfields' 
was previously set for the variable, remove it
+                       notify($ERRORS{'WARNING'}, 0, "'$message_variable_name' 
variable's value contains an 'invalidfields' key but no invalid substitution 
identifiers were found, removing the key");
+                       delete $hash_reference_value->{invalidfields};
+                       set_variable($message_variable_name, 
$hash_reference_value);
+               }
        }
        
-       if ($invalid_info) {
-               notify($ERRORS{'WARNING'}, 0, "message variables with invalid 
substitution identifiers found, setting '$invalid_variable_name' variable with 
value:\n" . format_data($invalid_info));
-               set_variable($invalid_variable_name, $invalid_info);
-       }
-       else {
-               delete_variable($invalid_variable_name);
-       }
        delete_variable($validate_variable_name);
        return 1;
 }


Reply via email to