Revision 615e561b

b/pithos/lib/client.py
71 71
    
72 72
    def _chunked_transfer(self, path, method='PUT', f=stdin, headers=None,
73 73
                          blocksize=1024):
74
        
74 75
        http = HTTPConnection(self.host)
75 76
        
76 77
        # write header
77 78
        path = '/%s/%s%s' % (self.api, self.account, path)
78 79
        http.putrequest(method, path)
79
        http.putheader('X-Auth-Token', self.token)
80
        http.putheader('Content-Type', 'application/octet-stream')
81
        http.putheader('Transfer-Encoding', 'chunked')
80
        http.putheader('x-auth-token', self.token)
81
        http.putheader('content-type', 'application/octet-stream')
82
        http.putheader('transfer-encoding', 'chunked')
82 83
        if headers:
83 84
            for header,value in headers.items():
84 85
                http.putheader(header, value)
......
128 129
        #print '*',  resp.status, headers, data
129 130
        return resp.status, headers, data
130 131
    
131
    def req(self, method, path, body=None, headers=None, format='text',
132
    def _req(self, method, path, body=None, headers=None, format='text',
132 133
            params=None):
133 134
        full_path = '/%s/%s%s?format=%s' % (self.api, self.account, path,
134 135
                                            format)
......
147 148
        kwargs['headers'] = headers or {}
148 149
        kwargs['headers']['X-Auth-Token'] = self.token
149 150
        if not headers or \
150
        'Transfer-Encoding' not in headers \
151
        or headers['Transfer-Encoding'] != 'chunked':
152
            kwargs['headers']['Content-Length'] = len(body) if body else 0
151
        'transfer-encoding' not in headers \
152
        or headers['transfer-encoding'] != 'chunked':
153
            kwargs['headers']['content-length'] = len(body) if body else 0
153 154
        if body:
154 155
            kwargs['body'] = body
155 156
        else:
156
            kwargs['headers']['Content-Type'] = ''
157
        kwargs['headers'].setdefault('Content-Type', 'application/octet-stream')
157
            kwargs['headers']['content-type'] = ''
158
        kwargs['headers'].setdefault('content-type', 'application/octet-stream')
158 159
        try:
160
            #print '*', method, full_path, kwargs
159 161
            conn.request(method, full_path, **kwargs)
160 162
        except socket.error, e:
161 163
            raise Fault(status=503)
......
169 171
                print '%s: %s' % (key.capitalize(), val)
170 172
            print
171 173
        
172
        length = resp.getheader('Content-length', None)
174
        length = resp.getheader('content-length', None)
173 175
        data = resp.read(length)
174 176
        if self.debug:
175 177
            print data
......
182 184
        return resp.status, headers, data
183 185
    
184 186
    def delete(self, path, format='text'):
185
        return self.req('DELETE', path, format=format)
187
        return self._req('DELETE', path, format=format)
186 188
    
187 189
    def get(self, path, format='text', headers=None, params=None):
188
        return self.req('GET', path, headers=headers, format=format,
190
        return self._req('GET', path, headers=headers, format=format,
189 191
                        params=params)
190 192
    
191 193
    def head(self, path, format='text', params=None):
192
        return self.req('HEAD', path, format=format, params=params)
194
        return self._req('HEAD', path, format=format, params=params)
193 195
    
194 196
    def post(self, path, body=None, format='text', headers=None, params=None):
195
        return self.req('POST', path, body, headers=headers, format=format,
197
        return self._req('POST', path, body, headers=headers, format=format,
196 198
                        params=params)
197 199
    
198 200
    def put(self, path, body=None, format='text', headers=None):
199
        return self.req('PUT', path, body, headers=headers, format=format)
201
        return self._req('PUT', path, body, headers=headers, format=format)
200 202
    
201 203
    def _list(self, path, detail=False, params=None, headers=None):
202 204
        format = 'json' if detail else 'text'
......
229 231
        prefix = 'x-%s-meta-' % entity
230 232
        for k,v in meta.items():
231 233
            k = '%s%s' % (prefix, k)
232
            k = '-'.join(elem.capitalize() for elem in k.split('-'))
233 234
            headers[k] = v
234
        self.post(path, headers=headers, params=params)
235
        return self.post(path, headers=headers, params=params)
235 236
    
236 237
    def _delete_metadata(self, path, entity, meta=[]):
237 238
        """
238 239
        delete previously set metadata
239 240
        """
240
        prefix = 'x-%s-meta-' % entity
241
        prev_meta = self._get_metadata(path, prefix)
241
        params = {'update':None}
242 242
        headers = {}
243
        for key, val in prev_meta.items():
244
            if key in meta:
245
                continue
246
            key = '%s%s' % (prefix, key)
247
            key = '-'.join(elem.capitalize() for elem in key.split('-'))
248
            headers[key] = val
249
        self.post(path, headers=headers)
243
        prefix = 'x-%s-meta-' % entity
244
        for m in meta:
245
            headers['%s%s' % (prefix, m)] = None
246
        return self.post(path, headers=headers)
250 247
    
251 248
    # Storage Account Services
252 249
    
......
259 256
        return self._get_metadata('', prefix, params=params)
260 257
    
261 258
    def update_account_metadata(self, **meta):
262
        self._update_metadata('', 'account', **meta)
259
        return self._update_metadata('', 'account', **meta)
263 260
        
264 261
    def delete_account_metadata(self, meta=[]):
265
        self._delete_metadata('', 'account', meta)
262
        return self._delete_metadata('', 'account', meta)
266 263
    
267 264
    def set_account_groups(self, **groups):
265
        """
266
        create account groups
267
        """
268 268
        headers = {}
269 269
        for key, val in groups.items():
270
            headers['X-Account-Group-%s' % key.capitalize()] = val
271
        self.post('', headers=headers)
270
            headers['x-account-group-%s' % key] = val
271
        params = {'update':None}
272
        return self.post('', headers=headers, params=params)
273
    
274
    def unset_account_groups(self, groups=[]):
275
        """
276
        delete account groups
277
        """
278
        headers = {}
279
        for elem in groups:
280
            headers['x-account-group-%s' % elem] = ''
281
        params = {'update':None}
282
        return self.post('', headers=headers, params=params)
272 283
    
273 284
    # Storage Container Services
274 285
    
......
298 309
    
299 310
    def create_container(self, container, headers=None, **meta):
300 311
        for k,v in meta.items():
301
            headers['X-Container-Meta-%s' %k.strip().upper()] = v.strip()
312
            headers['x-container-meta-%s' %k.strip().upper()] = v.strip()
302 313
        status, header, data = self.put('/' + container, headers=headers)
303 314
        if status == 202:
304 315
            return False
......
307 318
        return True
308 319
    
309 320
    def delete_container(self, container):
310
        self.delete('/' + container)
321
        return self.delete('/' + container)
311 322
    
312 323
    def retrieve_container_metadata(self, container, restricted=False,
313 324
                                    until=None):
......
316 327
        return self._get_metadata('/%s' % container, prefix, params=params)
317 328
    
318 329
    def update_container_metadata(self, container, **meta):
319
        self._update_metadata('/' + container, 'container', **meta)
330
        return self._update_metadata('/' + container, 'container', **meta)
320 331
        
321 332
    def delete_container_metadata(self, container, meta=[]):
322 333
        path = '/%s' % (container)
323
        self._delete_metadata(path, 'container', meta)
334
        return self._delete_metadata(path, 'container', meta)
324 335
    
325 336
    def set_container_policies(self, container, **policies):
326 337
        path = '/%s' % (container)
327 338
        headers = {}
328 339
        print ''
329 340
        for key, val in policies.items():
330
            headers['X-Container-Policy-%s' % key.capitalize()] = val
331
        self.post(path, headers=headers)
341
            headers['x-container-policy-%s' % key] = val
342
        return self.post(path, headers=headers)
332 343
    
333 344
    # Storage Object Services
334 345
    
......
344 355
        if not object:
345 356
            raise Fault('Directory markers have to be nested in a container')
346 357
        h = {'Content-Type':'application/directory'}
347
        self.create_object(container, object, f=None, headers=h)
358
        return self.create_object(container, object, f=None, headers=h)
348 359
    
349
    def _set_public(self, headers, public=False):
360
    def _set_public_header(self, headers, public=False):
350 361
        """
351 362
        sets the public header
352 363
        """
353 364
        if public == None:
354 365
            return
355 366
        elif public:
356
            headers['X-Object-Public'] = public
367
            headers['x-object-public'] = public
357 368
        else:
358
            headers['X-Object-Public'] = ''
369
            headers['x-object-public'] = ''
359 370
    
360 371
    def create_object(self, container, object, f=stdin, chunked=False,
361 372
                      blocksize=1024, headers={}, use_hashes=False,
......
367 378
        """
368 379
        path = '/%s/%s' % (container, object)
369 380
        for k,v in meta.items():
370
            headers['X-Object-Meta-%s' %k.strip().upper()] = v.strip()
371
        self._set_public(headers, public)
381
            headers['x-object-meta-%s' %k.strip().upper()] = v.strip()
382
        self._set_public_header(headers, public)
372 383
        headers = headers if headers else None
373 384
        if not chunked:
374 385
            format = 'json' if use_hashes else 'text'
375 386
            data = f.read() if f else None
376 387
            if data:
377 388
                if format == 'json':
378
                    data = eval(data)
379
                    data = json.dumps(data)
389
                    try:
390
                        data = eval(data)
391
                        data = json.dumps(data)
392
                    except SyntaxError:
393
                        raise Fault('Invalid formatting')
380 394
            return self.put(path, data, headers=headers, format=format)
381 395
        else:
382 396
            return self._chunked_transfer(path, 'PUT', f, headers=headers,
383 397
                                   blocksize=1024)
384 398
    
399
    def update_object_data(self, container, object, data=None, headers={},
400
                      offset=None, public=None, **meta):
401
        path = '/%s/%s' % (container, object)
402
        for k,v in meta.items():
403
            headers['x-object-meta-%s' %k.strip()] = v.strip()
404
        if 'content-range' not in headers.keys():
405
            if offset:
406
                headers['content-range'] = 'bytes %s-/*' % offset
407
            else:
408
                headers['content-range'] = 'bytes */*'
409
        self._set_public_header(headers, public)
410
        headers = headers if headers else None
411
        return self.post(path, data, headers=headers)
412
    
385 413
    def update_object(self, container, object, f=stdin, chunked=False,
386 414
                      blocksize=1024, headers={}, offset=None, public=None,
387 415
                      **meta):
388
        print locals()
389 416
        path = '/%s/%s' % (container, object)
390 417
        for k,v in meta.items():
391
            headers['X-Object-Meta-%s' %k.strip().upper()] = v.strip()
418
            headers['x-object-meta-%s' %k.strip()] = v.strip()
392 419
        if offset:
393
            headers['Content-Range'] = 'bytes %s-/*' % offset
420
            headers['content-range'] = 'bytes %s-/*' % offset
394 421
        else:
395
            headers['Content-Range'] = 'bytes */*'
396
        self._set_public(headers, public)
422
            headers['content-range'] = 'bytes */*'
423
        self._set_public_header(headers, public)
397 424
        headers = headers if headers else None
398 425
        if not chunked and f != stdin:
399 426
            data = f.read() if f else None
400
            self.post(path, data, headers=headers)
427
            return self.post(path, data, headers=headers)
401 428
        else:
402
            self._chunked_transfer(path, 'POST', f, headers=headers,
429
            return self._chunked_transfer(path, 'POST', f, headers=headers,
403 430
                                   blocksize=1024)
404 431
    
405 432
    def _change_obj_location(self, src_container, src_object, dst_container,
406
                             dst_object, remove=False, public=None, headers={}):
433
                             dst_object, remove=False, public=False, **meta):
407 434
        path = '/%s/%s' % (dst_container, dst_object)
408
        if not headers:
409
            headers = {}
435
        headers = {}
436
        for k, v in meta.items():
437
            headers['x-object-meta-%s' % k] = v 
410 438
        if remove:
411
            headers['X-Move-From'] = '/%s/%s' % (src_container, src_object)
439
            headers['x-move-from'] = '/%s/%s' % (src_container, src_object)
412 440
        else:
413
            headers['X-Copy-From'] = '/%s/%s' % (src_container, src_object)
414
        self._set_public(headers, public)
441
            headers['x-copy-from'] = '/%s/%s' % (src_container, src_object)
442
        self._set_public_header(headers, public)
415 443
        self.headers = headers if headers else None
416
        headers['Content-Length'] = 0
417
        self.put(path, headers=headers)
444
        headers['content-length'] = 0
445
        return self.put(path, headers=headers)
418 446
    
419 447
    def copy_object(self, src_container, src_object, dst_container,
420
                             dst_object, public=False, headers=None):
421
        self._change_obj_location(src_container, src_object,
422
                                   dst_container, dst_object,
423
                                   public, headers)
448
                             dst_object, public=False, **meta):
449
        return self._change_obj_location(src_container, src_object,
450
                                   dst_container, dst_object, False,
451
                                   public, **meta)
424 452
    
425 453
    def move_object(self, src_container, src_object, dst_container,
426
                             dst_object, headers=None):
427
        self._change_obj_location(src_container, src_object,
454
                             dst_object, public=False, **meta):
455
        return self._change_obj_location(src_container, src_object,
428 456
                                   dst_container, dst_object, True,
429
                                   public, headers)
457
                                   public, **meta)
430 458
    
431 459
    def delete_object(self, container, object):
432
        self.delete('/%s/%s' % (container, object))
460
        return self.delete('/%s/%s' % (container, object))
433 461
    
434 462
    def retrieve_object_metadata(self, container, object, restricted=False,
435 463
                                 version=None):
464
        """
465
        set restricted to True to get only user defined metadata
466
        """
436 467
        path = '/%s/%s' % (container, object)
437 468
        prefix = 'x-object-meta-' if restricted else None
438 469
        params = {'version':version} if version else None
......
440 471
    
441 472
    def update_object_metadata(self, container, object, **meta):
442 473
        path = '/%s/%s' % (container, object)
443
        self._update_metadata(path, 'object', **meta)
474
        return self._update_metadata(path, 'object', **meta)
444 475
    
445 476
    def delete_object_metadata(self, container, object, meta=[]):
446 477
        path = '/%s/%s' % (container, object)
447
        self._delete_metadata(path, 'object', meta)
478
        return self._delete_metadata(path, 'object', meta)
448 479
    
449 480
    def trash_object(self, container, object):
450 481
        """
......
453 484
        """
454 485
        path = '/%s/%s' % (container, object)
455 486
        meta = {'trash':'true'}
456
        self._update_metadata(path, 'object', **meta)
487
        return self._update_metadata(path, 'object', **meta)
457 488
    
458 489
    def restore_object(self, container, object):
459 490
        """
460 491
        restores a trashed object
461 492
        actualy removes trash object metadata info
462 493
        """
463
        self.delete_object_metadata(container, object, ['trash'])
494
        return self.delete_object_metadata(container, object, ['trash'])
464 495
    
465 496
    def publish_object(self, container, object):
466 497
        """
467 498
        sets a previously created object publicly accessible
468 499
        """
469 500
        path = '/%s/%s' % (container, object)
470
        headers = {}
471
        headers['Content-Range'] = 'bytes */*'
472
        self._set_public(headers, public=True)
473
        self.post(path, headers=headers)
501
        headers = {'content-range':'bytes */*'}
502
        self._set_public_header(headers, public=True)
503
        return self.post(path, headers=headers)
474 504
    
475 505
    def unpublish_object(self, container, object):
476 506
        """
477 507
        unpublish an object
478 508
        """
479 509
        path = '/%s/%s' % (container, object)
480
        headers = {}
481
        headers['Content-Range'] = 'bytes */*'
482
        self._set_public(headers, public=False)
483
        self.post(path, headers=headers)
510
        headers = {'content-range':'bytes */*'}
511
        self._set_public_header(headers, public=False)
512
        return self.post(path, headers=headers)
b/tools/store
47 47
import time as _time
48 48
import os
49 49

  
50
DEFAULT_HOST = 'pithos.dev.grnet.gr'
50
#DEFAULT_HOST = 'pithos.dev.grnet.gr'
51
DEFAULT_HOST = '127.0.0.1:8000'
51 52
DEFAULT_API = 'v1'
52 53

  
53 54
_cli_commands = {}

Also available in: Unified diff