Added mkdir functionality to storage
[kamaki] / kamaki / clients / storage.py
1 # Copyright 2011 GRNET S.A. All rights reserved.
2 #
3 # Redistribution and use in source and binary forms, with or
4 # without modification, are permitted provided that the following
5 # conditions are met:
6 #
7 #   1. Redistributions of source code must retain the above
8 #      copyright notice, this list of conditions and the following
9 #      disclaimer.
10 #
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.
15 #
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.
28 #
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.
33
34 from . import Client, ClientError
35
36
37 class StorageClient(Client):
38     """OpenStack Object Storage API 1.0 client"""
39
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
44
45     def assert_account(self):
46         if not self.account:
47             raise ClientError("Please provide an account")
48
49     def assert_container(self):
50         self.assert_account()
51         if not self.container:
52             raise ClientError("Please provide a container")
53
54     def create_container(self, container):
55         self.assert_account()
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)
60
61     def get_container_meta(self, container):
62         self.assert_account()
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)
67
68         reply = {}
69         prefix = 'x-container-'
70         for key, val in r.headers.items():
71             key = key.lower()
72             if key.startswith(prefix):
73                 reply[key[len(prefix):]] = val
74
75         return reply
76
77     def create_object(self, object, f, size=None, hash_cb=None,
78                       upload_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)
84
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)
89
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'])
95         return r.raw, size
96
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)
101
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))
107         return r.json