def _do_http_request(self, retry, machines_cache, request_executor, method, path, fields=None, **kwargs): some_request_failed = False for i, base_uri in enumerate(machines_cache): if i > 0: logger.info("Retrying on %s", base_uri) try: response = request_executor(method, base_uri + path, fields=fields, **kwargs) response.data.decode('utf-8') self._check_cluster_id(response) if some_request_failed: self.set_base_uri(base_uri) self._refresh_machines_cache() return response except (HTTPError, HTTPException, socket.error, socket.timeout) as e: self.http.clear() # switch to the next etcd node because we don't know exactly what happened, # whether the key didn't received an update or there is a network problem. if not retry and i + 1 < len(machines_cache): self.set_base_uri(machines_cache[i + 1]) if (isinstance(fields, dict) and fields.get("wait") == "true" and isinstance(e, (ReadTimeoutError, ProtocolError))): logger.debug("Watch timed out.") raise etcd.EtcdWatchTimedOut("Watch timed out: {0}".format(e), cause=e) logger.error("Request to server %s failed: %r", base_uri, e) logger.info("Reconnection allowed, looking for another server.") if not retry: raise etcd.EtcdException('{0} {1} request failed'.format(method, path)) some_request_failed = True raise etcd.EtcdConnectionFailed('No more machines in the cluster')
def _do_http_request(self, request_executor, method, url, fields=None, **kwargs): try: response = request_executor(method, url, fields=fields, **kwargs) response.data.decode('utf-8') self._check_cluster_id(response) except (HTTPError, HTTPException, socket.error, socket.timeout) as e: if (isinstance(fields, dict) and fields.get("wait") == "true" and isinstance(e, (ReadTimeoutError, ProtocolError))): logger.debug("Watch timed out.") # switch to the next etcd node because we don't know exactly what happened, # whether the key didn't received an update or there is a network problem. self._machines_cache.insert(0, self._base_uri) self._base_uri = self._next_server() raise etcd.EtcdWatchTimedOut("Watch timed out: {0}".format(e), cause=e) logger.error("Request to server %s failed: %r", self._base_uri, e) logger.info("Reconnection allowed, looking for another server.") self._base_uri = self._next_server(cause=e) response = False return response
def _do_http_request(self, request_executor, method, url, fields=None, **kwargs): try: response = request_executor(method, url, fields=fields, **kwargs) response.data.decode('utf-8') self._check_cluster_id(response) except (HTTPError, HTTPException, socket.error, socket.timeout) as e: if (isinstance(fields, dict) and fields.get("wait") == "true" and isinstance(e, ReadTimeoutError)): logger.debug("Watch timed out.") raise etcd.EtcdWatchTimedOut("Watch timed out: {0}".format(e), cause=e) logger.error("Request to server %s failed: %r", self._base_uri, e) logger.info("Reconnection allowed, looking for another server.") self._base_uri = self._next_server(cause=e) response = False return response
def wrapper(self, path, method, params=None, timeout=None): response = False if timeout is None: timeout = self.read_timeout if timeout == 0: timeout = None if not path.startswith('/'): raise ValueError('Path does not start with /') while not response: some_request_failed = False try: response = payload(self, path, method, params=params, timeout=timeout) # Check the cluster ID hasn't changed under us. We use # preload_content=False above so we can read the headers # before we wait for the content of a watch. self._check_cluster_id(response, path) # Now force the data to be preloaded in order to trigger any # IO-related errors in this method rather than when we try to # access it later. _ = response.data # urllib3 doesn't wrap all httplib exceptions and earlier versions # don't wrap socket errors either. except (HTTPError, HTTPException, socket.error) as e: if (isinstance(params, dict) and params.get("wait") == "true" and isinstance(e, ReadTimeoutError)): _log.debug("Watch timed out.") raise etcd.EtcdWatchTimedOut( "Watch timed out: %r" % e, cause=e ) _log.error("Request to server %s failed: %r", self._base_uri, e) if self._allow_reconnect: _log.info("Reconnection allowed, looking for another " "server.") # _next_server() raises EtcdException if there are no # machines left to try, breaking out of the loop. self._base_uri = self._next_server(cause=e) some_request_failed = True # if exception is raised on _ = response.data # the condition for while loop will be False # but we should retry response = False else: _log.debug("Reconnection disabled, giving up.") raise etcd.EtcdConnectionFailed( "Connection to etcd failed due to %r" % e, cause=e ) except etcd.EtcdClusterIdChanged as e: _log.warning(e) raise except: _log.debug("Unexpected request failure, re-raising.") raise if some_request_failed: if not self._use_proxies: # The cluster may have changed since last invocation self._machines_cache = self.machines self._machines_cache.remove(self._base_uri) return self._handle_server_response(response)
def api_execute(self, path, method, params=None, timeout=None): """ Executes the query. """ some_request_failed = False response = False if timeout is None: timeout = self.read_timeout if timeout == 0: timeout = None if not path.startswith('/'): raise ValueError('Path does not start with /') while not response: try: url = self._base_uri + path if (method == self._MGET) or (method == self._MDELETE): response = self.http.request(method, url, timeout=timeout, fields=params, redirect=self.allow_redirect, preload_content=False) elif (method == self._MPUT) or (method == self._MPOST): response = self.http.request_encode_body( method, url, fields=params, timeout=timeout, encode_multipart=False, redirect=self.allow_redirect, preload_content=False) else: raise etcd.EtcdException( 'HTTP method {} not supported'.format(method)) # Check the cluster ID hasn't changed under us. We use # preload_content=False above so we can read the headers # before we wait for the content of a watch. self._check_cluster_id(response) # Now force the data to be preloaded in order to trigger any # IO-related errors in this method rather than when we try to # access it later. _ = response.data # urllib3 doesn't wrap all httplib exceptions and earlier versions # don't wrap socket errors either. except (urllib3.exceptions.HTTPError, HTTPException, socket.error) as e: if (params.get("wait") == "true" and isinstance( e, urllib3.exceptions.ReadTimeoutError)): _log.debug("Watch timed out.") raise etcd.EtcdWatchTimedOut("Watch timed out: %r" % e, cause=e) _log.error("Request to server %s failed: %r", self._base_uri, e) if self._allow_reconnect: _log.info("Reconnection allowed, looking for another " "server.") # _next_server() raises EtcdException if there are no # machines left to try, breaking out of the loop. self._base_uri = self._next_server(cause=e) some_request_failed = True else: _log.debug("Reconnection disabled, giving up.") raise etcd.EtcdConnectionFailed( "Connection to etcd failed due to %r" % e, cause=e) except: _log.exception("Unexpected request failure, re-raising.") raise if some_request_failed: if not self._use_proxies: # The cluster may have changed since last invocation self._machines_cache = self.machines self._machines_cache.remove(self._base_uri) return self._handle_server_response(response)