swift 2.23.2__py3-none-any.whl → 2.35.0__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/__init__.py +29 -50
- swift/account/auditor.py +21 -118
- swift/account/backend.py +33 -28
- swift/account/reaper.py +37 -28
- swift/account/replicator.py +22 -0
- swift/account/server.py +60 -26
- swift/account/utils.py +28 -11
- swift-2.23.2.data/scripts/swift-account-audit → swift/cli/account_audit.py +23 -13
- swift-2.23.2.data/scripts/swift-config → swift/cli/config.py +2 -2
- swift/cli/container_deleter.py +5 -11
- swift-2.23.2.data/scripts/swift-dispersion-populate → swift/cli/dispersion_populate.py +8 -7
- swift/cli/dispersion_report.py +10 -9
- swift-2.23.2.data/scripts/swift-drive-audit → swift/cli/drive_audit.py +63 -21
- swift/cli/form_signature.py +3 -7
- swift-2.23.2.data/scripts/swift-get-nodes → swift/cli/get_nodes.py +8 -2
- swift/cli/info.py +183 -29
- swift/cli/manage_shard_ranges.py +708 -37
- swift-2.23.2.data/scripts/swift-oldies → swift/cli/oldies.py +25 -14
- swift-2.23.2.data/scripts/swift-orphans → swift/cli/orphans.py +7 -3
- swift/cli/recon.py +196 -67
- swift-2.23.2.data/scripts/swift-recon-cron → swift/cli/recon_cron.py +17 -20
- swift-2.23.2.data/scripts/swift-reconciler-enqueue → swift/cli/reconciler_enqueue.py +2 -3
- swift/cli/relinker.py +807 -126
- swift/cli/reload.py +135 -0
- swift/cli/ringbuilder.py +217 -20
- swift/cli/ringcomposer.py +0 -1
- swift/cli/shard-info.py +4 -3
- swift/common/base_storage_server.py +9 -20
- swift/common/bufferedhttp.py +48 -74
- swift/common/constraints.py +20 -15
- swift/common/container_sync_realms.py +9 -11
- swift/common/daemon.py +25 -8
- swift/common/db.py +198 -127
- swift/common/db_auditor.py +168 -0
- swift/common/db_replicator.py +95 -55
- swift/common/digest.py +141 -0
- swift/common/direct_client.py +144 -33
- swift/common/error_limiter.py +93 -0
- swift/common/exceptions.py +25 -1
- swift/common/header_key_dict.py +2 -9
- swift/common/http_protocol.py +373 -0
- swift/common/internal_client.py +129 -59
- swift/common/linkat.py +3 -4
- swift/common/manager.py +284 -67
- swift/common/memcached.py +396 -147
- swift/common/middleware/__init__.py +4 -0
- swift/common/middleware/account_quotas.py +211 -46
- swift/common/middleware/acl.py +3 -8
- swift/common/middleware/backend_ratelimit.py +230 -0
- swift/common/middleware/bulk.py +22 -34
- swift/common/middleware/catch_errors.py +1 -3
- swift/common/middleware/cname_lookup.py +6 -11
- swift/common/middleware/container_quotas.py +1 -1
- swift/common/middleware/container_sync.py +39 -17
- swift/common/middleware/copy.py +12 -0
- swift/common/middleware/crossdomain.py +22 -9
- swift/common/middleware/crypto/__init__.py +2 -1
- swift/common/middleware/crypto/crypto_utils.py +11 -15
- swift/common/middleware/crypto/decrypter.py +28 -11
- swift/common/middleware/crypto/encrypter.py +12 -17
- swift/common/middleware/crypto/keymaster.py +8 -15
- swift/common/middleware/crypto/kms_keymaster.py +2 -1
- swift/common/middleware/dlo.py +15 -11
- swift/common/middleware/domain_remap.py +5 -4
- swift/common/middleware/etag_quoter.py +128 -0
- swift/common/middleware/formpost.py +73 -70
- swift/common/middleware/gatekeeper.py +8 -1
- swift/common/middleware/keystoneauth.py +33 -3
- swift/common/middleware/list_endpoints.py +4 -4
- swift/common/middleware/listing_formats.py +85 -49
- swift/common/middleware/memcache.py +4 -81
- swift/common/middleware/name_check.py +3 -2
- swift/common/middleware/proxy_logging.py +160 -92
- swift/common/middleware/ratelimit.py +17 -10
- swift/common/middleware/read_only.py +6 -4
- swift/common/middleware/recon.py +59 -22
- swift/common/middleware/s3api/acl_handlers.py +25 -3
- swift/common/middleware/s3api/acl_utils.py +6 -1
- swift/common/middleware/s3api/controllers/__init__.py +6 -0
- swift/common/middleware/s3api/controllers/acl.py +3 -2
- swift/common/middleware/s3api/controllers/bucket.py +242 -137
- swift/common/middleware/s3api/controllers/logging.py +2 -2
- swift/common/middleware/s3api/controllers/multi_delete.py +43 -20
- swift/common/middleware/s3api/controllers/multi_upload.py +219 -133
- swift/common/middleware/s3api/controllers/obj.py +112 -8
- swift/common/middleware/s3api/controllers/object_lock.py +44 -0
- swift/common/middleware/s3api/controllers/s3_acl.py +2 -2
- swift/common/middleware/s3api/controllers/tagging.py +57 -0
- swift/common/middleware/s3api/controllers/versioning.py +36 -7
- swift/common/middleware/s3api/etree.py +22 -9
- swift/common/middleware/s3api/exception.py +0 -4
- swift/common/middleware/s3api/s3api.py +113 -41
- swift/common/middleware/s3api/s3request.py +384 -218
- swift/common/middleware/s3api/s3response.py +126 -23
- swift/common/middleware/s3api/s3token.py +16 -17
- swift/common/middleware/s3api/schema/delete.rng +1 -1
- swift/common/middleware/s3api/subresource.py +7 -10
- swift/common/middleware/s3api/utils.py +27 -10
- swift/common/middleware/slo.py +665 -358
- swift/common/middleware/staticweb.py +64 -37
- swift/common/middleware/symlink.py +52 -19
- swift/common/middleware/tempauth.py +76 -58
- swift/common/middleware/tempurl.py +192 -174
- swift/common/middleware/versioned_writes/__init__.py +51 -0
- swift/common/middleware/{versioned_writes.py → versioned_writes/legacy.py} +27 -26
- swift/common/middleware/versioned_writes/object_versioning.py +1482 -0
- swift/common/middleware/x_profile/exceptions.py +1 -4
- swift/common/middleware/x_profile/html_viewer.py +18 -19
- swift/common/middleware/x_profile/profile_model.py +1 -2
- swift/common/middleware/xprofile.py +10 -10
- swift-2.23.2.data/scripts/swift-container-server → swift/common/recon.py +13 -8
- swift/common/registry.py +147 -0
- swift/common/request_helpers.py +324 -57
- swift/common/ring/builder.py +67 -25
- swift/common/ring/composite_builder.py +1 -1
- swift/common/ring/ring.py +177 -51
- swift/common/ring/utils.py +1 -1
- swift/common/splice.py +10 -6
- swift/common/statsd_client.py +205 -0
- swift/common/storage_policy.py +49 -44
- swift/common/swob.py +86 -102
- swift/common/{utils.py → utils/__init__.py} +2191 -2762
- swift/common/utils/base.py +131 -0
- swift/common/utils/config.py +433 -0
- swift/common/utils/ipaddrs.py +256 -0
- swift/common/utils/libc.py +345 -0
- swift/common/utils/logs.py +859 -0
- swift/common/utils/timestamp.py +412 -0
- swift/common/wsgi.py +555 -536
- swift/container/auditor.py +14 -100
- swift/container/backend.py +552 -227
- swift/container/reconciler.py +126 -37
- swift/container/replicator.py +96 -22
- swift/container/server.py +397 -176
- swift/container/sharder.py +1580 -639
- swift/container/sync.py +94 -88
- swift/container/updater.py +53 -32
- swift/obj/auditor.py +153 -35
- swift/obj/diskfile.py +466 -217
- swift/obj/expirer.py +406 -124
- swift/obj/mem_diskfile.py +7 -4
- swift/obj/mem_server.py +1 -0
- swift/obj/reconstructor.py +523 -262
- swift/obj/replicator.py +249 -188
- swift/obj/server.py +213 -122
- swift/obj/ssync_receiver.py +145 -85
- swift/obj/ssync_sender.py +113 -54
- swift/obj/updater.py +653 -139
- swift/obj/watchers/__init__.py +0 -0
- swift/obj/watchers/dark_data.py +213 -0
- swift/proxy/controllers/account.py +11 -11
- swift/proxy/controllers/base.py +848 -604
- swift/proxy/controllers/container.py +452 -86
- swift/proxy/controllers/info.py +3 -2
- swift/proxy/controllers/obj.py +1009 -490
- swift/proxy/server.py +185 -112
- swift-2.35.0.dist-info/AUTHORS +501 -0
- swift-2.35.0.dist-info/LICENSE +202 -0
- {swift-2.23.2.dist-info → swift-2.35.0.dist-info}/METADATA +52 -61
- swift-2.35.0.dist-info/RECORD +201 -0
- {swift-2.23.2.dist-info → swift-2.35.0.dist-info}/WHEEL +1 -1
- {swift-2.23.2.dist-info → swift-2.35.0.dist-info}/entry_points.txt +43 -0
- swift-2.35.0.dist-info/pbr.json +1 -0
- swift/locale/de/LC_MESSAGES/swift.po +0 -1216
- swift/locale/en_GB/LC_MESSAGES/swift.po +0 -1207
- swift/locale/es/LC_MESSAGES/swift.po +0 -1085
- swift/locale/fr/LC_MESSAGES/swift.po +0 -909
- swift/locale/it/LC_MESSAGES/swift.po +0 -894
- swift/locale/ja/LC_MESSAGES/swift.po +0 -965
- swift/locale/ko_KR/LC_MESSAGES/swift.po +0 -964
- swift/locale/pt_BR/LC_MESSAGES/swift.po +0 -881
- swift/locale/ru/LC_MESSAGES/swift.po +0 -891
- swift/locale/tr_TR/LC_MESSAGES/swift.po +0 -832
- swift/locale/zh_CN/LC_MESSAGES/swift.po +0 -833
- swift/locale/zh_TW/LC_MESSAGES/swift.po +0 -838
- swift-2.23.2.data/scripts/swift-account-auditor +0 -23
- swift-2.23.2.data/scripts/swift-account-info +0 -51
- swift-2.23.2.data/scripts/swift-account-reaper +0 -23
- swift-2.23.2.data/scripts/swift-account-replicator +0 -34
- swift-2.23.2.data/scripts/swift-account-server +0 -23
- swift-2.23.2.data/scripts/swift-container-auditor +0 -23
- swift-2.23.2.data/scripts/swift-container-info +0 -51
- swift-2.23.2.data/scripts/swift-container-reconciler +0 -21
- swift-2.23.2.data/scripts/swift-container-replicator +0 -34
- swift-2.23.2.data/scripts/swift-container-sharder +0 -33
- swift-2.23.2.data/scripts/swift-container-sync +0 -23
- swift-2.23.2.data/scripts/swift-container-updater +0 -23
- swift-2.23.2.data/scripts/swift-dispersion-report +0 -24
- swift-2.23.2.data/scripts/swift-form-signature +0 -20
- swift-2.23.2.data/scripts/swift-init +0 -119
- swift-2.23.2.data/scripts/swift-object-auditor +0 -29
- swift-2.23.2.data/scripts/swift-object-expirer +0 -33
- swift-2.23.2.data/scripts/swift-object-info +0 -60
- swift-2.23.2.data/scripts/swift-object-reconstructor +0 -33
- swift-2.23.2.data/scripts/swift-object-relinker +0 -41
- swift-2.23.2.data/scripts/swift-object-replicator +0 -37
- swift-2.23.2.data/scripts/swift-object-server +0 -27
- swift-2.23.2.data/scripts/swift-object-updater +0 -23
- swift-2.23.2.data/scripts/swift-proxy-server +0 -23
- swift-2.23.2.data/scripts/swift-recon +0 -24
- swift-2.23.2.data/scripts/swift-ring-builder +0 -24
- swift-2.23.2.data/scripts/swift-ring-builder-analyzer +0 -22
- swift-2.23.2.data/scripts/swift-ring-composer +0 -22
- swift-2.23.2.dist-info/DESCRIPTION.rst +0 -166
- swift-2.23.2.dist-info/RECORD +0 -220
- swift-2.23.2.dist-info/metadata.json +0 -1
- swift-2.23.2.dist-info/pbr.json +0 -1
- {swift-2.23.2.dist-info → swift-2.35.0.dist-info}/top_level.txt +0 -0
swift/proxy/server.py
CHANGED
@@ -19,7 +19,6 @@ import socket
|
|
19
19
|
|
20
20
|
from collections import defaultdict
|
21
21
|
|
22
|
-
from swift import gettext_ as _
|
23
22
|
from random import shuffle
|
24
23
|
from time import time
|
25
24
|
import functools
|
@@ -29,24 +28,30 @@ from eventlet import Timeout
|
|
29
28
|
|
30
29
|
from swift import __canonical_version__ as swift_version
|
31
30
|
from swift.common import constraints
|
32
|
-
from swift.common.http import is_server_error
|
31
|
+
from swift.common.http import is_server_error, HTTP_INSUFFICIENT_STORAGE
|
33
32
|
from swift.common.storage_policy import POLICIES
|
34
33
|
from swift.common.ring import Ring
|
35
|
-
from swift.common.
|
34
|
+
from swift.common.error_limiter import ErrorLimiter
|
35
|
+
from swift.common.utils import Watchdog, get_logger, \
|
36
36
|
get_remote_client, split_path, config_true_value, generate_trans_id, \
|
37
37
|
affinity_key_function, affinity_locality_predicate, list_from_csv, \
|
38
|
-
|
38
|
+
parse_prefixed_conf, config_auto_int_value, node_to_string, \
|
39
|
+
config_request_node_count_value, config_percent_value, cap_length, \
|
40
|
+
parse_options
|
41
|
+
from swift.common.registry import register_swift_info
|
39
42
|
from swift.common.constraints import check_utf8, valid_api_version
|
40
43
|
from swift.proxy.controllers import AccountController, ContainerController, \
|
41
44
|
ObjectControllerRouter, InfoController
|
42
|
-
from swift.proxy.controllers.base import get_container_info,
|
45
|
+
from swift.proxy.controllers.base import get_container_info, \
|
43
46
|
DEFAULT_RECHECK_CONTAINER_EXISTENCE, DEFAULT_RECHECK_ACCOUNT_EXISTENCE, \
|
44
|
-
DEFAULT_RECHECK_UPDATING_SHARD_RANGES
|
47
|
+
DEFAULT_RECHECK_UPDATING_SHARD_RANGES, DEFAULT_RECHECK_LISTING_SHARD_RANGES
|
45
48
|
from swift.common.swob import HTTPBadRequest, HTTPForbidden, \
|
46
49
|
HTTPMethodNotAllowed, HTTPNotFound, HTTPPreconditionFailed, \
|
47
50
|
HTTPServerError, HTTPException, Request, HTTPServiceUnavailable, \
|
48
51
|
wsgi_to_str
|
49
52
|
from swift.common.exceptions import APIVersionError
|
53
|
+
from swift.common.wsgi import run_wsgi
|
54
|
+
from swift.obj import expirer
|
50
55
|
|
51
56
|
|
52
57
|
# List of entry points for mandatory middlewares.
|
@@ -101,7 +106,8 @@ class ProxyOverrideOptions(object):
|
|
101
106
|
:param conf: the proxy-server config dict.
|
102
107
|
:param override_conf: a dict of overriding configuration options.
|
103
108
|
"""
|
104
|
-
def __init__(self, base_conf, override_conf):
|
109
|
+
def __init__(self, base_conf, override_conf, app):
|
110
|
+
|
105
111
|
def get(key, default):
|
106
112
|
return override_conf.get(key, base_conf.get(key, default))
|
107
113
|
|
@@ -147,14 +153,28 @@ class ProxyOverrideOptions(object):
|
|
147
153
|
get('write_affinity_handoff_delete_count', 'auto'), None
|
148
154
|
)
|
149
155
|
|
156
|
+
self.rebalance_missing_suppression_count = int(get(
|
157
|
+
'rebalance_missing_suppression_count', 1))
|
158
|
+
self.concurrent_gets = config_true_value(get('concurrent_gets', False))
|
159
|
+
self.concurrency_timeout = float(get(
|
160
|
+
'concurrency_timeout', app.conn_timeout))
|
161
|
+
self.concurrent_ec_extra_requests = int(get(
|
162
|
+
'concurrent_ec_extra_requests', 0))
|
163
|
+
|
150
164
|
def __repr__(self):
|
151
|
-
return '%s({}, {%s})' % (
|
152
|
-
|
153
|
-
'
|
154
|
-
|
155
|
-
|
156
|
-
|
157
|
-
|
165
|
+
return '%s({}, {%s}, app)' % (
|
166
|
+
self.__class__.__name__, ', '.join(
|
167
|
+
'%r: %r' % (k, getattr(self, k)) for k in (
|
168
|
+
'sorting_method',
|
169
|
+
'read_affinity',
|
170
|
+
'write_affinity',
|
171
|
+
'write_affinity_node_count',
|
172
|
+
'write_affinity_handoff_delete_count',
|
173
|
+
'rebalance_missing_suppression_count',
|
174
|
+
'concurrent_gets',
|
175
|
+
'concurrency_timeout',
|
176
|
+
'concurrent_ec_extra_requests',
|
177
|
+
)))
|
158
178
|
|
159
179
|
def __eq__(self, other):
|
160
180
|
if not isinstance(other, ProxyOverrideOptions):
|
@@ -164,25 +184,31 @@ class ProxyOverrideOptions(object):
|
|
164
184
|
'read_affinity',
|
165
185
|
'write_affinity',
|
166
186
|
'write_affinity_node_count',
|
167
|
-
'write_affinity_handoff_delete_count'
|
187
|
+
'write_affinity_handoff_delete_count',
|
188
|
+
'rebalance_missing_suppression_count',
|
189
|
+
'concurrent_gets',
|
190
|
+
'concurrency_timeout',
|
191
|
+
'concurrent_ec_extra_requests',
|
192
|
+
))
|
168
193
|
|
169
194
|
|
170
195
|
class Application(object):
|
171
196
|
"""WSGI application for the proxy server."""
|
172
197
|
|
173
|
-
def __init__(self, conf,
|
198
|
+
def __init__(self, conf, logger=None, account_ring=None,
|
174
199
|
container_ring=None):
|
200
|
+
# This is for the sake of tests which instantiate an Application
|
201
|
+
# directly rather than via loadapp().
|
202
|
+
self._pipeline_final_app = self
|
203
|
+
|
175
204
|
if conf is None:
|
176
205
|
conf = {}
|
177
206
|
if logger is None:
|
178
|
-
self.logger = get_logger(conf, log_route='proxy-server'
|
207
|
+
self.logger = get_logger(conf, log_route='proxy-server',
|
208
|
+
statsd_tail_prefix='proxy-server')
|
179
209
|
else:
|
180
210
|
self.logger = logger
|
181
|
-
self.
|
182
|
-
self.sorts_by_timing = any(pc.sorting_method == 'timing'
|
183
|
-
for pc in self._override_options.values())
|
184
|
-
|
185
|
-
self._error_limiting = {}
|
211
|
+
self.backend_user_agent = 'proxy-server %s' % os.getpid()
|
186
212
|
|
187
213
|
swift_dir = conf.get('swift_dir', '/etc/swift')
|
188
214
|
self.swift_dir = swift_dir
|
@@ -190,25 +216,39 @@ class Application(object):
|
|
190
216
|
self.recoverable_node_timeout = float(
|
191
217
|
conf.get('recoverable_node_timeout', self.node_timeout))
|
192
218
|
self.conn_timeout = float(conf.get('conn_timeout', 0.5))
|
193
|
-
self.client_timeout =
|
194
|
-
self.put_queue_depth = int(conf.get('put_queue_depth', 10))
|
219
|
+
self.client_timeout = float(conf.get('client_timeout', 60))
|
195
220
|
self.object_chunk_size = int(conf.get('object_chunk_size', 65536))
|
196
221
|
self.client_chunk_size = int(conf.get('client_chunk_size', 65536))
|
197
222
|
self.trans_id_suffix = conf.get('trans_id_suffix', '')
|
198
223
|
self.post_quorum_timeout = float(conf.get('post_quorum_timeout', 0.5))
|
199
|
-
|
200
|
-
|
201
|
-
|
224
|
+
error_suppression_interval = \
|
225
|
+
float(conf.get('error_suppression_interval', 60))
|
226
|
+
error_suppression_limit = \
|
202
227
|
int(conf.get('error_suppression_limit', 10))
|
228
|
+
self.error_limiter = ErrorLimiter(error_suppression_interval,
|
229
|
+
error_suppression_limit)
|
203
230
|
self.recheck_container_existence = \
|
204
231
|
int(conf.get('recheck_container_existence',
|
205
232
|
DEFAULT_RECHECK_CONTAINER_EXISTENCE))
|
206
233
|
self.recheck_updating_shard_ranges = \
|
207
234
|
int(conf.get('recheck_updating_shard_ranges',
|
208
235
|
DEFAULT_RECHECK_UPDATING_SHARD_RANGES))
|
236
|
+
self.recheck_listing_shard_ranges = \
|
237
|
+
int(conf.get('recheck_listing_shard_ranges',
|
238
|
+
DEFAULT_RECHECK_LISTING_SHARD_RANGES))
|
209
239
|
self.recheck_account_existence = \
|
210
240
|
int(conf.get('recheck_account_existence',
|
211
241
|
DEFAULT_RECHECK_ACCOUNT_EXISTENCE))
|
242
|
+
self.container_existence_skip_cache = config_percent_value(
|
243
|
+
conf.get('container_existence_skip_cache_pct', 0))
|
244
|
+
self.container_updating_shard_ranges_skip_cache = \
|
245
|
+
config_percent_value(conf.get(
|
246
|
+
'container_updating_shard_ranges_skip_cache_pct', 0))
|
247
|
+
self.container_listing_shard_ranges_skip_cache = \
|
248
|
+
config_percent_value(conf.get(
|
249
|
+
'container_listing_shard_ranges_skip_cache_pct', 0))
|
250
|
+
self.account_existence_skip_cache = config_percent_value(
|
251
|
+
conf.get('account_existence_skip_cache_pct', 0))
|
212
252
|
self.allow_account_management = \
|
213
253
|
config_true_value(conf.get('allow_account_management', 'no'))
|
214
254
|
self.container_ring = container_ring or Ring(swift_dir,
|
@@ -219,17 +259,14 @@ class Application(object):
|
|
219
259
|
for policy in POLICIES:
|
220
260
|
policy.load_ring(swift_dir)
|
221
261
|
self.obj_controller_router = ObjectControllerRouter()
|
222
|
-
self.memcache = memcache
|
223
262
|
mimetypes.init(mimetypes.knownfiles +
|
224
263
|
[os.path.join(swift_dir, 'mime.types')])
|
225
264
|
self.account_autocreate = \
|
226
265
|
config_true_value(conf.get('account_autocreate', 'no'))
|
227
|
-
self.auto_create_account_prefix =
|
228
|
-
|
229
|
-
self.
|
230
|
-
|
231
|
-
self.expiring_objects_container_divisor = \
|
232
|
-
int(conf.get('expiring_objects_container_divisor') or 86400)
|
266
|
+
self.auto_create_account_prefix = \
|
267
|
+
constraints.AUTO_CREATE_ACCOUNT_PREFIX
|
268
|
+
self.expirer_config = expirer.ExpirerConfig(
|
269
|
+
conf, container_ring=self.container_ring, logger=self.logger)
|
233
270
|
self.max_containers_per_account = \
|
234
271
|
int(conf.get('max_containers_per_account') or 0)
|
235
272
|
self.max_containers_whitelist = [
|
@@ -250,21 +287,12 @@ class Application(object):
|
|
250
287
|
if a.strip()]
|
251
288
|
self.strict_cors_mode = config_true_value(
|
252
289
|
conf.get('strict_cors_mode', 't'))
|
290
|
+
self.allow_open_expired = config_true_value(
|
291
|
+
conf.get('allow_open_expired', 'f'))
|
253
292
|
self.node_timings = {}
|
254
293
|
self.timing_expiry = int(conf.get('timing_expiry', 300))
|
255
|
-
|
256
|
-
self.
|
257
|
-
self.conn_timeout))
|
258
|
-
value = conf.get('request_node_count', '2 * replicas').lower().split()
|
259
|
-
if len(value) == 1:
|
260
|
-
rnc_value = int(value[0])
|
261
|
-
self.request_node_count = lambda replicas: rnc_value
|
262
|
-
elif len(value) == 3 and value[1] == '*' and value[2] == 'replicas':
|
263
|
-
rnc_value = int(value[0])
|
264
|
-
self.request_node_count = lambda replicas: rnc_value * replicas
|
265
|
-
else:
|
266
|
-
raise ValueError(
|
267
|
-
'Invalid request_node_count value: %r' % ''.join(value))
|
294
|
+
value = conf.get('request_node_count', '2 * replicas')
|
295
|
+
self.request_node_count = config_request_node_count_value(value)
|
268
296
|
# swift_owner_headers are stripped by the account and container
|
269
297
|
# controllers; we should extend header stripping to object controller
|
270
298
|
# when a privileged object header is implemented.
|
@@ -278,6 +306,17 @@ class Application(object):
|
|
278
306
|
self.swift_owner_headers = [
|
279
307
|
name.strip().title()
|
280
308
|
for name in swift_owner_headers.split(',') if name.strip()]
|
309
|
+
|
310
|
+
# When upgrading from liberasurecode<=1.5.0, you may want to continue
|
311
|
+
# writing legacy CRCs until all nodes are upgraded and capabale of
|
312
|
+
# reading fragments with zlib CRCs.
|
313
|
+
# See https://bugs.launchpad.net/liberasurecode/+bug/1886088 for more
|
314
|
+
# information.
|
315
|
+
if 'write_legacy_ec_crc' in conf:
|
316
|
+
os.environ['LIBERASURECODE_WRITE_LEGACY_CRC'] = \
|
317
|
+
'1' if config_true_value(conf['write_legacy_ec_crc']) else '0'
|
318
|
+
# else, assume operators know what they're doing and leave env alone
|
319
|
+
|
281
320
|
# Initialization was successful, so now apply the client chunk size
|
282
321
|
# parameter as the default read / write buffer size for the network
|
283
322
|
# sockets.
|
@@ -296,20 +335,30 @@ class Application(object):
|
|
296
335
|
self.expose_info = config_true_value(
|
297
336
|
conf.get('expose_info', 'yes'))
|
298
337
|
self.disallowed_sections = list_from_csv(
|
299
|
-
conf.get('disallowed_sections', '
|
338
|
+
conf.get('disallowed_sections', ', '.join([
|
339
|
+
'swift.auto_create_account_prefix',
|
340
|
+
'swift.valid_api_versions',
|
341
|
+
])))
|
300
342
|
self.admin_key = conf.get('admin_key', None)
|
343
|
+
self._override_options = self._load_per_policy_config(conf)
|
344
|
+
self.sorts_by_timing = any(pc.sorting_method == 'timing'
|
345
|
+
for pc in self._override_options.values())
|
346
|
+
|
301
347
|
register_swift_info(
|
302
348
|
version=swift_version,
|
303
349
|
strict_cors_mode=self.strict_cors_mode,
|
304
350
|
policies=POLICIES.get_policy_info(),
|
305
351
|
allow_account_management=self.allow_account_management,
|
306
352
|
account_autocreate=self.account_autocreate,
|
353
|
+
allow_open_expired=self.allow_open_expired,
|
307
354
|
**constraints.EFFECTIVE_CONSTRAINTS)
|
355
|
+
self.watchdog = Watchdog()
|
356
|
+
self.watchdog.spawn()
|
308
357
|
|
309
358
|
def _make_policy_override(self, policy, conf, override_conf):
|
310
359
|
label_for_policy = _label_for_policy(policy)
|
311
360
|
try:
|
312
|
-
override = ProxyOverrideOptions(conf, override_conf)
|
361
|
+
override = ProxyOverrideOptions(conf, override_conf, self)
|
313
362
|
self.logger.debug("Loaded override config for %s: %r" %
|
314
363
|
(label_for_policy, override))
|
315
364
|
return override
|
@@ -367,8 +416,8 @@ class Application(object):
|
|
367
416
|
else POLICIES.get_by_index(policy_idx))
|
368
417
|
if options.read_affinity and options.sorting_method != 'affinity':
|
369
418
|
self.logger.warning(
|
370
|
-
|
371
|
-
|
419
|
+
"sorting_method is set to '%(method)s', not 'affinity'; "
|
420
|
+
"%(label)s read_affinity setting will have no effect.",
|
372
421
|
{'label': _label_for_policy(policy),
|
373
422
|
'method': options.sorting_method})
|
374
423
|
|
@@ -440,8 +489,6 @@ class Application(object):
|
|
440
489
|
:param start_response: WSGI callable
|
441
490
|
"""
|
442
491
|
try:
|
443
|
-
if self.memcache is None:
|
444
|
-
self.memcache = cache_from_env(env, True)
|
445
492
|
req = self.update_request(Request(env))
|
446
493
|
return self.handle_request(req)(env, start_response)
|
447
494
|
except UnicodeError:
|
@@ -474,14 +521,14 @@ class Application(object):
|
|
474
521
|
:param req: swob.Request object
|
475
522
|
"""
|
476
523
|
try:
|
477
|
-
self.logger.set_statsd_prefix('proxy-server')
|
478
524
|
if req.content_length and req.content_length < 0:
|
479
525
|
self.logger.increment('errors')
|
480
526
|
return HTTPBadRequest(request=req,
|
481
527
|
body='Invalid Content-Length')
|
482
528
|
|
483
529
|
try:
|
484
|
-
if not check_utf8(wsgi_to_str(req.path_info)
|
530
|
+
if not check_utf8(wsgi_to_str(req.path_info),
|
531
|
+
internal=req.allow_reserved_names):
|
485
532
|
self.logger.increment('errors')
|
486
533
|
return HTTPPreconditionFailed(
|
487
534
|
request=req, body='Invalid UTF8 or contains NULL')
|
@@ -505,8 +552,6 @@ class Application(object):
|
|
505
552
|
req.host.split(':')[0] in self.deny_host_headers:
|
506
553
|
return HTTPForbidden(request=req, body='Invalid host header')
|
507
554
|
|
508
|
-
self.logger.set_statsd_prefix('proxy-server.' +
|
509
|
-
controller.server_type.lower())
|
510
555
|
controller = controller(self, **path_parts)
|
511
556
|
if 'swift.trans_id' not in req.environ:
|
512
557
|
# if this wasn't set by an earlier middleware, set it now
|
@@ -561,7 +606,7 @@ class Application(object):
|
|
561
606
|
except HTTPException as error_response:
|
562
607
|
return error_response
|
563
608
|
except (Exception, Timeout):
|
564
|
-
self.logger.exception(
|
609
|
+
self.logger.exception('ERROR Unhandled exception in request')
|
565
610
|
return HTTPServerError(request=req)
|
566
611
|
|
567
612
|
def sort_nodes(self, nodes, policy=None):
|
@@ -597,9 +642,6 @@ class Application(object):
|
|
597
642
|
timing = round(timing, 3) # sort timings to the millisecond
|
598
643
|
self.node_timings[node['ip']] = (timing, now + self.timing_expiry)
|
599
644
|
|
600
|
-
def _error_limit_node_key(self, node):
|
601
|
-
return "{ip}:{port}/{device}".format(**node)
|
602
|
-
|
603
645
|
def error_limited(self, node):
|
604
646
|
"""
|
605
647
|
Check if the node is currently error limited.
|
@@ -607,20 +649,11 @@ class Application(object):
|
|
607
649
|
:param node: dictionary of node to check
|
608
650
|
:returns: True if error limited, False otherwise
|
609
651
|
"""
|
610
|
-
|
611
|
-
node_key = self._error_limit_node_key(node)
|
612
|
-
error_stats = self._error_limiting.get(node_key)
|
613
|
-
|
614
|
-
if error_stats is None or 'errors' not in error_stats:
|
615
|
-
return False
|
616
|
-
if 'last_error' in error_stats and error_stats['last_error'] < \
|
617
|
-
now - self.error_suppression_interval:
|
618
|
-
self._error_limiting.pop(node_key, None)
|
619
|
-
return False
|
620
|
-
limited = error_stats['errors'] > self.error_suppression_limit
|
652
|
+
limited = self.error_limiter.is_limited(node)
|
621
653
|
if limited:
|
654
|
+
self.logger.increment('error_limiter.is_limited')
|
622
655
|
self.logger.debug(
|
623
|
-
|
656
|
+
'Node is error limited: %s', node_to_string(node))
|
624
657
|
return limited
|
625
658
|
|
626
659
|
def error_limit(self, node, msg):
|
@@ -628,24 +661,30 @@ class Application(object):
|
|
628
661
|
Mark a node as error limited. This immediately pretends the
|
629
662
|
node received enough errors to trigger error suppression. Use
|
630
663
|
this for errors like Insufficient Storage. For other errors
|
631
|
-
use :func:`
|
664
|
+
use :func:`increment`.
|
632
665
|
|
633
666
|
:param node: dictionary of node to error limit
|
634
667
|
:param msg: error message
|
635
668
|
"""
|
636
|
-
|
637
|
-
|
638
|
-
|
639
|
-
|
640
|
-
|
641
|
-
|
642
|
-
|
643
|
-
|
644
|
-
|
645
|
-
|
646
|
-
|
647
|
-
|
648
|
-
|
669
|
+
self.error_limiter.limit(node)
|
670
|
+
self.logger.increment('error_limiter.forced_limit')
|
671
|
+
self.logger.error(
|
672
|
+
'Node will be error limited for %.2fs: %s, error: %s',
|
673
|
+
self.error_limiter.suppression_interval, node_to_string(node),
|
674
|
+
msg)
|
675
|
+
|
676
|
+
def _error_increment(self, node):
|
677
|
+
"""
|
678
|
+
Call increment() on error limiter once, emit metrics and log if error
|
679
|
+
suppression will be triggered.
|
680
|
+
|
681
|
+
:param node: dictionary of node to handle errors for
|
682
|
+
"""
|
683
|
+
if self.error_limiter.increment(node):
|
684
|
+
self.logger.increment('error_limiter.incremented_limit')
|
685
|
+
self.logger.error(
|
686
|
+
'Node will be error limited for %.2fs: %s',
|
687
|
+
self.error_limiter.suppression_interval, node_to_string(node))
|
649
688
|
|
650
689
|
def error_occurred(self, node, msg):
|
651
690
|
"""
|
@@ -654,16 +693,49 @@ class Application(object):
|
|
654
693
|
:param node: dictionary of node to handle errors for
|
655
694
|
:param msg: error message
|
656
695
|
"""
|
657
|
-
self._incr_node_errors(node)
|
658
696
|
if isinstance(msg, bytes):
|
659
697
|
msg = msg.decode('utf-8')
|
660
|
-
self.logger.error(
|
661
|
-
{'msg': msg, '
|
662
|
-
|
698
|
+
self.logger.error('%(msg)s %(node)s',
|
699
|
+
{'msg': msg, 'node': node_to_string(node)})
|
700
|
+
self._error_increment(node)
|
663
701
|
|
664
|
-
def
|
665
|
-
|
666
|
-
|
702
|
+
def check_response(self, node, server_type, response, method, path,
|
703
|
+
body=None):
|
704
|
+
"""
|
705
|
+
Check response for error status codes and update error limiters as
|
706
|
+
required.
|
707
|
+
|
708
|
+
:param node: a dict describing a node
|
709
|
+
:param server_type: the type of server from which the response was
|
710
|
+
received (e.g. 'Object').
|
711
|
+
:param response: an instance of HTTPResponse.
|
712
|
+
:param method: the request method.
|
713
|
+
:param path: the request path.
|
714
|
+
:param body: an optional response body. If given, up to 1024 of the
|
715
|
+
start of the body will be included in any log message.
|
716
|
+
:return True: if the response status code is less than 500, False
|
717
|
+
otherwise.
|
718
|
+
"""
|
719
|
+
ok = False
|
720
|
+
if response.status == HTTP_INSUFFICIENT_STORAGE:
|
721
|
+
self.error_limit(node, 'ERROR Insufficient Storage')
|
722
|
+
elif is_server_error(response.status):
|
723
|
+
values = {'status': response.status,
|
724
|
+
'method': method,
|
725
|
+
'path': path,
|
726
|
+
'type': server_type}
|
727
|
+
if body is None:
|
728
|
+
fmt = 'ERROR %(status)d Trying to %(method)s ' \
|
729
|
+
'%(path)s From %(type)s Server'
|
730
|
+
else:
|
731
|
+
fmt = 'ERROR %(status)d %(body)s Trying to %(method)s ' \
|
732
|
+
'%(path)s From %(type)s Server'
|
733
|
+
values['body'] = cap_length(body, 1024)
|
734
|
+
self.error_occurred(node, fmt % values)
|
735
|
+
else:
|
736
|
+
ok = True
|
737
|
+
|
738
|
+
return ok
|
667
739
|
|
668
740
|
def exception_occurred(self, node, typ, additional_info,
|
669
741
|
**kwargs):
|
@@ -674,7 +746,6 @@ class Application(object):
|
|
674
746
|
:param typ: server type
|
675
747
|
:param additional_info: additional information to log
|
676
748
|
"""
|
677
|
-
self._incr_node_errors(node)
|
678
749
|
if 'level' in kwargs:
|
679
750
|
log = functools.partial(self.logger.log, kwargs.pop('level'))
|
680
751
|
if 'exc_info' not in kwargs:
|
@@ -683,12 +754,12 @@ class Application(object):
|
|
683
754
|
log = self.logger.exception
|
684
755
|
if isinstance(additional_info, bytes):
|
685
756
|
additional_info = additional_info.decode('utf-8')
|
686
|
-
log(
|
687
|
-
|
688
|
-
{'type': typ, '
|
689
|
-
'port': node['port'], 'device': node['device'],
|
757
|
+
log('ERROR with %(type)s server %(node)s'
|
758
|
+
' re: %(info)s',
|
759
|
+
{'type': typ, 'node': node_to_string(node),
|
690
760
|
'info': additional_info},
|
691
761
|
**kwargs)
|
762
|
+
self._error_increment(node)
|
692
763
|
|
693
764
|
def modify_wsgi_pipeline(self, pipe):
|
694
765
|
"""
|
@@ -709,18 +780,18 @@ class Application(object):
|
|
709
780
|
except ValueError: # not in pipeline; ignore it
|
710
781
|
pass
|
711
782
|
self.logger.info(
|
712
|
-
|
713
|
-
|
783
|
+
'Adding required filter %(filter_name)s to pipeline at '
|
784
|
+
'position %(insert_at)d',
|
714
785
|
{'filter_name': filter_name, 'insert_at': insert_at})
|
715
786
|
ctx = pipe.create_filter(filter_name)
|
716
787
|
pipe.insert_filter(ctx, index=insert_at)
|
717
788
|
pipeline_was_modified = True
|
718
789
|
|
719
790
|
if pipeline_was_modified:
|
720
|
-
self.logger.info(
|
721
|
-
|
791
|
+
self.logger.info("Pipeline was modified. "
|
792
|
+
"New pipeline is \"%s\".", pipe)
|
722
793
|
else:
|
723
|
-
self.logger.debug(
|
794
|
+
self.logger.debug("Pipeline is \"%s\"", pipe)
|
724
795
|
|
725
796
|
|
726
797
|
def parse_per_policy_config(conf):
|
@@ -733,15 +804,8 @@ def parse_per_policy_config(conf):
|
|
733
804
|
:return: a dict mapping policy reference -> dict of policy options
|
734
805
|
:raises ValueError: if a policy config section has an invalid name
|
735
806
|
"""
|
736
|
-
policy_config = {}
|
737
|
-
all_conf = readconf(conf['__file__'])
|
738
807
|
policy_section_prefix = conf['__name__'] + ':policy:'
|
739
|
-
|
740
|
-
if not section.startswith(policy_section_prefix):
|
741
|
-
continue
|
742
|
-
policy_ref = section[len(policy_section_prefix):]
|
743
|
-
policy_config[policy_ref] = options
|
744
|
-
return policy_config
|
808
|
+
return parse_prefixed_conf(conf['__file__'], policy_section_prefix)
|
745
809
|
|
746
810
|
|
747
811
|
def app_factory(global_conf, **local_conf):
|
@@ -755,3 +819,12 @@ def app_factory(global_conf, **local_conf):
|
|
755
819
|
app = Application(conf)
|
756
820
|
app.check_config()
|
757
821
|
return app
|
822
|
+
|
823
|
+
|
824
|
+
def main():
|
825
|
+
conf_file, options = parse_options(test_config=True)
|
826
|
+
sys.exit(run_wsgi(conf_file, 'proxy-server', **options))
|
827
|
+
|
828
|
+
|
829
|
+
if __name__ == '__main__':
|
830
|
+
main()
|