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
@@ -0,0 +1,399 @@
1
+ # Copyright (c) 2010-2023 OpenStack Foundation
2
+ #
3
+ # Licensed under the Apache License, Version 2.0 (the "License");
4
+ # you may not use this file except in compliance with the License.
5
+ # You may obtain 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,
11
+ # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or
12
+ # implied.
13
+ # See the License for the specific language governing permissions and
14
+ # limitations under the License.
15
+
16
+ """Timestamp-related functions for use with Swift."""
17
+
18
+ import datetime
19
+ import functools
20
+ import math
21
+ import time
22
+
23
+ import six
24
+
25
+
26
+ NORMAL_FORMAT = "%016.05f"
27
+ INTERNAL_FORMAT = NORMAL_FORMAT + '_%016x'
28
+ SHORT_FORMAT = NORMAL_FORMAT + '_%x'
29
+ MAX_OFFSET = (16 ** 16) - 1
30
+ PRECISION = 1e-5
31
+ # Setting this to True will cause the internal format to always display
32
+ # extended digits - even when the value is equivalent to the normalized form.
33
+ # This isn't ideal during an upgrade when some servers might not understand
34
+ # the new time format - but flipping it to True works great for testing.
35
+ FORCE_INTERNAL = False # or True
36
+
37
+
38
+ @functools.total_ordering
39
+ class Timestamp(object):
40
+ """
41
+ Internal Representation of Swift Time.
42
+
43
+ The normalized form of the X-Timestamp header looks like a float
44
+ with a fixed width to ensure stable string sorting - normalized
45
+ timestamps look like "1402464677.04188"
46
+
47
+ To support overwrites of existing data without modifying the original
48
+ timestamp but still maintain consistency a second internal offset vector
49
+ is append to the normalized timestamp form which compares and sorts
50
+ greater than the fixed width float format but less than a newer timestamp.
51
+ The internalized format of timestamps looks like
52
+ "1402464677.04188_0000000000000000" - the portion after the underscore is
53
+ the offset and is a formatted hexadecimal integer.
54
+
55
+ The internalized form is not exposed to clients in responses from
56
+ Swift. Normal client operations will not create a timestamp with an
57
+ offset.
58
+
59
+ The Timestamp class in common.utils supports internalized and
60
+ normalized formatting of timestamps and also comparison of timestamp
61
+ values. When the offset value of a Timestamp is 0 - it's considered
62
+ insignificant and need not be represented in the string format; to
63
+ support backwards compatibility during a Swift upgrade the
64
+ internalized and normalized form of a Timestamp with an
65
+ insignificant offset are identical. When a timestamp includes an
66
+ offset it will always be represented in the internalized form, but
67
+ is still excluded from the normalized form. Timestamps with an
68
+ equivalent timestamp portion (the float part) will compare and order
69
+ by their offset. Timestamps with a greater timestamp portion will
70
+ always compare and order greater than a Timestamp with a lesser
71
+ timestamp regardless of it's offset. String comparison and ordering
72
+ is guaranteed for the internalized string format, and is backwards
73
+ compatible for normalized timestamps which do not include an offset.
74
+ """
75
+
76
+ def __init__(self, timestamp, offset=0, delta=0, check_bounds=True):
77
+ """
78
+ Create a new Timestamp.
79
+
80
+ :param timestamp: time in seconds since the Epoch, may be any of:
81
+
82
+ * a float or integer
83
+ * normalized/internalized string
84
+ * another instance of this class (offset is preserved)
85
+
86
+ :param offset: the second internal offset vector, an int
87
+ :param delta: deca-microsecond difference from the base timestamp
88
+ param, an int
89
+ """
90
+ if isinstance(timestamp, bytes):
91
+ timestamp = timestamp.decode('ascii')
92
+ if isinstance(timestamp, six.string_types):
93
+ base, base_offset = timestamp.partition('_')[::2]
94
+ self.timestamp = float(base)
95
+ if '_' in base_offset:
96
+ raise ValueError('invalid literal for int() with base 16: '
97
+ '%r' % base_offset)
98
+ if base_offset:
99
+ self.offset = int(base_offset, 16)
100
+ else:
101
+ self.offset = 0
102
+ else:
103
+ self.timestamp = float(timestamp)
104
+ self.offset = getattr(timestamp, 'offset', 0)
105
+ # increment offset
106
+ if offset >= 0:
107
+ self.offset += offset
108
+ else:
109
+ raise ValueError('offset must be non-negative')
110
+ if self.offset > MAX_OFFSET:
111
+ raise ValueError('offset must be smaller than %d' % MAX_OFFSET)
112
+ self.raw = int(round(self.timestamp / PRECISION))
113
+ # add delta
114
+ if delta:
115
+ self.raw = self.raw + delta
116
+ if self.raw <= 0:
117
+ raise ValueError(
118
+ 'delta must be greater than %d' % (-1 * self.raw))
119
+ self.timestamp = float(self.raw * PRECISION)
120
+ if check_bounds:
121
+ if self.timestamp < 0:
122
+ raise ValueError('timestamp cannot be negative')
123
+ if self.timestamp >= 10000000000:
124
+ raise ValueError('timestamp too large')
125
+
126
+ @classmethod
127
+ def now(cls, offset=0, delta=0):
128
+ return cls(time.time(), offset=offset, delta=delta)
129
+
130
+ def __repr__(self):
131
+ return INTERNAL_FORMAT % (self.timestamp, self.offset)
132
+
133
+ def __str__(self):
134
+ raise TypeError('You must specify which string format is required')
135
+
136
+ def __float__(self):
137
+ return self.timestamp
138
+
139
+ def __int__(self):
140
+ return int(self.timestamp)
141
+
142
+ def __nonzero__(self):
143
+ return bool(self.timestamp or self.offset)
144
+
145
+ def __bool__(self):
146
+ return self.__nonzero__()
147
+
148
+ @property
149
+ def normal(self):
150
+ return NORMAL_FORMAT % self.timestamp
151
+
152
+ @property
153
+ def internal(self):
154
+ if self.offset or FORCE_INTERNAL:
155
+ return INTERNAL_FORMAT % (self.timestamp, self.offset)
156
+ else:
157
+ return self.normal
158
+
159
+ @property
160
+ def short(self):
161
+ if self.offset or FORCE_INTERNAL:
162
+ return SHORT_FORMAT % (self.timestamp, self.offset)
163
+ else:
164
+ return self.normal
165
+
166
+ @property
167
+ def isoformat(self):
168
+ """
169
+ Get an isoformat string representation of the 'normal' part of the
170
+ Timestamp with microsecond precision and no trailing timezone, for
171
+ example::
172
+
173
+ 1970-01-01T00:00:00.000000
174
+
175
+ :return: an isoformat string
176
+ """
177
+ t = float(self.normal)
178
+ if six.PY3:
179
+ # On Python 3, round manually using ROUND_HALF_EVEN rounding
180
+ # method, to use the same rounding method than Python 2. Python 3
181
+ # used a different rounding method, but Python 3.4.4 and 3.5.1 use
182
+ # again ROUND_HALF_EVEN as Python 2.
183
+ # See https://bugs.python.org/issue23517
184
+ frac, t = math.modf(t)
185
+ us = round(frac * 1e6)
186
+ if us >= 1000000:
187
+ t += 1
188
+ us -= 1000000
189
+ elif us < 0:
190
+ t -= 1
191
+ us += 1000000
192
+ dt = datetime.datetime.utcfromtimestamp(t)
193
+ dt = dt.replace(microsecond=us)
194
+ else:
195
+ dt = datetime.datetime.utcfromtimestamp(t)
196
+
197
+ isoformat = dt.isoformat()
198
+ # python isoformat() doesn't include msecs when zero
199
+ if len(isoformat) < len("1970-01-01T00:00:00.000000"):
200
+ isoformat += ".000000"
201
+ return isoformat
202
+
203
+ @classmethod
204
+ def from_isoformat(cls, date_string):
205
+ """
206
+ Parse an isoformat string representation of time to a Timestamp object.
207
+
208
+ :param date_string: a string formatted as per an Timestamp.isoformat
209
+ property.
210
+ :return: an instance of this class.
211
+ """
212
+ start = datetime.datetime.strptime(date_string, "%Y-%m-%dT%H:%M:%S.%f")
213
+ delta = start - EPOCH
214
+ # This calculation is based on Python 2.7's Modules/datetimemodule.c,
215
+ # function delta_to_microseconds(), but written in Python.
216
+ return cls(delta.total_seconds())
217
+
218
+ def ceil(self):
219
+ """
220
+ Return the 'normal' part of the timestamp rounded up to the nearest
221
+ integer number of seconds.
222
+
223
+ This value should be used whenever the second-precision Last-Modified
224
+ time of a resource is required.
225
+
226
+ :return: a float value with second precision.
227
+ """
228
+ return math.ceil(float(self))
229
+
230
+ def __eq__(self, other):
231
+ if other is None:
232
+ return False
233
+ if not isinstance(other, Timestamp):
234
+ try:
235
+ other = Timestamp(other, check_bounds=False)
236
+ except ValueError:
237
+ return False
238
+ return self.internal == other.internal
239
+
240
+ def __ne__(self, other):
241
+ return not (self == other)
242
+
243
+ def __lt__(self, other):
244
+ if other is None:
245
+ return False
246
+ if not isinstance(other, Timestamp):
247
+ other = Timestamp(other, check_bounds=False)
248
+ if other.timestamp < 0:
249
+ return False
250
+ if other.timestamp >= 10000000000:
251
+ return True
252
+ return self.internal < other.internal
253
+
254
+ def __hash__(self):
255
+ return hash(self.internal)
256
+
257
+ def __invert__(self):
258
+ if self.offset:
259
+ raise ValueError('Cannot invert timestamps with offsets')
260
+ return Timestamp((999999999999999 - self.raw) * PRECISION)
261
+
262
+
263
+ def encode_timestamps(t1, t2=None, t3=None, explicit=False):
264
+ """
265
+ Encode up to three timestamps into a string. Unlike a Timestamp object, the
266
+ encoded string does NOT used fixed width fields and consequently no
267
+ relative chronology of the timestamps can be inferred from lexicographic
268
+ sorting of encoded timestamp strings.
269
+
270
+ The format of the encoded string is:
271
+ <t1>[<+/-><t2 - t1>[<+/-><t3 - t2>]]
272
+
273
+ i.e. if t1 = t2 = t3 then just the string representation of t1 is returned,
274
+ otherwise the time offsets for t2 and t3 are appended. If explicit is True
275
+ then the offsets for t2 and t3 are always appended even if zero.
276
+
277
+ Note: any offset value in t1 will be preserved, but offsets on t2 and t3
278
+ are not preserved. In the anticipated use cases for this method (and the
279
+ inverse decode_timestamps method) the timestamps passed as t2 and t3 are
280
+ not expected to have offsets as they will be timestamps associated with a
281
+ POST request. In the case where the encoding is used in a container objects
282
+ table row, t1 could be the PUT or DELETE time but t2 and t3 represent the
283
+ content type and metadata times (if different from the data file) i.e.
284
+ correspond to POST timestamps. In the case where the encoded form is used
285
+ in a .meta file name, t1 and t2 both correspond to POST timestamps.
286
+ """
287
+ form = '{0}'
288
+ values = [t1.short]
289
+ if t2 is not None:
290
+ t2_t1_delta = t2.raw - t1.raw
291
+ explicit = explicit or (t2_t1_delta != 0)
292
+ values.append(t2_t1_delta)
293
+ if t3 is not None:
294
+ t3_t2_delta = t3.raw - t2.raw
295
+ explicit = explicit or (t3_t2_delta != 0)
296
+ values.append(t3_t2_delta)
297
+ if explicit:
298
+ form += '{1:+x}'
299
+ if t3 is not None:
300
+ form += '{2:+x}'
301
+ return form.format(*values)
302
+
303
+
304
+ def decode_timestamps(encoded, explicit=False):
305
+ """
306
+ Parses a string of the form generated by encode_timestamps and returns
307
+ a tuple of the three component timestamps. If explicit is False, component
308
+ timestamps that are not explicitly encoded will be assumed to have zero
309
+ delta from the previous component and therefore take the value of the
310
+ previous component. If explicit is True, component timestamps that are
311
+ not explicitly encoded will be returned with value None.
312
+ """
313
+ # TODO: some tests, e.g. in test_replicator, put float timestamps values
314
+ # into container db's, hence this defensive check, but in real world
315
+ # this may never happen.
316
+ if not isinstance(encoded, six.string_types):
317
+ ts = Timestamp(encoded)
318
+ return ts, ts, ts
319
+
320
+ parts = []
321
+ signs = []
322
+ pos_parts = encoded.split('+')
323
+ for part in pos_parts:
324
+ # parse time components and their signs
325
+ # e.g. x-y+z --> parts = [x, y, z] and signs = [+1, -1, +1]
326
+ neg_parts = part.split('-')
327
+ parts = parts + neg_parts
328
+ signs = signs + [1] + [-1] * (len(neg_parts) - 1)
329
+ t1 = Timestamp(parts[0])
330
+ t2 = t3 = None
331
+ if len(parts) > 1:
332
+ t2 = t1
333
+ delta = signs[1] * int(parts[1], 16)
334
+ # if delta = 0 we want t2 = t3 = t1 in order to
335
+ # preserve any offset in t1 - only construct a distinct
336
+ # timestamp if there is a non-zero delta.
337
+ if delta:
338
+ t2 = Timestamp((t1.raw + delta) * PRECISION)
339
+ elif not explicit:
340
+ t2 = t1
341
+ if len(parts) > 2:
342
+ t3 = t2
343
+ delta = signs[2] * int(parts[2], 16)
344
+ if delta:
345
+ t3 = Timestamp((t2.raw + delta) * PRECISION)
346
+ elif not explicit:
347
+ t3 = t2
348
+ return t1, t2, t3
349
+
350
+
351
+ def normalize_timestamp(timestamp):
352
+ """
353
+ Format a timestamp (string or numeric) into a standardized
354
+ xxxxxxxxxx.xxxxx (10.5) format.
355
+
356
+ Note that timestamps using values greater than or equal to November 20th,
357
+ 2286 at 17:46 UTC will use 11 digits to represent the number of
358
+ seconds.
359
+
360
+ :param timestamp: unix timestamp
361
+ :returns: normalized timestamp as a string
362
+ """
363
+ return Timestamp(timestamp).normal
364
+
365
+
366
+ EPOCH = datetime.datetime(1970, 1, 1)
367
+
368
+
369
+ def last_modified_date_to_timestamp(last_modified_date_str):
370
+ """
371
+ Convert a last modified date (like you'd get from a container listing,
372
+ e.g. 2014-02-28T23:22:36.698390) to a float.
373
+ """
374
+ return Timestamp.from_isoformat(last_modified_date_str)
375
+
376
+
377
+ def normalize_delete_at_timestamp(timestamp, high_precision=False):
378
+ """
379
+ Format a timestamp (string or numeric) into a standardized
380
+ xxxxxxxxxx (10) or xxxxxxxxxx.xxxxx (10.5) format.
381
+
382
+ Note that timestamps less than 0000000000 are raised to
383
+ 0000000000 and values greater than November 20th, 2286 at
384
+ 17:46:39 UTC will be capped at that date and time, resulting in
385
+ no return value exceeding 9999999999.99999 (or 9999999999 if
386
+ using low-precision).
387
+
388
+ This cap is because the expirer is already working through a
389
+ sorted list of strings that were all a length of 10. Adding
390
+ another digit would mess up the sort and cause the expirer to
391
+ break from processing early. By 2286, this problem will need to
392
+ be fixed, probably by creating an additional .expiring_objects
393
+ account to work from with 11 (or more) digit container names.
394
+
395
+ :param timestamp: unix timestamp
396
+ :returns: normalized timestamp as a string
397
+ """
398
+ fmt = '%016.5f' if high_precision else '%010d'
399
+ return fmt % min(max(0, float(timestamp)), 9999999999.99999)
swift/common/wsgi.py CHANGED
@@ -21,7 +21,6 @@ import errno
21
21
  import fcntl
