Example #1
0
    def test_get_account_info_cache(self):
        # The original test that we prefer to preserve
        cached = {'status': 404, 'bytes': 3333, 'total_object_count': 10}
        req = Request.blank("/v1/account/cont",
                            environ={'swift.cache': FakeCache(cached)})
        resp = get_account_info(req.environ, FakeApp())
        self.assertEqual(resp['bytes'], 3333)
        self.assertEqual(resp['total_object_count'], 10)
        self.assertEqual(resp['status'], 404)

        # Here is a more realistic test
        cached = {
            'status': 404,
            'bytes': '3333',
            'container_count': '234',
            'total_object_count': '10',
            'meta': {}
        }
        req = Request.blank("/v1/account/cont",
                            environ={'swift.cache': FakeCache(cached)})
        resp = get_account_info(req.environ, FakeApp())
        self.assertEqual(resp['status'], 404)
        self.assertEqual(resp['bytes'], '3333')
        self.assertEqual(resp['container_count'], 234)
        self.assertEqual(resp['meta'], {})
        self.assertEqual(resp['total_object_count'], '10')
Example #2
0
    def test_get_account_info_cache(self):
        # The original test that we prefer to preserve
        cached = {'status': 404, 'bytes': 3333, 'total_object_count': 10}
        req = Request.blank("/v1/account/cont",
                            environ={'swift.cache': FakeCache(cached)})
        with patch(
                'swift.proxy.controllers.base.'
                '_prepare_pre_auth_info_request', FakeRequest):
            resp = get_account_info(req.environ, 'xxx')
        self.assertEquals(resp['bytes'], 3333)
        self.assertEquals(resp['total_object_count'], 10)
        self.assertEquals(resp['status'], 404)

        # Here is a more realistic test
        cached = {
            'status': 404,
            'bytes': '3333',
            'container_count': '234',
            'total_object_count': '10',
            'meta': {}
        }
        req = Request.blank("/v1/account/cont",
                            environ={'swift.cache': FakeCache(cached)})
        with patch(
                'swift.proxy.controllers.base.'
                '_prepare_pre_auth_info_request', FakeRequest):
            resp = get_account_info(req.environ, 'xxx')
        self.assertEquals(resp['status'], 404)
        self.assertEquals(resp['bytes'], '3333')
        self.assertEquals(resp['container_count'], 234)
        self.assertEquals(resp['meta'], {})
        self.assertEquals(resp['total_object_count'], '10')
Example #3
0
    def test_get_account_info_cache(self):
        # The original test that we prefer to preserve
        cached = {'status': 404,
                  'bytes': 3333,
                  'total_object_count': 10}
        req = Request.blank("/v1/account/cont",
                            environ={'swift.cache': FakeCache(cached)})
        with patch('swift.proxy.controllers.base.'
                   '_prepare_pre_auth_info_request', FakeRequest):
            resp = get_account_info(req.environ, 'xxx')
        self.assertEquals(resp['bytes'], 3333)
        self.assertEquals(resp['total_object_count'], 10)
        self.assertEquals(resp['status'], 404)

        # Here is a more realistic test
        cached = {'status': 404,
                  'bytes': '3333',
                  'container_count': '234',
                  'total_object_count': '10',
                  'meta': {}}
        req = Request.blank("/v1/account/cont",
                            environ={'swift.cache': FakeCache(cached)})
        with patch('swift.proxy.controllers.base.'
                   '_prepare_pre_auth_info_request', FakeRequest):
            resp = get_account_info(req.environ, 'xxx')
        self.assertEquals(resp['status'], 404)
        self.assertEquals(resp['bytes'], '3333')
        self.assertEquals(resp['container_count'], 234)
        self.assertEquals(resp['meta'], {})
        self.assertEquals(resp['total_object_count'], '10')
Example #4
0
    def test_get_account_info_cache(self):
        # Works with fake apps that return ints in the headers
        cached = {'status': 404,
                  'bytes': 3333,
                  'total_object_count': 10}
        req = Request.blank("/v1/account/cont",
                            environ={'swift.cache': FakeCache(cached)})
        resp = get_account_info(req.environ, FakeApp())
        self.assertEqual(resp['bytes'], 3333)
        self.assertEqual(resp['total_object_count'], 10)
        self.assertEqual(resp['status'], 404)

        # Works with strings too, like you get when parsing HTTP headers
        # that came in through a socket from the account server
        cached = {'status': 404,
                  'bytes': '3333',
                  'container_count': '234',
                  'total_object_count': '10',
                  'meta': {}}
        req = Request.blank("/v1/account/cont",
                            environ={'swift.cache': FakeCache(cached)})
        resp = get_account_info(req.environ, FakeApp())
        self.assertEqual(resp['status'], 404)
        self.assertEqual(resp['bytes'], 3333)
        self.assertEqual(resp['container_count'], 234)
        self.assertEqual(resp['meta'], {})
        self.assertEqual(resp['total_object_count'], 10)
Example #5
0
    def test_get_account_info_cache(self):
        # The original test that we prefer to preserve
        cached = {'status': 404,
                  'bytes': 3333,
                  'total_object_count': 10}
        req = Request.blank("/v1/account/cont",
                            environ={'swift.cache': FakeCache(cached)})
        resp = get_account_info(req.environ, FakeApp())
        self.assertEqual(resp['bytes'], 3333)
        self.assertEqual(resp['total_object_count'], 10)
        self.assertEqual(resp['status'], 404)

        # Here is a more realistic test
        cached = {'status': 404,
                  'bytes': '3333',
                  'container_count': '234',
                  'total_object_count': '10',
                  'meta': {}}
        req = Request.blank("/v1/account/cont",
                            environ={'swift.cache': FakeCache(cached)})
        resp = get_account_info(req.environ, FakeApp())
        self.assertEqual(resp['status'], 404)
        self.assertEqual(resp['bytes'], '3333')
        self.assertEqual(resp['container_count'], 234)
        self.assertEqual(resp['meta'], {})
        self.assertEqual(resp['total_object_count'], '10')
