in managementnode/lib/VCL/Module/OS/Linux.pm [6202:6346]
sub nfs_mount_share {
my $self = shift;
if (ref($self) !~ /linux/i) {
notify($ERRORS{'CRITICAL'}, 0, "subroutine was called as a function, it must be called as a class method");
return;
}
my ($remote_nfs_share, $local_mount_directory, $ignore_missing_remote_directory_error, $nfs_options, $is_retry_attempt) = @_;
if (!defined($remote_nfs_share)) {
notify($ERRORS{'WARNING'}, 0, "remote target argument was not supplied");
return;
}
elsif (!defined($local_mount_directory)) {
notify($ERRORS{'WARNING'}, 0, "local directory path argument was not supplied");
return;
}
my $computer_name = $self->data->get_computer_node_name();
# Try to repair NFS client if 1st attempt failed
if ($is_retry_attempt) {
# Check if nfs-utils is installed, if not, try to install it
# Error looks like this if nfs-utils is not installed:
# mount: wrong fs type, bad option, bad superblock on 10.1.2.3:/nfs,
# missing codepage or helper program, or other error
# (for several filesystems (e.g. nfs, cifs) you might
# need a /sbin/mount.<type> helper program)
# In some cases useful info is found in syslog - try
# dmesg | tail or so
if (!$self->command_exists('mount.nfs')) {
if (ref($self) =~ /Ubuntu/) {
$self->install_package('nfs-common');
}
else {
$self->install_package('nfs-utils');
}
}
# Check if the rpcbind service exists, if not, try to install it
# Mount may fail if rpcbind service is not installed and running:
# mount.nfs: rpc.statd is not running but is required for remote locking.
# mount.nfs: Either use '-o nolock' to keep locks local, or start statd.
# mount.nfs: an incorrect mount option was specified
$self->install_package('rpcbind') if !$self->service_exists('rpcbind');
# Try to start the service
$self->start_service('rpcbind') if $self->service_exists('rpcbind');
}
# Create the local mount point directory if it does not exist
my $local_mount_directory_previously_existed = $self->file_exists($local_mount_directory);
if (!$local_mount_directory_previously_existed && !$self->create_directory($local_mount_directory)) {
notify($ERRORS{'WARNING'}, 0, "unable to mount $remote_nfs_share on $computer_name, failed to create directory: $local_mount_directory");
return;
}
my $mount_command = "mount -t nfs $remote_nfs_share \"$local_mount_directory\" -v";
if ($nfs_options) {
# Add retry=0 if it wasn't explicitly specified in the argument
if ($nfs_options =~ /retry/) {
$mount_command .= " -o $nfs_options";
}
else {
$mount_command .= " -o retry=0,$nfs_options";
}
}
else {
$mount_command .= " -o retry=0";
}
# Save return value if error is encountered and don't return immediately
# Facilitates a single call to clean up local directory just created if it didn't previously exist
my $return_value;
notify($ERRORS{'DEBUG'}, 0, "attempting to mount NFS share on $computer_name: $mount_command");
my ($mount_exit_status, $mount_output) = $self->execute({
command => $mount_command,
timeout_seconds => 10,
max_attempts => 2,
});
if (!defined($mount_exit_status)) {
notify($ERRORS{'WARNING'}, 0, "failed to execute command to mount NFS share on $computer_name: $mount_command");
$return_value = undef;
}
elsif ($mount_exit_status eq 0) {
notify($ERRORS{'OK'}, 0, "mounted NFS share on $computer_name: $remote_nfs_share --> $local_mount_directory");
# Add the share to /etc/fstab
$self->add_fstab_nfs_mount($remote_nfs_share, $local_mount_directory);
return 1;
}
elsif (grep(/already mounted/, @$mount_output)) {
# mount.nfs: /mnt/mymountpoint is busy or already mounted
if ($self->is_nfs_share_mounted($remote_nfs_share, $local_mount_directory)) {
return 1;
}
else {
notify($ERRORS{'WARNING'}, 0, "failed to mount NFS share on $computer_name: $remote_nfs_share --> $local_mount_directory, mount command output indicates 'already mounted' but failed to verify mount in /proc/mounts, mount command: '$mount_command', exit status: $mount_exit_status, mount output:\n" . join("\n", @$mount_output));
$return_value = undef;
}
}
elsif (grep(/(No such file or directory)/, @$mount_output)) {
# mount.nfs: mount(2): No such file or directory
# mount.nfs: mounting <hostname>:/<remote directory> failed, reason given by server: No such file or directory
if ($ignore_missing_remote_directory_error) {
notify($ERRORS{'DEBUG'}, 0, "unable to mount NFS share on $computer_name because remote directory does not exist: $remote_nfs_share, returning 0");
}
else {
notify($ERRORS{'WARNING'}, 0, "unable to mount NFS share on $computer_name because remote directory does not exist: $remote_nfs_share, returning 0, command: '$mount_command', exit status: $mount_exit_status, output:\n" . join("\n", @$mount_output));
}
$return_value = 0;
}
elsif (grep(/(Invalid argument|incorrect mount option|Usage:)/, @$mount_output)) {
notify($ERRORS{'WARNING'}, 0, "failed to mount NFS share on $computer_name: $remote_nfs_share --> $local_mount_directory, command: '$mount_command', exit status: $mount_exit_status, output:\n" . join("\n", @$mount_output));
$return_value = undef;
}
elsif ($is_retry_attempt) {
notify($ERRORS{'WARNING'}, 0, "failed to mount NFS share on $computer_name on 2nd attempt: $remote_nfs_share --> $local_mount_directory, command: '$mount_command', exit status: $mount_exit_status, output:\n" . join("\n", @$mount_output));
$return_value = undef;
}
else {
notify($ERRORS{'OK'}, 0, "failed to mount NFS share on $computer_name on 1st attempt: $remote_nfs_share --> $local_mount_directory, command: '$mount_command', exit status: $mount_exit_status, output:\n" . join("\n", @$mount_output));
}
# Clean up local directory if it didn't previously exist
if (!$local_mount_directory_previously_existed) {
my @local_mount_directory_files = $self->find_files($local_mount_directory, '*', 1);
if (@local_mount_directory_files) {
notify($ERRORS{'WARNING'}, 0, "local mount directory just created will NOT be deleted: $local_mount_directory, NFS mount seemed to have failed but directory is not empty:\n" . join("\n", @local_mount_directory_files));
}
else {
notify($ERRORS{'DEBUG'}, 0, "local mount directory just created will be deleted: $local_mount_directory");
$self->delete_file($local_mount_directory);
}
}
if ($is_retry_attempt) {
return $return_value;
}
else {
# Try to mount the NFS share again, set retry flag to avoid endless loop
return $self->nfs_mount_share($remote_nfs_share, $local_mount_directory, $ignore_missing_remote_directory_error, $nfs_options, 1);
}
}