sub mount_nfs_shares()

in managementnode/lib/VCL/Module/OS.pm [5122:5271]


sub mount_nfs_shares {
	my $self = shift;
	if (ref($self) !~ /VCL::Module/) {
		notify($ERRORS{'CRITICAL'}, 0, "subroutine was called as a function, it must be called as a class method");
		return;
	}
	
	my $management_node_id = $self->data->get_management_node_id();
	my $computer_name = $self->data->get_computer_short_name();
	my $user_uid = $self->data->get_user_uid();
	
	# Get the NFS mount information configured for the management node from the variable table
	my $nfsmount_variable_name = "nfsmount|$management_node_id";
	my $nfsmount_variable_value = get_variable($nfsmount_variable_name);
	if (!$nfsmount_variable_value) {
		notify($ERRORS{'DEBUG'}, 0, "'$nfsmount_variable_name' variable is NOT configured for management node $management_node_id");
		return 1;
	}
	notify($ERRORS{'DEBUG'}, 0, "retrieved '$nfsmount_variable_name' variable configured for management node: '$nfsmount_variable_value'");
	
	my $error_encountered = 0;
	
	MOUNT_SPECIFICATION: for my $mount_specification (split(/;/, $nfsmount_variable_value)) {
		# Format:
		#    <IP/hostname>:<remote directory>,<local directory>
		# Example:
		#    10.0.0.12:/users/home/[username],/home/[username]
		my ($remote_host, $remote_specification, $local_specification) = $mount_specification =~
			/
				^\s*
				([^:\s]+)             # $remote_host
				\s*:\s*               # :
				(\/[^,]*[^,\s\/])\/?  # $remote_specification
				\s*,\s*               # ,
				(\/.*[^\s\/])\/?      # $local_specification
				\s*$
			/gx;
		if (!defined($remote_host) || !defined($remote_specification) || !defined($local_specification)) {
			notify($ERRORS{'CRITICAL'}, 0, "failed to parse mount specification: '$mount_specification'");
			$error_encountered = 1;
			next MOUNT_SPECIFICATION;
		}
		
		# Replace variables in local and remote directory paths
		my $local_substituted = $self->data->substitute_string_variables($local_specification);
		my $remote_substituted = $self->data->substitute_string_variables($remote_specification);
		my $remote_target = "$remote_host:$remote_substituted";
		
		notify($ERRORS{'DEBUG'}, 0, "parsed mount definition: '$mount_specification'\n" .
			"remote storage target : $remote_target" . ($remote_specification ne $remote_substituted ? " (specification: $remote_specification)" : '') . "\n" .
			"local mount directory : $local_substituted " . ($local_specification ne $local_substituted ? " (specification: $local_specification)" : '')
		);
		
		# Specify ignore error option to prevent warnings on first attempt
		my $mount_result = $self->nfs_mount_share($remote_target, $local_substituted, 1);
		# If successful or failed and returned undefined, stop processing this share
		if (!defined($mount_result)) {
			# Unrepairable error encountered
			$error_encountered = 1;
			next MOUNT_SPECIFICATION;
		}
		elsif ($mount_result == 1) {
			# Successfully mounted share
			next MOUNT_SPECIFICATION;
		}
		
		# nfs_mount_share() returned 0 indicating the remote directory does not exist
		notify($ERRORS{'OK'}, 0, "unable to mount $remote_target on $computer_name on first attempt, checking if directories need to be created");
		
		# Get the last component of the remote directory specification following the last forward slash
		my ($remote_directory_name_specification) = $remote_specification =~
			/
				\/
				(
					[^
						\/
					]+
				)
				$
			/gx;
		if (!$remote_directory_name_specification) {
			notify($ERRORS{'WARNING'}, 0, "failed to mount share on $computer_name: $remote_target --> $local_substituted, no attempt made to create user/reservation-specific directory on share because the remote directory name specification could not be determined: $remote_specification");
			return;
		}
		elsif ($remote_directory_name_specification !~
			/
				\[
				[^
					\]
				]+
				\]
			/gx) {
			notify($ERRORS{'WARNING'}, 0, "failed to mount share on $computer_name: $remote_target --> $local_substituted, no attempt made to create user/reservation-specific directory on share because the remote directory name specification does not contain a substitution value: $remote_directory_name_specification");
			return;
		}
		
		# Get the remote directory name and its parent directory path
		my ($remote_parent_directory_path, $remote_directory_name) = $remote_substituted =~
			/
				^
				(
					\/.+
				)
				\/
				(
					[^
						\/
					]+
				)
				$
			/gx;
		if (!defined($remote_directory_name)) {
			notify($ERRORS{'WARNING'}, 0, "failed to mount share on $computer_name: $remote_target --> $local_substituted, no attempt made to create user/reservation-specific directory on share because the remote directory name and its parent directory path could not be determined: $remote_substituted");
			return;
		}
		
		notify($ERRORS{'DEBUG'}, 0, "attempting to create user/reservation-specific directory on share, remote directory name specification contains a substitution value: $remote_directory_name_specification --> $remote_directory_name");
		
		# Attempt to mount the remote parent directory on the management node
		my $mn_temp_remote_target = "$remote_host:$remote_parent_directory_path";
		my $mn_temp_mount_directory_path = tempdir(CLEANUP => 1);
		my $mn_temp_create_directory_path = "$mn_temp_mount_directory_path/$remote_directory_name";
		if (!$self->mn_os->nfs_mount_share($mn_temp_remote_target, $mn_temp_mount_directory_path)) {
			notify($ERRORS{'WARNING'}, 0, "failed to mount share on $computer_name: $remote_target --> $local_substituted, failed to temporarily mount remote parent directory share on management node: $mn_temp_remote_target --> $mn_temp_mount_directory_path");
			return;
		}
		
		# Try to create the directory containing the substitution value
		if (!$self->mn_os->create_directory($mn_temp_create_directory_path)) {
			notify($ERRORS{'WARNING'}, 0, "failed to mount share on $computer_name: $remote_target --> $local_substituted, mounted temporary remote parent directory share on management node ($mn_temp_remote_target) but failed to create '$remote_directory_name' subdirectory under it");
			$self->mn_os->nfs_unmount_share($mn_temp_mount_directory_path);
			return;
		}
		
		# Check if the directory name contains a substitution for user-specific data
		if ($remote_directory_name_specification =~ /\[user/) {
			$self->mn_os->set_file_owner($mn_temp_create_directory_path, $user_uid);
			
			# Set the permissions on the directory to 700 so other users can't read contents
			$self->mn_os->set_file_permissions($mn_temp_create_directory_path, '700');
		}
		
		
		$self->mn_os->nfs_unmount_share($mn_temp_mount_directory_path);
		
		# Try to mount the share on the computer again
		$self->nfs_mount_share($remote_target, $local_substituted) || $error_encountered++;
	}
	return !$error_encountered
}