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/10/22 22:25:12 UTC
svn commit: r1710094 - /vcl/trunk/managementnode/lib/VCL/Module/OS/Linux.pm
Author: arkurth
Date: Thu Oct 22 20:25:12 2015
New Revision: 1710094
URL: http://svn.apache.org/viewvc?rev=1710094&view=rev
Log:
VCL-915
Added the following subroutines to Linux.pm. These are not currently being called from elsewhere:
mount_nfs_share
unmount_nfs_share
is_nfs_share_mounted
get_nfs_mount_string
add_fstab_nfs_mount
remove_matching_fstab_lines
Other
Added check to Linux.pm::configure_default_sshd and configure_ext_sshd to check if the sshd service exists first.
Modified:
vcl/trunk/managementnode/lib/VCL/Module/OS/Linux.pm
Modified: vcl/trunk/managementnode/lib/VCL/Module/OS/Linux.pm
URL: http://svn.apache.org/viewvc/vcl/trunk/managementnode/lib/VCL/Module/OS/Linux.pm?rev=1710094&r1=1710093&r2=1710094&view=diff
==============================================================================
--- vcl/trunk/managementnode/lib/VCL/Module/OS/Linux.pm (original)
+++ vcl/trunk/managementnode/lib/VCL/Module/OS/Linux.pm Thu Oct 22 20:25:12 2015
@@ -4964,6 +4964,11 @@ sub configure_default_sshd {
my $computer_node_name = $self->data->get_computer_node_name();
+ if (!$self->service_exists('sshd')) {
+ notify($ERRORS{'DEBUG'}, 0, "skipping default sshd configuation, sshd service does not exist");
+ return 1;
+ }
+
# Stop existing external sshd process if it is running
if (!$self->stop_external_sshd()) {
notify($ERRORS{'WARNING'}, 0, "unable to configure default sshd state, problem occurred attempting to kill external sshd process");
@@ -5014,6 +5019,11 @@ sub configure_ext_sshd {
return;
}
+ if (!$self->service_exists('sshd')) {
+ notify($ERRORS{'DEBUG'}, 0, "skipping ext_sshd configuation, sshd service does not exist");
+ return 1;
+ }
+
# Recreate the sshd_config file, set ListenAddress to the private IP address
if (!$self->configure_sshd_config_file({ListenAddress => $private_ip_address})) {
notify($ERRORS{'WARNING'}, 0, "unable to configure ext_sshd, failed to reconfigure sshd_config to only listen on private network on $computer_node_name");
@@ -6062,9 +6072,9 @@ sub get_ssh_public_key_string {
$public_key_string = $self->_get_ssh_public_key_string_helper($private_key_file_path, 'dropbearkey');
}
if ($public_key_string) {
- if ($comment) {
- $public_key_string =~ s/(ssh-[^\s]+\s[^\s=]+).*$/$1 $comment/g;
- }
+ #if ($comment) {
+ # $public_key_string =~ s/(ssh-[^\s]+\s[^\s=]+).*$/$1 $comment/g;
+ #}
return $public_key_string;
}
@@ -6208,6 +6218,386 @@ sub install_package {
}
}
+#/////////////////////////////////////////////////////////////////////////////
+
+=head2 mount_nfs_share
+
+ Parameters : $remote_nfs_share, $local_mount_directory, $options
+ Returns : boolean
+ Description : Mounts an NFS share on the computer. The $remote_nfs_share
+ argument must be in the for used by the mount command:
+ <hostname|IP>:/path-to-share
+
+ The $local_mount_directory argument must specify a directory.
+ This directory will be created if it does not already exist.
+
+ The $options argument allows NFS mount options to be specified
+ such as:
+ rsize=1048576,wsize=1048576,vers=3
+
+ The $options string must be formatted correctly and is passed
+ directly to the mount command.
+
+=cut
+
+sub mount_nfs_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, $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')) {
+ $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
+ if (!$self->service_exists('rpcbind')) {
+ $self->install_package('rpcbind');
+ }
+
+ # Try to start the service
+ $self->start_service('rpcbind');
+ }
+ else {
+ # Create the local mount point directory if it does not exist
+ if (!$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 ($options) {
+ $mount_command .= " -o $options";
+ }
+
+ 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{'CRITICAL'}, 0, "failed to execute command to mount NFS share on $computer_name: $mount_command");
+ return;
+ }
+ elsif ($mount_exit_status eq 0) {
+ notify($ERRORS{'OK'}, 0, "mounted NFS share on $computer_name: $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;
+ }
+ }
+ 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;
+ }
+ else {
+ if ($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;
+ }
+ else {
+ notify($ERRORS{'WARNING'}, 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));
+
+ # Try to mount the NFS share again, set retry flag to avoid endless loop
+ return $self->mount_nfs_share($remote_nfs_share, $local_mount_directory, $options, 1);
+ }
+ }
+}
+
+#/////////////////////////////////////////////////////////////////////////////
+
+=head2 unmount_nfs_share
+
+ Parameters : $local_mount_directory
+ Returns : boolean
+ Description : Unmounts an NFS share on the computer.
+
+=cut
+
+sub unmount_nfs_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 ($local_mount_directory) = @_;
+ if (!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();
+
+ my $umount_command = "umount -v \"$local_mount_directory\" -v";
+ my ($umount_exit_status, $umount_output) = $self->execute({
+ command => $umount_command,
+ timeout_seconds => 30,
+ max_attempts => 2,
+ });
+ if (!defined($umount_exit_status)) {
+ notify($ERRORS{'CRITICAL'}, 0, "failed to execute command to umount NFS share on $computer_name: $umount_command");
+ return;
+ }
+ elsif ($umount_exit_status eq 0) {
+ notify($ERRORS{'OK'}, 0, "unmounted NFS share on $computer_name: $local_mount_directory, output:\n" . join("\n", @$umount_output));
+ return 1;
+ }
+ elsif (grep(/not mounted/, @$umount_output)) {
+ notify($ERRORS{'OK'}, 0, "NFS share is not mounted on $computer_name: $local_mount_directory");
+ return 1;
+ }
+ else {
+ notify($ERRORS{'WARNING'}, 0, "failed to unmount NFS share on $computer_name: $local_mount_directory, command: '$umount_command', exit status: $umount_exit_status, output:\n" . join("\n", @$umount_output));
+ return;
+ }
+}
+
+#/////////////////////////////////////////////////////////////////////////////
+
+=head2 is_nfs_share_mounted
+
+ Parameters : $remote_nfs_share, $local_mount_directory
+ Returns : boolean
+ Description : Checks if an NFS share is mounted on the computer matching both
+ the remote NFS share path and local mount point directory
+ arguments.
+
+=cut
+
+sub is_nfs_share_mounted {
+ 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) = @_;
+ 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();
+
+ if ($self->get_nfs_mount_string($remote_nfs_share, $local_mount_directory)) {
+ notify($ERRORS{'DEBUG'}, 0, "NFS share is mounted on $computer_name: $remote_nfs_share --> $local_mount_directory");
+ return 1;
+ }
+ else {
+ notify($ERRORS{'DEBUG'}, 0, "NFS share is NOT mounted on $computer_name: $remote_nfs_share --> $local_mount_directory");
+ return 0;
+ }
+}
+
+#/////////////////////////////////////////////////////////////////////////////
+
+=head2 get_nfs_mount_string
+
+ Parameters : $remote_nfs_share, $local_mount_directory
+ Returns : string
+ Description : Examines the contents of /proc/mounts and attempts to locate a
+ line matching the arguments. If found, the line is returned which
+ may be used in /etc/fstab. If not found, 0 is returned. Undefined
+ is returned if an error occurs.
+
+=cut
+
+sub get_nfs_mount_string {
+ 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) = @_;
+ 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;
+ }
+
+ # Remove trailing slashes for consistent comparison
+ $remote_nfs_share =~ s/\/+$//;
+ $local_mount_directory =~ s/\/+$//;
+
+ # If the NFS share or local directory contain a space, the octal value will appear in /proc/mounts
+ $remote_nfs_share =~ s/ /\\\\040/g;
+ $local_mount_directory =~ s/ /\\\\040/g;
+
+ my $computer_name = $self->data->get_computer_node_name();
+
+ my $command = "cat /proc/mounts | grep ' nfs'";
+ my ($exit_status, $output) = $self->execute($command);
+ if (!defined($exit_status)) {
+ notify($ERRORS{'WARNING'}, 0, "failed to execute command on $computer_name: $command");
+ return;
+ }
+
+ for my $line (@$output) {
+ if ($line =~ m|^$remote_nfs_share\/?\s+$local_mount_directory\/?\s|) {
+ notify($ERRORS{'DEBUG'}, 0, "found NFS share line in /proc/mounts on $computer_name: $remote_nfs_share --> $local_mount_directory\n$line");
+ return $line;
+ }
+ }
+
+ notify($ERRORS{'DEBUG'}, 0, "/proc/mounts on $computer_name does NOT contain a line matching NFS share: $remote_nfs_share --> $local_mount_directory\n" . join("\n", @$output));
+ return 0;
+}
+
+#/////////////////////////////////////////////////////////////////////////////
+
+=head2 add_fstab_nfs_mount
+
+ Parameters : $remote_nfs_share, $local_mount_directory
+ Returns : boolean
+ Description : Adds a line to /etc/fstab for an existing NFS mount. The share
+ must be mounted prior to calling this subroutine.
+
+=cut
+
+sub add_fstab_nfs_mount {
+ 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) = @_;
+ 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();
+
+ my $nfs_mount_string = $self->get_nfs_mount_string($remote_nfs_share, $local_mount_directory);
+ if (!$nfs_mount_string) {
+ notify($ERRORS{'WARNING'}, 0, "unable to add NFS mount line to /etc/fstab, NFS share is not mounted: $remote_nfs_share --> $local_mount_directory");
+ return;
+ }
+
+ # Remove existing line matching the local mount directory followed by "nfs" to avoid duplicate lines
+ $self->remove_matching_fstab_lines("$local_mount_directory nfs");
+
+ my @fstab_lines = $self->get_file_contents('/etc/fstab');
+ push @fstab_lines, $nfs_mount_string;
+ my $new_fstab_contents = join("\n", @fstab_lines);
+
+ my $timestamp = POSIX::strftime("%Y-%m-%d_%H-%M-%S\n", localtime);
+ $self->copy_file('/etc/fstab', "/tmp/fstab.$timestamp");
+
+ if ($self->create_text_file('/etc/fstab', $new_fstab_contents)) {
+ notify($ERRORS{'OK'}, 0, "added line to /etc/fstab on $computer_name:\n$nfs_mount_string");
+ return 1;
+ }
+ else {
+ notify($ERRORS{'WARNING'}, 0, "failed to add line to /etc/fstab on $computer_name:\n$nfs_mount_string");
+ return;
+ }
+}
+
+#/////////////////////////////////////////////////////////////////////////////
+
+=head2 remove_matching_fstab_lines
+
+ Parameters : $regex_pattern
+ Returns : boolean
+ Description : Removes all lines from /etc/fstab matching the pattern.
+
+=cut
+
+sub remove_matching_fstab_lines {
+ 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 ($regex_pattern) = @_;
+ if (!defined($regex_pattern)) {
+ notify($ERRORS{'WARNING'}, 0, "pattern argument was not supplied");
+ return;
+ }
+
+ my $computer_name = $self->data->get_computer_node_name();
+
+ my $updated_fstab_contents;
+
+ my @matching_lines;
+ my @fstab_lines = $self->get_file_contents('/etc/fstab');
+ for my $fstab_line (@fstab_lines) {
+ (my $fstab_line_cleaned = $fstab_line) =~ s/\\040/ /g;
+
+ if ($fstab_line =~ m|$regex_pattern| || $fstab_line_cleaned =~ m|$regex_pattern|) {
+ push @matching_lines, $fstab_line;
+ notify($ERRORS{'DEBUG'}, 0, "removing line in /etc/fstab matching pattern: $regex_pattern\n$fstab_line");
+ next;
+ }
+ $updated_fstab_contents .= "$fstab_line\n";
+ }
+
+ if (!@matching_lines) {
+ notify($ERRORS{'DEBUG'}, 0, "/etc/fstab does not contain any lines matching pattern: $regex_pattern");
+ return 1;
+ }
+
+ notify($ERRORS{'DEBUG'}, 0, "removing " . scalar(@matching_lines) . " lines from /etc/fstab on $computer_name:\n" . join("\n", @matching_lines));
+
+ # Save a backup
+ my $timestamp = POSIX::strftime("%Y-%m-%d_%H-%M-%S\n", localtime);
+ $self->copy_file('/etc/fstab', "/tmp/fstab.$timestamp");
+
+ return $self->create_text_file('/etc/fstab', $updated_fstab_contents);
+}
+
##/////////////////////////////////////////////////////////////////////////////
1;
__END__