Author: arkurth
Date: Thu May 28 18:01:18 2009
New Revision: 779702
URL: http://svn.apache.org/viewvc?rev=779702&view=rev
Log:
VCL-140
Added get_variable() and set_variable() subroutines which access the variable
table.
Other
Added get_computer_private_ip_address() subroutine. It searches the /etc/hosts
file on the managment node for the computer specified
Modified:
incubator/vcl/trunk/managementnode/lib/VCL/DataStructure.pm
Modified: incubator/vcl/trunk/managementnode/lib/VCL/DataStructure.pm
URL:
http://svn.apache.org/viewvc/incubator/vcl/trunk/managementnode/lib/VCL/DataStructure.pm?rev=779702&r1=779701&r2=779702&view=diff
==============================================================================
--- incubator/vcl/trunk/managementnode/lib/VCL/DataStructure.pm (original)
+++ incubator/vcl/trunk/managementnode/lib/VCL/DataStructure.pm Thu May 28
18:01:18 2009
@@ -78,6 +78,8 @@
use Object::InsideOut;
use List::Util qw(min max);
+use YAML;
+
use VCL::utils;
##############################################################################
@@ -1408,6 +1410,303 @@
#/////////////////////////////////////////////////////////////////////////////
+=head2 get_computer_private_ip_address
+
+ Parameters : computer name (optional)
+ Returns : If successful: string containing IP address
+ If failed: false
+ Description : Retrieves the IP address for a computer from the
+ management node's local /etc/hosts file.
+
+ An optional argument can
+ be supplied containing the name of the computer for which the IP
+ address will be retrieved.
+
+ This subroutine may or may not be called as a DataStructure
+ object method. If this subroutine is called as an object method,
+ the computer name argument is optional. If it is not called as
an
+ object method, the computer name argument must be supplied.
+
+ The first time this subroutine is called as an object method
+ without an argument, the reservation computer's IP address is
+ retrieved from the /etc/hosts file and saved in the
DataStructure
+ object's data. Subsequent calls as an object method without an
+ argument will return the IP address retrieved the first time for
+ efficiency.
+
+=cut
+
+sub get_computer_private_ip_address {
+ my $self;
+ my $argument = shift;
+ my $computer_name;
+
+ # Check if subroutine was called as an object method
+ if (ref($argument) && $argument->isa('VCL::DataStructure')) {
+ # Subroutine was called as an object method, check if an
argument was specified
+ $self = $argument;
+ $argument = shift;
+ if ($argument) {
+ # Argument was specified, use this as the computer name
+ $computer_name = $argument;
+ }
+ else {
+ # Argument was not specified, check if private IP
address for this reservation's computer was already retrieved from /etc/hosts
+ if (my $existing_private_ip_address =
$self->request_data->{reservation}{$self->reservation_id}{computer}{privateIPaddress})
{
+ # This subroutine has already been run for the
reservation computer, return IP address retrieved earlier
+ notify($ERRORS{'DEBUG'}, 0, "returning private
IP address previously retrieved from /etc/hosts: $existing_private_ip_address");
+ return $existing_private_ip_address;
+ }
+
+ # Argument was not specified and private IP address has
not yet been saved in the request data
+ # Get the computer short name for this reservation
+ $computer_name = $self->get_computer_short_name();
+ }
+ }
+ elsif (ref($argument)) {
+ notify($ERRORS{'WARNING'}, 0, "subroutine was called with an
illegal argument type: " . ref($argument));
+ return;
+ }
+ else {
+ # Subroutine was not called as an object method
+ $computer_name = $argument;
+ }
+
+ # Make sure the computer name was determined either from an argument or
the request data
+ if (!$computer_name) {
+ notify($ERRORS{'WARNING'}, 0, "unable to determine computer
name from argument or request data");
+ return;
+ }
+
+ notify($ERRORS{'DEBUG'}, 0, "attempting to retrieve private IP address
for computer: $computer_name");
+
+ # Retrieve the contents of /etc/hosts using cat
+ my ($exit_status, $output) = run_command('cat /etc/hosts', 1);
+ if (defined $exit_status && $exit_status == 0) {
+ notify($ERRORS{'DEBUG'}, 0, "retrieved contents of /etc/hosts
on this management node, contains " . scalar @$output . " lines");
+ }
+ elsif (defined $exit_status) {
+ notify($ERRORS{'WARNING'}, 0, "failed to cat /etc/hosts on this
management node, exit status: $exit_status, output:\n" . join("\n", @$output));
+ return;
+ }
+ else {
+ notify($ERRORS{'WARNING'}, 0, "failed to run command to cat
/etc/hosts on this management node");
+ return;
+ }
+
+ # Find lines containing the computer name
+ my @matching_computer_hosts_lines = grep(/\s$computer_name/i, @$output);
+
+ # Extract matching lines which aren't commented out
+ my @uncommented_computer_hosts_lines = grep(/^\s*[^#]/,
@matching_computer_hosts_lines);
+
+ # Make sure 1 uncommented line was found
+ if (@matching_computer_hosts_lines == 0) {
+ notify($ERRORS{'WARNING'}, 0, "did not find any lines in
/etc/hosts containing '$computer_name'");
+ return;
+ }
+ elsif (@uncommented_computer_hosts_lines == 0) {
+ notify($ERRORS{'WARNING'}, 0, "did not find any uncommented
lines in /etc/hosts containing '$computer_name':\n" . join("\n",
@matching_computer_hosts_lines));
+ return;
+ }
+ elsif (@uncommented_computer_hosts_lines > 1) {
+ notify($ERRORS{'WARNING'}, 0, "found multiple uncommented lines
in /etc/hosts containing '$computer_name':\n" . join("\n",
@matching_computer_hosts_lines));
+ return;
+ }
+
+ my $matching_computer_hosts_line = $matching_computer_hosts_lines[0];
+ notify($ERRORS{'DEBUG'}, 0, "found line for '$computer_name' in
/etc/hosts:\n$matching_computer_hosts_line");
+
+ # Extract the IP address from the matching line
+ my ($ip_address) = $matching_computer_hosts_line =~
/\s*((?:[0-9]{1,3}\.?){4})\s+$computer_name/i;
+
+ # Check if IP address was found
+ if (!$ip_address) {
+ notify($ERRORS{'WARNING'}, 0, "unable to determine IP address
from line:\n$matching_computer_hosts_line");
+ return;
+ }
+
+ notify($ERRORS{'DEBUG'}, 0, "found IP address: $ip_address");
+
+ # Update the request data if subroutine was called as an object method
without an argument
+ if ($self && !$argument) {
+ $self->set_computer_private_ip_address($ip_address);
+ }
+
+ return $ip_address;
+}
+
+#/////////////////////////////////////////////////////////////////////////////
+
+=head2 get_variable
+
+ Parameters : $variable_name
+ Returns : If successful: reference to the data stored in the variable
table for
+ the variable name specified
+ If failed: false
+ Description : Queries the variable table for the variable with the name
specified by the subroutine argument.
+ Returns a reference to the data.
+
+=cut
+
+sub get_variable {
+ my $self = shift;
+ my $name = shift;
+
+ # Check if subroutine was called as an object method
+ unless (ref($self) && $self->isa('VCL::DataStructure')) {
+ notify($ERRORS{'CRITICAL'}, 0, "subroutine can only be called
as a VCL::DataStructure module object method");
+ return;
+ }
+
+ # Check the arguments
+ if (!defined($name)) {
+ notify($ERRORS{'WARNING'}, 0, "variable name argument was not
supplied");
+ return;
+ }
+
+ # Construct the select statement
+my $select_statement .= <<"EOF";
+SELECT
+variable.value
+FROM
+variable
+WHERE
+variable.name = '$name'
+EOF
+
+ # Call the database select subroutine
+ my @selected_rows = database_select($select_statement);
+
+ # Check to make 1 sure row was returned
+ if (!...@selected_rows) {
+ notify($ERRORS{'WARNING'}, 0, "unable to execute select
statement to retrieve variable '$name' from the database");
+ return;
+ }
+ elsif (@selected_rows == 0){
+ notify($ERRORS{'WARNING'}, 0, "variable '$name' does not exist
in the database");
+ return;
+ }
+ elsif (@selected_rows > 1){
+ notify($ERRORS{'WARNING'}, 0, "multiple rows exist in the
database for variable '$name':\n" . format_data(\...@selected_rows));
+ return;
+ }
+
+ # Get the serialized value from the variable row
+ my $serialized_value = $selected_rows[0]{value};
+
+ # Attempt to deserialize the value
+ # Use eval because Load() will call die() if it encounters an error
+ my $deserialized_value;
+ eval '$deserialized_value = YAML::Load($serialized_value)';
+ if ($EVAL_ERROR) {
+ notify($ERRORS{'WARNING'}, 0, "unable to deserialize the value
using YAML::Load(): $serialized_value");
+ return;
+ }
+
+ # Display the data type of the value retrieved from the variable table
+ if (my $deserialized_data_type = ref($deserialized_value)) {
+ notify($ERRORS{'DEBUG'}, 0, "returning $deserialized_data_type
reference");
+ }
+ else {
+ notify($ERRORS{'DEBUG'}, 0, "returning scalar
($deserialized_value)");
+ }
+
+ return $deserialized_value;
+}
+
+#/////////////////////////////////////////////////////////////////////////////
+
+=head2 set_variable
+
+ Parameters : $variable_name, $variable_value
+ Returns : If successful: true
+ If failed: false
+ Description : Inserts or updates a row in the variable table. This subroutine
+ will also update the variable.timestamp column. The
+ variable.setby column is automatically set to the filename and
+ line number which called this subroutine.
+
+=cut
+
+sub set_variable {
+ my $self = shift;
+ my $name_argument = shift;
+ my $value_argument = shift;
+
+ # Check if subroutine was called as an object method
+ unless (ref($self) && $self->isa('VCL::DataStructure')) {
+ notify($ERRORS{'CRITICAL'}, 0, "subroutine can only be called
as a VCL::DataStructure module object method");
+ return;
+ }
+
+ # Check the arguments
+ if (!defined($name_argument)) {
+ notify($ERRORS{'WARNING'}, 0, "variable name argument was not
supplied");
+ return;
+ }
+ elsif (!defined($value_argument)) {
+ notify($ERRORS{'WARNING'}, 0, "variable value argument was not
supplied");
+ return;
+ }
+
+ # Construct a string indicating where the variable was set from
+ my @caller = caller(0);
+ (my $calling_file) = $caller[1] =~ /([^\/]*)$/;
+ my $calling_line = $caller[2];
+ my $caller_string = "$calling_file:$calling_line";
+
+ # Attempt to serialize the value using YAML::Dump()
+ # Use eval because Dump() will call die() if it encounters an error
+ my $serialized_value;
+ eval '$serialized_value = YAML::Dump($value_argument)';
+ if ($EVAL_ERROR) {
+ notify($ERRORS{'WARNING'}, 0, "unable to serialize the value
using YAML::Dump(): $value_argument");
+ return;
+ }
+
+ # Escape all single quote characters with a backslash
+ # or else the SQL statement will fail becuase it is wrapped in single
quotes
+ $serialized_value =~ s/'/\\'/g;;
+
+ # Assemble an insert statement, if the variable already exists, update
the existing row
+ my $insert_statement .= <<"EOF";
+INSERT INTO variable
+(
+name,
+value,
+setby,
+timestamp
+)
+VALUES
+(
+'$name_argument',
+'$serialized_value',
+'$caller_string',
+NOW()
+)
+ON DUPLICATE KEY UPDATE
+name=VALUES(name),
+value=VALUES(value),
+setby=VALUES(setby),
+timestamp=VALUES(timestamp)
+EOF
+
+ # Execute the insert statement, the return value should be the id of
the row
+ my $inserted_id = database_execute($insert_statement);
+ if ($inserted_id) {
+ notify($ERRORS{'OK'}, 0, "set variable '$name_argument', id:
$inserted_id");
+ }
+ else {
+ notify($ERRORS{'WARNING'}, 0, "failed to set variable
'$name_argument'");
+ return;
+ }
+
+ return 1;
+}
+
+#/////////////////////////////////////////////////////////////////////////////
+
1;
__END__