22
22
  import os
23
23
  import signal
24
- from swift import gettext_ as _
25
24
  import sys
26
25
  from textwrap import dedent
27
26
  import time
@@ -207,19 +206,19 @@ def get_socket(conf):
207
206
  raise
208
207
  sleep(0.1)
209
208
  if not sock:
210
- raise Exception(_('Could not bind to %(addr)s:%(port)s '
211
- 'after trying for %(timeout)s seconds') % {
212
- 'addr': bind_addr[0], 'port': bind_addr[1],
213
- 'timeout': bind_timeout})
209
+ raise Exception('Could not bind to %(addr)s:%(port)s '
210
+ 'after trying for %(timeout)s seconds' % {
211
+ 'addr': bind_addr[0], 'port': bind_addr[1],
212
+ 'timeout': bind_timeout})
214
213
  # in my experience, sockets can hang around forever without keepalive
215
214
  sock.setsockopt(socket.SOL_SOCKET, socket.SO_KEEPALIVE, 1)
216
215
  sock.setsockopt(socket.IPPROTO_TCP, socket.TCP_NODELAY, 1)
217
216
  if hasattr(socket, 'TCP_KEEPIDLE'):
218
217
  sock.setsockopt(socket.IPPROTO_TCP, socket.TCP_KEEPIDLE, keepidle)
