Report allowed actions in cross-user object requests, with the 'X-Object-Allowed...
[pithos] / pithos / backends / base.py
index 78c5a85..9fa962c 100644 (file)
@@ -31,6 +31,9 @@
 # interpreted as representing official policies, either expressed
 # or implied, of GRNET S.A.
 
+class NotAllowedError(Exception):
+    pass
+
 class BaseBackend(object):
     """Abstract backend class that serves as a reference for actual implementations.
     
@@ -39,189 +42,431 @@ class BaseBackend(object):
     
     Note that the account level is always valid as it is checked from another subsystem.
     
+    When not replacing metadata/groups/policy, keys with empty values should be deleted.
+    
     The following variables should be available:
         'hash_algorithm': Suggested is 'sha256'
+        
         'block_size': Suggested is 4MB
     """
     
-    def get_account_meta(self, account):
+    def list_accounts(self, user, marker=None, limit=10000):
+        """Return a list of accounts the user can access.
+        
+        Parameters:
+            'marker': Start list from the next item after 'marker'
+            
+            'limit': Number of containers to return
+        """
+        return []
+    
+    def get_account_meta(self, user, account, until=None):
         """Return a dictionary with the account metadata.
         
         The keys returned are all user-defined, except:
             'name': The account name
+            
             'count': The number of containers (or 0)
+            
             'bytes': The total data size (or 0)
-            'modified': Last modification timestamp
+            
+            'modified': Last modification timestamp (overall)
+            
+            'until_timestamp': Last modification until the timestamp provided
+        
+        Raises:
+            NotAllowedError: Operation not permitted
         """
         return {}
     
-    def update_account_meta(self, account, meta, replace=False):
+    def update_account_meta(self, user, account, meta, replace=False):
         """Update the metadata associated with the account.
         
         Parameters:
             'meta': Dictionary with metadata to update
+            
             'replace': Replace instead of update
+        
+        Raises:
+            NotAllowedError: Operation not permitted
         """
         return
     
-    def put_container(self, account, name):
-        """Create a new container with the given name.
-
+    def get_account_groups(self, user, account):
+        """Return a dictionary with the user groups defined for this account.
+        
         Raises:
-            NameError: Container already exists
+            NotAllowedError: Operation not permitted
+        """
+        return {}
+    
+    def update_account_groups(self, user, account, groups, replace=False):
+        """Update the groups associated with the account.
+        
+        Raises:
+            NotAllowedError: Operation not permitted
+            
+            ValueError: Invalid data in groups
         """
         return
     
-    def delete_container(self, account, name):
-        """Delete the container with the given name.
-
+    def put_account(self, user, account):
+        """Create a new account with the given name.
+        
         Raises:
-            NameError: Container does not exist
-            IndexError: Container is not empty
+            NotAllowedError: Operation not permitted
         """
         return
     
-    def get_container_meta(self, account, name):
+    def delete_account(self, user, account):
+        """Delete the account with the given name.
+        
+        Raises:
+            NotAllowedError: Operation not permitted
+            
+            IndexError: Account is not empty
+        """
+        return
+    
+    def list_containers(self, user, account, marker=None, limit=10000, shared=False, until=None):
+        """Return a list of container names existing under an account.
+        
+        Parameters:
+            'marker': Start list from the next item after 'marker'
+            
+            'limit': Number of containers to return
+            
+            'shared': Only list containers with permissions set
+            
+        
+        Raises:
+            NotAllowedError: Operation not permitted
+        """
+        return []
+    
+    def get_container_meta(self, user, account, container, until=None):
         """Return a dictionary with the container metadata.
-
+        
         The keys returned are all user-defined, except:
             'name': The container name
+            
             'count': The number of objects
+            
             'bytes': The total data size
-            'created': Creation timestamp
-            'modified': Last modification timestamp
+            
+            'modified': Last modification timestamp (overall)
+            
+            'until_timestamp': Last modification until the timestamp provided
         
         Raises:
+            NotAllowedError: Operation not permitted
+            
             NameError: Container does not exist
         """
         return {}
     
-    def update_container_meta(self, account, name, meta, replace=False):
+    def update_container_meta(self, user, account, container, meta, replace=False):
         """Update the metadata associated with the container.
         
         Parameters:
             'meta': Dictionary with metadata to update
+            
             'replace': Replace instead of update
         
         Raises:
+            NotAllowedError: Operation not permitted
+            
             NameError: Container does not exist
         """
         return
     
-    def list_containers(self, account, marker=None, limit=10000):
-        """Return a list of containers existing under an account.
+    def get_container_policy(self, user, account, container):
+        """Return a dictionary with the container policy.
         
