Commit af3b2b36 authored by Stavros Sachtouris's avatar Stavros Sachtouris
Browse files

Added store_setmeta (pithos API implementation)

-In CLI:
    - store_meta for account, container and/or object
    - minor fixes to meta

In storage,pithos:
    - methods replace_account/container/object_meta in storage (OpenStack API)
    - methods set_account/container/object_meta in pithos (Pithos API)
    - minor bugfixes in client/untils and Client.request
parent 0e4bec91
......@@ -725,25 +725,54 @@ class store_meta(_store_account_command):
if container is None:
reply = self.client.get_account_meta()
elif object is None:
reply = self.client.get_container_object_meta(container)
print_dict(reply)
reply = self.client.get_container_meta(container)
else:
self.client.container = container
reply = self.client.get_object_meta(object)
print_dict(reply)
@command(api='storage')
class store_setmeta(_store_account_command):
"""Set a new metadatum for account [, container [or object]]"""
def main(self, metakey, metavalue, container=None, object=None):
super(store_setmeta, self).main()
if container is None:
self.client.set_account_meta({metakey:metavalue})
else:
self.client.container = container
if object is None:
self.client.set_container_meta({metakey:metavalue})
else:
self.client.set_object_meta(object, {metakey:metavalue})
@command(api='storage')
class store_set_account_meta(_store_account_command):
"""Set account meta-content"""
"""Set (replace) account meta-content"""
def main(self, metakey, metaval, *more):
def main(self, metakey, metaval, *moreargs):
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)
if len(moreargs)%2 == 1:
print('Parameter %s will be ignored' % moreargs[-1])
pairs = dict_from_args(*moreargs)
pairs[metakey] = metaval
self.client.set_account_meta(pairs)
@command(api='storage')
class store_set_container_meta(_store_account_command):
"""Set (replace) container meta-content"""
def main(self, container, metakey, metaval, *moreargs):
super(store_set_container_meta, self).main()
self.client.container = container
if len(moreargs)%2 == 1:
print('Parameter %s will be ignored' % moreargs[-1])
pairs = dict_from_args(*moreargs)
pairs[metakey] = metaval
print(unicode(pairs))
@command(api='storage')
class store_policy(_store_account_command):
"""Get policy for account [, container [or object]]"""
......
......@@ -85,7 +85,7 @@ class Client(object):
data = json.dumps(kwargs.pop('json'))
headers.setdefault('Content-Type', 'application/json')
if data:
headers.setdefault('Content-Length', str(len(data)))
headers.setdefault('Content-Length', unicode(len(data)))
if meta:
for key in meta.keys():
......
......@@ -37,6 +37,7 @@ import os
from time import time
from .storage import StorageClient
from .utils import path4url, params4url, prefix_keys
def pithos_hash(block, blockhash):
......@@ -77,8 +78,9 @@ class PithosClient(StorageClient):
self.assert_container()
meta = self.get_container_info(self.container)
blocksize = int(meta['block-size'])
blockhash = meta['block-hash']
print(unicode(meta))
blocksize = int(meta['x-container-block-size'])
blockhash = meta['x-container-block-hash']
size = size if size is not None else os.fstat(f.fileno()).st_size
nblocks = 1 + (size - 1) // blocksize
......@@ -129,3 +131,25 @@ class PithosClient(StorageClient):
self.put(path, params=params, headers=headers, json=hashmap,
success=201)
def set_account_meta(self, metapairs):
assert(type(metapairs) is dict)
self.assert_account()
path = path4url(self.account)+params4url({'update':None})
meta = prefix_keys(metapairs, 'X-Account-Meta-')
self.post(path, meta=meta, success=202)
def set_container_meta(self, metapairs):
assert(type(metapairs) is dict)
self.assert_container()
path=path4url(self.account, self.container)+params4url({'update':None})
meta = prefix_keys(metapairs, 'X-Container-Meta-')
self.post(path, meta=meta, success=202)
def set_object_meta(self, object, metapairs):
assert(type(metapairs) is dict)
self.assert_container()
path=path4url(self.account, self.container, object)+params4url({'update':None})
meta = prefix_keys(metapairs, 'X-Object-Meta-')
self.post(path, meta=meta, success=202)
......@@ -32,7 +32,7 @@
# or implied, of GRNET S.A.
from . import Client, ClientError
from .utils import filter_dict_with_prefix, prefix_keys
from .utils import filter_dict_with_prefix, prefix_keys, path4url, params4url
class StorageClient(Client):
"""OpenStack Object Storage API 1.0 client"""
......@@ -53,7 +53,7 @@ class StorageClient(Client):
def get_account_info(self):
self.assert_account()
path = '/%s' % self.account
path = path4url(self.account)
r = self.head(path, success=(204, 401))
if r.status_code == 401:
raise ClientError("No authorization")
......@@ -62,9 +62,9 @@ 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):
def replace_account_meta(self, metapairs):
self.assert_account()
path = '/%s' % self.account
path = path4url(self.account)
meta = prefix_keys(metapairs, 'X-Account-Meta-')
self.post(path, meta=meta, success=202)
......@@ -73,30 +73,32 @@ class StorageClient(Client):
def create_container(self, container):
self.assert_account()
path = '/%s/%s' % (self.account, container)
path = path4url(self.account, container)
r = self.put(path, success=(201, 202))
if r.status_code == 202:
raise ClientError("Container already exists", r.status_code)
def get_container_info(self, container):
self.assert_account()
path = '/%s/%s' % (self.account, container)
path = path4url(self.account, container)
r = self.head(path, success=(204, 404))
if r.status_code == 404:
raise ClientError("Container does not exist", r.status_code)
reply = {}
prefix = 'x-container-'
for key, val in r.headers.items():
key = key.lower()
if key.startswith(prefix):
reply[key[len(prefix):]] = val
reply = r.headers
return reply
def get_container_meta(self, container):
return filter_dict_with_prefix(self.get_container_info(container), 'X-Container-Meta-')
def get_container_object_meta(self, container):
return filter_dict_with_prefix(self.get_container_info(container), 'X-Container-Object-Meta')
def replace_container_meta(self, metapairs):
self.assert_container()
path=path4url(self.account, self.container)
meta = prefix_keys(metapairs, 'X-Container-Meta-')
self.post(path, meta=meta, success=202)
def get_container_policy(self, container):
return filter_dict_with_prefix(self.get_container_info(container), 'X-Container-Policy-')
......@@ -106,7 +108,7 @@ class StorageClient(Client):
# NotFound 404
# Conflict(not empty) 409
self.assert_account()
path = '/%s/%s' % (self.account, container)
path = path4url(self.account, container)
r = self.delete(path, success=(204, 404, 409))
if r.status_code == 404:
raise ClientError("Container does not exist", r.status_code)
......@@ -115,7 +117,7 @@ class StorageClient(Client):
def list_containers(self):
self.assert_account()
path = '/%s' % (self.account)
path = path4url(self.account)
params = dict(format='json')
r = self.get(path, params = params, success = (200, 204))
return r.json
......@@ -125,42 +127,47 @@ class StorageClient(Client):
# This is a naive implementation, it loads the whole file in memory
#Look in pithos for a nice implementation
self.assert_container()
path = '/%s/%s/%s' % (self.account, self.container, object)
path = path4url(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()
path = '/%s/%s/%s' % (self.account, self.container, object)
path = path4url(self.account, self.container, object)
self.put(path, data='', directory=True, success=201)
def get_object_info(self, object):
self.assert_container()
path = '/%s/%s/%s' % (self.account, self.container, object)
path = path4url(self.account, self.container, object)
r = self.head(path, success=200)
return r.headers
def get_object_meta(self, object):
return filter_dict_with_prefix(self.get_object_info(object), 'X-Object-Meta-')
def replace_object(self, metapairs):
self.assert_container()
path=path4url(self.account, self.container)
meta = prefix_keys(metapairs, 'X-Object-Meta-')
self.post(path, meta=meta, success=202)
def get_object(self, object):
self.assert_container()
path = '/%s/%s/%s' % (self.account, self.container, object)
path = path4url(self.account, self.container, object)
r = self.get(path, raw=True, success=200)
size = int(r.headers['content-length'])
return r.raw, size
def delete_object(self, object):
self.assert_container()
path = '/%s/%s/%s' % (self.account, self.container, object)
path = path4url(self.account, self.container, object)
r = self.delete(path, success=(204, 404))
if r.status_code == 404:
raise ClientError("Object %s not found" %object, r.status_code)
def list_objects(self):
self.assert_container()
path = '/%s/%s' % (self.account, self.container)
path = path4url(self.account, self.container)
params = dict(format='json')
r = self.get(path, params=params, success=(200, 204, 404))
if r.status_code == 404:
......@@ -169,7 +176,7 @@ class StorageClient(Client):
def list_objects_in_path(self, path_prefix):
self.assert_container()
path = '/%s/%s' % (self.account, self.container)
path = path4url(self.account, self.container)
params = dict(format='json', path=path_prefix)
r = self.get(path, params=params, success=(200, 204, 404))
if r.status_code == 404:
......
......@@ -41,3 +41,31 @@ def prefix_keys(d, prefix):
"""
return {prefix+key:d[key] for key in d.keys()}
def path4url(*args):
"""@return a string with all args in the form /arg1/arg2/...
@param args must be strings
"""
path = ''
for arg in args:
path = path + '/' + arg
return path
def params4url(params):
"""@return a string with all params in the form ?key1=val1&key2=val2&...
e.g. input
{'key1':'val1', 'key2':None, 'key3':'val3'}
will return
?key1=val1&key2&key3=val3
@param should be a dict.
Use params['somekey']=None for params that will apear without
a value at the final string
"""
assert(type(params) is dict)
result = ''
delimiter = '?'
for name in params:
result = result + delimiter + name
result = result + '=' + params[name] if params[name] is not None else result
delimeter = '&'
return result
Markdown is supported
0% or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment