~ubuntu-branches/ubuntu/raring/swift/raring-security

« back to all changes in this revision

Viewing changes to bin/swift

  • Committer: Package Import Robot
  • Author(s): Chuck Short
  • Date: 2012-04-10 09:23:54 UTC
  • mfrom: (1.2.9)
  • Revision ID: package-import@ubuntu.com-20120410092354-5z06qt1jal4wtoxf
Tags: 1.4.8-0ubuntu1
* New upstream release.
* debian/patches/fix-ubuntu-unittests.patch: Refreshed. 
* debian/patches/fix-doc-no-network.patch: Dont access network when
  trying to build docs.

Show diffs side-by-side

added added

removed removed

Lines of Context:
1
1
#!/usr/bin/python -u
2
 
# Copyright (c) 2010-2011 OpenStack, LLC.
 
2
# Copyright (c) 2010-2012 OpenStack, LLC.
3
3
#
4
4
# Licensed under the Apache License, Version 2.0 (the "License");
5
5
# you may not use this file except in compliance with the License.
30
30
# Inclusion of swift.common.client for convenience of single file distribution
31
31
 
32
32
import socket
33
 
from cStringIO import StringIO
34
 
from re import compile, DOTALL
35
 
from tokenize import generate_tokens, STRING, NAME, OP
36
33
from urllib import quote as _quote
37
34
from urlparse import urlparse, urlunparse, urljoin
38
35
 
80
77
 
81
78
    def __init__(self, msg, http_scheme='', http_host='', http_port='',
82
79
                 http_path='', http_query='', http_status=0, http_reason='',
83
 
                 http_device=''):
 
80
                 http_device='', http_response_content=''):
84
81
        Exception.__init__(self, msg)
85
82
        self.msg = msg
86
83
        self.http_scheme = http_scheme
91
88
        self.http_status = http_status
92
89
        self.http_reason = http_reason
93
90
        self.http_device = http_device
 
91
        self.http_response_content = http_response_content
94
92
 
95
93
    def __str__(self):
96
94
        a = self.msg
120
118
                b = '%s: device %s' % (b, self.http_device)
121
119
            else:
122
120
                b = 'device %s' % self.http_device
 
121
        if self.http_response_content:
 
122
            if len(self.http_response_content) <= 60:
 
123
                b += '   %s' % self.http_response_content
 
124
            else:
 
125
                b += '  [first 60 chars of response] %s' % \
 
126
                   self.http_response_content[:60]
123
127
        return b and '%s: %s' % (a, b) or a
124
128
 
125
129
 
147
151
    return parsed, conn
148
152
 
149
153
 
 
154
def json_request(method, url, **kwargs):
 
155
    """Takes a request in json parse it and return in json"""
 
156
    kwargs.setdefault('headers', {})
 
157
    if 'body' in kwargs:
 
158
        kwargs['headers']['Content-Type'] = 'application/json'
 
159
        kwargs['body'] = json_dumps(kwargs['body'])
 
160
    parsed, conn = http_connection(url)
 
161
    conn.request(method, parsed.path, **kwargs)
 
162
    resp = conn.getresponse()
 
163
    body = resp.read()
 
164
    if body:
 
165
        try:
 
166
            body = json_loads(body)
 
167
        except ValueError:
 
168
            body = None
 
169
    if not body or resp.status < 200 or resp.status >= 300:
 
170
        raise ClientException('Auth GET failed', http_scheme=parsed.scheme,
 
171
                              http_host=conn.host,
 
172
                              http_port=conn.port,
 
173
                              http_path=parsed.path,
 
174
                              http_status=resp.status,
 
175
                              http_reason=resp.reason)
 
176
    return resp, body
 
177
 
 
178
 
