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 exception.MaxRedirectsExceeded(redirects=MAX_REDIRECTS) loc = location.store_location conn_class = self._get_conn_class(loc) conn = conn_class(loc.netloc) conn.request(verb, loc.path, "", {}) resp = conn.getresponse() # Check for bad status codes if resp.status >= 400: reason = _("HTTP URL returned a %s status code.") % resp.status LOG.debug(reason) raise exception.BadStoreUri(loc.path, reason) location_header = resp.getheader("location") if location_header: if resp.status not in (301, 302): reason = (_("The HTTP URL attempted to redirect with an " "invalid %s status code.") % resp.status) LOG.debug(reason) raise exception.BadStoreUri(loc.path, 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 check_auth_params(): # Ensure that supplied credential parameters are as required for required in ('username', 'password', 'auth_url'): if required not in self.creds: raise exception.MissingCredentialError(required=required) # For v2.0 also check tenant is present if self.creds['auth_url'].rstrip('/').endswith('v2.0'): if 'tenant' not in self.creds: raise exception.MissingCredentialError(required='tenant') def _authenticate(auth_url): # If OS_AUTH_URL is missing a trailing slash add one if not auth_url.endswith('/'): auth_url += '/' token_url = urlparse.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) check_auth_params() auth_url = self.creds['auth_url'] for _ in range(self.MAX_REDIRECTS): try: _authenticate(auth_url) except exception.AuthorizationRedirect as e: # 2. Keystone may redirect us auth_url = e.url except exception.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 = urlparse.urljoin(auth_url, 'v2.0/') else: # If we sucessfully 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 exception.MaxRedirectsExceeded(redirects=self.MAX_REDIRECTS)
def wrapped(self, method, url, body, headers): for _ in xrange(MAX_REDIRECTS): try: return func(self, method, url, body, headers) except exception.RedirectException as redirect: if redirect.url is None: raise exception.InvalidRedirect() url = redirect.url raise exception.MaxRedirectsExceeded(redirects=MAX_REDIRECTS)
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 exception.MaxRedirectsExceeded(redirects=MAX_REDIRECTS) loc = location.store_location 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() raise exception.NotAuthenticated() if resp.status == httplib.NOT_FOUND: msg = 'VMware datastore could not find image at URI.' LOG.debug(msg) raise exception.NotFound(msg) reason = (_('HTTP request returned a %(status)s status code.') % { 'status': resp.status }) LOG.info(reason) raise exception.BadStoreUri(message=reason) 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 exception.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, 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 exception.MaxRedirectsExceeded(redirects=MAX_REDIRECTS) loc = location.store_location conn = self._get_http_conn(method, loc, headers) resp = conn.getresponse() if resp.status >= 400: if resp.status == httplib.NOT_FOUND: msg = _('VMware datastore could not find image at URI.') LOG.debug(msg) raise exception.NotFound(msg) msg = (_('HTTP URL %(url)s returned a %(status)s status code.') % { 'url': loc.get_uri(), 'status': resp.status }) LOG.debug(msg) raise exception.BadStoreUri(msg) location_header = resp.getheader('location') if location_header: if resp.status not in (301, 302): msg = (_("The HTTP URL %(path)s attempted to redirect " "with an invalid %(status)s status code.") % { 'path': loc.path, 'status': resp.status }) LOG.debug(msg) raise exception.BadStoreUri(msg) 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)