Coverage for nova/virt/vmwareapi/session.py: 0%
63 statements
« prev ^ index » next coverage.py v7.6.12, created at 2025-04-17 15:08 +0000
« prev ^ index » next coverage.py v7.6.12, created at 2025-04-17 15:08 +0000
1# Copyright (c) 2013 Hewlett-Packard Development Company, L.P.
2# Copyright (c) 2012 VMware, Inc.
3# Copyright (c) 2011 Citrix Systems, Inc.
4# Copyright 2011 OpenStack Foundation
5#
6# Licensed under the Apache License, Version 2.0 (the "License"); you may
7# not use this file except in compliance with the License. You may obtain
8# a copy of the License at
9#
10# http://www.apache.org/licenses/LICENSE-2.0
11#
12# Unless required by applicable law or agreed to in writing, software
13# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
14# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
15# License for the specific language governing permissions and limitations
16# under the License.
18import abc
19import itertools
21from oslo_log import log as logging
22from oslo_utils import excutils
23from oslo_vmware import api
24from oslo_vmware import exceptions as vexc
25from oslo_vmware import vim
26from oslo_vmware.vim_util import get_moref_value
28import nova.conf
30CONF = nova.conf.CONF
31LOG = logging.getLogger(__name__)
34class StableMoRefProxy(metaclass=abc.ABCMeta):
35 """Abstract base class which acts as a proxy
36 for Managed-Object-References (MoRef).
37 Those references are usually "stable", meaning
38 they don't change over the life-time of the object.
39 But usually doesn't mean always. In that case, we
40 need to fetch the reference again via some search method,
41 which uses a guaranteed stable identifier (names, uuids, ...)
42 """
44 def __init__(self, ref):
45 self.moref = ref
47 @property
48 def __class__(self):
49 # Suds accesses the __class__.__name__ attribute
50 # of the object to determine the xml-tag of the object
51 # so we have to fake it
52 return self.moref.__class__
54 @abc.abstractmethod
55 def fetch_moref(self, session):
56 """Updates the moref field or raises
57 same exception the initial search would have
58 """
60 def __getattr__(self, name):
61 return getattr(self.moref, name)
63 def __repr__(self):
64 return "StableMoRefProxy({!r})".format(self.moref)
67class MoRef(StableMoRefProxy):
68 """MoRef takes a closure to resolve the reference of a managed object
69 That closure is called again, in case we get a ManagedObjectNotFound
70 exception on said reference.
71 """
73 def __init__(self, closure, ref=None):
74 self._closure = closure
75 ref = ref or self._closure()
76 super().__init__(ref)
78 def fetch_moref(self, _):
79 self.moref = self._closure()
81 def __repr__(self):
82 return "MoRef({!r})".format(self.moref)
85class VMwareAPISession(api.VMwareAPISession):
86 """Sets up a session with the VC/ESX host and handles all
87 the calls made to the host.
88 """
90 def __init__(self, host_ip=CONF.vmware.host_ip,
91 host_port=CONF.vmware.host_port,
92 username=CONF.vmware.host_username,
93 password=CONF.vmware.host_password,
94 retry_count=CONF.vmware.api_retry_count,
95 scheme="https",
96 cacert=CONF.vmware.ca_file,
97 insecure=CONF.vmware.insecure,
98 pool_size=CONF.vmware.connection_pool_size):
99 super(VMwareAPISession, self).__init__(
100 host=host_ip,
101 port=host_port,
102 server_username=username,
103 server_password=password,
104 api_retry_count=retry_count,
105 task_poll_interval=CONF.vmware.task_poll_interval,
106 scheme=scheme,
107 create_session=True,
108 cacert=cacert,
109 insecure=insecure,
110 pool_size=pool_size)
112 @staticmethod
113 def _is_vim_object(module):
114 """Check if the module is a VIM Object instance."""
115 return isinstance(module, vim.Vim)
117 def _call_method(self, module, method, *args, **kwargs):
118 """Calls a method within the module specified with
119 args provided.
120 """
121 try:
122 if not self._is_vim_object(module):
123 return self.invoke_api(module, method, self.vim, *args,
124 **kwargs)
125 return self.invoke_api(module, method, *args, **kwargs)
126 except vexc.ManagedObjectNotFoundException as monfe:
127 with excutils.save_and_reraise_exception() as ctxt:
128 moref = monfe.details.get("obj") if monfe.details else None
129 for arg in itertools.chain(args, kwargs.values()):
130 if not isinstance(arg, StableMoRefProxy):
131 continue
132 moref_arg = get_moref_value(arg.moref)
133 if moref != moref_arg:
134 continue
135 # We have found the argument with the moref
136 # causing the exception and we can try to recover it
137 arg.fetch_moref(self)
138 if not arg.moref:
139 # We didn't recover the reference
140 ctxt.reraise = True
141 break
142 moref_arg = get_moref_value(arg.moref)
143 if moref != moref_arg:
144 # We actually recovered, so do not raise `monfe`
145 LOG.info("Replaced moref %s with %s",
146 moref, moref_arg)
147 ctxt.reraise = False
148 # We only end up here when we have recovered a moref by changing
149 # the stored value of an argument to a different value,
150 # so let's try again (and recover again if it happens more than once)
151 return self._call_method(module, method, *args, **kwargs)
153 def _wait_for_task(self, task_ref):
154 """Return a Deferred that will give the result of the given task.
155 The task is polled until it completes.
156 """
157 return self.wait_for_task(task_ref)