swift 2.31.1__py2.py3-none-any.whl → 2.32.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.
Files changed (104) hide show
  1. swift/cli/info.py +9 -2
  2. swift/cli/ringbuilder.py +5 -1
  3. swift/common/container_sync_realms.py +6 -7
  4. swift/common/daemon.py +7 -3
  5. swift/common/db.py +22 -7
  6. swift/common/db_replicator.py +19 -20
  7. swift/common/direct_client.py +63 -14
  8. swift/common/internal_client.py +24 -3
  9. swift/common/manager.py +43 -44
  10. swift/common/memcached.py +168 -74
  11. swift/common/middleware/__init__.py +4 -0
  12. swift/common/middleware/account_quotas.py +98 -40
  13. swift/common/middleware/backend_ratelimit.py +6 -4
  14. swift/common/middleware/crossdomain.py +21 -8
  15. swift/common/middleware/listing_formats.py +26 -38
  16. swift/common/middleware/proxy_logging.py +12 -9
  17. swift/common/middleware/s3api/controllers/bucket.py +8 -2
  18. swift/common/middleware/s3api/s3api.py +9 -4
  19. swift/common/middleware/s3api/s3request.py +32 -24
  20. swift/common/middleware/s3api/s3response.py +10 -1
  21. swift/common/middleware/tempauth.py +9 -10
  22. swift/common/middleware/versioned_writes/__init__.py +0 -3
  23. swift/common/middleware/versioned_writes/object_versioning.py +22 -5
  24. swift/common/middleware/x_profile/html_viewer.py +1 -1
  25. swift/common/middleware/xprofile.py +5 -0
  26. swift/common/request_helpers.py +1 -2
  27. swift/common/ring/ring.py +22 -19
  28. swift/common/swob.py +2 -1
  29. swift/common/{utils.py → utils/__init__.py} +610 -1146
  30. swift/common/utils/ipaddrs.py +256 -0
  31. swift/common/utils/libc.py +345 -0
  32. swift/common/utils/timestamp.py +399 -0
  33. swift/common/wsgi.py +70 -39
  34. swift/container/backend.py +106 -38
  35. swift/container/server.py +11 -2
  36. swift/container/sharder.py +34 -15
  37. swift/locale/de/LC_MESSAGES/swift.po +1 -320
  38. swift/locale/en_GB/LC_MESSAGES/swift.po +1 -347
  39. swift/locale/es/LC_MESSAGES/swift.po +1 -279
  40. swift/locale/fr/LC_MESSAGES/swift.po +1 -209
  41. swift/locale/it/LC_MESSAGES/swift.po +1 -207
  42. swift/locale/ja/LC_MESSAGES/swift.po +2 -278
  43. swift/locale/ko_KR/LC_MESSAGES/swift.po +3 -303
  44. swift/locale/pt_BR/LC_MESSAGES/swift.po +1 -204
  45. swift/locale/ru/LC_MESSAGES/swift.po +1 -203
  46. swift/locale/tr_TR/LC_MESSAGES/swift.po +1 -192
  47. swift/locale/zh_CN/LC_MESSAGES/swift.po +1 -192
  48. swift/locale/zh_TW/LC_MESSAGES/swift.po +1 -193
  49. swift/obj/diskfile.py +19 -6
  50. swift/obj/server.py +20 -6
  51. swift/obj/ssync_receiver.py +19 -9
  52. swift/obj/ssync_sender.py +10 -10
  53. swift/proxy/controllers/account.py +7 -7
  54. swift/proxy/controllers/base.py +374 -366
  55. swift/proxy/controllers/container.py +112 -53
  56. swift/proxy/controllers/obj.py +254 -390
  57. swift/proxy/server.py +3 -8
  58. {swift-2.31.1.data → swift-2.32.1.data}/scripts/swift-account-server +1 -1
  59. {swift-2.31.1.data → swift-2.32.1.data}/scripts/swift-container-server +1 -1
  60. {swift-2.31.1.data → swift-2.32.1.data}/scripts/swift-drive-audit +45 -14
  61. {swift-2.31.1.data → swift-2.32.1.data}/scripts/swift-object-server +1 -1
  62. {swift-2.31.1.data → swift-2.32.1.data}/scripts/swift-proxy-server +1 -1
  63. {swift-2.31.1.dist-info → swift-2.32.1.dist-info}/AUTHORS +4 -0
  64. {swift-2.31.1.dist-info → swift-2.32.1.dist-info}/METADATA +32 -35
  65. {swift-2.31.1.dist-info → swift-2.32.1.dist-info}/RECORD +103 -100
  66. {swift-2.31.1.dist-info → swift-2.32.1.dist-info}/WHEEL +1 -1
  67. {swift-2.31.1.dist-info → swift-2.32.1.dist-info}/entry_points.txt +0 -1
  68. swift-2.32.1.dist-info/pbr.json +1 -0
  69. swift-2.31.1.dist-info/pbr.json +0 -1
  70. {swift-2.31.1.data → swift-2.32.1.data}/scripts/swift-account-audit +0 -0
  71. {swift-2.31.1.data → swift-2.32.1.data}/scripts/swift-account-auditor +0 -0
  72. {swift-2.31.1.data → swift-2.32.1.data}/scripts/swift-account-info +0 -0
  73. {swift-2.31.1.data → swift-2.32.1.data}/scripts/swift-account-reaper +0 -0
  74. {swift-2.31.1.data → swift-2.32.1.data}/scripts/swift-account-replicator +0 -0
  75. {swift-2.31.1.data → swift-2.32.1.data}/scripts/swift-config +0 -0
  76. {swift-2.31.1.data → swift-2.32.1.data}/scripts/swift-container-auditor +0 -0
  77. {swift-2.31.1.data → swift-2.32.1.data}/scripts/swift-container-info +0 -0
  78. {swift-2.31.1.data → swift-2.32.1.data}/scripts/swift-container-reconciler +0 -0
  79. {swift-2.31.1.data → swift-2.32.1.data}/scripts/swift-container-replicator +0 -0
  80. {swift-2.31.1.data → swift-2.32.1.data}/scripts/swift-container-sharder +0 -0
  81. {swift-2.31.1.data → swift-2.32.1.data}/scripts/swift-container-sync +0 -0
  82. {swift-2.31.1.data → swift-2.32.1.data}/scripts/swift-container-updater +0 -0
  83. {swift-2.31.1.data → swift-2.32.1.data}/scripts/swift-dispersion-populate +0 -0
  84. {swift-2.31.1.data → swift-2.32.1.data}/scripts/swift-dispersion-report +0 -0
  85. {swift-2.31.1.data → swift-2.32.1.data}/scripts/swift-form-signature +0 -0
  86. {swift-2.31.1.data → swift-2.32.1.data}/scripts/swift-get-nodes +0 -0
  87. {swift-2.31.1.data → swift-2.32.1.data}/scripts/swift-init +0 -0
  88. {swift-2.31.1.data → swift-2.32.1.data}/scripts/swift-object-auditor +0 -0
  89. {swift-2.31.1.data → swift-2.32.1.data}/scripts/swift-object-expirer +0 -0
  90. {swift-2.31.1.data → swift-2.32.1.data}/scripts/swift-object-info +0 -0
  91. {swift-2.31.1.data → swift-2.32.1.data}/scripts/swift-object-reconstructor +0 -0
  92. {swift-2.31.1.data → swift-2.32.1.data}/scripts/swift-object-relinker +0 -0
  93. {swift-2.31.1.data → swift-2.32.1.data}/scripts/swift-object-replicator +0 -0
  94. {swift-2.31.1.data → swift-2.32.1.data}/scripts/swift-object-updater +0 -0
  95. {swift-2.31.1.data → swift-2.32.1.data}/scripts/swift-oldies +0 -0
  96. {swift-2.31.1.data → swift-2.32.1.data}/scripts/swift-orphans +0 -0
  97. {swift-2.31.1.data → swift-2.32.1.data}/scripts/swift-recon +0 -0
  98. {swift-2.31.1.data → swift-2.32.1.data}/scripts/swift-recon-cron +0 -0
  99. {swift-2.31.1.data → swift-2.32.1.data}/scripts/swift-reconciler-enqueue +0 -0
  100. {swift-2.31.1.data → swift-2.32.1.data}/scripts/swift-ring-builder +0 -0
  101. {swift-2.31.1.data → swift-2.32.1.data}/scripts/swift-ring-builder-analyzer +0 -0
  102. {swift-2.31.1.data → swift-2.32.1.data}/scripts/swift-ring-composer +0 -0
  103. {swift-2.31.1.dist-info → swift-2.32.1.dist-info}/LICENSE +0 -0
  104. {swift-2.31.1.dist-info → swift-2.32.1.dist-info}/top_level.txt +0 -0
