Added set_account_meta
authorStavros Sachtouris <saxtouri@admin.grnet.gr>
Thu, 5 Jul 2012 10:20:57 +0000 (13:20 +0300)
committerStavros Sachtouris <saxtouri@admin.grnet.gr>
Tue, 10 Jul 2012 14:09:27 +0000 (17:09 +0300)
In CLI:
    - added store_set_account_meta
    - added auxiliary dict_from_args in utils.py

In storage:
    - added set_account_meta
    - created client/util.py to store auxiliary methods semantically indepented Client
    - added auxiliary prefix_keys to client/utils.py
    - adjusted Client.request method to handle POST/PUT meta headers

kamaki/cli.py
kamaki/clients/__init__.py
kamaki/clients/pithos.py
kamaki/clients/storage.py
kamaki/clients/utils.py [new file with mode: 0644]
kamaki/utils.py

index d2574eb..a5f1d69 100755 (executable)
@@ -88,7 +88,7 @@ from requests.exceptions import ConnectionError
 
 from . import clients
 from .config import Config
-from .utils import print_addresses, print_dict, print_items, format_size
+from .utils import print_addresses, print_dict, print_items, format_size, dict_from_args
 
 
 _commands = OrderedDict()
@@ -732,6 +732,31 @@ class store_meta(_store_account_command):
         print_dict(reply)
 
 @command(api='storage')
+class store_set_account_meta(_store_account_command):
+    """Set account meta-content"""
+
+    def main(self, metakey, metaval, *more):
+        super(store_set_account_meta, self).main()
+        args_len = len(more)
+        if args_len%2 == 1:
+            print('Parameter %s will be ignored' % more[-1])
+        pairs = dict_from_args(*more)
+        pairs[metakey] = metaval
+        self.client.set_account_meta(pairs)
+
+@command(api='storage')
+class store_policy(_store_account_command):
+    """Get  policy for account [, container [or object]]"""
+
+    def main(self, container = None):
+        super(store_policy, self).main()
+        if container is None:
+            reply = self.client.get_account_policy()
+        else:
+            reply = self.client.get_container_policy(container)
+        print_dict(reply)
+
+@command(api='storage')
 class store_create(_store_account_command):
     """Create a container [or a directory object]"""
 
index 34751d3..57cef28 100644 (file)
@@ -71,6 +71,7 @@ class Client(object):
         raw = kwargs.pop('raw', False)
         success = kwargs.pop('success', 200)
         directory = kwargs.pop('directory', False)
+        meta = kwargs.pop('meta', False)
 
         data = kwargs.pop('data', None)
         headers = kwargs.pop('headers', {})
@@ -86,6 +87,10 @@ class Client(object):
             if data:
                 headers.setdefault('Content-Length', str(len(data)))
 
+        if meta:
+            for key in meta.keys():
+                headers[key] = meta[key]
+            
         url = self.base_url + path
         kwargs.setdefault('verify', False)  # Disable certificate verification
         r = requests.request(method, url, headers=headers, data=data, **kwargs)
index 6e796f4..b7c1ae6 100644 (file)
@@ -50,11 +50,9 @@ class PithosClient(StorageClient):
 
     def purge_container(self, container):
         self.assert_account()
-
         path = '/%s/%s' % (self.account, container)
-        #params = {'until': int(time())}
-        #self.delete(path, params=params, success=204)
-        self.delete(path, success=204)
+        params = {'until': int(time())}
+        self.delete(path, params=params, success=204)
 
     def put_block(self, data, hash):
         path = '/%s/%s' % (self.account, self.container)
index ee85d0b..6e9e914 100644 (file)
@@ -32,9 +32,7 @@
 # or implied, of GRNET S.A.
 
 from . import Client, ClientError
-
-def filter_dict_with_prefix(d, prefix):
-    return {key:d[key] for key in d if key.startswith(prefix)}
+from .utils import filter_dict_with_prefix, prefix_keys
 
 class StorageClient(Client):
     """OpenStack Object Storage API 1.0 client"""