219
218
  if warn_ssl:
220
- ssl_warning_message = _('WARNING: SSL should only be enabled for '
221
- 'testing purposes. Use external SSL '
222
- 'termination for a production deployment.')
219
+ ssl_warning_message = ('WARNING: SSL should only be enabled for '
220
+ 'testing purposes. Use external SSL '
221
+ 'termination for a production deployment.')
223
222
  get_logger(conf).warning(ssl_warning_message)
224
223
  print(ssl_warning_message)
225
224
  return sock
@@ -361,12 +360,30 @@ def loadapp(conf_file, global_conf=None, allow_modify_pipeline=True):
361
360
  if func and allow_modify_pipeline:
362
361
  func(PipelineWrapper(ctx))
363
362
  filters = [c.create() for c in reversed(ctx.filter_contexts)]
364
- app = ultimate_app
365
- app._pipeline_final_app = ultimate_app
363
+ pipeline = [ultimate_app]
364
+ request_logging_app = app = ultimate_app
366
365
  for filter_app in filters:
367
- app = filter_app(app)
366
+ app = filter_app(pipeline[0])
367
+ pipeline.insert(0, app)
368
+ if request_logging_app is ultimate_app and \
369
+ app.__class__.__name__ == 'ProxyLoggingMiddleware':
370
+ request_logging_app = filter_app(ultimate_app)
371
+ # Set some separate-pipeline attrs
372
+ request_logging_app._pipeline = [
373
+ request_logging_app, ultimate_app]
374
+ request_logging_app._pipeline_request_logging_app = \
375
+ request_logging_app
376
+ request_logging_app._pipeline_final_app = ultimate_app
377
+
378
+ for app in pipeline:
379
+ app._pipeline = pipeline
380
+ # For things like making (logged) backend requests for
381
+ # get_account_info and get_container_info
382
+ app._pipeline_request_logging_app = request_logging_app
383
+ # For getting proxy-server options like *_existence_skip_cache_pct
368
384
  app._pipeline_final_app = ultimate_app