Example #6
0
    def test_get_account_info_cache(self):
        # Works with fake apps that return ints in the headers
        cached = {'status': 404, 'bytes': 3333, 'total_object_count': 10}
        req = Request.blank("/v1/account/cont",
                            environ={'swift.cache': FakeCache(cached)})
        resp = get_account_info(req.environ, FakeApp())
        self.assertEqual(resp['bytes'], 3333)
        self.assertEqual(resp['total_object_count'], 10)
        self.assertEqual(resp['status'], 404)

        # Works with strings too, like you get when parsing HTTP headers
        # that came in through a socket from the account server
        cached = {
            'status': 404,
            'bytes': '3333',
            'container_count': '234',
            'total_object_count': '10',
            'meta': {}
        }
        req = Request.blank("/v1/account/cont",
                            environ={'swift.cache': FakeCache(cached)})
        resp = get_account_info(req.environ, FakeApp())
        self.assertEqual(resp['status'], 404)
        self.assertEqual(resp['bytes'], 3333)
        self.assertEqual(resp['container_count'], 234)
        self.assertEqual(resp['meta'], {})
        self.assertEqual(resp['total_object_count'], 10)
Example #7
0
 def test_get_account_info_infocache(self):
     app = FakeApp()
     ic = {}
     req = Request.blank("/v1/a", environ={'swift.cache': FakeCache(),
                                           'swift.infocache': ic})
     get_account_info(req.environ, app)
     got_infocaches = [e['swift.infocache'] for e in app.captured_envs]
     self.assertEqual(1, len(got_infocaches))
     self.assertIs(ic, got_infocaches[0])
Example #8
0
 def test_get_account_info_infocache(self):
     app = FakeApp()
     ic = {}
     req = Request.blank("/v1/a", environ={'swift.cache': FakeCache(),
                                           'swift.infocache': ic})
     get_account_info(req.environ, app)
     got_infocaches = [e['swift.infocache'] for e in app.captured_envs]
     self.assertEqual(1, len(got_infocaches))
     self.assertIs(ic, got_infocaches[0])
Example #9
0
    def __init__(self, request, conf, app, logger):
        super(StorletProxyHandler, self).__init__(
            request, conf, app, logger)
        self.storlet_container = conf.get('storlet_container')
        self.storlet_dependency = conf.get('storlet_dependency')
        self.storlet_containers = [self.storlet_container,
                                   self.storlet_dependency]

        if not self.is_storlet_request:
            # This is not storlet-related request, so pass it
            raise NotStorletRequest()

        # In proxy server, storlet handler validate if storlet enabled
        # at the account, anyway
        account_meta = get_account_info(self.request.environ,
                                        self.app)['meta']
        storlets_enabled = account_meta.get('storlet-enabled',
                                            'False')
        if not config_true_value(storlets_enabled):
            self.logger.debug('Account disabled for storlets')
            raise HTTPBadRequest('Account disabled for storlets',
                                 request=self.request)

        if self.is_storlet_object_update:
            # TODO(takashi): We have to validate metadata in COPY case
            self._validate_registration(self.request)
            raise NotStorletExecution()
        else:
            # if self.is_storlet_execution
            self._setup_gateway()
Example #10
0
    def __call__(self, env, start_response):
        req = Request(env)
        # We want to check POST here
        # it can possibly have content_length > 0
        if not self.enforce_quota or req.method not in ("POST", "PUT", "COPY"):
            return self.app(env, start_response)
        account_info = get_account_info(req.environ, self.app,
                                        swift_source='litequota')
        if not account_info:
            return self.app(env, start_response)
        service_plan = assemble_from_partial(self.metadata_key,
                                             account_info['meta'])
        try:
            ver, account, container, obj = \
                req.split_path(2, 4, rest_with_last=True)
        except ValueError:
            return self.app(env, start_response)
        if not service_plan and req.method == 'PUT' and not obj:
            service_plan = self.set_serviceplan(req, account)
        if not service_plan:
            return self.app(env, start_response)
        try:
            service_plan = json.loads(service_plan)
        except ValueError:
            return self.app(env, start_response)

        if service_plan.get('storage', None):
            resp = self.apply_storage_quota(req, service_plan['storage'],
                                            account_info,
                                            ver, account, container, obj)
            if resp:
                return resp(env, start_response)
        return self.app(env, start_response)
Example #11
0
    def __init__(self, request, conf, gateway_conf, app, logger):
        super(StorletProxyHandler, self).__init__(
            request, conf, gateway_conf, app, logger)
        self.storlet_containers = [self.storlet_container,
                                   self.storlet_dependency]
        self.agent = 'ST'
        self.extra_sources = []

        # A very initial hook for blocking requests
        self._should_block(request)

        if not self.is_storlet_request:
            # This is not storlet-related request, so pass it
            raise NotStorletRequest()

        # In proxy server, storlet handler validate if storlet enabled
        # at the account, anyway
        account_meta = get_account_info(self.request.environ,
                                        self.app)['meta']
        storlets_enabled = account_meta.get('storlet-enabled', 'False')
        if not config_true_value(storlets_enabled):
            msg = 'Account disabled for storlets'
            self.logger.debug(msg)
            raise HTTPBadRequest(msg.encode('utf8'), request=self.request)

        if self.is_storlet_acl_update:
            self.acl_string = self._validate_acl_update(self.request)
        elif self.is_storlet_object_update:
            # TODO(takashi): We have to validate metadata in COPY case
            self._validate_registration(self.request)
            raise NotStorletExecution()
        elif self.is_storlet_execution:
            self._setup_gateway()
        else:
            raise NotStorletExecution()
Example #12
0
    def __call__(self, request):

        if request.method not in ("POST", "PUT"):
            return self.app

        try:
            request.split_path(2, 4, rest_with_last=True)
        except ValueError:
            return self.app

        new_quota = request.headers.get('X-Account-Meta-Quota-Bytes')
        remove_quota = request.headers.get('X-Remove-Account-Meta-Quota-Bytes')
        if remove_quota:
            new_quota = 0  # X-Remove dominates if both are present

        if request.environ.get('reseller_request') is True:
            if new_quota and not new_quota.isdigit():
                return HTTPBadRequest()
            return self.app

        # deny quota set for non-reseller
        if new_quota is not None:
            return HTTPForbidden()

        account_info = get_account_info(request.environ, self.app)
        if not account_info or not account_info['bytes']:
            return self.app
        new_size = int(account_info['bytes']) + (request.content_length or 0)
        quota = int(account_info['meta'].get('quota-bytes', -1))

        if 0 <= quota < new_size:
            return HTTPRequestEntityTooLarge()

        return self.app