@@ -64,6 +62,15 @@ class StorageClient(Client):
     def get_account_meta(self):
         return filter_dict_with_prefix(self.get_account_info(), 'X-Account-Meta-')
 
+    def set_account_meta(self, metapairs):
+        self.assert_account()
+        path = '/%s' % self.account
+        meta = prefix_keys(metapairs, 'X-Account-Meta-')
+        self.post(path, meta=meta, success=202)
+
+    def get_account_policy(self):
+        return filter_dict_with_prefix(self.get_account_info(), 'X-Account-Policy-')
+
     def create_container(self, container):
         self.assert_account()
         path = '/%s/%s' % (self.account, container)
@@ -90,6 +97,9 @@ class StorageClient(Client):
     def get_container_meta(self, container):
         return filter_dict_with_prefix(self.get_container_info(container), 'X-Container-Meta-')
 
+    def get_container_policy(self, container):
+        return filter_dict_with_prefix(self.get_container_info(container), 'X-Container-Policy-')
+
     def delete_container(self, container):
         #Response codes
         #   Success             204
@@ -110,7 +120,7 @@ class StorageClient(Client):
         r = self.get(path, params = params, success = (200, 204))
         return r.json
 
-    """def create_object(self, object, f, size=None, hash_cb=None,
+    def create_object(self, object, f, size=None, hash_cb=None,
                       upload_cb=None):
         # This is a naive implementation, it loads the whole file in memory
         #Look in pithos for a nice implementation
@@ -118,7 +128,6 @@ class StorageClient(Client):
         path = '/%s/%s/%s' % (self.account, self.container, object)
         data = f.read(size) if size is not None else f.read()
         self.put(path, data=data, success=201)
-    """
 
     def create_directory(self, object):
         self.assert_container()
@@ -134,6 +143,7 @@ class StorageClient(Client):
     def get_object_meta(self, object):
         return filter_dict_with_prefix(self.get_object_info(object), 'X-Object-Meta-')
 
+
     def get_object(self, object):
         self.assert_container()
         path = '/%s/%s/%s' % (self.account, self.container, object)
diff --git a/kamaki/clients/utils.py b/kamaki/clients/utils.py
new file mode 100644 (file)
index 0000000..d81abcd
--- /dev/null
@@ -0,0 +1,43 @@
+# Copyright 2011-2012 GRNET S.A. All rights reserved.
+#
+# Redistribution and use in source and binary forms, with or
+# without modification, are permitted provided that the following
+# conditions are met:
+#
+#   1. Redistributions of source code must retain the above
+#      copyright notice, this list of conditions and the following
+#      disclaimer.
+#
+#   2. Redistributions in binary form must reproduce the above
+#      copyright notice, this list of conditions and the following
+#      disclaimer in the documentation and/or other materials
+#      provided with the distribution.
+#
+# THIS SOFTWARE IS PROVIDED BY GRNET S.A. ``AS IS'' AND ANY EXPRESS
+# OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
+# WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
+# PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL GRNET S.A OR
+# CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+# SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+# LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF
+# USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED
+# AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+# LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN
+# ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
+# POSSIBILITY OF SUCH DAMAGE.
+#
+# The views and conclusions contained in the software and
+# documentation are those of the authors and should not be
+# interpreted as representing official policies, either expressed
+# or implied, of GRNET S.A.
+
+def filter_dict_with_prefix(d, prefix):
+    """@return a dict that contains only the entries of d that are prefixed with prefic
+    """
+    return {key:d[key] for key in d if key.lower().startswith(prefix.lower())}
+
+def prefix_keys(d, prefix):
+    """@return a sallow copy of d with all its keys prefixed with prefix
+    """
+    return {prefix+key:d[key] for key in d.keys()}
+
index 5be7aaa..7edde8d 100644 (file)
@@ -96,3 +96,6 @@ def format_size(size):
     s = ('%.1f' % size).rstrip('.0')
     return s + unit
 
+def dict_from_args(*args):
+    return {args[i]:args[i+1] for i in range(0, len(args)/2)}
+