mirror of
https://github.com/ansible/awx.git
synced 2026-01-17 20:51:21 -03:30
Upgrade swifclient to 2.2.0
This commit is contained in:
parent
07bfe7c275
commit
15c2627968
@ -46,7 +46,7 @@ prettytable==0.7.2 (prettytable.py)
|
||||
pyrax==1.9.0 (pyrax/*)
|
||||
python-dateutil==2.2 (dateutil/*)
|
||||
python-novaclient==2.18.1 (novaclient/*, excluded bin/nova)
|
||||
python-swiftclient==2.0.3 (swiftclient/*, excluded bin/swift)
|
||||
python-swiftclient==2.2.0 (swiftclient/*, excluded bin/swift)
|
||||
pytz==2014.4 (pytz/*)
|
||||
rackspace-auth-openstack==1.3 (rackspace_auth_openstack/*)
|
||||
rackspace-novaclient==1.4 (no files)
|
||||
|
||||
@ -1,4 +1,4 @@
|
||||
# -*- encoding: utf-8 -*-
|
||||
# -*- coding: utf-8 -*-
|
||||
# Copyright (c) 2012 Rackspace
|
||||
# flake8: noqa
|
||||
# Licensed under the Apache License, Version 2.0 (the "License");
|
||||
@ -14,7 +14,7 @@
|
||||
# See the License for the specific language governing permissions and
|
||||
# limitations under the License.
|
||||
|
||||
""""
|
||||
"""
|
||||
OpenStack Swift Python client binding.
|
||||
"""
|
||||
from .client import *
|
||||
|
||||
@ -22,14 +22,17 @@ import requests
|
||||
import sys
|
||||
import logging
|
||||
import warnings
|
||||
import functools
|
||||
|
||||
from distutils.version import StrictVersion
|
||||
from requests.exceptions import RequestException, SSLError
|
||||
from urllib import quote as _quote
|
||||
from urlparse import urlparse, urlunparse
|
||||
from six.moves.urllib.parse import quote as _quote
|
||||
from six.moves.urllib.parse import urlparse, urlunparse
|
||||
from time import sleep, time
|
||||
import six
|
||||
|
||||
from swiftclient.exceptions import ClientException, InvalidHeadersException
|
||||
from swiftclient import version as swiftclient_version
|
||||
from swiftclient.exceptions import ClientException
|
||||
from swiftclient.utils import LengthWrapper
|
||||
|
||||
try:
|
||||
@ -85,8 +88,8 @@ def http_log(args, kwargs, resp, body):
|
||||
else:
|
||||
log_method = logger.info
|
||||
|
||||
log_method("REQ: %s" % "".join(string_parts))
|
||||
log_method("RESP STATUS: %s %s" % (resp.status, resp.reason))
|
||||
log_method("REQ: %s", "".join(string_parts))
|
||||
log_method("RESP STATUS: %s %s", resp.status, resp.reason)
|
||||
log_method("RESP HEADERS: %s", resp.getheaders())
|
||||
if body:
|
||||
log_method("RESP BODY: %s", body)
|
||||
@ -94,30 +97,20 @@ def http_log(args, kwargs, resp, body):
|
||||
|
||||
def quote(value, safe='/'):
|
||||
"""
|
||||
Patched version of urllib.quote that encodes utf8 strings before quoting
|
||||
Patched version of urllib.quote that encodes utf8 strings before quoting.
|
||||
On Python 3, call directly urllib.parse.quote().
|
||||
"""
|
||||
if six.PY3:
|
||||
return _quote(value, safe=safe)
|
||||
value = encode_utf8(value)
|
||||
if isinstance(value, str):
|
||||
if isinstance(value, bytes):
|
||||
return _quote(value, safe)
|
||||
else:
|
||||
return value
|
||||
|
||||
|
||||
def validate_headers(headers):
|
||||
if headers:
|
||||
for key, raw_value in headers.iteritems():
|
||||
value = str(encode_utf8(raw_value))
|
||||
|
||||
if '\n' in value:
|
||||
raise InvalidHeadersException("%r header contained a "
|
||||
"newline" % key)
|
||||
if '\r' in value:
|
||||
raise InvalidHeadersException("%r header contained a "
|
||||
"carriage return" % key)
|
||||
|
||||
|
||||
def encode_utf8(value):
|
||||
if isinstance(value, unicode):
|
||||
if isinstance(value, six.text_type):
|
||||
value = value.encode('utf8')
|
||||
return value
|
||||
|
||||
@ -133,7 +126,7 @@ except ImportError:
|
||||
|
||||
class HTTPConnection:
|
||||
def __init__(self, url, proxy=None, cacert=None, insecure=False,
|
||||
ssl_compression=False):
|
||||
ssl_compression=False, default_user_agent=None):
|
||||
"""
|
||||
Make an HTTPConnection or HTTPSConnection
|
||||
|
||||
@ -147,6 +140,12 @@ class HTTPConnection:
|
||||
:param ssl_compression: SSL compression should be disabled by default
|
||||
and this setting is not usable as of now. The
|
||||
parameter is kept for backward compatibility.
|
||||
:param default_user_agent: Set the User-Agent header on every request.
|
||||
If set to None (default), the user agent
|
||||
will be "python-swiftclient-<version>". This
|
||||
may be overridden on a per-request basis by
|
||||
explicitly setting the user-agent header on
|
||||
a call to request().
|
||||
:raises ClientException: Unable to handle protocol scheme
|
||||
"""
|
||||
self.url = url
|
||||
@ -154,6 +153,7 @@ class HTTPConnection:
|
||||
self.host = self.parsed_url.netloc
|
||||
self.port = self.parsed_url.port
|
||||
self.requests_args = {}
|
||||
self.request_session = requests.Session()
|
||||
if self.parsed_url.scheme not in ('http', 'https'):
|
||||
raise ClientException("Unsupported scheme")
|
||||
self.requests_args['verify'] = not insecure
|
||||
@ -171,24 +171,49 @@ class HTTPConnection:
|
||||
)
|
||||
}
|
||||
self.requests_args['stream'] = True
|
||||
if default_user_agent is None:
|
||||
default_user_agent = \
|
||||
'python-swiftclient-%s' % swiftclient_version.version_string
|
||||
self.default_user_agent = default_user_agent
|
||||
|
||||
def _request(self, *arg, **kwarg):
|
||||
""" Final wrapper before requests call, to be patched in tests """
|
||||
return requests.request(*arg, **kwarg)
|
||||
return self.request_session.request(*arg, **kwarg)
|
||||
|
||||
def request(self, method, full_path, data=None, headers={}, files=None):
|
||||
def _encode_meta_headers(self, items):
|
||||
"""Only encode metadata headers keys"""
|
||||
ret = {}
|
||||
for header, value in items:
|
||||
value = encode_utf8(value)
|
||||
header = header.lower()
|
||||
if isinstance(header, six.string_types):
|
||||
for target_type in 'container', 'account', 'object':
|
||||
prefix = 'x-%s-meta-' % target_type
|
||||
if header.startswith(prefix):
|
||||
header = encode_utf8(header)
|
||||
break
|
||||
ret[header] = value
|
||||
return ret
|
||||
|
||||
def request(self, method, full_path, data=None, headers=None, files=None):
|
||||
""" Encode url and header, then call requests.request """
|
||||
headers = dict((encode_utf8(x), encode_utf8(y)) for x, y in
|
||||
headers.iteritems())
|
||||
url = encode_utf8("%s://%s%s" % (
|
||||
if headers is None:
|
||||
headers = {}
|
||||
else:
|
||||
headers = self._encode_meta_headers(headers.items())
|
||||
|
||||
# set a default User-Agent header if it wasn't passed in
|
||||
if 'user-agent' not in headers:
|
||||
headers['user-agent'] = self.default_user_agent
|
||||
url = "%s://%s%s" % (
|
||||
self.parsed_url.scheme,
|
||||
self.parsed_url.netloc,
|
||||
full_path))
|
||||
full_path)
|
||||
self.resp = self._request(method, url, headers=headers, data=data,
|
||||
files=files, **self.requests_args)
|
||||
return self.resp
|
||||
|
||||
def putrequest(self, full_path, data=None, headers={}, files=None):
|
||||
def putrequest(self, full_path, data=None, headers=None, files=None):
|
||||
"""
|
||||
Use python-requests files upload
|
||||
|
||||
@ -210,7 +235,8 @@ class HTTPConnection:
|
||||
|
||||
self.resp.getheaders = getheaders
|
||||
self.resp.getheader = getheader
|
||||
self.resp.read = self.resp.raw.read
|
||||
self.resp.read = functools.partial(self.resp.raw.read,
|
||||
decode_content=True)
|
||||
return self.resp
|
||||
|
||||
|
||||
@ -236,9 +262,8 @@ def get_auth_1_0(url, user, key, snet, **kwargs):
|
||||
# if we don't have a x-storage-url header and if we get a body.
|
||||
if resp.status < 200 or resp.status >= 300 or (body and not url):
|
||||
raise ClientException('Auth GET failed', http_scheme=parsed.scheme,
|
||||
http_host=conn.host, http_port=conn.port,
|
||||
http_path=parsed.path, http_status=resp.status,
|
||||
http_reason=resp.reason)
|
||||
http_host=conn.host, http_path=parsed.path,
|
||||
http_status=resp.status, http_reason=resp.reason)
|
||||
if snet:
|
||||
parsed = list(urlparse(url))
|
||||
# Second item in the list is the netloc
|
||||
@ -251,7 +276,7 @@ def get_auth_1_0(url, user, key, snet, **kwargs):
|
||||
|
||||
def get_keystoneclient_2_0(auth_url, user, key, os_options, **kwargs):
|
||||
"""
|
||||
Authenticate against a auth 2.0 server.
|
||||
Authenticate against an auth 2.0 server.
|
||||
|
||||
We are using the keystoneclient library for our 2.0 authentication.
|
||||
"""
|
||||
@ -336,7 +361,7 @@ def get_auth(auth_url, user, key, **kwargs):
|
||||
if kwargs.get('tenant_name'):
|
||||
os_options['tenant_name'] = kwargs['tenant_name']
|
||||
|
||||
if (not 'tenant_name' in os_options):
|
||||
if not (os_options.get('tenant_name') or os_options.get('tenant_id')):
|
||||
raise ClientException('No tenant specified')
|
||||
|
||||
cacert = kwargs.get('cacert', None)
|
||||
@ -430,9 +455,9 @@ def get_account(url, token, marker=None, limit=None, prefix=None,
|
||||
resp_headers[header.lower()] = value
|
||||
if resp.status < 200 or resp.status >= 300:
|
||||
raise ClientException('Account GET failed', http_scheme=parsed.scheme,
|
||||
http_host=conn.host, http_port=conn.port,
|
||||
http_path=parsed.path, http_query=qs,
|
||||
http_status=resp.status, http_reason=resp.reason,
|
||||
http_host=conn.host, http_path=parsed.path,
|
||||
http_query=qs, http_status=resp.status,
|
||||
http_reason=resp.reason,
|
||||
http_response_content=body)
|
||||
if resp.status == 204:
|
||||
return resp_headers, []
|
||||
@ -463,9 +488,8 @@ def head_account(url, token, http_conn=None):
|
||||
http_log((url, method,), {'headers': headers}, resp, body)
|
||||
if resp.status < 200 or resp.status >= 300:
|
||||
raise ClientException('Account HEAD failed', http_scheme=parsed.scheme,
|
||||
http_host=conn.host, http_port=conn.port,
|
||||
http_path=parsed.path, http_status=resp.status,
|
||||
http_reason=resp.reason,
|
||||
http_host=conn.host, http_path=parsed.path,
|
||||
http_status=resp.status, http_reason=resp.reason,
|
||||
http_response_content=body)
|
||||
resp_headers = {}
|
||||
for header, value in resp.getheaders():
|
||||
@ -503,7 +527,6 @@ def post_account(url, token, headers, http_conn=None, response_dict=None):
|
||||
raise ClientException('Account POST failed',
|
||||
http_scheme=parsed.scheme,
|
||||
http_host=conn.host,
|
||||
http_port=conn.port,
|
||||
http_path=parsed.path,
|
||||
http_status=resp.status,
|
||||
http_reason=resp.reason,
|
||||
@ -580,9 +603,8 @@ def get_container(url, token, container, marker=None, limit=None,
|
||||
if resp.status < 200 or resp.status >= 300:
|
||||
raise ClientException('Container GET failed',
|
||||
http_scheme=parsed.scheme, http_host=conn.host,
|
||||
http_port=conn.port, http_path=cont_path,
|
||||
http_query=qs, http_status=resp.status,
|
||||
http_reason=resp.reason,
|
||||
http_path=cont_path, http_query=qs,
|
||||
http_status=resp.status, http_reason=resp.reason,
|
||||
http_response_content=body)
|
||||
resp_headers = {}
|
||||
for header, value in resp.getheaders():
|
||||
@ -623,8 +645,8 @@ def head_container(url, token, container, http_conn=None, headers=None):
|
||||
if resp.status < 200 or resp.status >= 300:
|
||||
raise ClientException('Container HEAD failed',
|
||||
http_scheme=parsed.scheme, http_host=conn.host,
|
||||
http_port=conn.port, http_path=path,
|
||||
http_status=resp.status, http_reason=resp.reason,
|
||||
http_path=path, http_status=resp.status,
|
||||
http_reason=resp.reason,
|
||||
http_response_content=body)
|
||||
resp_headers = {}
|
||||
for header, value in resp.getheaders():
|
||||
@ -656,7 +678,7 @@ def put_container(url, token, container, headers=None, http_conn=None,
|
||||
if not headers:
|
||||
headers = {}
|
||||
headers['X-Auth-Token'] = token
|
||||
if not 'content-length' in (k.lower() for k in headers):
|
||||
if 'content-length' not in (k.lower() for k in headers):
|
||||
headers['Content-Length'] = '0'
|
||||
conn.request(method, path, '', headers)
|
||||
resp = conn.getresponse()
|
||||
@ -669,8 +691,8 @@ def put_container(url, token, container, headers=None, http_conn=None,
|
||||
if resp.status < 200 or resp.status >= 300:
|
||||
raise ClientException('Container PUT failed',
|
||||
http_scheme=parsed.scheme, http_host=conn.host,
|
||||
http_port=conn.port, http_path=path,
|
||||
http_status=resp.status, http_reason=resp.reason,
|
||||
http_path=path, http_status=resp.status,
|
||||
http_reason=resp.reason,
|
||||
http_response_content=body)
|
||||
|
||||
|
||||
@ -696,7 +718,7 @@ def post_container(url, token, container, headers, http_conn=None,
|
||||
path = '%s/%s' % (parsed.path, quote(container))
|
||||
method = 'POST'
|
||||
headers['X-Auth-Token'] = token
|
||||
if not 'content-length' in (k.lower() for k in headers):
|
||||
if 'content-length' not in (k.lower() for k in headers):
|
||||
headers['Content-Length'] = '0'
|
||||
conn.request(method, path, '', headers)
|
||||
resp = conn.getresponse()
|
||||
@ -709,8 +731,8 @@ def post_container(url, token, container, headers, http_conn=None,
|
||||
if resp.status < 200 or resp.status >= 300:
|
||||
raise ClientException('Container POST failed',
|
||||
http_scheme=parsed.scheme, http_host=conn.host,
|
||||
http_port=conn.port, http_path=path,
|
||||
http_status=resp.status, http_reason=resp.reason,
|
||||
http_path=path, http_status=resp.status,
|
||||
http_reason=resp.reason,
|
||||
http_response_content=body)
|
||||
|
||||
|
||||
@ -746,8 +768,8 @@ def delete_container(url, token, container, http_conn=None,
|
||||
if resp.status < 200 or resp.status >= 300:
|
||||
raise ClientException('Container DELETE failed',
|
||||
http_scheme=parsed.scheme, http_host=conn.host,
|
||||
http_port=conn.port, http_path=path,
|
||||
http_status=resp.status, http_reason=resp.reason,
|
||||
http_path=path, http_status=resp.status,
|
||||
http_reason=resp.reason,
|
||||
http_response_content=body)
|
||||
|
||||
|
||||
@ -799,8 +821,8 @@ def get_object(url, token, container, name, http_conn=None,
|
||||
http_log(('%s%s' % (url.replace(parsed.path, ''), path), method,),
|
||||
{'headers': headers}, resp, body)
|
||||
raise ClientException('Object GET failed', http_scheme=parsed.scheme,
|
||||
http_host=conn.host, http_port=conn.port,
|
||||
http_path=path, http_status=resp.status,
|
||||
http_host=conn.host, http_path=path,
|
||||
http_status=resp.status,
|
||||
http_reason=resp.reason,
|
||||
http_response_content=body)
|
||||
if resp_chunk_size:
|
||||
@ -847,9 +869,8 @@ def head_object(url, token, container, name, http_conn=None):
|
||||
{'headers': headers}, resp, body)
|
||||
if resp.status < 200 or resp.status >= 300:
|
||||
raise ClientException('Object HEAD failed', http_scheme=parsed.scheme,
|
||||
http_host=conn.host, http_port=conn.port,
|
||||
http_path=path, http_status=resp.status,
|
||||
http_reason=resp.reason,
|
||||
http_host=conn.host, http_path=path,
|
||||
http_status=resp.status, http_reason=resp.reason,
|
||||
http_response_content=body)
|
||||
resp_headers = {}
|
||||
for header, value in resp.getheaders():
|
||||
@ -878,11 +899,10 @@ def put_object(url, token=None, container=None, name=None, contents=None,
|
||||
encoding will be used
|
||||
:param etag: etag of contents; if None, no etag will be sent
|
||||
:param chunk_size: chunk size of data to write; it defaults to 65536;
|
||||
used only if the the contents object has a 'read'
|
||||
method, eg. file-like objects, ignored otherwise
|
||||
:param content_type: value to send as content-type header; if None, no
|
||||
content-type will be set (remote end will likely try
|
||||
to auto-detect it)
|
||||
used only if the contents object has a 'read'
|
||||
method, e.g. file-like objects, ignored otherwise
|
||||
:param content_type: value to send as content-type header; if None, an
|
||||
empty string value will be sent
|
||||
:param headers: additional headers to include in the request, if any
|
||||
:param http_conn: HTTP connection object (If None, it will create the
|
||||
conn object)
|
||||
@ -916,11 +936,13 @@ def put_object(url, token=None, container=None, name=None, contents=None,
|
||||
if content_length is not None:
|
||||
headers['Content-Length'] = str(content_length)
|
||||
else:
|
||||
for n, v in headers.iteritems():
|
||||
for n, v in headers.items():
|
||||
if n.lower() == 'content-length':
|
||||
content_length = int(v)
|
||||
if content_type is not None:
|
||||
headers['Content-Type'] = content_type
|
||||
else: # python-requests sets application/x-www-form-urlencoded otherwise
|
||||
headers['Content-Type'] = ''
|
||||
if not contents:
|
||||
headers['Content-Length'] = '0'
|
||||
if hasattr(contents, 'read'):
|
||||
@ -954,9 +976,8 @@ def put_object(url, token=None, container=None, name=None, contents=None,
|
||||
|
||||
if resp.status < 200 or resp.status >= 300:
|
||||
raise ClientException('Object PUT failed', http_scheme=parsed.scheme,
|
||||
http_host=conn.host, http_port=conn.port,
|
||||
http_path=path, http_status=resp.status,
|
||||
http_reason=resp.reason,
|
||||
http_host=conn.host, http_path=path,
|
||||
http_status=resp.status, http_reason=resp.reason,
|
||||
http_response_content=body)
|
||||
|
||||
return resp.getheader('etag', '').strip('"')
|
||||
@ -994,9 +1015,8 @@ def post_object(url, token, container, name, headers, http_conn=None,
|
||||
|
||||
if resp.status < 200 or resp.status >= 300:
|
||||
raise ClientException('Object POST failed', http_scheme=parsed.scheme,
|
||||
http_host=conn.host, http_port=conn.port,
|
||||
http_path=path, http_status=resp.status,
|
||||
http_reason=resp.reason,
|
||||
http_host=conn.host, http_path=path,
|
||||
http_status=resp.status, http_reason=resp.reason,
|
||||
http_response_content=body)
|
||||
|
||||
|
||||
@ -1050,8 +1070,8 @@ def delete_object(url, token=None, container=None, name=None, http_conn=None,
|
||||
if resp.status < 200 or resp.status >= 300:
|
||||
raise ClientException('Object DELETE failed',
|
||||
http_scheme=parsed.scheme, http_host=conn.host,
|
||||
http_port=conn.port, http_path=path,
|
||||
http_status=resp.status, http_reason=resp.reason,
|
||||
http_path=path, http_status=resp.status,
|
||||
http_reason=resp.reason,
|
||||
http_response_content=body)
|
||||
|
||||
|
||||
@ -1071,9 +1091,8 @@ def get_capabilities(http_conn):
|
||||
if resp.status < 200 or resp.status >= 300:
|
||||
raise ClientException('Capabilities GET failed',
|
||||
http_scheme=parsed.scheme,
|
||||
http_host=conn.host, http_port=conn.port,
|
||||
http_path=parsed.path, http_status=resp.status,
|
||||
http_reason=resp.reason,
|
||||
http_host=conn.host, http_path=parsed.path,
|
||||
http_status=resp.status, http_reason=resp.reason,
|
||||
http_response_content=body)
|
||||
return json_loads(body)
|
||||
|
||||
@ -1101,7 +1120,7 @@ class Connection(object):
|
||||
:param max_backoff: maximum delay between retries (seconds)
|
||||
:param auth_version: OpenStack auth version, default is 1.0
|
||||
:param tenant_name: The tenant/account name, required when connecting
|
||||
to a auth 2.0 system.
|
||||
to an auth 2.0 system.
|
||||
:param os_options: The OpenStack options which can have tenant_id,
|
||||
auth_token, service_type, endpoint_type,
|
||||
tenant_name, object_storage_url, region_name
|
||||
|
||||
@ -68,5 +68,5 @@ class ClientException(Exception):
|
||||
return b and '%s: %s' % (a, b) or a
|
||||
|
||||
|
||||
class InvalidHeadersException(Exception):
|
||||
class SkipTest(Exception):
|
||||
pass
|
||||
|
||||
@ -12,10 +12,14 @@
|
||||
# implied.
|
||||
# See the License for the specific language governing permissions and
|
||||
# limitations under the License.
|
||||
|
||||
from __future__ import print_function
|
||||
|
||||
from itertools import chain
|
||||
import six
|
||||
import sys
|
||||
from time import sleep
|
||||
from Queue import Queue
|
||||
from six.moves.queue import Queue
|
||||
from threading import Thread
|
||||
from traceback import format_exception
|
||||
|
||||
@ -181,7 +185,7 @@ class MultiThreadingManager(object):
|
||||
(defaults to ``sys.stdout``) and the :meth:`error` method will print to the
|
||||
supplied ``error_stream`` (defaults to ``sys.stderr``). Both of these
|
||||
printing methods will format the given string with any supplied ``*args``
|
||||
(a la printf) and encode the result to utf8 if necessary.
|
||||
(a la printf). On Python 2, Unicode messages are encoded to utf8.
|
||||
|
||||
The attribute :attr:`self.error_count` is incremented once per error
|
||||
message printed, so an application can tell if any worker threads
|
||||
@ -193,9 +197,11 @@ class MultiThreadingManager(object):
|
||||
def __init__(self, print_stream=sys.stdout, error_stream=sys.stderr):
|
||||
"""
|
||||
:param print_stream: The stream to which :meth:`print_msg` sends
|
||||
formatted messages, encoded to utf8 if necessary.
|
||||
formatted messages
|
||||
:param error_stream: The stream to which :meth:`error` sends formatted
|
||||
messages, encoded to utf8 if necessary.
|
||||
messages
|
||||
|
||||
On Python 2, Unicode messages are encoded to utf8.
|
||||
"""
|
||||
self.print_stream = print_stream
|
||||
self.printer = QueueFunctionManager(self._print, 1, self)
|
||||
@ -256,9 +262,9 @@ class MultiThreadingManager(object):
|
||||
def _print(self, item, stream=None):
|
||||
if stream is None:
|
||||
stream = self.print_stream
|
||||
if isinstance(item, unicode):
|
||||
if six.PY2 and isinstance(item, unicode):
|
||||
item = item.encode('utf8')
|
||||
print >>stream, item
|
||||
print(item, file=stream)
|
||||
|
||||
def _print_error(self, item):
|
||||
self.error_count += 1
|
||||
|
||||
1611
awx/lib/site-packages/swiftclient/shell.py
Normal file
1611
awx/lib/site-packages/swiftclient/shell.py
Normal file
File diff suppressed because it is too large
Load Diff
@ -13,6 +13,12 @@
|
||||
# See the License for the specific language governing permissions and
|
||||
# limitations under the License.
|
||||
"""Miscellaneous utility functions for use with Swift."""
|
||||
import hashlib
|
||||
import hmac
|
||||
import logging
|
||||
import time
|
||||
|
||||
import six
|
||||
|
||||
TRUE_VALUES = set(('true', '1', 'yes', 'on', 't', 'y'))
|
||||
|
||||
@ -24,7 +30,7 @@ def config_true_value(value):
|
||||
This function come from swift.common.utils.config_true_value()
|
||||
"""
|
||||
return value is True or \
|
||||
(isinstance(value, basestring) and value.lower() in TRUE_VALUES)
|
||||
(isinstance(value, six.string_types) and value.lower() in TRUE_VALUES)
|
||||
|
||||
|
||||
def prt_bytes(bytes, human_flag):
|
||||
@ -57,6 +63,51 @@ def prt_bytes(bytes, human_flag):
|
||||
return(bytes)
|
||||
|
||||
|
||||
def generate_temp_url(path, seconds, key, method):
|
||||
""" Generates a temporary URL that gives unauthenticated access to the
|
||||
Swift object.
|
||||
|
||||
:param path: The full path to the Swift object. Example:
|
||||
/v1/AUTH_account/c/o.
|
||||
:param seconds: The amount of time in seconds the temporary URL will
|
||||
be valid for.
|
||||
:param key: The secret temporary URL key set on the Swift cluster.
|
||||
To set a key, run 'swift post -m
|
||||
"Temp-URL-Key:b3968d0207b54ece87cccc06515a89d4"'
|
||||
:param method: A HTTP method, typically either GET or PUT, to allow for
|
||||
this temporary URL.
|
||||
:raises: ValueError if seconds is not a positive integer
|
||||
:raises: TypeError if seconds is not an integer
|
||||
:return: the path portion of a temporary URL
|
||||
"""
|
||||
if seconds < 0:
|
||||
raise ValueError('seconds must be a positive integer')
|
||||
try:
|
||||
expiration = int(time.time() + seconds)
|
||||
except TypeError:
|
||||
raise TypeError('seconds must be an integer')
|
||||
|
||||
standard_methods = ['GET', 'PUT', 'HEAD', 'POST', 'DELETE']
|
||||
if method.upper() not in standard_methods:
|
||||
logger = logging.getLogger("swiftclient")
|
||||
logger.warning('Non default HTTP method %s for tempurl specified, '
|
||||
'possibly an error', method.upper())
|
||||
|
||||
hmac_body = '\n'.join([method.upper(), str(expiration), path])
|
||||
|
||||
# Encode to UTF-8 for py3 compatibility
|
||||
sig = hmac.new(key.encode(),
|
||||
hmac_body.encode(),
|
||||
hashlib.sha1).hexdigest()
|
||||
|
||||
return ('{path}?temp_url_sig='
|
||||
'{sig}&temp_url_expires={exp}'.format(
|
||||
path=path,
|
||||
sig=sig,
|
||||
exp=expiration)
|
||||
)
|
||||
|
||||
|
||||
class LengthWrapper(object):
|
||||
|
||||
def __init__(self, readable, length):
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user