Statistics
| Branch: | Tag: | Revision:

root / kamaki / clients / storage.py @ 33dc6317

History | View | Annotate | Download (8.8 kB)

1 5cffe0b4 Stavros Sachtouris
#a Copyright 2011 GRNET S.A. All rights reserved.
2 a1c50326 Giorgos Verigakis
#
3 a1c50326 Giorgos Verigakis
# Redistribution and use in source and binary forms, with or
4 a1c50326 Giorgos Verigakis
# without modification, are permitted provided that the following
5 a1c50326 Giorgos Verigakis
# conditions are met:
6 a1c50326 Giorgos Verigakis
#
7 a1c50326 Giorgos Verigakis
#   1. Redistributions of source code must retain the above
8 a1c50326 Giorgos Verigakis
#      copyright notice, this list of conditions and the following
9 a1c50326 Giorgos Verigakis
#      disclaimer.
10 a1c50326 Giorgos Verigakis
#
11 a1c50326 Giorgos Verigakis
#   2. Redistributions in binary form must reproduce the above
12 a1c50326 Giorgos Verigakis
#      copyright notice, this list of conditions and the following
13 a1c50326 Giorgos Verigakis
#      disclaimer in the documentation and/or other materials
14 a1c50326 Giorgos Verigakis
#      provided with the distribution.
15 a1c50326 Giorgos Verigakis
#
16 a1c50326 Giorgos Verigakis
# THIS SOFTWARE IS PROVIDED BY GRNET S.A. ``AS IS'' AND ANY EXPRESS
17 a1c50326 Giorgos Verigakis
# OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
18 a1c50326 Giorgos Verigakis
# WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
19 a1c50326 Giorgos Verigakis
# PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL GRNET S.A OR
20 a1c50326 Giorgos Verigakis
# CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
21 a1c50326 Giorgos Verigakis
# SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
22 a1c50326 Giorgos Verigakis
# LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF
23 a1c50326 Giorgos Verigakis
# USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED
24 a1c50326 Giorgos Verigakis
# AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
25 a1c50326 Giorgos Verigakis
# LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN
26 a1c50326 Giorgos Verigakis
# ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
27 a1c50326 Giorgos Verigakis
# POSSIBILITY OF SUCH DAMAGE.
28 a1c50326 Giorgos Verigakis
#
29 a1c50326 Giorgos Verigakis
# The views and conclusions contained in the software and
30 a1c50326 Giorgos Verigakis
# documentation are those of the authors and should not be
31 a1c50326 Giorgos Verigakis
# interpreted as representing official policies, either expressed
32 a1c50326 Giorgos Verigakis
# or implied, of GRNET S.A.
33 a1c50326 Giorgos Verigakis
34 6a0b1658 Giorgos Verigakis
from . import Client, ClientError
35 2f749e6e Stavros Sachtouris
from .utils import filter_in, filter_out, prefix_keys, path4url
36 5b263ba2 Stavros Sachtouris
#from .connection.kamakicon import KamakiHTTPConnection
37 a1c50326 Giorgos Verigakis
38 6a0b1658 Giorgos Verigakis
class StorageClient(Client):
39 d2cea1e2 Giorgos Verigakis
    """OpenStack Object Storage API 1.0 client"""
40 44b8928d Giorgos Verigakis
41 6a0b1658 Giorgos Verigakis
    def __init__(self, base_url, token, account=None, container=None):
42 6ad245d5 Stavros Sachtouris
        super(StorageClient, self).__init__(base_url, token)
43 6ad245d5 Stavros Sachtouris
        #super(StorageClient, self).__init__(base_url, token, http_client=KamakiHTTPConnection())
44 6a0b1658 Giorgos Verigakis
        self.account = account
45 6a0b1658 Giorgos Verigakis
        self.container = container
46 44b8928d Giorgos Verigakis
47 6a0b1658 Giorgos Verigakis
    def assert_account(self):
48 6a0b1658 Giorgos Verigakis
        if not self.account:
49 2f749e6e Stavros Sachtouris
            raise ClientError("No account provided")
50 44b8928d Giorgos Verigakis
51 6a0b1658 Giorgos Verigakis
    def assert_container(self):
52 6a0b1658 Giorgos Verigakis
        self.assert_account()
53 6a0b1658 Giorgos Verigakis
        if not self.container:
54 2f749e6e Stavros Sachtouris
            raise ClientError("No container provided")
55 44b8928d Giorgos Verigakis
56 d2dec8b1 Stavros Sachtouris
    def get_account_info(self):
57 d2dec8b1 Stavros Sachtouris
        self.assert_account()
58 af3b2b36 Stavros Sachtouris
        path = path4url(self.account)
