Author: brad Date: 2006-07-01 02:15:52 +0000 (Sat, 01 Jul 2006) New Revision: 16722
WebSVN: http://websvn.samba.org/cgi-bin/viewcvs.cgi?view=rev&root=samba&rev=16722 Log: Fixed error handling when working with the vix perl api. Added functionality to host_connect() function to log into windows as a user. This allows us to copy files and run commands on the windows vm. The initial_setup.conf parameters GUEST_ADMIN_USERNAME and GUEST_ADMIN_PASSWORD specify this account. Added function run_on_guest() to execute programs on the guest vm as the user mentioned above. Added function copy_to_guest() which takes a local src directory or filename and remote directory as parameters, and creates an associative list of local-remote file paths. The function passes this list to copy_files_to_guest() to perform the actual copy to the guest vm. With this update, these scripts can automatically setup a windows guest on vmware server with the only preconfiguration being that vmware tools is installed and the guest os has an ip address configured. I'll put together a zip file containing the set of scripts needed to make this happen as well as a README file a little later. Modified: branches/SOC/bnh/perl/initial_setup.conf branches/SOC/bnh/perl/vm_setup.pl Changeset: Modified: branches/SOC/bnh/perl/initial_setup.conf =================================================================== --- branches/SOC/bnh/perl/initial_setup.conf 2006-07-01 01:03:27 UTC (rev 16721) +++ branches/SOC/bnh/perl/initial_setup.conf 2006-07-01 02:15:52 UTC (rev 16722) @@ -20,8 +20,13 @@ # Where these scripts will be copied from on the unix host. # I don't know how this will work if the unix host is a different # system than the vmware server host. -export LOCAL_SCRIPT_PATH="./windows-scripts" +export LOCAL_SCRIPT_PATH="./windows-scripts/" +# In order to copy files and execute programs on the guest vm, +# we need administrator-level credentials to log in with. +export GUEST_ADMIN_USERNAME="administrator" +export GUEST_ADMIN_PASSWORD="adminpass" + # These parameters are optional, and change the windows guest # hostname and workgroup if set. #export GUEST_HOSTNAME="tortureguest" Modified: branches/SOC/bnh/perl/vm_setup.pl =================================================================== --- branches/SOC/bnh/perl/vm_setup.pl 2006-07-01 01:03:27 UTC (rev 16721) +++ branches/SOC/bnh/perl/vm_setup.pl 2006-07-01 02:15:52 UTC (rev 16722) @@ -35,6 +35,8 @@ my $username; my $password; my $vm_cfg_path; + my $guest_admin_username; + my $guest_admin_password; sub error { my $old_err_code = $err_code; @@ -45,7 +47,7 @@ } # Power on the guest if it isn't already running. - # Returns 0 when the guest is already running, and + # Returns 0 when the guest is already running, and # if not, it waits until it is started. sub start_guest { my $vm_power_state = $perl_vm->get_execution_state(); @@ -58,7 +60,7 @@ VMware::VmPerl::VM_EXECUTION_STATE_SUSPENDED) { if (!$perl_vm->start()) { - ($err_code, $err_str) = + ($err_code, $err_str) = $perl_vm->get_last_error(); return ($err_code); } @@ -74,10 +76,11 @@ # name of the method. Called locally, this function will lose # the first parameter. shift @_; - ($hostname, $port, $username, $password, $vm_cfg_path) = @_; + ($hostname, $port, $username, $password, $vm_cfg_path, + $guest_admin_username, $guest_admin_password) = @_; # Connect to host using vmperl api. - $perl_vm_credentials = + $perl_vm_credentials = VMware::VmPerl::ConnectParams::new($hostname, $port, $username, $password); if (!$perl_vm->connect($perl_vm_credentials, $vm_cfg_path)) { @@ -94,7 +97,8 @@ $hostname, $port, $username, $password, 0, VMware::Vix::Simple::VIX_INVALID_HANDLE); if ($err_code != VMware::Vix::Simple::VIX_OK) { - ($err_code, $err_str) = $vix_vm_host->get_last_error(); + $err_str = + VMware::Vix::Simple::GetErrorText($err_code); undef $perl_vm; undef $vix_vm; undef $vix_vm_host; @@ -114,15 +118,29 @@ } # Open VM. - ($err_code, $vix_vm) = + ($err_code, $vix_vm) = VMware::Vix::Simple::VMOpen($vix_vm_host, $vm_cfg_path); if ($err_code != VMware::Vix::Simple::VIX_OK) { - ($err_code, $err_str) = $vix_vm->get_last_error(); + $err_str = + VMware::Vix::Simple::GetErrorText($err_code); undef $perl_vm; undef $vix_vm; undef $vix_vm_host; return ($err_code); } + + # Login to $vix_vm guest OS. + $err_code = VMware::Vix::Simple::VMLoginInGuest($vix_vm, + $guest_admin_username, $guest_admin_password, + 0); + if ($err_code != VMware::Vix::Simple::VIX_OK) { + $err_str = + VMware::Vix::Simple::GetErrorText($err_code); + undef $perl_vm; + undef $vix_vm; + undef $vix_vm_host; + return ($err_code); + } return ($err_code); } @@ -134,7 +152,7 @@ $err_code = 1; $err_str = "Error creating new VmPerl object"; } - + undef $vix_vm; VMware::Vix::Simple::HostDisconnect($vix_vm_host); VMware::Vix::Simple::ReleaseHandle($vix_vm_host); @@ -151,7 +169,8 @@ } $err_code = host_connect(NULL, $hostname, $port, $username, - $password, $vm_cfg_path); + $password, $vm_cfg_path, $guest_admin_username, + $guest_admin_password); if ($err_code != 0) { my $old_err_str = $err_str; $err_str = "Re-connecting to host failed: " . @@ -164,7 +183,7 @@ sub create_snapshot { my $snapshot; - ($err_code, $snapshot) = + ($err_code, $snapshot) = VMware::Vix::Simple::VMCreateSnapshot($vix_vm, "Snapshot", "Created by vm_setup.pl", 0, VMware::Vix::Simple::VIX_INVALID_HANDLE); @@ -172,7 +191,8 @@ VMware::Vix::Simple::ReleaseHandle($snapshot); if ($err_code != VMware::Vix::Simple::VIX_OK) { - ($err_code, $err_str) = $vix_vm->get_last_error(); + $err_str = + VMware::Vix::Simple::GetErrorText($err_code); return $err_code; } @@ -189,17 +209,18 @@ sub revert_snapshot { my $snapshot; - # We are passing 0 to VMGetRootSnapshot because we can only + # We are passing 0 to VMGetRootSnapshot because we can only # have one snapshot in vmware server, and it has an id of 0. - ($err_code, $snapshot) = + ($err_code, $snapshot) = VMware::Vix::Simple::VMGetRootSnapshot($vix_vm, 0); if ($err_code != VMware::Vix::Simple::VIX_OK) { - ($err_code, $err_str) = $vix_vm->get_last_error(); + $err_str = + VMware::Vix::Simple::GetErrorText($err_code); return ($err_code); } my $job = VMware::Vix::API::VM::RevertToSnapshot($vix_vm, - $snapshot, 0, + $snapshot, 0, VMware::Vix::Simple::VIX_INVALID_HANDLE, undef,0); @@ -226,17 +247,103 @@ return ($err_code); } + # $dest_path must exist. It doesn't get created. + sub copy_files_to_guest { + shift @_; + my (%files) = @_; + + my $src_file; + my $dest_file; + + foreach $src_file (keys(%files)) { + $dest_file = $files{$src_file}; + $err_code = + VMware::Vix::Simple::VMCopyFileFromHostToGuest( + $vix_vm, $src_file, $dest_file, 0, + VMware::Vix::Simple::VIX_INVALID_HANDLE); + if ($err_code != VMware::Vix::Simple::VIX_OK) { + $err_str = "Copying $src_file: " . + VMware::Vix::Simple::GetErrorText( + $err_code); + return $err_code; + } + } + return $err_code; + } + sub copy_to_guest { - $err_code = -1; - $err_str = "Function copy_to_guest() is not yet implemented"; + # Read parameters $src_path, $dest_path. + shift @_; + my ($src_path, $dest_dir) = @_; + my $len = length($dest_dir); + my $idx = rindex($dest_dir, '\\'); + if ($idx != ($len - 1)) { + $err_code = -1; + $err_str = "Destination $dest_dir must be a " . + "directory path"; + return ($err_code); + } + + # If $src_filepath specifies a file, create it in $dest_path + # and keep the same name. + # If $src_path is a directory, create the files it contains in + # $dest_path, keeping the same names. + $len = length($src_path); + my %files; + $idx = rindex($src_path, '/'); + if ($idx == ($len - 1)) { + # $src_path is a directory. + if (!opendir (DIR_HANDLE, $src_path)) { + $err_code = -1; + $err_str = "Error opening directory $src_path"; + return $err_code; + } + + foreach $file (readdir DIR_HANDLE) { + my $src_file = $src_path . $file; + + if (!opendir(DIR_HANDLE2, $src_file)) { + # We aren't interested in subdirs. + my $dest_path = $dest_dir . $file; + $files{$src_file} = $dest_path; + } else { + closedir(DIR_HANDLE2); + } + } + } else { + # Strip if preceeding path from $src_path. + my $src_file = substr($src_path, ($idx + 1), $len); + my $dest_path = $dest_dir . $src_file; + + # Add $src_path => $dest_path to %files. + $files{$src_path} = $dest_path; + } + + $err_code = copy_files_to_guest(NULL, %files); + if ($err_code != 0) { + my $old_err_str = $err_str; + $err_str = "Copying files to host after " . + "populating %files: " . $old_err_str; + return ($err_code); + } return ($err_code); } sub run_on_guest { - $err_code = -1; - $err_str = "Function run_on_guest() is not yet implemented"; + # Read parameters $cmd, $cmd_args. + shift @_; + my ($cmd, $cmd_args) = @_; + $err_code = VMware::Vix::Simple::VMRunProgramInGuest($vix_vm, + $cmd, $cmd_args, 0, + VMware::Vix::Simple::VIX_INVALID_HANDLE); + if ($err_code != VMware::Vix::Simple::VIX_OK) { + $err_str = VMware::Vix::Simple::GetErrorText( + $err_code); + return ($err_code); + } + return ($err_code); } @@ -286,6 +393,9 @@ my $host_username = $ENV{'HOST_USERNAME'}; my $host_password = $ENV{'HOST_PASSWORD'}; +my $guest_admin_username = $ENV{'GUEST_ADMIN_USERNAME'}; +my $guest_admin_password = $ENV{'GUEST_ADMIN_PASSWORD'}; + my $guest_username = $ENV{'GUEST_USERNAME'}; my $guest_password = $ENV{'GUEST_PASSWORD'}; my $guest_hostname = $ENV{'GUEST_HOSTNAME'}; @@ -295,7 +405,8 @@ my $vm = VMHost; $vm->host_connect($host_server_name, $host_server_port, $host_username, - $host_password, $vm_cfg_path); + $host_password, $vm_cfg_path, $guest_admin_username, + $guest_admin_password); check_error($vm, "Error in \$vm->connect().\n"); print "Connected successfully to VM.\n"; @@ -309,15 +420,26 @@ print "Snapshot creation has started.\n"; # Copy the windows setup scripts to the VM. -$vm->copy_to_guest($local_script_path,$guest_script_path); +$vm->copy_to_guest($local_script_path, $guest_script_path); check_error($vm, "Error in \$vm->copy_to_guest().\n"); print "Windows setup scripts have been copied to the VM.\n"; -# Run win_setup.wsh on the VM. -$cmd = "cscript $guest_script_path win_setup.wsf /username:$guest_username" . - "/password: $guest_password"; -$vm->run_on_guest($cmd); -check_error($vm, "Error in \$vm->run_on_guest() executing " . $cmd . ".\n"); +# Run win_setup.wsf on the VM. +$cmd = "C:\\WINDOWS\\system32\\cscript.exe "; +$cmd_args = $guest_script_path . "win_setup.wsf /username:" . + $guest_username . " /password:" . $guest_password; + +if ($guest_hostname) { + $cmd_args = $cmd_args . " /hostname:" . $guest_hostname; +} + +if ($guest_workgroup) { + $cmd_args = $cmd_args . " /workgroup:" . $guest_workgroup; +} + +$vm->run_on_guest($cmd, $cmd_args); +check_error($vm, "Error in \$vm->run_on_guest() while executing: " . + $cmd . $cmd_args . ".\n"); print "Windows setup scripts have been successfully executed on the VM.\n"; # Destroy the vm object and disconnect from the vm.