150
179
def get_conn(options):
151
180
    """
152
181
    Return a connection building it from the options.
173
202
    if snet:
174
203
        parsed = list(urlparse(url))
175
204
        # Second item in the list is the netloc
176
 
        parsed[1] = 'snet-' + parsed[1]
 
205
        netloc = parsed[1]
 
206
        parsed[1] = 'snet-' + netloc
177
207
        url = urlunparse(parsed)
178
208
    return url, resp.getheader('x-storage-token',
179
209
                                                resp.getheader('x-auth-token'))
185
215
    else:
186
216
        tenant = user
187
217
 
188
 
    def json_request(method, token_url, **kwargs):
189
 
        kwargs.setdefault('headers', {})
190
 
        if 'body' in kwargs:
191
 
            kwargs['headers']['Content-Type'] = 'application/json'
192
 
            kwargs['body'] = json_dumps(kwargs['body'])
193
 
        parsed, conn = http_connection(token_url)
194
 
        conn.request(method, parsed.path, **kwargs)
195
 
        resp = conn.getresponse()
196
 
        body = resp.read()
197
 
        if body:
198
 
            try:
199
 
                body = json_loads(body)
200
 
            except ValueError:
201
 
                pass
202
 
        else:
203
 
            body = None
204
 
        if resp.status < 200 or resp.status >= 300:
205
 
            raise ClientException('Auth GET failed', http_scheme=parsed.scheme,
206
 
                                  http_host=conn.host,
207
 
                                  http_port=conn.port,
208
 
                                  http_path=parsed.path,
209
 
                                  http_status=resp.status,
210
 
                                  http_reason=resp.reason)
211
 
        return resp, body
212
218
    body = {"auth": {"tenantName": tenant,
213
219
                     "passwordCredentials":
214
220
                         {"username": user, "password": key}}}
253
259
    :param snet: use SERVICENET internal network (see above), default is False
254
260
    :param auth_version: OpenStack authentication version (default is 1.0)
255
261
    :returns: tuple of (storage URL, auth token)
256
 
    :raises ClientException: HTTP GET request to auth URL failed
 
262
    :raises: ClientException: HTTP GET request to auth URL failed
257
263
    """
258
 
    if auth_version == "1.0" or auth_version == "1":
 
264
    if auth_version in ["1.0", "1"]:
259
265
        return _get_auth_v1_0(url, user, key, snet)
260
 
    elif auth_version == "2.0" or auth_version == "2":
 
266
    elif auth_version in ["2.0", "2"]:
261
267
        return _get_auth_v2_0(url, user, key, snet)
262
268
 
263
269
 
306
312
    for header, value in resp.getheaders():
307
313
        resp_headers[header.lower()] = value
308
314
    if resp.status < 200 or resp.status >= 300:
309
 
        resp.read()
 
315
        body = resp.read()
310
316
        raise ClientException('Account GET failed', http_scheme=parsed.scheme,
311
317
                http_host=conn.host, http_port=conn.port,
312
318
                http_path=parsed.path, http_query=qs, http_status=resp.status,
313
 
                http_reason=resp.reason)
 
319
                http_reason=resp.reason, http_response_content=body)
314
320
    if resp.status == 204:
315
321
        resp.read()
316
322
        return resp_headers, []
335
341
        parsed, conn = http_connection(url)
336
342
    conn.request('HEAD', parsed.path, '', {'X-Auth-Token': token})
337
343
    resp = conn.getresponse()
338
 
    resp.read()
 
344
    body = resp.read()
339
345
    if resp.status < 200 or resp.status >= 300:
340
346
        raise ClientException('Account HEAD failed', http_scheme=parsed.scheme,
341
347
                http_host=conn.host, http_port=conn.port,
342
348
                http_path=parsed.path, http_status=resp.status,
343
 
                http_reason=resp.reason)
 
349
                http_reason=resp.reason, http_response_content=body)
344
350
    resp_headers = {}
345
351
    for header, value in resp.getheaders():
346
352
        resp_headers[header.lower()] = value
365
371
    headers['X-Auth-Token'] = token
366
372
    conn.request('POST', parsed.path, '', headers)
367
373
    resp = conn.getresponse()
368
 
    resp.read()
 
374
    body = resp.read()
369
375
    if resp.status < 200 or resp.status >= 300:
370
376
        raise ClientException('Account POST failed',
371
377
                              http_scheme=parsed.scheme,
373
379
                              http_port=conn.port,
374
380
                              http_path=parsed.path,
375
381
                              http_status=resp.status,
376
 
                              http_reason=resp.reason)
 
382
                              http_reason=resp.reason,
 
383
                              http_response_content=body)
377
384
 
378
385
 
379
386
def get_container(url, token, container, marker=None, limit=None,
427
434
    conn.request('GET', '%s?%s' % (path, qs), '', {'X-Auth-Token': token})
428
435
    resp = conn.getresponse()
429
436
    if resp.status < 200 or resp.status >= 300:
430
 
        resp.read()
 
437
        body = resp.read()
431
438
        raise ClientException('Container GET failed',
432
439
                http_scheme=parsed.scheme, http_host=conn.host,
433
440
                http_port=conn.port, http_path=path, http_query=qs,
434
 
                http_status=resp.status, http_reason=resp.reason)
 
441
                http_status=resp.status, http_reason=resp.reason,
 
442
                http_response_content=body)
435
443
    resp_headers = {}
436
444
    for header, value in resp.getheaders():
437
445
        resp_headers[header.lower()] = value
441
449
    return resp_headers, json_loads(resp.read())
442
450
 
443
451
 
444
 
def head_container(url, token, container, http_conn=None):
 
