Merge account policy in api. Document.
authorAntony Chazapis <chazapis@gmail.com>
Thu, 13 Oct 2011 16:42:14 +0000 (19:42 +0300)
committerAntony Chazapis <chazapis@gmail.com>
Thu, 13 Oct 2011 16:42:14 +0000 (19:42 +0300)
Refs #1165
Refs #1167

docs/source/devguide.rst
pithos/api/functions.py
pithos/api/util.py
pithos/backends/modular.py
pithos/middleware/auth.py

index c6ccebe..7f3e2f6 100644 (file)
@@ -25,12 +25,13 @@ Document Revisions
 =========================  ================================
 Revision                   Description
 =========================  ================================
-0.7 (Oct 4, 2011)          Suggest upload/download methods using hashmaps.
+0.7 (Oct 13, 2011)         Suggest upload/download methods using hashmaps.
 \                          Propose syncing algorithm.
 \                          Support cross-account object copy and move.
 \                          Pass token as a request parameter when using ``POST`` via an HTML form.
 \                          Optionally use source account to update object from another object.
 \                          Use container ``POST`` to upload missing blocks of data.
+\                          Report policy in account headers.
 0.6 (Sept 13, 2011)        Reply with Merkle hash as the ETag when updating objects.
 \                          Include version id in object replace/change replies.
 \                          Change conflict (409) replies format to text.
@@ -219,12 +220,10 @@ Cross-user requests are not allowed to use ``until`` and only include the accoun
 Reply Header Name           Value
 ==========================  =====================
 X-Account-Container-Count   The total number of containers
-X-Account-Object-Count      The total number of objects (**TBD**)
 X-Account-Bytes-Used        The total number of bytes stored
-X-Account-Bytes-Remaining   The total number of bytes remaining
-X-Account-Last-Login        The last login (**TBD**)
 X-Account-Until-Timestamp   The last account modification date until the timestamp provided
 X-Account-Group-*           Optional user defined groups
+X-Account-Policy-*          Account behavior and limits
 X-Account-Meta-*            Optional user defined metadata
 Last-Modified               The last account modification date (regardless of ``until``)
 ==========================  =====================
@@ -964,7 +963,7 @@ List of differences from the OOS API:
 * Support for ``X-Account-Meta-*`` style headers at the account level. Use ``POST`` to update.
 * Support for ``X-Container-Meta-*`` style headers at the container level. Can be set when creating via ``PUT``. Use ``POST`` to update.
 * Header ``X-Container-Object-Meta`` at the container level and parameter ``meta`` in container listings. (**TBD**)
-* Container policies to manage behavior and limits.
+* Account and container policies to manage behavior and limits. Container behavior overrides account settings. Account quota sets the maximum bytes limit, regardless of container values.
 * Headers ``X-Container-Block-*`` at the container level, exposing the underlying storage characteristics.
 * All metadata replies, at all levels, include latest modification information.
 * At all levels, a ``HEAD`` or ``GET`` request may use ``If-Modified-Since`` and ``If-Unmodified-Since`` headers.
index 00e341f..8255772 100644 (file)
@@ -186,13 +186,14 @@ def account_meta(request, v_account):
     try:
         meta = request.backend.get_account_meta(request.user, v_account, until)
         groups = request.backend.get_account_groups(request.user, v_account)
+        policy = request.backend.get_account_policy(request.user, v_account)
     except NotAllowedError:
         raise Unauthorized('Access denied')
     
     validate_modification_preconditions(request, meta)
     
     response = HttpResponse(status=204)
-    put_account_headers(response, request.quota, meta, groups)
+    put_account_headers(response, meta, groups, policy)
     return response
 
 @api_method('POST')
@@ -234,13 +235,14 @@ def container_list(request, v_account):
     try:
         meta = request.backend.get_account_meta(request.user, v_account, until)
         groups = request.backend.get_account_groups(request.user, v_account)