Example #13
0
    def get_defaults(self, req, req_type, format_args):
        acct_sysmeta = get_account_info(req.environ, self.app)['sysmeta']
        if req_type == 'object':
            cont_sysmeta = get_container_info(req.environ, self.app)['sysmeta']
        else:
            cont_sysmeta = {}

        defaults = {}
        prefix = 'default-%s-' % req_type
        for src in (self.conf, acct_sysmeta, cont_sysmeta):
            for key, value in src.items():
                if not key.lower().startswith(prefix):
                    continue
                header_to_default = key[len(prefix):].lower()
                if header_to_default.startswith(BLACKLIST_PREFIXES):
                    continue
                if header_to_default in BLACKLIST:
                    continue
                if self.conf['use_formatting']:
                    try:
                        value = value.format(**format_args)
                    except KeyError:
                        # This user may not have specified the default;
                        # don't fail because of someone else
                        pass
                defaults[header_to_default] = value
        return defaults
    def __call__(self, env, start_response):
        req = Request(env)

        # TOREMOVE: when merged
        # if we are doing a post to update the locked value then alow it.
        if req.method == 'POST':
            for header in req.headers:
                if header.lower() == "x-account-meta-%s" % \
                        self.locked_header.lower():
                    return self.app(env, start_response)

        # check if we are in a method we want to disallow.
        if not req.method in self.denied_methods:
            return self.app(env, start_response)

        account_info = get_account_info(env,
                                        self.app,
                                        swift_source="LCK")
        if not account_info:
            return self.app(env, start_response)

        if 'meta' in account_info and self.locked_header in \
           account_info['meta'] and config_true_value(
               account_info['meta'][self.locked_header]):
            self.logger.debug(
                "[account_access] account locked for %s" %
                (str(req.remote_user)))
            env['swift.authorize'] = self.deny
        return self.app(env, start_response)
Example #15
0
    def __init__(self, request, conf, gateway_conf, app, logger):
        super(StorletProxyHandler, self).__init__(request, conf, gateway_conf, app, logger)
        self.storlet_containers = [self.storlet_container, self.storlet_dependency]
        self.agent = "ST"
        self.extra_sources = []

        # A very initial hook for blocking requests
        self._should_block(request)

        if not self.is_storlet_request:
            # This is not storlet-related request, so pass it
            raise NotStorletRequest()

        # In proxy server, storlet handler validate if storlet enabled
        # at the account, anyway
        account_meta = get_account_info(self.request.environ, self.app)["meta"]
        storlets_enabled = account_meta.get("storlet-enabled", "False")
        if not config_true_value(storlets_enabled):
            self.logger.debug("Account disabled for storlets")
            raise HTTPBadRequest("Account disabled for storlets", request=self.request)

        if self.is_storlet_acl_update:
            self.acl_string = self._validate_acl_update(self.request)
        elif self.is_storlet_object_update:
            # TODO(takashi): We have to validate metadata in COPY case
            self._validate_registration(self.request)
            raise NotStorletExecution()
        elif self.is_storlet_execution:
            self._setup_gateway()
        else:
            raise NotStorletExecution()
Example #16
0
 def POST(self, env):
     """Handle posts dealing with metadata alteration"""
     req = Request(env)
     conn = HTTPConnection('%s:%s' % (self.mds_ip, self.mds_port))
     headers = req.params
     version, acc, con, obj = split_path(req.path, 1, 4, True)
     if not con:
         try:
             info = get_account_info(env, self.app)
             if info:
                 stor_policy = info['storage_policy']
                 headers['storage_policy'] = stor_policy
         except:
             pass
     else:
         try:
             info = get_container_info(env, self.app)
             if info:
                 stor_policy = info['storage_policy']
                 headers['storage_policy'] = stor_policy
         except:
             pass
     conn.request('POST', req.path, headers=headers)
     resp = conn.getresponse()
     #confirm response then pass along the request
     return self.app
Example #17
0
 def POST(self, env):
     """Handle posts dealing with metadata alteration"""
     req = Request(env)
     conn = HTTPConnection('%s:%s' % (self.mds_ip, self.mds_port))
     headers = req.params
     version, acc, con, obj = split_path(req.path, 1, 4, True)
     if not con:
         try:
             info = get_account_info(env, self.app)
             if info:
                 stor_policy = info['storage_policy']
                 headers['storage_policy'] = stor_policy
         except:
             pass
     else:
         try:
             info = get_container_info(env, self.app)
             if info:
                 stor_policy = info['storage_policy']
                 headers['storage_policy'] = stor_policy
         except:
             pass
     conn.request('POST', req.path, headers=headers)
     resp = conn.getresponse()
     #confirm response then pass along the request
     return self.app
Example #18
0
    def get_defaults(self, req, req_type, format_args):
        acct_sysmeta = get_account_info(req.environ, self.app)['sysmeta']
        if req_type == 'object':
            cont_sysmeta = get_container_info(req.environ, self.app)['sysmeta']
        else:
            cont_sysmeta = {}

        defaults = {}
        prefix = 'default-%s-' % req_type
        for src in (self.conf, acct_sysmeta, cont_sysmeta):
            for key, value in src.items():
                if not key.lower().startswith(prefix):
                    continue
                header_to_default = key[len(prefix):].lower()
                if header_to_default.startswith(BLACKLIST_PREFIXES):
                    continue
                if header_to_default in BLACKLIST:
                    continue
                if self.conf['use_formatting']:
                    try:
                        value = value.format(**format_args)
                    except KeyError:
                        # This user may not have specified the default;
                        # don't fail because of someone else
                        pass
                defaults[header_to_default] = value
        return defaults
