swift 2.33.0__py2.py3-none-any.whl → 2.34.1__py2.py3-none-any.whl
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- swift/account/auditor.py +11 -0
- swift/account/reaper.py +11 -1
- swift/account/replicator.py +22 -0
- swift/account/server.py +12 -1
- swift-2.33.0.data/scripts/swift-account-audit → swift/cli/account_audit.py +6 -2
- swift-2.33.0.data/scripts/swift-config → swift/cli/config.py +1 -1
- swift-2.33.0.data/scripts/swift-dispersion-populate → swift/cli/dispersion_populate.py +6 -2
- swift-2.33.0.data/scripts/swift-drive-audit → swift/cli/drive_audit.py +12 -3
- swift-2.33.0.data/scripts/swift-get-nodes → swift/cli/get_nodes.py +6 -2
- swift/cli/info.py +103 -2
- swift-2.33.0.data/scripts/swift-oldies → swift/cli/oldies.py +6 -3
- swift-2.33.0.data/scripts/swift-orphans → swift/cli/orphans.py +7 -2
- swift/cli/recon_cron.py +5 -5
- swift-2.33.0.data/scripts/swift-reconciler-enqueue → swift/cli/reconciler_enqueue.py +2 -3
- swift/cli/relinker.py +1 -1
- swift/cli/ringbuilder.py +24 -0
- swift/common/db.py +2 -1
- swift/common/db_auditor.py +2 -2
- swift/common/db_replicator.py +6 -0
- swift/common/exceptions.py +12 -0
- swift/common/manager.py +102 -0
- swift/common/memcached.py +6 -13
- swift/common/middleware/account_quotas.py +144 -43
- swift/common/middleware/backend_ratelimit.py +166 -24
- swift/common/middleware/catch_errors.py +1 -3
- swift/common/middleware/cname_lookup.py +3 -5
- swift/common/middleware/container_sync.py +6 -10
- swift/common/middleware/crypto/crypto_utils.py +4 -5
- swift/common/middleware/crypto/decrypter.py +4 -5
- swift/common/middleware/crypto/kms_keymaster.py +2 -1
- swift/common/middleware/listing_formats.py +26 -38
- swift/common/middleware/proxy_logging.py +22 -16
- swift/common/middleware/ratelimit.py +6 -7
- swift/common/middleware/recon.py +6 -7
- swift/common/middleware/s3api/acl_handlers.py +9 -0
- swift/common/middleware/s3api/controllers/multi_upload.py +1 -9
- swift/common/middleware/s3api/controllers/obj.py +20 -1
- swift/common/middleware/s3api/s3api.py +2 -0
- swift/common/middleware/s3api/s3request.py +171 -62
- swift/common/middleware/s3api/s3response.py +35 -6
- swift/common/middleware/s3api/s3token.py +2 -2
- swift/common/middleware/s3api/utils.py +1 -0
- swift/common/middleware/slo.py +153 -52
- swift/common/middleware/tempauth.py +6 -4
- swift/common/middleware/tempurl.py +2 -2
- swift/common/middleware/x_profile/exceptions.py +1 -4
- swift/common/middleware/x_profile/html_viewer.py +10 -11
- swift/common/middleware/x_profile/profile_model.py +1 -2
- swift/common/middleware/xprofile.py +6 -2
- swift/common/request_helpers.py +69 -0
- swift/common/statsd_client.py +207 -0
- swift/common/utils/__init__.py +97 -1635
- swift/common/utils/base.py +138 -0
- swift/common/utils/config.py +443 -0
- swift/common/utils/logs.py +999 -0
- swift/common/wsgi.py +11 -3
- swift/container/auditor.py +11 -0
- swift/container/backend.py +10 -10
- swift/container/reconciler.py +11 -2
- swift/container/replicator.py +22 -1
- swift/container/server.py +12 -1
- swift/container/sharder.py +36 -12
- swift/container/sync.py +11 -1
- swift/container/updater.py +11 -2
- swift/obj/auditor.py +18 -2
- swift/obj/diskfile.py +8 -6
- swift/obj/expirer.py +155 -36
- swift/obj/reconstructor.py +28 -4
- swift/obj/replicator.py +61 -22
- swift/obj/server.py +64 -36
- swift/obj/updater.py +11 -2
- swift/proxy/controllers/base.py +38 -22
- swift/proxy/controllers/obj.py +23 -26
- swift/proxy/server.py +15 -1
- {swift-2.33.0.dist-info → swift-2.34.1.dist-info}/AUTHORS +11 -3
- {swift-2.33.0.dist-info → swift-2.34.1.dist-info}/METADATA +34 -35
- {swift-2.33.0.dist-info → swift-2.34.1.dist-info}/RECORD +82 -108
- {swift-2.33.0.dist-info → swift-2.34.1.dist-info}/WHEEL +1 -1
- {swift-2.33.0.dist-info → swift-2.34.1.dist-info}/entry_points.txt +38 -1
- swift-2.34.1.dist-info/pbr.json +1 -0
- swift-2.33.0.data/scripts/swift-account-auditor +0 -23
- swift-2.33.0.data/scripts/swift-account-info +0 -52
- swift-2.33.0.data/scripts/swift-account-reaper +0 -23
- swift-2.33.0.data/scripts/swift-account-replicator +0 -34
- swift-2.33.0.data/scripts/swift-account-server +0 -23
- swift-2.33.0.data/scripts/swift-container-auditor +0 -23
- swift-2.33.0.data/scripts/swift-container-info +0 -59
- swift-2.33.0.data/scripts/swift-container-reconciler +0 -21
- swift-2.33.0.data/scripts/swift-container-replicator +0 -34
- swift-2.33.0.data/scripts/swift-container-server +0 -23
- swift-2.33.0.data/scripts/swift-container-sharder +0 -37
- swift-2.33.0.data/scripts/swift-container-sync +0 -23
- swift-2.33.0.data/scripts/swift-container-updater +0 -23
- swift-2.33.0.data/scripts/swift-dispersion-report +0 -24
- swift-2.33.0.data/scripts/swift-form-signature +0 -20
- swift-2.33.0.data/scripts/swift-init +0 -119
- swift-2.33.0.data/scripts/swift-object-auditor +0 -29
- swift-2.33.0.data/scripts/swift-object-expirer +0 -33
- swift-2.33.0.data/scripts/swift-object-info +0 -60
- swift-2.33.0.data/scripts/swift-object-reconstructor +0 -33
- swift-2.33.0.data/scripts/swift-object-relinker +0 -23
- swift-2.33.0.data/scripts/swift-object-replicator +0 -37
- swift-2.33.0.data/scripts/swift-object-server +0 -27
- swift-2.33.0.data/scripts/swift-object-updater +0 -23
- swift-2.33.0.data/scripts/swift-proxy-server +0 -23
- swift-2.33.0.data/scripts/swift-recon +0 -24
- swift-2.33.0.data/scripts/swift-recon-cron +0 -24
- swift-2.33.0.data/scripts/swift-ring-builder +0 -37
- swift-2.33.0.data/scripts/swift-ring-builder-analyzer +0 -22
- swift-2.33.0.data/scripts/swift-ring-composer +0 -22
- swift-2.33.0.dist-info/pbr.json +0 -1
- {swift-2.33.0.dist-info → swift-2.34.1.dist-info}/LICENSE +0 -0
- {swift-2.33.0.dist-info → swift-2.34.1.dist-info}/top_level.txt +0 -0
@@ -29,8 +29,6 @@ rewritten and the request is passed further down the WSGI chain.
|
|
29
29
|
|
30
30
|
import six
|
31
31
|
|
32
|
-
from swift import gettext_ as _
|
33
|
-
|
34
32
|
try:
|
35
33
|
import dns.resolver
|
36
34
|
import dns.exception
|
@@ -167,7 +165,7 @@ class CNAMELookupMiddleware(object):
|
|
167
165
|
elif self._domain_endswith_in_storage_domain(found_domain):
|
168
166
|
# Found it!
|
169
167
|
self.logger.info(
|
170
|
-
|
168
|
+
'Mapped %(given_domain)s to %(found_domain)s',
|
171
169
|
{'given_domain': given_domain,
|
172
170
|
'found_domain': found_domain})
|
173
171
|
if port:
|
@@ -180,8 +178,8 @@ class CNAMELookupMiddleware(object):
|
|
180
178
|
else:
|
181
179
|
# try one more deep in the chain
|
182
180
|
self.logger.debug(
|
183
|
-
|
184
|
-
|
181
|
+
'Following CNAME chain for '
|
182
|
+
'%(given_domain)s to %(found_domain)s',
|
185
183
|
{'given_domain': given_domain,
|
186
184
|
'found_domain': found_domain})
|
187
185
|
a_domain = found_domain
|
@@ -17,6 +17,7 @@ import os
|
|
17
17
|
|
18
18
|
from swift.common.constraints import valid_api_version
|
19
19
|
from swift.common.container_sync_realms import ContainerSyncRealms
|
20
|
+
from swift.common.request_helpers import append_log_info
|
20
21
|
from swift.common.swob import HTTPBadRequest, HTTPUnauthorized, wsgify
|
21
22
|
from swift.common.utils import (
|
22
23
|
config_true_value, get_logger, streq_const_time)
|
@@ -109,20 +110,17 @@ class ContainerSync(object):
|
|
109
110
|
valid = False
|
110
111
|
auth = auth.split()
|
111
112
|
if len(auth) != 3:
|
112
|
-
req.environ
|
113
|
-
'cs:not-3-args')
|
113
|
+
append_log_info(req.environ, 'cs:not-3-args')
|
114
114
|
else:
|
115
115
|
realm, nonce, sig = auth
|
116
116
|
realm_key = self.realms_conf.key(realm)
|
117
117
|
realm_key2 = self.realms_conf.key2(realm)
|
118
118
|
if not realm_key:
|
119
|
-
req.environ
|
120
|
-
'cs:no-local-realm-key')
|
119
|
+
append_log_info(req.environ, 'cs:no-local-realm-key')
|
121
120
|
else:
|
122
121
|
user_key = info.get('sync_key')
|
123
122
|
if not user_key:
|
124
|
-
req.environ
|
125
|
-
'cs:no-local-user-key')
|
123
|
+
append_log_info(req.environ, 'cs:no-local-user-key')
|
126
124
|
else:
|
127
125
|
# x-timestamp headers get shunted by gatekeeper
|
128
126
|
if 'x-backend-inbound-x-timestamp' in req.headers:
|
@@ -139,11 +137,9 @@ class ContainerSync(object):
|
|
139
137
|
realm_key2, user_key) if realm_key2 else expected
|
140
138
|
if not streq_const_time(sig, expected) and \
|
141
139
|
not streq_const_time(sig, expected2):
|
142
|
-
req.environ
|
143
|
-
'swift.log_info', []).append('cs:invalid-sig')
|
140
|
+
append_log_info(req.environ, 'cs:invalid-sig')
|
144
141
|
else:
|
145
|
-
req.environ
|
146
|
-
'swift.log_info', []).append('cs:valid')
|
142
|
+
append_log_info(req.environ, 'cs:valid')
|
147
143
|
valid = True
|
148
144
|
if not valid:
|
149
145
|
exc = HTTPUnauthorized(
|
@@ -22,7 +22,6 @@ from cryptography.hazmat.primitives.ciphers import Cipher, algorithms, modes
|
|
22
22
|
import six
|
23
23
|
from six.moves.urllib import parse as urlparse
|
24
24
|
|
25
|
-
from swift import gettext_ as _
|
26
25
|
from swift.common.exceptions import EncryptionException, UnknownSecretIdError
|
27
26
|
from swift.common.swob import HTTPInternalServerError
|
28
27
|
from swift.common.utils import get_logger
|
@@ -160,7 +159,7 @@ class CryptoWSGIContext(WSGIContext):
|
|
160
159
|
try:
|
161
160
|
fetch_crypto_keys = env[CRYPTO_KEY_CALLBACK]
|
162
161
|
except KeyError:
|
163
|
-
self.logger.exception(
|
162
|
+
self.logger.exception('ERROR get_keys() missing callback')
|
164
163
|
raise HTTPInternalServerError(
|
165
164
|
"Unable to retrieve encryption keys.")
|
166
165
|
|
@@ -181,12 +180,12 @@ class CryptoWSGIContext(WSGIContext):
|
|
181
180
|
self.crypto.check_key(key)
|
182
181
|
continue
|
183
182
|
except KeyError:
|
184
|
-
self.logger.exception(
|
183
|
+
self.logger.exception("Missing key for %r", name)
|
185
184
|
except TypeError:
|
186
|
-
self.logger.exception(
|
185
|
+
self.logger.exception("Did not get a keys dict")
|
187
186
|
except ValueError as e:
|
188
187
|
# don't include the key in any messages!
|
189
|
-
self.logger.exception(
|
188
|
+
self.logger.exception("Bad key for %(name)r: %(err)s",
|
190
189
|
{'name': name, 'err': e})
|
191
190
|
raise HTTPInternalServerError(
|
192
191
|
"Unable to retrieve encryption keys.")
|
@@ -16,7 +16,6 @@
|
|
16
16
|
import base64
|
17
17
|
import json
|
18
18
|
|
19
|
-
from swift import gettext_ as _
|
20
19
|
from swift.common.header_key_dict import HeaderKeyDict
|
21
20
|
from swift.common.http import is_success
|
22
21
|
from swift.common.middleware.crypto.crypto_utils import CryptoWSGIContext, \
|
@@ -77,10 +76,10 @@ class BaseDecrypterContext(CryptoWSGIContext):
|
|
77
76
|
crypto_meta['body_key'])
|
78
77
|
except KeyError as err:
|
79
78
|
self.logger.error(
|
80
|
-
|
79
|
+
'Error decrypting %(resp_type)s: Missing %(key)s',
|
81
80
|
{'resp_type': self.server_type, 'key': err})
|
82
81
|
except ValueError as err:
|
83
|
-
self.logger.error(
|
82
|
+
self.logger.error('Error decrypting %(resp_type)s: %(reason)s',
|
84
83
|
{'resp_type': self.server_type, 'reason': err})
|
85
84
|
raise HTTPInternalServerError(
|
86
85
|
body='Error decrypting %s' % self.server_type,
|
@@ -178,7 +177,7 @@ class DecrypterObjContext(BaseDecrypterContext):
|
|
178
177
|
value, key, required, bytes_to_wsgi)
|
179
178
|
except EncryptionException as err:
|
180
179
|
self.logger.error(
|
181
|
-
|
180
|
+
"Error decrypting header %(header)s: %(error)s",
|
182
181
|
{'header': header, 'error': err})
|
183
182
|
raise HTTPInternalServerError(
|
184
183
|
body='Error decrypting header',
|
@@ -313,7 +312,7 @@ class DecrypterObjContext(BaseDecrypterContext):
|
|
313
312
|
try:
|
314
313
|
crypto_meta = self.get_crypto_meta(header, check)
|
315
314
|
except EncryptionException as err:
|
316
|
-
self.logger.error(
|
315
|
+
self.logger.error('Error decrypting object: %s', err)
|
317
316
|
raise HTTPInternalServerError(
|
318
317
|
body='Error decrypting object', content_type='text/plain')
|
319
318
|
return crypto_meta
|
@@ -34,7 +34,7 @@ class KmsKeyMaster(BaseKeyMaster):
|
|
34
34
|
'domain_id', 'domain_name', 'project_id',
|
35
35
|
'project_domain_id', 'reauthenticate',
|
36
36
|
'auth_endpoint', 'api_class', 'key_id*',
|
37
|
-
'active_root_secret_id')
|
37
|
+
'barbican_endpoint', 'active_root_secret_id')
|
38
38
|
keymaster_conf_section = 'kms_keymaster'
|
39
39
|
|
40
40
|
def _get_root_secret(self, conf):
|
@@ -67,6 +67,7 @@ class KmsKeyMaster(BaseKeyMaster):
|
|
67
67
|
oslo_conf = cfg.ConfigOpts()
|
68
68
|
options.set_defaults(
|
69
69
|
oslo_conf, auth_endpoint=conf.get('auth_endpoint'),
|
70
|
+
barbican_endpoint=conf.get('barbican_endpoint'),
|
70
71
|
api_class=conf.get('api_class')
|
71
72
|
)
|
72
73
|
options.enable_logging()
|
@@ -18,6 +18,7 @@ import six
|
|
18
18
|
from xml.etree.cElementTree import Element, SubElement, tostring
|
19
19
|
|
20
20
|
from swift.common.constraints import valid_api_version
|
21
|
+
from swift.common.header_key_dict import HeaderKeyDict
|
21
22
|
from swift.common.http import HTTP_NO_CONTENT
|
22
23
|
from swift.common.request_helpers import get_param
|
23
24
|
from swift.common.swob import HTTPException, HTTPNotAcceptable, Request, \
|
@@ -178,52 +179,39 @@ class ListingFilter(object):
|
|
178
179
|
start_response(status, headers)
|
179
180
|
return resp_iter
|
180
181
|
|
181
|
-
header_to_index = {}
|
182
|
-
resp_content_type = resp_length = None
|
183
|
-
for i, (header, value) in enumerate(headers):
|
184
|
-
header = header.lower()
|
185
|
-
if header == 'content-type':
|
186
|
-
header_to_index[header] = i
|
187
|
-
resp_content_type = value.partition(';')[0]
|
188
|
-
elif header == 'content-length':
|
189
|
-
header_to_index[header] = i
|
190
|
-
resp_length = int(value)
|
191
|
-
elif header == 'vary':
|
192
|
-
header_to_index[header] = i
|
193
|
-
|
194
182
|
if not status.startswith(('200 ', '204 ')):
|
195
183
|
start_response(status, headers)
|
196
184
|
return resp_iter
|
197
185
|
|
186
|
+
headers_dict = HeaderKeyDict(headers)
|
187
|
+
resp_content_type = headers_dict.get(
|
188
|
+
'content-type', '').partition(';')[0]
|
189
|
+
resp_length = headers_dict.get('content-length')
|
190
|
+
|
198
191
|
if can_vary:
|
199
|
-
if 'vary' in
|
200
|
-
value =
|
192
|
+
if 'vary' in headers_dict:
|
193
|
+
value = headers_dict['vary']
|
201
194
|
if 'accept' not in list_from_csv(value.lower()):
|
202
|
-
|
203
|
-
'Vary', value + ', Accept')
|
195
|
+
headers_dict['vary'] = value + ', Accept'
|
204
196
|
else:
|
205
|
-
|
197
|
+
headers_dict['vary'] = 'Accept'
|
206
198
|
|
207
199
|
if resp_content_type != 'application/json':
|
208
|
-
start_response(status,
|
200
|
+
start_response(status, list(headers_dict.items()))
|
209
201
|
return resp_iter
|
210
202
|
|
211
|
-
if
|
212
|
-
|
213
|
-
|
203
|
+
if req.method == 'HEAD':
|
204
|
+
headers_dict['content-type'] = out_content_type + '; charset=utf-8'
|
205
|
+
# proxy logging (and maybe other mw?) seem to be good about
|
206
|
+
# sticking this on HEAD/204 but we do it here to be responsible
|
207
|
+
# and explicit
|
208
|
+
headers_dict['content-length'] = 0
|
209
|
+
start_response(status, list(headers_dict.items()))
|
214
210
|
return resp_iter
|
215
211
|
|
216
|
-
|
217
|
-
|
218
|
-
|
219
|
-
else:
|
220
|
-
headers[header_to_index[header]] = (
|
221
|
-
headers[header_to_index[header]][0], str(value))
|
222
|
-
|
223
|
-
if req.method == 'HEAD':
|
224
|
-
set_header('content-type', out_content_type + '; charset=utf-8')
|
225
|
-
set_header('content-length', None) # don't know, can't determine
|
226
|
-
start_response(status, headers)
|
212
|
+
if resp_length is None or \
|
213
|
+
int(resp_length) > MAX_CONTAINER_LISTING_CONTENT_LENGTH:
|
214
|
+
start_response(status, list(headers_dict.items()))
|
227
215
|
return resp_iter
|
228
216
|
|
229
217
|
body = b''.join(resp_iter)
|
@@ -237,7 +225,7 @@ class ListingFilter(object):
|
|
237
225
|
except ValueError:
|
238
226
|
# Static web listing that's returning invalid JSON?
|
239
227
|
# Just pass it straight through; that's about all we *can* do.
|
240
|
-
start_response(status,
|
228
|
+
start_response(status, list(headers_dict.items()))
|
241
229
|
return [body]
|
242
230
|
|
243
231
|
if not req.allow_reserved_names:
|
@@ -257,16 +245,16 @@ class ListingFilter(object):
|
|
257
245
|
body = json.dumps(listing).encode('ascii')
|
258
246
|
except KeyError:
|
259
247
|
# listing was in a bad format -- funky static web listing??
|
260
|
-
start_response(status,
|
248
|
+
start_response(status, list(headers_dict.items()))
|
261
249
|
return [body]
|
262
250
|
|
263
251
|
if not body:
|
264
252
|
status = '%s %s' % (HTTP_NO_CONTENT,
|
265
253
|
RESPONSE_REASONS[HTTP_NO_CONTENT][0])
|
266
254
|
|
267
|
-
|
268
|
-
|
269
|
-
start_response(status,
|
255
|
+
headers_dict['content-type'] = out_content_type + '; charset=utf-8'
|
256
|
+
headers_dict['content-length'] = len(body)
|
257
|
+
start_response(status, list(headers_dict.items()))
|
270
258
|
return [body]
|
271
259
|
|
272
260
|
|
@@ -88,7 +88,9 @@ bandwidth usage will want to only sum up logs with no ``swift.source``.
|
|
88
88
|
import os
|
89
89
|
import time
|
90
90
|
|
91
|
+
from swift.common.constraints import valid_api_version
|
91
92
|
from swift.common.middleware.catch_errors import enforce_byte_count
|
93
|
+
from swift.common.request_helpers import get_log_info
|
92
94
|
from swift.common.swob import Request
|
93
95
|
from swift.common.utils import (get_logger, get_remote_client,
|
94
96
|
config_true_value, reiterate,
|
@@ -247,6 +249,7 @@ class ProxyLoggingMiddleware(object):
|
|
247
249
|
:param start_time: timestamp request started
|
248
250
|
:param end_time: timestamp request completed
|
249
251
|
:param resp_headers: dict of the response headers
|
252
|
+
:param ttfb: time to first byte
|
250
253
|
:param wire_status_int: the on the wire status int
|
251
254
|
"""
|
252
255
|
self.obscure_req(req)
|
@@ -269,10 +272,8 @@ class ProxyLoggingMiddleware(object):
|
|
269
272
|
duration_time_str = "%.4f" % (end_time - start_time)
|
270
273
|
policy_index = get_policy_index(req.headers, resp_headers)
|
271
274
|
|
272
|
-
acc, cont, obj = None, None, None
|
273
275
|
swift_path = req.environ.get('swift.backend_path', req.path)
|
274
|
-
|
275
|
-
_, acc, cont, obj = split_path(swift_path, 1, 4, True)
|
276
|
+
acc, cont, obj = self.get_aco_from_path(swift_path)
|
276
277
|
|
277
278
|
replacements = {
|
278
279
|
# Time information
|
@@ -317,8 +318,7 @@ class ProxyLoggingMiddleware(object):
|
|
317
318
|
'transaction_id': req.environ.get('swift.trans_id'),
|
318
319
|
'request_time': duration_time_str,
|
319
320
|
'source': req.environ.get('swift.source'),
|
320
|
-
'log_info':
|
321
|
-
','.join(req.environ.get('swift.log_info', '')),
|
321
|
+
'log_info': get_log_info(req.environ),
|
322
322
|
'policy_index': policy_index,
|
323
323
|
'ttfb': ttfb,
|
324
324
|
'pid': self.pid,
|
@@ -347,22 +347,28 @@ class ProxyLoggingMiddleware(object):
|
|
347
347
|
self.access_logger.update_stats(metric_name_policy + '.xfer',
|
348
348
|
bytes_received + bytes_sent)
|
349
349
|
|
350
|
+
def get_aco_from_path(self, swift_path):
|
351
|
+
try:
|
352
|
+
version, acc, cont, obj = split_path(swift_path, 1, 4, True)
|
353
|
+
if not valid_api_version(version):
|
354
|
+
raise ValueError
|
355
|
+
except ValueError:
|
356
|
+
acc, cont, obj = None, None, None
|
357
|
+
return acc, cont, obj
|
358
|
+
|
350
359
|
def get_metric_name_type(self, req):
|
351
360
|
swift_path = req.environ.get('swift.backend_path', req.path)
|
352
|
-
|
353
|
-
|
354
|
-
|
355
|
-
|
356
|
-
|
357
|
-
|
358
|
-
|
359
|
-
|
360
|
-
return stat_type
|
361
|
+
acc, cont, obj = self.get_aco_from_path(swift_path)
|
362
|
+
if obj:
|
363
|
+
return 'object'
|
364
|
+
if cont:
|
365
|
+
return 'container'
|
366
|
+
if acc:
|
367
|
+
return 'account'
|
368
|
+
return req.environ.get('swift.source') or 'UNKNOWN'
|
361
369
|
|
362
370
|
def statsd_metric_name(self, req, status_int, method):
|
363
371
|
stat_type = self.get_metric_name_type(req)
|
364
|
-
if stat_type is None:
|
365
|
-
return None
|
366
372
|
stat_method = method if method in self.valid_methods \
|
367
373
|
else 'BAD_METHOD'
|
368
374
|
return '.'.join((stat_type, stat_method, str(status_int)))
|
@@ -13,7 +13,6 @@
|
|
13
13
|
# See the License for the specific language governing permissions and
|
14
14
|
# limitations under the License.
|
15
15
|
import time
|
16
|
-
from swift import gettext_ as _
|
17
16
|
|
18
17
|
import eventlet
|
19
18
|
|
@@ -261,7 +260,7 @@ class RateLimitMiddleware(object):
|
|
261
260
|
|
262
261
|
if account_name in self.ratelimit_blacklist or \
|
263
262
|
account_global_ratelimit == 'BLACKLIST':
|
264
|
-
self.logger.error(
|
263
|
+
self.logger.error('Returning 497 because of blacklisting: %s',
|
265
264
|
account_name)
|
266
265
|
eventlet.sleep(self.BLACK_LIST_SLEEP)
|
267
266
|
return Response(status='497 Blacklisted',
|
@@ -276,8 +275,8 @@ class RateLimitMiddleware(object):
|
|
276
275
|
if self.log_sleep_time_seconds and \
|
277
276
|
need_to_sleep > self.log_sleep_time_seconds:
|
278
277
|
self.logger.warning(
|
279
|
-
|
280
|
-
|
278
|
+
"Ratelimit sleep log: %(sleep)s for "
|
279
|
+
"%(account)s/%(container)s/%(object)s",
|
281
280
|
{'sleep': need_to_sleep, 'account': account_name,
|
282
281
|
'container': container_name, 'object': obj_name})
|
283
282
|
if need_to_sleep > 0:
|
@@ -288,8 +287,8 @@ class RateLimitMiddleware(object):
|
|
288
287
|
else:
|
289
288
|
path = '/'.join((account_name, container_name))
|
290
289
|
self.logger.error(
|
291
|
-
|
292
|
-
|
290
|
+
'Returning 498 for %(meth)s to %(path)s. '
|
291
|
+
'Ratelimit (Max Sleep) %(e)s',
|
293
292
|
{'meth': req.method, 'path': path, 'e': str(e)})
|
294
293
|
error_resp = Response(status='498 Rate Limited',
|
295
294
|
body='Slow down', request=req)
|
@@ -309,7 +308,7 @@ class RateLimitMiddleware(object):
|
|
309
308
|
self.memcache_client = cache_from_env(env)
|
310
309
|
if not self.memcache_client:
|
311
310
|
self.logger.warning(
|
312
|
-
|
311
|
+
'Warning: Cannot ratelimit without a memcached client')
|
313
312
|
return self.app(env, start_response)
|
314
313
|
try:
|
315
314
|
version, account, container, obj = req.split_path(1, 4, True)
|
swift/common/middleware/recon.py
CHANGED
@@ -20,7 +20,6 @@ import time
|
|
20
20
|
from resource import getpagesize
|
21
21
|
|
22
22
|
from swift import __version__ as swiftver
|
23
|
-
from swift import gettext_ as _
|
24
23
|
from swift.common.constraints import check_mount
|
25
24
|
from swift.common.storage_policy import POLICIES
|
26
25
|
from swift.common.swob import Request, Response
|
@@ -89,11 +88,11 @@ class ReconMiddleware(object):
|
|
89
88
|
if err.errno == errno.ENOENT and ignore_missing:
|
90
89
|
pass
|
91
90
|
else:
|
92
|
-
self.logger.exception(
|
91
|
+
self.logger.exception('Error reading recon cache file')
|
93
92
|
except ValueError:
|
94
|
-
self.logger.exception(
|
93
|
+
self.logger.exception('Error parsing recon cache file')
|
95
94
|
except Exception:
|
96
|
-
self.logger.exception(
|
95
|
+
self.logger.exception('Error retrieving recon data')
|
97
96
|
return dict((key, None) for key in cache_keys)
|
98
97
|
|
99
98
|
def get_version(self):
|
@@ -181,7 +180,7 @@ class ReconMiddleware(object):
|
|
181
180
|
try:
|
182
181
|
return {self.devices: os.listdir(self.devices)}
|
183
182
|
except Exception:
|
184
|
-
self.logger.exception(
|
183
|
+
self.logger.exception('Error listing devices')
|
185
184
|
return {self.devices: None}
|
186
185
|
|
187
186
|
def get_updater_info(self, recon_type):
|
@@ -277,7 +276,7 @@ class ReconMiddleware(object):
|
|
277
276
|
except IOError as err:
|
278
277
|
sums[ringfile] = None
|
279
278
|
if err.errno != errno.ENOENT:
|
280
|
-
self.logger.exception(
|
279
|
+
self.logger.exception('Error reading ringfile')
|
281
280
|
return sums
|
282
281
|
|
283
282
|
def get_swift_conf_md5(self):
|
@@ -287,7 +286,7 @@ class ReconMiddleware(object):
|
|
287
286
|
hexsum = md5_hash_for_file(SWIFT_CONF_FILE)
|
288
287
|
except IOError as err:
|
289
288
|
if err.errno != errno.ENOENT:
|
290
|
-
self.logger.exception(
|
289
|
+
self.logger.exception('Error reading swift.conf')
|
291
290
|
return {SWIFT_CONF_FILE: hexsum}
|
292
291
|
|
293
292
|
def get_quarantine_count(self):
|
@@ -133,6 +133,15 @@ class BaseAclHandler(object):
|
|
133
133
|
query = {}
|
134
134
|
else:
|
135
135
|
query = {'version-id': version_id}
|
136
|
+
if self.req.method == 'HEAD':
|
137
|
+
# This HEAD for ACL is going to also be the definitive response
|
138
|
+
# to the client so we need to include client params. We don't
|
139
|
+
# do this for other client request methods because they may
|
140
|
+
# have invalid combinations of params and headers for a swift
|
141
|
+
# HEAD request.
|
142
|
+
part_number = self.req.params.get('partNumber')
|
143
|
+
if part_number is not None:
|
144
|
+
query['part-number'] = part_number
|
136
145
|
resp = self.req.get_acl_response(app, 'HEAD',
|
137
146
|
container, obj,
|
138
147
|
headers, query=query)
|
@@ -196,15 +196,7 @@ class PartController(Controller):
|
|
196
196
|
raise InvalidArgument('ResourceType', 'partNumber',
|
197
197
|
'Unexpected query string parameter')
|
198
198
|
|
199
|
-
|
200
|
-
part_number = int(get_param(req, 'partNumber'))
|
201
|
-
if part_number < 1 or self.conf.max_upload_part_num < part_number:
|
202
|
-
raise Exception()
|
203
|
-
except Exception:
|
204
|
-
err_msg = 'Part number must be an integer between 1 and %d,' \
|
205
|
-
' inclusive' % self.conf.max_upload_part_num
|
206
|
-
raise InvalidArgument('partNumber', get_param(req, 'partNumber'),
|
207
|
-
err_msg)
|
199
|
+
part_number = req.validate_part_number()
|
208
200
|
|
209
201
|
upload_id = get_param(req, 'uploadId')
|
210
202
|
_get_upload_info(req, self.app, upload_id)
|
@@ -90,8 +90,14 @@ class ObjectController(Controller):
|
|
90
90
|
if version_id not in ('null', None) and \
|
91
91
|
'object_versioning' not in get_swift_info():
|
92
92
|
raise S3NotImplemented()
|
93
|
+
part_number = req.validate_part_number(check_max=False)
|
94
|
+
|
95
|
+
query = {}
|
96
|
+
if version_id is not None:
|
97
|
+
query['version-id'] = version_id
|
98
|
+
if part_number is not None:
|
99
|
+
query['part-number'] = part_number
|
93
100
|
|
94
|
-
query = {} if version_id is None else {'version-id': version_id}
|
95
101
|
if version_id not in ('null', None):
|
96
102
|
container_info = req.get_container_info(self.app)
|
97
103
|
if not container_info.get(
|
@@ -101,6 +107,19 @@ class ObjectController(Controller):
|
|
101
107
|
|
102
108
|
resp = req.get_response(self.app, query=query)
|
103
109
|
|
110
|
+
if not resp.is_slo:
|
111
|
+
# SLO ignores part_number for non-slo objects, but s3api only
|
112
|
+
# allows the query param for non-MPU if it's exactly 1.
|
113
|
+
part_number = req.validate_part_number(parts_count=1)
|
114
|
+
if part_number == 1:
|
115
|
+
# When the query param *is* exactly 1 the response status code
|
116
|
+
# and headers are updated.
|
117
|
+
resp.status = HTTP_PARTIAL_CONTENT
|
118
|
+
resp.headers['Content-Range'] = \
|
119
|
+
'bytes 0-%d/%s' % (int(resp.headers['Content-Length']) - 1,
|
120
|
+
resp.headers['Content-Length'])
|
121
|
+
# else: part_number is None
|
122
|
+
|
104
123
|
if req.method == 'HEAD':
|
105
124
|
resp.app_iter = None
|
106
125
|
|
@@ -149,6 +149,7 @@ from six.moves.urllib.parse import parse_qs
|
|
149
149
|
from swift.common.constraints import valid_api_version
|
150
150
|
from swift.common.middleware.listing_formats import \
|
151
151
|
MAX_CONTAINER_LISTING_CONTENT_LENGTH
|
152
|
+
from swift.common.request_helpers import append_log_info
|
152
153
|
from swift.common.wsgi import PipelineWrapper, loadcontext, WSGIContext
|
153
154
|
|
154
155
|
from swift.common.middleware import app_property
|
@@ -353,6 +354,7 @@ class S3ApiMiddleware(object):
|
|
353
354
|
self.logger.debug(e.cause)
|
354
355
|
except ErrorResponse as err_resp:
|
355
356
|
self.logger.increment(err_resp.metric_name)
|
357
|
+
append_log_info(env, 's3:err:%s' % err_resp.summary)
|
356
358
|
if isinstance(err_resp, InternalError):
|
357
359
|
self.logger.exception(err_resp)
|
358
360
|
resp = err_resp
|