This is an automated email from the ASF dual-hosted git repository.

jfthomps pushed a commit to branch VCL-1096_Window_NFS_shares
in repository https://gitbox.apache.org/repos/asf/vcl.git


The following commit(s) were added to refs/heads/VCL-1096_Window_NFS_shares by 
this push:
     new 3dffb95  VCL-1096 - Add ability to automatically mount NFS shares 
under Windows
3dffb95 is described below

commit 3dffb95ed3d45b096585d9b147f2878b7d13b47f
Author: Josh Thompson <jftho...@ncsu.edu>
AuthorDate: Wed Jan 30 16:04:33 2019 -0500

    VCL-1096 - Add ability to automatically mount NFS shares under Windows
    
    Windows.pm:
    -modified pre_capture: added call to $self->unmount_nfs_shares at end of 
function to removing mounting of any NFS shares at next user login
    -modified sanitize: added call to $self->unmount_nfs_shares at end of 
function to remove code that would run at user login to do NFS mounts
    -added reserve function that calls parent reserve function and then calls 
$self->mount_nfs_shares
    -added nfs_mount_share
    -added nfs_unmount_share
    -added set_windows_nfs_client_uid
---
 managementnode/lib/VCL/Module/OS/Windows.pm | 296 +++++++++++++++++++++++++++-
 1 file changed, 294 insertions(+), 2 deletions(-)

