Revision e3fd7f91
b/pithos/lib/client.py | ||
---|---|---|
4 | 4 |
import json |
5 | 5 |
import types |
6 | 6 |
import socket |
7 |
import pithos.api.faults |
|
8 |
|
|
9 |
ERROR_CODES = {304:'Not Modified', |
|
10 |
400:'Bad Request', |
|
11 |
401:'Unauthorized', |
|
12 |
404:'Not Found', |
|
13 |
409:'Conflict', |
|
14 |
411:'Length Required', |
|
15 |
412:'Precondition Failed', |
|
16 |
416:'Range Not Satisfiable', |
|
17 |
422:'Unprocessable Entity', |
|
18 |
503:'Service Unavailable'} |
|
7 | 19 |
|
8 | 20 |
class Fault(Exception): |
9 |
def __init__(self, data=''): |
|
21 |
def __init__(self, data='', status=None): |
|
22 |
if data == '' and status in ERROR_CODES.keys(): |
|
23 |
data = ERROR_CODES[status] |
|
10 | 24 |
Exception.__init__(self, data) |
11 | 25 |
self.data = data |
12 |
|
|
26 |
self.status = status |
|
13 | 27 |
|
14 | 28 |
class Client(object): |
15 | 29 |
def __init__(self, host, account, api='v1', verbose=False, debug=False): |
... | ... | |
20 | 34 |
self.api = api |
21 | 35 |
self.verbose = verbose or debug |
22 | 36 |
self.debug = debug |
23 |
|
|
37 |
|
|
24 | 38 |
def _chunked_transfer(self, path, method='PUT', f=stdin, headers=None, |
25 | 39 |
blocksize=1024): |
26 | 40 |
http = HTTPConnection(self.host) |
... | ... | |
58 | 72 |
|
59 | 73 |
# get response |
60 | 74 |
resp = http.getresponse() |
75 |
|
|
61 | 76 |
headers = dict(resp.getheaders()) |
62 | 77 |
|
63 | 78 |
if self.verbose: |
... | ... | |
71 | 86 |
print data |
72 | 87 |
|
73 | 88 |
|
89 |
if data: |
|
90 |
assert data[-1] == '\n' |
|
91 |
#remove trailing enter |
|
92 |
data = data and data[:-1] or data |
|
93 |
|
|
94 |
if int(resp.status) in ERROR_CODES.keys(): |
|
95 |
raise Fault(data, int(resp.status)) |
|
96 |
|
|
74 | 97 |
return resp.status, headers, data |
75 | 98 |
|
76 | 99 |
def req(self, method, path, body=None, headers=None, format='text', |
... | ... | |
96 | 119 |
kwargs['body'] = body |
97 | 120 |
kwargs['headers']['Content-Type'] = 'application/octet-stream' |
98 | 121 |
#print '****', method, full_path, kwargs |
99 |
#TODO catch socket.error |
|
100 |
conn.request(method, full_path, **kwargs) |
|
122 |
try: |
|
123 |
conn.request(method, full_path, **kwargs) |
|
124 |
except socket.error, e: |
|
125 |
raise Fault(status=503) |
|
126 |
|
|
101 | 127 |
resp = conn.getresponse() |
102 | 128 |
headers = dict(resp.getheaders()) |
103 | 129 |
|
... | ... | |
117 | 143 |
#remove trailing enter |
118 | 144 |
data = data and data[:-1] or data |
119 | 145 |
|
146 |
if int(resp.status) in ERROR_CODES.keys(): |
|
147 |
raise Fault(data, int(resp.status)) |
|
148 |
|
|
149 |
#print '*', resp.status, headers, data |
|
120 | 150 |
return resp.status, headers, data |
121 | 151 |
|
122 | 152 |
def delete(self, path, format='text'): |
... | ... | |
147 | 177 |
|
148 | 178 |
def _get_metadata(self, path, prefix=None, params=None): |
149 | 179 |
status, headers, data = self.head(path, params=params) |
150 |
if status == '404': |
|
151 |
return None |
|
152 | 180 |
prefixlen = prefix and len(prefix) or 0 |
153 | 181 |
meta = {} |
154 | 182 |
for key, val in headers.items(): |
... | ... | |
189 | 217 |
if status == 202: |
190 | 218 |
return False |
191 | 219 |
elif status != 201: |
192 |
raise Fault(data) |
|
220 |
raise Fault(data, int(status))
|
|
193 | 221 |
return True |
194 | 222 |
|
195 | 223 |
def delete_container(self, container): |
... | ... | |
222 | 250 |
path = '/%s/%s' % (container, object) |
223 | 251 |
if not chunked and f != stdin: |
224 | 252 |
data = f and f.read() or None |
225 |
self.put(path, data, headers=headers) |
|
253 |
return self.put(path, data, headers=headers)
|
|
226 | 254 |
else: |
227 |
self._chunked_transfer(path, 'PUT', f, headers=headers, |
|
255 |
return self._chunked_transfer(path, 'PUT', f, headers=headers,
|
|
228 | 256 |
blocksize=1024) |
229 | 257 |
|
230 | 258 |
def update_object(self, container, object, f=stdin, chunked=False, |
b/tools/store | ||
---|---|---|
57 | 57 |
|
58 | 58 |
self.parser = parser |
59 | 59 |
self.args = args |
60 |
|
|
60 |
|
|
61 | 61 |
def add_options(self, parser): |
62 | 62 |
pass |
63 | 63 |
|
... | ... | |
105 | 105 |
self.list_objects(container) |
106 | 106 |
else: |
107 | 107 |
self.list_containers() |
108 |
|
|
108 |
|
|
109 | 109 |
def list_containers(self): |
110 | 110 |
params = {'limit':self.limit, 'marker':self.marker} |
111 | 111 |
headers = {'IF_MODIFIED_SINCE':self.if_modified_since, |
... | ... | |
148 | 148 |
default=False, help='show metadata until that date') |
149 | 149 |
parser.add_option('--format', action='store', dest='format', |
150 | 150 |
default='%d/%m/%Y', help='format to parse until date') |
151 |
parser.add_option('--version', action='store', dest='version', |
|
152 |
default=None, help='show specific version \ |
|
153 |
(applies only for objects)') |
|
151 | 154 |
|
152 | 155 |
def execute(self, path=''): |
153 | 156 |
container, sep, object = path.partition('/') |
... | ... | |
263 | 266 |
dest='manifest', default=None, |
264 | 267 |
help='use for large file support') |
265 | 268 |
parser.add_option('--touch', action='store_true', |
266 |
dest='touch', default=True,
|
|
269 |
dest='touch', default=False,
|
|
267 | 270 |
help='create object with zero data') |
268 | 271 |
|
269 | 272 |
def execute(self, path, srcpath='-', *args): |
... | ... | |
334 | 337 |
@cli_command('update') |
335 | 338 |
class UpdateObject(Command): |
336 | 339 |
syntax = '<container>/<object> path [key=val] [...]' |
337 |
description = 'update object metadata/data' |
|
340 |
description = 'update object metadata/data (default mode: append)'
|
|
338 | 341 |
|
339 | 342 |
def add_options(self, parser): |
340 | 343 |
parser.add_option('-a', action='store_true', dest='append', |
341 |
default=None, help='append data')
|
|
344 |
default=True, help='append data')
|
|
342 | 345 |
parser.add_option('--start', action='store', |
343 | 346 |
dest='start', |
344 | 347 |
default=None, help='range of data to be updated') |
... | ... | |
356 | 359 |
dest='manifest', default=None, |
357 | 360 |
help='use for large file support') |
358 | 361 |
|
359 |
def execute(self, path, srcpath, *args): |
|
362 |
def execute(self, path, srcpath='-', *args):
|
|
360 | 363 |
headers = {} |
361 | 364 |
if self.manifest: |
362 | 365 |
headers['X_OBJECT_MANIFEST'] = self.manifest |
... | ... | |
451 | 454 |
|
452 | 455 |
try: |
453 | 456 |
cmd.execute(*cmd.args) |
454 |
except TypeError: |
|
457 |
except TypeError, e: |
|
458 |
print e |
|
455 | 459 |
cmd.parser.usage = '%%prog %s [options] %s' % (name, cmd.syntax) |
456 | 460 |
cmd.parser.print_help() |
457 | 461 |
exit(1) |
458 | 462 |
except Fault, f: |
459 |
print f.data |
|
463 |
print f.status, f.data
|
|
460 | 464 |
|
461 | 465 |
if __name__ == '__main__': |
462 | 466 |
main() |
Also available in: Unified diff