-        Parameters:
-            'marker': Start list from the next item after 'marker'
-            'limit': Number of containers to return
+        The keys returned are:
+            'quota': The maximum bytes allowed (default is 0 - unlimited)
+            
+            'versioning': Can be 'auto', 'manual' or 'none' (default is 'manual')
+        
+        Raises:
+            NotAllowedError: Operation not permitted
+            
+            NameError: Container does not exist
         """
-        return []
+        return {}
+    
+    def update_container_policy(self, user, account, container, policy, replace=False):
+        """Update the policy associated with the account.
+        
+        Raises:
+            NotAllowedError: Operation not permitted
+            
+            NameError: Container does not exist
+            
+            ValueError: Invalid policy defined
+        """
+        return
+    
+    def put_container(self, user, account, container, policy=None):
+        """Create a new container with the given name.
+        
+        Raises:
+            NotAllowedError: Operation not permitted
+            
+            NameError: Container already exists
+            
+            ValueError: Invalid policy defined
+        """
+        return
     
-    def list_objects(self, account, container, prefix='', delimiter=None, marker=None, limit=10000, virtual=True, keys=[]):
-        """Return a list of objects existing under a container.
+    def delete_container(self, user, account, container, until=None):
+        """Delete/purge the container with the given name.
+        
+        Raises:
+            NotAllowedError: Operation not permitted
+            
+            NameError: Container does not exist
+            
+            IndexError: Container is not empty
+        """
+        return
+    
+    def list_objects(self, user, account, container, prefix='', delimiter=None, marker=None, limit=10000, virtual=True, keys=[], shared=False, until=None):
+        """Return a list of object (name, version_id) tuples existing under a container.
         
         Parameters:
             'prefix': List objects starting with 'prefix'
+            
             'delimiter': Return unique names before 'delimiter' and after 'prefix'
+            
             'marker': Start list from the next item after 'marker'
+            
             'limit': Number of objects to return
+            
             'virtual': If not set, the result will only include names starting
-                with 'prefix' and ending without a 'delimiter' or with the first
-                occurance of the 'delimiter' after 'prefix'.
-                If set, the result will include all names after 'prefix', up to and
-                including the 'delimiter' if it is found
+                       with 'prefix' and ending without a 'delimiter' or with
+                       the first occurance of the 'delimiter' after 'prefix'.
+                       If set, the result will include all names after 'prefix',
+                       up to and including the 'delimiter' if it is found
+            
             'keys': Include objects that have meta with the keys in the list
+            
+            'shared': Only list objects with permissions set
         
         Raises:
+            NotAllowedError: Operation not permitted
+            
             NameError: Container does not exist
         """
         return []
     
-    def list_object_meta(self, account, name):
+    def list_object_meta(self, user, account, container, until=None):
         """Return a list with all the container's object meta keys.
         
         Raises:
+            NotAllowedError: Operation not permitted
+            
             NameError: Container does not exist
         """
         return []
     
-    def get_object_meta(self, account, container, name):
+    def get_object_meta(self, user, account, container, name, version=None):
         """Return a dictionary with the object metadata.
         
         The keys returned are all user-defined, except:
-            'name': The account name
+            'name': The object name
+            
             'bytes': The total data size
-            'version': The latest version (zero if not versioned)
-            'created': Creation timestamp
-            'modified': Last modification timestamp
+            
+            'modified': Last modification timestamp (overall)
+            
+            'modified_by': The user that committed the object (version requested)
+            
+            'version': The version identifier
+            
+            'version_timestamp': The version's modification timestamp
         
         Raises:
+            NotAllowedError: Operation not permitted
+            
             NameError: Container/object does not exist
+            
+            IndexError: Version does not exist
         """
         return {}
     
-    def update_object_meta(self, account, container, name, meta, replace=False):
-        """Update the metadata associated with the object.
+    def update_object_meta(self, user, account, container, name, meta, replace=False):
+        """Update the metadata associated with the object and return the new version.
         
         Parameters:
-            'meta': Dictionary with metadata to update.
-                Use the 'versioned' key to control versioning
+            'meta': Dictionary with metadata to update
+            
             'replace': Replace instead of update
         
         Raises:
+            NotAllowedError: Operation not permitted
+            
+            NameError: Container/object does not exist
+        """
+        return ''
+    
+    def get_object_permissions(self, user, account, container, name):
+        """Return the action allowed on the object, the path
+        from which the object gets its permissions from,
+        along with a dictionary containing the permissions.
+        
+        The dictionary keys are (also used for defining the action):
+            'read': The object is readable by the users/groups in the list
+            
+            'write': The object is writable by the users/groups in the list
+        
+        Raises:
+            NotAllowedError: Operation not permitted
+            
+            NameError: Container/object does not exist
+        """
+        return {}
+    
+    def update_object_permissions(self, user, account, container, name, permissions):
+        """Update the permissions associated with the object.
+        
+        Parameters:
+            'permissions': Dictionary with permissions to update
+        
+        Raises:
+            NotAllowedError: Operation not permitted
+            
             NameError: Container/object does not exist