452
def head_container(url, token, container, http_conn=None, headers=None):
445
453
    """
446
454
    Get container stats.
447
455
 
459
467
    else:
460
468
        parsed, conn = http_connection(url)
461
469
    path = '%s/%s' % (parsed.path, quote(container))
462
 
    conn.request('HEAD', path, '', {'X-Auth-Token': token})
 
470
    req_headers = {'X-Auth-Token': token}
 
471
    if headers:
 
472
        req_headers.update(headers)
 
473
    conn.request('HEAD', path, '', req_headers)
463
474
    resp = conn.getresponse()
464
 
    resp.read()
 
475
    body = resp.read()
465
476
    if resp.status < 200 or resp.status >= 300:
466
477
        raise ClientException('Container HEAD failed',
467
478
                http_scheme=parsed.scheme, http_host=conn.host,
468
479
                http_port=conn.port, http_path=path, http_status=resp.status,
469
 
                http_reason=resp.reason)
 
480
                http_reason=resp.reason, http_response_content=body)
470
481
    resp_headers = {}
471
482
    for header, value in resp.getheaders():
472
483
        resp_headers[header.lower()] = value
495
506
    headers['X-Auth-Token'] = token
496
507
    conn.request('PUT', path, '', headers)
497
508
    resp = conn.getresponse()
498
 
    resp.read()
 
509
    body = resp.read()
499
510
    if resp.status < 200 or resp.status >= 300:
500
511
        raise ClientException('Container PUT failed',
501
512
                http_scheme=parsed.scheme, http_host=conn.host,
502
513
                http_port=conn.port, http_path=path, http_status=resp.status,
503
 
                http_reason=resp.reason)
 
514
                http_reason=resp.reason, http_response_content=body)
504
515
 
505
516
 
506
517
def post_container(url, token, container, headers, http_conn=None):
523
534
    headers['X-Auth-Token'] = token
524
535
    conn.request('POST', path, '', headers)
525
536
    resp = conn.getresponse()
526
 
    resp.read()
 
537
    body = resp.read()
527
538
    if resp.status < 200 or resp.status >= 300:
528
539
        raise ClientException('Container POST failed',
529
540
                http_scheme=parsed.scheme, http_host=conn.host,
530
541
                http_port=conn.port, http_path=path, http_status=resp.status,
531
 
                http_reason=resp.reason)
 
542
                http_reason=resp.reason, http_response_content=body)
532
543
 
533
544
 
534
545
def delete_container(url, token, container, http_conn=None):
549
560
    path = '%s/%s' % (parsed.path, quote(container))
550
561
    conn.request('DELETE', path, '', {'X-Auth-Token': token})
551
562
    resp = conn.getresponse()
552
 
    resp.read()
 
563
    body = resp.read()
553
564
    if resp.status < 200 or resp.status >= 300:
554
565
        raise ClientException('Container DELETE failed',
555
566
                http_scheme=parsed.scheme, http_host=conn.host,
556
567
                http_port=conn.port, http_path=path, http_status=resp.status,
557
 
                http_reason=resp.reason)
 
568
                http_reason=resp.reason, http_response_content=body)
558
569
 
559
570
 
560
571
def get_object(url, token, container, name, http_conn=None,
584
595
    conn.request('GET', path, '', {'X-Auth-Token': token})
585
596
    resp = conn.getresponse()
586
597
    if resp.status < 200 or resp.status >= 300:
587
 
        resp.read()
 
598
        body = resp.read()
588
599
        raise ClientException('Object GET failed', http_scheme=parsed.scheme,
589
600
                http_host=conn.host, http_port=conn.port, http_path=path,
590
 
                http_status=resp.status, http_reason=resp.reason)
 
601
                http_status=resp.status, http_reason=resp.reason,
 
602
                http_response_content=body)
591
603
    if resp_chunk_size:
592
604
 
593
605
        def _object_body():
625
637
    path = '%s/%s/%s' % (parsed.path, quote(container), quote(name))
626
638
    conn.request('HEAD', path, '', {'X-Auth-Token': token})
627
639
    resp = conn.getresponse()
628
 
    resp.read()
 
640
    body = resp.read()
629
641
    if resp.status < 200 or resp.status >= 300:
630
642
        raise ClientException('Object HEAD failed', http_scheme=parsed.scheme,
631
643
                http_host=conn.host, http_port=conn.port, http_path=path,
632
 
                http_status=resp.status, http_reason=resp.reason)
 
644
                http_status=resp.status, http_reason=resp.reason,
 
645
                http_response_content=body)
633
646
    resp_headers = {}
634
647
    for header, value in resp.getheaders():
635
648
        resp_headers[header.lower()] = value
719
732
    else:
720
733
        conn.request('PUT', path, contents, headers)
721
734
    resp = conn.getresponse()
722
 
    resp.read()
 
735
    body = resp.read()
723
736
    if resp.status < 200 or resp.status >= 300:
724
737
        raise ClientException('Object PUT failed', http_scheme=parsed.scheme,
725
738
                http_host=conn.host, http_port=conn.port, http_path=path,
726
 
                http_status=resp.status, http_reason=resp.reason)
 
739
                http_status=resp.status, http_reason=resp.reason,
 
740
                http_response_content=body)
727
741
    return resp.getheader('etag', '').strip('"')
728
742
 
729
743
 
748
762
    headers['X-Auth-Token'] = token
749
763
    conn.request('POST', path, '', headers)
750
764
    resp = conn.getresponse()
751
 
    resp.read()
 
765
    body = resp.read()
752
766
    if resp.status < 200 or resp.status >= 300:
753
767
        raise ClientException('Object POST failed', http_scheme=parsed.scheme,
754
768
                http_host=conn.host, http_port=conn.port, http_path=path,
755
 
                http_status=resp.status, http_reason=resp.reason)
 
769
                http_status=resp.status, http_reason=resp.reason,
 
770
                http_response_content=body)
756
771
 
757
772
 
758
773
def delete_object(url, token=None, container=None, name=None, http_conn=None,
790
805
        headers['X-Auth-Token'] = token
791
806
    conn.request('DELETE', path, '', headers)
792
807
    resp = conn.getresponse()
793
 
    resp.read()
 
808
    body = resp.read()
794
809
    if resp.status < 200 or resp.status >= 300:
795
810
        raise ClientException('Object DELETE failed',
796
811
                http_scheme=parsed.scheme, http_host=conn.host,
797
812
                http_port=conn.port, http_path=path, http_status=resp.status,
798
 
                http_reason=resp.reason)
 
813
                http_reason=resp.reason, http_response_content=body)
799
814
 
800
815
 
801
816
class Connection(object):
803
818
 
804
819
    def __init__(self, authurl, user, key, retries=5, preauthurl=None,
805
820
                 preauthtoken=None, snet=False, starting_backoff=1,
806
 
                 auth_version=1):
 
821
                 auth_version="1"):
807
822
        """