Example #19
0
    def __call__(self, env, start_response):
        req = Request(env)
        try:
            version, account, container, obj = req.split_path(
                2, 4, rest_with_last=True)
            is_swifty_request = valid_api_version(version)
        except ValueError:
            is_swifty_request = False

        if not is_swifty_request:
            return self.app(env, start_response)

        if not obj:
            typ = 'Container' if container else 'Account'
            client_header = 'X-%s-Rfc-Compliant-Etags' % typ
            sysmeta_header = 'X-%s-Sysmeta-Rfc-Compliant-Etags' % typ
            if client_header in req.headers:
                if req.headers[client_header]:
                    req.headers[sysmeta_header] = config_true_value(
                        req.headers[client_header])
                else:
                    req.headers[sysmeta_header] = ''
            if req.headers.get(client_header.replace('X-', 'X-Remove-', 1)):
                req.headers[sysmeta_header] = ''

            def translating_start_response(status, headers, exc_info=None):
                return start_response(
                    status,
                    [(client_header if h.title() == sysmeta_header else h, v)
                     for h, v in headers], exc_info)

            return self.app(env, translating_start_response)

        container_info = get_container_info(env, self.app, 'EQ')
        if not container_info or not is_success(container_info['status']):
            return self.app(env, start_response)

        flag = container_info.get('sysmeta', {}).get('rfc-compliant-etags')
        if flag is None:
            account_info = get_account_info(env, self.app, 'EQ')
            if not account_info or not is_success(account_info['status']):
                return self.app(env, start_response)

            flag = account_info.get('sysmeta', {}).get('rfc-compliant-etags')

        if flag is None:
            flag = self.conf.get('enable_by_default', 'false')

        if not config_true_value(flag):
            return self.app(env, start_response)

        status, headers, resp_iter = req.call_application(self.app)

        headers = [(header,
                    value) if header.lower() != 'etag' or (value.startswith(
                        ('"', 'W/"')) and value.endswith('"')) else
                   (header, '"%s"' % value) for header, value in headers]

        start_response(status, headers)
        return resp_iter
Example #20
0
 def test_get_account_info_swift_source(self):
     req = Request.blank("/v1/a", environ={'swift.cache': FakeCache({})})
     with patch(
             'swift.proxy.controllers.base.'
             '_prepare_pre_auth_info_request', FakeRequest):
         resp = get_account_info(req.environ, 'a', swift_source='MC')
     self.assertEquals(resp['meta']['fakerequest-swift-source'], 'MC')
Example #21
0
    def _get_keys(self, env):
        """
        Returns the X-[Account|Container]-Meta-Temp-URL-Key[-2] header values
        for the account or container, or an empty list if none are set. Each
        value comes as a 2-tuple (key, scope), where scope is either
        CONTAINER_SCOPE or ACCOUNT_SCOPE.

        Returns 0-4 elements depending on how many keys are set in the
        account's or container's metadata.

        :param env: The WSGI environment for the request.
        :returns: [
            (X-Account-Meta-Temp-URL-Key str value, ACCOUNT_SCOPE) if set,
            (X-Account-Meta-Temp-URL-Key-2 str value, ACCOUNT_SCOPE if set,
            (X-Container-Meta-Temp-URL-Key str value, CONTAINER_SCOPE) if set,
            (X-Container-Meta-Temp-URL-Key-2 str value, CONTAINER_SCOPE if set,
        ]
        """
        account_info = get_account_info(env, self.app, swift_source='TU')
        account_keys = get_tempurl_keys_from_metadata(account_info['meta'])

        container_info = get_container_info(env, self.app, swift_source='TU')
        container_keys = get_tempurl_keys_from_metadata(
            container_info.get('meta', []))

        return ([(ak, ACCOUNT_SCOPE) for ak in account_keys] +
                [(ck, CONTAINER_SCOPE) for ck in container_keys])
Example #22
0
    def account_acls(self, req):
        """
        Return a dict of ACL data from the account server via get_account_info.

        Auth systems may define their own format, serialization, structure,
        and capabilities implemented in the ACL headers and persisted in the
        sysmeta data.  However, auth systems are strongly encouraged to be
        interoperable with Tempauth.

        Account ACLs are set and retrieved via the header
           X-Account-Access-Control

        For header format and syntax, see:
         * :func:`swift.common.middleware.acl.parse_acl()`
         * :func:`swift.common.middleware.acl.format_acl()`
        """
        info = get_account_info(req.environ, self.app, swift_source='TA')
        try:
            acls = acls_from_account_info(info)
        except ValueError as e1:
            self.logger.warning("Invalid ACL stored in metadata: %r" % e1)
            return None
        except NotImplementedError as e2:
            self.logger.warning(
                "ACL version exceeds middleware version: %r"
                % e2)
            return None
        return acls
Example #23
0
    def _get_keys(self, env):
        """
        Returns the X-[Account|Container]-Meta-Temp-URL-Key[-2] header values
        for the account or container, or an empty list if none are set.

        Returns 0-4 elements depending on how many keys are set in the
        account's or container's metadata.

        Also validate that the request
        path indicates a valid container; if not, no keys will be returned.

        :param env: The WSGI environment for the request.
        :returns: list of tempurl keys
        """
        parts = env['PATH_INFO'].split('/', 4)
        if len(parts) < 4 or parts[0] or not valid_api_version(parts[1]) \
                or not parts[2] or not parts[3]:
            return []

        account_info = get_account_info(env, self.app, swift_source='FP')
        account_keys = get_tempurl_keys_from_metadata(account_info['meta'])

        container_info = get_container_info(env, self.app, swift_source='FP')
        container_keys = get_tempurl_keys_from_metadata(
            container_info.get('meta', []))

        return account_keys + container_keys
    def _get_keys(self, env):
        """
        Returns the X-[Account|Container]-Meta-Temp-URL-Key[-2] header values
        for the account or container, or an empty list if none are set.

        Returns 0-4 elements depending on how many keys are set in the
        account's or container's metadata.

        Also validate that the request
        path indicates a valid container; if not, no keys will be returned.

        :param env: The WSGI environment for the request.
        :returns: list of tempurl keys
        """
        parts = env["PATH_INFO"].split("/", 4)
        if len(parts) < 4 or parts[0] or parts[1] != "v1" or not parts[2] or not parts[3]:
            return []

        account_info = get_account_info(env, self.app, swift_source="FP")
        account_keys = get_tempurl_keys_from_metadata(account_info["meta"])

        container_info = get_container_info(env, self.app, swift_source="FP")
        container_keys = get_tempurl_keys_from_metadata(container_info.get("meta", []))

        return account_keys + container_keys
