def _create_connection(self, url, file_size, cookies): """Create HTTP connection to write to the file with given URL.""" 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) else: excep_msg = _("Invalid scheme: %s.") % scheme LOG.error(excep_msg) raise ValueError(excep_msg) conn.putrequest('PUT', path + '?' + query) conn.putheader('User-Agent', USER_AGENT) conn.putheader('Content-Length', file_size) conn.putheader('Cookie', self._build_vim_cookie_header(cookies)) conn.endheaders() 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.") % url LOG.exception(excep_msg) raise exceptions.VimConnectionException(excep_msg, excep)
def __init__(self, ref, name, capacity=None, freespace=None, type=None, datacenter=None): """Datastore object holds ref and name together for convenience. :param ref: a vSphere reference to a datastore :param name: vSphere unique name for this datastore :param capacity: (optional) capacity in bytes of this datastore :param freespace: (optional) free space in bytes of datastore :param type: (optional) datastore type :param datacenter: (optional) oslo.vmware Datacenter object """ if name is None: raise ValueError(_("Datastore name cannot be None")) if ref is None: raise ValueError(_("Datastore reference cannot be None")) if freespace is not None and capacity is None: raise ValueError(_("Invalid capacity")) if capacity is not None and freespace is not None: if capacity < freespace: raise ValueError(_("Capacity is smaller than free space")) self.ref = ref self.name = name self.capacity = capacity self.freespace = freespace self.type = type self.datacenter = datacenter
def connect(self, method, content_length, cookie): try: if self._scheme == 'http': conn = httplib.HTTPConnection(self._server) elif self._scheme == 'https': conn = httplib.HTTPSConnection(self._server) 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 _create_connection(self, url, file_size, cookies): """Create HTTP connection to write to the file with given URL.""" 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) else: excep_msg = _("Invalid scheme: %s.") % scheme LOG.error(excep_msg) raise ValueError(excep_msg) conn.putrequest('PUT', path + '?' + query) conn.putheader('User-Agent', USER_AGENT) conn.putheader('Content-Length', file_size) conn.putheader('Cookie', self._build_vim_cookie_header(cookies)) conn.endheaders() 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.") % url LOG.exception(excep_msg) raise exceptions.VimConnectionException(excep_msg, excep)
def __init__(self, ref, name): """Datacenter object holds ref and name together for convenience.""" if name is None: raise ValueError(_("Datacenter name cannot be None")) if ref is None: raise ValueError(_("Datacenter reference cannot be None")) self.ref = ref self.name = name
def __init__(self, fault_list, message, cause=None, details=None): super(VimFaultException, self).__init__(message, cause) if not isinstance(fault_list, list): raise ValueError(_("fault_list must be a list")) if details is not None and not isinstance(details, dict): raise ValueError(_("details must be a dict")) self.fault_list = fault_list self.details = details
def __init__(self, datastore_name, *paths): if datastore_name is None or datastore_name == '': raise ValueError(_("Datastore name cannot be empty")) self._datastore_name = datastore_name self._rel_path = '' if paths: if None in paths: raise ValueError(_("Path component cannot be None")) self._rel_path = posixpath.join(*paths)
def _inner(): """Task performing the image write operation. This method performs image data transfer through an update call. After the update, it waits until the image state becomes 'active', 'killed' or unknown. If the final state is not 'active' an instance of ImageTransferException is thrown. :raises: ImageTransferException """ LOG.debug( "Calling image service update on image: %(image)s " "with meta: %(meta)s", {"image": self._image_id, "meta": self._image_meta}, ) try: self._image_service.update(self._context, self._image_id, self._image_meta, data=self._input_file) self._running = True while self._running: LOG.debug("Retrieving status of image: %s.", self._image_id) image_meta = self._image_service.show(self._context, self._image_id) image_status = image_meta.get("status") if image_status == "active": self.stop() LOG.debug("Image: %s is now active.", self._image_id) self._done.send(True) elif image_status == "killed": self.stop() excep_msg = _("Image: %s is in killed state.") % self._image_id LOG.error(excep_msg) excep = exceptions.ImageTransferException(excep_msg) self._done.send_exception(excep) elif image_status in ["saving", "queued"]: LOG.debug( "Image: %(image)s is in %(state)s state; " "sleeping for %(sleep)d seconds.", {"image": self._image_id, "state": image_status, "sleep": IMAGE_SERVICE_POLL_INTERVAL}, ) greenthread.sleep(IMAGE_SERVICE_POLL_INTERVAL) else: self.stop() excep_msg = _("Image: %(image)s is in unknown " "state: %(state)s.") % { "image": self._image_id, "state": image_status, } LOG.error(excep_msg) excep = exceptions.ImageTransferException(excep_msg) self._done.send_exception(excep) except Exception as excep: self.stop() excep_msg = _("Error occurred while writing image: %s") % self._image_id LOG.exception(excep_msg) excep = exceptions.ImageTransferException(excep_msg, excep) self._done.send_exception(excep)
def _inner(): """Task performing the file read-write operation.""" self._running = True while self._running: try: data = self._input_file.read(rw_handles.READ_CHUNKSIZE) if not data: LOG.debug("File read-write task is done.") self.stop() self._done.send(True) self._output_file.write(data) # update lease progress if applicable if hasattr(self._input_file, "update_progress"): self._input_file.update_progress() if hasattr(self._output_file, "update_progress"): self._output_file.update_progress() greenthread.sleep(FILE_READ_WRITE_TASK_SLEEP_TIME) except Exception as excep: self.stop() excep_msg = _("Error occurred during file read-write " "task.") LOG.exception(excep_msg) excep = exceptions.ImageTransferException(excep_msg, excep) self._done.send_exception(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.warn(excep_msg, exc_info=True) 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) raise clazz(unicode(excep), excep.details) raise except exceptions.VimConnectionException: with excutils.save_and_reraise_exception(): # Re-create the session during connection exception. LOG.warn(_LW("Re-creating session due to connection " "problems while invoking method " "%(module)s.%(method)s."), { 'module': module, 'method': method }, exc_info=True) self._create_session()
def register_fault_class(name, exception): fault_class = _fault_classes_registry.get(name) if not issubclass(exception, VMwareDriverException): raise TypeError(_("exception should be a subclass of " "VMwareDriverException")) if fault_class: LOG.debug('Overriding exception for %s', name) _fault_classes_registry[name] = exception
def __init__(self, message, cause=None): Exception.__init__(self) if isinstance(message, list): # we need this to protect against developers using # this method like VimFaultException raise ValueError(_("exception_summary must not be a list")) self.msg = message self.cause = cause
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.warn(excep_msg, exc_info=True) 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) raise clazz(six.text_type(excep), excep.details) raise except exceptions.VimConnectionException: with excutils.save_and_reraise_exception(): # Re-create the session during connection exception. LOG.warn(_LW("Re-creating session due to connection " "problems while invoking method " "%(module)s.%(method)s."), {'module': module, 'method': method}, exc_info=True) self._create_session()
def _poll_lease(self, lease): """Poll the state of the given lease. When the lease is ready, the event (param done) is notified. In case of any error, appropriate exception is set in the event. :param lease: lease whose state is to be polled """ LOG.debug("Invoking VIM API to read state of lease: %s.", lease) try: state = self.invoke_api(vim_util, 'get_object_property', self.vim, lease, 'state') except exceptions.VimException: with excutils.save_and_reraise_exception(): LOG.exception(_LE("Error occurred while checking " "state of lease: %s."), lease) else: if state == 'ready': LOG.debug("Lease: %s is ready.", lease) raise loopingcall.LoopingCallDone() elif state == 'initializing': LOG.debug("Lease: %s is initializing.", lease) elif state == 'error': LOG.debug("Invoking VIM API to read lease: %s error.", lease) error_msg = self._get_error_message(lease) excep_msg = _("Lease: %(lease)s is in error state. Details: " "%(error_msg)s.") % {'lease': lease, 'error_msg': error_msg} LOG.error(excep_msg) raise exceptions.VimException(excep_msg) else: # unknown state excep_msg = _("Unknown state: %(state)s for lease: " "%(lease)s.") % {'state': state, 'lease': lease} LOG.error(excep_msg) raise exceptions.VimException(excep_msg)
def _poll_lease(self, lease): """Poll the state of the given lease. When the lease is ready, the event (param done) is notified. In case of any error, appropriate exception is set in the event. :param lease: lease whose state is to be polled """ LOG.debug("Invoking VIM API to read state of lease: %s.", lease) try: state = self.invoke_api(vim_util, 'get_object_property', self.vim, lease, 'state') except exceptions.VimException: with excutils.save_and_reraise_exception(): LOG.exception( _LE("Error occurred while checking " "state of lease: %s."), lease) else: if state == 'ready': LOG.debug("Lease: %s is ready.", lease) raise loopingcall.LoopingCallDone() elif state == 'initializing': LOG.debug("Lease: %s is initializing.", lease) elif state == 'error': LOG.debug("Invoking VIM API to read lease: %s error.", lease) error_msg = self._get_error_message(lease) excep_msg = _("Lease: %(lease)s is in error state. Details: " "%(error_msg)s.") % { 'lease': lease, 'error_msg': error_msg } LOG.error(excep_msg) raise exceptions.VimException(excep_msg) else: # unknown state excep_msg = _("Unknown state: %(state)s for lease: " "%(lease)s.") % { 'state': state, 'lease': lease } LOG.error(excep_msg) raise exceptions.VimException(excep_msg)
def parse(cls, datastore_path): """Constructs a DatastorePath object given a datastore path string.""" if not datastore_path: raise ValueError(_("Datastore path cannot be empty")) spl = datastore_path.split('[', 1)[1].split(']', 1) path = "" if len(spl) == 1: datastore_name = spl[0] else: datastore_name, path = spl return cls(datastore_name, path.strip())
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 (socket.error, httplib.NotConnected) 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 _find_vmdk_url(self, lease_info, host, port): """Find the URL corresponding to a VMDK file in lease info.""" url = None for deviceUrl in lease_info.deviceUrl: if deviceUrl.disk: url = self._fix_esx_url(deviceUrl.url, host, port) break if not url: excep_msg = _("Could not retrieve VMDK URL from lease info.") LOG.error(excep_msg) raise exceptions.VimException(excep_msg) LOG.debug("Found VMDK URL: %s from lease info.", url) return url
def _create_connection(self, session, url, vmdk_size): """Create HTTP connection to write to VMDK file.""" LOG.debug( "Creating HTTP connection to write to VMDK file with " "size = %(vmdk_size)d and URL = %(url)s.", { 'vmdk_size': vmdk_size, 'url': url }) cookies = session.vim.client.options.transport.cookiejar _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) else: excep_msg = _("Invalid scheme: %s.") % scheme LOG.error(excep_msg) raise ValueError(excep_msg) if query: path = path + '?' + query conn.putrequest('PUT', path) conn.putheader('User-Agent', USER_AGENT) conn.putheader('Content-Length', str(vmdk_size)) conn.putheader('Overwrite', 't') conn.putheader('Cookie', self._build_vim_cookie_header(cookies)) conn.putheader('Content-Type', 'binary/octet-stream') conn.endheaders() return conn except (httplib.InvalidURL, httplib.CannotSendRequest, httplib.CannotSendHeader) 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 _create_connection(self, session, url, vmdk_size): """Create HTTP connection to write to VMDK file.""" LOG.debug("Creating HTTP connection to write to VMDK file with " "size = %(vmdk_size)d and URL = %(url)s.", {'vmdk_size': vmdk_size, 'url': url}) cookies = session.vim.client.options.transport.cookiejar _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) else: excep_msg = _("Invalid scheme: %s.") % scheme LOG.error(excep_msg) raise ValueError(excep_msg) if query: path = path + '?' + query conn.putrequest('PUT', path) conn.putheader('User-Agent', USER_AGENT) conn.putheader('Content-Length', str(vmdk_size)) conn.putheader('Overwrite', 't') conn.putheader('Cookie', self._build_vim_cookie_header(cookies)) conn.putheader('Content-Type', 'binary/octet-stream') conn.endheaders() return conn except (httplib.InvalidURL, httplib.CannotSendRequest, httplib.CannotSendHeader) 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 build_url(self, scheme, server, rel_path, datacenter_name=None): """Constructs and returns a DatastoreURL. :param scheme: scheme of the URL (http, https). :param server: hostname or ip :param rel_path: relative path of the file on the datastore :param datacenter_name: (optional) datacenter name :return: a DatastoreURL object """ if self.datacenter is None and datacenter_name is None: raise ValueError(_("datacenter must be set to build url")) if datacenter_name is None: datacenter_name = self.datacenter.name return DatastoreURL(scheme, server, rel_path, datacenter_name, self.name)
def join(self, *paths): """Join one or more path components intelligently into a datastore path. If any component is an absolute path, all previous components are thrown away, and joining continues. The return value is the concatenation of the paths with exactly one slash ('/') inserted between components, unless p is empty. :return: A datastore path """ if paths: if None in paths: raise ValueError(_("Path component cannot be None")) return DatastorePath(self.datastore, self._rel_path, *paths) return self
def connect(self, method, content_length, cookie): try: if self._scheme == 'http': conn = httplib.HTTPConnection(self._server) elif self._scheme == 'https': conn = httplib.HTTPSConnection(self._server) 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 _create_connection(self, session, url): LOG.debug("Opening URL: %s for reading.", url) try: cookies = session.vim.client.options.transport.cookiejar headers = {'User-Agent': USER_AGENT, 'Cookie': self._build_vim_cookie_header(cookies)} request = urllib2.Request(url, None, headers) conn = urllib2.urlopen(request) return conn 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 opening URL: %s for " "reading.") % url LOG.exception(excep_msg) raise exceptions.VimException(excep_msg, excep)
def _create_connection(self, session, url): LOG.debug("Opening URL: %s for reading.", url) try: cookies = session.vim.client.options.transport.cookiejar headers = { 'User-Agent': USER_AGENT, 'Cookie': self._build_vim_cookie_header(cookies) } request = urllib2.Request(url, None, headers) conn = urllib2.urlopen(request) return conn 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 opening URL: %s for " "reading.") % url LOG.exception(excep_msg) raise exceptions.VimException(excep_msg, excep)
def read(self, chunk_size): """Read a chunk of data from the VMDK file. :param chunk_size: size of read chunk :returns: the data :raises: VimException """ try: data = self._file_handle.read(READ_CHUNKSIZE) self._bytes_read += len(data) return data 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 reading data from" " %s.") % self._url LOG.exception(excep_msg) raise exceptions.VimException(excep_msg, excep)
def _retrieve_properties_ex_fault_checker(response): """Checks the RetrievePropertiesEx API response for errors. Certain faults are sent in the SOAP body as a property of missingSet. This method raises VimFaultException when a fault is found in the response. :param response: response from RetrievePropertiesEx API call :raises: VimFaultException """ fault_list = [] details = {} if not response: # This is the case when the session has timed out. ESX SOAP # server sends an empty RetrievePropertiesExResponse. Normally # missingSet in the response objects has the specifics about # the error, but that's not the case with a timed out idle # session. It is as bad as a terminated session for we cannot # use the session. Therefore setting fault to NotAuthenticated # fault. LOG.debug("RetrievePropertiesEx API response is empty; setting " "fault to %s.", exceptions.NOT_AUTHENTICATED) fault_list = [exceptions.NOT_AUTHENTICATED] else: for obj_cont in response.objects: if hasattr(obj_cont, 'missingSet'): for missing_elem in obj_cont.missingSet: f_type = missing_elem.fault.fault f_name = f_type.__class__.__name__ fault_list.append(f_name) if f_name == exceptions.NO_PERMISSION: details['object'] = f_type.object.value details['privilegeId'] = f_type.privilegeId if fault_list: fault_string = _("Error occurred while calling " "RetrievePropertiesEx.") raise exceptions.VimFaultException(fault_list, fault_string, details=details)
def _poll_task(self, task): """Poll the given task until completion. If the task completes successfully, the method returns the task info using the input event (param done). In case of any error, appropriate exception is set in the event. :param task: managed object reference of the task """ LOG.debug("Invoking VIM API to read info of task: %s.", task) try: task_info = self.invoke_api(vim_util, 'get_object_property', self.vim, task, 'info') except exceptions.VimException: with excutils.save_and_reraise_exception(): LOG.exception(_LE("Error occurred while reading info of " "task: %s."), task) else: if task_info.state in ['queued', 'running']: if hasattr(task_info, 'progress'): LOG.debug("Task: %(task)s progress is %(progress)s%%.", {'task': task, 'progress': task_info.progress}) elif task_info.state == 'success': LOG.debug("Task: %s status is success.", task) raise loopingcall.LoopingCallDone(task_info) else: error_msg = six.text_type(task_info.error.localizedMessage) excep_msg = _("Task: %(task)s failed with error: " "%(error)s.") % {'task': task, 'error': error_msg} LOG.error(excep_msg) error = task_info.error name = error.fault.__class__.__name__ task_ex = exceptions.get_fault_class(name)(error_msg) raise task_ex
def test_vim_fault_exception(self): vfe = exceptions.VimFaultException([ValueError("example")], _("cause")) string = str(vfe) self.assertEqual("cause\nFaults: [ValueError('example',)]", string)
def test_exception_summary_string(self): e = exceptions.VimException(_("string"), ValueError("foo")) string = str(e) self.assertEqual("string\nCause: foo", string)
def _start_transfer(context, timeout_secs, read_file_handle, max_data_size, write_file_handle=None, image_service=None, image_id=None, image_meta=None): """Start the image transfer. The image reader reads the data from the image source and writes to the blocking queue. The image source is always a file handle (VmdkReadHandle or ImageReadHandle); therefore, a FileReadWriteTask is created for this transfer. The image writer reads the data from the blocking queue and writes it to the image destination. The image destination is either a file or VMDK in VMware datastore or an image in the image service. If the destination is a file or VMDK in VMware datastore, the method creates a FileReadWriteTask which reads from the blocking queue and writes to either FileWriteHandle or VmdkWriteHandle. In the case of image service as the destination, an instance of ImageWriter task is created which reads from the blocking queue and writes to the image service. :param context: write context needed for the image service :param timeout_secs: time in seconds to wait for the transfer to complete :param read_file_handle: handle to read data from :param max_data_size: maximum transfer size :param write_file_handle: handle to write data to; if this is None, then param image_service and param image_id should be set. :param image_service: image service handle :param image_id: ID of the image in the image service :param image_meta: image meta-data :raises: ImageTransferException, ValueError """ # Create the blocking queue blocking_queue = BlockingQueue(BLOCKING_QUEUE_SIZE, max_data_size) # Create the image reader reader = FileReadWriteTask(read_file_handle, blocking_queue) # Create the image writer if write_file_handle: # File or VMDK in VMware datastore is the image destination writer = FileReadWriteTask(blocking_queue, write_file_handle) elif image_service and image_id: # Image service image is the destination writer = ImageWriter(context, blocking_queue, image_service, image_id, image_meta) else: excep_msg = _("No image destination given.") LOG.error(excep_msg) raise ValueError(excep_msg) # Start the reader and writer LOG.debug("Starting image transfer with reader: %(reader)s and writer: " "%(writer)s", {'reader': reader, 'writer': writer}) reader.start() writer.start() timer = timeout.Timeout(timeout_secs) try: # Wait for the reader and writer to complete reader.wait() writer.wait() except (timeout.Timeout, exceptions.ImageTransferException) as excep: excep_msg = (_("Error occurred during image transfer with reader: " "%(reader)s and writer: %(writer)s") % {'reader': reader, 'writer': writer}) LOG.exception(excep_msg) reader.stop() writer.stop() if isinstance(excep, exceptions.ImageTransferException): raise raise exceptions.ImageTransferException(excep_msg, excep) finally: timer.cancel() read_file_handle.close() if write_file_handle: write_file_handle.close()
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_list.append(fault.get("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 _start_transfer( context, timeout_secs, read_file_handle, max_data_size, write_file_handle=None, image_service=None, image_id=None, image_meta=None, ): """Start the image transfer. The image reader reads the data from the image source and writes to the blocking queue. The image source is always a file handle (VmdkReadHandle or ImageReadHandle); therefore, a FileReadWriteTask is created for this transfer. The image writer reads the data from the blocking queue and writes it to the image destination. The image destination is either a file or VMDK in VMware datastore or an image in the image service. If the destination is a file or VMDK in VMware datastore, the method creates a FileReadWriteTask which reads from the blocking queue and writes to either FileWriteHandle or VmdkWriteHandle. In the case of image service as the destination, an instance of ImageWriter task is created which reads from the blocking queue and writes to the image service. :param context: write context needed for the image service :param timeout_secs: time in seconds to wait for the transfer to complete :param read_file_handle: handle to read data from :param max_data_size: maximum transfer size :param write_file_handle: handle to write data to; if this is None, then param image_service and param image_id should be set. :param image_service: image service handle :param image_id: ID of the image in the image service :param image_meta: image meta-data :raises: ImageTransferException, ValueError """ # Create the blocking queue blocking_queue = BlockingQueue(BLOCKING_QUEUE_SIZE, max_data_size) # Create the image reader reader = FileReadWriteTask(read_file_handle, blocking_queue) # Create the image writer if write_file_handle: # File or VMDK in VMware datastore is the image destination writer = FileReadWriteTask(blocking_queue, write_file_handle) elif image_service and image_id: # Image service image is the destination writer = ImageWriter(context, blocking_queue, image_service, image_id, image_meta) else: excep_msg = _("No image destination given.") LOG.error(excep_msg) raise ValueError(excep_msg) # Start the reader and writer LOG.debug( "Starting image transfer with reader: %(reader)s and writer: " "%(writer)s", {"reader": reader, "writer": writer}, ) reader.start() writer.start() timer = timeout.Timeout(timeout_secs) try: # Wait for the reader and writer to complete reader.wait() writer.wait() except (timeout.Timeout, exceptions.ImageTransferException) as excep: excep_msg = _("Error occurred during image transfer with reader: " "%(reader)s and writer: %(writer)s") % { "reader": reader, "writer": writer, } LOG.exception(excep_msg) reader.stop() writer.stop() if isinstance(excep, exceptions.ImageTransferException): raise raise exceptions.ImageTransferException(excep_msg, excep) finally: timer.cancel() read_file_handle.close() if write_file_handle: write_file_handle.close()
def _inner(): """Task performing the image write operation. This method performs image data transfer through an update call. After the update, it waits until the image state becomes 'active', 'killed' or unknown. If the final state is not 'active' an instance of ImageTransferException is thrown. :raises: ImageTransferException """ LOG.debug("Calling image service update on image: %(image)s " "with meta: %(meta)s", {'image': self._image_id, 'meta': self._image_meta}) try: self._image_service.update(self._context, self._image_id, self._image_meta, data=self._input_file) self._running = True while self._running: LOG.debug("Retrieving status of image: %s.", self._image_id) image_meta = self._image_service.show(self._context, self._image_id) image_status = image_meta.get('status') if image_status == 'active': self.stop() LOG.debug("Image: %s is now active.", self._image_id) self._done.send(True) elif image_status == 'killed': self.stop() excep_msg = (_("Image: %s is in killed state.") % self._image_id) LOG.error(excep_msg) excep = exceptions.ImageTransferException(excep_msg) self._done.send_exception(excep) elif image_status in ['saving', 'queued']: LOG.debug("Image: %(image)s is in %(state)s state; " "sleeping for %(sleep)d seconds.", {'image': self._image_id, 'state': image_status, 'sleep': IMAGE_SERVICE_POLL_INTERVAL}) greenthread.sleep(IMAGE_SERVICE_POLL_INTERVAL) else: self.stop() excep_msg = (_("Image: %(image)s is in unknown " "state: %(state)s.") % {'image': self._image_id, 'state': image_status}) LOG.error(excep_msg) excep = exceptions.ImageTransferException(excep_msg) self._done.send_exception(excep) except Exception as excep: self.stop() excep_msg = (_("Error occurred while writing image: %s") % self._image_id) LOG.exception(excep_msg) excep = exceptions.ImageTransferException(excep_msg, excep) self._done.send_exception(excep)