Esempio n. 1
0
    def get_qnet_progress(self, request, suffix=''):
        """The user progress checking handler"""
        abs_path = self.qnet_domain + self.qnet_progress
        # check absolute path and used element
        if abs_path != '' and self.qnet_element != '':
            # try to request
            try:
                url = self._format_api_url(abs_path)
                response = self._request_get(url)
            except Exception as e:
                return HTTPServerError(body="GET Qnet progress error: %s" %
                                       str(e))

            # parse progress
            progress = self._convert_progress(response['progress'])
            self.is_done = progress['is_done']
            self.score = progress['score']

            # grade
            if self.is_done:
                self.runtime.publish(self, 'grade', {
                    'value': self.score,
                    'max_value': self.weight
                })

            # return result
            return HTTPOk(headers={'Content-Type': 'application/json'},
                          body=json.dumps({
                              'is_done': self.is_done,
                              'score': self.score,
                              'max_score': self.weight
                          }))

        else:
            return HTTPServerError(body="Bad request to the Qnet platform")
Esempio n. 2
0
    def add_cluster(self, req, cluster_meta):
        """
        Adds a new cluster to Daisy.

        :param req: The WSGI/Webob Request object
        :param image_meta: Mapping of metadata about cluster

        :raises HTTPBadRequest if x-cluster-name is missing
        """
        self._enforce(req, 'add_cluster')
        cluster_name = cluster_meta["name"]
        if not cluster_name:
            raise ValueError('cluster name is null!')
        # target_systems = cluster_meta['target_systems']
        # if not target_systems:
        #     raise ValueError('target_systems is null!')
        if not cluster_meta.get('target_systems', None):
            cluster_meta['target_systems'] = "os"
        cluster_name_split = cluster_name.split('_')
        for cluster_name_info in cluster_name_split:
            if not cluster_name_info.isalnum():
                raise ValueError(
                    'cluster name must be numbers or letters or underscores !')
        try:
            params = {"filters": dict(name=cluster_name)}
            cluster_name_repeat = \
                registry.get_clusters_detail(req.context, **params)
        except Exception:
            pass
        else:
            if cluster_name_repeat:
                msg = _('cluster name [%s] is in use!') % cluster_name
                raise HTTPBadRequest(explanation=msg)

        if cluster_meta.get('nodes', None):
            orig_keys = list(cluster_meta['nodes'])
            for host_id in orig_keys:
                self._raise_404_if_host_deleted(req, host_id)
                node = registry.get_host_metadata(req.context, host_id)
                if node['status'] == 'in-cluster':
                    msg = _("Forbidden to add host %s with status "
                            "'in-cluster' in another cluster") % host_id
                    raise HTTPForbidden(explanation=msg)
                if node.get('interfaces', None):
                    interfaces = node['interfaces']
                    input_host_pxe_info = [
                        interface for interface in interfaces
                        if interface.get('is_deployment', None) == 1
                    ]
                    if not input_host_pxe_info and node.get('os_status',
                                                            None) != 'active':
                        msg = _(
                            "The host %s has more than one dhcp server, "
                            "please choose one interface for deployment") % \
                            host_id
                        raise HTTPServerError(explanation=msg)
        print cluster_name
        print cluster_meta
        cluster_meta = registry.add_cluster_metadata(req.context, cluster_meta)
        return {'cluster_meta': cluster_meta}
Esempio n. 3
0
 def DELETE(self, req):
     """HTTP DELETE request handler."""
     container_info = self.container_info(self.account_name,
                                          self.container_name)
     container_partition = container_info['partition']
     containers = container_info['nodes']
     req.acl = container_info['write_acl']
     req.environ['swift_sync_key'] = container_info['sync_key']
     object_versions = container_info['versions']
     if object_versions:
         # this is a version manifest and needs to be handled differently
         lcontainer = object_versions.split('/')[0]
         prefix_len = '%03x' % len(self.object_name)
         lprefix = prefix_len + self.object_name + '/'
         last_item = None
         try:
             for last_item in self._listing_iter(lcontainer, lprefix,
                                                 req.environ):
                 pass
         except ListingIterNotFound:
             # no worries, last_item is None
             pass
         except ListingIterNotAuthorized, err:
             return err.aresp
         except ListingIterError:
             return HTTPServerError(request=req)
Esempio n. 4
0
 def __call__(self, env, start_response):
     try:
         return self.app(env, start_response)
     except Exception, err:
         self.logger.exception(_('Error: %s'), err)
         resp = HTTPServerError(request=Request(env),
                                body='An error occurred',
                                content_type='text/plain')
         return resp(env, start_response)