@@ -21,13 +21,14 @@ from six.moves.urllib.parse import unquote
21
21
 
22
22
  from swift.common.memcached import MemcacheConnectionError
23
23
  from swift.common.utils import public, private, csv_append, Timestamp, \
24
- config_true_value, ShardRange, cache_from_env, filter_shard_ranges
24
+ config_true_value, ShardRange, cache_from_env, filter_namespaces, \
25
+ NamespaceBoundList
25
26
  from swift.common.constraints import check_metadata, CONTAINER_LISTING_LIMIT
26
27
  from swift.common.http import HTTP_ACCEPTED, is_success
27
28
  from swift.common.request_helpers import get_sys_meta_prefix, get_param, \
28
29
  constrain_req_limit, validate_container_params
29
- from swift.proxy.controllers.base import Controller, delay_denial, \
30
- cors_validation, set_info_cache, clear_info_cache, _get_info_from_caches, \
30
+ from swift.proxy.controllers.base import Controller, delay_denial, NodeIter, \
31
+ cors_validation, set_info_cache, clear_info_cache, get_container_info, \
31
32
  record_cache_op_metrics, get_cache_key, headers_from_container_info, \
32
33
  update_headers
33
34
  from swift.common.storage_policy import POLICIES
@@ -91,9 +92,9 @@ class ContainerController(Controller):
91
92
  return None
