You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@vcl.apache.org by ar...@apache.org on 2015/02/05 21:04:44 UTC

svn commit: r1657678 - in /vcl/trunk: managementnode/lib/VCL/DataStructure.pm managementnode/lib/VCL/Module/OS.pm managementnode/lib/VCL/utils.pm mysql/update-vcl.sql mysql/vcl.sql

Author: arkurth
Date: Thu Feb  5 20:04:44 2015
New Revision: 1657678

URL: http://svn.apache.org/r1657678
Log:
VCL-174
Added sublog.id column to vcl.sql and update-vcl.sql, which is referenced by the natlog table.

Updated natlog table in vcl.sql and update-vcl.sql to reference sublog.id instead of containing a computer ID value.

Updated DataStructure.pm to reflect the schema changes.

Added utils.pm::get_request_log_info. This is called from DataStructure.pm::get_log_data. I reworked get_log_data because it was only retrieving data for a single sublog entry.

Added utils.pm::update_reservation_natlog. This is called from get_request_info when the NAT ports are determined.

Added checks to OS.pm::process_connect_methods to ensure that the NAT host firewall object implements the 'configure_nat' and 'configure_nat_reservation' subroutines before attempting to call them.

Modified:
    vcl/trunk/managementnode/lib/VCL/DataStructure.pm
    vcl/trunk/managementnode/lib/VCL/Module/OS.pm
    vcl/trunk/managementnode/lib/VCL/utils.pm
    vcl/trunk/mysql/update-vcl.sql
    vcl/trunk/mysql/vcl.sql

Modified: vcl/trunk/managementnode/lib/VCL/DataStructure.pm
URL: http://svn.apache.org/viewvc/vcl/trunk/managementnode/lib/VCL/DataStructure.pm?rev=1657678&r1=1657677&r2=1657678&view=diff
==============================================================================
--- vcl/trunk/managementnode/lib/VCL/DataStructure.pm (original)
+++ vcl/trunk/managementnode/lib/VCL/DataStructure.pm Thu Feb  5 20:04:44 2015
@@ -167,12 +167,7 @@ $SUBROUTINE_MAPPINGS{log_remote_ip} = '$
 $SUBROUTINE_MAPPINGS{log_imageid} = '$self->request_data->{log}{imageid}';
 $SUBROUTINE_MAPPINGS{log_size} = '$self->request_data->{log}{size}';
 
-$SUBROUTINE_MAPPINGS{sublog_imageid} = '$self->request_data->{log}{imageid}';
-$SUBROUTINE_MAPPINGS{sublog_imagerevisionid} = '$self->request_data->{log}{imagerevisionid}';
-$SUBROUTINE_MAPPINGS{sublog_computerid} = '$self->request_data->{log}{computerid}';
-$SUBROUTINE_MAPPINGS{sublog_ip_address} = '$self->request_data->{log}{IPaddress}';
-$SUBROUTINE_MAPPINGS{sublog_managementnodeid} = '$self->request_data->{log}{managementnodeid}';
-$SUBROUTINE_MAPPINGS{sublog_predictivemoduleid} = '$self->request_data->{log}{predictivemoduleid}';
+$SUBROUTINE_MAPPINGS{sublog_id} = '$self->request_data->{reservation}{RESERVATION_ID}{SUBLOG_ID}';
 
 #$SUBROUTINE_MAPPINGS{request_reservationid} = '$self->request_data->{RESERVATIONID}';
 $SUBROUTINE_MAPPINGS{reservation_id} = '$self->request_data->{RESERVATIONID}';
@@ -852,7 +847,11 @@ sub _automethod : Automethod {
 			
 			if ($self->get_log_data()) {
 				# Log data was retrieved, check if requested data is now populated
-				if (!eval "defined $hash_path") {
+				if (eval "defined $hash_path") {
+					$return_value = eval $hash_path;
+					notify($ERRORS{'DEBUG'}, 0, "log data was retrieved and corresponding data has been initialized for $method_name: $return_value");
+				}
+				else {
 					notify($ERRORS{'WARNING'}, 0, "log data was retrieved but corresponding data has not been initialized for $method_name: $hash_path", $self->request_data) if $show_warnings;
 					return sub { };
 				}
@@ -1398,88 +1397,73 @@ sub print_subroutines {
 
 =head2 get_log_data
 
- Parameters  : log ID (optional)
+ Parameters  : none
  Returns     : hash reference
  Description : Retrieves data from the log and sublog tables for the log ID
                either specified via an argument or the log ID for the
-					reservation represented by the DataStructure object.
+               reservation represented by the DataStructure object.
 
 =cut
 
 sub get_log_data {
-	my $self;
-	my $argument = shift;
-	my $request_log_id;
-	
-	# Check if subroutine was called as an object method
-	if (ref($argument) =~ /DataStructure/) {
-		# Subroutine was called as an object method, get next argument
-		$self = $argument;
-		$argument = shift;
-		
-		# If argument wasn't passed, attempt to get the log id from this DataStructure object
-		if (!$argument) {
-			# Get the log id and make sure it is set
-			$request_log_id = $self->get_request_log_id();
-			if (!$request_log_id) {
-				notify($ERRORS{'WARNING'}, 0, "log id was not passed as an argument and could not be retrieved from the existing DataStructure object");
-				return;
-			}
+	my $self = shift;
+	unless (ref($self) && $self->isa('VCL::DataStructure')) {
+		notify($ERRORS{'WARNING'}, 0, "subroutine can only be called as a VCL::DataStructure module object method");
+		return;
+	}
+	
+	my $current_reservation_id = $self->get_reservation_id();
+	my $request_id = $self->get_request_id();
+	my @reservation_ids = $self->get_reservation_ids();
+	
+	# Retrieve log info for all reservations
+	my $log_info = get_request_log_info($request_id) || return;
+	
+	$self->request_data->{log} = $log_info;
+	
+	# Get a mapping between computer to reservation IDs
+	# TODO: add sublog.reservationid column, this will no longer be necessary
+	my $computer_reservation_ids = {};
+	for my $reservation_id (@reservation_ids) {
+		my $reservation_data;
+		if ($reservation_id eq $current_reservation_id) {
+			$reservation_data = $self;
 		}
 		else {
-			$request_log_id = $argument;
+			$reservation_data = $self->get_reservation_data($reservation_id);
+		}	
+		if (!$reservation_data) {
+			notify($ERRORS{'WARNING'}, 0, "DataStructure object could not be retrieved for reservation $reservation_id");
+			next;
 		}
-	}
-	else {
-		$request_log_id = $argument;
 		
-		# Make sure log id was determined and is valid
-		if (!$request_log_id) {
-			notify($ERRORS{'WARNING'}, 0, "log id was not passed as an argument and subroutine was not called as an object method");
-			return;
+		my $reservation_computer_id = $reservation_data->get_computer_id();
+		if (!$reservation_computer_id) {
+			notify($ERRORS{'WARNING'}, 0, "computer ID could not be determined for reservation $reservation_id");
+			next;
 		}
+		
+		$computer_reservation_ids->{$reservation_computer_id} = $reservation_id;
 	}
 	
-	# Make sure log id was determined and is valid
-	if (!$request_log_id) {
-		notify($ERRORS{'WARNING'}, 0, "log id could not be determined");
-		return;
-	}
-	elsif ($request_log_id !~ /^\d+$/) {
-		notify($ERRORS{'WARNING'}, 0, "log id is not valid: $request_log_id");
-		return;
-	}
-	
-	# Construct a select statement 
-	my $sql_select_statement = "
-	SELECT
-	*
-	FROM
-	log
-	LEFT JOIN sublog ON sublog.logid = log.id
-	WHERE
-	log.id = $request_log_id
-	";
-	
-	# Call database_select() to execute the select statement and make sure 1 row was returned
-	my @select_rows = VCL::utils::database_select($sql_select_statement);
-	if (!scalar @select_rows == 1) {
-		notify($ERRORS{'WARNING'}, 0, "select statement returned " . scalar @select_rows . " rows:\n" . join("\n", $sql_select_statement));
-		return;
-	}
-	
-	# $select_rows[0] is a hash reference, the keys are the column names
-	# Loop through the column names and add the data to $self->request_data
-	my $row = $select_rows[0];
-	
-	my %data_hash;
-	foreach my $column_name (sort keys(%{$row})) {
-		# Get the data value for the column
-		my $data_value = $row->{$column_name};
-		$self->request_data->{log}{$column_name} = $data_value if !defined($self->request_data->{log}{$column_name});
+	for my $sublog_id (keys %{$log_info->{sublog}}) {
+		my $sublog_computer_id = $log_info->{sublog}{$sublog_id}{computerid};
+		if (!$sublog_computer_id) {
+			notify($ERRORS{'WARNING'}, 0, "computer ID is not defined for sublog $sublog_id:\n" . format_data($log_info));
+			next;
+		}
+		
+		my $reservation_id = $computer_reservation_ids->{$sublog_computer_id};
+		if (!$reservation_id) {
+			notify($ERRORS{'WARNING'}, 0, "computer ID is set to $sublog_computer_id for sublog ID $sublog_id, no reservation assigned to this request is assigned that computer ID");
+			next;
+		}
+		
+		$self->request_data->{reservation}{$reservation_id}{SUBLOG_ID} = $sublog_id;
+		$self->request_data->{reservation}{$reservation_id}{sublog} = $log_info->{sublog}{$sublog_id};
 	}
 	
-	notify($ERRORS{'DEBUG'}, 0, "retrieved log data for log id: $request_log_id");
+	notify($ERRORS{'DEBUG'}, 0, "updated DataStructure object with log and sublog data");
 	return $self->request_data->{log};
 }
 

Modified: vcl/trunk/managementnode/lib/VCL/Module/OS.pm
URL: http://svn.apache.org/viewvc/vcl/trunk/managementnode/lib/VCL/Module/OS.pm?rev=1657678&r1=1657677&r2=1657678&view=diff
==============================================================================
--- vcl/trunk/managementnode/lib/VCL/Module/OS.pm (original)
+++ vcl/trunk/managementnode/lib/VCL/Module/OS.pm Thu Feb  5 20:04:44 2015
@@ -2852,14 +2852,26 @@ sub process_connect_methods {
 		}
 		
 		# Perform general NAT configuration
-		if (!$self->nathost_os->firewall->configure_nat()) {
-			notify($ERRORS{'WARNING'}, 0, "unable to process connect methods, failed to configure NAT on $nathost_hostname");
+		if ($self->nathost_os->firewall->can('configure_nat')) {
+			if (!$self->nathost_os->firewall->configure_nat()) {
+				notify($ERRORS{'WARNING'}, 0, "unable to process connect methods, failed to configure NAT on $nathost_hostname");
+				return;
+			}
+		}
+		else {
+			notify($ERRORS{'CRITICAL'}, 0, "NAT not configured on $nathost_hostname, " . ref($self->nathost_os->firewall) . " does not implement a 'configure_nat' subroutine");
 			return;
 		}
 		
 		# Perform reservation-specific NAT configuration
-		if (!$self->nathost_os->firewall->configure_nat_reservation()) {
-			notify($ERRORS{'WARNING'}, 0, "unable to process connect methods, failed to configure NAT on $nathost_hostname for this reservation");
+		if ($self->nathost_os->firewall->can('configure_nat_reservation')) {
+			if (!$self->nathost_os->firewall->configure_nat_reservation()) {
+				notify($ERRORS{'WARNING'}, 0, "unable to process connect methods, failed to configure NAT on $nathost_hostname for this reservation");
+				return;
+			}
+		}
+		else {
+			notify($ERRORS{'CRITICAL'}, 0, "NAT not configured on $nathost_hostname for this reservation, " . ref($self->nathost_os->firewall) . " does not implement a 'configure_nat_reservation' subroutine");
 			return;
 		}
 	}
@@ -3897,7 +3909,7 @@ sub update_cluster {
 			push(@cluster_string, "child= $request_data->{reservation}{$rid}{computer}{IPaddress}" . "\n");
 			notify($ERRORS{'DEBUG'}, 0, "writing child=  $request_data->{reservation}{$rid}{computer}{IPaddress}");
 		}
-
+		
 		#Create iptables rule for each node in cluster on the node being processed
 		# Could slow things down for large clusters, but they can communicate with each other
 		if ($self->can('enable_firewall_port')) {

Modified: vcl/trunk/managementnode/lib/VCL/utils.pm
URL: http://svn.apache.org/viewvc/vcl/trunk/managementnode/lib/VCL/utils.pm?rev=1657678&r1=1657677&r2=1657678&view=diff
==============================================================================
--- vcl/trunk/managementnode/lib/VCL/utils.pm (original)
+++ vcl/trunk/managementnode/lib/VCL/utils.pm Thu Feb  5 20:04:44 2015
@@ -173,6 +173,7 @@ our @EXPORT = qw(
 	get_request_current_state_name
 	get_request_end
 	get_request_info
+	get_request_log_info
 	get_reservation_accounts
 	get_reservation_computerloadlog_entries
 	get_reservation_computerloadlog_time
@@ -272,6 +273,7 @@ our @EXPORT = qw(
 	update_request_checkuser
 	update_request_state
 	update_reservation_lastcheck
+	update_reservation_natlog
 	update_reservation_password
 	update_sublog_ipaddress
 	xml_string_to_hash
@@ -3093,11 +3095,14 @@ EOF
 				if (!populate_reservation_natport($reservation_id)) {
 					notify($ERRORS{'CRITICAL'}, 0, "failed to populate natport table for reservation");
 				}
+				if (!update_reservation_natlog($reservation_id)) {
+					notify($ERRORS{'CRITICAL'}, 0, "failed to populate natlog table for reservation");
+				}
 			}
 		}
 		
 		# Add the connect method info to the hash
-		my $connect_method_info = get_connect_method_info($imagerevision_id, $no_cache);
+		my $connect_method_info = get_connect_method_info($imagerevision_id, 0);
 		$request_info->{reservation}{$reservation_id}{connect_methods} = $connect_method_info;
 		
 		# Add the managementnode info to the hash
@@ -3177,6 +3182,133 @@ EOF
 
 #/////////////////////////////////////////////////////////////////////////////
 
+=head2  get_request_log_info
+
+ Parameters  : $request_id, $no_cache (optional)
+ Returns     : hash reference
+ Description : Retrieves data from the log and sublog tables for the request.
+               A hash is constructed. Example:
+               {
+                 "computerid" => 3588,
+                 "ending" => "none",
+                 "finalend" => "0000-00-00 00:00:00",
+                 "id" => 5354,
+                 ...
+                 "sublog" => {
+                   74 => {
+                     "IPaddress" => undef,
+                     "blockEnd" => undef,
+                     "blockRequestid" => undef,
+                     "blockStart" => undef,
+                     "computerid" => 3588,
+                     "hostcomputerid" => undef,
+                     "id" => 74,
+                     "imageid" => 3081,
+                     "imagerevisionid" => 9147,
+                     "logid" => 5354,
+                     "managementnodeid" => 8,
+                     "predictivemoduleid" => 8
+                   },
+                   75 => {
+                     "IPaddress" => undef,
+                     ...
+                   },
+                 },
+                 "userid" => 2870,
+                 "wasavailable" => 0
+               }
+
+=cut
+
+sub get_request_log_info {
+	my ($request_id, $no_cache) = @_;
+	if (!defined($request_id)) {
+		notify($ERRORS{'WARNING'}, 0, "request ID argument was not specified");
+		return;
+	}
+	
+	if (!$no_cache && defined($ENV{log_info}{$request_id})) {
+		return $ENV{log_info}{$request_id};
+	}
+	
+	# Get a hash ref containing the database column names
+	my $database_table_columns = get_database_table_columns();
+	
+	my %tables = (
+		'log' => 'log',
+		'sublog' => 'sublog',
+	);
+	
+	# 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_alias (keys %tables) {
+		my $table_name = $tables{$table_alias};
+		my @columns = @{$database_table_columns->{$table_name}};
+		for my $column (@columns) {
+			$select_statement .= "$table_alias.$column AS '$table_alias-$column',\n";
+		}
+	}
+	
+	# Remove the comma after the last column line
+	$select_statement =~ s/,$//;
+	
+	# Complete the select statement
+	$select_statement .= <<EOF;
+FROM
+request,
+log,
+sublog
+WHERE
+request.id = $request_id
+AND log.id = request.logid
+AND sublog.logid = log.id
+EOF
+
+	# Call the database select subroutine
+	my @rows = database_select($select_statement);
+	if (!@rows) {
+		notify($ERRORS{'WARNING'}, 0, "log info for request $request_id could not be retrieved from the database, select statement:\n$select_statement");
+		return;
+	}
+
+	# Build the hash
+	my $log_info;
+
+	for my $row (@rows) {
+		my $sublog_id = $row->{'sublog-id'};
+		if (!$sublog_id) {
+			notify($ERRORS{'WARNING'}, 0, "failed to retrieve log info for request $request_id, row does not contain a 'sublog-id' value:\n" . format_data($row));
+			return;
+		}
+		
+		# Loop through all the columns returned
+		for my $key (keys %$row) {
+			my $value = $row->{$key};
+			
+			# Split the table-column names
+			my ($table, $column) = $key =~ /^([^-]+)-(.+)/;
+			
+			if ($table eq 'log') {
+				$log_info->{$column} = $value;
+			}
+			elsif ($table eq 'sublog') {
+				$log_info->{$table}{$sublog_id}{$column} = $value;
+			}
+			else {
+				$log_info->{$table}{$column} = $value;
+			}
+		}
+	}
+	
+	$ENV{log_info}{$request_id} = $log_info;
+	#notify($ERRORS{'DEBUG'}, 0, "retrieved log info for request $request_id:\n" . format_data($log_info));
+	return $log_info;
+}
+
+#/////////////////////////////////////////////////////////////////////////////
+
 =head2 set_managementnode_state
 
  Parameters  : management node info, state
@@ -7548,6 +7680,76 @@ EOF
 		return 0;
 	}
 }
+
+#/////////////////////////////////////////////////////////////////////////////
+
+=head2 update_reservation_natlog
+
+ Parameters  : $reservation_id
+ Returns     : boolean
+ Description : Adds or updates an entry in the natlog table.
+
+=cut
+
+sub update_reservation_natlog {
+	my ($reservation_id) = @_;
+	if (!defined($reservation_id)) {
+		notify($ERRORS{'WARNING'}, 0, "reservation ID argument was not supplied");
+		return;
+	}
+	
+	my $insert_statement = <<EOF;
+INSERT IGNORE INTO
+natlog
+(
+   sublogid,
+   nathostresourceid,
+   publicIPaddress,
+   publicport,
+	internalIPaddress,
+   internalport,
+   protocol,
+   timestamp
+)
+(
+SELECT
+   sublog.id,
+   nathost.resourceid,
+   nathost.publicIPaddress,
+   natport.publicport,
+	nathost.internalIPaddress,
+   connectmethodport.port AS internalport,
+   connectmethodport.protocol,
+   NOW()
+   FROM
+   request,
+   reservation,
+   sublog,
+   natport,
+   nathost,
+   connectmethodport
+   WHERE
+   reservation.id = $reservation_id
+   AND reservation.requestid = request.id
+   AND request.logid = sublog.logid
+   AND sublog.computerid = reservation.computerid
+   AND natport.reservationid = reservation.id
+   AND natport.nathostid = nathost.id
+   AND natport.connectmethodportid = connectmethodport.id
+)
+ON DUPLICATE KEY UPDATE
+timestamp=VALUES(timestamp)
+EOF
+
+	if (database_execute($insert_statement)) {
+		notify($ERRORS{'DEBUG'}, 0, "updated natlog table for reservation $reservation_id");
+		return 1;
+	}
+	else {
+		notify($ERRORS{'WARNING'}, 0, "failed to update natlog table for reservation $reservation_id");
+		return 0;
+	}
+}
 
 #/////////////////////////////////////////////////////////////////////////////
 

Modified: vcl/trunk/mysql/update-vcl.sql
URL: http://svn.apache.org/viewvc/vcl/trunk/mysql/update-vcl.sql?rev=1657678&r1=1657677&r2=1657678&view=diff
==============================================================================
--- vcl/trunk/mysql/update-vcl.sql (original)
+++ vcl/trunk/mysql/update-vcl.sql Thu Feb  5 20:04:44 2015
@@ -87,6 +87,7 @@ BEGIN
   )
   THEN
     SET @statement_array = CONCAT('ALTER TABLE `', Database(), '`.', tableName, ' ADD COLUMN ', columnName, ' ', columnDefinition);
+    -- CALL PrintMessage((SELECT CONCAT('adding column: ', @statement_array)));
     PREPARE statement_string FROM @statement_array;
     EXECUTE statement_string;
   END IF;
@@ -1058,15 +1059,18 @@ CREATE TABLE IF NOT EXISTS `nathost` (
 -- 
 
 CREATE TABLE IF NOT EXISTS `natlog` (
-  `logid` int(10) unsigned NOT NULL,
-  `computerid` smallint(5) unsigned NOT NULL,
+  `sublogid` int(10) unsigned NOT NULL,
+  `nathostresourceid` mediumint(8) unsigned NOT NULL,
   `publicIPaddress` varchar(15) NOT NULL,
-  `internalIPaddress` varchar(15) NOT NULL,
   `publicport` smallint(5) unsigned NOT NULL,
+  `internalIPaddress` varchar(15) NOT NULL,
   `internalport` smallint(5) unsigned NOT NULL,
-  `protocol` enum('TCP','UDP') NOT NULL,
-  KEY `logid` (`logid`),
-  KEY `computerid` (`computerid`)
+  `protocol` enum('TCP','UDP') NOT NULL DEFAULT 'TCP',
+  `timestamp` datetime NOT NULL,
+  UNIQUE KEY `sublogid` (`sublogid`,`nathostresourceid`,`publicIPaddress`,`publicport`,`internalIPaddress`,`internalport`,`protocol`),
+  KEY `logid` (`sublogid`),
+  KEY `nathostid` (`nathostresourceid`),
+  KEY `nathostresourceid` (`nathostresourceid`)
 ) ENGINE=InnoDB DEFAULT CHARSET=latin1;
 
 -- --------------------------------------------------------
@@ -1278,6 +1282,7 @@ CALL AddIndexIfNotExists('statgraphcache
 -- Table structure change for table `sublog`
 --
 
+CALL AddColumnIfNotExists('sublog', 'id', "int(10) unsigned NOT NULL AUTO_INCREMENT PRIMARY KEY FIRST");
 CALL AddColumnIfNotExists('sublog', 'hostcomputerid', "smallint(5) unsigned default NULL");
 CALL AddColumnIfNotExists('sublog', 'blockRequestid', "mediumint(8) unsigned NOT NULL");
 CALL AddColumnIfNotExists('sublog', 'blockStart', "datetime NOT NULL");
@@ -2045,8 +2050,8 @@ CALL AddConstraintIfNotExists('nathost',
 -- Constraints for table `natlog`
 --
 
-CALL AddConstraintIfNotExists('natlog', 'computerid', 'computer', 'id', 'both', 'CASCADE');
-CALL AddConstraintIfNotExists('natlog', 'logid', 'log', 'id', 'both', 'CASCADE');
+CALL AddConstraintIfNotExists('natlog', 'sublogid', 'sublog', 'id', 'both', 'CASCADE');
+CALL AddConstraintIfNotExists('natlog', 'nathostresourceid', 'resource', 'id', 'update', 'CASCADE');
 
 -- --------------------------------------------------------
 

Modified: vcl/trunk/mysql/vcl.sql
URL: http://svn.apache.org/viewvc/vcl/trunk/mysql/vcl.sql?rev=1657678&r1=1657677&r2=1657678&view=diff
==============================================================================
--- vcl/trunk/mysql/vcl.sql (original)
+++ vcl/trunk/mysql/vcl.sql Thu Feb  5 20:04:44 2015
@@ -675,15 +675,18 @@ CREATE TABLE IF NOT EXISTS `nathost` (
 -- 
 
 CREATE TABLE IF NOT EXISTS `natlog` (
-  `logid` int(10) unsigned NOT NULL,
-  `computerid` smallint(5) unsigned NOT NULL,
+  `sublogid` int(10) unsigned NOT NULL,
+  `nathostresourceid` mediumint(8) unsigned NOT NULL,
   `publicIPaddress` varchar(15) NOT NULL,
-  `internalIPaddress` varchar(15) NOT NULL,
   `publicport` smallint(5) unsigned NOT NULL,
+  `internalIPaddress` varchar(15) NOT NULL,
   `internalport` smallint(5) unsigned NOT NULL,
-  `protocol` enum('TCP','UDP') NOT NULL,
-  KEY `logid` (`logid`),
-  KEY `computerid` (`computerid`)
+  `protocol` enum('TCP','UDP') NOT NULL DEFAULT 'TCP',
+  `timestamp` datetime NOT NULL,
+  UNIQUE KEY `sublogid` (`sublogid`,`nathostresourceid`,`publicIPaddress`,`publicport`,`internalIPaddress`,`internalport`,`protocol`),
+  KEY `logid` (`sublogid`),
+  KEY `nathostid` (`nathostresourceid`),
+  KEY `nathostresourceid` (`nathostresourceid`)
 ) ENGINE=InnoDB DEFAULT CHARSET=latin1;
 
 -- --------------------------------------------------------
@@ -1205,6 +1208,7 @@ CREATE TABLE IF NOT EXISTS `subimages` (
 -- 
 
 CREATE TABLE IF NOT EXISTS `sublog` (
+  `id` int(10) unsigned NOT NULL AUTO_INCREMENT,
   `logid` int(10) unsigned NOT NULL default '0',
   `imageid` smallint(5) unsigned NOT NULL default '0',
   `imagerevisionid` mediumint(8) unsigned NOT NULL,
@@ -1216,6 +1220,7 @@ CREATE TABLE IF NOT EXISTS `sublog` (
   `blockRequestid` mediumint(8) unsigned NOT NULL,
   `blockStart` datetime NOT NULL,
   `blockEnd` datetime NOT NULL,
+  PRIMARY KEY (`id`),
   KEY `logid` (`logid`),
   KEY `imageid` (`imageid`),
   KEY `imagerevisionid` (`imagerevisionid`),
@@ -2305,9 +2310,9 @@ ALTER TABLE `nathost` ADD CONSTRAINT FOR
 -- 
 -- Constraints for table `natlog`
 --
-ALTER TABLE `natlog` ADD CONSTRAINT FOREIGN KEY (`logid`) REFERENCES `log` (`id`) ON DELETE CASCADE ON UPDATE CASCADE;
-ALTER TABLE `natlog` ADD CONSTRAINT FOREIGN KEY (`computerid`) REFERENCES `computer` (`id`) ON DELETE CASCADE ON UPDATE CASCADE;
-
+ALTER TABLE `natlog` ADD CONSTRAINT FOREIGN KEY (`sublogid`) REFERENCES `sublog` (`id`) ON DELETE CASCADE ON UPDATE CASCADE;
+ALTER TABLE `natlog` ADD CONSTRAINT FOREIGN KEY (`nathostresourceid`) REFERENCES `resource` (`id`) ON UPDATE CASCADE;
+  
 -- 
 -- Constraints for table `nathostcomputermap`
 --