Esempio n. 5
0
    def get_qnet_status(self, request, suffix=''):
        """The lab status checking handler"""
        abs_path = self.qnet_domain + self.qnet_status
        # check absolute path and used element
        if abs_path != '' and self.qnet_element != '':
            # try to request
            try:
                url = self._format_api_url(abs_path)
                response = self._request_get(url)
            except Exception as e:
                return HTTPServerError(body="GET Qnet status error: %s" %
                                       str(e))

            # return result
            return HTTPOk(headers={'Content-Type': 'application/json'},
                          body=json.dumps(response['wstatus']))

        else:
            return HTTPServerError(body="Bad request to the Qnet platform")
Esempio n. 6
0
    def __call__(self, env, start_response):
        trans_id = env.get('HTTP_X_TRANS_ID')
        if not trans_id:
            trans_id = 'tx' + uuid.uuid4().hex
            env['HTTP_X_TRANS_ID'] = trans_id
        try:

            def my_start_response(status, response_headers, exc_info=None):
                trans_header = ('x-trans-id', trans_id)
                response_headers.append(trans_header)
                return start_response(status, response_headers, exc_info)
            return self.app(env, my_start_response)
        except Exception, err:
            self.logger.exception(_('Error: %s'), err)
            resp = HTTPServerError(request=Request(env),
                                   body='An error occurred',
                                   content_type='text/plain')
            resp.headers['x-trans-id'] = trans_id
            return resp(env, start_response)
Esempio n. 7
0
 def start_qnet_lab(self, request, suffix=''):
     """The starting handler"""
     abs_path = self.qnet_domain + self.qnet_path
     # check absolute path and used element
     if abs_path != '' and self.qnet_element != '':
         return {
             'uri':
             abs_path.format(element=self.qnet_element) +
             ('?return_uri=%s' % request['from'])
         }
     else:
         return HTTPServerError(body="Bad request to the Qnet platform")
Esempio n. 8
0
    def __call__(self, env, start_response):
        """
        If used, this should be the first middleware in pipeline.
        """
        trans_id = 'tx' + uuid.uuid4().hex
        env['swift.trans_id'] = trans_id
        self.logger.txn_id = trans_id
        try:

            def my_start_response(status, response_headers, exc_info=None):
                trans_header = ('x-trans-id', trans_id)
                response_headers.append(trans_header)
                return start_response(status, response_headers, exc_info)
            return self.app(env, my_start_response)
        except (Exception, Timeout), err:
            self.logger.exception(_('Error: %s'), err)
            resp = HTTPServerError(request=Request(env),
                                   body='An error occurred',
                                   content_type='text/plain')
            resp.headers['x-trans-id'] = trans_id
            return resp(env, start_response)
Esempio n. 9
0
    def __call__(self, env, start_response):
        """
        If used, this should be the first middleware in pipeline.
        """
        trans_id = 'tx' + uuid.uuid4().hex
        env['swift.trans_id'] = trans_id
        self.logger.txn_id = trans_id
        try:

            def my_start_response(status, response_headers, exc_info=None):
                trans_header = ('x-trans-id', trans_id)
                response_headers.append(trans_header)
                return start_response(status, response_headers, exc_info)

            return self.app(env, my_start_response)
        except (Exception, Timeout), err:
            self.logger.exception(_('Error: %s'), err)
            resp = HTTPServerError(request=Request(env),
                                   body='An error occurred',
                                   content_type='text/plain')
            resp.headers['x-trans-id'] = trans_id
            return resp(env, start_response)
    def start_lab(self, request, suffix=''):
        self.started = True

        if self.course_name != '' and self.course_element != '' and self.iteration_id != '':

            html_academy_link = self.lab_url.format(
                name=self.course_name,
                element=self.course_element,
            )

            return HTTPFound(location=html_academy_link)
        else:
            return HTTPServerError(explanation='Course Name, Course Element and Iteration ID fields are required!')
