Merge remote-tracking branch 'upstream/master' into python-registry-v2
This commit is contained in:
commit
26cea9a07c
96 changed files with 2044 additions and 626 deletions
|
@ -2,8 +2,12 @@
|
|||
from swiftclient.client import Connection, ClientException
|
||||
from storage.basestorage import BaseStorage
|
||||
from util.registry.generatorfile import GeneratorFile
|
||||
|
||||
from urlparse import urlparse
|
||||
from random import SystemRandom
|
||||
from hashlib import sha1
|
||||
from time import time
|
||||
|
||||
import hmac
|
||||
import string
|
||||
import logging
|
||||
|
||||
|
@ -12,9 +16,9 @@ logger = logging.getLogger(__name__)
|
|||
|
||||
class SwiftStorage(BaseStorage):
|
||||
def __init__(self, swift_container, storage_path, auth_url, swift_user,
|
||||
swift_password, auth_version=None, os_options=None, ca_cert_path=None):
|
||||
swift_password, auth_version=None, os_options=None, ca_cert_path=None,
|
||||
temp_url_key=None):
|
||||
super(SwiftStorage, self).__init__()
|
||||
|
||||
self._swift_container = swift_container
|
||||
self._storage_path = storage_path
|
||||
|
||||
|
@ -24,6 +28,8 @@ class SwiftStorage(BaseStorage):
|
|||
self._swift_user = swift_user
|
||||
self._swift_password = swift_password
|
||||
|
||||
self._temp_url_key = temp_url_key
|
||||
|
||||
try:
|
||||
self._auth_version = int(auth_version or '2')
|
||||
except ValueError:
|
||||
|
@ -53,8 +59,12 @@ class SwiftStorage(BaseStorage):
|
|||
|
||||
return path
|
||||
|
||||
def _normalize_path(self, path=None):
|
||||
path = self._storage_path + (path or '')
|
||||
def _normalize_path(self, object_path=None):
|
||||
path = self._storage_path
|
||||
if not path.endswith('/'):
|
||||
path = path + '/'
|
||||
|
||||
path = path + (object_path or '')
|
||||
|
||||
# Openstack does not like paths starting with '/' and we always normalize
|
||||
# to remove trailing '/'
|
||||
|
@ -118,15 +128,66 @@ class SwiftStorage(BaseStorage):
|
|||
logger.exception('Could not head object: %s', path)
|
||||
return None
|
||||
|
||||
def get_direct_download_url(self, path, expires_in=60, requires_cors=False):
|
||||
def get_direct_download_url(self, object_path, expires_in=60, requires_cors=False):
|
||||
if requires_cors:
|
||||
return None
|
||||
|
||||
# TODO(jschorr): This method is not strictly necessary but would result in faster operations
|
||||
# when using this storage engine. However, the implementation (as seen in the link below)
|
||||
# is not clean, so we punt on this for now.
|
||||
# http://docs.openstack.org/juno/config-reference/content/object-storage-tempurl.html
|
||||
return None
|
||||
# Reference: http://docs.openstack.org/juno/config-reference/content/object-storage-tempurl.html
|
||||
if not self._temp_url_key:
|
||||
return None
|
||||
|
||||
# Retrieve the auth details for the connection.
|
||||
try:
|
||||
object_url_value, _ = self._get_connection().get_auth()
|
||||
except ClientException:
|
||||
logger.exception('Got client exception when trying to load Swift auth')
|
||||
return None
|
||||
|
||||
object_url = urlparse(object_url_value)
|
||||
scheme = object_url.scheme
|
||||
path = object_url.path
|
||||
hostname = object_url.netloc
|
||||
|
||||
if not path.endswith('/'):
|
||||
path = path + '/'
|
||||
|
||||
object_path = self._normalize_path(object_path)
|
||||
|
||||
# Generate the signed HMAC body.
|
||||
method = 'GET'
|
||||
expires = int(time() + expires_in)
|
||||
full_path = '%s%s/%s' % (path, self._swift_container, object_path)
|
||||
|
||||
hmac_body = '%s\n%s\n%s' % (method, expires, full_path)
|
||||
sig = hmac.new(self._temp_url_key.encode('utf-8'), hmac_body.encode('utf-8'), sha1).hexdigest()
|
||||
|
||||
surl = '{scheme}://{host}{full_path}?temp_url_sig={sig}&temp_url_expires={expires}'
|
||||
return surl.format(scheme=scheme, host=hostname, full_path=full_path, sig=sig, expires=expires)
|
||||
|
||||
def validate(self, client):
|
||||
if self._temp_url_key:
|
||||
# Add a file to test direct download.
|
||||
self.put_content('dd_path', 'testing 3456')
|
||||
|
||||
# Generate a direct download URL.
|
||||
dd_url = self.get_direct_download_url('dd_path')
|
||||
|
||||
if not dd_url:
|
||||
self.remove('dd_path')
|
||||
raise Exception('Could not validate direct download URL; the token may be invalid.')
|
||||
|
||||
# Try to retrieve the direct download URL.
|
||||
response = client.get(dd_url, timeout=2)
|
||||
|
||||
# Remove the test file.
|
||||
self.remove('dd_path')
|
||||
|
||||
if response.status_code != 200:
|
||||
logger.debug('Direct download failure: %s => %s with body %s', dd_url,
|
||||
response.status_code, response.text)
|
||||
|
||||
msg = 'Direct download URL failed with status code %s. Please check your temp-url-key.'
|
||||
raise Exception(msg % response.status_code)
|
||||
|
||||
def get_content(self, path):
|
||||
return self._get_object(path)
|
||||
|
|
Reference in a new issue