def _query(self, location, verb): redirects_followed = 0 while redirects_followed < MAX_REDIRECTS: loc = location.store_location conn = self._get_response(loc, verb) # NOTE(sigmavirus24): If it was generally successful, break early if conn.status_code < 300: break self._check_store_uri(conn, loc) redirects_followed += 1 # NOTE(sigmavirus24): Close the response so we don't leak sockets conn.close() location = self._new_location(location, conn.headers['location']) else: reason = (_("The HTTP URL exceeded %s maximum " "redirects.") % MAX_REDIRECTS) LOG.debug(reason) raise exceptions.MaxRedirectsExceeded(message=reason) resp = conn.raw content_length = int(resp.getheader('content-length', 0)) return (conn, resp, content_length)
def _query(self, location, method, depth=0): if depth > MAX_REDIRECTS: msg = ("The HTTP URL exceeded %(max_redirects)s maximum " "redirects.", { 'max_redirects': MAX_REDIRECTS }) LOG.debug(msg) raise exceptions.MaxRedirectsExceeded(redirects=MAX_REDIRECTS) loc = location.store_location # NOTE(arnaud): use a decorator when the config is not tied to self for i in range(self.api_retry_count + 1): cookie = self._build_vim_cookie_header( self._session.vim.client.options.transport.cookiejar) headers = {'Cookie': cookie} try: conn = self._get_http_conn(method, loc, headers) resp = conn.getresponse() except Exception: with excutils.save_and_reraise_exception(): LOG.exception( _LE('Failed to access image %(image)s ' 'content.') % {'image': location.image_id}) if resp.status >= 400: if resp.status == httplib.UNAUTHORIZED: self._create_session() continue if resp.status == httplib.NOT_FOUND: reason = _('VMware datastore could not find image at URI.') LOG.info(reason) raise exceptions.NotFound(message=reason) msg = ('HTTP request returned a %(status)s status code.' % { 'status': resp.status }) LOG.debug(msg) raise exceptions.BadStoreUri(msg) break location_header = resp.getheader('location') if location_header: if resp.status not in (301, 302): reason = (_("The HTTP URL %(path)s attempted to redirect " "with an invalid %(status)s status code.") % { 'path': loc.path, 'status': resp.status }) LOG.info(reason) raise exceptions.BadStoreUri(message=reason) location_class = glance_store.location.Location new_loc = location_class(location.store_name, location.store_location.__class__, uri=location_header, image_id=location.image_id, store_specs=location.store_specs) return self._query(new_loc, method, depth + 1) content_length = int(resp.getheader('content-length', 0)) return (conn, resp, content_length)
def _query(self, location, verb, depth=0): if depth > MAX_REDIRECTS: reason = (_("The HTTP URL exceeded %s maximum " "redirects.") % MAX_REDIRECTS) LOG.debug(reason) raise exceptions.MaxRedirectsExceeded(message=reason) loc = location.store_location conn_class = self._get_conn_class(loc) conn = conn_class(loc.netloc) hearders = {} if loc.token: hearders.setdefault('x-auth-token', loc.token) verb = 'GET' conn.request(verb, loc.path, "", hearders) resp = conn.getresponse() try: size = jsonutils.loads(resp.read())['size'] except Exception: size = 0 raise exception.BadStoreUri(loc.path, reason) return (conn, resp, size) conn.request(verb, loc.path, "", {}) resp = conn.getresponse() # Check for bad status codes if resp.status >= 400: if resp.status == httplib.NOT_FOUND: reason = _("HTTP datastore could not find image at URI.") LOG.debug(reason) raise exceptions.NotFound(message=reason) reason = (_("HTTP URL %(url)s returned a " "%(status)s status code.") % dict(url=loc.path, status=resp.status)) LOG.debug(reason) raise exceptions.BadStoreUri(message=reason) location_header = resp.getheader("location") if location_header: if resp.status not in (301, 302): reason = (_("The HTTP URL %(url)s attempted to redirect " "with an invalid %(status)s status code.") % dict(url=loc.path, status=resp.status)) LOG.info(reason) raise exceptions.BadStoreUri(message=reason) location_class = glance_store.location.Location new_loc = location_class(location.store_name, location.store_location.__class__, uri=location_header, image_id=location.image_id, store_specs=location.store_specs) return self._query(new_loc, verb, depth + 1) content_length = int(resp.getheader('content-length', 0)) return (conn, resp, content_length)
def authenticate(self): """Authenticate with the Keystone service. There are a few scenarios to consider here: 1. Which version of Keystone are we using? v1 which uses headers to pass the credentials, or v2 which uses a JSON encoded request body? 2. Keystone may respond back with a redirection using a 305 status code. 3. We may attempt a v1 auth when v2 is what's called for. In this case, we rewrite the url to contain /v2.0/ and retry using the v2 protocol. """ def _authenticate(auth_url): # If OS_AUTH_URL is missing a trailing slash add one if not auth_url.endswith('/'): auth_url += '/' token_url = urllib.parse.urljoin(auth_url, "tokens") # 1. Check Keystone version is_v2 = auth_url.rstrip('/').endswith('v2.0') if is_v2: self._v2_auth(token_url) else: self._v1_auth(token_url) self.check_auth_params() auth_url = self.creds['auth_url'] for _ in range(self.MAX_REDIRECTS): try: _authenticate(auth_url) except exceptions.AuthorizationRedirect as e: # 2. Keystone may redirect us auth_url = e.url except exceptions.AuthorizationFailure: # 3. In some configurations nova makes redirection to # v2.0 keystone endpoint. Also, new location does not # contain real endpoint, only hostname and port. if 'v2.0' not in auth_url: auth_url = urllib.parse.urljoin(auth_url, 'v2.0/') else: # If we successfully auth'd, then memorize the correct auth_url # for future use. self.creds['auth_url'] = auth_url break else: # Guard against a redirection loop raise exceptions.MaxRedirectsExceeded(redirects=self.MAX_REDIRECTS)
def _query(self, location, method, headers, depth=0): if depth > MAX_REDIRECTS: msg = ("The HTTP URL exceeded %(max_redirects)s maximum " "redirects." % { 'max_redirects': MAX_REDIRECTS }) LOG.debug(msg) raise exceptions.MaxRedirectsExceeded(redirects=MAX_REDIRECTS) loc = location.store_location try: conn = self._get_http_conn(method, loc, headers) resp = conn.getresponse() except Exception: with excutils.save_and_reraise_exception(): LOG.exception( _('Failed to access image %(image)s content.') % {'image': location.image_id}) if resp.status >= 400: if resp.status == httplib.NOT_FOUND: reason = _('VMware datastore could not find image at URI.') LOG.info(reason) raise exceptions.NotFound(message=reason) msg = ('HTTP request returned a %(status)s status code.' % { 'status': resp.status }) LOG.debug(msg) raise exceptions.BadStoreUri(msg) location_header = resp.getheader('location') if location_header: if resp.status not in (301, 302): reason = (_("The HTTP URL %(path)s attempted to redirect " "with an invalid %(status)s status code.") % { 'path': loc.path, 'status': resp.status }) LOG.info(reason) raise exceptions.BadStoreUri(message=reason) location_class = glance_store.location.Location new_loc = location_class(location.store_name, location.store_location.__class__, uri=location_header, image_id=location.image_id, store_specs=location.store_specs) return self._query(new_loc, method, depth + 1) content_length = int(resp.getheader('content-length', 0)) return (conn, resp, content_length)
def _query(self, location, method): session = new_session(self.api_insecure, self.ca_file) loc = location.store_location redirects_followed = 0 # TODO(sabari): The redirect logic was added to handle cases when the # backend redirects http url's to https. But the store never makes a # http request and hence this can be safely removed. while redirects_followed < MAX_REDIRECTS: conn, resp = self._retry_request(session, method, location) # NOTE(sigmavirus24): _retry_request handles 4xx and 5xx errors so # if the response is not a redirect, we can return early. if not conn.is_redirect: break redirects_followed += 1 location_header = conn.headers.get('location') if location_header: if resp.status not in (301, 302): reason = (_("The HTTP URL %(path)s attempted to redirect " "with an invalid %(status)s status code.") % { 'path': loc.path, 'status': resp.status }) LOG.info(reason) raise exceptions.BadStoreUri(message=reason) conn.close() location = self._new_location(location, location_header) else: # NOTE(sigmavirus24): We exceeded the maximum number of redirects msg = ("The HTTP URL exceeded %(max_redirects)s maximum " "redirects.", { 'max_redirects': MAX_REDIRECTS }) LOG.debug(msg) raise exceptions.MaxRedirectsExceeded(redirects=MAX_REDIRECTS) content_length = int(resp.getheader('content-length', 0)) return (conn, resp, content_length)