Esempio n. 11
0
    def GETorHEAD(self, req):
        """Handle HTTP GET or HEAD requests."""
        container_info = self.container_info(self.account_name,
                                             self.container_name)
        req.acl = container_info['read_acl']
        if 'swift.authorize' in req.environ:
            aresp = req.environ['swift.authorize'](req)
            if aresp:
                return aresp
        partition, nodes = self.app.object_ring.get_nodes(
            self.account_name, self.container_name, self.object_name)
        shuffle(nodes)
        resp = self.GETorHEAD_base(req, _('Object'), partition,
                self.iter_nodes(partition, nodes, self.app.object_ring),
                req.path_info, len(nodes))
        # Whether we get a 416 Requested Range Not Satisfiable or not,
        # we should request a manifest because size of manifest file
        # can be not 0. After checking a manifest, redo the range request
        # on the whole object.
        if req.range:
            req_range = req.range
            req.range = None
            resp2 = self.GETorHEAD_base(req, _('Object'), partition,
                                        self.iter_nodes(partition,
                                                        nodes,
                                                        self.app.object_ring),
                                        req.path_info, len(nodes))
            if 'x-object-manifest' not in resp2.headers:
                return resp
            resp = resp2
            req.range = str(req_range)

        if 'x-object-manifest' in resp.headers:
            lcontainer, lprefix = \
                resp.headers['x-object-manifest'].split('/', 1)
            lcontainer = unquote(lcontainer)
            lprefix = unquote(lprefix)
            try:
                listing = list(self._listing_iter(lcontainer, lprefix,
                                req.environ))
            except ListingIterNotFound:
                return HTTPNotFound(request=req)
            except ListingIterNotAuthorized, err:
                return err.aresp
            except ListingIterError:
                return HTTPServerError(request=req)
Esempio n. 12
0
    def __call__(self, env, start_response):
        if env['REQUEST_METHOD'] != 'PUT':
            return self.app(env, start_response)

        version, account, container, obj = split_path(env['PATH_INFO'], 1, 4,
                                                      True)
        if not obj:
            return self.app(env, start_response)
        if not obj.lower().endswith('.jpg') and\
                not obj.lower().endswith('.jpeg'):
            return self.app(env, start_response)

        extractor = MetaExtractor(env['wsgi.input'])
        env['wsgi.input'] = extractor
        try:
            resp = self._app_call(env)
        except Exception:
            resp = HTTPServerError(request=Request(env), body="error")
            return resp(env, start_response)
        start_response(self._response_status, self._response_headers,
                       self._response_exc_info)
        status = int(self._response_status.split()[0])
        if status < 200 or status > 300:
            return resp

        headers = {}
        for tag in extractor.exif_parser.tags:
            if tag.tag().startswith('Unknown'):
                continue
            if len(tag.value()) > MAX_META_VALUE_LENGTH:
                continue
            header = 'X-Object-Meta-' + tag.tag().replace(' ', '-')
            headers[header] = tag.value()

        # TODO: merge with the PUT headers
        self.logger.info(headers)
        post_req = make_pre_authed_request(env,
                                           method='POST',
                                           swift_source='JpegMeta',
                                           path=env['PATH_INFO'],
                                           headers=headers)
        post_resp = post_req.get_response(self.app)
        if not is_success(post_resp.status_int):
            self.logger.info('POST with JPEG headers failed: ' +
                             str(post_resp.body))
        return resp
Esempio n. 13
0
 def publish(self, environ):
     request = Request(environ)
     # xml-rpc only!
     if request.content_type.find('text/xml') >= 0:
         # FIXME pumazi: aww... this sucks! using the repoze.bfg.xmlrpc
         #   (xmlrpc module) code was a mistake :(
         #   The result of this is unloading the request twice =/
         params, call_name = xmlrpclib.loads(request.body)
         storage = self.storage_factory(environ, self.config)
         # route the call
         call = xmlrpc_router(call_name)
         if call is not None:
             try:
                 response = call(storage, request)
             except Exception, e:
                 response = HTTPServerError(str(e))
         else:
             response = HTTPNotFound()
    def check(self, request, match):
        """Checks if the current request/match can be viewed.

        For WhoAuthentication this just delegates to the authenticate()
        API method, and uses the challenge() method if the user is not
        authorized for the request.
        """
        # Don't auth if it's not required by the match.
        if match.get('auth') != 'True':
            return

        # If something further up the stack has already dealt with auth,
        # then things are highly unlikely to work properly.
        if 'REMOTE_USER' in request.environ:
            msg = 'The webserver appears to have handled authentication '\
                  'internally, which is not compatible with this product.'
            raise HTTPServerError(msg)

        # Authenticate the user.
        api = self._api_factory(request.environ)
        identity = api.authenticate()
        if identity is None:
            self._raise_challenge(request)

        # Check against the username matched from the url, if any.
        username = identity.get("username")
        if match.get("username") not in (None, username):
            cef_kwds = {"signature": AUTH_FAILURE}
            if username is not None:
                cef_kwds["username"] = username
            err = "Username Does Not Match URL"
            self.logger.cef(err, 7, request.environ, self.config, **cef_kwds)
            self._raise_challenge(request)

        # Adjust environ to record the successful auth.
        # The identity must somehow get "userid" and "username" keys,
        # either from the authenticator or from an mdprovider.
        request.environ.pop("HTTP_AUTHORIZATION", None)
        match["user_id"] = identity["userid"]
        request.remote_user = identity["username"]
        request.environ["REMOTE_USER"] = identity["username"]
        request.user = User(identity["username"], identity["userid"])
        request.user.update(identity)
