Joshua Hesketh | 36c3fa5 | 2014-01-22 11:40:52 +1100 | [diff] [blame] | 1 | # Copyright 2014 Rackspace Australia |
| 2 | # |
| 3 | # Licensed under the Apache License, Version 2.0 (the "License"); you may |
| 4 | # not use this file except in compliance with the License. You may obtain |
| 5 | # a copy of the License at |
| 6 | # |
| 7 | # http://www.apache.org/licenses/LICENSE-2.0 |
| 8 | # |
| 9 | # Unless required by applicable law or agreed to in writing, software |
| 10 | # distributed under the License is distributed on an "AS IS" BASIS, WITHOUT |
| 11 | # WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the |
| 12 | # License for the specific language governing permissions and limitations |
| 13 | # under the License. |
| 14 | |
| 15 | import hmac |
| 16 | from hashlib import sha1 |
Joshua Hesketh | b95d38b | 2014-05-14 14:58:33 -0700 | [diff] [blame] | 17 | import logging |
Joshua Hesketh | 36c3fa5 | 2014-01-22 11:40:52 +1100 | [diff] [blame] | 18 | from time import time |
| 19 | import os |
| 20 | import random |
Christian Berendt | e35b99c | 2014-06-06 16:57:47 +0200 | [diff] [blame] | 21 | import six |
Joshua Hesketh | 36c3fa5 | 2014-01-22 11:40:52 +1100 | [diff] [blame] | 22 | import string |
Joshua Hesketh | 36c3fa5 | 2014-01-22 11:40:52 +1100 | [diff] [blame] | 23 | import urlparse |
| 24 | |
| 25 | |
| 26 | class Swift(object): |
Joshua Hesketh | b95d38b | 2014-05-14 14:58:33 -0700 | [diff] [blame] | 27 | log = logging.getLogger("zuul.lib.swift") |
| 28 | |
Joshua Hesketh | 36c3fa5 | 2014-01-22 11:40:52 +1100 | [diff] [blame] | 29 | def __init__(self, config): |
| 30 | self.config = config |
| 31 | self.connection = False |
| 32 | if self.config.has_option('swift', 'X-Account-Meta-Temp-Url-Key'): |
| 33 | self.secure_key = self.config.get('swift', |
| 34 | 'X-Account-Meta-Temp-Url-Key') |
| 35 | else: |
| 36 | self.secure_key = ''.join( |
| 37 | random.choice(string.ascii_uppercase + string.digits) |
| 38 | for x in range(20) |
| 39 | ) |
| 40 | |
Joshua Hesketh | b95d38b | 2014-05-14 14:58:33 -0700 | [diff] [blame] | 41 | self.storage_url = '' |
Joshua Hesketh | c496750 | 2014-05-15 06:39:14 -0700 | [diff] [blame] | 42 | if self.config.has_option('swift', 'X-Storage-Url'): |
| 43 | self.storage_url = self.config.get('swift', 'X-Storage-Url') |
Joshua Hesketh | b95d38b | 2014-05-14 14:58:33 -0700 | [diff] [blame] | 44 | |
| 45 | try: |
Joshua Hesketh | c496750 | 2014-05-15 06:39:14 -0700 | [diff] [blame] | 46 | if self.config.has_section('swift'): |
| 47 | if (not self.config.has_option('swift', 'Send-Temp-Url-Key') |
Joshua Hesketh | 29d99b7 | 2014-08-19 16:27:42 +1000 | [diff] [blame] | 48 | or self.config.getboolean('swift', |
| 49 | 'Send-Temp-Url-Key')): |
Joshua Hesketh | c496750 | 2014-05-15 06:39:14 -0700 | [diff] [blame] | 50 | self.connect() |
| 51 | |
| 52 | # Tell swift of our key |
| 53 | headers = {} |
| 54 | headers['X-Account-Meta-Temp-Url-Key'] = self.secure_key |
| 55 | self.connection.post_account(headers) |
| 56 | |
| 57 | if not self.config.has_option('swift', 'X-Storage-Url'): |
| 58 | self.connect() |
| 59 | self.storage_url = self.connection.get_auth()[0] |
Joshua Hesketh | b95d38b | 2014-05-14 14:58:33 -0700 | [diff] [blame] | 60 | except Exception as e: |
| 61 | self.log.warning("Unable to set up swift. Signed storage URL is " |
| 62 | "likely to be wrong. %s" % e) |
Joshua Hesketh | 36c3fa5 | 2014-01-22 11:40:52 +1100 | [diff] [blame] | 63 | |
| 64 | def connect(self): |
Joshua Hesketh | c496750 | 2014-05-15 06:39:14 -0700 | [diff] [blame] | 65 | if not self.connection: |
Joshua Hesketh | 36c3fa5 | 2014-01-22 11:40:52 +1100 | [diff] [blame] | 66 | authurl = self.config.get('swift', 'authurl') |
| 67 | |
| 68 | user = (self.config.get('swift', 'user') |
| 69 | if self.config.has_option('swift', 'user') else None) |
| 70 | key = (self.config.get('swift', 'key') |
| 71 | if self.config.has_option('swift', 'key') else None) |
| 72 | retries = (self.config.get('swift', 'retries') |
| 73 | if self.config.has_option('swift', 'retries') else 5) |
| 74 | preauthurl = (self.config.get('swift', 'preauthurl') |
| 75 | if self.config.has_option('swift', 'preauthurl') |
| 76 | else None) |
| 77 | preauthtoken = (self.config.get('swift', 'preauthtoken') |
| 78 | if self.config.has_option('swift', 'preauthtoken') |
| 79 | else None) |
| 80 | snet = (self.config.get('swift', 'snet') |
| 81 | if self.config.has_option('swift', 'snet') else False) |
| 82 | starting_backoff = (self.config.get('swift', 'starting_backoff') |
| 83 | if self.config.has_option('swift', |
| 84 | 'starting_backoff') |
| 85 | else 1) |
| 86 | max_backoff = (self.config.get('swift', 'max_backoff') |
| 87 | if self.config.has_option('swift', 'max_backoff') |
| 88 | else 64) |
| 89 | tenant_name = (self.config.get('swift', 'tenant_name') |
| 90 | if self.config.has_option('swift', 'tenant_name') |
| 91 | else None) |
| 92 | auth_version = (self.config.get('swift', 'auth_version') |
| 93 | if self.config.has_option('swift', 'auth_version') |
| 94 | else 2.0) |
| 95 | cacert = (self.config.get('swift', 'cacert') |
| 96 | if self.config.has_option('swift', 'cacert') else None) |
| 97 | insecure = (self.config.get('swift', 'insecure') |
| 98 | if self.config.has_option('swift', 'insecure') |
| 99 | else False) |
| 100 | ssl_compression = (self.config.get('swift', 'ssl_compression') |
| 101 | if self.config.has_option('swift', |
| 102 | 'ssl_compression') |
| 103 | else True) |
| 104 | |
| 105 | available_os_options = ['tenant_id', 'auth_token', 'service_type', |
| 106 | 'endpoint_type', 'tenant_name', |
| 107 | 'object_storage_url', 'region_name'] |
| 108 | |
| 109 | os_options = {} |
| 110 | for os_option in available_os_options: |
| 111 | if self.config.has_option('swift', os_option): |
| 112 | os_options[os_option] = self.config.get('swift', os_option) |
| 113 | |
Antoine Musso | 62fa2d4 | 2014-06-04 22:55:23 +0200 | [diff] [blame] | 114 | import swiftclient |
Joshua Hesketh | 36c3fa5 | 2014-01-22 11:40:52 +1100 | [diff] [blame] | 115 | self.connection = swiftclient.client.Connection( |
| 116 | authurl=authurl, user=user, key=key, retries=retries, |
| 117 | preauthurl=preauthurl, preauthtoken=preauthtoken, snet=snet, |
| 118 | starting_backoff=starting_backoff, max_backoff=max_backoff, |
| 119 | tenant_name=tenant_name, os_options=os_options, |
| 120 | auth_version=auth_version, cacert=cacert, insecure=insecure, |
| 121 | ssl_compression=ssl_compression) |
| 122 | |
Joshua Hesketh | 36c3fa5 | 2014-01-22 11:40:52 +1100 | [diff] [blame] | 123 | def generate_form_post_middleware_params(self, destination_prefix='', |
| 124 | **kwargs): |
| 125 | """Generate the FormPost middleware params for the given settings""" |
| 126 | |
| 127 | # Define the available settings and their defaults |
| 128 | settings = { |
| 129 | 'container': '', |
| 130 | 'expiry': 7200, |
| 131 | 'max_file_size': 104857600, |
| 132 | 'max_file_count': 10, |
| 133 | 'file_path_prefix': '' |
| 134 | } |
| 135 | |
Christian Berendt | e35b99c | 2014-06-06 16:57:47 +0200 | [diff] [blame] | 136 | for key, default in six.iteritems(settings): |
James E. Blair | d650023 | 2014-06-23 15:05:48 -0700 | [diff] [blame] | 137 | # TODO(jeblair): Remove the following two lines after a |
| 138 | # deprecation period for the underscore variants of the |
| 139 | # settings in YAML. |
Joshua Hesketh | 36c3fa5 | 2014-01-22 11:40:52 +1100 | [diff] [blame] | 140 | if key in kwargs: |
| 141 | settings[key] = kwargs[key] |
James E. Blair | d650023 | 2014-06-23 15:05:48 -0700 | [diff] [blame] | 142 | # Since we prefer '-' rather than '_' in YAML, look up |
| 143 | # keys there using hyphens. Continue to use underscores |
| 144 | # everywhere else. |
| 145 | altkey = key.replace('_', '-') |
| 146 | if altkey in kwargs: |
| 147 | settings[key] = kwargs[altkey] |
Joshua Hesketh | 36c3fa5 | 2014-01-22 11:40:52 +1100 | [diff] [blame] | 148 | elif self.config.has_option('swift', 'default_' + key): |
| 149 | settings[key] = self.config.get('swift', 'default_' + key) |
James E. Blair | 897d9cf | 2015-02-27 14:21:56 -0800 | [diff] [blame] | 150 | # TODO: these are always strings; some should be converted |
| 151 | # to ints. |
Joshua Hesketh | 36c3fa5 | 2014-01-22 11:40:52 +1100 | [diff] [blame] | 152 | |
James E. Blair | 897d9cf | 2015-02-27 14:21:56 -0800 | [diff] [blame] | 153 | expires = int(time() + int(settings['expiry'])) |
Joshua Hesketh | 36c3fa5 | 2014-01-22 11:40:52 +1100 | [diff] [blame] | 154 | redirect = '' |
| 155 | |
| 156 | url = os.path.join(self.storage_url, settings['container'], |
| 157 | settings['file_path_prefix'], |
| 158 | destination_prefix) |
| 159 | u = urlparse.urlparse(url) |
| 160 | |
| 161 | hmac_body = '%s\n%s\n%s\n%s\n%s' % (u.path, redirect, |
| 162 | settings['max_file_size'], |
| 163 | settings['max_file_count'], |
| 164 | expires) |
| 165 | |
| 166 | signature = hmac.new(self.secure_key, hmac_body, sha1).hexdigest() |
| 167 | |
| 168 | return url, hmac_body, signature |