diff --git a/oslo_vmware/api.py b/oslo_vmware/api.py
index a9839c07..ed3a5535 100644
--- a/oslo_vmware/api.py
+++ b/oslo_vmware/api.py
@@ -140,7 +140,7 @@ class VMwareAPISession(object):
api_retry_count, task_poll_interval, scheme='https',
create_session=True, wsdl_loc=None, pbm_wsdl_loc=None,
port=443, cacert=None, insecure=True, pool_size=10,
- connection_timeout=None):
+ connection_timeout=None, op_id_prefix='oslo.vmware'):
"""Initializes the API session with given parameters.
:param host: ESX/VC server IP address or host name
@@ -164,6 +164,7 @@ class VMwareAPISession(object):
connection pool
:param connection_timeout: Maximum time in seconds to wait for peer to
respond.
+ :param op_id_prefix: String prefix for the operation ID.
:raises: VimException, VimFaultException, VimAttributeException,
VimSessionOverLoadException
"""
@@ -184,6 +185,7 @@ class VMwareAPISession(object):
self._insecure = insecure
self._pool_size = pool_size
self._connection_timeout = connection_timeout
+ self._op_id_prefix = op_id_prefix
if create_session:
self._create_session()
@@ -202,7 +204,8 @@ class VMwareAPISession(object):
cacert=self._cacert,
insecure=self._insecure,
pool_maxsize=self._pool_size,
- connection_timeout=self._connection_timeout)
+ connection_timeout=self._connection_timeout,
+ op_id_prefix=self._op_id_prefix)
return self._vim
@property
@@ -215,7 +218,8 @@ class VMwareAPISession(object):
cacert=self._cacert,
insecure=self._insecure,
pool_maxsize=self._pool_size,
- connection_timeout=self._connection_timeout)
+ connection_timeout=self._connection_timeout,
+ op_id_prefix=self._op_id_prefix)
if self._session_id:
# To handle the case where pbm property is accessed after
# session creation. If pbm property is accessed before session
@@ -401,13 +405,15 @@ class VMwareAPISession(object):
:param task: managed object reference of the task
"""
- LOG.debug("Invoking VIM API to read info of task: %s.", task)
try:
+ # we poll tasks too often, so skip logging the opID as it generates
+ # too much noise in the logs
task_info = self.invoke_api(vim_util,
'get_object_property',
self.vim,
task,
- 'info')
+ 'info',
+ skip_op_id=True)
except exceptions.VimException:
with excutils.save_and_reraise_exception():
LOG.exception(_LE("Error occurred while reading info of "
diff --git a/oslo_vmware/pbm.py b/oslo_vmware/pbm.py
index b0c60af5..df5b33f8 100644
--- a/oslo_vmware/pbm.py
+++ b/oslo_vmware/pbm.py
@@ -42,7 +42,7 @@ class Pbm(service.Service):
def __init__(self, protocol='https', host='localhost', port=443,
wsdl_url=None, cacert=None, insecure=True, pool_maxsize=10,
- connection_timeout=None):
+ connection_timeout=None, op_id_prefix='oslo.vmware'):
"""Constructs a PBM service client object.
:param protocol: http or https
@@ -55,13 +55,15 @@ class Pbm(service.Service):
used only if cacert is not specified
:param pool_maxsize: Maximum number of connections in http
connection pool
+ :param op_id_prefix: String prefix for the operation ID.
:param connection_timeout: Maximum time in seconds to wait for peer to
respond.
"""
base_url = service.Service.build_base_url(protocol, host, port)
soap_url = base_url + '/pbm'
super(Pbm, self).__init__(wsdl_url, soap_url, cacert, insecure,
- pool_maxsize, connection_timeout)
+ pool_maxsize, connection_timeout,
+ op_id_prefix)
def set_soap_cookie(self, cookie):
"""Set the specified vCenter session cookie in the SOAP header
diff --git a/oslo_vmware/service.py b/oslo_vmware/service.py
index 477a6c3f..0a67cad2 100644
--- a/oslo_vmware/service.py
+++ b/oslo_vmware/service.py
@@ -22,6 +22,7 @@ import os
import netaddr
from oslo_utils import timeutils
+from oslo_utils import uuidutils
import requests
import six
import six.moves.http_client as httplib
@@ -29,6 +30,7 @@ import suds
from suds import cache
from suds import client
from suds import plugin
+import suds.sax.element as element
from suds import transport
from oslo_vmware._i18n import _
@@ -70,6 +72,7 @@ class ServiceMessagePlugin(plugin.MessagePlugin):
# 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., as opposed to test.
+
context.envelope.prune()
context.envelope.walk(self.add_attribute_for_value)
@@ -194,9 +197,10 @@ class Service(object):
def __init__(self, wsdl_url=None, soap_url=None,
cacert=None, insecure=True, pool_maxsize=10,
- connection_timeout=None):
+ connection_timeout=None, op_id_prefix='oslo.vmware'):
self.wsdl_url = wsdl_url
self.soap_url = soap_url
+ self.op_id_prefix = op_id_prefix
LOG.debug("Creating suds client with soap_url='%s' and wsdl_url='%s'",
self.soap_url, self.wsdl_url)
transport = RequestsTransport(cacert=cacert,
@@ -260,6 +264,17 @@ class Service(object):
fault_string,
details=details)
+ def _add_operation_id(self, op_id):
+ """Add operation ID for the next remote call to vCenter.
+
+ The operation ID is a random string which allows to correlate log
+ messages across different systems (OpenStack, vCenter, ESX).
+ """
+ headers = [element.Element('operationID').setText(op_id)]
+ if self.client.options.soapheaders is not None:
+ headers.append(self.client.options.soapheaders)
+ self.client.set_options(soapheaders=headers)
+
@property
def service_content(self):
if self._service_content is None:
@@ -297,6 +312,18 @@ class Service(object):
managed_object)
if managed_object is None:
return
+
+ skip_op_id = kwargs.pop('skip_op_id', False)
+ if not skip_op_id:
+ # Generate opID. It will appear in vCenter and ESX logs for
+ # this particular remote call.
+ op_id = '%s-%s' % (self.op_id_prefix,
+ uuidutils.generate_uuid())
+ LOG.debug('Invoking %s.%s with opID=%s',
+ managed_object._type,
+ attr_name,
+ op_id)
+ self._add_operation_id(op_id)
request = getattr(self.client.service, attr_name)
response = request(managed_object, **kwargs)
if (attr_name.lower() == 'retrievepropertiesex'):
diff --git a/oslo_vmware/tests/test_api.py b/oslo_vmware/tests/test_api.py
index fbc4c8de..9a002bd2 100644
--- a/oslo_vmware/tests/test_api.py
+++ b/oslo_vmware/tests/test_api.py
@@ -137,7 +137,8 @@ class VMwareAPISessionTest(base.TestCase):
cacert=self.cert_mock,
insecure=False,
pool_maxsize=VMwareAPISessionTest.POOL_SIZE,
- connection_timeout=None)
+ connection_timeout=None,
+ op_id_prefix='oslo.vmware')
@mock.patch.object(pbm, 'Pbm')
def test_pbm(self, pbm_mock):
@@ -412,7 +413,8 @@ class VMwareAPISessionTest(base.TestCase):
api_session.invoke_api.assert_called_with(vim_util,
'get_object_property',
api_session.vim, task,
- 'info')
+ 'info',
+ skip_op_id=True)
self.assertEqual(task_info_list_size,
api_session.invoke_api.call_count)
@@ -437,7 +439,8 @@ class VMwareAPISessionTest(base.TestCase):
api_session.invoke_api.assert_called_with(vim_util,
'get_object_property',
api_session.vim, task,
- 'info')
+ 'info',
+ skip_op_id=True)
self.assertEqual(task_info_list_size,
api_session.invoke_api.call_count)
@@ -453,7 +456,8 @@ class VMwareAPISessionTest(base.TestCase):
api_session.invoke_api.assert_called_once_with(vim_util,
'get_object_property',
api_session.vim, task,
- 'info')
+ 'info',
+ skip_op_id=True)
def test_wait_for_lease_ready(self):
api_session = self._create_api_session(True)
diff --git a/oslo_vmware/tests/test_service.py b/oslo_vmware/tests/test_service.py
index d11b38cc..1accb92f 100644
--- a/oslo_vmware/tests/test_service.py
+++ b/oslo_vmware/tests/test_service.py
@@ -374,6 +374,31 @@ class ServiceTest(base.TestCase):
svc_obj.client.options.transport.cookiejar = [cookie]
self.assertIsNone(svc_obj.get_http_cookie())
+ def test_add_operation_id(self):
+ def fake_set_options(*args, **kwargs):
+ headers = kwargs['soapheaders']
+ self.assertEqual(1, len(headers))
+ txt = headers[0].getText()
+ self.assertEqual('fira-12345', txt)
+
+ svc_obj = service.Service()
+ svc_obj.client.options.soapheaders = None
+ setattr(svc_obj.client, 'set_options', fake_set_options)
+ svc_obj._add_operation_id('fira-12345')
+
+ def test_add_operation_id_with_existing_header(self):
+ def fake_set_options(*args, **kwargs):
+ headers = kwargs['soapheaders']
+ self.assertEqual(2, len(headers))
+ txt = headers[0].getText()
+ self.assertEqual('fira-12345', txt)
+ self.assertEqual('vc-session-cookie', headers[1])
+
+ svc_obj = service.Service()
+ svc_obj.client.options.soapheaders = 'vc-session-cookie'
+ setattr(svc_obj.client, 'set_options', fake_set_options)
+ svc_obj._add_operation_id('fira-12345')
+
class MemoryCacheTest(base.TestCase):
"""Test class for MemoryCache."""
diff --git a/oslo_vmware/tests/test_vim_util.py b/oslo_vmware/tests/test_vim_util.py
index a542509b..8e43c955 100644
--- a/oslo_vmware/tests/test_vim_util.py
+++ b/oslo_vmware/tests/test_vim_util.py
@@ -222,7 +222,8 @@ class VimUtilTest(base.TestCase):
moref._type = "VirtualMachine"
retrieve_result = mock.Mock()
- def vim_RetrievePropertiesEx_side_effect(pc, specSet, options):
+ def vim_RetrievePropertiesEx_side_effect(pc, specSet, options,
+ skip_op_id=False):
self.assertTrue(pc is vim.service_content.propertyCollector)
self.assertEqual(1, options.maxObjects)
@@ -361,7 +362,7 @@ class VimUtilTest(base.TestCase):
val = vim_util.get_object_property(vim, moref, property_name)
self.assertEqual(prop.val, val)
get_object_properties.assert_called_once_with(
- vim, moref, [property_name])
+ vim, moref, [property_name], skip_op_id=False)
def test_find_extension(self):
vim = mock.Mock()
diff --git a/oslo_vmware/vim.py b/oslo_vmware/vim.py
index e8492463..a97ffc2c 100644
--- a/oslo_vmware/vim.py
+++ b/oslo_vmware/vim.py
@@ -21,7 +21,7 @@ class Vim(service.Service):
def __init__(self, protocol='https', host='localhost', port=None,
wsdl_url=None, cacert=None, insecure=True, pool_maxsize=10,
- connection_timeout=None):
+ connection_timeout=None, op_id_prefix='oslo.vmware'):
"""Constructs a VIM service client object.
:param protocol: http or https
@@ -36,6 +36,7 @@ class Vim(service.Service):
connection pool
:param connection_timeout: Maximum time in seconds to wait for peer to
respond.
+ :param op_id_prefix: String prefix for the operation ID.
:raises: VimException, VimFaultException, VimAttributeException,
VimSessionOverLoadException, VimConnectionException
"""
@@ -44,7 +45,8 @@ class Vim(service.Service):
if wsdl_url is None:
wsdl_url = soap_url + '/vimService.wsdl'
super(Vim, self).__init__(wsdl_url, soap_url, cacert, insecure,
- pool_maxsize, connection_timeout)
+ pool_maxsize, connection_timeout,
+ op_id_prefix)
def retrieve_service_content(self):
return self.RetrieveServiceContent(service.SERVICE_INSTANCE)
diff --git a/oslo_vmware/vim_util.py b/oslo_vmware/vim_util.py
index 511daf68..24d92861 100644
--- a/oslo_vmware/vim_util.py
+++ b/oslo_vmware/vim_util.py
@@ -285,13 +285,14 @@ def get_objects(vim, type_, max_objects, properties_to_collect=None,
options=options)
-def get_object_properties(vim, moref, properties_to_collect):
+def get_object_properties(vim, moref, properties_to_collect, skip_op_id=False):
"""Get properties of the given managed object.
:param vim: Vim object
:param moref: managed object reference
:param properties_to_collect: names of the managed object properties to be
collected
+ :param skip_op_id: whether to skip putting opID in the request
:returns: properties of the given managed object
:raises: VimException, VimFaultException, VimAttributeException,
VimSessionOverLoadException, VimConnectionException
@@ -317,7 +318,8 @@ def get_object_properties(vim, moref, properties_to_collect):
retrieve_result = vim.RetrievePropertiesEx(
vim.service_content.propertyCollector,
specSet=[property_filter_spec],
- options=options)
+ options=options,
+ skip_op_id=skip_op_id)
cancel_retrieval(vim, retrieve_result)
return retrieve_result.objects
@@ -422,17 +424,19 @@ class WithRetrieval(object):
self.vim, self.retrieve_result)
-def get_object_property(vim, moref, property_name):
+def get_object_property(vim, moref, property_name, skip_op_id=False):
"""Get property of the given managed object.
:param vim: Vim object
:param moref: managed object reference
:param property_name: name of the property to be retrieved
+ :param skip_op_id: whether to skip putting opID in the request
:returns: property of the given managed object
:raises: VimException, VimFaultException, VimAttributeException,
VimSessionOverLoadException, VimConnectionException
"""
- props = get_object_properties(vim, moref, [property_name])
+ props = get_object_properties(vim, moref, [property_name],
+ skip_op_id=skip_op_id)
prop_val = None
if props:
prop = None