Esempio n. 15
0
 def __call__(self, env, start_response):
     """
     """
     req = Request(env)
     self.loc.reload()
     if self.loc.age == 0:
         self.logger.warn(
             'dispatcher relay rule is invalid, using old rules now.')
     if not self.is_keystone_proxy_path(req):
         return self.app(env, start_response)
     try:
         (loc_prefix, api_type) = self.location_api_check(req)
     except Exception:
         return HTTPPreconditionFailed(body='invalid PATH')(env,
                                                            start_response)
     ks_port = self.keystone_auth_port \
         if api_type == self.keystone_proxy_auth_path \
         else self.keystone_admin_port
     servers = self.loc.swift_of(loc_prefix)
     if not servers:
         return HTTPPreconditionFailed(body='invalid Location prefix')(
             env, start_response)
     (succ_resps, fail_resps) = self.request_to_ks(req, servers, ks_port)
     if len(succ_resps) == 0:
         resp = fail_resps[0]
         if isinstance(resp, HTTPException):
             return resp(env, start_response)
         start_response('%s %s' % (resp.status, resp.reason),
                        resp.getheaders())
         return resp.read()
     if self.loc.is_merged(loc_prefix):
         try:
             (body, header) = self.ks_merge_response(succ_resps, loc_prefix)
         except Exception, err:
             return HTTPServerError(body=err)(env, start_response)
         res = Response(status='200 OK')
         res.headerlist = header
         res.body = body
         return res(env, start_response)
