def _create_write_connection(self, method, url, file_size=None, cookies=None, overwrite=None, content_type=None, cacerts=False, ssl_thumbprint=None): """Create HTTP connection to write to VMDK file.""" LOG.debug("Creating HTTP connection to write to file with " "size = %(file_size)d and URL = %(url)s.", {'file_size': file_size, 'url': url}) try: conn = self._create_connection(url, method, cacerts, ssl_thumbprint) headers = {'User-Agent': USER_AGENT} if file_size: headers.update({'Content-Length': str(file_size)}) if overwrite: headers.update({'Overwrite': overwrite}) if cookies: headers.update({'Cookie': self._build_vim_cookie_header(cookies)}) if content_type: headers.update({'Content-Type': content_type}) for key, value in headers.items(): conn.putheader(key, value) conn.endheaders() return conn except requests.RequestException as excep: excep_msg = _("Error occurred while creating HTTP connection " "to write to VMDK file with URL = %s.") % url LOG.exception(excep_msg) raise exceptions.VimConnectionException(excep_msg, excep)
def connect(self, method, content_length, cookie): try: if self._scheme == 'http': conn = httplib.HTTPConnection(self._server) elif self._scheme == 'https': # TODO(browne): This needs to be changed to use python requests conn = httplib.HTTPSConnection(self._server) # nosec else: excep_msg = _("Invalid scheme: %s.") % self._scheme LOG.error(excep_msg) raise ValueError(excep_msg) conn.putrequest(method, '/folder/%s?%s' % (self.path, self._query)) conn.putheader('User-Agent', constants.USER_AGENT) conn.putheader('Content-Length', content_length) conn.putheader('Cookie', cookie) conn.endheaders() LOG.debug("Created HTTP connection to transfer the file with " "URL = %s.", str(self)) return conn except (httplib.InvalidURL, httplib.CannotSendRequest, httplib.CannotSendHeader) as excep: excep_msg = _("Error occurred while creating HTTP connection " "to write to file with URL = %s.") % str(self) LOG.exception(excep_msg) raise exceptions.VimConnectionException(excep_msg, excep)
def _invoke_api(module, method, *args, **kwargs): try: api_method = getattr(module, method) return api_method(*args, **kwargs) except exceptions.VimFaultException as excep: # If this is due to an inactive session, we should re-create # the session and retry. if exceptions.NOT_AUTHENTICATED in excep.fault_list: # The NotAuthenticated fault is set by the fault checker # due to an empty response. An empty response could be a # valid response; for e.g., response for the query to # return the VMs in an ESX server which has no VMs in it. # Also, the server responds with an empty response in the # case of an inactive session. Therefore, we need a way to # differentiate between these two cases. if self.is_current_session_active(): LOG.debug("Returning empty response for " "%(module)s.%(method)s invocation.", {'module': module, 'method': method}) return [] else: # empty response is due to an inactive session excep_msg = ( _("Current session: %(session)s is inactive; " "re-creating the session while invoking " "method %(module)s.%(method)s.") % {'session': _trunc_id(self._session_id), 'module': module, 'method': method}) LOG.debug(excep_msg) self._create_session() raise exceptions.VimConnectionException(excep_msg, excep) else: # no need to retry for other VIM faults like # InvalidArgument # Raise specific exceptions here if possible if excep.fault_list: LOG.debug("Fault list: %s", excep.fault_list) fault = excep.fault_list[0] clazz = exceptions.get_fault_class(fault) if clazz: raise clazz(six.text_type(excep), details=excep.details) raise except exceptions.VimConnectionException: with excutils.save_and_reraise_exception(): # Re-create the session during connection exception only # if the session has expired. Otherwise, it could be # a transient issue. if not self.is_current_session_active(): LOG.debug("Re-creating session due to connection " "problems while invoking method " "%(module)s.%(method)s.", {'module': module, 'method': method}) self._create_session()
def test_invoke_api_not_recreate_session(self): api_session = self._create_api_session(True) api_session._create_session = mock.Mock() vim_obj = api_session.vim vim_obj.SessionIsActive.return_value = True ret = mock.Mock() responses = [exceptions.VimConnectionException(None), ret] def api(*args, **kwargs): response = responses.pop(0) if isinstance(response, Exception): raise response return response module = mock.Mock() module.api = api with mock.patch.object(greenthread, 'sleep'): self.assertEqual(ret, api_session.invoke_api(module, 'api')) self.assertFalse(api_session._create_session.called)
def write(self, data): """Write data to the file. :param data: data to be written :raises: VimConnectionException, VimException """ try: self._file_handle.send(data) except requests.RequestException as excep: excep_msg = _("Connection error occurred while writing data to" " %s.") % self._url LOG.exception(excep_msg) raise exceptions.VimConnectionException(excep_msg, excep) except Exception as excep: # TODO(vbala) We need to catch and raise specific exceptions # related to connection problems, invalid request and invalid # arguments. excep_msg = _("Error occurred while writing data to" " %s.") % self._url LOG.exception(excep_msg) raise exceptions.VimException(excep_msg, excep)
def request_handler(managed_object, **kwargs): """Handler for vSphere API calls. Invokes the API and parses the response for fault checking and other errors. :param managed_object: managed object reference argument of the API call :param kwargs: keyword arguments of the API call :returns: response of the API call :raises: VimException, VimFaultException, VimAttributeException, VimSessionOverLoadException, VimConnectionException """ try: if isinstance(managed_object, str): # For strings, use string value for value and type # of the managed object. managed_object = vim_util.get_moref(managed_object, managed_object) if managed_object is None: return request = getattr(self.client.service, attr_name) response = request(managed_object, **kwargs) if (attr_name.lower() == 'retrievepropertiesex'): Service._retrieve_properties_ex_fault_checker(response) return response except exceptions.VimFaultException: # Catch the VimFaultException that is raised by the fault # check of the SOAP response. raise except suds.WebFault as excep: fault_string = None if excep.fault: fault_string = excep.fault.faultstring doc = excep.document detail = None if doc is not None: detail = doc.childAtPath('/detail') if not detail: # NOTE(arnaud): this is needed with VC 5.1 detail = doc.childAtPath('/Envelope/Body/Fault/detail') fault_list = [] details = {} if detail: for fault in detail.getChildren(): fault_type = fault.get('type') if fault_type.endswith(exceptions.SECURITY_ERROR): fault_type = exceptions.NOT_AUTHENTICATED fault_list.append(fault_type) for child in fault.getChildren(): details[child.name] = child.getText() raise exceptions.VimFaultException(fault_list, fault_string, excep, details) except AttributeError as excep: raise exceptions.VimAttributeException( _("No such SOAP method %s.") % attr_name, excep) except (httplib.CannotSendRequest, httplib.ResponseNotReady, httplib.CannotSendHeader) as excep: raise exceptions.VimSessionOverLoadException( _("httplib error in %s.") % attr_name, excep) except requests.RequestException as excep: raise exceptions.VimConnectionException( _("requests error in %s.") % attr_name, excep) except Exception as excep: # TODO(vbala) should catch specific exceptions and raise # appropriate VimExceptions. # Socket errors which need special handling; some of these # might be caused by server API call overload. if (six.text_type(excep).find(ADDRESS_IN_USE_ERROR) != -1 or six.text_type(excep).find(CONN_ABORT_ERROR)) != -1: raise exceptions.VimSessionOverLoadException( _("Socket error in %s.") % attr_name, excep) # Type error which needs special handling; it might be caused # by server API call overload. elif six.text_type(excep).find(RESP_NOT_XML_ERROR) != -1: raise exceptions.VimSessionOverLoadException( _("Type error in %s.") % attr_name, excep) else: raise exceptions.VimException( _("Exception in %s.") % attr_name, excep)
def fake_temp_session_exception(): raise vexc.VimConnectionException("it's a fake!", "Session Exception")
def _create_write_connection(self, url, file_size=None, cookies=None, overwrite=None, content_type=None, cacerts=False): """Create HTTP connection to write to VMDK file.""" LOG.debug( "Creating HTTP connection to write to file with " "size = %(file_size)d and URL = %(url)s.", { 'file_size': file_size, 'url': url }) _urlparse = urlparse.urlparse(url) scheme, netloc, path, params, query, fragment = _urlparse try: if scheme == 'http': conn = httplib.HTTPConnection(netloc) elif scheme == 'https': conn = httplib.HTTPSConnection(netloc) cert_reqs = None # cacerts can be either True or False or contain # actual certificates. If it is a boolean, then # we need to set cert_reqs and clear the cacerts if isinstance(cacerts, bool): if cacerts: cert_reqs = ssl.CERT_REQUIRED else: cert_reqs = ssl.CERT_NONE cacerts = None conn.set_cert(ca_certs=cacerts, cert_reqs=cert_reqs) else: excep_msg = _("Invalid scheme: %s.") % scheme LOG.error(excep_msg) raise ValueError(excep_msg) if query: path = path + '?' + query headers = {'User-Agent': USER_AGENT} if file_size: headers.update({'Content-Length': str(file_size)}) if overwrite: headers.update({'Overwrite': overwrite}) if cookies: headers.update( {'Cookie': self._build_vim_cookie_header(cookies)}) if content_type: headers.update({'Content-Type': content_type}) conn.putrequest('PUT', path) for key, value in six.iteritems(headers): conn.putheader(key, value) conn.endheaders() return conn except requests.RequestException as excep: excep_msg = _("Error occurred while creating HTTP connection " "to write to VMDK file with URL = %s.") % url LOG.exception(excep_msg) raise exceptions.VimConnectionException(excep_msg, excep)
def test_select_datastore(self, filter_datastores, get_profile_id): # Test with no hosts. size_bytes = units.Ki req = {self._ds_sel.SIZE_BYTES: size_bytes} self._vops.get_hosts.return_value = mock.Mock(objects=[]) self.assertEqual((), self._ds_sel.select_datastore(req)) self._vops.get_hosts.assert_called_once_with() # Test with single host with no valid datastores. host_1 = self._create_host('host-1') self._vops.get_hosts.return_value = mock.Mock( objects=[mock.Mock(obj=host_1)]) self._vops.continue_retrieval.return_value = None self._vops.get_dss_rp.side_effect = exceptions.VimException('error') self.assertEqual((), self._ds_sel.select_datastore(req)) self._vops.get_dss_rp.assert_called_once_with(host_1) # Test with three hosts and vCenter connection problem while fetching # datastores for the second host. self._vops.get_dss_rp.reset_mock() host_2 = self._create_host('host-2') host_3 = self._create_host('host-3') self._vops.get_hosts.return_value = mock.Mock( objects=[mock.Mock(obj=host_1), mock.Mock(obj=host_2), mock.Mock(obj=host_3)]) self._vops.get_dss_rp.side_effect = [ exceptions.VimException('no valid datastores'), exceptions.VimConnectionException('connection error')] self.assertRaises(exceptions.VimConnectionException, self._ds_sel.select_datastore, req) get_dss_rp_exp_calls = [mock.call(host_1), mock.call(host_2)] self.assertEqual(get_dss_rp_exp_calls, self._vops.get_dss_rp.call_args_list) # Modify previous case to return datastores for second and third host, # where none of them meet the requirements which include a storage # profile and affinity requirements. aff_ds_types = [ds_sel.DatastoreType.VMFS] req[ds_sel.DatastoreSelector.HARD_AFFINITY_DS_TYPE] = aff_ds_types ds_1a = mock.sentinel.ds_1a anti_affinity_ds = [ds_1a] req[ds_sel.DatastoreSelector.HARD_ANTI_AFFINITY_DS] = anti_affinity_ds profile_name = mock.sentinel.profile_name req[ds_sel.DatastoreSelector.PROFILE_NAME] = profile_name profile_id = mock.sentinel.profile_id get_profile_id.return_value = profile_id ds_2a = mock.sentinel.ds_2a ds_2b = mock.sentinel.ds_2b ds_3a = mock.sentinel.ds_3a self._vops.get_dss_rp.reset_mock() rp_2 = mock.sentinel.rp_2 rp_3 = mock.sentinel.rp_3 self._vops.get_dss_rp.side_effect = [ exceptions.VimException('no valid datastores'), ([ds_2a, ds_2b], rp_2), ([ds_3a], rp_3)] filter_datastores.return_value = [] self.assertEqual((), self._ds_sel.select_datastore(req)) get_profile_id.assert_called_once_with(profile_name) get_dss_rp_exp_calls.append(mock.call(host_3)) self.assertEqual(get_dss_rp_exp_calls, self._vops.get_dss_rp.call_args_list) filter_datastores_exp_calls = [ mock.call([ds_2a, ds_2b], size_bytes, profile_id, anti_affinity_ds, aff_ds_types), mock.call([ds_3a], size_bytes, profile_id, anti_affinity_ds, aff_ds_types)] self.assertEqual(filter_datastores_exp_calls, filter_datastores.call_args_list) # Modify previous case to have a non-empty summary list after filtering # with preferred utilization threshold unset. self._vops.get_dss_rp.side_effect = [ exceptions.VimException('no valid datastores'), ([ds_2a, ds_2b], rp_2), ([ds_3a], rp_3)] summary_2b = self._create_summary(ds_2b, free_space=0.5 * units.Mi, capacity=units.Mi) filter_datastores.side_effect = [[summary_2b]] self._vops.get_connected_hosts.return_value = [host_1] self.assertEqual((host_2, rp_2, summary_2b), self._ds_sel.select_datastore(req)) # Modify previous case to have a preferred utilization threshold # satsified by one datastore. self._vops.get_dss_rp.side_effect = [ exceptions.VimException('no valid datastores'), ([ds_2a, ds_2b], rp_2), ([ds_3a], rp_3)] req[ds_sel.DatastoreSelector.PREF_UTIL_THRESH] = 0.4 summary_3a = self._create_summary(ds_3a, free_space=0.7 * units.Mi, capacity=units.Mi) filter_datastores.side_effect = [[summary_2b], [summary_3a]] self.assertEqual((host_3, rp_3, summary_3a), self._ds_sel.select_datastore(req)) # Modify previous case to have a preferred utilization threshold # which cannot be satisfied. self._vops.get_dss_rp.side_effect = [ exceptions.VimException('no valid datastores'), ([ds_2a, ds_2b], rp_2), ([ds_3a], rp_3)] filter_datastores.side_effect = [[summary_2b], [summary_3a]] req[ds_sel.DatastoreSelector.PREF_UTIL_THRESH] = 0.2 summary_2b.freeSpace = 0.75 * units.Mi self.assertEqual((host_2, rp_2, summary_2b), self._ds_sel.select_datastore(req)) # Clear side effects. self._vops.get_dss_rp.side_effect = None