From: Stavros Sachtouris Date: Thu, 5 Jul 2012 10:20:57 +0000 (+0300) Subject: Added set_account_meta X-Git-Tag: v0.6~254 X-Git-Url: https://code.grnet.gr/git/kamaki/commitdiff_plain/0e4bec912fe59adb8ec59f3b31fb7cdc120dea0c Added set_account_meta 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 --- diff --git a/kamaki/cli.py b/kamaki/cli.py index d2574eb..a5f1d69 100755 --- a/kamaki/cli.py +++ b/kamaki/cli.py @@ -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]""" diff --git a/kamaki/clients/__init__.py b/kamaki/clients/__init__.py index 34751d3..57cef28 100644 --- a/kamaki/clients/__init__.py +++ b/kamaki/clients/__init__.py @@ -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) diff --git a/kamaki/clients/pithos.py b/kamaki/clients/pithos.py index 6e796f4..b7c1ae6 100644 --- a/kamaki/clients/pithos.py +++ b/kamaki/clients/pithos.py @@ -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) diff --git a/kamaki/clients/storage.py b/kamaki/clients/storage.py index ee85d0b..6e9e914 100644 --- a/kamaki/clients/storage.py +++ b/kamaki/clients/storage.py @@ -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 index 0000000..d81abcd --- /dev/null +++ b/kamaki/clients/utils.py @@ -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()} + diff --git a/kamaki/utils.py b/kamaki/utils.py index 5be7aaa..7edde8d 100644 --- a/kamaki/utils.py +++ b/kamaki/utils.py @@ -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)} +