diff --git a/managementnode/lib/VCL/Module/OS/Windows.pm 
b/managementnode/lib/VCL/Module/OS/Windows.pm
index 52f7b19..479fc22 100644
--- a/managementnode/lib/VCL/Module/OS/Windows.pm
+++ b/managementnode/lib/VCL/Module/OS/Windows.pm
@@ -677,14 +677,27 @@ sub pre_capture {
                notify($ERRORS{'WARNING'}, 0, "unable to set sshd service 
startup mode to manual");
                return 0;
        }
-       
+
+=item *
+
+ Unmount any NFS shares
+
+=cut
+
+       if (!$self->unmount_nfs_shares()) {
+               notify($ERRORS{'WARNING'}, 0, "unable to unmount NFS shares");
+               return;
+       }
+       else {
+               notify($ERRORS{'DEBUG'}, 0, "Call to unmount_nfs_shares 
returned successfully");
+       }
+
 =back
 
 =cut
 
        notify($ERRORS{'OK'}, 0, "returning 1");
        return 1;
-
 } ## end sub pre_capture
 
 #//////////////////////////////////////////////////////////////////////////////
@@ -1178,6 +1191,14 @@ sub sanitize {
                return 0;
        }
        
+       if (!$self->unmount_nfs_shares()) {
+               notify($ERRORS{'WARNING'}, 0, "failed to unmount nfs shares");
+               return 0;
+       }
+       else {
+               notify($ERRORS{'DEBUG'}, 0, "successfully unmounted any NFS 
shares");
+       }
+
        notify($ERRORS{'OK'}, 0, "$computer_node_name has been sanitized");
        return 1;
 } ## end sub sanitize
@@ -14912,6 +14933,277 @@ sub _escape_password {
 
 #//////////////////////////////////////////////////////////////////////////////
 
+=head2 reserve
+
+ Parameters  : none
+ Returns     : boolean
+ Description : Calls parent OS.pm::reserve then mounts NFS shares.
+
+=cut
+
+sub reserve {
+       my $self = shift;
+       if (ref($self) !~ /Windows/i) {
+               notify($ERRORS{'CRITICAL'}, 0, "subroutine was called as a 
function, it must be called as a class method");
+               return 0;
+       }
+       
+       # Call OS.pm's reserve subroutine
+       $self->SUPER::reserve() || return;
+       
+       notify($ERRORS{'OK'}, 0, "beginning Windows reserve tasks");
+       
+       # Attempt to mount NFS shares configured for the management node (Site 
Configuration > NFS Mounts)
+       $self->mount_nfs_shares();
+       
+       notify($ERRORS{'OK'}, 0, "Windows reserve tasks complete");
+       return 1;
+}
+
+#/////////////////////////////////////////////////////////////////////////////
+
+=head2 nfs_mount_share
+
+ Parameters  : $remote_target
+ Returns     : boolean
+ Description : Prepares a Windows image to automatically mount a user's NFS
+               shares when the user logs in.
+               
+               The Windows image is checked to determine if the required 
Windows
+               features are installed in the image. If not installed, an 
attempt
+               is made to install them. If any features are installed, a reboot
+               is performed.
+
+=cut
+
+sub nfs_mount_share {
+       my $self = shift;
+       if (ref($self) !~ /Windows/i) {
+               notify($ERRORS{'CRITICAL'}, 0, "subroutine was called as a 
function, it must be called as a class method");
+               return;
+       }
+       
+       my ($remote_target) = @_;
+       if (!$remote_target) {
+               notify($ERRORS{'WARNING'}, 0, "remote NFS target argument was 
not supplied");
+               return;
+       }
+       
+       # This subroutine may be called multiple times to allow multiple shares 
to be mounted
+       # If this is not the first call, append to the batch file instead of 
recreating it
+       my $previously_called = $self->{nfs_mount_share_called};
+       if ($previously_called && 
!$self->{nfs_mount_share_preparation_complete}) {
+               notify($ERRORS{'DEBUG'}, 0, "skipping subsequent NFS mount 
attempt, this subroutine was previously called but the preparation tasks failed 
to complete");
+               return;
+       }
+       
+       $self->{nfs_mount_share_called} = 1;
+       
+       my $username = $self->data->get_user_login_id();
+       my $uid = $self->data->get_user_uid();
+       my $reservation_id = $self->data->get_reservation_id();
+       my $computer_name = $self->data->get_computer_node_name();
+       my $management_node_id = $self->data->get_management_node_id;
+       
+       my $nfs_mount_batch_file_path = 'C:/mount_nfs.cmd';
+       
+       # Only perform the prep tasks the first time this subroutine is called
+       if ($previously_called) {
+               notify($ERRORS{'DEBUG'}, 0, "Windows NFS preparation tasks not 
necessary, this subroutine was previously executed");
+       }
+       else {
+               notify($ERRORS{'DEBUG'}, 0, "beginning Windows NFS preparation 
tasks");
+               
+               $self->delete_file($nfs_mount_batch_file_path);
+               
+               my $windows_product_name = $self->get_product_name();
+               if ($windows_product_name =~ /(Windows.*Professional)/) {
+                       notify($ERRORS{'WARNING'}, 0, "Windows NFS share not 
mounted, Client for NFS is not available on this edition: 
$windows_product_name");
+                       return 0;
+               }
+               
+               # Check if required Windows features are installed in the image
+               # Attempt to install them if missing
+               # A reboot is required if any features are installed
+               my @required_windows_feature_names = (
+                       'ServicesForNFS-ClientOnly',
+                       'ClientForNFS-Infrastructure',
+               );
+               
+               my $installed_feature_count = 0;
+               for my $required_windows_feature_name 
(@required_windows_feature_names) {
+                       #notify($ERRORS{'DEBUG'}, 0, "sleeping 10 seconds 
before installing next Windows feature");
+                       #sleep_uninterrupted(10) if $installed_feature_count > 
0;
+                       
+                       if 
(!$self->is_windows_feature_enabled($required_windows_feature_name)) {
+                               if 
($self->enable_windows_feature($required_windows_feature_name)) {
+                                       $self->{windows_nfs_reboot_required} = 
1;
+                               }
+                               else {
+                                       notify($ERRORS{'WARNING'}, 0, "failed 
to prepare Windows NFS, '$required_windows_feature_name' Windows feature could 
not be enabled");
+                                       return;
+                               }
+                       }
+                       $installed_feature_count++;
+               }
+               
+               # Stop and disable the "TCP/IP NetBIOS Helper" service - it 
causes delays using NFS shares
+               $self->stop_service('lmhosts');
+               $self->set_service_startup_mode('lmhosts', 'disabled');
+               
+               # Set the anonymous UID
+               $self->set_windows_nfs_client_uid($uid) || return;
+               
+               #if ($self->{windows_nfs_reboot_required}) {
+               #       notify($ERRORS{'DEBUG'}, 0, "attempting to reboot 
$computer_name to complete the configuration of the NFS Client");
+               #       if (!$self->reboot()) {
+               #               notify($ERRORS{'WARNING'}, 0, "failed to 
prepare Windows NFS, failed to reboot $computer_name after configuring NFS 
client");
+               #               return;
+               #       }
+               #}
+               
+               # Attempt to start the NFS client or make sure it's already 
started
+               $self->start_service('NfsClnt') || return;
+               
+               #if (!$self->start_service('NfsClnt')) {
+               #       if ($self->{windows_nfs_reboot_required}) {
+               #               notify($ERRORS{'WARNING'}, 0, "failed to 
prepare Windows NFS, failed to start the NFS client, $computer_name was already 
rebooted");
+               #               return;
+               #       }
+               #       else {
+               #               if (!$self->reboot()) {
+               #                       notify($ERRORS{'WARNING'}, 0, "failed 
to prepare Windows NFS, failed to reboot $computer_name after attempting to 
start the NFS client");
+               #                       return;
+               #               }
+               #               
+               #               if (!$self->start_service('NfsClnt')) {
+               #                       notify($ERRORS{'WARNING'}, 0, "failed 
to prepare Windows NFS, failed to start the NFS client on $computer_name after 
it was rebooted");
+               #                       return;
+               #               }
+               #       }
+               #}
+               #notify($ERRORS{'DEBUG'}, 0, "Windows NFS preparation tasks 
complete");
+               
+               $self->{nfs_mount_share_preparation_complete} = 1;
+       }
+       
+       my $mount_script_contents;
+       if (!$previously_called) {
+               $mount_script_contents = "nfsadmin.exe client start\r\n";
+       }
+       $mount_script_contents .= "C:\\Windows\\system32\\mount.exe -o 
mtype=hard $remote_target *";
+       
+       if ($previously_called) {
+               notify($ERRORS{'DEBUG'}, 0, "appending line to 
$nfs_mount_batch_file_path: $mount_script_contents");
+               if (!$self->append_text_file($nfs_mount_batch_file_path, 
$mount_script_contents)) {
+                       notify($ERRORS{'WARNING'}, 0, "failed to append batch 
file to mount NFS shares: $nfs_mount_batch_file_path");
+                       return;
+               }
+       }
+       else {
+               notify($ERRORS{'DEBUG'}, 0, "creating Windows NFS mount batch 
file: $nfs_mount_batch_file_path, contents:\n$mount_script_contents");
+               if (!$self->create_text_file($nfs_mount_batch_file_path, 
$mount_script_contents)) {
+                       notify($ERRORS{'WARNING'}, 0, "failed to create Windows 
NFS mount batch file: $nfs_mount_batch_file_path");
+                       return;
+               }
+               $self->add_hklm_run_registry_key('VCL Mount NFS', 
$nfs_mount_batch_file_path) || return;
+               $self->execute("chmod 777 $nfs_mount_batch_file_path");
+       }
+       
+       notify($ERRORS{'DEBUG'}, 0, "finished Windows NFS mount tasks");
+       return 1;
+}
+
+#/////////////////////////////////////////////////////////////////////////////
+
+=head2 nfs_unmount_share
+
+ Parameters  : none
+ Returns     : boolean
+ Description : This doesn't actually unmount any shares but deletes the 
registry
+               key and batch file created to mount NFS shares when a user logs
+               in.
+
+=cut
+
+sub nfs_unmount_share {
+       my $self = shift;
+       if (ref($self) !~ /Windows/i) {
+               notify($ERRORS{'CRITICAL'}, 0, "subroutine was called as a 
function, it must be called as a class method");
+               return;
+       }
+       
+       $self->delete_file('C:/mount_nfs.cmd');
+       $self->delete_hklm_run_registry_key('VCL Mount NFS');
+       return 1;
+}
+
+#/////////////////////////////////////////////////////////////////////////////
+
+=head2 set_windows_nfs_client_uid
+
+ Parameters  : $uid_number
+ Returns     : boolean
+ Description : Sets registry values used by the Windows NFS Client to determine
+               which user UID number to use when accessing NFS shares.
+
+=cut
+
+sub set_windows_nfs_client_uid {
+       my $self = shift;
+       if (ref($self) !~ /Windows/i) {
+               notify($ERRORS{'CRITICAL'}, 0, "subroutine was called as a 
function, it must be called as a class method");
+               return;
+       }
+       
+       my $uid = shift || $self->data->get_user_uid();
+       my $computer_name = $self->data->get_computer_node_name();
+       
+       notify($ERRORS{'DEBUG'}, 0, "attempting to configure the Windows NFS 
Client to use anonymous UID $uid");
+       
+       my $nfs_client_service_name = 'NfsClnt';
+       my $base_key = 
'HKEY_LOCAL_MACHINE\SOFTWARE\Microsoft\ClientForNFS\CurrentVersion\Default';
+       my $uid_key = 'AnonymousUid';
+       
+       # Check if UID already set correctly
+       my $existing_uid = $self->reg_query($base_key, $uid_key, 1) || '';
+       if ($existing_uid eq $uid) {
+               notify($ERRORS{'DEBUG'}, 0, "anonymous UID ($existing_uid) 
value are already set correctly in the registry on $computer_name");
+       }
+       else {
+               # Set the registry keys
+               if (!$self->reg_add($base_key, $uid_key, 'REG_DWORD', $uid)) {
+                       notify($ERRORS{'WARNING'}, 0, "failed to set Windows 
NFS Client anonymous UID in the registry");
+                       return;
+               }
+       }
+       
+       # Stop the NFS service, this may fail if something is already mounted
+       if (!$self->{windows_nfs_reboot_required}) {
+               if ($self->stop_service($nfs_client_service_name)) {
+                       ## Service won't restart immediately after stopping it
+                       #sleep_uninterrupted(10);
+                       
+                       if ($self->start_service($nfs_client_service_name)) {
+                               notify($ERRORS{'DEBUG'}, 0, "set Windows NFS 
Client anonymous UID value in registry and restarted $nfs_client_service_name 
service");
+                       }
+                       else {
+                               notify($ERRORS{'WARNING'}, 0, "failed to 
restart Windows NFS Client service, it may be in use, $computer_name will be 
rebooted");
+                               $self->{windows_nfs_reboot_required} = 1;
+                       }
+               }
+               else {
+                       notify($ERRORS{'WARNING'}, 0, "failed to stop Windows 
NFS Client service, it may be in use, $computer_name will be rebooted");
+                       $self->{windows_nfs_reboot_required} = 1;
+               }
+       }
+       
+       notify($ERRORS{'DEBUG'}, 0, "set Windows NFS Client anonymous UID 
values in registry");
+       return 1;
+}
+
+#//////////////////////////////////////////////////////////////////////////////
+
 1;
 __END__
 

Reply via email to