| #!/usr/bin/perl -w |
| |
| # Licensed to the Apache Software Foundation (ASF) under one or more |
| # contributor license agreements. See the NOTICE file distributed with |
| # this work for additional information regarding copyright ownership. |
| # The ASF licenses this file to You under the Apache License, Version 2.0 |
| # (the "License"); you may not use this file except in compliance with |
| # the License. You may obtain a copy of the License at |
| # |
| # http://www.apache.org/licenses/LICENSE-2.0 |
| # |
| # Unless required by applicable law or agreed to in writing, software |
| # distributed under the License is distributed on an "AS IS" BASIS, |
| # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. |
| # See the License for the specific language governing permissions and |
| # limitations under the License. |
| |
| ############################################################################## |
| # $Id: Windows.pm 1953 2008-12-12 14:23:17Z arkurth $ |
| ############################################################################## |
| |
| =head1 NAME |
| |
| VCL::Module::OS::Windows.pm - VCL module to support Windows operating systems |
| |
| =head1 SYNOPSIS |
| |
| Needs to be written |
| |
| =head1 DESCRIPTION |
| |
| This module provides VCL support for Windows operating systems. |
| |
| =cut |
| |
| ############################################################################## |
| package VCL::Module::OS::Windows; |
| |
| # Specify the lib path using FindBin |
| use FindBin; |
| use lib "$FindBin::Bin/../../.."; |
| |
| # Configure inheritance |
| use base qw(VCL::Module::OS); |
| |
| # Specify the version of this module |
| our $VERSION = '2.00'; |
| |
| # Specify the version of Perl to use |
| use 5.008000; |
| |
| use strict; |
| use warnings; |
| use diagnostics; |
| |
| use VCL::utils; |
| use VCL::Module::Utils::Logging; |
| use VCL::Module::Utils::SCP; |
| use VCL::Module::Utils::SSH; |
| use File::Basename; |
| |
| ############################################################################## |
| |
| =head1 OBJECT METHODS |
| |
| =cut |
| |
| #///////////////////////////////////////////////////////////////////////////// |
| |
| =head2 run_command |
| |
| Parameters : String containing the Windows command to be run |
| Returns : Array: |
| - first index contains the return code of the command |
| - indices > 0 contain the lines of output generated by running |
| the command |
| Description : Runs a command on a Windows node. The command is executed by |
| by passing it through SSH. The command passed to this subroutine |
| is formatted so that it runs as a Windows command would normally |
| run by using the Windows command shell instead of Cygwin's bash |
| shell. |
| |
| =cut |
| |
| sub run_command { |
| my $self = shift; |
| my ($command) = @_; |
| |
| # Get the computer node name |
| my $computer_node_name = $self->data->get_computer_node_name(); |
| |
| # Passing Windows-style commands through SSH/Cygwin causes problems |
| # Encapsulate the command in a 'cmd.exe /q /v:on /k' command and call exit afterwards |
| # First replace % with !, the /v:on switch allows this so the variables aren't interpolated |
| # /q turns echo off |
| $command =~ s/\%/\!/g; |
| |
| # This causes the command to be run in a normal Windows command shell rather than Cygwin's bash shell |
| $command = "cmd.exe /q /v:on /c '$command'"; |
| |
| # Replace line breaks with && |
| $command =~ s/\n/ && /g; |
| |
| # Run the SSH command |
| my @ssh_results = ssh($computer_node_name, $IDENTITY_wxp, $command); |
| |
| return @ssh_results; |
| } ## end sub run_command |
| #///////////////////////////////////////////////////////////////////////////// |
| |
| =head2 run_remote_script |
| |
| Parameters : |
| Returns : |
| Description : |
| |
| =cut |
| |
| sub run_remote_script { |
| my $self = shift; |
| my ($script_path) = @_; |
| |
| # Take the script path apart |
| my ($filename, $directory, $extension) = fileparse($script_path, qr/\.[^.]*$/); |
| |
| # Remove the leading period from the extension |
| $extension =~ s/^\.//; |
| |
| # Assemble the remote script path |
| my $remote_script_scp_path = "\$TEMP/$filename.$extension"; |
| my $remote_script_ssh_path = "\%TEMP\%\\$filename.$extension"; |
| |
| # Copy the script to the node |
| if (!$self->copy_file($script_path, $remote_script_scp_path)) { |
| log_warning("failed to execute script, unable to copy $script_path to $remote_script_scp_path"); |
| return 0; |
| } |
| |
| # Assemble a script execution command based on the extension |
| my $command; |
| if ($extension =~ /ws|js|vbs|vbe|wsf|wsh/i) { |
| # Call cscript.exe for vbs and similar files |
| $command = "%SystemRoot%/System32/cscript.exe $remote_script_ssh_path //NoLogo"; |
| } |
| elsif ($extension !~ /bat|cmd/i) { |
| # Attempt to run other types of files in the Windows command interpreter |
| log_warning("unsupported script extension: $filename.$extension, attempting to run file in Windows command interpreter"); |
| $command = $remote_script_ssh_path; |
| } |
| else { |
| $command = $remote_script_ssh_path; |
| } |
| |
| # Attempt to run the script |
| my ($command_exit_status, @command_output) = $self->run_command($command); |
| if ($command_exit_status) { |
| log_warning("failed to execute script: $script_path"); |
| } |
| |
| return ($command_exit_status, @command_output); |
| } ## end sub run_remote_script |
| |
| #///////////////////////////////////////////////////////////////////////////// |
| |
| =head2 copy_file |
| |
| Parameters : |
| Returns : |
| Description : |
| |
| =cut |
| |
| sub copy_file { |
| my $self = shift; |
| my ($source_file_path, $destination_file_path) = @_; |
| |
| # Get the computer node name |
| my $computer_node_name = $self->data->get_computer_node_name(); |
| |
| my %scp_options = (options => 'v', |
| identity_file => $IDENTITY_wxp, |
| source_path => $source_file_path, |
| destination_host => $computer_node_name, |
| destination_path => $destination_file_path,); |
| |
| # Run the SCP command |
| if (!scp(\%scp_options)) { |
| log_warning("failed to copy file using SCP"); |
| return 0; |
| } |
| |
| log_info("file copied using SCP: $source_file_path --> $computer_node_name:$destination_file_path"); |
| return 1; |
| } ## end sub copy_file |
| |
| #///////////////////////////////////////////////////////////////////////////// |
| |
| =head2 capture_prepare |
| |
| Parameters : |
| Returns : |
| Description : |
| |
| =cut |
| |
| sub capture_prepare { |
| 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; |
| } |
| |
| my $request_id = $self->data->get_request_id(); |
| my $reservation_id = $self->data->get_reservation_id(); |
| my $image_id = $self->data->get_image_id(); |
| my $image_os_name = $self->data->get_image_os_name(); |
| my $management_node_keys = $self->data->get_management_node_keys(); |
| my $image_os_type = $self->data->get_image_os_type(); |
| my $image_name = $self->data->get_image_name(); |
| my $imagemeta_sysprep = $self->data->get_imagemeta_sysprep(); |
| my $computer_id = $self->data->get_computer_id(); |
| my $computer_short_name = $self->data->get_computer_short_name(); |
| my $computer_node_name = $self->data->get_computer_node_name(); |
| my $computer_type = $self->data->get_computer_type(); |
| my $user_id = $self->data->get_user_id(); |
| my $user_unityid = $self->data->get_user_login_id(); |
| my $managementnode_shortname = $self->data->get_management_node_short_name(); |
| my $computer_private_ip = $self->data->get_computer_private_ip(); |
| |
| notify($ERRORS{'OK'}, 0, "beginning Windows-specific image capture preparation tasks: $image_name on $computer_short_name"); |
| |
| my @sshcmd; |
| |
| # Change password of root and sshd service back to default |
| # Needed only for sshd service on windows OS's |
| my $p = $WINDOWS_ROOT_PASSWORD; |
| if (changewindowspasswd($computer_short_name, "root", $p)) { |
| notify($ERRORS{'OK'}, 0, "changed Windows password on $computer_short_name, root, $p"); |
| } |
| else { |
| notify($ERRORS{'OK'}, 0, "failed to change windows password $computer_short_name,root,$p"); |
| } |
| |
| |
| # Check for user account and clean out if listed |
| if (_is_user_added($computer_node_name, $user_unityid, $computer_type, $image_os_name)) { |
| # Make sure user is logged off |
| my @QA = run_ssh_command($computer_node_name, $IDENTITY_wxp, "cmd /c qwinsta.exe", "root"); |
| foreach my $r (@{$QA[1]}) { |
| if ($r =~ /([>]?)([-a-zA-Z0-9]*)\s+([a-zA-Z0-9]*)\s+ ([0-9]*)\s+([a-zA-Z]*)/) { |
| my $state = $5; |
| my $session = $2; |
| my $user = $3; |
| if ($5 =~ /Active/) { |
| notify($ERRORS{'OK'}, 0, "detected $user on $session still logged on $computer_node_name $r, sleeping 7 before logging off"); |
| sleep 7; |
| my @LF = run_ssh_command($computer_node_name, $IDENTITY_wxp, "cmd /c logoff.exe $session"); |
| foreach my $l (@{$LF[1]}) { |
| notify($ERRORS{'OK'}, 0, "output from attempt to logoff $user on $session"); |
| } |
| |
| } |
| } ## end if ($r =~ /([>]?)([-a-zA-Z0-9]*)\s+([a-zA-Z0-9]*)\s+ ([0-9]*)\s+([a-zA-Z]*)/) |
| } ## end foreach my $r (@{$QA[1]}) |
| #delete user |
| if (del_user($computer_node_name, $user_unityid, $computer_type, $image_os_name)) { |
| notify($ERRORS{'OK'}, 0, "$user_unityid account deleted from $computer_node_name"); |
| } |
| } ## end if (_is_user_added($computer_node_name, $user_unityid... |
| |
| # Determine if machine has static private IP address |
| # If so we need to change back to DHCP |
| if ($image_name =~ /^win2003/) { |
| notify($ERRORS{'OK'}, 0, "Windows Server 2003 image detected, private adapter will be changed from DHCP to static on $computer_short_name"); |
| |
| my %ip; |
| my $myadapter; |
| undef @sshcmd; |
| @sshcmd = run_ssh_command($computer_node_name, $management_node_keys, "ipconfig -all", "root"); |
| # build hash of needed info and set the correct private adapter. |
| foreach my $a (@{$sshcmd[1]}) { |
| if ($a =~ /Ethernet adapter (.*):/) { |
| #print "$1\n"; |
| $myadapter = $1; |
| } |
| if ($a =~ /IP Address([\s.]*): $computer_private_ip/) { |
| $ip{$myadapter}{"private"} = 1; |
| notify($ERRORS{'OK'}, 0, "privateIP found $computer_private_ip"); |
| } |
| if ($a =~ /DHCP Enabled([\s.]*): (No|Yes)/) { |
| $ip{$myadapter}{"DHCPenabled"} = $2; |
| notify($ERRORS{'OK'}, 0, "DHCP enabled $2"); |
| } |
| } ## end foreach my $a (@{$sshcmd[1]}) |
| my $privateadapter; |
| foreach my $key (keys %ip) { |
| if (defined($ip{$key}{private})) { |
| if ($ip{$key}{private}) { |
| $privateadapter = $key; |
| } |
| } |
| } |
| |
| if ($ip{$privateadapter}{"DHCPenabled"} =~ /No/) { |
| notify($ERRORS{'OK'}, 0, "DHCP disabled for $privateadapter on $computer_node_name - reseting to dhcp"); |
| if (open(NETSH, "/usr/bin/ssh -q -i $management_node_keys $computer_node_name \"netsh interface ip set address name=\\\"$privateadapter\\\" source=dhcp\" & 2>&1 |")) { |
| #losing connection |
| my $go = 1; |
| while ($go) { |
| #print "hi\n"; |
| sleep 4; |
| if (open(PS, "ps -ef |")) { |
| my @ps = <PS>; |
| close(PS); |
| sleep 4; |
| foreach my $p (@ps) { |
| if ($p =~ /$computer_node_name netsh interface/) { |
| if ($p =~ /(root)\s+([0-9]*)/) { |
| if (open(KILLIT, "kill -9 $2 |")) { |
| close(KILLIT); |
| close(NETSH); |
| notify($ERRORS{'OK'}, 0, "killing ssh $computer_node_name netsh process"); |
| } |
| } |
| } |
| } ## end foreach my $p (@ps) |
| } ## end if (open(PS, "ps -ef |")) |
| $go = 0; |
| } ## end while ($go) |
| } # Close open netsh SSH handle |
| |
| #make sure it came back confirm is was reset to dhcp |
| sleep 5; |
| my $sshd_status = _sshd_status($computer_node_name, $image_name); |
| if ($sshd_status eq "on") { |
| notify($ERRORS{'OK'}, 0, "successful $computer_node_name is accessible after dhcp assignment"); |
| my $myadapter; |
| undef @sshcmd; |
| @sshcmd = run_ssh_command($computer_node_name, $management_node_keys, "ipconfig -all", "root"); |
| # build hash of needed info and set the correct private adapter. |
| foreach my $a (@{$sshcmd[1]}) { |
| if ($a =~ /Ethernet adapter (.*):/) { |
| #print "$1\n"; |
| $myadapter = $1; |
| } |
| if ($a =~ /IP Address([\s.]*): $computer_private_ip/) { |
| $ip{$myadapter}{"private"} = 1; |
| } |
| if ($a =~ /DHCP Enabled([\s.]*): (No|Yes)/) { |
| $ip{$myadapter}{"DHCPenabled"} = $2; |
| } |
| } ## end foreach my $a (@{$sshcmd[1]}) |
| if ($ip{$privateadapter}{"DHCPenabled"} =~ /Yes/) { |
| notify($ERRORS{'OK'}, 0, "successful $computer_node_name is correctly assigned to use dhcp"); |
| } |
| elsif ($ip{$privateadapter}{"DHCPenabled"} =~ /No/) { |
| notify($ERRORS{'CRITICAL'}, 0, "could not change $privateadapter on $computer_node_name back to dhcp"); |
| |
| return 0; |
| } |
| } ## end if ($sshd_status eq "on") |
| else { |
| notify($ERRORS{'CRITICAL'}, 0, "sshd_status set to off, can not reconnect to $computer_node_name"); |
| return 0; |
| } |
| } # Close if DHCP == no |
| |
| else { |
| notify($ERRORS{'OK'}, 0, "dhcp for $privateadapter is set to Yes on $computer_node_name $ip{$privateadapter}{DHCPenabled} - no change needed"); |
| } |
| } ## end if ($image_name =~ /^win2003/) |
| |
| if ($IPCONFIGURATION eq "static") { |
| #so we don't have conflicts we should set the public adapter back to dhcp |
| #this change is immediate |
| #figure out which adapter it public |
| my $myadapter; |
| my %ip; |
| my ($privateadapter, $publicadapter); |
| undef @sshcmd; |
| @sshcmd = run_ssh_command($computer_node_name, $management_node_keys, "ipconfig -all", "root"); |
| # build hash of needed info and set the correct private adapter. |
| my $id = 1; |
| foreach my $a (@{$sshcmd[1]}) { |
| if ($a =~ /Ethernet adapter (.*):/) { |
| $myadapter = $1; |
| $ip{$myadapter}{"id"} = $id; |
| $ip{$myadapter}{"private"} = 0; |
| } |
| if ($a =~ /IP Address([\s.]*): $computer_private_ip/) { |
| $ip{$myadapter}{"private"} = 1; |
| } |
| if ($a =~ /Physical Address([\s.]*): ([-0-9]*)/) { |
| $ip{$myadapter}{"MACaddress"} = $2; |
| } |
| $id++; |
| } ## end foreach my $a (@{$sshcmd[1]}) |
| |
| foreach my $key (keys %ip) { |
| if (defined($ip{$key}{private})) { |
| if (!($ip{$key}{private})) { |
| $publicadapter = "\"$key\""; |
| } |
| } |
| } |
| |
| undef @sshcmd; |
| my $netshcmd = "netsh interface ip set address name=\\\"$publicadapter\\\" source=dhcp"; |
| @sshcmd = run_ssh_command($computer_node_name, $management_node_keys, $netshcmd, "root"); |
| foreach my $l (@{$sshcmd[1]}) { |
| if ($l =~ /Ok/) { |
| notify($ERRORS{'OK'}, 0, "successfully set $publicadapter to dhcp"); |
| } |
| else { |
| notify($ERRORS{'OK'}, 0, "problem setting $publicadapter to dhcp on $computer_node_name @{ $sshcmd[1] }"); |
| } |
| } |
| } ## end if ($IPCONFIGURATION eq "static") |
| |
| # Defrag before removing pagefile |
| # we do this to speed up the process |
| # defraging without a page file takes a little longer |
| notify($ERRORS{'OK'}, 0, "starting defrag on $computer_node_name"); |
| undef @sshcmd; |
| @sshcmd = run_ssh_command($computer_node_name, $management_node_keys, "cmd.exe /c defrag C: -f", "root"); |
| my $defragged = 0; |
| foreach my $d (@{$sshcmd[1]}) { |
| if ($d =~ /Defragmentation Report/) { |
| notify($ERRORS{'OK'}, 0, "successfully defragmented $computer_node_name"); |
| $defragged = 1; |
| } |
| } |
| if (!$defragged) { |
| notify($ERRORS{'WARNING'}, 0, "problem occurred while defragmenting $computer_node_name: @{ $sshcmd[1] }"); |
| } |
| |
| |
| # Copy new auto_create_image.vbs and auto_prepare_for_image.vbs |
| # This moves(sometimes) the pagefile and reboots the box |
| # It actually checks for a removes the pagefile.sys |
| my @scp; |
| if (run_scp_command("$TOOLS/auto_create_image.vbs", "$computer_node_name:auto_create_image.vbs", $management_node_keys)) { |
| notify($ERRORS{'OK'}, 0, "successfully copied auto_create_image.vbs to $computer_node_name"); |
| } |
| else { |
| notify($ERRORS{'CRITICAL'}, 0, "failed to copy auto_create_image.vbs to $computer_node_name "); |
| return 0; |
| } |
| |
| |
| # Make sure sshd service is set to auto |
| if (_set_sshd_startmode($computer_node_name, "auto")) { |
| notify($ERRORS{'OK'}, 0, "successfully set auto mode for sshd start"); |
| } |
| else { |
| notify($ERRORS{'CRITICAL'}, 0, "failed to set auto mode for sshd on $computer_node_name"); |
| return 0; |
| } |
| |
| my @list; |
| my $l; |
| #execute the vbs script to disable the pagefile and reboot |
| undef @sshcmd; |
| @sshcmd = run_ssh_command($computer_node_name, $management_node_keys, "cscript.exe //Nologo auto_create_image.vbs", "root"); |
| foreach $l (@{$sshcmd[1]}) { |
| if ($l =~ /createimage reboot/) { |
| notify($ERRORS{'OK'}, 0, "auto_create_image.vbs initiated, $computer_node_name rebooting, sleeping 50"); |
| sleep 50; |
| next; |
| } |
| elsif ($l =~ /failed error/) { |
| notify($ERRORS{'WARNING'}, 0, "auto_create_image.vbs failed, @{ $sshcmd[1] }"); |
| #legacy code for a bug in xcat, now fixed |
| # force a reboot, or really a power cycle. |
| #crap hate to do this. |
| notify($ERRORS{'WARNING'}, 0, "forcing a power cycle"); |
| if (_rpower($computer_node_name, "boot")) { |
| notify($ERRORS{'WARNING'}, 0, "forced power cycle complete"); |
| next; |
| } |
| } ## end elsif ($l =~ /failed error/) [ if ($l =~ /createimage reboot/) |
| } ## end foreach $l (@{$sshcmd[1]}) |
| |
| |
| #Set up simple ping loop to determine if machine is actually rebooting |
| my $online = 1; |
| my $pingloop = 0; |
| notify($ERRORS{'OK'}, 0, "checking for pingable $computer_node_name"); |
| while ($online) { |
| if (!(_pingnode($computer_node_name))) { |
| notify($ERRORS{'OK'}, 0, "Success $computer_node_name is not pingable"); |
| $online = 0; |
| } |
| else { |
| notify($ERRORS{'OK'}, 0, "$computer_node_name is still pingable - loop $pingloop"); |
| sleep 10; |
| $pingloop++; |
| } |
| if ($pingloop > 10) { |
| notify($ERRORS{'CRITICAL'}, 0, "$computer_node_name should have rebooted by now, trying to force it"); |
| if (_rpower($computer_node_name, "boot")) { |
| notify($ERRORS{'WARNING'}, 0, "forced power cycle complete"); |
| sleep 25; |
| next; |
| } |
| } |
| } ## end while ($online) |
| |
| |
| # Wait until the reboot process has started to shutdown services |
| notify($ERRORS{'OK'}, 0, "$computer_node_name rebooting, waiting"); |
| my $socketflag = 0; |
| |
| |
| REBOOTED: |
| my $rebooted = 1; |
| my $reboot_wait_count = 0; |
| while ($rebooted) { |
| if ($reboot_wait_count > 55) { |
| notify($ERRORS{'CRITICAL'}, 0, "waited $reboot_wait_count on reboot after auto_create_image on $computer_node_name"); |
| return 0; |
| } |
| notify($ERRORS{'OK'}, 0, "$computer_node_name not completed reboot sleeping for 25"); |
| sleep 25; |
| if (_pingnode($computer_node_name)) { |
| #it pingable check if sshd is open |
| notify($ERRORS{'OK'}, 0, "$computer_node_name is pingable, checking sshd port"); |
| my $sshd = _sshd_status($computer_node_name, $image_name); |
| if ($sshd =~ /on/) { |
| $rebooted = 0; |
| notify($ERRORS{'OK'}, 0, "$computer_node_name sshd is open"); |
| } |
| else { |
| notify($ERRORS{'OK'}, 0, "$computer_node_name sshd NOT open yet,sleep 5"); |
| sleep 5; |
| } |
| } ## end if (_pingnode($computer_node_name)) |
| $reboot_wait_count++; |
| } # Close while rebooted |
| |
| |
| # Check for recent bug |
| undef @sshcmd; |
| @sshcmd = run_ssh_command($computer_node_name, $IDENTITY_wxp, "uname -s"); |
| foreach my $l (@{$sshcmd[1]}) { |
| if ($l =~ /^Warning:/) { |
| #if (makesshgkh($computer_node_name)) { |
| #} |
| } |
| if ($l =~ /^Read from socket failed:/) { |
| if ($socketflag) { |
| notify($ERRORS{'CRITICAL'}, 0, "could not login $computer_node_name via ssh socket failure"); |
| return 0; |
| } |
| notify($ERRORS{'CRITICAL'}, 0, "discovered ssh read from socket failure on $computer_node_name, attempting to repair"); |
| #power cycle node |
| if (_rpower($computer_node_name, "cycle")) { |
| notify($ERRORS{'CRITICAL'}, 0, "$computer_node_name power cycled going to reboot check routine"); |
| sleep 40; |
| $socketflag = 1; |
| goto REBOOTED; |
| } |
| } ## end if ($l =~ /^Read from socket failed:/) |
| } ## end foreach my $l (@{$sshcmd[1]}) |
| |
| notify($ERRORS{'OK'}, 0, "proceeding to CIMONITOR"); |
| #monitor for signal to set node to image and then reboot |
| my $sshd_status; |
| my ($loop, $rebootsignal, $reboot_copied) = 0; |
| CIMONITOR: |
| #check ssh port in case we finish above steps before first reboot completes |
| # while ssh port is off sleep few seconds then loop |
| # this section is useless for linux images |
| my $ping_result = _pingnode($computer_node_name); |
| #check our loop |
| if ($loop > 200) { |
| notify($ERRORS{'CRITICAL'}, 0, "CIMONITOR $computer_node_name taking longer to reboot than expected, check it"); |
| return 0; |
| } |
| notify($ERRORS{'OK'}, 0, "CIMONITOR ping check"); |
| if (!$ping_result) { |
| sleep 5; |
| notify($ERRORS{'OK'}, 0, "CIMONITOR ping is off waiting for $computer_node_name to complete reboot"); |
| $loop++; |
| goto CIMONITOR; |
| } |
| # is port 22 open yet |
| if (!nmap_port($computer_node_name, 22)) { |
| notify($ERRORS{'OK'}, 0, "port 22 not open on $computer_node_name yet, looping"); |
| $loop++; |
| sleep 3; |
| goto CIMONITOR; |
| } |
| |
| # Remove old Sysprep files if they exist |
| if (run_ssh_command($computer_node_name, $IDENTITY_wxp, "/usr/bin/rm.exe -rf C:\/Sysprep", "root")) { |
| notify($ERRORS{'OK'}, 0, "removed any existing Sysprep files"); |
| } |
| |
| # Copy Sysprep files |
| COPY_SYSPREP: |
| if ($imagemeta_sysprep) { |
| #cp sysprep to C: |
| #chmod C:\Sysprep\* |
| # which sysprep to use |
| my $sysprep_files; |
| if ($image_name =~ /^winxp/) { |
| $sysprep_files = $SYSPREP; |
| } |
| elsif ($image_name =~ /^win2003/) { |
| $sysprep_files = $SYSPREP_2003; |
| } |
| |
| notify($ERRORS{'OK'}, 0, "copying Sysprep files to $computer_short_name"); |
| if (run_scp_command($sysprep_files, "$computer_node_name:C:\/Sysprep", $IDENTITY_wxp)) { |
| notify($ERRORS{'OK'}, 0, "copied Sysprep directory $sysprep_files to $computer_node_name C:"); |
| |
| if (run_ssh_command($computer_node_name, $IDENTITY_wxp, "/usr/bin/chmod.exe -R 755 C:\/Sysprep", "root")) { |
| notify($ERRORS{'OK'}, 0, "chmoded -R 755 C:\/Sysprep files "); |
| } |
| else { |
| notify($ERRORS{'CRITICAL'}, 0, "could not chmod -R 755 on $computer_node_name $!"); |
| } |
| } ## end if (run_scp_command($sysprep_files, "$computer_node_name:C:\/Sysprep"... |
| else { |
| notify($ERRORS{'CRITICAL'}, 0, "could not copy $sysprep_files to $computer_node_name, $!"); |
| return 0; |
| } |
| } ## end if ($imagemeta_sysprep) |
| |
| # Set sshd service startup to manual |
| if (_set_sshd_startmode($computer_node_name, "manual")) { |
| notify($ERRORS{'OK'}, 0, "successfully set manual mode for sshd start"); |
| } |
| else { |
| notify($ERRORS{'CRITICAL'}, 0, "failed to set manual mode for sshd on $computer_node_name"); |
| return 0; |
| } |
| |
| |
| #actually remove the pagefile.sys sometimes movefile.exe does not work |
| if (run_ssh_command($computer_node_name, $IDENTITY_wxp, "/usr/bin/rm -v C:\/pagefile.sys", "root")) { |
| notify($ERRORS{'OK'}, 0, "removed pagefile.sys "); |
| } |
| |
| notify($ERRORS{'OK'}, 0, "returning 1"); |
| return 1; |
| } ## end sub capture_prepare |
| |
| #///////////////////////////////////////////////////////////////////////////// |
| |
| =head2 capture_start |
| |
| Parameters : |
| Returns : |
| Description : |
| |
| =cut |
| |
| sub capture_start { |
| |
| 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; |
| } |
| |
| my $request_id = $self->data->get_request_id(); |
| my $reservation_id = $self->data->get_reservation_id(); |
| my $image_id = $self->data->get_image_id(); |
| my $image_os_name = $self->data->get_image_os_name(); |
| my $management_node_keys = $self->data->get_management_node_keys(); |
| my $image_os_type = $self->data->get_image_os_type(); |
| my $image_name = $self->data->get_image_name(); |
| my $imagemeta_sysprep = $self->data->get_imagemeta_sysprep(); |
| my $computer_id = $self->data->get_computer_id(); |
| my $computer_short_name = $self->data->get_computer_short_name(); |
| my $computer_node_name = $self->data->get_computer_node_name(); |
| my $computer_type = $self->data->get_computer_type(); |
| my $user_id = $self->data->get_user_id(); |
| my $user_unityid = $self->data->get_user_login_id(); |
| my $managementnode_shortname = $self->data->get_management_node_short_name(); |
| my $computer_private_ip = $self->data->get_computer_private_ip(); |
| |
| notify($ERRORS{'OK'}, 0, "initiating Windows image capture: $image_name on $computer_short_name"); |
| |
| my @sshcmd; |
| |
| if ($imagemeta_sysprep) { |
| notify($ERRORS{'OK'}, 0, "starting sysprep on $computer_node_name"); |
| if (open(SSH, "/usr/bin/ssh -q -i $IDENTITY_wxp $computer_node_name \"C:\/Sysprep\/sysprep.cmd\" 2>&1 |")) { |
| my $notstop = 1; |
| my $loop = 0; |
| while ($notstop) { |
| my $l = <SSH>; |
| $loop++; |
| #notify($ERRORS{'DEBUG'}, 0, "sysprep.cmd loop count: $loop"); |
| #notify($ERRORS{'DEBUG'}, 0, "$l"); |
| if ($l =~ /sysprep/) { |
| notify($ERRORS{'OK'}, 0, "sysprep.exe has started, $l"); |
| |
| notify($ERRORS{'DEBUG'}, 0, "attempting to kill management node sysprep.cmd SSH process in 60 seconds"); |
| sleep 60; |
| |
| notify($ERRORS{'DEBUG'}, 0, "attempting to kill management node sysprep.cmd SSH process"); |
| if (_killsysprep($computer_node_name)) { |
| notify($ERRORS{'OK'}, 0, "killed sshd process for sysprep command"); |
| } |
| |
| notify($ERRORS{'DEBUG'}, 0, "closing SSH filehandle"); |
| close(SSH); |
| notify($ERRORS{'DEBUG'}, 0, "SSH filehandle closed"); |
| |
| $notstop = 0; |
| } ## end if ($l =~ /sysprep/) |
| elsif ($l =~ /sysprep.cmd: Permission denied/) { |
| notify($ERRORS{'CRITICAL'}, 0, "chmod 755 failed to correctly set execute on sysprep.cmd output $l"); |
| close(SSH); |
| return 0; |
| } |
| |
| #avoid infinite loop |
| if ($loop > 1000) { |
| notify($ERRORS{'DEBUG'}, 0, "sysprep executed in loop control condition, exceeded limit"); |
| |
| notify($ERRORS{'DEBUG'}, 0, "attempting to kill management node sysprep.cmd SSH process in 60 seconds"); |
| sleep 60; |
| |
| notify($ERRORS{'DEBUG'}, 0, "attempting to kill management node sysprep.cmd SSH process"); |
| if (_killsysprep($computer_node_name)) { |
| notify($ERRORS{'OK'}, 0, "killed sshd process for sysprep command"); |
| } |
| |
| notify($ERRORS{'DEBUG'}, 0, "closing SSH filehandle"); |
| close(SSH); |
| notify($ERRORS{'DEBUG'}, 0, "SSH filehandle closed"); |
| |
| $notstop = 0; |
| } ## end if ($loop > 1000) |
| |
| } ## end while ($notstop) |
| } # Close open handle for SSH sysprep.cmd command |
| else { |
| notify($ERRORS{'CRITICAL'}, 0, "failed to start sysprep on $computer_node_name $!"); |
| return 0; |
| } # Close sysprep.cmd could not be launched |
| } # Close if Sysprep |
| |
| else { |
| #non sysprep option |
| # |
| #just reboot machine -- future expansion of additional methods newsid, custom scripts, etc. |
| notify($ERRORS{'OK'}, 0, "starting custom script VCLprep1.vbs on $computer_node_name"); |
| if (run_scp_command("$TOOLS/VCLprep1.vbs", "$computer_node_name:VCLprep1.vbs", $IDENTITY_wxp)) { |
| undef @sshcmd; |
| @sshcmd = run_ssh_command($computer_node_name, $IDENTITY_wxp, "cscript //Nologo VCLprep1.vbs", "root"); |
| foreach my $s (@{$sshcmd[1]}) { |
| chomp($s); |
| if ($s =~ /copied VCLprepare/) { |
| notify($ERRORS{'OK'}, 0, "$s"); |
| } |
| if ($s =~ /rebooting/) { |
| notify($ERRORS{'OK'}, 0, "SUCCESS started image procedure on $computer_node_name"); |
| last; |
| } |
| } ## end foreach my $s (@{$sshcmd[1]}) |
| } # Close SCP VCLPrep1.vbs |
| else { |
| notify($ERRORS{'CRITICAL'}, 0, "failed to copy $TOOLS/VCLprep1.vbs to $computer_node_name "); |
| return 0; |
| } |
| } # Close if not Sysprep |
| |
| notify($ERRORS{'OK'}, 0, "returning 1"); |
| return 1; |
| } ## end sub capture_start |
| |
| #///////////////////////////////////////////////////////////////////////////// |
| |
| 1; |
| __END__ |
| |
| =head1 BUGS and LIMITATIONS |
| |
| There are no known bugs in this module. |
| Please report problems to the VCL team (vcl_help@ncsu.edu). |
| |
| =head1 AUTHOR |
| |
| Aaron Peeler, aaron_peeler@ncsu.edu |
| Andy Kurth, andy_kurth@ncsu.edu |
| |
| =head1 SEE ALSO |
| |
| L<http://vcl.ncsu.edu> |
| |
| |
| =cut |