59 d2dec8b1 Stavros Sachtouris
        r = self.head(path, success=(204, 401))
60 d2dec8b1 Stavros Sachtouris
        if r.status_code == 401:
61 5b263ba2 Stavros Sachtouris
            r.release()
62 d2dec8b1 Stavros Sachtouris
            raise ClientError("No authorization")
63 5b263ba2 Stavros Sachtouris
        reply = r.headers
64 5b263ba2 Stavros Sachtouris
        r.release()
65 5b263ba2 Stavros Sachtouris
        return reply
66 d2dec8b1 Stavros Sachtouris
67 af3b2b36 Stavros Sachtouris
    def replace_account_meta(self, metapairs):
68 0e4bec91 Stavros Sachtouris
        self.assert_account()
69 af3b2b36 Stavros Sachtouris
        path = path4url(self.account)
70 e742badc Stavros Sachtouris
        for key, val in  metapairs:
71 e742badc Stavros Sachtouris
            self.set_header('X-Account-Meta-'+key, val)
72 5b263ba2 Stavros Sachtouris
        r = self.post(path, success=202)
73 5b263ba2 Stavros Sachtouris
        r.release()
74 0e4bec91 Stavros Sachtouris
75 379cd4bb Stavros Sachtouris
    def del_account_meta(self, metakey):
76 e6b39366 Stavros Sachtouris
        headers = self.get_account_info()
77 e742badc Stavros Sachtouris
        self.headers = filter_out(headers, 'X-Account-Meta-'+metakey, exactMatch = True)
78 e742badc Stavros Sachtouris
        if len(self.headers) == len(headers):
79 e6b39366 Stavros Sachtouris
            raise ClientError('X-Account-Meta-%s not found' % metakey, 404)
80 e6b39366 Stavros Sachtouris
        path = path4url(self.account)
81 5b263ba2 Stavros Sachtouris
        r = self.post(path, success = 202)
82 5b263ba2 Stavros Sachtouris
        r.release()
83 0e4bec91 Stavros Sachtouris
84 60560d7c Giorgos Verigakis
    def create_container(self, container):
85 6a0b1658 Giorgos Verigakis
        self.assert_account()
86 af3b2b36 Stavros Sachtouris
        path = path4url(self.account, container)
87 6a0b1658 Giorgos Verigakis
        r = self.put(path, success=(201, 202))
88 6a0b1658 Giorgos Verigakis
        if r.status_code == 202:
89 5b263ba2 Stavros Sachtouris
            r.release()
90 16d445fe Giorgos Verigakis
            raise ClientError("Container already exists", r.status_code)
91 5b263ba2 Stavros Sachtouris
        r.release()
92 44b8928d Giorgos Verigakis
93 6c4778ae Stavros Sachtouris
    def get_container_info(self, container):
94 6a0b1658 Giorgos Verigakis
        self.assert_account()
95 af3b2b36 Stavros Sachtouris
        path = path4url(self.account, container)
96 6a0b1658 Giorgos Verigakis
        r = self.head(path, success=(204, 404))
97 6a0b1658 Giorgos Verigakis
        if r.status_code == 404:
98 5b263ba2 Stavros Sachtouris
            r.release()
99 6a0b1658 Giorgos Verigakis
            raise ClientError("Container does not exist", r.status_code)
100 5b263ba2 Stavros Sachtouris
        reply = r.headers
101 5b263ba2 Stavros Sachtouris
        r.release()
102 5b263ba2 Stavros Sachtouris
        return reply
103 44b8928d Giorgos Verigakis
104 b66dfee7 Stavros Sachtouris
    def delete_container(self, container):
105 b66dfee7 Stavros Sachtouris
        self.assert_account()
106 af3b2b36 Stavros Sachtouris
        path = path4url(self.account, container)
107 b66dfee7 Stavros Sachtouris
        r = self.delete(path, success=(204, 404, 409))
108 b66dfee7 Stavros Sachtouris
        if r.status_code == 404:
109 5b263ba2 Stavros Sachtouris
            r.release()
110 b66dfee7 Stavros Sachtouris
            raise ClientError("Container does not exist", r.status_code)
111 b66dfee7 Stavros Sachtouris
        elif r.status_code == 409:
112 5b263ba2 Stavros Sachtouris
            r.release()
113 b66dfee7 Stavros Sachtouris
            raise ClientError("Container is not empty", r.status_code)
114 5b263ba2 Stavros Sachtouris
        r.release()
115 b66dfee7 Stavros Sachtouris
116 11f8eed3 Stavros Sachtouris
    def list_containers(self):
117 11f8eed3 Stavros Sachtouris
        self.assert_account()
118 2f749e6e Stavros Sachtouris
        self.set_param('format', 'json')
