I am having trouble with this script, cdromdisconnect.pl, and I was hoping someone could help me with it...
When I run 'cdromdisconnect.pl --host my.esx.host --op list --server my.vc.host --passthroughauth', I get 'Host my.esx.host not found.' Yet when I run 'datacenterlisting.pl --datacenter MyDC' it finds 'my.esx.host' just fine. Am I missing something here? Why is the cdrom script not able to find hosts when other scripts have no trouble?
Any help would be appreciated.
-monkeedu
AFAIK, there isn't a way to do a view on a MoRef, just on property values. You can't, for example, match against an array property value. You'll need to adjust your script logic. Once you have your host system view ($host), then you should use the vm property ($host->vm) to get a list of Virtual Machines.
You probably need to change:
my $host_moRef = $host->{mo_ref}{value}; ####################################################################################### # Get all VMs that are currently running on that ESX Server ####################################################################################### my $vm_views = Vim::find_entity_views(view_type => 'VirtualMachine', filter => {'runtime.host' => $host_moRef}); my $numDevices = 0; foreach my $vm_view (@$vm_views) {
to:
####################################################################################### # Get all VMs that are currently running on that ESX Server ####################################################################################### my $numDevices = 0; my $vm_view; foreach (@{$host->vm}) { $vm_view = Vim::get_view( mo_ref => $_ );
There are some optimizations I can suggest to speed it up, but its probably best to get it working first.
I would try it without the passthru just to be sure, use --username= and --password= with a valid VC login.
Yes, I have tried with and without the pass-through. Neither worked.
I wonder if your name and FQDN names are not the same.
Try the following script, I set my test host in a state where the two don't match.
#!/usr/bin/perl -w use strict; use warnings; use VMware::VIRuntime; Opts::parse(); Opts::validate(); Util::connect(); my ($hostname, $name, $hosts_view); $hosts_view = Vim::find_entity_views( view_type => "HostSystem"); foreach ( @{$hosts_view} ) { $name = $_->name; $hostname = $_->config->network->dnsConfig->hostName; $hostname .= $_->config->network->dnsConfig->domainName; print "Name = $name; hostname = $hostname\n"; } Util::disconnect();
Output:
$ perl FindHost.pl --username=root --password=vmware --server=172.16.14.51 name = ESX-02.vmwlab.local; hostname = ESX-01.vmwlab.local
It doesn't matter which I use, the name or the FQDN, both fail to find the host. Just as a test, I attempted to run the same script using the ESX host as the --server option instead of Virtual Center, and now I get a different error:
C:\Program Files\VMware\VMware VI Perl Toolkit\Perl\apps\vm>cdromdisconnect.pl --op list --server my.esx.host Enter username: xxxxxxx Enter password: xxxxxxx Filtering is only supported for Simple Type at C:\Program Files\VMware\VMware VI Perl Toolkit\Perl\apps\vm\cdromdisconnect.pl line 68 End Disconnect
I can see where the script is using the filter, but I don't know enough Perl and its use with the VM API to understand what Simple Type is.
Here is the script:
#!/usr/bin/perl -w use strict; use warnings; use Getopt::Long; use VMware::VIRuntime; use VMware::VILib; # cdromDisconnect.pl # To get usage, run pod2html. # # Copyright 2007, VMware Inc. All rights reserved. # Script provided as a sample. # DISCLAIMER. THIS SCRIPT IS PROVIDED TO YOU "AS IS" WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, # WHETHER ORAL OR WRITTEN, EXPRESS OR IMPLIED. THE AUTHOR SPECIFICALLY DISCLAIMS ANY IMPLIED WARRANTIES # OR CONDITIONS OF MERCHANTABILITY, SATISFACTORY QUALITY, NON-INFRINGEMENT AND FITNESS FOR A PARTICULAR PURPOSE. # my %opts = ( host => { type => "=s", variable => "host", help => "Host Name", required => 0}, op => { type => "=s", variable => "operation", help => "Operation (list|disconnect)", default => 'list', required => 0}, ); my $env; # a static variable to cache $env MO my $login = 0; # keep track if you logged in. # validate options, and connect to the server Opts::add_options(%opts); Opts::parse(); Opts::validate(); my $op = Opts::get_option ('op'); Fail ("Usage: Op must be list, or disconnect.\n") unless ($op =~ /^list|disconnect$/); Util::connect(); $login = 1; # used by Fail. $| = 1; # set to unbuffered I/O, improves messages to console ####################################################################################### # Decide what type of connection that you have # ... If through VC, then you need to get the host name argument # ... If through ESX, then collect the ESX host view ####################################################################################### my $host_name; my $host; my $sc = Vim::get_service_content(); if ($sc->about->apiType eq "VirtualCenter") { Fail ("Please supply the --host parameter.\n") unless (Opts::option_is_set ('host')); $host_name = Opts::get_option('host'); $host = Vim::find_entity_view(view_type => 'HostSystem', filter => {'name' => "$host_name\$"}); Fail ("Host $host_name not found.\n") unless ($host); die "Host ". $opts{host}. " not host found." unless ($host); } else { $host = Vim::find_entity_view(view_type => 'HostSystem'); } my $host_moRef = $host->{mo_ref}{value}; ####################################################################################### # Get all VMs that are currently running on that ESX Server ####################################################################################### my $vm_views = Vim::find_entity_views(view_type => 'VirtualMachine', filter => {'runtime.host' => $host_moRef}); my $numDevices = 0; foreach my $vm_view (@$vm_views) { next unless ($vm_view->runtime->powerState->val eq 'poweredOn'); # ignore if VM is not powered on my $devices = $vm_view->config->hardware->device; my $vm_name = $vm_view->name; foreach my $device (@$devices) { my $name = $device->deviceInfo->label; next unless ($device->isa ('VirtualCdrom')); # look of only CDROM's next unless ($device->backing->isa ('VirtualCdromAtapiBackingInfo')); # only connected to host devices next unless ($device->connectable->connected == 1); # only those who are connected if ($op eq 'list') { print "Virtual Machine Device\n----------------------------\n" if ($numDevices == 0); printf "%-20.20s %s\n", $vm_name, $name; } else { # simply change the connected flag $device->connectable->connected(0); my $devSpec = VirtualDeviceConfigSpec->new( operation => VirtualDeviceConfigSpecOperation->new('edit'), device => $device); Reconfig ($vm_view, $devSpec, "Disconnecting $name on $vm_name"); } $numDevices++; } } print $numDevices, " devices found.\n"; # logout Util::disconnect(); ######################################################################################### # Reconfig calls ReconfigVM and interprets status /errors ######################################################################################### sub Reconfig { my ($vm, $devSpec, $msg) = @_; print ("$msg ... "); my $vmspec = VirtualMachineConfigSpec->new( deviceChange => [$devSpec] ); eval { $vm->ReconfigVM( spec => $vmspec ); }; if ($@) { print "reconfiguration failed.\n "; if ($@->isa ('SoapFault')) { print $@->fault_string, "\n"; } else { print $@; } } else { print "succeeded.\n"; } } sub Fail { my ($msg) = @_; Util::disconnect() if ($login); die ($msg); exit (); }
The name passed to rye script has to match the ManagedObject property. It is possible the DNS hostname could differ from this property. Did you run the script I posted? I would just do a quick sanity check, looks like it couldn't find a host matching the string you passed to the disconnect script.
I ran your script and found something interesting. The names did NOT match the hostnames. Every hostname was missing a '.' I went back and tried to run the original script with the incorrect hostname, and it still failed with a host not found error.
To recap:
C:\Program Files\VMware\VMware VI Perl Toolkit\Perl\apps\vm>checkfqdn.pl --server my.vc.host Enter username: xxxxx Enter password: xxxxx Name = esx01.host.local; hostname = esx01host.local Name = esx02.host.local; hostname = esx02host.local Name = esx03.host.local; hostname = esx03host.local C:\Program Files\VMware\VMware VI Perl Toolkit\Perl\apps\vm>cdromdisconnect.pl --server my.vc.host --host esx01host.local Enter username: xxxxxx Enter password: xxxxxx Host esx01host.local not found. C:\Program Files\VMware\VMware VI Perl Toolkit\Perl\apps\vm>cdromdisconnect.pl --server my.vc.host --host esx01.host.local Enter username: xxxxxx Enter password: xxxxxx Host esx01.host.local not found. C:\Program Files\VMware\VMware VI Perl Toolkit\Perl\apps\vm>cdromdisconnect.pl --server esx01host.local Enter username: xxxxx Enter password: xxxxx Error connecting to server at 'https://esx01host.local/sdk/webService': Bad hostname C:\Program Files\VMware\VMware VI Perl Toolkit\Perl\apps\vm>cdromdisconnect.pl --server esx01.host.local Enter username: xxxxx Enter password: xxxxx Filtering is only supported for Simple Type at C:\Program Files\VMware\VMware VI Perl Toolkit\Perl\apps\vm\cdromdisconnect.pl line 68 End Disconnect
I think that is my fault. I missed a "." in the print. Sorry. :). But looks like your hostnames match your name property. Does it work ok any other names?
Nope, not a single one. Which makes me think its either a problem with the script, or some odd firewall issue, though I doubt firewalls are the problem.
I think I found the problem.
It looks like there is a '$' in the filter parameter to the find_entity_view and is breaking your string for a match. I'm guessing it was added in an attempt to make a full string match, but should be done as a qr//.
You should change the following line:
$host = Vim::find_entity_view(view_type => 'HostSystem', filter => {'name' => "$host_name\$"});
to:
$host = Vim::find_entity_view(view_type => 'HostSystem', filter => {'name' => qr/$host_name$/});
or:
$host = Vim::find_entity_view(view_type => 'HostSystem', filter => {'name' => "$host_name"});
Close! That change gets past the first 'filter' issue. But the second one still remains:
C:\Program Files\VMware\VMware VI Perl Toolkit\Perl\apps\vm>cdromdisconnect.pl --server my.vc.local --passthroughauth --host my.esx01.local Filtering is only supported for Simple Type at C:\Program Files\VMware\VMware VI Perl Toolkit\Perl\apps\vm\cdromdisconnect.pl line 69 End Disconnect
Line 69 in the cdrom script I have refers to:
my $vm_views = Vim::find_entity_views(view_type => 'VirtualMachine', filter => {'runtime.host' => $host_moRef});
Again, I don't know Perl from Ruby from Ada from a hole in the ground, what would I do to go about fixing this line? Something like this:
my $vm_views = Vim::find_entity_views(view_type => 'VirtualMachine', filter => {'runtime.host' => "$host_moRef\$"});
Thanks for all your help. You've certainly gotten me further than I'd have gotten on my own!
-monkeedu
AFAIK, there isn't a way to do a view on a MoRef, just on property values. You can't, for example, match against an array property value. You'll need to adjust your script logic. Once you have your host system view ($host), then you should use the vm property ($host->vm) to get a list of Virtual Machines.
You probably need to change:
my $host_moRef = $host->{mo_ref}{value}; ####################################################################################### # Get all VMs that are currently running on that ESX Server ####################################################################################### my $vm_views = Vim::find_entity_views(view_type => 'VirtualMachine', filter => {'runtime.host' => $host_moRef}); my $numDevices = 0; foreach my $vm_view (@$vm_views) {
to:
####################################################################################### # Get all VMs that are currently running on that ESX Server ####################################################################################### my $numDevices = 0; my $vm_view; foreach (@{$host->vm}) { $vm_view = Vim::get_view( mo_ref => $_ );
There are some optimizations I can suggest to speed it up, but its probably best to get it working first.
Beautiful. That change has it working exactly as intended. Now I need to understand why what is intended isn't what I need it to do. lol
What this script shows are Virtual Machines that are pointing to the host device for their cd-rom, which is useful, but I need to know if a VM's cd-rom is pointing to anything at all; client device, host device, or datastore iso. As a test, I pointed a VM to an iso, then ran this script against its host, and the script reported no devices. Any advice? 😛
-monkeedu
Well, I didn't write the original script, but I'll take a stab at it. The script is there to address the problem where you go to VMotion a Virtual Machine and find that it has a CDROM backed to the ESX host CDROM drive. This would cause the VMotion to fail, whereas a datastore backed ISO would not block vmotion. So people started creating tools to automatically disconnect ESX host backed CDROMs. I suspect this script was written with the intent to address that issue, so the list operation just checks for ESX host CDROM drive connections.
You can see that it ignores all but Atapi (ESX Host CDROM devices) with the following line in the code:
next unless ($device->backing->isa ('VirtualCdromAtapiBackingInfo')); # only connected to host devices
Essentially the script author skips any device that is not (isa test) a VirtualCdrom and the backing isn't a VirtualCdromAtapiBackingInfo. If you comment out the line I quoted above, it will pretty much work on any CDROM device. This may or may not be your final intended result, but would likely be a quick fix. After making that change, you'll list and disconnect all cdrom devices depending on how you run the script.
Awesome. It does what I need now with that line commented out. Maybe I'll get crazy and try to write a new, similar script that is more targeted at just the reporting I need (yeah right!). Thanks for your help, I appreciate it!
-monkeedu