1 # Copyright 2011 GRNET S.A. All rights reserved.
3 # Redistribution and use in source and binary forms, with or
4 # without modification, are permitted provided that the following
7 # 1. Redistributions of source code must retain the above
8 # copyright notice, this list of conditions and the following
11 # 2. Redistributions in binary form must reproduce the above
12 # copyright notice, this list of conditions and the following
13 # disclaimer in the documentation and/or other materials
14 # provided with the distribution.
16 # THIS SOFTWARE IS PROVIDED BY GRNET S.A. ``AS IS'' AND ANY EXPRESS
17 # OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
18 # WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
19 # PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL GRNET S.A OR
20 # CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
21 # SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
22 # LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF
23 # USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED
24 # AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
25 # LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN
26 # ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
27 # POSSIBILITY OF SUCH DAMAGE.
29 # The views and conclusions contained in the software and
30 # documentation are those of the authors and should not be
31 # interpreted as representing official policies, either expressed
32 # or implied, of GRNET S.A.
34 from . import Client, ClientError
37 class StorageClient(Client):
38 """OpenStack Object Storage API 1.0 client"""
40 def __init__(self, base_url, token, account=None, container=None):
41 super(StorageClient, self).__init__(base_url, token)
42 self.account = account
43 self.container = container
45 def assert_account(self):
47 raise ClientError("Please provide an account")
49 def assert_container(self):
51 if not self.container:
52 raise ClientError("Please provide a container")
54 def create_container(self, container):
56 path = '/%s/%s' % (self.account, container)
57 r = self.put(path, success=(201, 202))
58 if r.status_code == 202:
59 raise ClientError("Container already exists", r.status_code)
61 def get_container_meta(self, container):
63 path = '/%s/%s' % (self.account, container)
64 r = self.head(path, success=(204, 404))
65 if r.status_code == 404:
66 raise ClientError("Container does not exist", r.status_code)
69 prefix = 'x-container-'
70 for key, val in r.headers.items():
72 if key.startswith(prefix):
73 reply[key[len(prefix):]] = val
77 def create_object(self, object, f, size=None, hash_cb=None,
79 # This is a naive implementation, it loads the whole file in memory
80 self.assert_container()
81 path = '/%s/%s/%s' % (self.account, self.container, object)
82 data = f.read(size) if size is not None else f.read()
83 self.put(path, data=data, success=201)
85 def create_directory(self, object):
86 self.assert_container()
87 path = '/%s/%s/%s' % (self.account, self.container, object)
88 self.put(path, data='', directory=True, success=201)
90 def get_object(self, object):
91 self.assert_container()
92 path = '/%s/%s/%s' % (self.account, self.container, object)
93 r = self.get(path, raw=True, success=200)
94 size = int(r.headers['content-length'])
97 def delete_object(self, object):
98 self.assert_container()
99 path = '/%s/%s/%s' % (self.account, self.container, object)
100 self.delete(path, success=204)
102 def list_objects(self, path=''):
103 self.assert_container()
104 path = '/%s/%s' % (self.account, self.container)
105 params = dict(format='json')
106 r = self.get(path, params=params, success=(200, 204))