# Copyright 2014 Rackspace Australia # # Licensed under the Apache License, Version 2.0 (the "License"); you may # not use this file except in compliance with the License. You may obtain # a copy of the License at # # http://www.apache.org/licenses/LICENSE-2.0 # # Unless required by applicable law or agreed to in writing, software # distributed under the License is distributed on an "AS IS" BASIS, WITHOUT # WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the # License for the specific language governing permissions and limitations # under the License. import hmac from hashlib import sha1 import logging from time import time import os import random import six from six.moves import urllib import string class Swift(object): log = logging.getLogger("zuul.Swift") def __init__(self, config): self.config = config self.connection = False if self.config.has_option('swift', 'X-Account-Meta-Temp-Url-Key'): self.secure_key = self.config.get('swift', 'X-Account-Meta-Temp-Url-Key') else: self.secure_key = ''.join( random.choice(string.ascii_uppercase + string.digits) for x in range(20) ) self.storage_url = '' if self.config.has_option('swift', 'X-Storage-Url'): self.storage_url = self.config.get('swift', 'X-Storage-Url') try: if self.config.has_section('swift'): if (not self.config.has_option('swift', 'Send-Temp-Url-Key') or self.config.getboolean('swift', 'Send-Temp-Url-Key')): self.connect() # Tell swift of our key headers = {} headers['X-Account-Meta-Temp-Url-Key'] = self.secure_key self.connection.post_account(headers) if not self.config.has_option('swift', 'X-Storage-Url'): self.connect() self.storage_url = self.connection.get_auth()[0] except Exception as e: self.log.warning("Unable to set up swift. Signed storage URL is " "likely to be wrong. %s" % e) def connect(self): if not self.connection: authurl = self.config.get('swift', 'authurl') user = (self.config.get('swift', 'user') if self.config.has_option('swift', 'user') else None) key = (self.config.get('swift', 'key') if self.config.has_option('swift', 'key') else None) retries = (self.config.get('swift', 'retries') if self.config.has_option('swift', 'retries') else 5) preauthurl = (self.config.get('swift', 'preauthurl') if self.config.has_option('swift', 'preauthurl') else None) preauthtoken = (self.config.get('swift', 'preauthtoken') if self.config.has_option('swift', 'preauthtoken') else None) snet = (self.config.get('swift', 'snet') if self.config.has_option('swift', 'snet') else False) starting_backoff = (self.config.get('swift', 'starting_backoff') if self.config.has_option('swift', 'starting_backoff') else 1) max_backoff = (self.config.get('swift', 'max_backoff') if self.config.has_option('swift', 'max_backoff') else 64) tenant_name = (self.config.get('swift', 'tenant_name') if self.config.has_option('swift', 'tenant_name') else None) auth_version = (self.config.get('swift', 'auth_version') if self.config.has_option('swift', 'auth_version') else 2.0) cacert = (self.config.get('swift', 'cacert') if self.config.has_option('swift', 'cacert') else None) insecure = (self.config.get('swift', 'insecure') if self.config.has_option('swift', 'insecure') else False) ssl_compression = (self.config.get('swift', 'ssl_compression') if self.config.has_option('swift', 'ssl_compression') else True) available_os_options = ['tenant_id', 'auth_token', 'service_type', 'endpoint_type', 'tenant_name', 'object_storage_url', 'region_name'] os_options = {} for os_option in available_os_options: if self.config.has_option('swift', os_option): os_options[os_option] = self.config.get('swift', os_option) import swiftclient self.connection = swiftclient.client.Connection( authurl=authurl, user=user, key=key, retries=retries, preauthurl=preauthurl, preauthtoken=preauthtoken, snet=snet, starting_backoff=starting_backoff, max_backoff=max_backoff, tenant_name=tenant_name, os_options=os_options, auth_version=auth_version, cacert=cacert, insecure=insecure, ssl_compression=ssl_compression) def generate_form_post_middleware_params(self, destination_prefix='', **kwargs): """Generate the FormPost middleware params for the given settings""" # Define the available settings and their defaults settings = { 'container': '', 'expiry': 7200, 'max_file_size': 104857600, 'max_file_count': 10, 'file_path_prefix': '' } for key, default in six.iteritems(settings): # TODO(jeblair): Remove the following two lines after a # deprecation period for the underscore variants of the # settings in YAML. if key in kwargs: settings[key] = kwargs[key] # Since we prefer '-' rather than '_' in YAML, look up # keys there using hyphens. Continue to use underscores # everywhere else. altkey = key.replace('_', '-') if altkey in kwargs: settings[key] = kwargs[altkey] elif self.config.has_option('swift', 'default_' + key): settings[key] = self.config.get('swift', 'default_' + key) # TODO: these are always strings; some should be converted # to ints. expires = int(time() + int(settings['expiry'])) redirect = '' url = os.path.join(self.storage_url, settings['container'], settings['file_path_prefix'], destination_prefix) u = urllib.parse.urlparse(url) hmac_body = '%s\n%s\n%s\n%s\n%s' % (u.path, redirect, settings['max_file_size'], settings['max_file_count'], expires) signature = hmac.new(self.secure_key, hmac_body, sha1).hexdigest() return url, hmac_body, signature