
blueprint vmware-compute-driver Rename VMWare to VMware Rename network_utils to network_util to conform to the util class naming convention Remove the infinite loop in vim.__getattr__ Change-Id: I5bdad331a86c7aa4ca36e7a8345b53e455678c0f
180 lines
7.1 KiB
Python
180 lines
7.1 KiB
Python
# vim: tabstop=4 shiftwidth=4 softtabstop=4
|
|
|
|
# Copyright (c) 2012 VMware, Inc.
|
|
# Copyright (c) 2011 Citrix Systems, Inc.
|
|
# Copyright 2011 OpenStack LLC.
|
|
#
|
|
# Licensed 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.
|
|
|
|
"""
|
|
Classes for making VMware VI SOAP calls.
|
|
"""
|
|
|
|
import httplib
|
|
|
|
try:
|
|
import suds
|
|
except ImportError:
|
|
suds = None
|
|
|
|
from nova.openstack.common import cfg
|
|
from nova.virt.vmwareapi import error_util
|
|
|
|
RESP_NOT_XML_ERROR = 'Response is "text/html", not "text/xml"'
|
|
CONN_ABORT_ERROR = 'Software caused connection abort'
|
|
ADDRESS_IN_USE_ERROR = 'Address already in use'
|
|
|
|
vmwareapi_wsdl_loc_opt = cfg.StrOpt('vmwareapi_wsdl_loc',
|
|
default=None,
|
|
help='VIM Service WSDL Location '
|
|
'e.g http://<server>/vimService.wsdl. '
|
|
'Due to a bug in vSphere ESX 4.1 default wsdl. '
|
|
'Refer readme-vmware to setup')
|
|
|
|
CONF = cfg.CONF
|
|
CONF.register_opt(vmwareapi_wsdl_loc_opt)
|
|
|
|
|
|
if suds:
|
|
|
|
class VIMMessagePlugin(suds.plugin.MessagePlugin):
|
|
|
|
def addAttributeForValue(self, node):
|
|
# suds does not handle AnyType properly.
|
|
# VI SDK requires type attribute to be set when AnyType is used
|
|
if node.name == 'value':
|
|
node.set('xsi:type', 'xsd:string')
|
|
|
|
def marshalled(self, context):
|
|
"""suds will send the specified soap envelope.
|
|
Provides the plugin with the opportunity to prune empty
|
|
nodes and fixup nodes before sending it to the server.
|
|
"""
|
|
# suds builds the entire request object based on the wsdl schema.
|
|
# VI SDK throws server errors if optional SOAP nodes are sent
|
|
# without values, e.g. <test/> as opposed to <test>test</test>
|
|
context.envelope.prune()
|
|
context.envelope.walk(self.addAttributeForValue)
|
|
|
|
|
|
class Vim:
|
|
"""The VIM Object."""
|
|
|
|
def __init__(self,
|
|
protocol="https",
|
|
host="localhost"):
|
|
"""
|
|
Creates the necessary Communication interfaces and gets the
|
|
ServiceContent for initiating SOAP transactions.
|
|
|
|
protocol: http or https
|
|
host : ESX IPAddress[:port] or ESX Hostname[:port]
|
|
"""
|
|
if not suds:
|
|
raise Exception(_("Unable to import suds."))
|
|
|
|
self._protocol = protocol
|
|
self._host_name = host
|
|
wsdl_url = CONF.vmwareapi_wsdl_loc
|
|
if wsdl_url is None:
|
|
raise Exception(_("Must specify vmwareapi_wsdl_loc"))
|
|
# TODO(sateesh): Use this when VMware fixes their faulty wsdl
|
|
#wsdl_url = '%s://%s/sdk/vimService.wsdl' % (self._protocol,
|
|
# self._host_name)
|
|
url = '%s://%s/sdk' % (self._protocol, self._host_name)
|
|
self.client = suds.client.Client(wsdl_url, location=url,
|
|
plugins=[VIMMessagePlugin()])
|
|
self._service_content = self.RetrieveServiceContent("ServiceInstance")
|
|
|
|
def get_service_content(self):
|
|
"""Gets the service content object."""
|
|
return self._service_content
|
|
|
|
def __getattr__(self, attr_name):
|
|
"""Makes the API calls and gets the result."""
|
|
def vim_request_handler(managed_object, **kwargs):
|
|
"""
|
|
Builds the SOAP message and parses the response for fault
|
|
checking and other errors.
|
|
|
|
managed_object : Managed Object Reference or Managed
|
|
Object Name
|
|
**kwargs : Keyword arguments of the call
|
|
"""
|
|
# Dynamic handler for VI SDK Calls
|
|
try:
|
|
request_mo = self._request_managed_object_builder(
|
|
managed_object)
|
|
request = getattr(self.client.service, attr_name)
|
|
response = request(request_mo, **kwargs)
|
|
# To check for the faults that are part of the message body
|
|
# and not returned as Fault object response from the ESX
|
|
# SOAP server
|
|
if hasattr(error_util.FaultCheckers,
|
|
attr_name.lower() + "_fault_checker"):
|
|
fault_checker = getattr(error_util.FaultCheckers,
|
|
attr_name.lower() + "_fault_checker")
|
|
fault_checker(response)
|
|
return response
|
|
# Catch the VimFaultException that is raised by the fault
|
|
# check of the SOAP response
|
|
except error_util.VimFaultException, excep:
|
|
raise
|
|
except suds.WebFault, excep:
|
|
doc = excep.document
|
|
detail = doc.childAtPath("/Envelope/Body/Fault/detail")
|
|
fault_list = []
|
|
for child in detail.getChildren():
|
|
fault_list.append(child.get("type"))
|
|
raise error_util.VimFaultException(fault_list, excep)
|
|
except AttributeError, excep:
|
|
raise error_util.VimAttributeError(_("No such SOAP method "
|
|
"'%s' provided by VI SDK") % (attr_name), excep)
|
|
except (httplib.CannotSendRequest,
|
|
httplib.ResponseNotReady,
|
|
httplib.CannotSendHeader), excep:
|
|
raise error_util.SessionOverLoadException(_("httplib "
|
|
"error in %s: ") % (attr_name), excep)
|
|
except Exception, excep:
|
|
# Socket errors which need special handling for they
|
|
# might be caused by ESX API call overload
|
|
if (str(excep).find(ADDRESS_IN_USE_ERROR) != -1 or
|
|
str(excep).find(CONN_ABORT_ERROR)) != -1:
|
|
raise error_util.SessionOverLoadException(_("Socket "
|
|
"error in %s: ") % (attr_name), excep)
|
|
# Type error that needs special handling for it might be
|
|
# caused by ESX host API call overload
|
|
elif str(excep).find(RESP_NOT_XML_ERROR) != -1:
|
|
raise error_util.SessionOverLoadException(_("Type "
|
|
"error in %s: ") % (attr_name), excep)
|
|
else:
|
|
raise error_util.VimException(
|
|
_("Exception in %s ") % (attr_name), excep)
|
|
return vim_request_handler
|
|
|
|
def _request_managed_object_builder(self, managed_object):
|
|
"""Builds the request managed object."""
|
|
# Request Managed Object Builder
|
|
if isinstance(managed_object, str):
|
|
mo = suds.sudsobject.Property(managed_object)
|
|
mo._type = managed_object
|
|
else:
|
|
mo = managed_object
|
|
return mo
|
|
|
|
def __repr__(self):
|
|
return "VIM Object"
|
|
|
|
def __str__(self):
|
|
return "VIM Object"
|