808
823
        :param authurl: authenitcation URL
809
824
        :param user: user name to authenticate as
1791
1806
        conn.put_container(args[0])
1792
1807
        if options.segment_size is not None:
1793
1808
            conn.put_container(args[0] + '_segments')
1794
 
    except Exception:
1795
 
        pass
 
1809
    except ClientException, err:
 
1810
        msg = ' '.join(str(x) for x in (err.http_status, err.http_reason))
 
1811
        if err.http_response_content:
 
1812
            if msg:
 
1813
                msg += ': '
 
1814
            msg += err.http_response_content[:60]
 
1815
        error_queue.put(
 
1816
            'Error trying to create container %r: %s' % (args[0], msg))
 
1817
    except Exception, err:
 
1818
        error_queue.put(
 
1819
            'Error trying to create container %r: %s' % (args[0], err))
1796
1820
    try:
1797
1821
        for arg in args[1:]:
1798
1822
            if isdir(arg):
1846
1870
        options.auth_version = "2.0"
1847
1871
 
1848
1872
    # Use new-style args if old ones not present
1849
 
    if not options.auth and options.auth_url:
1850
 
        options.auth = options.auth_url
1851
 
    if not options.user and options.username:
1852
 
        options.user = options.username
1853
 
    if not options.key and options.password:
1854
 
        options.key = options.password
 
1873
    if not options.auth and options.os_auth_url:
 
1874
        options.auth = options.os_auth_url
 
1875
    if not options.user and options.os_username:
 
1876
        options.user = options.os_username
 
1877
    if not options.key and options.os_password:
 
1878
        options.key = options.os_password
1855
1879
 
1856
1880
    # Handle trailing '/' in URL
1857
1881
    if options.auth and not options.auth.endswith('/'):
1901
1925
    parser.add_option('-K', '--key', dest='key',
1902
1926
                      default=environ.get('ST_KEY'),
1903
1927
                      help='Key for obtaining an auth token')
1904
 
    parser.add_option('--auth_url', dest='auth_url',
 
1928
    parser.add_option('--os_auth_url', dest='os_auth_url',
1905
1929
                      default=environ.get('OS_AUTH_URL'),
1906
1930
                      help=SUPPRESS_HELP)
1907
 
    parser.add_option('--username', dest='username',
 
1931
    parser.add_option('--os_username', dest='os_username',
1908
1932
                      default=environ.get('OS_USERNAME'),
1909
1933
                      help=SUPPRESS_HELP)
1910
 
    parser.add_option('--password', dest='password',
 
1934
    parser.add_option('--os_password', dest='os_password',
1911
1935
                      default=environ.get('OS_PASSWORD'),
1912
1936
                      help=SUPPRESS_HELP)
1913
1937
    parser.disable_interspersed_args()