369
- return app
385
+
386
+ return pipeline[0]
370
387
  return ctx.create()
371
388
 
372
389
 
@@ -430,6 +447,9 @@ def run_server(conf, logger, sock, global_conf=None, ready_callback=None,
430
447
  # header; "Etag" just won't do).
431
448
  'capitalize_response_headers': False,
432
449
  }
450
+ if conf.get('keepalive_timeout'):
451
+ server_kwargs['keepalive'] = float(conf['keepalive_timeout']) or False
452
+
433
453
  if ready_callback:
434
454
  ready_callback()
435
455
  # Yes, eventlet, we know -- we have to support bad clients, though
@@ -788,27 +808,10 @@ class ServersPerPortStrategy(StrategyBase):
788
808
  yield sock
789
809
 
790
810
 
791
- def run_wsgi(conf_path, app_section, *args, **kwargs):
792
- """
793
- Runs the server according to some strategy. The default strategy runs a
794
- specified number of workers in pre-fork model. The object-server (only)
795
- may use a servers-per-port strategy if its config has a servers_per_port
796
- setting with a value greater than zero.
797
-
798
- :param conf_path: Path to paste.deploy style configuration file/directory
799
- :param app_section: App name from conf file to load config from
800
- :param allow_modify_pipeline: Boolean for whether the server should have
801
- an opportunity to change its own pipeline.
802
- Defaults to True
803
- :returns: 0 if successful, nonzero otherwise
804
- """
811
+ def check_config(conf_path, app_section, *args, **kwargs):
805
812
  # Load configuration, Set logger and Load request processor
