Hi Guys
I'm writing a script to shutdown a bunch of VMs, change their Memory or CPU allocation and bring them back up. But when I call the ReconfigVM method, I'm getting a strange error:
Reconfiguration failed:Undefined subroutine &Active code page: 850::ReconfigVM_Task called at C:\Users\probinso\Documents\dev\SetVMOffline.pl line 220Here's my code
#!/usr/bin/perl use strict; use warnings; use VMware::VIRuntime; $SIG{INT} = sub { Util::disconnect(); exit; }; my %opts = ( name => { type => "=s", variable => "VM_NAME", help => "VirtualMachine Name", required => 1, }, memory => { type => "=i", variable => "VM_MEM", help => "The amount of Memory to be allocated to the VirtualMachine(s) in MB", required => 0, }, numcpu => { type => "=i", variable => "VM_CPU", help => "The amount of CPUs to be allocated to the VirtualMachine(s)", required => 0, }, timeout => { type => "=i", variable => "TIMEOUT", help => "Set this if you want to force VMs to be poweredOff after a given number of seconds", }, ); Opts::add_options(%opts); Opts::parse(); Opts::validate(); Util::connect(); my (%poweredState, %updateState); my ($c, $mem, $cpu) = 0; my @vmList = (); my @vmnames = Opts::get_option('name'); my $memory = Opts::get_option('memory'); if($memory) { $mem = (memoryMB => $memory); } my $numcpu = Opts::get_option('numcpu'); if($numcpu) { $cpu = (numCPUs => $numcpu); } my $timeout = Opts::get_option('timeOut'); if(!$timeout) { $timeout = 99999; } foreach (@vmnames) { my $vm = Vim::find_entity_view ( view_type => 'VirtualMachine', filter => { 'name' => qr/$_/i } ); if(! $vm) { # Please dial the number and try again print "Could not find virtual machine of name $_\n Please check the spelling and CaPitAliSation\n"; exit; } push(@vmList, $vm); $vm->update_view_data(); if($vm->runtime->powerState->val eq "poweredOn") { $poweredState{$vm} = "poweredOn"; # $vm->ShutdownGuest(); shutdown_guest($vm); } else { $poweredState{$vm} = "poweredOff"; } $c++; } my $time = time(); while ($time) { my $updatedvms = 0; foreach my $vm (@vmList) { $vm->update_view_data(); if($vm->runtime->powerState->val eq "poweredOff" && !$updateState{$vm}) { my $ret = update_vm($vm); if ($ret) { $updateState{$vm} = "TRUE"; } else { $updateState{$vm} = "FALSE"; } } elsif(($time + $timeout) < time()) { my $ret = poweroff_vm($vm); } if($updateState{$vm} eq "TRUE") { $updatedvms++; } } if(($time + ($timeout * $c)) > time() || $c == $updatedvms) { last; } } foreach my $vm (@vmList) { if($poweredState{$vm} eq "poweredOn") { poweron_vm($vm); } $vm->update_view_data(); print $vm->name." was ".$poweredState{$vm}." ".$vm->name."\nWas updated? ".$updateState{$vm}."\n".$vm->name." is now ".$vm->runtime->powerState->val."\n"; } Util::disconnect(); sub shutdown_guest { my $mor_host = $_->runtime->host; my $hostname = Vim::get_view(mo_ref => $mor_host)->name; eval { $_->ShutdownGuest(); Util::trace (0, "\nGuest '" . $_->name . "' under host $hostname shutdown "); }; if ($@) { if (ref($@) eq 'SoapFault') { Util::trace (0, "\nError in '" . $_->name . "' under host $hostname: "); if (ref($@->detail) eq 'InvalidState') { Util::trace(0,"Current State of the " ." virtual machine is not supported for this operation"); } elsif (ref($@->detail) eq 'InvalidPowerState') { Util::trace(0, "The attempted operation". " cannot be performed in the current state" ); } elsif (ref($@->detail) eq 'NotSupported') { Util::trace(0, "The operation is not supported on the object"); } elsif(ref($@->detail) eq 'ToolsUnavailable') { Util::trace(0,"VMTools are not running in this VM"); } else { Util::trace(0, "VM '" .$_->name. "' can't be shutdown \n" . $@ . "" ); } } else { Util::trace(0, "VM '" .$_->name. "' can't be shutdown \n" . $@ . "" ); } return 0; } return 1; } sub poweroff_vm { my $mor_host = $_->runtime->host; my $hostname = Vim::get_view(mo_ref => $mor_host)->name; eval { $_->PowerOffVM(); Util::trace (0, "\nvirtual machine '" . $_->name . "' under host $hostname powered off "); }; if ($@) { if (ref($@) eq 'SoapFault') { Util::trace (0, "\nError in '" . $_->name . "' under host $hostname: "); if (ref($@->detail) eq 'InvalidPowerState') { Util::trace(0, "The attempted operation". " cannot be performed in the current state" ); } elsif (ref($@->detail) eq 'InvalidState') { Util::trace(0,"Current State of the". " virtual machine is not supported for this operation"); } elsif(ref($@->detail) eq 'NotSupported') { Util::trace(0,"Virtual machine is marked as template"); } else { Util::trace(0, "VM '" .$_->name. "' can't be powered off \n" . $@ . "" ); } } else { Util::trace(0, "VM '" .$_->name. "' can't be powered off \n" . $@ . "" ); } return 0; } return 1; } sub update_vm { my $vmspec; if($memory && $numcpu) { $vmspec = VirtualMachineConfigSpec->new(memoryMB => $mem, numCPUs => $cpu); } elsif($memory) { $vmspec = VirtualMachineConfigSpec->new(memoryMB => $mem); } elsif($numcpu) { $vmspec = VirtualMachineConfigSpec->new(numCPUs => $cpu); } else { Util::trace(0,"Nothing to do with these virtual machines!"); exit; } eval { $_->ReconfigVM_Task(spec => $vmspec); }; if ($@) { Util::trace(0, "\nReconfiguration failed: "); if (ref($@) eq 'SoapFault') { if (ref($@->detail) eq 'TooManyDevices') { Util::trace(0, "\nNumber of virtual devices exceeds " . "the maximum for a given controller.\n"); } elsif (ref($@->detail) eq 'InvalidDeviceSpec') { Util::trace(0, "The Device configuration is not valid\n"); Util::trace(0, "\nFollowing is the detailed error: \n\n$@"); } elsif (ref($@->detail) eq 'FileAlreadyExists') { Util::trace(0, "\nOperation failed because file already exists"); } else { Util::trace(0, "\n" . $@ . "\n"); } } else { Util::trace(0, "\n" . $@ . "\n"); } return 0; } return 1; } sub poweron_vm { my $mor_host = $_->runtime->host; my $hostname = Vim::get_view(mo_ref => $mor_host)->name; eval { $_->PowerOnVM(); Util::trace(0, "\nvirtual machine '" . $_->name . "' under host $hostname powered on \n"); }; if ($@) { if (ref($@) eq 'SoapFault') { Util::trace (0, "\nError in '" . $_->name . "' under host $hostname: "); if (ref($@->detail) eq 'NotSupported') { Util::trace(0,"Virtual machine is marked as a template "); } elsif (ref($@->detail) eq 'InvalidPowerState') { Util::trace(0, "The attempted operation". " cannot be performed in the current state" ); } elsif (ref($@->detail) eq 'InvalidState') { Util::trace(0,"Current State of the " ." virtual machine is not supported for this operation"); } else { Util::trace(0, "VM '" .$_->name. "' can't be powered on \n" . $@ . "" ); } } else { Util::trace(0, "VM '" .$_->name. "' can't be powered on \n" . $@ . "" ); } return 0; } return 1; }
Fixed it.
Turns out it was because I was passing the virtualMachine object ($vm) as a scalar to the subroutine, this was causing things to break.
If I make $vm a global variable and reference it directly from the subroutine, it works fine.