You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@vcl.apache.org by jf...@apache.org on 2008/12/12 19:20:18 UTC
svn commit: r726079 [5/32] - in /incubator/vcl/tags/import: ./
managementnode/ managementnode/bin/ managementnode/etc/
managementnode/etc/vcl/ managementnode/legacy_vcl_vbs_scripts/
managementnode/lib/ managementnode/lib/VCL/ managementnode/lib/VCL/Mod...
Added: incubator/vcl/tags/import/managementnode/lib/VCL/Module/OS/Windows.pm
URL: http://svn.apache.org/viewvc/incubator/vcl/tags/import/managementnode/lib/VCL/Module/OS/Windows.pm?rev=726079&view=auto
==============================================================================
--- incubator/vcl/tags/import/managementnode/lib/VCL/Module/OS/Windows.pm (added)
+++ incubator/vcl/tags/import/managementnode/lib/VCL/Module/OS/Windows.pm Fri Dec 12 10:20:10 2008
@@ -0,0 +1,798 @@
+#!/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
Added: incubator/vcl/tags/import/managementnode/lib/VCL/Module/OS/Windows/Desktop.pm
URL: http://svn.apache.org/viewvc/incubator/vcl/tags/import/managementnode/lib/VCL/Module/OS/Windows/Desktop.pm?rev=726079&view=auto
==============================================================================
--- incubator/vcl/tags/import/managementnode/lib/VCL/Module/OS/Windows/Desktop.pm (added)
+++ incubator/vcl/tags/import/managementnode/lib/VCL/Module/OS/Windows/Desktop.pm Fri Dec 12 10:20:10 2008
@@ -0,0 +1,84 @@
+#!/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: Desktop.pm 1953 2008-12-12 14:23:17Z arkurth $
+##############################################################################
+
+=head1 NAME
+
+VCL::Module::OS::Windows::Desktop
+
+=head1 SYNOPSIS
+
+ Needs to be written
+
+=head1 DESCRIPTION
+
+ This module provides...
+
+=cut
+
+##############################################################################
+package VCL::Module::OS::Windows::Desktop;
+
+# Specify the lib path using FindBin
+use FindBin;
+use lib "$FindBin::Bin/../../../..";
+
+# Configure inheritance
+use base qw(VCL::Module::OS::Windows);
+
+# 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;
+
+##############################################################################
+
+=head1 OBJECT METHODS
+
+=cut
+
+#/////////////////////////////////////////////////////////////////////////////
+
+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
Added: incubator/vcl/tags/import/managementnode/lib/VCL/Module/OS/Windows/Desktop/Vista.pm
URL: http://svn.apache.org/viewvc/incubator/vcl/tags/import/managementnode/lib/VCL/Module/OS/Windows/Desktop/Vista.pm?rev=726079&view=auto
==============================================================================
--- incubator/vcl/tags/import/managementnode/lib/VCL/Module/OS/Windows/Desktop/Vista.pm (added)
+++ incubator/vcl/tags/import/managementnode/lib/VCL/Module/OS/Windows/Desktop/Vista.pm Fri Dec 12 10:20:10 2008
@@ -0,0 +1,1508 @@
+#!/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: Vista.pm 1953 2008-12-12 14:23:17Z arkurth $
+##############################################################################
+
+=head1 NAME
+
+VCL::Module::OS::Windows::Desktop::Vista.pm - VCL module to support Windows Vista operating system
+
+=head1 SYNOPSIS
+
+ Needs to be written
+
+=head1 DESCRIPTION
+
+ This module provides VCL support for Windows Vista.
+
+=cut
+
+##############################################################################
+package VCL::Module::OS::Windows::Desktop::Vista;
+
+# Specify the lib path using FindBin
+use FindBin;
+use lib "$FindBin::Bin/../../../../..";
+
+# Configure inheritance
+use base qw(VCL::Module::OS::Windows::Desktop);
+
+# 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::Provisioning::xCAT;
+use File::Basename;
+
+##############################################################################
+
+=head1 CLASS VARIABLES
+
+=cut
+
+=head2 $CONFIGURATION_FILES
+
+ Data type : Scalar
+ Description : Location of script/utilty/configuration files needed to
+ configure the OS. This is normally the directory under
+ the 'tools' directory specific to this OS.
+
+=cut
+
+our $CONFIGURATION_DIRECTORY = "$TOOLS/Sysprep_Vista";
+
+=head2 $ROOT_PASSWORD
+
+ Data type : Scalar
+ Description : Password for the node's root account.
+
+=cut
+
+our $ROOT_PASSWORD = $WINDOWS_ROOT_PASSWORD;
+
+##############################################################################
+
+=head1 OBJECT METHODS
+
+=cut
+
+#/////////////////////////////////////////////////////////////////////////////
+
+=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 Vista image capture preparation tasks: $image_name on $computer_short_name");
+
+ $self->disable_autoadminlogon();
+ #$self->import_registry_file("$CONFIGURATION_DIRECTORY/Scripts/test.reg");
+ #$self->disable_pagefile();
+ #$self->firewall_disable_rdp();
+ #$self->firewall_enable_rdp('152.1.0.0/16');
+ exit;
+
+ # Node variables
+ my $local_configuration_directory = 'C:/VCL';
+ my $local_scripts_directory = 'C:/VCL/Scripts';
+
+
+ # Remove old configuration files if they exist
+ notify($ERRORS{'OK'}, 0, "attempting to remove old configuration directory if it exists: $local_configuration_directory");
+ my ($remove_old_status, $remove_old_output) = run_ssh_command($computer_node_name, $management_node_keys, "/usr/bin/rm.exe -rf $local_configuration_directory");
+ if (defined($remove_old_status) && $remove_old_status == 0) {
+ notify($ERRORS{'OK'}, 0, "removed existing configuration directory: $local_configuration_directory");
+ }
+ elsif (defined($remove_old_status)) {
+ notify($ERRORS{'OK'}, 0, "unable to remove existing configuration directory: $local_configuration_directory, exit status: $remove_old_status, output:\n@{$remove_old_output}");
+ }
+ else {
+ notify($ERRORS{'WARNING'}, 0, "failed to run ssh command to remove existing configuration directory: $local_configuration_directory");
+ return 0;
+ }
+
+
+ # Copy configuration files
+ notify($ERRORS{'OK'}, 0, "copying Sysprep and other configuration files to $computer_short_name");
+ if (run_scp_command($CONFIGURATION_DIRECTORY, "$computer_node_name:$local_configuration_directory", $IDENTITY_wxp)) {
+ notify($ERRORS{'OK'}, 0, "copied $CONFIGURATION_DIRECTORY directory to $computer_node_name:$local_configuration_directory");
+
+ notify($ERRORS{'OK'}, 0, "attempting to set permissions on $computer_node_name:$local_configuration_directory");
+ if (run_ssh_command($computer_node_name, $IDENTITY_wxp, "/usr/bin/chmod.exe -R 755 $local_configuration_directory")) {
+ notify($ERRORS{'OK'}, 0, "chmoded -R 755 $computer_node_name:$local_configuration_directory");
+ }
+ else {
+ notify($ERRORS{'WARNING'}, 0, "could not chmod -R 755 $computer_node_name:$local_configuration_directory");
+ }
+ } ## end if (run_scp_command($CONFIGURATION_DIRECTORY, "$computer_node_name:C:\/Sysprep"...
+ else {
+ notify($ERRORS{'WARNING'}, 0, "failed to copy $CONFIGURATION_DIRECTORY to $computer_node_name");
+ return 0;
+ }
+
+
+ # Set root account password
+ notify($ERRORS{'OK'}, 0, "changing root password on $computer_short_name");
+ my ($root_password_exit_status, $root_password_output) = run_ssh_command($computer_node_name, $management_node_keys, "net user root '$ROOT_PASSWORD'");
+ if ($root_password_exit_status == 0) {
+ notify($ERRORS{'OK'}, 0, "root password changed to $ROOT_PASSWORD");
+ }
+ else {
+ notify($ERRORS{'WARNING'}, 0, "failed to change root password to $ROOT_PASSWORD, exit status: $root_password_exit_status, output:\n@{$root_password_output}");
+ return 0;
+ }
+
+ # Log off all currently logged in users
+ notify($ERRORS{'OK'}, 0, "logging off all currently logged in users");
+ logoff_users($computer_node_name);
+
+ # Wait to allow any files in use by users justed logged out to close
+ notify($ERRORS{'OK'}, 0, "waiting for 5 seconds after any users were logged off to allow files to close");
+ sleep 5;
+
+ # Delete the user assigned to this reservation
+ notify($ERRORS{'OK'}, 0, "attempting to delete user $user_unityid from $computer_node_name");
+ delete_user($computer_node_name, $user_id);
+
+
+ my @sshcmd;
+ 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
+ #DEFRAG: notify($ERRORS{'OK'}, 0, "starting defrag on $computer_node_name");
+ #my ($defrag_exit_status, $defrag_output) = run_ssh_command($computer_node_name, $management_node_keys, "defrag.exe C: -v");
+ #if (defined($defrag_exit_status)) {
+ # notify($ERRORS{'OK'}, 0, "defrag exit status: $defrag_exit_status, defrag output:\n$defrag_output");
+ #}
+ #else {
+ # notify($ERRORS{'WARNING'}, 0, "defrag failed");
+ #}
+
+
+
+ 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 $local_scripts_directory/auto_create_image.vbs");
+ 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 (VCL::Module::Provisioning::xCAT::_rpower($computer_node_name, "cycle")) {
+ 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 (VCL::Module::Provisioning::xCAT::_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 (VCL::Module::Provisioning::xCAT::_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;
+ }
+
+ ## 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 -fv C:\/pagefile.sys")) {
+ 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
+
+#/////////////////////////////////////////////////////////////////////////////
+
+=head2 user_exists
+
+ Parameters :
+ Returns :
+ Description :
+
+=cut
+
+sub user_exists {
+ my ($node, $user) = @_;
+ notify($ERRORS{'WARNING'}, 0, "node is not defined") if (!(defined($node)));
+ notify($ERRORS{'WARNING'}, 0, "user is not defined") if (!(defined($user)));
+
+ my ($net_user_exit_status, $net_user_output) = run_ssh_command($node, $IDENTITY_wxp, "net user $user");
+ if ($net_user_exit_status == 0) {
+ notify($ERRORS{'OK'}, 0, "user $user exists on $node");
+ return 1;
+ }
+ elsif ($net_user_exit_status == 2) {
+ notify($ERRORS{'OK'}, 0, "user $user does NOT exist on $node");
+ return 0;
+ }
+ elsif ($net_user_exit_status) {
+ notify($ERRORS{'WARNING'}, 0, "failed to determine if user $user exists on $node, exit status: $net_user_exit_status, output:\n@{$net_user_output}");
+ return;
+ }
+ else {
+ notify($ERRORS{'WARNING'}, 0, "failed to run SSH command to determine if user $user exists on $node");
+ return;
+ }
+}
+
+#/////////////////////////////////////////////////////////////////////////////
+
+=head2 logoff_users
+
+ Parameters :
+ Returns :
+ Description :
+
+=cut
+
+sub logoff_users {
+ my $self = shift;
+ my $management_node_keys = $self->data->get_management_node_keys();
+ my $computer_node_name = $self->data->get_computer_node_name();
+
+
+ my ($exit_status, $output) = run_ssh_command($computer_node_name, $management_node_keys, "qwinsta.exe");
+ if ($exit_status > 0) {
+ notify($ERRORS{'WARNING'}, 0, "failed to run qwinsta.exe on $computer_node_name, exit status: $exit_status, output:\n@{$output}");
+ return;
+ }
+ elsif (!defined($exit_status)) {
+ notify($ERRORS{'WARNING'}, 0, "failed to run qwinsta.exe SSH command on $computer_node_name");
+ return;
+ }
+
+ my @active_user_lines = grep(/Active/, @{$output});
+
+ notify($ERRORS{'OK'}, 0, "users are currently logged in on $computer_node_name: " . @active_user_lines);
+
+ foreach my $active_user_line (@active_user_lines) {
+ $active_user_line =~ /\s+(\S+)\s+(.*\w)\s*(\d+)\s+Active.*/;
+ my $session_name = $1;
+ my $username = $2;
+ my $session_id = $3;
+
+ notify($ERRORS{'DEBUG'}, 0, "user logged in: $username, session name: $session_name, session id: $session_id");
+
+ my ($logoff_exit_status, $logoff_output) = run_ssh_command($computer_node_name, $management_node_keys, "logoff.exe /v $session_id");
+ if ($logoff_exit_status == 0) {
+ notify($ERRORS{'OK'}, 0, "logged off user: $username, exit status: $logoff_exit_status, output:\n@{$logoff_output}");
+ }
+ else {
+ notify($ERRORS{'WARNING'}, 0, "failed to log off user: $username, exit status: $logoff_exit_status, output:\n@{$logoff_output}");
+ }
+
+ }
+
+ return 1;
+}
+
+#/////////////////////////////////////////////////////////////////////////////
+
+=head2 delete_user
+
+ Parameters : $node, $user, $type, $osname
+ Returns : 1 success 0 failure
+ Description : removes user account and profile directory from specificed node
+
+=cut
+
+sub delete_user {
+ my $self = shift;
+ my $management_node_keys = $self->data->get_management_node_keys();
+ my $computer_node_name = $self->data->get_computer_node_name();
+
+ # Attempt to get the username from the arguments
+ # If no argument was supplied, use the user specified in the DataStructure
+ my $username = shift;
+ if (!(defined($username))) {
+ $username = $self->data->get_user_logon_id();
+ }
+
+ notify($ERRORS{'OK'}, 0, "attempting to delete user $username from $computer_node_name");
+
+ # Attempt to delete the user account
+ my $delete_user_command = "net user $username /DELETE";
+ my ($delete_user_exit_status, $delete_user_output) = run_ssh_command($computer_node_name, $management_node_keys, $delete_user_command);
+ if (defined($delete_user_exit_status) && $delete_user_exit_status == 0) {
+ notify($ERRORS{'OK'}, 0, "deleted user $username from $computer_node_name");
+ }
+ elsif (defined($delete_user_exit_status)) {
+ notify($ERRORS{'WARNING'}, 0, "failed to delete user $username from $computer_node_name, exit status: $delete_user_exit_status, output:\n@{$delete_user_output}");
+ return 0;
+ }
+ else {
+ notify($ERRORS{'WARNING'}, 0, "failed to run ssh command delete user $username from $computer_node_name");
+ return;
+ }
+
+ # Delete the user's home directory
+ my $delete_profile_command = "/bin/rm -rf /cygdrive/c/Users/$username";
+ my ($delete_profile_exit_status, $delete_profile_output) = run_ssh_command($computer_node_name, $management_node_keys, $delete_profile_command);
+ if (defined($delete_profile_exit_status) && $delete_profile_exit_status == 0) {
+ notify($ERRORS{'OK'}, 0, "deleted profile for user $username from $computer_node_name");
+ }
+ elsif (defined($delete_profile_exit_status)) {
+ notify($ERRORS{'WARNING'}, 0, "failed to delete profile for user $username from $computer_node_name, exit status: $delete_profile_exit_status, output:\n@{$delete_profile_output}");
+ return 0;
+ }
+ else {
+ notify($ERRORS{'WARNING'}, 0, "failed to run ssh command delete profile for user $username from $computer_node_name");
+ return;
+ }
+
+ return 1;
+} ## end sub del_user
+
+#/////////////////////////////////////////////////////////////////////////////
+
+=head2 disable_pagefile
+
+ Parameters :
+ Returns :
+ Description :
+
+=cut
+
+sub disable_pagefile {
+ my $self = shift;
+ my $management_node_keys = $self->data->get_management_node_keys();
+ my $computer_node_name = $self->data->get_computer_node_name();
+
+ my $disable_pagefile_key = "HKEY_LOCAL_MACHINE\\SYSTEM\\CurrentControlSet\\Control\\Session Manager\\Memory Management";
+ my $disable_pagefile_command = "reg.exe add \"$disable_pagefile_key\" /v \"PagingFiles\" /t REG_SZ /d \"\" /f";
+ my ($disable_pagefile_exit_status, $disable_pagefile_output) = run_ssh_command($computer_node_name, $management_node_keys, $disable_pagefile_command);
+ if ($disable_pagefile_exit_status == 0) {
+ notify($ERRORS{'OK'}, 0, "registry key set to disable pagefile");
+ }
+ elsif ($disable_pagefile_exit_status) {
+ notify($ERRORS{'WARNING'}, 0, "failed to set registry key to disable pagefile, exit status: $disable_pagefile_exit_status, output:\n@{$disable_pagefile_output}");
+ return;
+ }
+ else {
+ notify($ERRORS{'WARNING'}, 0, "failed to run SSH command to set registry key to disable pagefile");
+ return;
+ }
+
+ # Attempt to reboot the computer in order to delete the pagefile
+ if ($self->reboot()) {
+ notify($ERRORS{'OK'}, 0, "computer was rebooted after disabling pagefile in the registry");
+ }
+ else {
+ notify($ERRORS{'WARNING'}, 0, "failed to reboot computer after disabling pagefile");
+ return;
+ }
+
+ # Attempt to delete the pagefile
+ my $delete_pagefile_command = "attrib.exe -S -H -R C:/pagefile.sys";
+ $delete_pagefile_command .= " && /usr/bin/rm.exe -rfv C:/pagefile.sys";
+ my ($delete_pagefile_exit_status, $delete_pagefile_output) = run_ssh_command($computer_node_name, $management_node_keys, $delete_pagefile_command);
+ if ($delete_pagefile_exit_status == 0) {
+ notify($ERRORS{'OK'}, 0, "pagefile.sys was deleted");
+ return 1;
+ }
+ elsif ($delete_pagefile_exit_status) {
+ notify($ERRORS{'WARNING'}, 0, "failed to delete pagefile.sys, exit status: $delete_pagefile_exit_status, output:\n@{$delete_pagefile_output}");
+ return;
+ }
+ else {
+ notify($ERRORS{'WARNING'}, 0, "failed to run SSH command to delete pagefile.sys");
+ return;
+ }
+}
+
+#/////////////////////////////////////////////////////////////////////////////
+
+=head2 import_registry_file
+
+ Parameters :
+ Returns :
+ Description :
+
+=cut
+
+sub import_registry_file {
+ my $self = shift;
+ my $management_node_keys = $self->data->get_management_node_keys();
+ my $computer_node_name = $self->data->get_computer_node_name();
+
+ my $registry_file_path = shift;
+ if (!defined($registry_file_path) || !$registry_file_path) {
+ notify($ERRORS{'WARNING'}, 0, "registry file path was not passed correctly as an argument");
+ return;
+ }
+
+ my $registry_file_contents = `cat $registry_file_path`;
+ notify($ERRORS{'DEBUG'}, 0, "registry file contents:\n$registry_file_contents");
+ $registry_file_contents =~ s/([\"])/\\$1/gs;
+
+ my $import_registry_command = "/usr/bin/echo.exe -E \"$registry_file_contents\" > tmp.reg";
+ $import_registry_command .= " && reg.exe IMPORT tmp.reg";
+ my ($import_registry_exit_status, $import_registry_output) = run_ssh_command($computer_node_name, $management_node_keys, $import_registry_command);
+ if ($import_registry_exit_status == 0) {
+ notify($ERRORS{'OK'}, 0, "registry file contents imported");
+ }
+ elsif ($import_registry_exit_status) {
+ notify($ERRORS{'WARNING'}, 0, "failed to import registry file contents, exit status: $import_registry_exit_status, output:\n@{$import_registry_output}");
+ return;
+ }
+ else {
+ notify($ERRORS{'WARNING'}, 0, "failed to run SSH command to import registry file contents");
+ return;
+ }
+
+}
+
+#/////////////////////////////////////////////////////////////////////////////
+
+=head2 import_registry_string
+
+ Parameters :
+ Returns :
+ Description :
+
+=cut
+
+sub import_registry_string {
+ my $self = shift;
+ my $management_node_keys = $self->data->get_management_node_keys();
+ my $computer_node_name = $self->data->get_computer_node_name();
+
+ my $registry_string = shift;
+ if (!defined($registry_string) || !$registry_string) {
+ notify($ERRORS{'WARNING'}, 0, "registry file path was not passed correctly as an argument");
+ return;
+ }
+
+ notify($ERRORS{'DEBUG'}, 0, "registry string:\n$registry_string");
+ $registry_string =~ s/([\"])/\\$1/gs;
+
+ my $import_registry_command = "/usr/bin/echo.exe -E \"$registry_string\" > tmp.reg";
+ $import_registry_command .= " && reg.exe IMPORT tmp.reg";
+ my ($import_registry_exit_status, $import_registry_output) = run_ssh_command($computer_node_name, $management_node_keys, $import_registry_command);
+ if ($import_registry_exit_status == 0) {
+ notify($ERRORS{'OK'}, 0, "registry string contents imported");
+ }
+ elsif ($import_registry_exit_status) {
+ notify($ERRORS{'WARNING'}, 0, "failed to import registry string contents, exit status: $import_registry_exit_status, output:\n@{$import_registry_output}");
+ return;
+ }
+ else {
+ notify($ERRORS{'WARNING'}, 0, "failed to run SSH command to import registry string contents");
+ return;
+ }
+
+}
+
+#/////////////////////////////////////////////////////////////////////////////
+
+=head2 enable_autoadminlogon
+
+ Parameters :
+ Returns :
+ Description :
+
+=cut
+
+sub enable_autoadminlogon {
+ my $self = shift;
+ my $management_node_keys = $self->data->get_management_node_keys();
+ my $computer_node_name = $self->data->get_computer_node_name();
+
+ my $registry_string .= <<"EOF";
+Windows Registry Editor Version 5.00
+
+; This file enables autoadminlogon for the root account
+
+[HKEY_LOCAL_MACHINE\\SOFTWARE\\Microsoft\\Windows NT\\CurrentVersion\\Winlogon]
+"AutoAdminLogon"="1"
+"DefaultUserName"="root"
+"DefaultPassword"= "$ROOT_PASSWORD"
+EOF
+
+ # Import the string into the registry
+ if ($self->import_registry_string($registry_string)) {
+ notify($ERRORS{'WARNING'}, 0, "successfully enabled autoadminlogon");
+ return 1;
+ }
+ else {
+ notify($ERRORS{'WARNING'}, 0, "failed to enable autoadminlogon");
+ return 0;
+ }
+}
+
+#/////////////////////////////////////////////////////////////////////////////
+
+=head2 disable_autoadminlogon
+
+ Parameters :
+ Returns :
+ Description :
+
+=cut
+
+sub disable_autoadminlogon {
+ my $self = shift;
+ my $management_node_keys = $self->data->get_management_node_keys();
+ my $computer_node_name = $self->data->get_computer_node_name();
+
+ my $registry_string .= <<EOF;
+Windows Registry Editor Version 5.00
+
+; This file disables autoadminlogon for the root account
+
+[HKEY_LOCAL_MACHINE\\SOFTWARE\\Microsoft\\Windows NT\\CurrentVersion\\Winlogon]
+"AutoAdminLogon"="0"
+"DefaultUserName"=""
+"DefaultPassword"= ""
+EOF
+
+ # Import the string into the registry
+ if ($self->import_registry_string($registry_string)) {
+ notify($ERRORS{'WARNING'}, 0, "successfully disabled autoadminlogon");
+ return 1;
+ }
+ else {
+ notify($ERRORS{'WARNING'}, 0, "failed to disable autoadminlogon");
+ return 0;
+ }
+}
+
+#/////////////////////////////////////////////////////////////////////////////
+
+=head2 reboot
+
+ Parameters :
+ Returns :
+ Description :
+
+=cut
+
+sub reboot {
+ my $self = shift;
+ my $management_node_keys = $self->data->get_management_node_keys();
+ my $computer_node_name = $self->data->get_computer_node_name();
+
+ my $reboot_start_time = time();
+ notify($ERRORS{'DEBUG'}, 0, "reboot will be attempted on $computer_node_name");
+
+ # Make sure sshd service is set to auto
+ notify($ERRORS{'DEBUG'}, 0, "attempting to make sure sshd service startup is set to auto");
+ if (_set_sshd_startmode($computer_node_name, "auto")) {
+ notify($ERRORS{'OK'}, 0, "successfully set sshd service startup mode to auto on $computer_node_name");
+ }
+ else {
+ notify($ERRORS{'WARNING'}, 0, "failed to set sshd service startup mode to auto on $computer_node_name");
+ }
+
+
+ # Initiate the shutdown.exe command to reboot the computer
+ my $shutdown_command = "C:/Windows/system32/shutdown.exe -r -t 0 -f";
+ my ($shutdown_exit_status, $shutdown_output) = run_ssh_command($computer_node_name, $management_node_keys, $shutdown_command);
+ if (defined($shutdown_exit_status) && $shutdown_exit_status == 0) {
+ notify($ERRORS{'OK'}, 0, "successfully executed reboot command on $computer_node_name");
+ }
+ elsif (defined($shutdown_exit_status)) {
+ notify($ERRORS{'WARNING'}, 0, "failed to execute reboot command on $computer_node_name, exit status: $shutdown_exit_status, output:\n@{$shutdown_output}");
+ return 0;
+ }
+ else {
+ notify($ERRORS{'WARNING'}, 0, "failed to execute ssh command to reboot $computer_node_name");
+ return;
+ }
+
+ notify($ERRORS{'OK'}, 0, "sleeping for 30 seconds while $computer_node_name begins reboot");
+ sleep 30;
+
+ # Wait maximum of 4 minutes for the computer to go offline then come back up
+ if (!$self->wait_for_ping(4)) {
+ # Check if the computer was ever offline, it should have been or else reboot never happened
+ notify($ERRORS{'WARNING'}, 0, "$computer_node_name never responded to ping, attempting hard power reset");
+
+ # Just explicitly call xCAT's _rpower for now
+ # TODO: implement public reset() subroutines in all of the provisioning modules
+ # TODO: allow provisioning and OS modules access to each other's subroutines
+ if (VCL::Module::Provisioning::xCAT::_rpower($computer_node_name, "cycle")) {
+ notify($ERRORS{'OK'}, 0, "initiated hard power reset on $computer_node_name");
+ }
+ else {
+ notify($ERRORS{'WARNING'}, 0, "reboot failed, failed to initiate hard power reset on $computer_node_name");
+ return 0;
+ }
+
+ # Wait for computer to respond to ping after initiating hard reset
+ # Wait longer than the first attempt
+ if (!$self->wait_for_ping(6)) {
+ # Check if the computer was ever offline, it should have been or else reboot never happened
+ notify($ERRORS{'WARNING'}, 0, "reboot failed, $computer_node_name never responded to ping even after hard power reset");
+ return 0;
+ }
+ }
+
+ notify($ERRORS{'OK'}, 0, "sleeping for 15 seconds while $computer_node_name initializes");
+ sleep 15;
+
+ # Ping successful, try ssh
+ notify($ERRORS{'OK'}, 0, "waiting for ssh to respond on $computer_node_name");
+ if ($self->wait_for_ssh(3)) {
+ my $reboot_end_time = time();
+ my $reboot_duration = ($reboot_end_time - $reboot_start_time);
+ notify($ERRORS{'OK'}, 0, "reboot succeeded on $computer_node_name, took $reboot_duration seconds");\
+ return 1;
+ }
+ else {
+ notify($ERRORS{'WARNING'}, 0, "reboot failed, ssh never became available on $computer_node_name");
+ return 0;
+ }
+
+}
+
+#/////////////////////////////////////////////////////////////////////////////
+
+=head2 wait_for_ping
+
+ Parameters : Maximum number of minutes to wait (optional)
+ Returns : 1 if computer is pingable, 0 otherwise
+ Description : Attempts to ping the computer specified in the DataStructure
+ for the current reservation. It will wait up to a maximum number
+ of minutes. This can be specified by passing the subroutine an
+ integer value or the default value of 5 minutes will be used.
+
+=cut
+
+sub wait_for_ping {
+ my $self = shift;
+ my $computer_node_name = $self->data->get_computer_node_name();
+
+ # Attempt to get the total number of minutes to wait from the command line
+ my $total_wait_minutes = shift;
+ if (!defined($total_wait_minutes) || $total_wait_minutes !~ /^\d+$/) {
+ $total_wait_minutes = 5;
+ }
+
+ # Looping configuration variables
+ # Seconds to wait in between loop attempts
+ my $attempt_delay = 30;
+ # Total loop attempts made
+ # Add 1 to the number of attempts because if you're waiting for x intervals, you check x+1 times including at 0
+ my $attempts = ($total_wait_minutes * 2) + 1;
+
+ notify($ERRORS{'OK'}, 0, "waiting for $computer_node_name to respond to ping, maximum of $total_wait_minutes minutes");
+
+ # Loop until computer is online
+ my $computer_was_offline = 0;
+ my $computer_pingable = 0;
+ for (my $attempt = 1; $attempt <= $attempts; $attempt++) {
+ notify($ERRORS{'OK'}, 0, "attempt $attempt/$attempts: checking if computer is pingable: $computer_node_name");
+ $computer_pingable = _pingnode($computer_node_name);
+
+ if ($computer_pingable && $computer_was_offline) {
+ notify($ERRORS{'OK'}, 0, "$computer_node_name is pingable, reboot is nearly complete");
+ last;
+ }
+ elsif ($computer_pingable && !$computer_was_offline) {
+ notify($ERRORS{'OK'}, 0, "$computer_node_name is still pingable, reboot has not begun");
+ }
+ else {
+ $computer_was_offline = 1;
+ notify($ERRORS{'OK'}, 0, "$computer_node_name is not pingable, reboot is not complete");
+ }
+
+ notify($ERRORS{'OK'}, 0, "sleeping for $attempt_delay seconds before next ping attempt");
+ sleep $attempt_delay;
+ }
+
+ # Check if the computer ever went offline and if it is now pingable
+ if ($computer_pingable && $computer_was_offline) {
+ notify($ERRORS{'OK'}, 0, "$computer_node_name was offline and is now pingable");
+ return 1;
+ }
+ elsif ($computer_pingable && !$computer_was_offline) {
+ notify($ERRORS{'WARNING'}, 0, "$computer_node_name was never offline and is still pingable");
+ return 0;
+ }
+ else {
+ my $total_wait = ($attempts * $attempt_delay);
+ notify($ERRORS{'WARNING'}, 0, "$computer_node_name is not pingable after waiting for $total_wait seconds");
+ return 0;
+ }
+}
+
+#/////////////////////////////////////////////////////////////////////////////
+
+=head2 wait_for_ssh
+
+ Parameters : Maximum number of minutes to wait (optional)
+ Returns : 1 if ssh succeeded to computer, 0 otherwise
+ Description : Attempts to communicate to the computer specified in the
+ DataStructure for the current reservation via SSH. It will wait
+ up to a maximum number of minutes. This can be specified by
+ passing the subroutine an integer value or the default value
+ of 5 minutes will be used.
+
+=cut
+
+sub wait_for_ssh {
+ my $self = shift;
+ my $management_node_keys = $self->data->get_management_node_keys();
+ my $computer_node_name = $self->data->get_computer_node_name();
+
+ # Attempt to get the total number of minutes to wait from the arguments
+ # If not specified, use default value
+ my $total_wait_minutes = shift;
+ if (!defined($total_wait_minutes) || $total_wait_minutes !~ /^\d+$/) {
+ $total_wait_minutes = 5;
+ }
+
+ # Looping configuration variables
+ # Seconds to wait in between loop attempts
+ my $attempt_delay = 15;
+ # Total loop attempts made
+ # Add 1 to the number of attempts because if you're waiting for x intervals, you check x+1 times including at 0
+ my $attempts = ($total_wait_minutes * 4) + 1;
+
+ notify($ERRORS{'OK'}, 0, "waiting for $computer_node_name to respond to ssh, maximum of $total_wait_minutes minutes");
+
+ # Loop until ssh is available
+ my $ssh_result = 0;
+ for (my $attempt = 1; $attempt <= $attempts; $attempt++) {
+ notify($ERRORS{'OK'}, 0, "attempt $attempt/$attempts: checking ssh on computer: $computer_node_name");
+
+ # Run a test SSH command
+ my ($exit_status, $output) = run_ssh_command($computer_node_name, $management_node_keys, "echo testing ssh on $computer_node_name");
+
+ # The exit status will be 0 if the command succeeded
+ if (defined($exit_status) && $exit_status == 0) {
+ notify($ERRORS{'OK'}, 0, "test ssh command succeeded on $computer_node_name");
+ return 1;
+ }
+
+ notify($ERRORS{'OK'}, 0, "sleeping for $attempt_delay seconds before next ssh attempt");
+ sleep $attempt_delay;
+ }
+
+ notify($ERRORS{'WARNING'}, 0, "$computer_node_name is not available via ssh");
+ return 0;
+}
+
+#/////////////////////////////////////////////////////////////////////////////
+
+=head2 firewall_enable_ping_private
+
+ Parameters :
+ Returns : 1 if succeeded, 0 otherwise
+ Description :
+
+=cut
+
+sub firewall_enable_ping_private {
+ my $self = shift;
+
+ my %firewall_parameters = (
+ name => 'VCL: allow ping from private network',
+ dir => 'in',
+ action => 'allow',
+ description => 'Allows incoming ping (ICMP type 8) messages from 10.x.x.x addresses',
+ enable => 'yes',
+ localip => '10.0.0.0/8',
+ remoteip => '10.0.0.0/8',
+ protocol => 'icmpv4:8,any',
+ );
+
+ # Call the configure firewall subroutine, pass it the necessary parameters
+ if ($self->firewall_configure(\%firewall_parameters)) {
+ notify($ERRORS{'OK'}, 0, "successfully opened firewall for incoming ping on private network");
+ return 1;
+ }
+ else {
+ notify($ERRORS{'WARNING'}, 0, "failed to open firewall for incoming ping on private network");
+ return 0;
+ }
+}
+
+#/////////////////////////////////////////////////////////////////////////////
+
+=head2 firewall_enable_ssh_private
+
+ Parameters :
+ Returns : 1 if succeeded, 0 otherwise
+ Description :
+
+=cut
+
+sub firewall_enable_ssh_private {
+ my $self = shift;
+
+ my %firewall_parameters = (
+ name => 'VCL: allow ssh port 22 from private network',
+ dir => 'in',
+ action => 'allow',
+ description => 'Allows incoming TCP port 22 traffic from 10.x.x.x addresses',
+ enable => 'yes',
+ localip => '10.0.0.0/8',
+ remoteip => '10.0.0.0/8',
+ localport => '22',
+ protocol => 'TCP',
+ );
+
+ # Call the configure firewall subroutine, pass it the necessary parameters
+ if ($self->firewall_configure(\%firewall_parameters)) {
+ notify($ERRORS{'OK'}, 0, "successfully opened firewall for incoming ssh via TCP port 22 on private network");
+ return 1;
+ }
+ else {
+ notify($ERRORS{'WARNING'}, 0, "failed to open firewall for incoming ssh via TCP port 22 on private network");
+ return 0;
+ }
+}
+
+#/////////////////////////////////////////////////////////////////////////////
+
+=head2 firewall_enable_rdp
+
+ Parameters :
+ Returns : 1 if succeeded, 0 otherwise
+ Description :
+
+=cut
+
+sub firewall_enable_rdp {
+ my $self = shift;
+
+ # Check if the remote IP was passed correctly as an argument
+ my $remote_ip = shift;
+ if (!defined($remote_ip) || $remote_ip !~ /[\d\.\/]/) {
+ $remote_ip = 'any';
+ }
+
+ my %firewall_parameters = (
+ name => "VCL: allow RDP port 3389 from $remote_ip",
+ dir => 'in',
+ action => 'allow',
+ description => "Allows incoming TCP port 3389 traffic from $remote_ip",
+ enable => 'yes',
+ remoteip => $remote_ip,
+ localport => '3389',
+ protocol => 'TCP',
+ );
+
+ # Call the configure firewall subroutine, pass it the necessary parameters
+ if ($self->firewall_configure(\%firewall_parameters)) {
+ notify($ERRORS{'OK'}, 0, "successfully opened firewall for incoming RDP via TCP port 3389 from $remote_ip");
+ return 1;
+ }
+ else {
+ notify($ERRORS{'WARNING'}, 0, "failed to open firewall for incoming RDP via TCP port 3389 from $remote_ip");
+ return 0;
+ }
+}
+
+#/////////////////////////////////////////////////////////////////////////////
+
+=head2 firewall_disable_rdp
+
+ Parameters :
+ Returns : 1 if succeeded, 0 otherwise
+ Description :
+
+=cut
+
+sub firewall_disable_rdp {
+ my $self = shift;
+
+ #"\netsh.exe advfirewall firewall delete rule name=RDP protocol=TCP localport=3389"
+
+ my %firewall_parameters = (
+ name => 'all',
+ localport => '3389',
+ protocol => 'TCP',
+ );
+
+ # Call the configure firewall subroutine, pass it the necessary parameters
+ if ($self->firewall_close(\%firewall_parameters)) {
+ notify($ERRORS{'OK'}, 0, "successfully closed firewall for incoming RDP via TCP port 3389");
+ return 1;
+ }
+ else {
+ notify($ERRORS{'WARNING'}, 0, "failed to close firewall for incoming RDP via TCP port 3389");
+ return 0;
+ }
+}
+
+#/////////////////////////////////////////////////////////////////////////////
+
+=head2 firewall_configure
+
+ Parameters :
+ Returns : 1 if succeeded, 0 otherwise
+ Description :
+
+=cut
+
+sub firewall_configure {
+ my $self = shift;
+ my $management_node_keys = $self->data->get_management_node_keys();
+ my $computer_node_name = $self->data->get_computer_node_name();
+
+ # Check the arguments
+ my $firewall_parameters = shift;
+ if (!defined($firewall_parameters) || !$firewall_parameters) {
+ notify($ERRORS{'WARNING'}, 0, "failed to open firewall on $computer_node_name, parameters hash reference was not passed");
+ return;
+ }
+ if (!defined($firewall_parameters->{name}) || !$firewall_parameters->{name}) {
+ notify($ERRORS{'WARNING'}, 0, "failed to open firewall on $computer_node_name, 'name' hash key was not passed");
+ return;
+ }
+ if (!defined($firewall_parameters->{dir}) || !$firewall_parameters->{dir}) {
+ notify($ERRORS{'WARNING'}, 0, "failed to open firewall on $computer_node_name, 'dir' hash key was not passed");
+ return;
+ }
+ if (!defined($firewall_parameters->{action}) || !$firewall_parameters->{action}) {
+ notify($ERRORS{'WARNING'}, 0, "failed to open firewall on $computer_node_name, 'action' hash key was not passed");
+ return;
+ }
+
+ # Add quotes around anything with a space in the parameters hash which isn't already enclosed in quotes
+ foreach my $rule_property (sort keys(%{$firewall_parameters})) {
+ $firewall_parameters->{$rule_property} =~ s/^(.*\s.*)$/\"$1\"/g;
+ notify($ERRORS{'DEBUG'}, 0, "enclosing property in quotes: $firewall_parameters->{$rule_property}");
+ }
+
+ # Attempt to run the command to set existing firewall rule
+
+ # Usage: set rule
+ # group=<string> | name=<string>
+ # [dir=in|out]
+ # [profile=public|private|domain|any[,...]]
+ # [program=<program path>]
+ # [service=service short name|any]
+ # [localip=any|<IPv4 address>|<IPv6 address>|<subnet>|<range>|<list>]
+ # [remoteip=any|localsubnet|dns|dhcp|wins|defaultgateway|
+ # <IPv4 address>|<IPv6 address>|<subnet>|<range>|<list>]
+ # [localport=0-65535|RPC|RPC-EPMap|any[,...]]
+ # [remoteport=0-65535|any[,...]]
+ # [protocol=0-255|icmpv4|icmpv6|icmpv4:type,code|icmpv6:type,code|
+ # tcp|udp|any]
+ # new
+ # [name=<string>]
+ # [dir=in|out]
+ # [program=<program path>
+ # [service=<service short name>|any]
+ # [action=allow|block|bypass]
+ # [description=<string>]
+ # [enable=yes|no]
+ # [profile=public|private|domain|any[,...]]
+ # [localip=any|<IPv4 address>|<IPv6 address>|<subnet>|<range>|<list>]
+ # [remoteip=any|localsubnet|dns|dhcp|wins|defaultgateway|
+ # <IPv4 address>|<IPv6 address>|<subnet>|<range>|<list>]
+ # [localport=0-65535|RPC|RPC-EPMap|any[,...]]
+ # [remoteport=0-65535|any[,...]]
+ # [protocol=0-255|icmpv4|icmpv6|icmpv4:type,code|icmpv6:type,code|
+ # tcp|udp|any]
+ # [interfacetype=wireless|lan|ras|any]
+ # [rmtcomputergrp=<SDDL string>]
+ # [rmtusrgrp=<SDDL string>]
+ # [edge=yes|no]
+ # [security=authenticate|authenc|notrequired]
+
+ # Assemble the command based on the keys populated in the hash
+ my $set_rule_command = "netsh.exe advfirewall firewall set rule";
+ $set_rule_command .= " name=$firewall_parameters->{name}";
+ $set_rule_command .= " new";
+ foreach my $rule_property (sort keys(%{$firewall_parameters})) {
+ next if $rule_property eq 'name';
+ $set_rule_command .= " $rule_property=$firewall_parameters->{$rule_property}";
+ }
+
+ # Attempt to set properties of existing rule
+ notify($ERRORS{'DEBUG'}, 0, "attempting to set matching firewall rules on $computer_node_name, command:\n$set_rule_command");
+ my ($set_rule_exit_status, $set_rule_output) = run_ssh_command($computer_node_name, $management_node_keys, $set_rule_command);
+ if (defined($set_rule_exit_status) && ($set_rule_exit_status == 0)) {
+ notify($ERRORS{'OK'}, 0, "successfully set matching firewall rules");
+ return 1;
+ }
+ elsif (defined($set_rule_exit_status) && ($set_rule_exit_status == 1)) {
+ notify($ERRORS{'OK'}, 0, "unable to set matching firewall rules, rule does not exist");
+ }
+ elsif (defined($set_rule_exit_status)) {
+ notify($ERRORS{'WARNING'}, 0, "failed to set matching firewall rules on $computer_node_name, exit status: $set_rule_exit_status, output:\n@{$set_rule_output}");
+ }
+ else {
+ notify($ERRORS{'WARNING'}, 0, "failed to run ssh command to set matching firewall rules on $computer_node_name");
+ }
+
+
+ # Attempt to run the command to add the firewall rule
+
+ # Usage: add rule name=<string>
+ # dir=in|out
+ # action=allow|block|bypass
+ # [program=<program path>]
+ # [service=<service short name>|any]
+ # [description=<string>]
+ # [enable=yes|no (default=yes)]
+ # [profile=public|private|domain|any[,...]]
+ # [localip=any|<IPv4 address>|<IPv6 address>|<subnet>|<range>|<list>]
+ # [remoteip=any|localsubnet|dns|dhcp|wins|defaultgateway|
+ # <IPv4 address>|<IPv6 address>|<subnet>|<range>|<list>]
+ # [localport=0-65535|RPC|RPC-EPMap|any[,...] (default=any)]
+ # [remoteport=0-65535|any[,...] (default=any)]
+ # [protocol=0-255|icmpv4|icmpv6|icmpv4:type,code|icmpv6:type,code|
+ # tcp|udp|any (default=any)]
+ # [interfacetype=wireless|lan|ras|any]
+ # [rmtcomputergrp=<SDDL string>]
+ # [rmtusrgrp=<SDDL string>]
+ # [edge=yes|no (default=no)]
+ # [security=authenticate|authenc|notrequired (default=notrequired)]
+
+ # Assemble the command based on the keys populated in the hash
+ my $add_rule_command = "netsh.exe advfirewall firewall add rule";
+ $add_rule_command .= " name=$firewall_parameters->{name}";
+ foreach my $rule_property (sort keys(%{$firewall_parameters})) {
+ next if $rule_property eq 'name';
+ $add_rule_command .= " $rule_property=$firewall_parameters->{$rule_property}";
+ }
+
+ # Add the firewall rule
+ my ($add_rule_exit_status, $add_rule_output) = run_ssh_command($computer_node_name, $management_node_keys, $add_rule_command);
+ if (defined($add_rule_exit_status) && $add_rule_exit_status == 0) {
+ notify($ERRORS{'OK'}, 0, "successfully added firewall rule");
+ }
+ elsif (defined($add_rule_exit_status)) {
+ notify($ERRORS{'WARNING'}, 0, "failed to add firewall rule on $computer_node_name, exit status: $add_rule_exit_status, output:\n@{$add_rule_output}");
+ return 0;
+ }
+ else {
+ notify($ERRORS{'WARNING'}, 0, "failed to add firewall rule on $computer_node_name");
+ return;
+ }
+
+ return 1;
+}
+
+#/////////////////////////////////////////////////////////////////////////////
+
+=head2 firewall_close
+
+ Parameters :
+ Returns : 1 if succeeded, 0 otherwise
+ Description :
+
+=cut
+
+sub firewall_close {
+ my $self = shift;
+ my $management_node_keys = $self->data->get_management_node_keys();
+ my $computer_node_name = $self->data->get_computer_node_name();
+
+ # Make sure firewall parameters hash was passed
+ my $firewall_parameters = shift;
+ if (!defined($firewall_parameters) || !$firewall_parameters) {
+ notify($ERRORS{'WARNING'}, 0, "failed to close firewall on $computer_node_name, parameters hash reference was not passed");
+ return;
+ }
+
+ # Add quotes around anything with a space in the parameters hash which isn't already enclosed in quotes
+ foreach my $rule_property (sort keys(%{$firewall_parameters})) {
+ $firewall_parameters->{$rule_property} =~ s/^(.*\s.*)$/\"$1\"/g;
+ notify($ERRORS{'DEBUG'}, 0, "enclosing '$rule_property' property in quotes: $firewall_parameters->{$rule_property}");
+ }
+
+ # Usage: delete rule name=<string>
+ # [dir=in|out]
+ # [profile=public|private|domain|any[,...]]
+ # [program=<program path>]
+ # [service=<service short name>|any]
+ # [localip=any|<IPv4 address>|<IPv6 address>|<subnet>|<range>|<list>]
+ # [remoteip=any|localsubnet|dns|dhcp|wins|defaultgateway|
+ # <IPv4 address>|<IPv6 address>|<subnet>|<range>|<list>]
+ # [localport=0-65535|RPC|RPC-EPMap|any[,...]]
+ # [remoteport=0-65535|any[,...]]
+ # [protocol=0-255|icmpv4|icmpv6|icmpv4:type,code|icmpv6:type,code|
+ # tcp|udp|any]
+
+ # Assemble the command based on the keys populated in the hash
+ my $delete_rule_command = "netsh.exe advfirewall firewall delete rule";
+ foreach my $rule_property (sort keys(%{$firewall_parameters})) {
+ $delete_rule_command .= " $rule_property=$firewall_parameters->{$rule_property}";
+ }
+
+ # Attempt to delete existing rules
+ notify($ERRORS{'DEBUG'}, 0, "attempting to delete matching firewall rules on $computer_node_name, command:\n$delete_rule_command");
+ my ($delete_rule_exit_status, $delete_rule_output) = run_ssh_command($computer_node_name, $management_node_keys, $delete_rule_command);
+ if (defined($delete_rule_exit_status) && ($delete_rule_exit_status == 0)) {
+ notify($ERRORS{'OK'}, 0, "successfully deleted matching firewall rules");
+ return 1;
+ }
+ elsif (defined($delete_rule_exit_status) && ($delete_rule_exit_status == 1)) {
+ notify($ERRORS{'OK'}, 0, "unable to delete matching firewall rules, rule does not exist");
+ return 1;
+ }
+ elsif (defined($delete_rule_exit_status)) {
+ notify($ERRORS{'WARNING'}, 0, "failed to delete matching firewall rules on $computer_node_name, exit status: $delete_rule_exit_status, output:\n@{$delete_rule_output}");
+ return 0;
+ }
+ else {
+ notify($ERRORS{'WARNING'}, 0, "failed to run ssh command to delete matching firewall rules on $computer_node_name");
+ return 0;
+ }
+}
+
+#/////////////////////////////////////////////////////////////////////////////
+
+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>
+
+=head1 COPYRIGHT AND LICENSE
+
+ Copyright (C) 2004-2008 by NC State University. All Rights Reserved.
+
+ Virtual Computing Laboratory
+ North Carolina State University
+ Raleigh, NC, USA 27695
+
+ For use license and copyright information see LICENSE and COPYRIGHT files
+ included in the source files.
+
+=cut
Added: incubator/vcl/tags/import/managementnode/lib/VCL/Module/OS/Windows/Desktop/XP.pm
URL: http://svn.apache.org/viewvc/incubator/vcl/tags/import/managementnode/lib/VCL/Module/OS/Windows/Desktop/XP.pm?rev=726079&view=auto
==============================================================================
--- incubator/vcl/tags/import/managementnode/lib/VCL/Module/OS/Windows/Desktop/XP.pm (added)
+++ incubator/vcl/tags/import/managementnode/lib/VCL/Module/OS/Windows/Desktop/XP.pm Fri Dec 12 10:20:10 2008
@@ -0,0 +1,78 @@
+#!/usr/bin/perl -w
+##############################################################################
+# $Id: XP.pm 1953 2008-12-12 14:23:17Z arkurth $
+##############################################################################
+
+=head1 NAME
+
+VCL::Module::OS::Windows::Desktop::XP
+
+=head1 SYNOPSIS
+
+ Needs to be written
+
+=head1 DESCRIPTION
+
+ This module provides...
+
+=cut
+
+##############################################################################
+package VCL::Module::OS::Windows::Desktop::XP;
+
+# Specify the lib path using FindBin
+use FindBin;
+use lib "$FindBin::Bin/../../../../..";
+
+# Configure inheritance
+use base qw(VCL::Module::OS::Windows::Desktop);
+
+# 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;
+
+##############################################################################
+
+=head1 OBJECT METHODS
+
+=cut
+
+#/////////////////////////////////////////////////////////////////////////////
+
+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>
+
+=head1 COPYRIGHT AND LICENSE
+
+ Copyright (C) 2004-2008 by NC State University. All Rights Reserved.
+
+ Virtual Computing Laboratory
+ North Carolina State University
+ Raleigh, NC, USA 27695
+
+ For use license and copyright information see LICENSE and COPYRIGHT files
+ included in the source files.
+
+=cut
Propchange: incubator/vcl/tags/import/managementnode/lib/VCL/Module/OS/Windows/Desktop/XP.pm
------------------------------------------------------------------------------
svn:executable =