sub generate_private_key_file()

in managementnode/lib/VCL/Module/OS/Linux/ManagementNode.pm [761:861]


sub generate_private_key_file {
	my $self = shift;
	if (ref($self) !~ /VCL::Module/i) {
		notify($ERRORS{'CRITICAL'}, 0, "subroutine was called as a function, it must be called as a class method");
		return;
	}
	
	my $arguments_hash_ref = shift;
	if (defined($arguments_hash_ref) && !ref($arguments_hash_ref) || ref($arguments_hash_ref) ne 'HASH') {
		notify($ERRORS{'WARNING'}, 0, "argument was supplied but is not a hash reference:\n" . format_data($arguments_hash_ref));
		return;
	}
	
	my $private_key_file_path = $self->get_private_key_file_path();
	my $bits = 4096;
	
	# If provided and true, existing private key file will be deleted if it exists
	my $force = $arguments_hash_ref->{force};
	
	my $management_node_id = $self->data->get_management_node_id() || return;
	my $management_node_short_name = $self->data->get_management_node_short_name() || return;
	my $reservation_id = $self->data->get_reservation_id();
	
	notify($ERRORS{'DEBUG'}, 0, "*** attempting to generate a new private key file on $management_node_short_name: $private_key_file_path ***");
	
	# Make sure the private key file does not already exist
	if ($self->file_exists($private_key_file_path)) {
		if ($force) {
			(my $timestamp = makedatestring()) =~ s/\s+/_/g;
			my $backup_private_key_file_path = $private_key_file_path . "_$timestamp";
			if ($self->copy_file($private_key_file_path, $backup_private_key_file_path)) {
				notify($ERRORS{'OK'}, 0, "force argument was specified, existing private key file will be overwritten, created backup copy: $private_key_file_path --> $backup_private_key_file_path");
			}
			else {
				notify($ERRORS{'WARNING'}, 0, "failed to generate encryption keys, force argument was specified, existing private key file exists but failed to create backup copy: $private_key_file_path --> $backup_private_key_file_path");
				return;
			}
		}
		else {
			notify($ERRORS{'WARNING'}, 0, "failed to generate encryption keys, private key file already exists: $private_key_file_path");
			return;
		}
	}
	
	# Delete cached RSA object
	if ($self->{private_key_object_from_file}) {
		notify($ERRORS{'DEBUG'}, 0, "deleting cached RSA private key object");
		delete $self->{private_key_object_from_file};
	}
	
	# Delete all existing cryptsecret entries for the management node
	# The website's API won't delete any that may have been created with an earlier key
	delete_management_node_cryptsecret($management_node_id);
	
	# Override the die handler 
	local $SIG{__DIE__} = sub{};
	
	# Create a new RSA object containing a private/public key pair
	# Create an RSA object based on the existing private key contained in the file
	my $rsa_generate;
	eval {
		$rsa_generate = Crypt::OpenSSL::RSA->generate_key($bits);
	};
	if ($EVAL_ERROR || !$rsa_generate) {
		notify($ERRORS{'WARNING'}, 0, "failed to create private key file on management node $management_node_short_name: $private_key_file_path, RSA object could not be created" . ($EVAL_ERROR ? ", error:\n" . $EVAL_ERROR : ''));
		return;
	}

	my $private_key_string;
	eval {
		$private_key_string = $rsa_generate->get_private_key_string();
	};
	if ($EVAL_ERROR || !$private_key_string) {
		notify($ERRORS{'WARNING'}, 0, "failed to create private key file on management node $management_node_short_name: $private_key_file_path, private key string could not be retireved from RSA object" . ($EVAL_ERROR ? ", error:\n" . $EVAL_ERROR : ''));
		return;
	}
	
	my $public_key_string;
	eval {
		$public_key_string = $rsa_generate->get_public_key_x509_string();
	};
	if ($EVAL_ERROR ||  !$public_key_string) {
		notify($ERRORS{'WARNING'}, 0, "failed to create private key file on management node $management_node_short_name: $private_key_file_path, public key string could not be retireved from RSA object" . ($EVAL_ERROR ? ", error:\n" . $EVAL_ERROR : ''));
		return;
	}
	
	$self->create_text_file($private_key_file_path, $private_key_string) || return;
	
	# Update cryptkey table with the public key string
	if (!set_management_node_cryptkey_pubkey($management_node_id, $public_key_string)) {
		notify($ERRORS{'WARNING'}, 0, "created private key file on management node $management_node_short_name: $private_key_file_path, failed to update cryptkey table in database, attempting to delete private key file just created: $private_key_file_path");
		$self->delete_file($private_key_file_path);
		return;
	}
	
	# Call the XML-RPC API to create a new cryptsecret entry for this reservation
	call_check_crypt_secrets($reservation_id);
	
	notify($ERRORS{'OK'}, 0, "created private key file on management node $management_node_short_name: $private_key_file_path, updated cryptkey.pubkey value in database");
	return 1;
}