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


Reply via email to