806
- try:
807
- (conf, logger, log_name) = \
808
- _initrp(conf_path, app_section, *args, **kwargs)
809
- except ConfigFileError as e:
810
- print(e)
811
- return 1
813
+ (conf, logger, log_name) = \
814
+ _initrp(conf_path, app_section, *args, **kwargs)
812
815
 
813
816
  # optional nice/ionice priority scheduling
814
817
  utils.modify_priority(conf, logger)
@@ -825,16 +828,16 @@ def run_wsgi(conf_path, app_section, *args, **kwargs):
825
828
  strategy = WorkersStrategy(conf, logger)
826
829
  try:
827
830
  # Quick sanity check
828
- int(conf['bind_port'])
831
+ if not (1 <= int(conf['bind_port']) <= 2 ** 16 - 1):
832
+ raise ValueError
829
833
  except (ValueError, KeyError, TypeError):
830
834
  error_msg = 'bind_port wasn\'t properly set in the config file. ' \
831
- 'It must be explicitly set to a valid port number.'
835
+ 'It must be explicitly set to a valid port number.'
832
836
  logger.error(error_msg)
833
- print(error_msg)
834
- return 1
837
+ raise ConfigFileError(error_msg)
835
838
 
836
839
  # patch event before loadapp
837
- utils.eventlet_monkey_patch()
840
+ utils.monkey_patch()
838
841
 