119 2f749e6e Stavros Sachtouris
        path = path4url(self.account)
120 e742badc Stavros Sachtouris
        r = self.get(path, success = (200, 204))
121 5b263ba2 Stavros Sachtouris
        reply = r.json
122 5b263ba2 Stavros Sachtouris
        r.release()
123 5b263ba2 Stavros Sachtouris
        return reply
124 11f8eed3 Stavros Sachtouris
125 65a45524 Stavros Sachtouris
    def upload_object(self, object, f, size=None):
126 6a0b1658 Giorgos Verigakis
        # This is a naive implementation, it loads the whole file in memory
127 8c4f0fbf Stavros Sachtouris
        #Look in pithos for a nice implementation
128 6a0b1658 Giorgos Verigakis
        self.assert_container()
129 af3b2b36 Stavros Sachtouris
        path = path4url(self.account, self.container, object)
130 188f23b9 Giorgos Verigakis
        data = f.read(size) if size is not None else f.read()
131 5b263ba2 Stavros Sachtouris
        r = self.put(path, data=data, success=201)
132 5b263ba2 Stavros Sachtouris
        r.release()
133 44b8928d Giorgos Verigakis
134 f3a722d4 Stavros Sachtouris
    def create_directory(self, object):
135 f3a722d4 Stavros Sachtouris
        self.assert_container()
136 af3b2b36 Stavros Sachtouris
        path = path4url(self.account, self.container, object)
137 4e68908f Stavros Sachtouris
        self.set_header('Content-Type', 'application/directory')
138 4e68908f Stavros Sachtouris
        self.set_header('Content-length', '0')
139 5b263ba2 Stavros Sachtouris
        r = self.put(path, success=201)
140 5b263ba2 Stavros Sachtouris
        r.release()
141 f3a722d4 Stavros Sachtouris
142 6c4778ae Stavros Sachtouris
    def get_object_info(self, object):
143 6c4778ae Stavros Sachtouris
        self.assert_container()
144 af3b2b36 Stavros Sachtouris
        path = path4url(self.account, self.container, object)
145 6c4778ae Stavros Sachtouris
        r = self.head(path, success=200)
146 5b263ba2 Stavros Sachtouris
        reply = r.headers
147 5b263ba2 Stavros Sachtouris
        r.release()
148 5b263ba2 Stavros Sachtouris
        return reply
149 6c4778ae Stavros Sachtouris
150 d0b42fb4 Stavros Sachtouris
    def get_object_meta(self, object):
151 f70616fc Stavros Sachtouris
        r = filter_in(self.get_object_info(object), 'X-Object-Meta-')
152 f70616fc Stavros Sachtouris
        reply = {}
153 f70616fc Stavros Sachtouris
        for (key, val) in r.items():
154 f70616fc Stavros Sachtouris
            metakey = key.split('-')[-1]
155 f70616fc Stavros Sachtouris
            reply[metakey] = val
156 f70616fc Stavros Sachtouris
        return reply
157 e6b39366 Stavros Sachtouris
158 89c2e77b Stavros Sachtouris
    def del_object_meta(self, metakey, object):
159 6de1f262 Stavros Sachtouris
        self.assert_container()
160 f70616fc Stavros Sachtouris
        self.set_header('X-Object-Meta-'+metakey, '')
161 e6b39366 Stavros Sachtouris
        path = path4url(self.account, self.container, object)
162 5b263ba2 Stavros Sachtouris
        r = self.post(path, success = 202)
163 5b263ba2 Stavros Sachtouris
        r.release()
164 d0b42fb4 Stavros Sachtouris
165 e742badc Stavros Sachtouris
    def replace_object_meta(self, metapairs):
166 af3b2b36 Stavros Sachtouris
        self.assert_container()
167 af3b2b36 Stavros Sachtouris
        path=path4url(self.account, self.container)
168 e742badc Stavros Sachtouris
        for key, val in metapairs:
169 e742badc Stavros Sachtouris
            self.set_header('X-Object-Meta-'+key, val)
170 5b263ba2 Stavros Sachtouris
        r = self.post(path, success=202)
171 5b263ba2 Stavros Sachtouris
        r.release()
172 0e4bec91 Stavros Sachtouris
173 176894c1 Giorgos Verigakis
    def get_object(self, object):
174 6a0b1658 Giorgos Verigakis
        self.assert_container()
175 af3b2b36 Stavros Sachtouris
        path = path4url(self.account, self.container, object)
176 2f749e6e Stavros Sachtouris
        r = self.get(path, success=200)
177 6a0b1658 Giorgos Verigakis
        size = int(r.headers['content-length'])
178 5b263ba2 Stavros Sachtouris
        cnt = r.content