92
93
 
93
94
  def _clear_container_info_cache(self, req):
94
- clear_info_cache(self.app, req.environ,
95
+ clear_info_cache(req.environ,
95
96
  self.account_name, self.container_name)
96
- clear_info_cache(self.app, req.environ,
97
+ clear_info_cache(req.environ,
97
98
  self.account_name, self.container_name, 'listing')
98
99
  # TODO: should we also purge updating shards from cache?
99
100
 
@@ -102,32 +103,49 @@ class ContainerController(Controller):
102
103
  self.account_name, self.container_name)
103
104
  concurrency = self.app.container_ring.replica_count \
104
105
  if self.app.get_policy_options(None).concurrent_gets else 1
105
- node_iter = self.app.iter_nodes(self.app.container_ring, part,
106
- self.logger, req)
106
+ node_iter = NodeIter(self.app, self.app.container_ring, part,
107
+ self.logger, req)
107
108
  resp = self.GETorHEAD_base(
108
109
  req, 'Container', node_iter, part,
109
110
  req.swift_entity_path, concurrency)
110
111
  return resp
111
112
 
112
- def _make_shard_ranges_response_body(self, req, shard_range_dicts):
113
- # filter shard ranges according to request constraints and return a
114
- # serialised list of shard ranges
113
+ def _make_namespaces_response_body(self, req, ns_bound_list):
114
+ """
115
+ Filter namespaces according to request constraints and return a
116
+ serialised list of namespaces.
117
+
118
+ :param req: the request object.
119
+ :param ns_bound_list: an instance of
120
+ :class:`~swift.common.utils.NamespaceBoundList`.
121
+ :return: a serialised list of namespaces.
122
+ """
115
123
  marker = get_param(req, 'marker', '')
116
124
  end_marker = get_param(req, 'end_marker')
117
125
  includes = get_param(req, 'includes')
118
126
  reverse = config_true_value(get_param(req, 'reverse'))
119
127
  if reverse:
120
128
  marker, end_marker = end_marker, marker
121
- shard_ranges = [
122
- ShardRange.from_dict(shard_range)
123
- for shard_range in shard_range_dicts]
124
- shard_ranges = filter_shard_ranges(shard_ranges, includes, marker,
125
- end_marker)
129
+ namespaces = ns_bound_list.get_namespaces()
130
+ namespaces = filter_namespaces(
131
+ namespaces, includes, marker, end_marker)
126
132
  if reverse:
127
- shard_ranges.reverse()
128
- return json.dumps([dict(sr) for sr in shard_ranges]).encode('ascii')
133
+ namespaces.reverse()
134
+ return json.dumps([dict(ns) for ns in namespaces]).encode('ascii')
129
135
 
130
136
  def _get_shard_ranges_from_cache(self, req, headers):
137
+ """
138
+ Try to fetch shard namespace data from cache and, if successful, return
139
+ a response. Also return the cache state.
140
+
141
+ The response body will be a list of dicts each of which describes
142
+ a Namespace (i.e. includes the keys ``lower``, ``upper`` and ``name``).
143
+
144
+ :param req: an instance of ``swob.Request``.
145
+ :param headers: Headers to be sent with request.
146
+ :return: a tuple comprising (an instance of ``swob.Response``or
147
+ ``None`` if no namespaces were found in cache, the cache state).
148
+ """
131
149
  infocache = req.environ.setdefault('swift.infocache', {})
132
150
  memcache = cache_from_env(req.environ, True)
133
151
  cache_key = get_cache_key(self.account_name,
@@ -135,11 +153,10 @@ class ContainerController(Controller):
135
153
  shard='listing')
136
154
 
137
155
  resp_body = None
138
- cached_range_dicts = infocache.get(cache_key)
139
- if cached_range_dicts:
156
+ ns_bound_list = infocache.get(cache_key)
157
+ if ns_bound_list:
140
158
  cache_state = 'infocache_hit'
141
- resp_body = self._make_shard_ranges_response_body(
142
- req, cached_range_dicts)
159
+ resp_body = self._make_namespaces_response_body(req, ns_bound_list)
143
160
  elif memcache:
144
161
  skip_chance = \
145
162
  self.app.container_listing_shard_ranges_skip_cache
@@ -147,12 +164,20 @@ class ContainerController(Controller):
147
164
  cache_state = 'skip'
148
165
  else:
149
166
  try:
150
- cached_range_dicts = memcache.get(
167
+ cached_namespaces = memcache.get(
151
168
  cache_key, raise_on_error=True)
152
- if cached_range_dicts:
169
+ if cached_namespaces:
153
170
  cache_state = 'hit'
154
- resp_body = self._make_shard_ranges_response_body(
155
- req, cached_range_dicts)
171
+ if six.PY2:
172
+ # json.loads() in memcache.get will convert json
173
+ # 'string' to 'unicode' with python2, here we cast
174
+ # 'unicode' back to 'str'
175
+ cached_namespaces = [
176
+ [lower.encode('utf-8'), name.encode('utf-8')]
177
+ for lower, name in cached_namespaces]
178
+ ns_bound_list = NamespaceBoundList(cached_namespaces)
179
+ resp_body = self._make_namespaces_response_body(
180
+ req, ns_bound_list)
156
181
  else:
157
182
  cache_state = 'miss'
158
183
  except MemcacheConnectionError:
@@ -162,9 +187,9 @@ class ContainerController(Controller):
162
187
  resp = None
163
188
  else:
164
189
  # shard ranges can be returned from cache
165
- infocache[cache_key] = tuple(cached_range_dicts)
190
+ infocache[cache_key] = ns_bound_list
166
191
  self.logger.debug('Found %d shards in cache for %s',
167
- len(cached_range_dicts), req.path_qs)
192
+ len(ns_bound_list.bounds), req.path_qs)
168
193
  headers.update({'x-backend-record-type': 'shard',
169
194
  'x-backend-cached-results': 'true'})
170
195
  # mimic GetOrHeadHandler.get_working_response...
@@ -180,36 +205,62 @@ class ContainerController(Controller):
180
205
  return resp, cache_state
181
206
 
182
207
  def _store_shard_ranges_in_cache(self, req, resp):
183
- # parse shard ranges returned from backend, store them in infocache and
184
- # memcache, and return a list of dicts
185
- cache_key = get_cache_key(self.account_name, self.container_name,
186
- shard='listing')
208
+ """
209
+ Parse shard ranges returned from backend, store them in both infocache
210
+ and memcache.
211
+
212
+ :param req: the request object.
213
+ :param resp: the response object for the shard range listing.
214
+ :return: an instance of
215
+ :class:`~swift.common.utils.NamespaceBoundList`.
216
+ """
217
+ # Note: Any gaps in the response's shard ranges will be 'lost' as a
218
+ # result of compacting the list of shard ranges to a
219
+ # NamespaceBoundList. That is ok. When the cached NamespaceBoundList is
220
+ # transformed back to shard range Namespaces to perform a listing, the
221
+ # Namespace before each gap will have expanded to include the gap,
222
+ # which means that the backend GET to that shard will have an
223
+ # end_marker beyond that shard's upper bound, and equal to the next
224
+ # available shard's lower. At worst, some misplaced objects, in the gap
225
+ # above the shard's upper, may be included in the shard's response.
187
226
  data = self._parse_listing_response(req, resp)
188
227
  backend_shard_ranges = self._parse_shard_ranges(req, data, resp)
189
228
  if backend_shard_ranges is None:
190
229
  return None
191
230
 
192
- cached_range_dicts = [dict(sr) for sr in backend_shard_ranges]
231
+ ns_bound_list = NamespaceBoundList.parse(backend_shard_ranges)
193
232
  if resp.headers.get('x-backend-sharding-state') == 'sharded':
194
233
  # cache in infocache even if no shard ranges returned; this
195
234
  # is unexpected but use that result for this request
196
235
  infocache = req.environ.setdefault('swift.infocache', {})
197
- infocache[cache_key] = tuple(cached_range_dicts)
236
+ cache_key = get_cache_key(
237
+ self.account_name, self.container_name, shard='listing')
238
+ infocache[cache_key] = ns_bound_list
198
239
  memcache = cache_from_env(req.environ, True)
199
- if memcache and cached_range_dicts:
240
+ if memcache and ns_bound_list:
200
241
  # cache in memcache only if shard ranges as expected
201
- self.logger.debug('Caching %d shards for %s',
202
- len(cached_range_dicts), req.path_qs)
203
- memcache.set(cache_key, cached_range_dicts,
242
+ self.logger.info('Caching listing shards for %s (%d shards)',
243
+ cache_key, len(ns_bound_list.bounds))
244
+ memcache.set(cache_key, ns_bound_list.bounds,
204
245
  time=self.app.recheck_listing_shard_ranges)
205
- return cached_range_dicts
246
+ return ns_bound_list
206
247
 
207
248
  def _get_shard_ranges_from_backend(self, req):
208
- # Make a backend request for shard ranges. The response is cached and
209
- # then returned as a list of dicts.
249
+ """
250
+ Make a backend request for shard ranges and return a response.
251
+
252
+ The response body will be a list of dicts each of which describes
253
+ a Namespace (i.e. includes the keys ``lower``, ``upper`` and ``name``).
254
+ If the response headers indicate that the response body contains a
255
+ complete list of shard ranges for a sharded container then the response
256
+ body will be transformed to a ``NamespaceBoundsList`` and cached.
257
+
258
+ :param req: an instance of ``swob.Request``.
259
+ :return: an instance of ``swob.Response``.
260
+ """
210
261
  # Note: We instruct the backend server to ignore name constraints in
211
262
  # request params if returning shard ranges so that the response can
212
- # potentially be cached. Only do this if the container state is
263
+ # potentially be cached, but we only cache it if the container state is
213
264
  # 'sharded'. We don't attempt to cache shard ranges for a 'sharding'
214
265
  # container as they may include the container itself as a 'gap filler'
215
266
  # for shard ranges that have not yet cleaved; listings from 'gap
@@ -232,10 +283,10 @@ class ContainerController(Controller):
232
283
  if (resp_record_type == 'shard' and
233
284
  sharding_state == 'sharded' and
234
285
  complete_listing):
235
- cached_range_dicts = self._store_shard_ranges_in_cache(req, resp)
236
- if cached_range_dicts:
237
- resp.body = self._make_shard_ranges_response_body(
238
- req, cached_range_dicts)
286
+ ns_bound_list = self._store_shard_ranges_in_cache(req, resp)
287
+ if ns_bound_list:
288
+ resp.body = self._make_namespaces_response_body(
289
+ req, ns_bound_list)
239
290
  return resp
240
291
 
241
292
  def _record_shard_listing_cache_metrics(
@@ -334,18 +385,19 @@ class ContainerController(Controller):
334
385
  params['states'] = 'listing'
335
386
  req.params = params
336
387
 
337
- memcache = cache_from_env(req.environ, True)
338
388
  if (req.method == 'GET'
339
389
  and get_param(req, 'states') == 'listing'
340
390
  and record_type != 'object'):
341
391
  may_get_listing_shards = True
342
- info = _get_info_from_caches(self.app, req.environ,
343
- self.account_name,
344
- self.container_name)
392
+ # Only lookup container info from cache and skip the backend HEAD,
393
+ # since we are going to GET the backend container anyway.
394
+ info = get_container_info(
395
+ req.environ, self.app, swift_source=None, cache_only=True)
345
396
  else:
346
397
  info = None
347
398
  may_get_listing_shards = False
348
399
 
400
+ memcache = cache_from_env(req.environ, True)
349
401
  sr_cache_state = None
350
402
  if (may_get_listing_shards and
351
403
  self.app.recheck_listing_shard_ranges > 0
@@ -379,10 +431,10 @@ class ContainerController(Controller):
379
431
  # node and got up-to-date information for the container.
380
432
  resp.headers['X-Backend-Recheck-Container-Existence'] = str(
381
433
  self.app.recheck_container_existence)
382
- set_info_cache(self.app, req.environ, self.account_name,
434
+ set_info_cache(req.environ, self.account_name,
383
435
  self.container_name, resp)
384
436
  if 'swift.authorize' in req.environ:
385
- req.acl = resp.headers.get('x-container-read')
437
+ req.acl = wsgi_to_str(resp.headers.get('x-container-read'))
386
438
  aresp = req.environ['swift.authorize'](req)
387
439
  if aresp:
388
440
  # Don't cache this. It doesn't reflect the state of the
@@ -424,8 +476,15 @@ class ContainerController(Controller):
424
476
  # 'X-Backend-Storage-Policy-Index'.
425
477
  req.headers[policy_key] = resp.headers[policy_key]
426
478
  shard_listing_history.append((self.account_name, self.container_name))
427
- shard_ranges = [ShardRange.from_dict(data)
428
- for data in json.loads(resp.body)]
479
+ # Note: when the response body has been synthesised from cached data,
480
+ # each item in the list only has 'name', 'lower' and 'upper' keys. We
481
+ # therefore cannot use ShardRange.from_dict(), and the ShardRange
482
+ # instances constructed here will only have 'name', 'lower' and 'upper'
483
+ # attributes set.
484
+ # Ideally we would construct Namespace objects here, but later we use
485
+ # the ShardRange account and container properties to access parsed
486
+ # parts of the name.
487
+ shard_ranges = [ShardRange(**data) for data in json.loads(resp.body)]
429
488
  self.logger.debug('GET listing from %s shards for: %s',
430
489
  len(shard_ranges), req.path_qs)
431
490
  if not shard_ranges: