Modified: vcl/trunk/managementnode/lib/VCL/new.pm
URL: 
http://svn.apache.org/viewvc/vcl/trunk/managementnode/lib/VCL/new.pm?rev=1644185&r1=1644184&r2=1644185&view=diff
==============================================================================
--- vcl/trunk/managementnode/lib/VCL/new.pm (original)
+++ vcl/trunk/managementnode/lib/VCL/new.pm Tue Dec  9 21:11:37 2014
@@ -698,14 +698,14 @@ sub computer_not_being_used {
                        notify($ERRORS{'WARNING'}, 0, "$computer_short_name is 
NOT available, its state is $computer_state_name");
                        return 0;
                }
-
+               
                # Return 0 if computer state is maintenance and request state 
name is not vmhostinuse
                # Allow computers to go from maintenance directly to a vmhost
                if ($computer_state_name =~ /^(maintenance)$/ && 
$request_state_name !~ /tovmhostinuse/) {
                        notify($ERRORS{'WARNING'}, 0, "$computer_short_name is 
NOT available, its state is $computer_state_name");
                        return 0;
                }
-
+               
                # Warn if computer state isn't available or reload - except for 
reinstall requests
                if ($request_state_name !~ /^(reinstall)$/ && 
$computer_state_name !~ /^(available|reload)$/) {
                        notify($ERRORS{'WARNING'}, 0, "$computer_short_name 
state is $computer_state_name, checking if any conflicting reservations are 
active");
@@ -916,10 +916,10 @@ sub reserve_computer {
        my $user_emailnotices               = 
$self->data->get_user_emailnotices();
        my $user_imtype_name                = 
$self->data->get_user_imtype_name();
        my $user_im_id                      = $self->data->get_user_im_id();
-
+       
        # Needed for computerloadflow   
        insertloadlog($reservation_id, $computer_id, "addinguser", "Adding user 
to $computer_short_name");
-
+       
        # Call OS module's reserve subroutine
        if (!$self->os->reserve()) {
                $self->reservation_failed("OS module failed to reserve 
resources for this reservation");

Modified: vcl/trunk/managementnode/lib/VCL/reclaim.pm
URL: 
http://svn.apache.org/viewvc/vcl/trunk/managementnode/lib/VCL/reclaim.pm?rev=1644185&r1=1644184&r2=1644185&view=diff
==============================================================================
--- vcl/trunk/managementnode/lib/VCL/reclaim.pm (original)
+++ vcl/trunk/managementnode/lib/VCL/reclaim.pm Tue Dec  9 21:11:37 2014
@@ -106,30 +106,42 @@ sub process {
 
        # Remove related fixedIPsr variable, if it exists
        if ($server_request_id) {
-               my $variable_name = "fixedIPsr" . $server_request_id;
-               if(is_variable_set($variable_name)){
-               #Delete from variable table.
-               my $delete_sql_statement = "DELETE variable FROM variable WHERE 
name = '$variable_name' ";
-               if (database_execute($delete_sql_statement)) {
-                                       notify($ERRORS{'DEBUG'}, 0, "Deleted 
server reservation entry for $variable_name from variable table");
-               }   
-         }   
+               my $variable_name = "fixedIPsr" . $server_request_id;
+               if (is_variable_set($variable_name)){
+                       #Delete from variable table.
+                       my $delete_sql_statement = "DELETE variable FROM 
variable WHERE name = '$variable_name' ";
+                       if (database_execute($delete_sql_statement)) {
+                       notify($ERRORS{'DEBUG'}, 0, "Deleted server reservation 
entry for $variable_name from variable table");
+                       }   
+               }   
                
-               if($public_ip_configuration =~ /static/i) {
+               if ($public_ip_configuration =~ /static/i) {
                        my $original_IPvalue = "originalIPaddr_" . 
$server_request_id;
-                       if(is_variable_set($original_IPvalue)) {
+                       if (is_variable_set($original_IPvalue)) {
                                my $original_Public_IP = 
get_variable($original_IPvalue);
-                               
if(update_computer_public_ip_address($computer_id, $original_Public_IP)) {
+                               if 
(update_computer_public_ip_address($computer_id, $original_Public_IP)) {
                                        notify($ERRORS{'DEBUG'}, 0, "restored 
original IP address: $original_Public_IP for $computer_state_name ");
                                }
-            my $delete_sql_statement = "DELETE variable FROM variable WHERE 
name = '$original_IPvalue' ";
-            if (database_execute($delete_sql_statement)) {
-                       notify($ERRORS{'DEBUG'}, 0, "Deleted server reservation 
entry for $original_IPvalue from variable table");
-            }   
+                               my $delete_sql_statement = "DELETE variable 
FROM variable WHERE name = '$original_IPvalue' ";
+                               if (database_execute($delete_sql_statement)) {
+                                       notify($ERRORS{'DEBUG'}, 0, "Deleted 
server reservation entry for $original_IPvalue from variable table");
+                               }   
                        }
                }
        }
-
+       
+       # Clean up rules on the NAT host if NAT is used
+       if ($self->nathost_os(0)) {
+               my $nathost_hostname = $self->data->get_nathost_hostname();
+               if ($self->nathost_os->firewall()) {
+                       if (!$self->nathost_os->firewall->delete_chain('nat', 
$reservation_id)) {
+                               notify($ERRORS{'CRITICAL'}, 0, "failed to 
delete '$reservation_id' chain from the nat table on NAT host 
$nathost_hostname");
+                       }
+               }
+               else {
+                       notify($ERRORS{'CRITICAL'}, 0, "failed to delete 
'$reservation_id' chain from the nat table on NAT host $nathost_hostname, NAT 
host OS object is not available");
+               }
+       }
        
        # Insert into computerloadlog if request state = timeout
        if ($request_state_name =~ /timeout|deleted/) {

Modified: vcl/trunk/managementnode/lib/VCL/utils.pm
URL: 
http://svn.apache.org/viewvc/vcl/trunk/managementnode/lib/VCL/utils.pm?rev=1644185&r1=1644184&r2=1644185&view=diff
==============================================================================
--- vcl/trunk/managementnode/lib/VCL/utils.pm (original)
+++ vcl/trunk/managementnode/lib/VCL/utils.pm Tue Dec  9 21:11:37 2014
@@ -126,6 +126,7 @@ our @EXPORT = qw(
        get_computer_grp_members
        get_computer_ids
        get_computer_info
+       get_computer_nathost_info
        get_computer_private_ip_address_info
        get_computers_controlled_by_mn
        get_connect_method_info
@@ -157,6 +158,7 @@ our @EXPORT = qw(
        get_management_node_vmhost_ids
        get_management_node_vmhost_info
        get_module_info
+       get_nathost_assigned_public_ports
        get_next_image_default
        get_os_info
        get_production_imagerevision_info
@@ -203,6 +205,7 @@ our @EXPORT = qw(
        notify_via_IM
        notify_via_oascript
        parent_directory_path
+       populate_reservation_natport
        preplogfile
        read_file_to_array
        remove_array_duplicates
@@ -2974,7 +2977,7 @@ sub database_execute {
 
 =head2  get_request_info
 
- Parameters  : $request_id
+ Parameters  : $request_id, $no_cache (optional)
  Returns     : hash
  Description : Retrieves all request/reservation information.
 
@@ -2982,12 +2985,17 @@ sub database_execute {
 
 
 sub get_request_info {
-       my ($request_id) = @_;
+       my ($request_id, $no_cache) = @_;
        if (!(defined($request_id))) {
                notify($ERRORS{'WARNING'}, 0, "request ID argument was not 
specified");
                return;
        }
        
+       # Don't use cached info by default
+       if (!defined($no_cache)) {
+               $no_cache = 1;
+       }
+       
        # Get a hash ref containing the database column names
        my $database_table_columns = get_database_table_columns();
        
@@ -3083,31 +3091,43 @@ EOF
                
                # Add the image info to the hash
                my $image_id = 
$request_info->{reservation}{$reservation_id}{imageid};
-               my $image_info = get_image_info($image_id, 1);
+               my $image_info = get_image_info($image_id, $no_cache);
                $request_info->{reservation}{$reservation_id}{image} = 
$image_info;
                
                # Add the imagerevision info to the hash
                my $imagerevision_id = 
$request_info->{reservation}{$reservation_id}{imagerevisionid};
-               my $imagerevision_info = 
get_imagerevision_info($imagerevision_id, 1);
+               my $imagerevision_info = 
get_imagerevision_info($imagerevision_id, $no_cache);
                $request_info->{reservation}{$reservation_id}{imagerevision} = 
$imagerevision_info;
                
                # Add the computer info to the hash
                my $computer_id = 
$request_info->{reservation}{$reservation_id}{computerid};
-               my $computer_info = get_computer_info($computer_id, 1);
+               my $computer_info = get_computer_info($computer_id, $no_cache);
                $request_info->{reservation}{$reservation_id}{computer} = 
$computer_info;
                
+               # Populate natport table for reservation
+               # Make sure this wasn't called from 
populate_reservation_natport or else recursive loop will occur
+               my $caller_trace = get_caller_trace(5);
+               if ($caller_trace !~ /populate_reservation_natport/) {
+                       my $request_state_name = $request_info->{state}{name};
+                       if ($request_state_name =~ 
/(new|reserved|modified|test)/) {
+                               if 
(!populate_reservation_natport($reservation_id)) {
+                                       notify($ERRORS{'CRITICAL'}, 0, "failed 
to populate natport table for reservation");
+                               }
+                       }
+               }
+               
                # Add the connect method info to the hash
-               my $connect_method_info = 
get_connect_method_info($imagerevision_id);
+               my $connect_method_info = 
get_connect_method_info($imagerevision_id, $no_cache);
                $request_info->{reservation}{$reservation_id}{connect_methods} 
= $connect_method_info;
-       
+               
                # Add the managementnode info to the hash
                my $management_node_id = 
$request_info->{reservation}{$reservation_id}{managementnodeid};
-               my $management_node_info = 
get_management_node_info($management_node_id);
+               my $management_node_info = 
get_management_node_info($management_node_id, $no_cache);
                $request_info->{reservation}{$reservation_id}{managementnode} = 
$management_node_info;
                
                # Retrieve the user info and add to the hash
                my $user_id = $request_info->{userid};
-               my $user_info = get_user_info($user_id, 0, 1);
+               my $user_info = get_user_info($user_id, 0, $no_cache);
                $request_info->{user} = $user_info;
                
                my $imagemeta_root_access = 
$request_info->{reservation}{$reservation_id}{image}{imagemeta}{rootaccess};
@@ -3899,7 +3919,7 @@ EOF
        
        $vmhost_info->{vmprofile}{vmpath} = 
$vmhost_info->{vmprofile}{datastorepath} if !$vmhost_info->{vmprofile}{vmpath};
        $vmhost_info->{vmprofile}{virtualdiskpath} = 
$vmhost_info->{vmprofile}{vmpath} if 
!$vmhost_info->{vmprofile}{virtualdiskpath};
-       
+
        notify($ERRORS{'DEBUG'}, 0, "retrieved VM host $vmhost_id info, 
computer: $vmhost_info->{computer}{hostname}");
        $ENV{vmhost_info}{$vmhost_id} = $vmhost_info;
        return $ENV{vmhost_info}{$vmhost_id};
@@ -6882,8 +6902,11 @@ sub get_computer_info {
                notify($ERRORS{'WARNING'}, 0, "computer identifier argument was 
not supplied");
                return;
        }
-       
-       return $ENV{computer_info}{$computer_identifier} if (!$no_cache && 
$ENV{computer_info}{$computer_identifier});
+
+       if (!$no_cache && defined($ENV{computer_info}{$computer_identifier})) {
+               return $ENV{computer_info}{$computer_identifier};
+       }
+       notify($ERRORS{'DEBUG'}, 0, "retrieving info for computer 
$computer_identifier");
        
        # Get a hash ref containing the database column names
        my $database_table_columns = get_database_table_columns();
@@ -6895,7 +6918,6 @@ sub get_computer_info {
                'module',
                'schedule',
                'platform',
-               'nathost',
        );
        
        # Construct the select statement
@@ -6935,10 +6957,6 @@ ON (
 )
 LEFT JOIN (schedule) ON (schedule.id = computer.scheduleid)
 LEFT JOIN (module AS predictivemodule) ON (predictivemodule.id = 
computer.predictivemoduleid)
-LEFT JOIN (nathost, nathostcomputermap) ON (
-       nathostcomputermap.computerid = computer.id
-       AND nathostcomputermap.nathostid = nathost.id
-)
 
 WHERE
 computer.deleted != '1'
@@ -6996,6 +7014,8 @@ EOF
                }
        }
        
+       my $computer_id = $computer_info->{id};
+       
        # Set the short name of the computer based on the hostname
        my $computer_hostname = $computer_info->{hostname};
        my ($computer_shortname) = $computer_hostname =~ /^([^\.]+)/;
@@ -7054,7 +7074,12 @@ EOF
                }
        }
        
-       #notify($ERRORS{'DEBUG'}, 0, "retrieved info for computer 
'$computer_identifier':\n" . format_data($computer_info));
+       my $nathost_info = get_computer_nathost_info($computer_id, $no_cache);
+       if ($nathost_info) {
+               $computer_info->{nathost} = $nathost_info;
+       }
+       
+       notify($ERRORS{'DEBUG'}, 0, "retrieved info for computer: 
$computer_identifier");
        $ENV{computer_info}{$computer_identifier} = $computer_info;
        $ENV{computer_info}{$computer_identifier}{RETRIEVAL_TIME} = time;
        return $ENV{computer_info}{$computer_identifier};
@@ -7062,6 +7087,456 @@ EOF
 
 #/////////////////////////////////////////////////////////////////////////////
 
+=head2 get_computer_nathost_info
+
+ Parameters  : $computer_identifier
+ Returns     : hash reference
+ Description : Retrieves nathost info if a nathost is mapped to the computer 
via
+               the nathostcomputermap table. Example:
+                                       {
+                                         "HOSTNAME" => "nat1.vcl.org",
+                                         "datedeleted" => undef,
+                                         "deleted" => 0,
+                                         "id" => 2,
+                                         "natIP" => "x.x.x.x",
+                                         "nathostcomputermap" => {
+                                                "computerid" => 3591,
+                                                "nathostid" => 2
+                                         },
+                                         "resource" => {
+                                                "id" => 6185,
+                                                "resourcetype" => {
+                                                       "id" => 16,
+                                                       "name" => 
"managementnode"
+                                                },
+                                                "resourcetypeid" => 16,
+                                                "subid" => 8
+                                         },
+                                         "resourceid" => 6185
+                                       }
+
+=cut
+
+sub get_computer_nathost_info {
+       my ($computer_identifier, $no_cache) = @_;
+       if (!defined($computer_identifier)){
+               notify($ERRORS{'WARNING'}, 0, "computer identifier argument was 
not supplied");
+               return;
+       }
+       
+       return $ENV{nathost_info}{$computer_identifier} if (!$no_cache && 
$ENV{nathost_info}{$computer_identifier});
+       
+       # Get a hash ref containing the database column names
+       my $database_table_columns = get_database_table_columns();
+       
+       my @tables = (
+               'nathost',
+               'nathostcomputermap',
+               'resource',
+               'resourcetype',
+       );
+       
+       # Construct the select statement
+       my $select_statement = "SELECT DISTINCT\n";
+       
+       # Get the column names for each table and add them to the select 
statement
+       for my $table (@tables) {
+               my @columns = @{$database_table_columns->{$table}};
+               for my $column (@columns) {
+                       $select_statement .= "$table.$column AS 
'$table-$column',\n";
+               }
+       }
+       
+       # Remove the comma after the last column line
+       $select_statement =~ s/,$//;
+       
+       # Complete the select statement
+       $select_statement .= <<EOF;
+FROM
+computer,
+nathostcomputermap,
+nathost,
+resource,
+resourcetype
+
+WHERE
+nathostcomputermap.computerid = computer.id
+AND nathostcomputermap.nathostid = nathost.id
+AND nathost.resourceid = resource.id
+AND resource.resourcetypeid = resourcetype.id
+AND
+EOF
+
+       # If the computer identifier is all digits match it to computer.id
+       # Otherwise, match computer.hostname
+       if ($computer_identifier =~ /^\d+$/) {
+               $select_statement .= "computer.id = \'$computer_identifier\'";
+       }
+       else {
+               $select_statement .= "computer.hostname REGEXP 
'$computer_identifier(\\\\.|\$)'";
+       }
+       
+       # Call the database select subroutine
+       my @selected_rows = database_select($select_statement);
+
+       if (!@selected_rows) {
+               notify($ERRORS{'DEBUG'}, 0, "NAT host is not mapped to computer 
$computer_identifier");
+               return {};
+       }
+       elsif (scalar @selected_rows > 1) {
+               notify($ERRORS{'WARNING'}, 0, "unable to determine NAT host 
mapped to computer $computer_identifier, " . scalar @selected_rows . " rows 
were returned from database select statement:\n$select_statement");
+               return;
+       }
+       
+       # Get the single row returned from the select statement
+       my $row = $selected_rows[0];
+       
+       # Construct a hash with all of the computer info
+       my $nathost_info;
+       
+       # Loop through all the columns returned
+       for my $key (keys %$row) {
+               my $value = $row->{$key};
+               
+               # Split the table-column names
+               my ($table, $column) = $key =~ /^([^-]+)-(.+)/;
+               
+               # Add the values for the primary table to the hash
+               # Add values for other tables under separate keys
+               if ($table eq $tables[0]) {
+                       $nathost_info->{$column} = $value;
+               }
+               elsif ($table eq 'resourcetype') {
+                       $nathost_info->{resource}{resourcetype}{$column} = 
$value;
+               }
+               else {
+                       $nathost_info->{$table}{$column} = $value;
+               }
+       }
+       
+       $nathost_info->{HOSTNAME} = '<unknown>';
+       
+       my $resource_id = $nathost_info->{resource}{id};
+       my $resource_type = $nathost_info->{resource}{resourcetype}{name};
+       my $resource_subid = $nathost_info->{resource}{subid};
+       if ($resource_type eq 'managementnode') {
+               my $management_node_info = 
get_management_node_info($resource_subid) || {};
+               $nathost_info->{HOSTNAME} = $management_node_info->{hostname};
+       }
+       elsif ($resource_type eq 'computer') {
+               my $computer_info = get_computer_info($resource_subid) || {};
+               $nathost_info->{HOSTNAME} = $computer_info->{hostname};
+       }
+       else {
+               notify($ERRORS{'WARNING'}, 0, "NAT host resource type is not 
supported: $resource_type, resource ID: $resource_id");
+       }
+       
+       notify($ERRORS{'DEBUG'}, 0, "retrieved info for NAT host mapped to 
computer computer $computer_identifier:\n" . format_data($nathost_info));
+       $ENV{nathost_info}{$computer_identifier} = $nathost_info;
+       return $ENV{nathost_info}{$computer_identifier};
+}
+
+#/////////////////////////////////////////////////////////////////////////////
+
+=head2 get_nathost_assigned_public_ports
+
+ Parameters  : $nathost_id
+ Returns     : array
+ Description : Retrieves a list of natport.publicport values for the nathost
+               specified by the argument.
+
+=cut
+
+sub get_nathost_assigned_public_ports {
+       my ($nathost_id) = @_;
+       if (!defined($nathost_id)) {
+               notify($ERRORS{'WARNING'}, 0, "nathost ID argument was not 
supplied");
+               return;
+       }
+       
+       my $select_statement = "SELECT publicport FROM natport WHERE nathostid 
= $nathost_id ORDER BY publicport ASC";
+       my @selected_rows = database_select($select_statement);
+       my @ports;
+       for my $row (@selected_rows) {
+               push @ports, $row->{publicport};
+       }
+       
+       if (@ports) {
+               notify($ERRORS{'DEBUG'}, 0, "retrieved assigned public ports 
for nathost $nathost_id: " . join(", ", @ports));
+       }
+       else {
+               notify($ERRORS{'DEBUG'}, 0, "no public ports are assigned for 
nathost $nathost_id");
+       }
+       return @ports;
+}
+
+#/////////////////////////////////////////////////////////////////////////////
+
+=head2 populate_reservation_natport
+
+ Parameters  : $reservation_id
+ Returns     : boolean
+ Description : Populates the natport table for a reservation if the computer is
+               mapped to a nathost. The natport table is checked for each
+               connect method port assigned to each connect method for the
+               reservation.
+
+=cut
+
+sub populate_reservation_natport {
+       my ($reservation_id) = @_;
+       if (!defined($reservation_id)) {
+               notify($ERRORS{'WARNING'}, 0, "reservation ID argument was not 
supplied");
+               return;
+       }
+       
+       my $request_info = {get_reservation_request_info($reservation_id, 0)};
+       my $computer_id = 
$request_info->{reservation}{$reservation_id}{computerid};
+       my $computer_name = 
$request_info->{reservation}{$reservation_id}{computer}{SHORTNAME};
+       my $imagerevision_id = 
$request_info->{reservation}{$reservation_id}{imagerevision}{id};
+       
+       my $nathost_info = 
$request_info->{reservation}{$reservation_id}{computer}{nathost};
+       my $nathost_id = $nathost_info->{id};
+       my $nathost_hostname = $nathost_info->{HOSTNAME};
+       my $nathost_public_ip_address = $nathost_info->{natIP};
+       
+       # Make sure the nathost info is defined
+       if (!defined($nathost_id)) {
+               notify($ERRORS{'DEBUG'}, 0, "natport table does not need to be 
populated, computer $computer_id is not mapped to a NAT host");
+               return 1;
+       }
+       notify($ERRORS{'DEBUG'}, 0, "computer $computer_id is mapped to NAT 
host $nathost_hostname ($nathost_hostname)");
+       
+       # Retrieve the connect method info - do not use cached info
+       my $connect_method_info = get_connect_method_info($imagerevision_id, 1);
+       
+       # Retrieve the ports already assigned to the nathost
+       my @assigned_ports = get_nathost_assigned_public_ports($nathost_id);
+       
+       # Put the assigned ports into a hash for easy checking
+       my %assigned_port_hash = map { $_ => 1 } @assigned_ports;
+       
+       my %available_port_hash;
+       
+       # Retrieve and parse the natport_ranges variable
+       my $natport_ranges_variable = get_variable('natport_ranges') || 
'49152-65535';
+       my @natport_ranges = split(/[,;]+/, $natport_ranges_variable);
+       for my $natport_range (@natport_ranges) {
+               my ($start_port, $end_port) = $natport_range =~ /(\d+)-(\d+)/g;
+               if (!defined($start_port)) {
+                       notify($ERRORS{'WARNING'}, 0, "unable to parse NAT port 
range: '$natport_range'");
+                       next;
+               }
+               
+               # Make sure port range isn't backwards
+               if ($end_port < $start_port) {
+                       my $start_port_temp = $start_port;
+                       $start_port = $end_port;
+                       $end_port = $start_port_temp;
+               }
+               
+               # Loop through all of the ports in the range, check if already 
assigned
+               for (my $port = $start_port; $port<=$end_port; $port++) {
+                       if (!defined($assigned_port_hash{$port})) {
+                               $available_port_hash{$port} = 1;
+                       }
+               }
+       }
+       
+       # Loop through the connect methods
+       # Check if a public port has been assigned for each
+       for my $connect_method_id (sort keys %$connect_method_info) {
+               my $connect_method_port_info = 
$connect_method_info->{$connect_method_id}{connectmethodport};
+               
+               CONNECT_METHOD_PORT_ID: for my $connect_method_port_id (sort 
keys %$connect_method_port_info) {
+                       my $connect_method_port = 
$connect_method_port_info->{$connect_method_port_id};
+                       
+                       if (defined($connect_method_port->{natport})) {
+                               notify($ERRORS{'DEBUG'}, 0, "NAT public port is 
already assigned for connect method ID: $connect_method_id, port ID: 
$connect_method_port_id\n" . format_data($connect_method_port->{natport}));
+                               next CONNECT_METHOD_PORT_ID;
+                       }
+                       
+                       # Select a random port from the list of available ports
+                       my @available_ports = sort keys %available_port_hash;
+                       my $available_port_count = scalar(@available_ports);
+                       if (!$available_port_count) {
+                               notify($ERRORS{'CRITICAL'}, 0, "no NAT public 
ports are available for NAT host $nathost_hostname ($nathost_id)");
+                               return;
+                       }
+                       my $random_index =  int(rand($available_port_count));
+                       my $public_port = $available_ports[$random_index];
+                       
+                       # Remove the selected port from the available port hash
+                       delete $available_port_hash{$public_port};
+                       
+                       # Make multiple attempts, it's possible 2 reservations 
will attempt to assign the same public port at the same time
+                       # Using random ports helps avoid collisions
+                       # TODO: add semaphore
+                       my $attempt_limit = 5;
+                       for (my $attempt = 1; $attempt <= $attempt_limit; 
$attempt++) {
+                               sleep_uninterrupted(1);
+                               if (insert_natport($reservation_id, 
$nathost_id, $connect_method_port_id, $public_port)) {
+                                       next CONNECT_METHOD_PORT_ID;
+                               }
+                       }
+                       notify($ERRORS{'CRITICAL'}, 0, "failed to insert 
natport entry after making $attempt_limit attempts:\n" .
+                               "connectmethod ID: $connect_method_id\n" .
+                               "connectmethodport ID: 
$connect_method_port_id\n" .
+                               "reservation ID: $reservation_id\n" .
+                               "nathost ID: $nathost_id\n" .
+                               "public port: $public_port"
+                       );
+                       return;
+               }
+       }
+       
+       # Get the connect method info again to verify all ports are assigned a 
NAT public port
+       my $info_string = "";
+       $connect_method_info = get_connect_method_info($imagerevision_id, 1);
+       for my $connect_method_id (sort keys %$connect_method_info) {
+               my $connect_method = $connect_method_info->{$connect_method_id};
+               my $connect_method_name = $connect_method->{name};
+               
+               for my $connect_method_port_id (sort keys 
%{$connect_method->{connectmethodport}}) {
+                       my $connect_method_port = 
$connect_method->{connectmethodport}{$connect_method_port_id};
+                       my $protocol = $connect_method_port->{protocol};
+                       my $port = $connect_method_port->{port};
+                       
+                       my $nat_port = $connect_method_port->{natport};
+                       my $public_port = $nat_port->{publicport};
+                       if (!defined($nat_port)) {
+                               notify($ERRORS{'WARNING'}, 0, "NAT public port 
is not assigned for connect method ID: $connect_method_id, port ID: 
$connect_method_port_id");
+                               return;
+                       }
+                       $info_string .= "$connect_method_name: 
$nathost_public_ip_address:$public_port --> $computer_name:$port ($protocol)\n";
+               }
+       }
+       notify($ERRORS{'DEBUG'}, 0, "NAT port forwarding 
information:\n$info_string");
+       return 1;
+}
+
+#/////////////////////////////////////////////////////////////////////////////
+
+=head2 insert_natport
+
+ Parameters  : $reservation_id, $nathost_id, $connect_method_port_id, 
$public_port
+ Returns     : boolean
+ Description : Inserts an entry into the natport table.
+
+=cut
+
+sub insert_natport {
+       my ($reservation_id, $nathost_id, $connect_method_port_id, 
$public_port) = @_;
+       if (!defined($reservation_id)) {
+               notify($ERRORS{'WARNING'}, 0, "reservation ID argument was not 
supplied");
+               return;
+       }
+       elsif (!defined($nathost_id)) {
+               notify($ERRORS{'WARNING'}, 0, "nathost ID argument was not 
supplied");
+               return;
+       }
+       elsif (!defined($connect_method_port_id)) {
+               notify($ERRORS{'WARNING'}, 0, "connect method port ID argument 
was not supplied");
+               return;
+       }
+       elsif (!defined($public_port)) {
+               notify($ERRORS{'WARNING'}, 0, "public port argument was not 
supplied");
+               return;
+       }
+       
+       my $insert_statement = <<EOF;
+INSERT INTO
+natport
+(
+   reservationid,
+   nathostid,
+   connectmethodportid,
+   publicport
+)
+VALUES
+(
+   $reservation_id,
+   $nathost_id,
+   $connect_method_port_id,
+   $public_port
+)
+EOF
+
+       my $result = database_execute($insert_statement);
+       if ($result) {
+               notify($ERRORS{'DEBUG'}, 0, "inserted entry into natport 
table:\nreservation: $reservation_id\nnathost ID: 
$nathost_id\nconnectmethodport ID: $connect_method_port_id\npublic port: 
$public_port");
+               return 1;
+       }
+       else {
+               notify($ERRORS{'WARNING'}, 0, "failed to insert entry into 
natport table\nreservation: $reservation_id\nnathost ID: 
$nathost_id\nconnectmethodport ID: $connect_method_port_id\npublic port: 
$public_port");
+               return 0;
+       }
+}
+       
+
+#/////////////////////////////////////////////////////////////////////////////
+
+=head2 get_reservation_request_id
+
+ Parameters  : $reservation_id, $no_cache (optional)
+ Returns     : integer
+ Description : Retrieves the request ID assigned of a reservation.
+
+=cut
+
+sub get_reservation_request_id {
+       my ($reservation_id, $no_cache) = @_;
+       if (!defined($reservation_id)) {
+               notify($ERRORS{'WARNING'}, 0, "reservation ID argument was not 
supplied");
+               return;
+       }
+       
+       if (!$no_cache && 
defined($ENV{reservation_request_id}{$reservation_id})) {
+               return $ENV{reservation_request_id}{$reservation_id};
+       }
+       
+       my $select_statement = "SELECT requestid FROM reservation WHERE id = 
'$reservation_id'";
+       my @selected_rows = database_select($select_statement);
+       if (!@selected_rows) {
+               notify($ERRORS{'WARNING'}, 0, "failed to retrieve request ID 
for reservation $reservation_id");
+               return;
+       }
+       
+       my $row = $selected_rows[0];
+       my $request_id = $row->{requestid};
+       notify($ERRORS{'DEBUG'}, 0, "retrieved reservation $reservation_id 
request ID: $request_id");
+       $ENV{reservation_request_id}{$reservation_id} = $request_id;
+       return $request_id;
+}
+
+#/////////////////////////////////////////////////////////////////////////////
+
+=head2 get_reservation_request_info
+
+ Parameters  : $reservation_id, $no_cache (optional)
+ Returns     : hash reference
+ Description : Retrieves the request info for a reservation.
+
+=cut
+
+sub get_reservation_request_info {
+       my ($reservation_id, $no_cache) = @_;
+       if (!defined($reservation_id)) {
+               notify($ERRORS{'WARNING'}, 0, "reservation ID argument was not 
supplied");
+               return;
+       }
+       
+       my $request_id = get_reservation_request_id($reservation_id, $no_cache);
+       if (!$request_id) {
+               notify($ERRORS{'WARNING'}, 0, "unable to retrieve request info 
for reservation $reservation_id, failed to determine request ID for 
reservation");
+               return;
+       }
+       
+       return get_request_info($request_id, $no_cache);
+}
+
+#/////////////////////////////////////////////////////////////////////////////
+
 =head2 get_computer_ids
 
  Parameters  : $computer_identifier
@@ -7897,11 +8372,15 @@ sub reservation_being_processed {
 sub run_command {
        my ($command, $no_output) = @_;
        
-       my $output_string = `$command 2>&1`;
+       my $output_string;
+       $output_string = `$command 2>&1`;
+       $output_string = '' unless $output_string;
+       
        my $exit_status = $?;
        if ($exit_status >= 0) {
                $exit_status = $exit_status >> 8;
        }
+
        
        # Remove any trailing newlines from the output
        chomp $output_string;
@@ -9611,7 +10090,52 @@ sub kill_child_processes {
  Parameters  : $imagerevision_id, $no_cache (optional)
  Returns     : hash reference
  Description : Returns the connect methods for the image revision specified as
-               the argument.
+               the argument. Example:
+                                       {
+                                        4 => {
+                                               "RETRIEVAL_TIME" => 
"1417709281",
+                                               "connectmethodmap" => {
+                                                 "OSid" => 36,
+                                                 "OStypeid" => undef,
+                                                 "autoprovisioned" => undef,
+                                                 "connectmethodid" => 4,
+                                                 "disabled" => 0,
+                                                 "imagerevisionid" => undef
+                                               },
+                                               "connectmethodport" => {
+                                                 35 => {
+                                                        "connectmethodid" => 4,
+                                                        "id" => 35,
+                                                        "natport" => {
+                                                               
"connectmethodportid" => 35,
+                                                               "nathostid" => 
2,
+                                                               "publicport" => 
56305,
+                                                               "reservationid" 
=> 3115
+                                                        },
+                                                        "port" => 3389,
+                                                        "protocol" => "TCP"
+                                                 },
+                                                 37 => {
+                                                        "connectmethodid" => 4,
+                                                        "id" => 37,
+                                                        "natport" => {
+                                                               
"connectmethodportid" => 37,
+                                                               "nathostid" => 
2,
+                                                               "publicport" => 
63058,
+                                                               "reservationid" 
=> 3115
+                                                        },
+                                                        "port" => 3389,
+                                                        "protocol" => "UDP"
+                                                 }
+                                               },
+                                               "description" => "Linux xRDP 
(Remote Desktop Protocol)",
+                                               "id" => 4,
+                                               "name" => "xRDP",
+                                               "servicename" => "xrdp",
+                                               "startupscript" => undef
+                                        }
+                                 }
+
 
 =cut
 
@@ -9646,6 +10170,7 @@ sub get_connect_method_info {
                'connectmethod',
                'connectmethodport',
                'connectmethodmap',
+               'natport',
        );
        
        # Construct the select statement
@@ -9666,10 +10191,13 @@ sub get_connect_method_info {
        $select_statement .= <<EOF;
 FROM
 connectmethod,
-connectmethodport,
+
+connectmethodport
+LEFT JOIN natport ON (natport.connectmethodportid = connectmethodport.id),
+
 connectmethodmap,
-imagerevision
 
+imagerevision
 LEFT JOIN image ON (image.id = imagerevision.imageid)
 LEFT JOIN OS ON (OS.id = image.OSid)
 LEFT JOIN OStype ON (OStype.name = OS.type)
@@ -9712,15 +10240,18 @@ EOF
                        # Split the table-column names
                        my ($table, $column) = $key =~ /^([^-]+)-(.+)/;
                        
-                       # Add the values for the primary table to the hash
-                       # Add values for other tables under separate keys
                        if ($table eq 'connectmethod') {
                                
$connect_method_info->{$connectmethod_id}{$column} = $value;
                        }
                        elsif ($table eq 'connectmethodport') {
-                               my $protocol = 
$row->{"connectmethodport-protocol"};
-                               my $port = $row->{"connectmethodport-port"};
-                               
$connect_method_info->{$connectmethod_id}{$table}{$protocol}{$port} = 1;
+                               my $connectmethodport_id = 
$row->{"connectmethodport-id"};
+                               
$connect_method_info->{$connectmethod_id}{'connectmethodport'}{$connectmethodport_id}{$column}
 = $value;
+                       }
+                       elsif ($table eq 'natport') {
+                               if (defined($value)) {
+                                       my $connectmethodport_id = 
$row->{"connectmethodport-id"};
+                                       
$connect_method_info->{$connectmethod_id}{'connectmethodport'}{$connectmethodport_id}{'natport'}{$column}
 = $value;
+                               }
                        }
                        else {
                                
$connect_method_info->{$connectmethod_id}{$table}{$column} = $value;
@@ -11932,7 +12463,6 @@ EOF
 
 =cut
 
-
 sub get_provisioning_osinstalltype_info {
        my ($provisioning_id) = @_;
        if (!defined($provisioning_id)) {


Reply via email to