summaryrefslogtreecommitdiff
path: root/nova/virt/vmwareapi/session.py
diff options
context:
space:
mode:
Diffstat (limited to 'nova/virt/vmwareapi/session.py')
-rw-r--r--nova/virt/vmwareapi/session.py157
1 files changed, 157 insertions, 0 deletions
diff --git a/nova/virt/vmwareapi/session.py b/nova/virt/vmwareapi/session.py
new file mode 100644
index 0000000000..973db5760f
--- /dev/null
+++ b/nova/virt/vmwareapi/session.py
@@ -0,0 +1,157 @@
+# Copyright (c) 2013 Hewlett-Packard Development Company, L.P.
+# Copyright (c) 2012 VMware, Inc.
+# Copyright (c) 2011 Citrix Systems, Inc.
+# Copyright 2011 OpenStack Foundation
+#
+# 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.
+
+import abc
+import itertools
+
+from oslo_log import log as logging
+from oslo_utils import excutils
+from oslo_vmware import api
+from oslo_vmware import exceptions as vexc
+from oslo_vmware import vim
+from oslo_vmware.vim_util import get_moref_value
+
+import nova.conf
+
+CONF = nova.conf.CONF
+LOG = logging.getLogger(__name__)
+
+
+class StableMoRefProxy(metaclass=abc.ABCMeta):
+ """Abstract base class which acts as a proxy
+ for Managed-Object-References (MoRef).
+ Those references are usually "stable", meaning
+ they don't change over the life-time of the object.
+ But usually doesn't mean always. In that case, we
+ need to fetch the reference again via some search method,
+ which uses a guaranteed stable identifier (names, uuids, ...)
+ """
+
+ def __init__(self, ref):
+ self.moref = ref
+
+ @property
+ def __class__(self):
+ # Suds accesses the __class__.__name__ attribute
+ # of the object to determine the xml-tag of the object
+ # so we have to fake it
+ return self.moref.__class__
+
+ @abc.abstractmethod
+ def fetch_moref(self, session):
+ """Updates the moref field or raises
+ same exception the initial search would have
+ """
+
+ def __getattr__(self, name):
+ return getattr(self.moref, name)
+
+ def __repr__(self):
+ return "StableMoRefProxy({!r})".format(self.moref)
+
+
+class MoRef(StableMoRefProxy):
+ """MoRef takes a closure to resolve the reference of a managed object
+ That closure is called again, in case we get a ManagedObjectNotFound
+ exception on said reference.
+ """
+
+ def __init__(self, closure, ref=None):
+ self._closure = closure
+ ref = ref or self._closure()
+ super().__init__(ref)
+
+ def fetch_moref(self, _):
+ self.moref = self._closure()
+
+ def __repr__(self):
+ return "MoRef({!r})".format(self.moref)
+
+
+class VMwareAPISession(api.VMwareAPISession):
+ """Sets up a session with the VC/ESX host and handles all
+ the calls made to the host.
+ """
+
+ def __init__(self, host_ip=CONF.vmware.host_ip,
+ host_port=CONF.vmware.host_port,
+ username=CONF.vmware.host_username,
+ password=CONF.vmware.host_password,
+ retry_count=CONF.vmware.api_retry_count,
+ scheme="https",
+ cacert=CONF.vmware.ca_file,
+ insecure=CONF.vmware.insecure,
+ pool_size=CONF.vmware.connection_pool_size):
+ super(VMwareAPISession, self).__init__(
+ host=host_ip,
+ port=host_port,
+ server_username=username,
+ server_password=password,
+ api_retry_count=retry_count,
+ task_poll_interval=CONF.vmware.task_poll_interval,
+ scheme=scheme,
+ create_session=True,
+ cacert=cacert,
+ insecure=insecure,
+ pool_size=pool_size)
+
+ @staticmethod
+ def _is_vim_object(module):
+ """Check if the module is a VIM Object instance."""
+ return isinstance(module, vim.Vim)
+
+ def _call_method(self, module, method, *args, **kwargs):
+ """Calls a method within the module specified with
+ args provided.
+ """
+ try:
+ if not self._is_vim_object(module):
+ return self.invoke_api(module, method, self.vim, *args,
+ **kwargs)
+ return self.invoke_api(module, method, *args, **kwargs)
+ except vexc.ManagedObjectNotFoundException as monfe:
+ with excutils.save_and_reraise_exception() as ctxt:
+ moref = monfe.details.get("obj") if monfe.details else None
+ for arg in itertools.chain(args, kwargs.values()):
+ if not isinstance(arg, StableMoRefProxy):
+ continue
+ moref_arg = get_moref_value(arg.moref)
+ if moref != moref_arg:
+ continue
+ # We have found the argument with the moref
+ # causing the exception and we can try to recover it
+ arg.fetch_moref(self)
+ if not arg.moref:
+ # We didn't recover the reference
+ ctxt.reraise = True
+ break
+ moref_arg = get_moref_value(arg.moref)
+ if moref != moref_arg:
+ # We actually recovered, so do not raise `monfe`
+ LOG.info("Replaced moref %s with %s",
+ moref, moref_arg)
+ ctxt.reraise = False
+ # We only end up here when we have recovered a moref by changing
+ # the stored value of an argument to a different value,
+ # so let's try again (and recover again if it happens more than once)
+ return self._call_method(module, method, *args, **kwargs)
+
+ def _wait_for_task(self, task_ref):
+ """Return a Deferred that will give the result of the given task.
+ The task is polled until it completes.
+ """
+ return self.wait_for_task(task_ref)