Esempio n. 16
0
    def __call__(self, env, start_response):
        req = Request(env)
        if env['REQUEST_METHOD'] not in ['GET']:
            return self.app(env, start_response)

        version, account, container, obj = split_path(
            env['PATH_INFO'], 1, 4, True)
        try:
            resp = self._app_call(env)
        except Exception:
            resp = HTTPServerError(request=req, body="error")
            return resp(env, start_response)
        status = int(self._response_status.split()[0])

        if status < 200 or status > 300:
            start_response(self._response_status, self._response_headers,
                           self._response_exc_info)
            return resp
        SLOmd5 = ''
        if req.params.get('multipart-manifest') == 'get':
            if req.params.get('format') == 'raw':
                resp = self.convert_segment_listing(
                    self._response_headers, resp)
            else:
                h = hashlib.md5()
                segments = self._get_manifest_read(resp)
                for seg_dict in segments:
                    if 'data' in seg_dict:
                        continue
                    sub_path = get_valid_utf8_str(seg_dict['name'])
                    sub_cont, sub_obj = split_path(sub_path, 2, 2, True)
                    h.update(self._fetch_sub_slo_segments(req, version,
                             account, sub_cont, sub_obj))
                SLOmd5 = h.hexdigest()
        self._post_slomd5_header(env, SLOmd5)
        return self.app(env, start_response)
    def authenticate_user(self, request, config, username=None):
        """Authenticates a user and returns his id.

        "request" is the request received.
        The function makes sure that the user name found in the headers
        is compatible with the username if provided.

        It returns the user id from the database, if the password is the right
        one.
        """
        environ = request.environ

        # If something further up the stack has already dealt with auth,
        # then things are highly unlikely to work properly.
        if 'REMOTE_USER' in environ:
            msg = 'The webserver appears to have handled authentication '\
                  'internally, which is not compatible with this product.'
            raise HTTPServerError(msg)

        auth = environ.get('HTTP_AUTHORIZATION')
        if auth is not None:
            # for now, only supporting basic authentication
            # let's decipher the base64 encoded value
            if not auth.startswith('Basic '):
                self._log_cef('Authorization header contains unknown protocol',
                              7, environ)
                raise HTTPUnauthorized('Invalid token')

            auth = auth[len('Basic '):].strip()
            try:
                # Split in such a way as to preserve
                # passwords that contain ':'.
                user_name, password = base64.decodestring(auth).split(':', 1)
            except (binascii.Error, ValueError):
                self._log_cef('Authorization header is badly encoded', 7,
                              environ)
                raise HTTPUnauthorized('Invalid token')

            # let's reject the call if the url is not owned by the user
            if (username is not None and user_name != username):
                self._log_cef('Username Does Not Match URL', 7, environ,
                              config, user_name, AUTH_FAILURE)
                raise HTTPUnauthorized()

            # if this is an email, hash it. Save the original for logging and
            #  debugging.
            remote_user_original = user_name
            try:
                user_name = extract_username(user_name)
            except UnicodeError:
                self._log_cef('Username contains invalid characters', 7,
                              environ)
                raise HTTPBadRequest(
                    'Invalid characters specified in ' + 'username', {},
                    'Username must be BIDI ' + 'compliant UTF-8')

            # let's try an authentication
            # the authenticate_user API takes a unicode UTF-8 for the password
            try:
                password = password.decode('utf8')
            except UnicodeDecodeError:
                self._log_cef('Password is not utf-8 encoded', 7, environ)
                raise HTTPUnauthorized()

            #first we need to figure out if this is old-style or new-style auth
            if hasattr(self.backend, 'generate_reset_code'):

                # XXX to be removed once we get the proper fix see bug #662859
                if (hasattr(self.backend, 'check_node')
                        and self.backend.check_node):
                    user_id = self.backend.authenticate_user(
                        user_name, password, environ.get('HTTP_HOST'))
                else:
                    user_id = self.backend.authenticate_user(
                        user_name, password)
                request.user = User(user_name, user_id)
            else:
                user = User(user_name)
                credentials = {"username": user_name, "password": password}
                attrs = []
                check_node = self.config.get('auth.check_node')
                if check_node:
                    attrs.append('syncNode')
                user_id = self.backend.authenticate_user(
                    user, credentials, attrs)
                if not user_id:
                    user_id = None
                    user = None
                else:
                    if (check_node and
                            user.get('syncNode') != environ.get('HTTP_HOST')):
                        self._log_cef('User authenticated to wrong node', 7,
                                      environ)
                        user_id = None
                        user = None

                request.user = user

            if user_id is None:
                err_user = user_name
                if remote_user_original is not None and \
                    user_name != remote_user_original:
                    err_user += ' (%s)' % (remote_user_original)
                self._log_cef('User Authentication Failed', 5, environ, config,
                              err_user, AUTH_FAILURE)
                raise HTTPUnauthorized()

            # we're all clear ! setting up REMOTE_USER
            request.remote_user = environ['REMOTE_USER'] = user_name

            # we also want to keep the password in clear text to reuse it
            # and remove it from the environ
            request.user_password = password
            request._authorization = environ['HTTP_AUTHORIZATION']

            del environ['HTTP_AUTHORIZATION']
            return user_id
Esempio n. 18
0
    """Called by onLineFrom or onRawDataFrom to notify us that the Request
    has been fully read and we can begin processing it."""

    try:
      response = yield self.requestHandler.findHandlerFor(request)
    except HTTPNotFound, e:
      response = e
    except:
      # We got an error while trying to to find a wsgi
      # application to handle the request, log it and try to
      # report something useful to the user.
      
      exc_info = sys.exc_info()
      self.log.exception('Unexpected Exception encountered while attempting to locate a handler for %s', request.path_info)
      #request.startResponse('500 Unexpeted',(('Content-type', 'text/plain'),),exc_info)
      response = HTTPServerError(detail="".join(traceback.format_exception(*exc_info)), request=request)
      response.text = response.html_body(request.environ)
      del exc_info
      

    # Valid responses are either WSGI Apps, Operation or of instances Responses
    if isinstance(response,self.Operation):
      try:
        response = yield response #yield (self.scheduler.call,)  + response
      except Exception, e:
        exc_info = sys.exc_info()
        self.log.exception('Unexpected Exception encountered in coroutine %s', request.path_info)
        response = HTTPServerError(detail="<br/>\n".join(traceback.format_exception(*exc_info)), request=request)
        response.text = response.html_body(request.environ)

          
