Author: arkurth Date: Mon Jun 7 18:59:25 2010 New Revision: 952366 URL: http://svn.apache.org/viewvc?rev=952366&view=rev Log: VCL-298 Added new VMware modules to support Server 2.x and ESXi 4.x: VMware.pm - provisioning module VIX_API.pm - utility module which implements subroutines to use the VMware VIX API vSphere_SDK.pm - utility module which implements subroutines to use the VMware vSphere SDK
Created Provisioning/VMware directory. The new modules reside here so they don't conflict with the existing VMware modules. Added: incubator/vcl/trunk/managementnode/lib/VCL/Module/Provisioning/VMware/ incubator/vcl/trunk/managementnode/lib/VCL/Module/Provisioning/VMware/VIX_API.pm (with props) incubator/vcl/trunk/managementnode/lib/VCL/Module/Provisioning/VMware/VMware.pm (with props) incubator/vcl/trunk/managementnode/lib/VCL/Module/Provisioning/VMware/vSphere_SDK.pm (with props) Added: incubator/vcl/trunk/managementnode/lib/VCL/Module/Provisioning/VMware/VIX_API.pm URL: http://svn.apache.org/viewvc/incubator/vcl/trunk/managementnode/lib/VCL/Module/Provisioning/VMware/VIX_API.pm?rev=952366&view=auto ============================================================================== --- incubator/vcl/trunk/managementnode/lib/VCL/Module/Provisioning/VMware/VIX_API.pm (added) +++ incubator/vcl/trunk/managementnode/lib/VCL/Module/Provisioning/VMware/VIX_API.pm Mon Jun 7 18:59:25 2010 @@ -0,0 +1,939 @@ +#!/usr/bin/perl -w +############################################################################### +# $Id$ +############################################################################### +# 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. +############################################################################### + +=head1 NAME + +VCL::Provisioning::VIX_API + +=head1 SYNOPSIS + + Needs to be written + +=head1 DESCRIPTION + + This module provides VCL support for VMWare VIX API + http://www.vmware.com + +=cut + +############################################################################## +package VCL::Module::Provisioning::VMware::VIX_API; + +# Specify the lib path using FindBin +use FindBin; +use lib "$FindBin::Bin/../../../.."; + +# Configure inheritance +use base qw(VCL::Module::Provisioning::VMware::VMware); + +# 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 English qw( -no_match_vars ); + +use VCL::utils; + +use VMware::Vix::Simple; +use VMware::Vix::API::Constants; + +############################################################################## + +=head1 CLASS VARIABLES + +=cut + +=head2 %VIX_PROPERTY_VM + + Data type : hash + Description : Contains a mapping between numerical and textual + VIX_PROPERTY_VM_* properties + +=cut + +our %VIX_PROPERTY_VM; +$VIX_PROPERTY_VM{eval(VIX_PROPERTY_VM_NUM_VCPUS)} = 'VM_NUM_VCPUS'; +$VIX_PROPERTY_VM{eval(VIX_PROPERTY_VM_VMX_PATHNAME)} = 'VM_VMX_PATHNAME'; +$VIX_PROPERTY_VM{eval(VIX_PROPERTY_VM_VMTEAM_PATHNAME)} = 'VM_VMTEAM_PATHNAME'; +$VIX_PROPERTY_VM{eval(VIX_PROPERTY_VM_MEMORY_SIZE)} = 'VM_MEMORY_SIZE'; +$VIX_PROPERTY_VM{eval(VIX_PROPERTY_VM_READ_ONLY)} = 'VM_READ_ONLY'; +$VIX_PROPERTY_VM{eval(VIX_PROPERTY_VM_IN_VMTEAM)} = 'VM_IN_VMTEAM'; +$VIX_PROPERTY_VM{eval(VIX_PROPERTY_VM_POWER_STATE)} = 'VM_POWER_STATE'; +$VIX_PROPERTY_VM{eval(VIX_PROPERTY_VM_TOOLS_STATE)} = 'VM_TOOLS_STATE'; +$VIX_PROPERTY_VM{eval(VIX_PROPERTY_VM_IS_RUNNING)} = 'VM_IS_RUNNING'; +$VIX_PROPERTY_VM{eval(VIX_PROPERTY_VM_SUPPORTED_FEATURES)} = 'VM_SUPPORTED_FEATURES'; +$VIX_PROPERTY_VM{eval(VIX_PROPERTY_VM_IS_RECORDING)} = 'VM_IS_RECORDING'; +$VIX_PROPERTY_VM{eval(VIX_PROPERTY_VM_IS_REPLAYING)} = 'VM_IS_REPLAYING'; + +=head2 %VIX_POWERSTATE + + Data type : hash + Description : Contains a mapping between numerical and textual + VIX_POWERSTATE_* properties + +=cut + +our %VIX_POWERSTATE; +$VIX_POWERSTATE{eval(VIX_POWERSTATE_POWERING_OFF)} = 'POWERING_OFF'; # power off has been called but not completed +$VIX_POWERSTATE{eval(VIX_POWERSTATE_POWERED_OFF)} = 'POWERED_OFF'; # VM is not running +$VIX_POWERSTATE{eval(VIX_POWERSTATE_POWERING_ON)} = 'POWERING_ON'; # power on has been called but not completed +$VIX_POWERSTATE{eval(VIX_POWERSTATE_POWERED_ON)} = 'POWERED_ON'; # VM is running +$VIX_POWERSTATE{eval(VIX_POWERSTATE_SUSPENDING)} = 'SUSPENDING'; # suspend has been called but not completed +$VIX_POWERSTATE{eval(VIX_POWERSTATE_SUSPENDED)} = 'SUSPENDED'; # VM is suspended +$VIX_POWERSTATE{eval(VIX_POWERSTATE_TOOLS_RUNNING)} = 'TOOLS_RUNNING'; # VM is running and the VMware Tools is active +$VIX_POWERSTATE{eval(VIX_POWERSTATE_RESETTING)} = 'RESETTING'; # reset has been called but not completed +$VIX_POWERSTATE{eval(VIX_POWERSTATE_BLOCKED_ON_MSG)} = 'BLOCKED_ON_MSG'; # VM state change is blocked, waiting for user interaction + +############################################################################## + +=head1 API OBJECT METHODS + +=cut + +#///////////////////////////////////////////////////////////////////////////// + +=head2 get_vm_power_state + + Parameters : $vmx_path + Returns : string + Description : Determines the power state of the VM specified by the vmx file + path argument and returns a string containing one of the + following values: + -on + -off + -suspended + -blocked + +=cut + +sub get_vm_power_state { + my $self = shift; + if (ref($self) !~ /vmware/i) { + notify($ERRORS{'CRITICAL'}, 0, "subroutine was called as a function, it must be called as a class method"); + return; + } + + # Get the vmx path and format it for the VIX API + my $vix_vmx_path = $self->_get_datastore_path(shift) || return; + + my $attempt = 0; + my $attempt_limit = 3; + my $attempt_delay = 5; + my @power_states; + while ($attempt < $attempt_limit) { + $attempt++; + (@power_states = $self->_get_vm_power_states($vix_vmx_path)) || return; + my $return_state; + if (grep(/POWERED_OFF/, @power_states)) { + $return_state = "off"; + } + elsif (grep(/POWERED_ON/, @power_states)) { + $return_state = "on"; + } + elsif (grep(/SUSPENDED/, @power_states)) { + $return_state = "suspended"; + } + elsif (grep(/BLOCKED_ON_MSG/, @power_states)) { + $return_state = "blocked"; + } + else { + notify($ERRORS{'OK'}, 0, "attempt $attempt/$attempt_limit: VM $vix_vmx_path in a transition power state (@power_states), sleeping for $attempt_delay"); + sleep $attempt_delay; + next; + } + + notify($ERRORS{'DEBUG'}, 0, "VM $vix_vmx_path power state: $return_state"); + return $return_state; + } + + notify($ERRORS{'WARNING'}, 0, "VM $vix_vmx_path is still in a transition power state (@power_states)"); + return; +} + +#///////////////////////////////////////////////////////////////////////////// + +=head2 get_registered_vms + + Parameters : none + Returns : array + Description : Retrieves a list of the running VMs on the VM host. Returns an + array containing the vmx file paths of the running VMs. + +=cut + +sub get_registered_vms { + my $self = shift; + if (ref($self) !~ /vmware/i) { + notify($ERRORS{'CRITICAL'}, 0, "subroutine was called as a function, it must be called as a class method"); + return; + } + + my $vmx_base_directory_path = $self->get_vmx_base_directory_path() || return; + (my @registered_vms = $self->_find_items(VIX_FIND_REGISTERED_VMS)) || return; + + # Convert the vmx paths back to the normal non-VIX format + for (my $i=0; $i<scalar(@registered_vms); $i++) { + $registered_vms[$i] =~ s/\s*\[standard\]\s*/$vmx_base_directory_path\//ig; + } + return @registered_vms; +} + +#///////////////////////////////////////////////////////////////////////////// + +=head2 vm_power_off + + Parameters : $vmx_file_path + Returns : boolean + Description : Powers off the VM specified by the vmx file path argument. + +=cut + +sub vm_power_off { + my $self = shift; + if (ref($self) !~ /vmware/i) { + notify($ERRORS{'CRITICAL'}, 0, "subroutine was called as a function, it must be called as a class method"); + return; + } + + # Get the vmx path and format it for the VIX API + my $vix_vmx_path = $self->_get_datastore_path(shift) || return; + + # Get the VM handle + my $vm_handle = $self->_get_vm_handle($vix_vmx_path) || return; + + # Call VMPowerOff + notify($ERRORS{'DEBUG'}, 0, "attempting to power off VM: $vix_vmx_path"); + my ($error) = VMPowerOff($vm_handle, VIX_VMPOWEROP_NORMAL); + if ($error == VIX_OK) { + notify($ERRORS{'DEBUG'}, 0, "powered off VM: $vix_vmx_path"); + return 1; + } + elsif ($error == VIX_E_VM_NOT_RUNNING) { + notify($ERRORS{'DEBUG'}, 0, "VM is not running: $vix_vmx_path"); + return 1; + } + else { + my $error_text = GetErrorText($error); + notify($ERRORS{'WARNING'}, 0, "failed to power off VM: $vix_vmx_path, error: $error, $error_text"); + return; + } +} + +#///////////////////////////////////////////////////////////////////////////// + +=head2 vm_power_on + + Parameters : $vmx_file_path + Returns : boolean + Description : Powers on the VM specified by the vmx file path argument. + +=cut + +sub vm_power_on { + my $self = shift; + if (ref($self) !~ /vmware/i) { + notify($ERRORS{'CRITICAL'}, 0, "subroutine was called as a function, it must be called as a class method"); + return; + } + + # Get the vmx path and format it for the VIX API + my $vix_vmx_path = $self->_get_datastore_path(shift) || return; + + # Get the VM handle + my $vm_handle = $self->_get_vm_handle($vix_vmx_path) || return; + + # Call VMPowerOn + notify($ERRORS{'DEBUG'}, 0, "attempting to power on VM: $vix_vmx_path"); + my ($error) = VMPowerOn($vm_handle, VIX_VMPOWEROP_NORMAL, VIX_INVALID_HANDLE); + if ($error == VIX_OK) { + notify($ERRORS{'DEBUG'}, 0, "powered on VM: $vix_vmx_path"); + return 1; + } + else { + my $error_text = GetErrorText($error); + notify($ERRORS{'WARNING'}, 0, "failed to power on VM: $vix_vmx_path, error: $error, $error_text"); + return; + } +} + +#///////////////////////////////////////////////////////////////////////////// + +=head2 is_vm_registered + + Parameters : $vmx_file_path + Returns : boolean + Description : Determines if the VM specified by the vmx file path argument is + registered. + +=cut + +sub is_vm_registered { + my $self = shift; + if (ref($self) !~ /vmware/i) { + notify($ERRORS{'CRITICAL'}, 0, "subroutine was called as a function, it must be called as a class method"); + return; + } + + # Get the vmx path and format it for the VIX API + my $vix_vmx_path = $self->_get_datastore_path(shift) || return; + + # Make sure the VM is registered + my @registered_vms = $self->get_registered_vms(); + if (!...@registered_vms) { + notify($ERRORS{'DEBUG'}, 0, "there are no registered VMs"); + return 0; + } + + # Loop through the registered VMs and try to find a match + # Can't use grep because the vmx paths contain square brackets + for my $registered_vmx_path (@registered_vms) { + my $registered_vix_vmx_path = $self->_get_datastore_path($registered_vmx_path); + if ($vix_vmx_path eq $registered_vix_vmx_path) { + notify($ERRORS{'DEBUG'}, 0, "VM is registered: $vix_vmx_path"); + return 1; + } + } + + notify($ERRORS{'DEBUG'}, 0, "VM is not registered: $vix_vmx_path"); + + if (defined($self->{vm_handle}{$vix_vmx_path})) { + ReleaseHandle($self->{vm_handle}{$vix_vmx_path}); + } + + return 0; +} + +#///////////////////////////////////////////////////////////////////////////// + +=head2 vm_register + + Parameters : $vmx_file_path + Returns : boolean + Description : Registers the VM specified by the vmx file path argument. Returns + true if the VM is successfully registered or if it is already + registered. + +=cut + +sub vm_register { + my $self = shift; + if (ref($self) !~ /vmware/i) { + notify($ERRORS{'CRITICAL'}, 0, "subroutine was called as a function, it must be called as a class method"); + return; + } + + # Get the vmx path and format it for the VIX API + my $vix_vmx_path = $self->_get_datastore_path(shift) || return; + + # Get the VM host handle + my $host_handle = $self->_get_host_handle() || return; + + # Make sure the VM is not already registered + if ($self->is_vm_registered($vix_vmx_path)) { + notify($ERRORS{'OK'}, 0, "VM is already registered: $vix_vmx_path"); + return 1; + } + + # Call RegisterVM + notify($ERRORS{'DEBUG'}, 0, "attempting to register VM: $vix_vmx_path"); + my ($error) = RegisterVM($host_handle, $vix_vmx_path); + if ($error != VIX_OK) { + my $error_text = GetErrorText($error); + notify($ERRORS{'WARNING'}, 0, "failed to register VM: $vix_vmx_path, error: $error, $error_text"); + return; + } + + # Make sure the VM was successfully registered + if ($self->is_vm_registered($vix_vmx_path)) { + notify($ERRORS{'OK'}, 0, "registered VM: $vix_vmx_path"); + return 1; + } + else { + notify($ERRORS{'OK'}, 0, "VM is NOT registered, VIX did not return an error"); + return; + } +} + +#///////////////////////////////////////////////////////////////////////////// + +=head2 vm_unregister + + Parameters : $vmx_file_path + Returns : boolean + Description : Unregisters the VM specified by the vmx file path argument. + Returns true if the VM is successfully unregistered or if it was + not registered to begin with. + +=cut + +sub vm_unregister { + my $self = shift; + if (ref($self) !~ /vmware/i) { + notify($ERRORS{'CRITICAL'}, 0, "subroutine was called as a function, it must be called as a class method"); + return; + } + + # Get the vmx path and format it for the VIX API + my $vix_vmx_path = $self->_get_datastore_path(shift) || return; + + # Get the VM host handle + my $host_handle = $self->_get_host_handle() || return; + + # Make sure the VM is registered + if (!$self->is_vm_registered($vix_vmx_path)) { + notify($ERRORS{'OK'}, 0, "VM is not registered: $vix_vmx_path"); + return 1; + } + + # Make sure the VM is powered off + # If the VM is on and unregistered, the unregister command will succeed but the VM remains registered + my $power_state = $self->get_vm_power_state($vix_vmx_path) || return; + if ($power_state ne 'off') { + $self->vm_power_off($vix_vmx_path) || return; + } + + # Call RegisterVM + notify($ERRORS{'DEBUG'}, 0, "attempting to unregister VM: $vix_vmx_path"); + my ($error) = UnregisterVM($host_handle, $vix_vmx_path); + if ($error != VIX_OK) { + my $error_text = GetErrorText($error); + notify($ERRORS{'WARNING'}, 0, "failed to unregister VM: $vix_vmx_path, error: $error, $error_text"); + return; + } + + # Make sure the VM was unregistered + if (!$self->is_vm_registered($vix_vmx_path)) { + notify($ERRORS{'OK'}, 0, "unregistered VM: $vix_vmx_path"); + return 1; + } + else { + notify($ERRORS{'WARNING'}, 0, "VM is still registered, VIX did not return an error"); + return; + } +} + +#///////////////////////////////////////////////////////////////////////////// + +=head2 is_restricted + + Parameters : none + Returns : boolean + Description : Determines if remote access to the VM host via the VIX API is + restricted due to the type of VMware license being used on the + host. 0 is returned if remote access is not restricted. 1 is + returned if remote access is restricted and the access to the VM + host is read-only. + +=cut + +sub is_restricted { + my $self = shift; + if (ref($self) !~ /module/i) { + notify($ERRORS{'CRITICAL'}, 0, "subroutine was called as a function, it must be called as a class method"); + return; + } + + # Get the VM host handle + my $host_handle = $self->_get_host_handle() || return; + + # Call RegisterVM + notify($ERRORS{'DEBUG'}, 0, "checking if access to the VM host via the VIX API is restricted due to the license"); + my ($error) = RegisterVM($host_handle, ''); + + if ($error == VIX_E_LICENSE) { + my $error_text = GetErrorText($error); + notify($ERRORS{'DEBUG'}, 0, "access to the VM host via the VIX API is restricted due to the license, result of attempting to register a VM: $error_text"); + return 1; + } + else { + my $error_text = GetErrorText($error); + notify($ERRORS{'DEBUG'}, 0, "access to the VM host via the VIX API is NOT restricted due to the license"); + return 0; + } +} + +############################################################################## + +=head1 PRIVATE API OBJECT METHODS + +=cut + +#///////////////////////////////////////////////////////////////////////////// + +=head2 initialize + + Parameters : none + Returns : boolean + Description : Initialized the VMware VIX API object by obtaining a VM host + handle. False is returned if a host handle cannot be obtained. + +=cut + +sub initialize { + my $self = shift; + if (ref($self) !~ /vmware/i) { + notify($ERRORS{'CRITICAL'}, 0, "subroutine was called as a function, it must be called as a class method"); + return; + } + + $self->_get_host_handle() || return; + + return 1; +} + +#///////////////////////////////////////////////////////////////////////////// + +=head2 _find_items + + Parameters : $search_type, $timeout_seconds (optional) + Returns : array + Description : Exposes the VMware VIX API FindItems function. It searches for + VMs matching the search type argument. The search type values: + -VIX_FIND_RUNNING_VMS (1) + -VIX_FIND_REGISTERED_VMS (4) + +=cut + +sub _find_items { + my $self = shift; + if (ref($self) !~ /vmware/i) { + notify($ERRORS{'CRITICAL'}, 0, "subroutine was called as a function, it must be called as a class method"); + return; + } + + # Get the VM host handle argument + my $host_handle = $self->_get_host_handle() || return; + + # Get the search type argument + my $search_type = shift; + if (!defined($search_type)) { + notify($ERRORS{'WARNING'}, 0, "search type argument was not supplied"); + return; + } + + # Get the optional timeout seconds argument + my $timeout_seconds = shift || 15; + + # Check if the search type is valid and set a string + my $search_type_string; + if ($search_type == VIX_FIND_RUNNING_VMS) { + $search_type_string = 'running VMs'; + } + elsif ($search_type == VIX_FIND_REGISTERED_VMS) { + $search_type_string = 'registered VMs'; + } + else { + notify($ERRORS{'WARNING'}, 0, "unsupported search type specified: search_type"); + } + notify($ERRORS{'DEBUG'}, 0, "attempting to find $search_type_string"); + + # Call FindItems + my ($error, @vm_list) = FindItems($host_handle, $search_type, $timeout_seconds); + if ($error) { + my $error_text = GetErrorText($error); + notify($ERRORS{'WARNING'}, 0, "failed to find VMs, error: $error, $error_text"); + return; + } + else { + notify($ERRORS{'DEBUG'}, 0, "found " . scalar(@vm_list) . " $search_type_string:\n" . join("\n", @vm_list)); + return @vm_list; + } +} + +#///////////////////////////////////////////////////////////////////////////// + +=head2 _get_host_handle + + Parameters : none + Returns : boolean + Description : Obtains a VM host handle and stores it in the VIX API object. + +=cut + +sub _get_host_handle { + my $self = shift; + if (ref($self) !~ /vmware/i) { + notify($ERRORS{'CRITICAL'}, 0, "subroutine was called as a function, it must be called as a class method"); + return; + } + + # Check if the host handle has already been obtained + if (defined($self->{host_handle}) || $self->{host_handle}) { + return $self->{host_handle}; + } + + my $host_hostname = $self->data->get_vmhost_hostname(); + my $host_username = $self->data->get_vmhost_profile_username(); + my $host_password = $self->data->get_vmhost_profile_password(); + my $host_port = '8333'; + my $host_service_provider = $self->_get_vix_service_provider(); + + # Assemble the URLs to try + my @host_url_possibilities = ( + "https://$host_hostname/sdk", + "https://$host_hostname:$host_port/sdk", + "http://$host_hostname/sdk", + "http://$host_hostname:$host_port/sdk", + ); + + # Call HostConnect, check how long it takes to connect + for my $host_url (@host_url_possibilities) { + notify($ERRORS{'DEBUG'}, 0, "attempting to connect to VM host: $host_url"); + my ($error, $host_handle) = HostConnect(VIX_API_VERSION, + $host_service_provider, + $host_url, + $host_port, + $host_username, + $host_password, + 0, + VIX_INVALID_HANDLE); + + # Check if an error occurred + if ($error == VIX_OK) { + notify($ERRORS{'DEBUG'}, 0, "connected to VM host $host_url"); + $self->{host_handle} = $host_handle; + return $self->{host_handle}; + } + else { + my $error_text = GetErrorText($error); + notify($ERRORS{'DEBUG'}, 0, "unable to connect to VM host using URL: $host_url, error: $error, $error_text"); + } + } + + notify($ERRORS{'WARNING'}, 0, "failed to connect to VM host using any of the possible URLs"); + return; +} + +#///////////////////////////////////////////////////////////////////////////// + +=head2 _get_vm_handle + + Parameters : $vmx_file_path + Returns : VIX VM handle object + Description : Obtains a VM handle for the VM specified by the vmx path + argument. + +=cut + +sub _get_vm_handle { + my $self = shift; + if (ref($self) !~ /vmware/i) { + notify($ERRORS{'CRITICAL'}, 0, "subroutine was called as a function, it must be called as a class method"); + return; + } + + # Get the vmx path formatted for VIX + my $vix_vmx_path = $self->_get_datastore_path(shift) || return; + + # If a VM handle was previously obtained, release it + if ($self->{vm_handle}{$vix_vmx_path}) { + ReleaseHandle($self->{vm_handle}{$vix_vmx_path}); + } + + # Get the host handle + my $host_handle = $self->_get_host_handle() || return; + + # Call HostOpenVM + notify($ERRORS{'DEBUG'}, 0, "attempting to obtain VM handle: $vix_vmx_path"); + my ($error, $vm_handle) = HostOpenVM($host_handle, + $vix_vmx_path, + VIX_VMOPEN_NORMAL, + VIX_INVALID_HANDLE); + + # Check if error occurred + if ($error != VIX_OK) { + my $error_text = GetErrorText($error); + notify($ERRORS{'WARNING'}, 0, "failed to obtain VM handle: $vix_vmx_path, error: $error, $error_text"); + return; + } + else { + $self->{vm_handle}{$vix_vmx_path} = $vm_handle; + return $self->{vm_handle}{$vix_vmx_path}; + } +} + +#///////////////////////////////////////////////////////////////////////////// + +=head2 _get_vm_power_states + + Parameters : $vmx_path + Returns : array + Description : Retrieves the power state names for the VM specified by the vmx + path argument. An array containing the names is returned. Valid + power state names are: + -POWERING_OFF + -POWERED_OFF + -POWERING_ON + -POWERED_ON + -SUSPENDING + -SUSPENDED + -TOOLS_RUNNING + -RESETTING + -BLOCKED_ON_MSG + + +=cut + +sub _get_vm_power_states { + my $self = shift; + if (ref($self) !~ /vmware/i) { + notify($ERRORS{'CRITICAL'}, 0, "subroutine was called as a function, it must be called as a class method"); + return; + } + + # Get the vmx path and format it for the VIX API + my $vix_vmx_path = $self->_get_datastore_path(shift) || return; + + # Get the power state property + my ($power_state_id) = $self->_get_properties($vix_vmx_path, VIX_PROPERTY_VM_POWER_STATE); + if (!$power_state_id) { + notify($ERRORS{'WARNING'}, 0, "failed to retrieve power state property for VM: $vix_vmx_path"); + return; + } + + # There may be multiple power states in effect, the value returned must be evaluated bitwise against the valid power state IDs + my @powerstate_names; + my $powerstate_string; + for my $vix_powerstate_id (keys %VIX_POWERSTATE) { + if ($power_state_id & $vix_powerstate_id) { + unshift @powerstate_names, $VIX_POWERSTATE{$vix_powerstate_id}; + $powerstate_string .= "$VIX_POWERSTATE{$vix_powerstate_id} ($vix_powerstate_id), "; + } + } + $powerstate_string =~ s/, $//; + + notify($ERRORS{'DEBUG'}, 0, "power states for VM: $vix_vmx_path:\n" . join("\n", @powerstate_names)); + return @powerstate_names; +} + +#///////////////////////////////////////////////////////////////////////////// + +=head2 _get_properties + + Parameters : $vm_handle, $property_id_1, $property_id_2... + Returns : array + Description : Exposes the VIX GetProperties function to retrieve the properties + of a handle. + +=cut + +sub _get_properties { + my $self = shift; + if (ref($self) !~ /vmware/i) { + notify($ERRORS{'CRITICAL'}, 0, "subroutine was called as a function, it must be called as a class method"); + return; + } + + # Get the vmx path and format it for the VIX API + my $vix_vmx_path = $self->_get_datastore_path(shift) || return; + + # Get the VM handle argument + my $vm_handle = $self->_get_vm_handle($vix_vmx_path) || return; + + # Get the property ID argument + my @property_ids = @_; + if (!...@property_ids) { + notify($ERRORS{'WARNING'}, 0, "property ID arguments were not supplied"); + return; + } + + # Make sure the property IDs are valid + my $property_name_string; + for my $property_id (@property_ids) { + if (!defined($VIX_PROPERTY_VM{$property_id})) { + notify($ERRORS{'WARNING'}, 0, "unsupported property ID was passed as an argument: $property_id"); + return; + } + $property_name_string .= "$VIX_PROPERTY_VM{$property_id} ($property_id), "; + } + $property_name_string =~ s/, $//; + + # Call GetProperties + notify($ERRORS{'DEBUG'}, 0, "attempting to retrieve values of properties: $property_name_string"); + my ($error, @property_values) = GetProperties($vm_handle, @property_ids); + if ($error) { + my $error_text = GetErrorText($error); + notify($ERRORS{'WARNING'}, 0, "failed to retrieve values of properties: $property_name_string, error: $error, $error_text"); + return; + } + + # Make sure the property ID array is the same size as the value array + if (scalar(@property_ids) != scalar(@property_values)) { + notify($ERRORS{'WARNING'}, 0, "property ID count " . scalar(@property_ids) . " does not match the number of properties returned by GetProperties " . scalar(@property_values)); + return; + } + + # Assemble a string showing the names and values of the properties retrieved + my $property_value_string; + for (my $i=0; $i<scalar(@property_ids); $i++) { + my $property_id = $property_ids[$i]; + my $property_name = $VIX_PROPERTY_VM{$property_id}; + my $property_value = $property_values[$i]; + $property_value_string .= "$property_name ($property_id) = $property_value\n" + } + notify($ERRORS{'DEBUG'}, 0, "retrieved properties:\n$property_value_string"); + + return @property_values; +} + +#///////////////////////////////////////////////////////////////////////////// + +=head2 _get_datastore_path + + Parameters : $vmx_file_path + Returns : string + Description : Converts the vmx file path argument to a datastore path. + +=cut + +sub _get_datastore_path { + my ($self) = shift; + if (ref($self) !~ /vmware/i) { + notify($ERRORS{'CRITICAL'}, 0, "subroutine was called as a function, it must be called as a class method"); + return; + } + + # Get the path argument if supplied + my $path = shift; + if (!$path) { + notify($ERRORS{'WARNING'}, 0, "path argument was not supplied"); + return; + } + + # Per the VIX documentation: + # For VMware Server 1.x, supply the full path name instead of the datastore path + # Also, if the path already contains a '[' assume it's a datastore path and return it unaltered + my $host_service_provider = $self->_get_vix_service_provider() || return; + if ($host_service_provider == VIX_SERVICEPROVIDER_VMWARE_SERVER || $path =~ /\[/) { + return $path; + } + + my $datastore_name; + my $relative_datastore_path; + + if ($path =~ /^\/vmfs\/volumes\//) { + ($datastore_name) = $path =~ /\/vmfs\/volumes\/([^\/]+)/; + ($relative_datastore_path) = $path =~ /$datastore_name\/(.*)/; + } + else { + $datastore_name = 'standard'; + + my $vmx_base_directory_path = $self->get_vmx_base_directory_path() || return; + ($relative_datastore_path) = $path =~ /$vmx_base_directory_path\/(.*)/; + } + + $relative_datastore_path =~ s/(^[\s\/]+|[\s\/]+$)//g if $relative_datastore_path; + + if (!$datastore_name || !$relative_datastore_path) { + notify($ERRORS{'WARNING'}, 0, "unable to determine datastore name and relative datastore path from path: $path"); + return; + } + + return "[$datastore_name] $relative_datastore_path"; +} + +#///////////////////////////////////////////////////////////////////////////// + +=head2 _get_vix_service_provider + + Parameters : none + Returns : integer + Description : Determines the appropriate VIX_SERVICEPROVIDER value to use + depending on the VMware product being used. Per the VMware VIX + documentation: + vCenter Server, ESX/ESXi hosts, VMware Server 2.0: VIX_SERVICEPROVIDER_VMWARE_VI_SERVER + VMware Workstation: VIX_SERVICEPROVIDER_VMWARE_WORKSTATION + VMware Player: VIX_SERVICEPROVIDER_VMWARE_PLAYER + VMware Server 1.0.x: VIX_SERVICEPROVIDER_VMWARE_SERVER + +=cut + +sub _get_vix_service_provider { + my ($self) = @_; + if (ref($self) !~ /vmware/i) { + notify($ERRORS{'CRITICAL'}, 0, "subroutine was called as a function, it must be called as a class method"); + return; + } + + # Return the value stored in this object if it has already been determined + return $self->{service_provider} if $self->{service_provider}; + + # Check the VM host type name, figure out which VMware product is being used and set the object's service_provider key + # Use VIX_SERVICEPROVIDER_VMWARE_VI_SERVER as the default value since it's most common + my $vmhost_type_name = $self->data->get_vmhost_type_name(); + if ($vmhost_type_name =~ /(workstation)/i) { + $self->{service_provider} = VIX_SERVICEPROVIDER_VMWARE_WORKSTATION; + notify($ERRORS{'DEBUG'}, 0, "VM type is $vmhost_type_name, using service provider: VIX_SERVICEPROVIDER_VMWARE_WORKSTATION"); + } + elsif ($vmhost_type_name =~ /(player)/i) { + $self->{service_provider} = VIX_SERVICEPROVIDER_VMWARE_PLAYER; + notify($ERRORS{'DEBUG'}, 0, "VM host type is $vmhost_type_name, using service provider: VIX_SERVICEPROVIDER_VMWARE_PLAYER"); + } + elsif ($vmhost_type_name =~ /^(vmwareGSX|vmwarefreeserver|.*1\..*)$/i) { + $self->{service_provider} = VIX_SERVICEPROVIDER_VMWARE_SERVER; + notify($ERRORS{'DEBUG'}, 0, "VM host type is $vmhost_type_name, using service provider: VIX_SERVICEPROVIDER_VMWARE_SERVER"); + } + else { + $self->{service_provider} = VIX_SERVICEPROVIDER_VMWARE_VI_SERVER; + notify($ERRORS{'DEBUG'}, 0, "VM host type is $vmhost_type_name, using service provider: VIX_SERVICEPROVIDER_VMWARE_VI_SERVER"); + } + + return $self->{service_provider}; +} + +#///////////////////////////////////////////////////////////////////////////// + +=head2 DESTROY + + Parameters : none + Returns : true + Description : Called when the VIX API object is destroyed. Disconnects the host + handle. + +=cut + +sub DESTROY { + my $self = shift; + notify($ERRORS{'DEBUG'}, 0, "destructor called, ref(\$self)=" . ref($self)); + + # Check for an overridden destructor + $self->SUPER::DESTROY if $self->can("SUPER::DESTROY"); + + # Disconnect from the VM host if connected + HostDisconnect($self->{host_handle}) if $self->{host_handle}; + + return 1; +} + +#///////////////////////////////////////////////////////////////////////////// + +1; +__END__ + +=head1 SEE ALSO + +L<http://cwiki.apache.org/VCL/> + +=cut Propchange: incubator/vcl/trunk/managementnode/lib/VCL/Module/Provisioning/VMware/VIX_API.pm ------------------------------------------------------------------------------ svn:eol-style = native Propchange: incubator/vcl/trunk/managementnode/lib/VCL/Module/Provisioning/VMware/VIX_API.pm ------------------------------------------------------------------------------ svn:keywords = Date Revision Author HeadURL Id