def _v1_auth(self, token_url): creds = self.creds headers = {} headers['X-Auth-User'] = creds['username'] headers['X-Auth-Key'] = creds['password'] tenant = creds.get('tenant') if tenant: headers['X-Auth-Tenant'] = tenant resp, resp_body = self._do_request(token_url, 'GET', headers=headers) if resp.status in (200, 204): try: self.management_url = resp['x-server-management-url'] self.auth_token = resp['x-auth-token'] except KeyError: raise exception.AuthorizationFailure() elif resp.status == 305: raise exception.RedirectException(resp['location']) elif resp.status == 400: raise exception.AuthBadRequest() elif resp.status == 401: raise exception.NotAuthorized() elif resp.status == 404: raise exception.AuthUrlNotFound(url=token_url) else: raise Exception(_('Unexpected response: %s' % resp.status))
def _v3_auth(self, token_url): creds = { "auth": { "identity": { "methods": ["password"], "password": { "user": { "name": self.creds['username'], "domain": { "id": self.creds['user_domain_id'] }, "password": self.creds['password'] } } }, "scope": { "project": { "name": self.creds['project'], "domain": { "id": self.creds['project_domain_id'] } } } } } headers = {'Content-Type': 'application/json'} req_body = jsonutils.dumps(creds) resp, resp_body = self._do_request(token_url, 'POST', headers=headers, body=req_body) resp_body = jsonutils.loads(resp_body) if resp.status == 201: resp_auth = resp['x-subject-token'] creds_region = self.creds.get('region') if self.configure_via_auth: endpoint = get_endpoint(resp_body['token']['catalog'], endpoint_region=creds_region) self.management_url = endpoint self.auth_token = resp_auth elif resp.status == 305: raise exception.RedirectException(resp['location']) elif resp.status == 400: raise exception.AuthBadRequest(url=token_url) elif resp.status == 401: raise Exception(_('Unexpected response: %s') % resp.status)
def _v2_auth(self, token_url): creds = self.creds creds = { "auth": { "tenantName": creds['tenant'], "passwordCredentials": { "username": creds['username'], "password": creds['password'] } } } headers = {} headers['Content-Type'] = 'application/json' req_body = json.dumps(creds) resp, resp_body = self._do_request(token_url, 'POST', headers=headers, body=req_body) if resp.status == 200: resp_auth = json.loads(resp_body)['access'] # FIXME(sirp): for now just using the first endpoint we get back # from the service catalog for glance, and using the public url. for service in resp_auth['serviceCatalog']: if service['type'] == 'image': glance_endpoint = service['endpoints'][0]['publicURL'] break else: raise exception.NoServiceEndpoint() self.management_url = glance_endpoint self.auth_token = resp_auth['token']['id'] elif resp.status == 305: raise exception.RedirectException(resp['location']) elif resp.status == 400: raise exception.AuthBadRequest(url=token_url) elif resp.status == 401: raise exception.NotAuthorized() elif resp.status == 404: raise exception.AuthUrlNotFound(url=token_url) else: raise Exception(_('Unexpected response: %s') % resp.status)
def _v2_auth(self, token_url): creds = self.creds creds = { "auth": { "tenantName": creds['tenant'], "passwordCredentials": { "username": creds['username'], "password": creds['password'] } } } headers = {} headers['Content-Type'] = 'application/json' req_body = jsonutils.dumps(creds) resp, resp_body = self._do_request(token_url, 'POST', headers=headers, body=req_body) if resp.status == 200: resp_auth = jsonutils.loads(resp_body)['access'] creds_region = self.creds.get('region') if self.configure_via_auth: endpoint = get_endpoint(resp_auth['serviceCatalog'], endpoint_region=creds_region) self.management_url = endpoint self.auth_token = resp_auth['token']['id'] elif resp.status == 305: raise exception.RedirectException(resp['location']) elif resp.status == 400: raise exception.AuthBadRequest(url=token_url) elif resp.status == 401: raise exception.NotAuthenticated() elif resp.status == 404: raise exception.AuthUrlNotFound(url=token_url) else: raise Exception(_('Unexpected response: %s') % resp.status)
def _do_request(self, method, url, body, headers): """ Connects to the server and issues a request. Handles converting any returned HTTP error status codes to OpenStack/Glance exceptions and closing the server connection. Returns the result data, or raises an appropriate exception. :param method: HTTP method ("GET", "POST", "PUT", etc...) :param url: urlparse.ParsedResult object with URL information :param body: data to send (as string, filelike or iterable), or None (default) :param headers: mapping of key/value pairs to add as headers :note If the body param has a read attribute, and method is either POST or PUT, this method will automatically conduct a chunked-transfer encoding and use the body as a file object or iterable, transferring chunks of data using the connection's send() method. This allows large objects to be transferred efficiently without buffering the entire body in memory. """ if url.query: path = url.path + "?" + url.query else: path = url.path try: connection_type = self.get_connection_type() headers = self._encode_headers(headers or {}) if 'x-auth-token' not in headers and self.auth_tok: headers['x-auth-token'] = self.auth_tok c = connection_type(url.hostname, url.port, **self.connect_kwargs) def _pushing(method): return method.lower() in ('post', 'put') def _simple(body): return body is None or isinstance(body, six.string_types) def _filelike(body): return hasattr(body, 'read') def _sendbody(connection, iter): connection.endheaders() for sent in iter: # iterator has done the heavy lifting pass def _chunkbody(connection, iter): connection.putheader('Transfer-Encoding', 'chunked') connection.endheaders() for chunk in iter: connection.send('%x\r\n%s\r\n' % (len(chunk), chunk)) connection.send('0\r\n\r\n') # Do a simple request or a chunked request, depending # on whether the body param is file-like or iterable and # the method is PUT or POST # if not _pushing(method) or _simple(body): # Simple request... c.request(method, path, body, headers) elif _filelike(body) or self._iterable(body): c.putrequest(method, path) use_sendfile = self._sendable(body) # According to HTTP/1.1, Content-Length and Transfer-Encoding # conflict. for header, value in headers.items(): if use_sendfile or header.lower() != 'content-length': c.putheader(header, str(value)) iter = self.image_iterator(c, headers, body) if use_sendfile: # send actual file without copying into userspace _sendbody(c, iter) else: # otherwise iterate and chunk _chunkbody(c, iter) else: raise TypeError('Unsupported image type: %s' % body.__class__) res = c.getresponse() def _retry(res): return res.getheader('Retry-After') status_code = self.get_status_code(res) if status_code in self.OK_RESPONSE_CODES: return res elif status_code in self.REDIRECT_RESPONSE_CODES: raise exception.RedirectException(res.getheader('Location')) elif status_code == httplib.UNAUTHORIZED: raise exception.NotAuthenticated(res.read()) elif status_code == httplib.FORBIDDEN: raise exception.Forbidden(res.read()) elif status_code == httplib.NOT_FOUND: raise exception.NotFound(res.read()) elif status_code == httplib.CONFLICT: raise exception.Duplicate(res.read()) elif status_code == httplib.BAD_REQUEST: raise exception.Invalid(res.read()) elif status_code == httplib.MULTIPLE_CHOICES: raise exception.MultipleChoices(body=res.read()) elif status_code == httplib.REQUEST_ENTITY_TOO_LARGE: raise exception.LimitExceeded(retry=_retry(res), body=res.read()) elif status_code == httplib.INTERNAL_SERVER_ERROR: raise exception.ServerError() elif status_code == httplib.SERVICE_UNAVAILABLE: raise exception.ServiceUnavailable(retry=_retry(res)) else: raise exception.UnexpectedStatus(status=status_code, body=res.read()) except (socket.error, IOError) as e: raise exception.ClientConnectionError(e)
def _v2_auth(self, token_url): def get_endpoint(service_catalog): """ Select an endpoint from the service catalog We search the full service catalog for services matching both type and region. If the client supplied no region then any 'image' endpoint is considered a match. There must be one -- and only one -- successful match in the catalog, otherwise we will raise an exception. """ # FIXME(sirp): for now just use the public url. endpoint = None region = self.creds.get('region') for service in service_catalog: try: service_type = service['type'] except KeyError: msg = _('Encountered service with no "type": %s' % service) logger.warn(msg) continue if service_type == 'image': for ep in service['endpoints']: if region is None or region == ep['region']: if endpoint is not None: # This is a second match, abort raise exception.RegionAmbiguity(region=region) endpoint = ep if endpoint is None: raise exception.NoServiceEndpoint() return endpoint['publicURL'] creds = self.creds creds = { "auth": { "tenantName": creds['tenant'], "passwordCredentials": { "username": creds['username'], "password": creds['password'] } } } headers = {} headers['Content-Type'] = 'application/json' req_body = json.dumps(creds) resp, resp_body = self._do_request( token_url, 'POST', headers=headers, body=req_body) if resp.status == 200: resp_auth = json.loads(resp_body)['access'] self.management_url = get_endpoint(resp_auth['serviceCatalog']) self.auth_token = resp_auth['token']['id'] elif resp.status == 305: raise exception.RedirectException(resp['location']) elif resp.status == 400: raise exception.AuthBadRequest(url=token_url) elif resp.status == 401: raise exception.NotAuthenticated() elif resp.status == 404: raise exception.AuthUrlNotFound(url=token_url) else: raise Exception(_('Unexpected response: %s') % resp.status)
def _do_request(self, method, url, body, headers): """ Connects to the server and issues a request. Handles converting any returned HTTP error status codes to OpenStack/Glance exceptions and closing the server connection. Returns the result data, or raises an appropriate exception. :param method: HTTP method ("GET", "POST", "PUT", etc...) :param url: urlparse.ParsedResult object with URL information :param body: string of data to send, or None (default) :param headers: mapping of key/value pairs to add as headers :note If the body param has a read attribute, and method is either POST or PUT, this method will automatically conduct a chunked-transfer encoding and use the body as a file object, transferring chunks of data using the connection's send() method. This allows large objects to be transferred efficiently without buffering the entire body in memory. """ if url.query: path = url.path + "?" + url.query else: path = url.path try: connection_type = self.get_connection_type() headers = headers or {} if 'x-auth-token' not in headers and self.auth_tok: headers['x-auth-token'] = self.auth_tok c = connection_type(url.hostname, url.port, **self.connect_kwargs) # Do a simple request or a chunked request, depending # on whether the body param is a file-like object and # the method is PUT or POST if hasattr(body, 'read') and method.lower() in ('post', 'put'): # Chunk it, baby... c.putrequest(method, path) for header, value in headers.items(): c.putheader(header, value) c.putheader('Transfer-Encoding', 'chunked') c.endheaders() chunk = body.read(self.CHUNKSIZE) while chunk: c.send('%x\r\n%s\r\n' % (len(chunk), chunk)) chunk = body.read(self.CHUNKSIZE) c.send('0\r\n\r\n') else: # Simple request... c.request(method, path, body, headers) res = c.getresponse() status_code = self.get_status_code(res) if status_code in self.OK_RESPONSE_CODES: return res elif status_code in self.REDIRECT_RESPONSE_CODES: raise exception.RedirectException(res.getheader('Location')) elif status_code == httplib.UNAUTHORIZED: raise exception.NotAuthorized(res.read()) elif status_code == httplib.FORBIDDEN: raise exception.NotAuthorized(res.read()) elif status_code == httplib.NOT_FOUND: raise exception.NotFound(res.read()) elif status_code == httplib.CONFLICT: raise exception.Duplicate(res.read()) elif status_code == httplib.BAD_REQUEST: raise exception.Invalid(res.read()) elif status_code == httplib.MULTIPLE_CHOICES: raise exception.MultipleChoices(body=res.read()) elif status_code == httplib.INTERNAL_SERVER_ERROR: raise Exception("Internal Server error: %s" % res.read()) else: raise Exception("Unknown error occurred! %s" % res.read()) except (socket.error, IOError), e: raise exception.ClientConnectionError(e)