Esempio n. 19
0
    def __call__(self):
        """
        :return httplib.HTTP(S)Connection in success, and webob.exc.HTTPException in failure
        """
        if self.headers.has_key('content-length'):
            if int(self.headers['content-length']) >= MAX_FILE_SIZE:
                return HTTPRequestEntityTooLarge(request=self.req)

        parsed = urlparse(self.url)
        if self.proxy:
            proxy_parsed = urlparse(self.proxy)

        if self._proxy_request_check(parsed.path):
            host, port = self.split_netloc(proxy_parsed)
            path = self.url
            ssl = True if proxy_parsed.scheme == 'https' else False
        else:
            host, port = self.split_netloc(parsed)
            path = parsed.path
            ssl = True if parsed.scheme == 'https' else False
        self.headers['host'] = '%s:%s' % (host, port)

        if self.method == 'PUT' and len(parsed.path.split('/')) >= 5:
            if self.headers.has_key('content-length') and int(
                    self.headers['content-length']) != 0:
                if not self.headers.has_key('expect'):
                    self.headers['expect'] = '100-continue'
            chunked = self.req.headers.get('transfer-encoding')
            if isinstance(self.req.environ['wsgi.input'], str):
                reader = self.req.environ['wsgi.input'].read
                data_source = iter(lambda: reader(self.chunk_size), '')
            else:
                data_source = self.req.environ['wsgi.input']
            bytes_transferred = 0
            try:
                conn = self._connect_put_node(host,
                                              port,
                                              self.method,
                                              path,
                                              headers=self.headers,
                                              query_string=parsed.query,
                                              ssl=ssl)
                if not conn:
                    return HTTPServiceUnavailable(request=self.req)
                with ContextPool(1) as pool:
                    conn.failed = False
                    conn.queue = Queue(10)
                    pool.spawn(self._send_file, conn, path)
                    while True:
                        with ChunkReadTimeout(self.client_timeout):
                            try:
                                chunk = next(data_source)
                            except StopIteration:
                                if chunked:
                                    conn.queue.put('0\r\n\r\n')
                                break
                            except TypeError, err:
                                self.logger.info('Chunk Read Error: %s' % err)
                                break
                            except Exception, err:
                                self.logger.info('Chunk Read Error: %s' % err)
                                return HTTPServerError(request=self.req)
                        bytes_transferred += len(chunk)
                        if bytes_transferred > MAX_FILE_SIZE:
                            return HTTPRequestEntityTooLarge(request=self.req)
                        if not conn.failed:
                            conn.queue.put('%x\r\n%s\r\n' %
                                           (len(chunk),
                                            chunk) if chunked else chunk)
Esempio n. 20
0
    def handle_request(self, req):
        """
        Entry point for proxy server.
        Should return a WSGI-style callable (such as webob.Response).

        :param req: webob.Request object
        """
        try:
            self.logger.set_statsd_prefix('proxy-server')
            if req.content_length and req.content_length < 0:
                self.logger.increment('errors')
                return HTTPBadRequest(request=req,
                                      body='Invalid Content-Length')

            try:
                if not check_utf8(req.path_info):
                    self.logger.increment('errors')
                    return HTTPPreconditionFailed(request=req,
                                                  body='Invalid UTF8')
            except UnicodeError:
                self.logger.increment('errors')
                return HTTPPreconditionFailed(request=req, body='Invalid UTF8')

            try:
                controller, path_parts = self.get_controller(req.path)
                p = req.path_info
                if isinstance(p, unicode):
                    p = p.encode('utf-8')
            except ValueError:
                self.logger.increment('errors')
                return HTTPNotFound(request=req)
            if not controller:
                self.logger.increment('errors')
                return HTTPPreconditionFailed(request=req, body='Bad URL')
            if self.deny_host_headers and \
                    req.host.split(':')[0] in self.deny_host_headers:
                return HTTPForbidden(request=req, body='Invalid host header')

            self.logger.set_statsd_prefix('proxy-server.' +
                                          controller.server_type.lower())
            controller = controller(self, **path_parts)
            if 'swift.trans_id' not in req.environ:
                # if this wasn't set by an earlier middleware, set it now
                trans_id = 'tx' + uuid.uuid4().hex
                req.environ['swift.trans_id'] = trans_id
                self.logger.txn_id = trans_id
            req.headers['x-trans-id'] = req.environ['swift.trans_id']
            controller.trans_id = req.environ['swift.trans_id']
            self.logger.client_ip = get_remote_client(req)
            try:
                handler = getattr(controller, req.method)
                getattr(handler, 'publicly_accessible')
            except AttributeError:
                return HTTPMethodNotAllowed(request=req)
            if path_parts['version']:
                req.path_info_pop()
            if 'swift.authorize' in req.environ:
                # We call authorize before the handler, always. If authorized,
                # we remove the swift.authorize hook so isn't ever called
                # again. If not authorized, we return the denial unless the
                # controller's method indicates it'd like to gather more
                # information and try again later.
                resp = req.environ['swift.authorize'](req)
                if not resp:
                    # No resp means authorized, no delayed recheck required.
                    del req.environ['swift.authorize']
                else:
                    # Response indicates denial, but we might delay the denial
                    # and recheck later. If not delayed, return the error now.
                    if not getattr(handler, 'delay_denial', None):
                        return resp
            # Save off original request method (GET, POST, etc.) in case it
            # gets mutated during handling.  This way logging can display the
            # method the client actually sent.
            req.environ['swift.orig_req_method'] = req.method
            return handler(req)
        except (Exception, Timeout):
            self.logger.exception(_('ERROR Unhandled exception in request'))
            return HTTPServerError(request=req)
