summaryrefslogtreecommitdiffstats
path: root/nova
diff options
context:
space:
mode:
authorsateesh <sateesh.chodapuneedi@citrix.com>2011-03-10 21:07:44 +0530
committersateesh <sateesh.chodapuneedi@citrix.com>2011-03-10 21:07:44 +0530
commit3e97dc47221d19b39aba99f6d389d2ec326e72be (patch)
treeb85f7c1040133e103ebf03cc6c4a064fa95dffbb /nova
parentf53357d32304cd721185704fa0d48454b5627199 (diff)
Updated the code to detect the exception by fault type.
SOAP faults are embedded in the SOAP response as a property. Certain faults are sent as a part of the SOAP body as property of missingSet. E.g. NotAuthenticated fault. So we examine the response object for missingSet and try to check the property for fault type.
Diffstat (limited to 'nova')
-rw-r--r--nova/console/vmrc.py2
-rw-r--r--nova/virt/vmwareapi/error_util.py82
-rw-r--r--nova/virt/vmwareapi/fake.py13
-rw-r--r--nova/virt/vmwareapi/network_utils.py44
-rw-r--r--nova/virt/vmwareapi/vim.py69
-rw-r--r--nova/virt/vmwareapi/vmops.py13
-rw-r--r--nova/virt/vmwareapi_conn.py23
7 files changed, 178 insertions, 68 deletions
diff --git a/nova/console/vmrc.py b/nova/console/vmrc.py
index 09f8067e5..9c5e3b444 100644
--- a/nova/console/vmrc.py
+++ b/nova/console/vmrc.py
@@ -119,7 +119,7 @@ class VMRCSessionConsole(VMRCConsole):
vim_session._get_vim(),
"AcquireCloneTicket",
vim_session._get_vim().get_service_content().sessionManager)
- return str(vm_ref) + ":" + virtual_machine_ticket
+ return str(vm_ref.value) + ":" + virtual_machine_ticket
def is_otp(self):
"""Is one time password."""
diff --git a/nova/virt/vmwareapi/error_util.py b/nova/virt/vmwareapi/error_util.py
new file mode 100644
index 000000000..3196b5038
--- /dev/null
+++ b/nova/virt/vmwareapi/error_util.py
@@ -0,0 +1,82 @@
+# vim: tabstop=4 shiftwidth=4 softtabstop=4
+
+# 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.
+
+"""
+Exception classes and SOAP response error checking module
+"""
+
+FAULT_NOT_AUTHENTICATED = "NotAuthenticated"
+FAULT_ALREADY_EXISTS = "AlreadyExists"
+
+
+class VimException(Exception):
+ """The VIM Exception class"""
+
+ def __init__(self, exception_summary, excep):
+ Exception.__init__(self)
+ self.exception_summary = exception_summary
+ self.exception_obj = excep
+
+ def __str__(self):
+ return self.exception_summary + str(self.exception_obj)
+
+
+class SessionOverLoadException(VimException):
+ """Session Overload Exception"""
+ pass
+
+
+class VimAttributeError(VimException):
+ """VI Attribute Error"""
+ pass
+
+
+class VimFaultException(Exception):
+ """The VIM Fault exception class"""
+
+ def __init__(self, fault_list, excep):
+ Exception.__init__(self)
+ self.fault_list = fault_list
+ self.exception_obj = excep
+
+ def __str__(self):
+ return str(self.exception_obj)
+
+
+class FaultCheckers:
+ """Methods for fault checking of SOAP response. Per Method error handlers
+ for which we desire error checking are defined. SOAP faults are
+ embedded in the SOAP as a property and not as a SOAP fault."""
+
+ @classmethod
+ def retrieveproperties_fault_checker(self, resp_obj):
+ """Checks the RetrieveProperties response for errors. Certain faults
+ are sent as a part of the SOAP body as property of missingSet.
+ For example NotAuthenticated fault"""
+ fault_list = []
+ for obj_cont in resp_obj:
+ if hasattr(obj_cont, "missingSet"):
+ for missing_elem in obj_cont.missingSet:
+ fault_type = missing_elem.fault.fault.__class__.__name__
+ #Fault needs to be added to the type of fault for
+ #uniformity in error checking as SOAP faults define
+ fault_list.append(fault_type)
+ if fault_list:
+ exc_msg_list = ', '.join(fault_list)
+ raise VimFaultException(fault_list, Exception(_("Error(s) %s "
+ "occurred in the call to RetrieveProperties") %
+ exc_msg_list))
diff --git a/nova/virt/vmwareapi/fake.py b/nova/virt/vmwareapi/fake.py
index 40ed18340..909d1a6cf 100644
--- a/nova/virt/vmwareapi/fake.py
+++ b/nova/virt/vmwareapi/fake.py
@@ -25,7 +25,7 @@ import uuid
from nova import exception
from nova import log as logging
from nova.virt.vmwareapi import vim
-from nova.virt.vmwareapi.vim import SessionFaultyException
+from nova.virt.vmwareapi import error_util
_CLASSES = ['Datacenter', 'Datastore', 'ResourcePool', 'VirtualMachine',
'Network', 'HostSystem', 'HostNetworkSystem', 'Task', 'session',
@@ -500,7 +500,7 @@ class FakeVim(object):
"out: %s") % s)
del _db_content['session'][s]
- def _terminate(self, *args, **kwargs):
+ def _terminate_session(self, *args, **kwargs):
""" Terminates a session """
s = kwargs.get("sessionId")[0]
if s not in _db_content['session']:
@@ -512,7 +512,9 @@ class FakeVim(object):
if (self._session is None or self._session not in
_db_content['session']):
LOG.debug(_("Session is faulty"))
- raise SessionFaultyException(_("Session Invalid"))
+ raise error_util.VimFaultException(
+ [error_util.FAULT_NOT_AUTHENTICATED],
+ _("Session Invalid"))
def _create_vm(self, method, *args, **kwargs):
""" Creates and registers a VM object with the Host System """
@@ -656,8 +658,9 @@ class FakeVim(object):
return lambda *args, **kwargs: self._login()
elif attr_name == "Logout":
self._logout()
- elif attr_name == "Terminate":
- return lambda *args, **kwargs: self._terminate(*args, **kwargs)
+ elif attr_name == "TerminateSession":
+ return lambda *args, **kwargs: self._terminate_session(
+ *args, **kwargs)
elif attr_name == "CreateVM_Task":
return lambda *args, **kwargs: self._create_vm(attr_name,
*args, **kwargs)
diff --git a/nova/virt/vmwareapi/network_utils.py b/nova/virt/vmwareapi/network_utils.py
index 59a3c234f..f27121071 100644
--- a/nova/virt/vmwareapi/network_utils.py
+++ b/nova/virt/vmwareapi/network_utils.py
@@ -20,15 +20,12 @@ Utility functions for ESX Networking
"""
from nova import log as logging
+from nova.virt.vmwareapi import error_util
from nova.virt.vmwareapi import vim_util
from nova.virt.vmwareapi import vm_util
-from nova.virt.vmwareapi.vim import VimException
LOG = logging.getLogger("nova.virt.vmwareapi.network_utils")
-PORT_GROUP_EXISTS_EXCEPTION = \
- 'The specified key, name, or identifier already exists.'
-
class NetworkHelper:
@@ -38,7 +35,13 @@ class NetworkHelper:
argument. """
datacenters = session._call_method(vim_util, "get_objects",
"Datacenter", ["network"])
- vm_networks = datacenters[0].propSet[0].val.ManagedObjectReference
+ vm_networks_ret = datacenters[0].propSet[0].val
+ #Meaning there are no networks on the host. suds responds with a ""
+ #in the parent property field rather than a [] in the
+ #ManagedObjectRefernce property field of the parent
+ if not vm_networks_ret:
+ return None
+ vm_networks = vm_networks_ret.ManagedObjectReference
networks = session._call_method(vim_util,
"get_properites_for_a_collection_of_objects",
"Network", vm_networks, ["summary.name"])
@@ -54,9 +57,14 @@ class NetworkHelper:
#Get the list of vSwicthes on the Host System
host_mor = session._call_method(vim_util, "get_objects",
"HostSystem")[0].obj
- vswitches = session._call_method(vim_util,
+ vswitches_ret = session._call_method(vim_util,
"get_dynamic_property", host_mor,
- "HostSystem", "config.network.vswitch").HostVirtualSwitch
+ "HostSystem", "config.network.vswitch")
+ #Meaning there are no vSwitches on the host. Shouldn't be the case,
+ #but just doing code check
+ if not vswitches_ret:
+ return
+ vswitches = vswitches_ret.HostVirtualSwitch
#Get the vSwitch associated with the network adapter
for elem in vswitches:
try:
@@ -71,9 +79,13 @@ class NetworkHelper:
""" Checks if the vlan_inteface exists on the esx host """
host_net_system_mor = session._call_method(vim_util, "get_objects",
"HostSystem", ["configManager.networkSystem"])[0].propSet[0].val
- physical_nics = session._call_method(vim_util,
+ physical_nics_ret = session._call_method(vim_util,
"get_dynamic_property", host_net_system_mor,
- "HostNetworkSystem", "networkInfo.pnic").PhysicalNic
+ "HostNetworkSystem", "networkInfo.pnic")
+ #Meaning there are no physical nics on the host
+ if not physical_nics_ret:
+ return False
+ physical_nics = physical_nics_ret.PhysicalNic
for pnic in physical_nics:
if vlan_interface == pnic.device:
return True
@@ -84,9 +96,15 @@ class NetworkHelper:
""" Get the vlan id and vswicth associated with the port group """
host_mor = session._call_method(vim_util, "get_objects",
"HostSystem")[0].obj
- port_grps_on_host = session._call_method(vim_util,
+ port_grps_on_host_ret = session._call_method(vim_util,
"get_dynamic_property", host_mor,
- "HostSystem", "config.network.portgroup").HostPortGroup
+ "HostSystem", "config.network.portgroup")
+ if not port_grps_on_host_ret:
+ excep = ("ESX SOAP server returned an empty port group "
+ "for the host system in its response")
+ LOG.exception(excep)
+ raise Exception(_(excep))
+ port_grps_on_host = port_grps_on_host_ret.HostPortGroup
for p_gp in port_grps_on_host:
if p_gp.spec.name == pg_name:
p_grp_vswitch_name = p_gp.vswitch.split("-")[-1]
@@ -113,13 +131,13 @@ class NetworkHelper:
session._call_method(session._get_vim(),
"AddPortGroup", network_system_mor,
portgrp=add_prt_grp_spec)
- except VimException, exc:
+ except error_util.VimFaultException, exc:
#There can be a race condition when two instances try
#adding port groups at the same time. One succeeds, then
#the other one will get an exception. Since we are
#concerned with the port group being created, which is done
#by the other call, we can ignore the exception.
- if str(exc).find(PORT_GROUP_EXISTS_EXCEPTION) == -1:
+ if error_util.FAULT_ALREADY_EXISTS not in exc.fault_list:
raise Exception(exc)
LOG.debug(_("Created Port Group with name %s on "
"the ESX host") % pg_name)
diff --git a/nova/virt/vmwareapi/vim.py b/nova/virt/vmwareapi/vim.py
index 6a3e4b376..cea65e198 100644
--- a/nova/virt/vmwareapi/vim.py
+++ b/nova/virt/vmwareapi/vim.py
@@ -21,11 +21,13 @@ Classes for making VMware VI SOAP calls
import httplib
+from suds import WebFault
from suds.client import Client
from suds.plugin import MessagePlugin
from suds.sudsobject import Property
from nova import flags
+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'
@@ -40,33 +42,6 @@ flags.DEFINE_string('vmwareapi_wsdl_loc',
'Read the readme for vmware to setup')
-class VimException(Exception):
- """The VIM Exception class"""
-
- def __init__(self, exception_summary, excep):
- Exception.__init__(self)
- self.exception_summary = exception_summary
- self.exception_obj = excep
-
- def __str__(self):
- return self.exception_summary + str(self.exception_obj)
-
-
-class SessionOverLoadException(VimException):
- """Session Overload Exception"""
- pass
-
-
-class SessionFaultyException(VimException):
- """Session Faulty Exception"""
- pass
-
-
-class VimAttributeError(VimException):
- """VI Attribute Error"""
- pass
-
-
class VIMMessagePlugin(MessagePlugin):
def addAttributeForValue(self, node):
@@ -133,29 +108,49 @@ class Vim:
request_mo = \
self._request_managed_object_builder(managed_object)
request = getattr(self.client.service, attr_name)
- return request(request_mo, **kwargs)
+ 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 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 VimAttributeError(_("No such SOAP method '%s'"
- " provided by VI SDK") % (attr_name), 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 SessionOverLoadException(_("httplib error in"
- " %s: ") % (attr_name), 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 SessionOverLoadException(_("Socket error in"
- " %s: ") % (attr_name), excep)
+ 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 SessionOverLoadException(_("Type error in "
- " %s: ") % (attr_name), excep)
+ raise error_util.SessionOverLoadException(_("Type "
+ "error in %s: ") % (attr_name), excep)
else:
- raise VimException(
+ raise error_util.VimException(
_("Exception in %s ") % (attr_name), excep)
return vim_request_handler
diff --git a/nova/virt/vmwareapi/vmops.py b/nova/virt/vmwareapi/vmops.py
index 524c35af5..344c4518b 100644
--- a/nova/virt/vmwareapi/vmops.py
+++ b/nova/virt/vmwareapi/vmops.py
@@ -373,10 +373,15 @@ class VMWareVMOps(object):
def _check_if_tmp_folder_exists():
#Copy the contents of the VM that were there just before the
#snapshot was taken
- ds_ref = vim_util.get_dynamic_property(self._session._get_vim(),
- vm_ref,
- "VirtualMachine",
- "datastore").ManagedObjectReference[0]
+ ds_ref_ret = vim_util.get_dynamic_property(
+ self._session._get_vim(),
+ vm_ref,
+ "VirtualMachine",
+ "datastore")
+ if not ds_ref_ret:
+ raise Exception(_("Failed to get the datastore reference(s) "
+ "which the VM uses"))
+ ds_ref = ds_ref_ret.ManagedObjectReference[0]
ds_browser = vim_util.get_dynamic_property(
self._session._get_vim(),
ds_ref,
diff --git a/nova/virt/vmwareapi_conn.py b/nova/virt/vmwareapi_conn.py
index bd3ab4320..a2609278d 100644
--- a/nova/virt/vmwareapi_conn.py
+++ b/nova/virt/vmwareapi_conn.py
@@ -40,6 +40,7 @@ from nova import db
from nova import flags
from nova import log as logging
from nova import utils
+from nova.virt.vmwareapi import error_util
from nova.virt.vmwareapi import vim
from nova.virt.vmwareapi import vim_util
from nova.virt.vmwareapi.vmops import VMWareVMOps
@@ -60,7 +61,7 @@ flags.DEFINE_string('vmwareapi_host_password',
'Password for connection to VMWare ESX host.'
'Used only if connection_type is vmwareapi.')
flags.DEFINE_float('vmwareapi_task_poll_interval',
- 1.0,
+ 5.0,
'The interval used for polling of remote tasks '
'Used only if connection_type is vmwareapi')
flags.DEFINE_float('vmwareapi_api_retry_count',
@@ -264,13 +265,19 @@ class VMWareAPISession(object):
ret_val = temp_module(*args, **kwargs)
return ret_val
- except vim.SessionFaultyException, excep:
+ except error_util.VimFaultException, excep:
# If it is a Session Fault Exception, it may point
# to a session gone bad. So we try re-creating a session
# and then proceeding ahead with the call.
exc = excep
- self._create_session()
- except vim.SessionOverLoadException, excep:
+ if error_util.FAULT_NOT_AUTHENTICATED in excep.fault_list:
+ self._create_session()
+ else:
+ #No re-trying for errors for API call has gone through
+ #and is the caller's fault. Caller should handle these
+ #errors. e.g, InvalidArgument fault.
+ break
+ except error_util.SessionOverLoadException, excep:
# For exceptions which may come because of session overload,
# we retry
exc = excep
@@ -288,7 +295,7 @@ class VMWareAPISession(object):
LOG.critical(_("In vmwareapi:_call_method, "
"got this exception: %s") % exc)
- raise Exception(exc)
+ raise
def _get_vim(self):
"""Gets the VIM object reference"""
@@ -301,11 +308,11 @@ class VMWareAPISession(object):
The task is polled until it completes.
"""
done = event.Event()
- self.loop = utils.LoopingCall(self._poll_task, instance_id, task_ref,
+ loop = utils.LoopingCall(self._poll_task, instance_id, task_ref,
done)
- self.loop.start(FLAGS.vmwareapi_task_poll_interval, now=True)
+ loop.start(FLAGS.vmwareapi_task_poll_interval, now=True)
ret_val = done.wait()
- self.loop.stop()
+ loop.stop()
return ret_val
def _poll_task(self, instance_id, task_ref, done):