+        policy = request.backend.get_account_policy(request.user, v_account)
     except NotAllowedError:
         raise Unauthorized('Access denied')
     
     validate_modification_preconditions(request, meta)
     
     response = HttpResponse()
-    put_account_headers(response, request.quota, meta, groups)
+    put_account_headers(response, meta, groups, policy)
     
     marker = request.GET.get('marker')
     limit = get_int_parameter(request.GET.get('limit'))
@@ -329,11 +331,6 @@ def container_create(request, v_account, v_container):
     #                       badRequest (400)
     
     meta, policy = get_container_headers(request)
-    try:
-        if policy and int(policy.get('quota', 0)) > request.quota:
-            policy['quota'] = request.quota
-    except:
-        raise BadRequest('Invalid quota header')
     
     try:
         request.backend.put_container(request.user, v_account, v_container, policy)
@@ -380,11 +377,6 @@ def container_update(request, v_account, v_container):
         replace = False
     if policy:
         try:
-            if int(policy.get('quota', 0)) > request.quota:
-                policy['quota'] = request.quota
-        except:
-            raise BadRequest('Invalid quota header')
-        try:
             request.backend.update_container_policy(request.user, v_account,
                                                 v_container, policy, replace)
         except NotAllowedError:
index 50f6e27..bff9fc3 100644 (file)
@@ -119,13 +119,11 @@ def get_account_headers(request):
             groups[n].remove('')
     return meta, groups
 
-def put_account_headers(response, quota, meta, groups):
+def put_account_headers(response, meta, groups, policy):
     if 'count' in meta:
         response['X-Account-Container-Count'] = meta['count']
     if 'bytes' in meta:
         response['X-Account-Bytes-Used'] = meta['bytes']
-        if quota:
-            response['X-Account-Bytes-Remaining'] = quota - meta['bytes']
     response['Last-Modified'] = http_date(int(meta['modified']))
     for k in [x for x in meta.keys() if x.startswith('X-Account-Meta-')]:
         response[smart_str(k, strings_only=True)] = smart_str(meta[k], strings_only=True)
@@ -136,7 +134,9 @@ def put_account_headers(response, quota, meta, groups):
         k = format_header_key('X-Account-Group-' + k)
         v = smart_str(','.join(v), strings_only=True)
         response[k] = v
-    
+    for k, v in policy.iteritems():
+        response[smart_str(format_header_key('X-Account-Policy-' + k), strings_only=True)] = smart_str(v, strings_only=True)
+
 def get_container_headers(request):
     meta = get_header_prefix(request, 'X-Container-Meta-')
     policy = dict([(k[19:].lower(), v.replace(' ', '')) for k, v in get_header_prefix(request, 'X-Container-Policy-').iteritems()])
index 6917a02..acff49d 100644 (file)
@@ -225,9 +225,13 @@ class ModularBackend(BaseBackend):
         
         logger.debug("get_account_policy: %s", account)
         if user != account:
-            raise NotAllowedError
+            if account not in self._allowed_accounts(user):
+                raise NotAllowedError
+            return {}
         path, node = self._lookup_account(account, True)
-        return self.node.policy_get(node)
+        policy = self.default_policy.copy()
+        policy.update(self.node.policy_get(node))
+        return policy
     
     @backend_method
     def update_account_policy(self, user, account, policy, replace=False):
@@ -337,7 +341,9 @@ class ModularBackend(BaseBackend):
                 raise NotAllowedError
             return {}
         path, node = self._lookup_container(account, container)
-        return self.node.policy_get(node)
+        policy = self.default_policy.copy()
+        policy.update(self.node.policy_get(node))
+        return policy
     
     @backend_method
     def update_container_policy(self, user, account, container, policy, replace=False):
index 20eb393..c9aa8f4 100644 (file)
@@ -63,4 +63,3 @@ class AuthMiddleware(object):
         
         request.user_obj = user
         request.user = user.uniq
-        request.quota = user.quota