Esempio n. 21
0
    def update_cluster(self, req, id, cluster_meta):
        """
        Updates an existing cluster with the registry.

        :param request: The WSGI/Webob Request object
        :param id: The opaque cluster identifier

        :retval Returns the updated cluster information as a mapping
        """
        self._enforce(req, 'update_cluster')
        if 'nodes' in cluster_meta:
            orig_keys = list(cluster_meta['nodes'])
            for host_id in orig_keys:
                self._raise_404_if_host_deleted(req, host_id)
                node = registry.get_host_metadata(req.context, host_id)
                if node['status'] == 'in-cluster':
                    host_cluster = registry.get_host_clusters(
                        req.context, host_id)
                    if host_cluster[0]['cluster_id'] != id:
                        msg = _("Forbidden to add host %s with status "
                                "'in-cluster' in another cluster") % host_id
                        raise HTTPForbidden(explanation=msg)
                if node.get('interfaces', None):
                    interfaces = node['interfaces']
                    input_host_pxe_info = [
                        interface for interface in interfaces
                        if interface.get('is_deployment', None) == 1
                    ]
                    if not input_host_pxe_info and node.get('os_status',
                                                            None) != 'active':
                        msg = _(
                            "The host %s has more than one dhcp server, "
                            "please choose one interface for deployment") % \
                            host_id
                        raise HTTPServerError(explanation=msg)
        if 'networks' in cluster_meta:
            orig_keys = list(cluster_meta['networks'])
            for network_id in orig_keys:
                self._raise_404_if_network_deleted(req, network_id)
        orig_cluster_meta = self.get_cluster_meta_or_404(req, id)

        # Do not allow any updates on a deleted cluster.
        # Fix for LP Bug #1060930
        if orig_cluster_meta['deleted']:
            msg = _("Forbidden to update deleted cluster.")
            raise HTTPForbidden(explanation=msg,
                                request=req,
                                content_type="text/plain")
        try:
            cluster_meta = registry.update_cluster_metadata(
                req.context, id, cluster_meta)

        except exception.Invalid as e:
            msg = (_("Failed to update cluster metadata. Got error: %s") %
                   utils.exception_to_str(e))
            LOG.warning(msg)
            raise HTTPBadRequest(explanation=msg,
                                 request=req,
                                 content_type="text/plain")
        except exception.NotFound as e:
            msg = (_("Failed to find cluster to update: %s") %
                   utils.exception_to_str(e))
            LOG.warning(msg)
            raise HTTPNotFound(explanation=msg,
                               request=req,
                               content_type="text/plain")
        except exception.Forbidden as e:
            msg = (_("Forbidden to update cluster: %s") %
                   utils.exception_to_str(e))
            LOG.warning(msg)
            raise HTTPForbidden(explanation=msg,
                                request=req,
                                content_type="text/plain")
        except (exception.Conflict, exception.Duplicate) as e:
            LOG.warning(utils.exception_to_str(e))
            raise HTTPConflict(body=_('Cluster operation conflicts'),
                               request=req,
                               content_type='text/plain')
        else:
            self.notifier.info('cluster.update', cluster_meta)

        return {'cluster_meta': cluster_meta}
