blob: 3c411d3ff139824d9fd6f623f6ff7e02130b357b [file] [log] [blame]
Joshua Hesketh36c3fa52014-01-22 11:40:52 +11001# 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
15import hmac
16from hashlib import sha1
Joshua Heskethb95d38b2014-05-14 14:58:33 -070017import logging
Joshua Hesketh36c3fa52014-01-22 11:40:52 +110018from time import time
19import os
20import random
Christian Berendte35b99c2014-06-06 16:57:47 +020021import six
Joshua Hesketh36c3fa52014-01-22 11:40:52 +110022import string
Joshua Hesketh36c3fa52014-01-22 11:40:52 +110023import urlparse
24
25
26class Swift(object):
Joshua Heskethb95d38b2014-05-14 14:58:33 -070027 log = logging.getLogger("zuul.lib.swift")
28
Joshua Hesketh36c3fa52014-01-22 11:40:52 +110029 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 Heskethb95d38b2014-05-14 14:58:33 -070041 self.storage_url = ''
Joshua Heskethc4967502014-05-15 06:39:14 -070042 if self.config.has_option('swift', 'X-Storage-Url'):
43 self.storage_url = self.config.get('swift', 'X-Storage-Url')
Joshua Heskethb95d38b2014-05-14 14:58:33 -070044
45 try:
Joshua Heskethc4967502014-05-15 06:39:14 -070046 if self.config.has_section('swift'):
47 if (not self.config.has_option('swift', 'Send-Temp-Url-Key')
Joshua Hesketh29d99b72014-08-19 16:27:42 +100048 or self.config.getboolean('swift',
49 'Send-Temp-Url-Key')):
Joshua Heskethc4967502014-05-15 06:39:14 -070050 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 Heskethb95d38b2014-05-14 14:58:33 -070060 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 Hesketh36c3fa52014-01-22 11:40:52 +110063
64 def connect(self):
Joshua Heskethc4967502014-05-15 06:39:14 -070065 if not self.connection:
Joshua Hesketh36c3fa52014-01-22 11:40:52 +110066 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 Musso62fa2d42014-06-04 22:55:23 +0200114 import swiftclient
Joshua Hesketh36c3fa52014-01-22 11:40:52 +1100115 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 Hesketh36c3fa52014-01-22 11:40:52 +1100123 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 Berendte35b99c2014-06-06 16:57:47 +0200136 for key, default in six.iteritems(settings):
James E. Blaird6500232014-06-23 15:05:48 -0700137 # TODO(jeblair): Remove the following two lines after a
138 # deprecation period for the underscore variants of the
139 # settings in YAML.
Joshua Hesketh36c3fa52014-01-22 11:40:52 +1100140 if key in kwargs:
141 settings[key] = kwargs[key]
James E. Blaird6500232014-06-23 15:05:48 -0700142 # 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 Hesketh36c3fa52014-01-22 11:40:52 +1100148 elif self.config.has_option('swift', 'default_' + key):
149 settings[key] = self.config.get('swift', 'default_' + key)
James E. Blair897d9cf2015-02-27 14:21:56 -0800150 # TODO: these are always strings; some should be converted
151 # to ints.
Joshua Hesketh36c3fa52014-01-22 11:40:52 +1100152
James E. Blair897d9cf2015-02-27 14:21:56 -0800153 expires = int(time() + int(settings['expiry']))
Joshua Hesketh36c3fa52014-01-22 11:40:52 +1100154 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