Example #25
0
 def test_get_account_info_no_cache(self):
     app = FakeApp()
     req = Request.blank("/v1/AUTH_account",
                         environ={'swift.cache': FakeCache({})})
     resp = get_account_info(req.environ, app)
     self.assertEqual(resp['bytes'], 6666)
     self.assertEqual(resp['total_object_count'], 1000)
Example #26
0
 def test_get_account_info_no_cache(self):
     app = FakeApp()
     req = Request.blank("/v1/AUTH_account",
                         environ={'swift.cache': FakeCache({})})
     resp = get_account_info(req.environ, app)
     self.assertEqual(resp['bytes'], 6666)
     self.assertEqual(resp['total_object_count'], 1000)
Example #27
0
    def __call__(self, request):
       
        if request.method not in ("PUT","COPY"):
            return self.app

        try:
            split_path(request.path,2, 4, rest_with_last=True)
        except ValueError:
            return self.app

        new_quota = request.headers.get('X-Account-Meta-Quota-Bytes')
        if new_quota:
            if not new_quota.isdigit():
                return jresponse('-1', 'bad request', request, 400)
            return self.app

        account_info = get_account_info(request.environ, self.app)
        new_size = int(account_info['bytes']) + (request.content_length or 0)
        quota = int(account_info['meta'].get('quota-bytes', -1))

        if 0 <= quota < new_size:
            respbody='Your request is too large.'
            return jresponse('-1', respbody, request,413)

        return self.app
Example #28
0
    def account_acls(self, req):
        """
        Return a dict of ACL data from the account server via get_account_info.

        Auth systems may define their own format, serialization, structure,
        and capabilities implemented in the ACL headers and persisted in the
        sysmeta data.  However, auth systems are strongly encouraged to be
        interoperable with Tempauth.

        Account ACLs are set and retrieved via the header
           X-Account-Access-Control

        For header format and syntax, see:
         * :func:`swift.common.middleware.acl.parse_acl()`
         * :func:`swift.common.middleware.acl.format_acl()`
        """
        info = get_account_info(req.environ, self.app, swift_source='TA')
        try:
            acls = acls_from_account_info(info)
        except ValueError as e1:
            self.logger.warn("Invalid ACL stored in metadata: %r" % e1)
            return None
        except NotImplementedError as e2:
            self.logger.warn("ACL version exceeds middleware version: %r" % e2)
            return None
        return acls
Example #29
0
    def __call__(self, request):

        if request.method not in ("POST", "PUT"):
            return self.app

        try:
            request.split_path(2, 4, rest_with_last=True)
        except ValueError:
            return self.app

        new_quota = request.headers.get('X-Account-Meta-Quota-Bytes')

        if request.environ.get('reseller_request') is True:
            if new_quota and not new_quota.isdigit():
                return HTTPBadRequest()
            return self.app

        # deny quota set for non-reseller
        if new_quota is not None:
            return HTTPForbidden()

        account_info = get_account_info(request.environ, self.app)
        if not account_info or not account_info['bytes']:
            return self.app
        new_size = int(account_info['bytes']) + (request.content_length or 0)
        quota = int(account_info['meta'].get('quota-bytes', -1))

        if 0 <= quota < new_size:
            return HTTPRequestEntityTooLarge()

        return self.app
Example #30
0
 def is_account_storlet_enabled(self):
     account_meta = get_account_info(self.request.environ, self.app)['meta']
     storlets_enabled = account_meta.get('storlet-enabled', 'False')
     if not config_true_value(storlets_enabled):
         self.logger.debug('Vertigo - Account disabled for storlets')
         raise HTTPBadRequest('Vertigo - Error: Account disabled for'
                              ' storlets.\n', request=self.request)
     return True
Example #31
0
    def test_get_deleted_account_410(self):
        resp_headers = {'x-account-status': 'deleted'}

        req = Request.blank('/v1/a')
        with mock.patch('swift.proxy.controllers.base.http_connect',
                        fake_http_connect(404, headers=resp_headers)):
            info = get_account_info(req.environ, self.app)
        self.assertEqual(410, info.get('status'))
Example #32
0
 def test_get_account_info_no_cache(self):
     swift.proxy.controllers.base.make_pre_authed_request = FakeRequest
     req = Request.blank("/v1/AUTH_account",
                         environ={'swift.cache': FakeCache({})})
     resp = get_account_info(req.environ, 'xxx')
     print resp
     self.assertEquals(resp['bytes'], 6666)
     self.assertEquals(resp['total_object_count'], 1000)
Example #33
0
 def is_account_storlet_enabled(self):
     account_meta = get_account_info(self.request.environ, self.app)['meta']
     storlets_enabled = account_meta.get('storlet-enabled', 'False')
     if not config_true_value(storlets_enabled):
         self.logger.debug('Vertigo - Account disabled for storlets')
         raise HTTPBadRequest('Vertigo - Error: Account disabled for'
                              ' storlets.\n', request=self.request)
     return True
Example #34
0
 def test_get_account_info_env(self):
     cache_key = get_cache_key("account")
     req = Request.blank(
         "/v1/account",
         environ={'swift.infocache': {cache_key: {'bytes': 3867}},
                  'swift.cache': FakeCache({})})
     resp = get_account_info(req.environ, 'xxx')
     self.assertEqual(resp['bytes'], 3867)
Example #35
0
 def test_get_account_info_env(self):
     cache_key = get_account_memcache_key("account")
     env_key = 'swift.%s' % cache_key
     req = Request.blank("/v1/account",
                         environ={env_key: {'bytes': 3867},
                                  'swift.cache': FakeCache({})})
     resp = get_account_info(req.environ, 'xxx')
     self.assertEquals(resp['bytes'], 3867)
Example #36
0
 def test_get_account_info_no_cache(self):
     req = Request.blank("/v1/AUTH_account",
                         environ={'swift.cache': FakeCache({})})
     with patch('swift.proxy.controllers.base.'
                '_prepare_pre_auth_info_request', FakeRequest):
         resp = get_account_info(req.environ, 'xxx')
     self.assertEquals(resp['bytes'], 6666)
     self.assertEquals(resp['total_object_count'], 1000)
    def test_get_deleted_account_410(self):
        resp_headers = {'x-account-status': 'deleted'}

        req = Request.blank('/v1/a')
        with mock.patch('swift.proxy.controllers.base.http_connect',
                        fake_http_connect(404, headers=resp_headers)):
            info = get_account_info(req.environ, self.app)
        self.assertEqual(410, info.get('status'))
Example #38
0
 def test_get_account_info_env(self):
     cache_key = get_cache_key("account")
     req = Request.blank(
         "/v1/account",
         environ={'swift.infocache': {cache_key: {'bytes': 3867}},
                  'swift.cache': FakeCache({})})
     resp = get_account_info(req.environ, 'xxx')
     self.assertEqual(resp['bytes'], 3867)
Example #39
0
 def test_get_account_info_env(self):
     cache_key = get_account_memcache_key("account")
     env_key = 'swift.%s' % cache_key
     req = Request.blank("/v1/account",
                         environ={env_key: {'bytes': 3867},
                                  'swift.cache': FakeCache({})})
     resp = get_account_info(req.environ, 'xxx')
     self.assertEquals(resp['bytes'], 3867)
Example #40
0
 def test_get_account_info_no_cache(self):
     swift.proxy.controllers.base.make_pre_authed_request = FakeRequest
     req = Request.blank("/v1/AUTH_account",
                         environ={'swift.cache': FakeCache({})})
     resp = get_account_info(req.environ, 'xxx')
     print resp
     self.assertEquals(resp['bytes'], 6666)
     self.assertEquals(resp['total_object_count'], 1000)
Example #41
0
    def handle_ratelimit(self, req, account_name, container_name, obj_name):
        """
        Performs rate limiting and account white/black listing.  Sleeps
        if necessary. If self.memcache_client is not set, immediately returns
        None.

        :param account_name: account name from path
        :param container_name: container name from path
        :param obj_name: object name from path
        """
        if not self.memcache_client:
            return None

        try:
            account_info = get_account_info(req.environ, self.app,
                                            swift_source='RL')
            account_global_ratelimit = \
                account_info.get('sysmeta', {}).get('global-write-ratelimit')
        except ValueError:
            account_global_ratelimit = None

        if account_name in self.ratelimit_whitelist or \
                account_global_ratelimit == 'WHITELIST':
            return None

        if account_name in self.ratelimit_blacklist or \
                account_global_ratelimit == 'BLACKLIST':
            self.logger.error(_('Returning 497 because of blacklisting: %s'),
                              account_name)
            eventlet.sleep(self.BLACK_LIST_SLEEP)
            return Response(status='497 Blacklisted',
                            body='Your account has been blacklisted',
                            request=req)

        for key, max_rate in self.get_ratelimitable_key_tuples(
                req, account_name, container_name=container_name,
                obj_name=obj_name, global_ratelimit=account_global_ratelimit):
            try:
                need_to_sleep = self._get_sleep_time(key, max_rate)
                if self.log_sleep_time_seconds and \
                        need_to_sleep > self.log_sleep_time_seconds:
                    self.logger.warning(
                        _("Ratelimit sleep log: %(sleep)s for "
                          "%(account)s/%(container)s/%(object)s"),
                        {'sleep': need_to_sleep, 'account': account_name,
                         'container': container_name, 'object': obj_name})
                if need_to_sleep > 0:
                    eventlet.sleep(need_to_sleep)
            except MaxSleepTimeHitError as e:
                self.logger.error(
                    _('Returning 498 for %(meth)s to %(acc)s/%(cont)s/%(obj)s '
                      '. Ratelimit (Max Sleep) %(e)s'),
                    {'meth': req.method, 'acc': account_name,
                     'cont': container_name, 'obj': obj_name, 'e': str(e)})
                error_resp = Response(status='498 Rate Limited',
                                      body='Slow down', request=req)
                return error_resp
        return None
Example #42
0
    def handle_ratelimit(self, req, account_name, container_name, obj_name):
        """
        Performs rate limiting and account white/black listing.  Sleeps
        if necessary. If self.memcache_client is not set, immediately returns
        None.

        :param account_name: account name from path
        :param container_name: container name from path
        :param obj_name: object name from path
        """
        if not self.memcache_client:
            return None

        try:
            account_info = get_account_info(req.environ, self.app,
                                            swift_source='RL')
            account_global_ratelimit = \
                account_info.get('sysmeta', {}).get('global-write-ratelimit')
        except ValueError:
            account_global_ratelimit = None

        if account_name in self.ratelimit_whitelist or \
                account_global_ratelimit == 'WHITELIST':
            return None

        if account_name in self.ratelimit_blacklist or \
                account_global_ratelimit == 'BLACKLIST':
            self.logger.error(_('Returning 497 because of blacklisting: %s'),
                              account_name)
            eventlet.sleep(self.BLACK_LIST_SLEEP)
            return Response(status='497 Blacklisted',
                            body='Your account has been blacklisted',
                            request=req)

        for key, max_rate in self.get_ratelimitable_key_tuples(
                req, account_name, container_name=container_name,
                obj_name=obj_name, global_ratelimit=account_global_ratelimit):
            try:
                need_to_sleep = self._get_sleep_time(key, max_rate)
                if self.log_sleep_time_seconds and \
                        need_to_sleep > self.log_sleep_time_seconds:
                    self.logger.warning(
                        _("Ratelimit sleep log: %(sleep)s for "
                          "%(account)s/%(container)s/%(object)s"),
                        {'sleep': need_to_sleep, 'account': account_name,
                         'container': container_name, 'object': obj_name})
                if need_to_sleep > 0:
                    eventlet.sleep(need_to_sleep)
            except MaxSleepTimeHitError as e:
                self.logger.error(
                    _('Returning 498 for %(meth)s to %(acc)s/%(cont)s/%(obj)s '
                      '. Ratelimit (Max Sleep) %(e)s'),
                    {'meth': req.method, 'acc': account_name,
                     'cont': container_name, 'obj': obj_name, 'e': str(e)})
                error_resp = Response(status='498 Rate Limited',
                                      body='Slow down', request=req)
                return error_resp
        return None
    def __call__(self, request):

        if request.method not in ("POST", "PUT"):
            return self.app

        try:
            ver, account, container, obj = request.split_path(
                2, 4, rest_with_last=True)
        except ValueError:
            return self.app

        if not container:
            # account request, so we pay attention to the quotas
            new_quota = request.headers.get('X-Account-Meta-Quota-Bytes')
            remove_quota = request.headers.get(
                'X-Remove-Account-Meta-Quota-Bytes')
        else:
            # container or object request; even if the quota headers are set
            # in the request, they're meaningless
            new_quota = remove_quota = None

        if remove_quota:
            new_quota = 0  # X-Remove dominates if both are present

        if request.environ.get('reseller_request') is True:
            if new_quota and not new_quota.isdigit():
                return HTTPBadRequest()
            return self.app

        # deny quota set for non-reseller
        if new_quota is not None:
            return HTTPForbidden()

        if obj and request.method == "POST" or not obj:
            return self.app

        copy_from = request.headers.get('X-Copy-From')
        content_length = (request.content_length or 0)

        if obj and copy_from:
            path = '/' + ver + '/' + account + '/' + copy_from.lstrip('/')
            object_info = get_object_info(request.environ, self.app, path)
            if not object_info or not object_info['length']:
                content_length = 0
            else:
                content_length = int(object_info['length'])

        account_info = get_account_info(request.environ, self.app)
        if not account_info or not account_info['bytes']:
            return self.app

        new_size = int(account_info['bytes']) + content_length
        quota = int(account_info['meta'].get('quota-bytes', -1))

        if 0 <= quota < new_size:
            return HTTPRequestEntityTooLarge()

        return self.app
Example #44
0
 def test_get_account_info_no_cache(self):
     req = Request.blank("/v1/AUTH_account",
                         environ={'swift.cache': FakeCache({})})
     with patch(
             'swift.proxy.controllers.base.'
             '_prepare_pre_auth_info_request', FakeRequest):
         resp = get_account_info(req.environ, 'xxx')
     self.assertEquals(resp['bytes'], 6666)
     self.assertEquals(resp['total_object_count'], 1000)
Example #45
0
 def test_get_account_info_cache(self):
     swift.proxy.controllers.base.make_pre_authed_request = FakeRequest
     cached = {'status': 404, 'bytes': 3333, 'total_object_count': 10}
     req = Request.blank("/v1/account/cont",
                         environ={'swift.cache': FakeCache(cached)})
     resp = get_account_info(req.environ, 'xxx')
     self.assertEquals(resp['bytes'], 3333)
     self.assertEquals(resp['total_object_count'], 10)
     self.assertEquals(resp['status'], 404)
Example #46
0
    def test_get_account_info_cache(self):
        # The original test that we prefer to preserve
        cached = {"status": 404, "bytes": 3333, "total_object_count": 10}
        req = Request.blank("/v1/account/cont", environ={"swift.cache": FakeCache(cached)})
        resp = get_account_info(req.environ, FakeApp())
        self.assertEquals(resp["bytes"], 3333)
        self.assertEquals(resp["total_object_count"], 10)
        self.assertEquals(resp["status"], 404)

        # Here is a more realistic test
        cached = {"status": 404, "bytes": "3333", "container_count": "234", "total_object_count": "10", "meta": {}}
        req = Request.blank("/v1/account/cont", environ={"swift.cache": FakeCache(cached)})
        resp = get_account_info(req.environ, FakeApp())
        self.assertEquals(resp["status"], 404)
        self.assertEquals(resp["bytes"], "3333")
        self.assertEquals(resp["container_count"], 234)
        self.assertEquals(resp["meta"], {})
        self.assertEquals(resp["total_object_count"], "10")
Example #47
0
    def get_ratelimitable_key_tuples(self, req, account_name,
                                     container_name=None, obj_name=None):
        """
        Returns a list of key (used in memcache), ratelimit tuples. Keys
        should be checked in order.

        :param req: swob request
        :param account_name: account name from path
        :param container_name: container name from path
        :param obj_name: object name from path
        """
        keys = []
        # COPYs are not limited
        if self.account_ratelimit and \
                account_name and container_name and not obj_name and \
                req.method in ('PUT', 'DELETE'):
            keys.append(("ratelimit/%s" % account_name,
                         self.account_ratelimit))

        if account_name and container_name and obj_name and \
                req.method in ('PUT', 'DELETE', 'POST', 'COPY'):
            container_size = self.get_container_size(
                account_name, container_name)
            container_rate = get_maxrate(
                self.container_ratelimits, container_size)
            if container_rate:
                keys.append((
                    "ratelimit/%s/%s" % (account_name, container_name),
                    container_rate))

        if account_name and container_name and not obj_name and \
                req.method == 'GET':
            container_size = self.get_container_size(
                account_name, container_name)
            container_rate = get_maxrate(
                self.container_listing_ratelimits, container_size)
            if container_rate:
                keys.append((
                    "ratelimit_listing/%s/%s" % (account_name, container_name),
                    container_rate))

        if account_name and req.method in ('PUT', 'DELETE', 'POST', 'COPY'):
            account_info = get_account_info(req.environ, self.app)
            account_global_ratelimit = \
                account_info.get('sysmeta', {}).get('global-write-ratelimit')
            if account_global_ratelimit:
                try:
                    account_global_ratelimit = float(account_global_ratelimit)
                    if account_global_ratelimit > 0:
                        keys.append((
                            "ratelimit/global-write/%s" % account_name,
                            account_global_ratelimit))
                except ValueError:
                    pass

        return keys
Example #48
0
    def __call__(self, request):

        if request.method not in ("POST", "PUT"):
            return self.app

        try:
            ver, account, container, obj = request.split_path(2, 4, rest_with_last=True)
        except ValueError:
            return self.app

        if not container:
            # account request, so we pay attention to the quotas
            new_quota = request.headers.get("X-Account-Meta-Quota-Bytes")
            remove_quota = request.headers.get("X-Remove-Account-Meta-Quota-Bytes")
        else:
            # container or object request; even if the quota headers are set
            # in the request, they're meaningless
            new_quota = remove_quota = None

        if remove_quota:
            new_quota = 0  # X-Remove dominates if both are present

        if request.environ.get("reseller_request") is True:
            if new_quota and not new_quota.isdigit():
                return HTTPBadRequest()
            return self.app

        # deny quota set for non-reseller
        if new_quota is not None:
            return HTTPForbidden()

        if obj and request.method == "POST" or not obj:
            return self.app

        copy_from = request.headers.get("X-Copy-From")
        content_length = request.content_length or 0

        if obj and copy_from:
            path = "/" + ver + "/" + account + "/" + copy_from.lstrip("/")
            object_info = get_object_info(request.environ, self.app, path)
            if not object_info or not object_info["length"]:
                content_length = 0
            else:
                content_length = int(object_info["length"])

        account_info = get_account_info(request.environ, self.app)
        if not account_info or not account_info["bytes"]:
            return self.app

        new_size = int(account_info["bytes"]) + content_length
        quota = int(account_info["meta"].get("quota-bytes", -1))

        if 0 <= quota < new_size:
            return HTTPRequestEntityTooLarge()

        return self.app
Example #49
0
    def is_account_crystal_enabled(self):
        account_meta = get_account_info(self.request.environ,
                                        self.app)['meta']
        crystal_enabled = account_meta.get('crystal-enabled',
                                           'False')

        if not config_true_value(crystal_enabled):
            return False

        return True
Example #50
0
    def is_account_storlet_enabled(self):
        account_meta = get_account_info(self.request.environ,
                                        self.app)['meta']
        storlets_enabled = account_meta.get('storlet-enabled',
                                            'False')

        if not config_true_value(storlets_enabled):
            return False

        return True
    def is_account_storlet_enabled(self):
        account_meta = get_account_info(self.request.environ,
                                        self.app)['meta']
        storlets_enabled = account_meta.get('storlet-enabled',
                                            'False')

        if not config_true_value(storlets_enabled):
            return True # TODO: CHANGE TO FALSE

        return True
Example #52
0
    def test_get_account_info_cache(self):
        # The original test that we prefer to preserve
        cached = {"status": 404, "bytes": 3333, "total_object_count": 10}
        req = Request.blank("/v1/account/cont", environ={"swift.cache": FakeCache(cached)})
        with patch("swift.proxy.controllers.base." "_prepare_pre_auth_info_request", FakeRequest):
            resp = get_account_info(req.environ, "xxx")
        self.assertEquals(resp["bytes"], 3333)
        self.assertEquals(resp["total_object_count"], 10)
        self.assertEquals(resp["status"], 404)

        # Here is a more realistic test
        cached = {"status": 404, "bytes": "3333", "container_count": "234", "total_object_count": "10", "meta": {}}
        req = Request.blank("/v1/account/cont", environ={"swift.cache": FakeCache(cached)})
        with patch("swift.proxy.controllers.base." "_prepare_pre_auth_info_request", FakeRequest):
            resp = get_account_info(req.environ, "xxx")
        self.assertEquals(resp["status"], 404)
        self.assertEquals(resp["bytes"], "3333")
        self.assertEquals(resp["container_count"], 234)
        self.assertEquals(resp["meta"], {})
        self.assertEquals(resp["total_object_count"], "10")
Example #53
0
 def test_get_account_info_cache(self):
     swift.proxy.controllers.base.make_pre_authed_request = FakeRequest
     cached = {'status': 404,
               'bytes': 3333,
               'total_object_count': 10}
     req = Request.blank("/v1/account/cont",
                         environ={'swift.cache': FakeCache(cached)})
     resp = get_account_info(req.environ, 'xxx')
     self.assertEquals(resp['bytes'], 3333)
     self.assertEquals(resp['total_object_count'], 10)
     self.assertEquals(resp['status'], 404)
Example #54
0
    def is_proxy_fs(self, env):
        if 'pfs.is_bimodal' in env:
            return env['pfs.is_bimodal']

        parts = env['PATH_INFO'].split('/', 3)
        if len(parts) < 3 or parts[1] not in ('v1', 'v1.0'):
            # If it's not a swift request, it can't be a ProxyFS request
            return False

        account_info = get_account_info(env, self.base_app, swift_source='')
        # ignore status; rely on something elsewhere in the pipeline
        # to propagate the error
        return utils.config_true_value(account_info["sysmeta"].get(
            'proxyfs-bimodal'))
Example #55
0
    def is_enabled_for(self, env):
        """
        Whether an account or container has meta-data to opt out of undelete
        protection
        """
        sysmeta_c = get_container_info(env, self.app)['sysmeta']
        # Container info gets & caches account info, so this is basically free
        sysmeta_a = get_account_info(env, self.app)['sysmeta']

        enabled = sysmeta_c.get(SYSMETA_UNDELETE_ENABLED)
        if enabled is None:
            enabled = sysmeta_a.get(SYSMETA_UNDELETE_ENABLED,
                                    self.enable_by_default)
        return utils.config_true_value(enabled)
Example #56
0
    def _get_keys(self, env):
        """
        Fetch the tempurl keys for the account. Also validate that the request
        path indicates a valid container; if not, no keys will be returned.

        :param env: The WSGI environment for the request.
        :returns: list of tempurl keys
        """
        parts = env['PATH_INFO'].split('/', 4)
        if len(parts) < 4 or parts[0] or parts[1] != 'v1' or not parts[2] or \
                not parts[3]:
            return []

        account_info = get_account_info(env, self.app, swift_source='FP')
        return get_tempurl_keys_from_metadata(account_info['meta'])
Example #57
0
    def _get_keys(self, env, account):
        """
        Returns the X-Account-Meta-Temp-URL-Key[-2] header values for the
        account, or an empty list if none is set.

        Returns 0, 1, or 2 elements depending on how many keys are set
        in the account's metadata.

        :param env: The WSGI environment for the request.
        :param account: Account str.
        :returns: [X-Account-Meta-Temp-URL-Key str value if set,
                   X-Account-Meta-Temp-URL-Key-2 str value if set]
        """
        account_info = get_account_info(env, self.app, swift_source='TU')
        return get_tempurl_keys_from_metadata(account_info['meta'])