Esempio n. 22
0
             bodies.append(response.read())
             if response.status >= HTTP_INTERNAL_SERVER_ERROR:
                 self.error_occurred(conn.node,
                     _('ERROR %(status)d %(body)s From Object Server ' \
                     're: %(path)s') % {'status': response.status,
                     'body': bodies[-1][:1024], 'path': req.path})
             elif is_success(response.status):
                 etags.add(response.getheader('etag').strip('"'))
     except (Exception, Timeout):
         self.exception_occurred(
             conn.node, _('Object'),
             _('Trying to get final status of PUT to %s') % req.path)
 if len(etags) > 1:
     self.app.logger.error(
         _('Object servers returned %s mismatched etags'), len(etags))
     return HTTPServerError(request=req)
 etag = len(etags) and etags.pop() or None
 while len(statuses) < len(nodes):
     statuses.append(HTTP_SERVICE_UNAVAILABLE)
     reasons.append('')
     bodies.append('')
 resp = self.best_response(req,
                           statuses,
                           reasons,
                           bodies,
                           _('Object PUT'),
                           etag=etag)
 if source_header:
     resp.headers['X-Copied-From'] = quote(
         source_header.split('/', 2)[2])
     if 'last-modified' in source_resp.headers:
Esempio n. 23
0
    def __call__(self):
        """
        :return httplib.HTTP(S)Connection in success, and webob.exc.HTTPException in failure
        """
        if self.headers.has_key('content-length'):
            if int(self.headers['content-length']) >= MAX_FILE_SIZE:
                return HTTPRequestEntityTooLarge(request=self.req)

        parsed = urlparse(self.url)
        if self.proxy:
            proxy_parsed = urlparse(self.proxy)

        if self._proxy_request_check(parsed.path):
            host, port = self.split_netloc(proxy_parsed)
            path = self.url
        else:
            host, port = self.split_netloc(parsed)
            path = parsed.path
        self.headers['host'] = '%s:%s' % (host, port)

        if self.method == 'PUT' and len(parsed.path.split('/')) == 5:
            chunked = self.req.headers.get('transfer-encoding')
            reader = self.req.environ['wsgi.input'].read
            data_source = iter(lambda: reader(self.chunk_size), '')
            bytes_transferred = 0
            # pile = GreenPile()
            # pile.spawn(self._connect_server, host, port, self.method, path, self.headers, parsed.query)
            # conns = [conn for conn in pile if conn]
            # conn = conns[0]
            try:
                with ConnectionTimeout(self.conn_timeout):
                    conn = http_connect_raw(host,
                                            port,
                                            self.method,
                                            path,
                                            headers=self.headers,
                                            query_string=parsed.query)
                with ContextPool(1) as pool:
                    conn.failed = False
                    conn.queue = Queue(10)
                    pool.spawn(self._send_file, conn, path)
                    while True:
                        with ChunkReadTimeout(self.client_timeout):
                            try:
                                chunk = next(data_source)
                            except StopIteration:
                                if chunked:
                                    conn.queue.put('0\r\n\r\n')
                                break
                            except TypeError, err:
                                self.logger.info('Chunk Read Error: %s' % err)
                                break
                            except Exception, err:
                                self.logger.info('Chunk Read Error: %s' % err)
                                return HTTPServerError(request=self.req)
                        bytes_transferred += len(chunk)
                        if bytes_transferred > MAX_FILE_SIZE:
                            return HTTPRequestEntityTooLarge(request=self.req)
                        if not conn.failed:
                            conn.queue.put('%x\r\n%s\r\n' %
                                           (len(chunk),
                                            chunk) if chunked else chunk)
Esempio n. 24
0
        self.signature_methods[signature_cls.name] = signature_cls()

        # FIXME: the nonce list heavily depends on traffic usage
        nonce_cache_size = self._config.get('nonce_cache_size', 20000)
        self.nonce_list = NOnceList(nonce_cache_size)

    def __call__(self, environ, start_response):
        # 1. get the webob request and oauth request
        req = OAuthRequest(environ)
        try:
            response = self.process(self.get_storage(environ), req)
        except Error, e:
            response = HTTPBadRequest(e.message)
        except:
            response = HTTPServerError(
                "An unknown problem has occured, "
                "please contact your site administrator for help with this "
                "issue.")
        return response(environ, start_response)

    def get_storage(self, environ):
        """Transparent access to the storage without worrying about
        the factory."""
        return self.storage_factory(environ, self._config)

    def process(self, storage, request):
        """Process the OAuth request."""
        # 2. determine if the request is an oauth request
        consumer_key = request.oauth_params.get('oauth_consumer_key', None)
        oauth_token_key = request.oauth_params.get('oauth_token', None)
        if len(request.oauth_params) == 0:  # not an oauth reqeust
            raise NotAnOAuthRequest("The request made does not contain one "