839
842
  # Ensure the configuration and application can be loaded before proceeding.
840
843
  global_conf = {'log_name': log_name}
@@ -842,16 +845,44 @@ def run_wsgi(conf_path, app_section, *args, **kwargs):
842
845
  if 'global_conf_callback' in kwargs:
843
846
  kwargs['global_conf_callback'](conf, global_conf)
844
847
 
845
- allow_modify_pipeline = kwargs.get('allow_modify_pipeline', True)
846
-
847
848
  # set utils.FALLOCATE_RESERVE if desired
848
849
  utils.FALLOCATE_RESERVE, utils.FALLOCATE_IS_PERCENT = \
849
850
  utils.config_fallocate_value(conf.get('fallocate_reserve', '1%'))
851
+ return conf, logger, global_conf, strategy
852
+
853
+
854
+ def run_wsgi(conf_path, app_section, *args, **kwargs):
855
+ """
856
+ Runs the server according to some strategy. The default strategy runs a
857
+ specified number of workers in pre-fork model. The object-server (only)
858
+ may use a servers-per-port strategy if its config has a servers_per_port
859
+ setting with a value greater than zero.
860
+
861
+ :param conf_path: Path to paste.deploy style configuration file/directory
862
+ :param app_section: App name from conf file to load config from
863
+ :param allow_modify_pipeline: Boolean for whether the server should have
864
+ an opportunity to change its own pipeline.
865
+ Defaults to True
866
+ :param test_config: if False (the default) then load and validate the
867
+ config and if successful then continue to run the server; if True then
868
+ load and validate the config but do not run the server.
869
+ :returns: 0 if successful, nonzero otherwise
870
+ """
871
+ try:
872
+ conf, logger, global_conf, strategy = check_config(
873
+ conf_path, app_section, *args, **kwargs)
874
+ except ConfigFileError as err:
875
+ print(err)
876
+ return 1
877
+
878
+ if kwargs.get('test_config'):
879
+ return 0
850
880
 
851
881
  # Do some daemonization process hygene before we fork any children or run a
852
882
  # server without forking.
853
883
  clean_up_daemon_hygiene()
854
884
 
885
+ allow_modify_pipeline = kwargs.get('allow_modify_pipeline', True)
855
886
  no_fork_sock = strategy.no_fork_sock()
856
887
  if no_fork_sock:
857
888
  run_server(conf, logger, no_fork_sock, global_conf=global_conf,