+            
+            ValueError: Invalid users/groups in permissions
+            
+            AttributeError: Can not set permissions, as this object
+                is already shared/private by another object higher
+                in the hierarchy, or setting permissions here will
+                invalidate other permissions deeper in the hierarchy
         """
         return
     
-    def get_object_hashmap(self, account, container, name, version=None):
+    def get_object_public(self, user, account, container, name):
+        """Return the public URL of the object if applicable.
+        
+        Raises:
+            NotAllowedError: Operation not permitted
+            
+            NameError: Container/object does not exist
+        """
+        return None
+    
+    def update_object_public(self, user, account, container, name, public):
+        """Update the public status of the object.
+        
+        Parameters:
+            'public': Boolean value
+        
+        Raises:
+            NotAllowedError: Operation not permitted
+            
+            NameError: Container/object does not exist
+        """
+        return
+    
+    def get_object_hashmap(self, user, account, container, name, version=None):
         """Return the object's size and a list with partial hashes.
         
         Raises:
+            NotAllowedError: Operation not permitted
+            
             NameError: Container/object does not exist
+            
             IndexError: Version does not exist
         """
         return 0, []
     
-    def update_object_hashmap(self, account, container, name, size, hashmap):
-        """Create/update an object with the specified size and partial hashes.
+    def update_object_hashmap(self, user, account, container, name, size, hashmap, meta={}, replace_meta=False, permissions=None):
+        """Create/update an object with the specified size and partial hashes and return the new version.
+        
+        Parameters:
+            'dest_meta': Dictionary with metadata to change
+            
+            'replace_meta': Replace metadata instead of update
+            
+            'permissions': Updated object permissions
         
         Raises:
-            NameError: Container/block does not exist
+            NotAllowedError: Operation not permitted
+            
+            NameError: Container does not exist
+            
+            ValueError: Invalid users/groups in permissions
+            
+            AttributeError: Can not set permissions
         """
-        return
+        return ''
     
-    def copy_object(self, account, src_container, src_name, dest_container, dest_name, dest_meta={}, replace_meta=False):
-        """Copy an object's data and metadata.
+    def copy_object(self, user, account, src_container, src_name, dest_container, dest_name, dest_meta={}, replace_meta=False, permissions=None, src_version=None):
+        """Copy an object's data and metadata and return the new version.
         
         Parameters:
-            'dest_meta': Dictionary with metadata to changes from source to destination
+            'dest_meta': Dictionary with metadata to change from source to destination
+            
             'replace_meta': Replace metadata instead of update
+            
+            'permissions': New object permissions
+            
+            'src_version': Copy from the version provided
         
         Raises:
+            NotAllowedError: Operation not permitted
+            
             NameError: Container/object does not exist
+            
+            IndexError: Version does not exist
+            
+            ValueError: Invalid users/groups in permissions
+            
+            AttributeError: Can not set permissions
         """
-        return
+        return ''
     
-    def move_object(self, account, src_container, src_name, dest_container, dest_name, dest_meta={}, replace_meta=False):
-        """Move an object's data and metadata.
+    def move_object(self, user, account, src_container, src_name, dest_container, dest_name, dest_meta={}, replace_meta=False, permissions=None):
+        """Move an object's data and metadata and return the new version.
         
         Parameters:
-            'dest_meta': Dictionary with metadata to changes from source to destination
+            'dest_meta': Dictionary with metadata to change from source to destination
+            
             'replace_meta': Replace metadata instead of update
+            
+            'permissions': New object permissions
         
         Raises:
+            NotAllowedError: Operation not permitted
+            
             NameError: Container/object does not exist
+            
+            ValueError: Invalid users/groups in permissions
+            
+            AttributeError: Can not set permissions
         """
-        return
+        return ''
     
-    def delete_object(self, account, container, name):
-        """Delete an object.
+    def delete_object(self, user, account, container, name, until=None):
+        """Delete/purge an object.
         
         Raises:
+            NotAllowedError: Operation not permitted
+            
             NameError: Container/object does not exist
         """
         return
     
+    def list_versions(self, user, account, container, name):
+        """Return a list of all (version, version_timestamp) tuples for an object.
+        
+        Raises:
+            NotAllowedError: Operation not permitted
+        """
+        return []
+    
     def get_block(self, hash):
         """Return a block's data.