179 5b263ba2 Stavros Sachtouris
        r.release()
180 5b263ba2 Stavros Sachtouris
        return cnt, size
181 44b8928d Giorgos Verigakis
182 c2867610 Stavros Sachtouris
    def copy_object(self, src_container, src_object, dst_container, dst_object=False):
183 c2867610 Stavros Sachtouris
        self.assert_account()
184 c2867610 Stavros Sachtouris
        dst_object = dst_object or src_object
185 c2867610 Stavros Sachtouris
        dst_path = path4url(self.account, dst_container, dst_object)
186 c2867610 Stavros Sachtouris
        self.set_header('X-Copy-From', path4url(src_container, src_object))
187 c2867610 Stavros Sachtouris
        self.set_header('Content-Length', 0)
188 5b263ba2 Stavros Sachtouris
        r = self.put(dst_path, success=201)
189 5b263ba2 Stavros Sachtouris
        r.release()
190 c2867610 Stavros Sachtouris
191 eed330ab Stavros Sachtouris
    def move_object(self, src_container, src_object, dst_container, dst_object=False):
192 eed330ab Stavros Sachtouris
        self.assert_account()
193 eed330ab Stavros Sachtouris
        dst_object = dst_object or src_object
194 eed330ab Stavros Sachtouris
        dst_path = path4url(self.account, dst_container, dst_object)
195 eed330ab Stavros Sachtouris
        self.set_header('X-Move-From', path4url(src_container, src_object))
196 eed330ab Stavros Sachtouris
        self.set_header('Content-Length', 0)
197 5b263ba2 Stavros Sachtouris
        r = self.put(dst_path, success=201)
198 5b263ba2 Stavros Sachtouris
        r.release()
199 eed330ab Stavros Sachtouris
200 a1c50326 Giorgos Verigakis
    def delete_object(self, object):
201 6a0b1658 Giorgos Verigakis
        self.assert_container()
202 af3b2b36 Stavros Sachtouris
        path = path4url(self.account, self.container, object)
203 bebdd0d6 Stavros Sachtouris
        r = self.delete(path, success=(204, 404))
204 bebdd0d6 Stavros Sachtouris
        if r.status_code == 404:
205 5b263ba2 Stavros Sachtouris
            r.release()
206 450bb2e6 Stavros Sachtouris
            raise ClientError("Object %s not found" %object, r.status_code)
207 5b263ba2 Stavros Sachtouris
        r.release()
208 e2bd16d5 Stavros Sachtouris
       
209 e2bd16d5 Stavros Sachtouris
    def list_objects(self):
210 2bcb595a Giorgos Verigakis
        self.assert_container()
211 af3b2b36 Stavros Sachtouris
        path = path4url(self.account, self.container)
212 2f749e6e Stavros Sachtouris
        self.set_param('format', 'json')
213 2f749e6e Stavros Sachtouris
        r = self.get(path, success=(200, 204, 304, 404), )
214 175f40ab Stavros Sachtouris
        if r.status_code == 404:
215 5b263ba2 Stavros Sachtouris
            r.release()
216 dd9a5d7c Stavros Sachtouris
            raise ClientError("Incorrect account (%s) for that container"%self.account, r.status_code)
217 16ce7b91 Stavros Sachtouris
        elif r.status_code == 304:
218 5b263ba2 Stavros Sachtouris
            r.release()
219 16ce7b91 Stavros Sachtouris
            return []
220 5b263ba2 Stavros Sachtouris
        reply = r.json
221 5b263ba2 Stavros Sachtouris
        r.release()
222 5b263ba2 Stavros Sachtouris
        return reply
223 e2bd16d5 Stavros Sachtouris
224 e2bd16d5 Stavros Sachtouris
    def list_objects_in_path(self, path_prefix):
225 a79f6d30 Stavros Sachtouris
        self.assert_container()
226 af3b2b36 Stavros Sachtouris
        path = path4url(self.account, self.container)
227 2f749e6e Stavros Sachtouris
        self.set_param('format', 'json')
228 2f749e6e Stavros Sachtouris
        self.set_param('path', 'path_prefix')
229 2f749e6e Stavros Sachtouris
        r = self.get(path, success=(200, 204, 404))
230 a79f6d30 Stavros Sachtouris
        if r.status_code == 404:
231 5b263ba2 Stavros Sachtouris
            r.release()
232 dd9a5d7c Stavros Sachtouris
            raise ClientError("Incorrect account (%s) for that container"%self.account, r.status_code)
233 5b263ba2 Stavros Sachtouris
        reply = r.json
234 5b263ba2 Stavros Sachtouris
        r.release()
235 5b263ba2 Stavros Sachtouris
        return reply