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/common/bufferedhttp.py
CHANGED
@@ -27,28 +27,22 @@ BufferedHTTPResponse.
|
|
27
27
|
"""
|
28
28
|
|
29
29
|
from swift.common import constraints
|
30
|
+
import http.client
|
30
31
|
import logging
|
31
32
|
import time
|
32
33
|
import socket
|
33
34
|
|
34
|
-
import
|
35
|
-
|
36
|
-
|
37
|
-
from six.moves.urllib.parse import quote, parse_qsl, urlencode
|
38
|
-
import six
|
35
|
+
from eventlet.green.http.client import CONTINUE, HTTPConnection, \
|
36
|
+
HTTPResponse, HTTPSConnection, _UNKNOWN, ImproperConnectionState
|
37
|
+
from urllib.parse import quote, parse_qsl, urlencode
|
39
38
|
|
40
|
-
|
41
|
-
httplib = eventlet.import_patched('httplib')
|
42
|
-
from eventlet.green import httplib as green_httplib
|
43
|
-
else:
|
44
|
-
httplib = eventlet.import_patched('http.client')
|
45
|
-
from eventlet.green.http import client as green_httplib
|
39
|
+
from eventlet.green.http import client as green_http_client
|
46
40
|
|
47
41
|
# Apparently http.server uses this to decide when/whether to send a 431.
|
48
42
|
# Give it some slack, so the app is more likely to get the chance to reject
|
49
43
|
# with a 400 instead.
|
50
|
-
|
51
|
-
|
44
|
+
http.client._MAXHEADERS = constraints.MAX_HEADER_COUNT * 1.6
|
45
|
+
green_http_client._MAXHEADERS = constraints.MAX_HEADER_COUNT * 1.6
|
52
46
|
|
53
47
|
|
54
48
|
class BufferedHTTPResponse(HTTPResponse):
|
@@ -56,21 +50,24 @@ class BufferedHTTPResponse(HTTPResponse):
|
|
56
50
|
|
57
51
|
def __init__(self, sock, debuglevel=0, strict=0,
|
58
52
|
method=None): # pragma: no cover
|
53
|
+
# sock should be an eventlet.greenio.GreenSocket
|
59
54
|
self.sock = sock
|
60
|
-
|
61
|
-
|
62
|
-
#
|
63
|
-
|
64
|
-
|
55
|
+
if sock is None:
|
56
|
+
# ...but it could be None if we close the connection as we're
|
57
|
+
# getting it wrapped up in a Response
|
58
|
+
self._real_socket = None
|
59
|
+
# No socket means no file-like -- set it to None like in
|
60
|
+
# HTTPResponse.close()
|
61
|
+
self.fp = None
|
65
62
|
else:
|
66
63
|
# sock.fd is a socket.socket, which should have a _real_close
|
67
64
|
self._real_socket = sock.fd
|
68
|
-
|
65
|
+
self.fp = sock.makefile('rb')
|
69
66
|
self.debuglevel = debuglevel
|
70
67
|
self.strict = strict
|
71
68
|
self._method = method
|
72
69
|
|
73
|
-
self.
|
70
|
+
self._headers = self.msg = None
|
74
71
|
|
75
72
|
# from the Status-Line of the response
|
76
73
|
self.version = _UNKNOWN # HTTP-Version
|
@@ -83,10 +80,17 @@ class BufferedHTTPResponse(HTTPResponse):
|
|
83
80
|
self.will_close = _UNKNOWN # conn will close at end of response
|
84
81
|
self._readline_buffer = b''
|
85
82
|
|
86
|
-
|
87
|
-
|
88
|
-
|
89
|
-
|
83
|
+
@property
|
84
|
+
def headers(self):
|
85
|
+
return self._headers
|
86
|
+
|
87
|
+
@headers.setter
|
88
|
+
def headers(self, hdrs):
|
89
|
+
try:
|
90
|
+
header_payload = hdrs.get_payload()
|
91
|
+
except AttributeError:
|
92
|
+
pass
|
93
|
+
else:
|
90
94
|
if isinstance(header_payload, list) and len(header_payload) == 1:
|
91
95
|
header_payload = header_payload[0].get_payload()
|
92
96
|
if header_payload:
|
@@ -100,12 +104,19 @@ class BufferedHTTPResponse(HTTPResponse):
|
|
100
104
|
break
|
101
105
|
header, value = line.split(':', 1)
|
102
106
|
value = value.strip(' \t\n\r')
|
103
|
-
|
107
|
+
hdrs.add_header(header, value)
|
108
|
+
# Clear the payload now that all headers are present.
|
109
|
+
# Otherwise, we may double-up the headers parsed here
|
110
|
+
# if/when repeatedly setting the headers property.
|
111
|
+
hdrs.set_payload(None)
|
112
|
+
self._headers = hdrs
|
104
113
|
|
105
114
|
def expect_response(self):
|
106
115
|
if self.fp:
|
107
116
|
self.fp.close()
|
108
117
|
self.fp = None
|
118
|
+
if not self.sock:
|
119
|
+
raise ImproperConnectionState('Socket already closed')
|
109
120
|
self.fp = self.sock.makefile('rb', 0)
|
110
121
|
version, status, reason = self._read_status()
|
111
122
|
if status != CONTINUE:
|
@@ -115,15 +126,7 @@ class BufferedHTTPResponse(HTTPResponse):
|
|
115
126
|
self.status = status
|
116
127
|
self.reason = reason.strip()
|
117
128
|
self.version = 11
|
118
|
-
|
119
|
-
# Under py2, HTTPMessage.__init__ reads the headers
|
120
|
-
# which advances fp
|
121
|
-
self.msg = HTTPMessage(self.fp, 0)
|
122
|
-
# immediately kill msg.fp to make sure it isn't read again
|
123
|
-
self.msg.fp = None
|
124
|
-
else:
|
125
|
-
# py3 has a separate helper for it
|
126
|
-
self.headers = self.msg = httplib.parse_headers(self.fp)
|
129
|
+
self.headers = self.msg = http.client.parse_headers(self.fp)
|
127
130
|
|
128
131
|
def read(self, amt=None):
|
129
132
|
if not self._readline_buffer:
|
@@ -147,26 +150,6 @@ class BufferedHTTPResponse(HTTPResponse):
|
|
147
150
|
self._readline_buffer = b''
|
148
151
|
return buf + HTTPResponse.read(self, smaller_amt)
|
149
152
|
|
150
|
-
def readline(self, size=1024):
|
151
|
-
# You'd think Python's httplib would provide this, but it doesn't.
|
152
|
-
# It does, however, provide a comment in the HTTPResponse class:
|
153
|
-
#
|
154
|
-
# # XXX It would be nice to have readline and __iter__ for this,
|
155
|
-
# # too.
|
156
|
-
#
|
157
|
-
# Yes, it certainly would.
|
158
|
-
while (b'\n' not in self._readline_buffer
|
159
|
-
and len(self._readline_buffer) < size):
|
160
|
-
read_size = size - len(self._readline_buffer)
|
161
|
-
chunk = HTTPResponse.read(self, read_size)
|
162
|
-
if not chunk:
|
163
|
-
break
|
164
|
-
self._readline_buffer += chunk
|
165
|
-
|
166
|
-
line, newline, rest = self._readline_buffer.partition(b'\n')
|
167
|
-
self._readline_buffer = rest
|
168
|
-
return line + newline
|
169
|
-
|
170
153
|
def nuke_from_orbit(self):
|
171
154
|
"""
|
172
155
|
Terminate the socket with extreme prejudice.
|
@@ -176,14 +159,9 @@ class BufferedHTTPResponse(HTTPResponse):
|
|
176
159
|
you care about has a reference to this socket.
|
177
160
|
"""
|
178
161
|
if self._real_socket:
|
179
|
-
|
180
|
-
|
181
|
-
|
182
|
-
self._real_socket.close()
|
183
|
-
else:
|
184
|
-
# Hopefully this is equivalent?
|
185
|
-
# TODO: verify that this does everything ^^^^ does for py2
|
186
|
-
self._real_socket._real_close()
|
162
|
+
# Hopefully this is equivalent to py2's _real_socket.close()?
|
163
|
+
# TODO: verify that this does everything ^^^^ does for py2
|
164
|
+
self._real_socket._real_close()
|
187
165
|
self._real_socket = None
|
188
166
|
self.close()
|
189
167
|
|
@@ -258,13 +236,13 @@ def http_connect(ipaddr, port, device, partition, method, path,
|
|
258
236
|
:param ssl: set True if SSL should be used (default: False)
|
259
237
|
:returns: HTTPConnection object
|
260
238
|
"""
|
261
|
-
if isinstance(path,
|
239
|
+
if isinstance(path, str):
|
262
240
|
path = path.encode("utf-8")
|
263
|
-
if isinstance(device,
|
241
|
+
if isinstance(device, str):
|
264
242
|
device = device.encode("utf-8")
|
265
|
-
if isinstance(partition,
|
243
|
+
if isinstance(partition, str):
|
266
244
|
partition = partition.encode('utf-8')
|
267
|
-
elif isinstance(partition,
|
245
|
+
elif isinstance(partition, int):
|
268
246
|
partition = str(partition).encode('ascii')
|
269
247
|
path = quote(b'/' + device + b'/' + partition + path)
|
270
248
|
return http_connect_raw(
|
@@ -295,14 +273,10 @@ def http_connect_raw(ipaddr, port, method, path, headers=None,
|
|
295
273
|
conn = BufferedHTTPConnection('%s:%s' % (ipaddr, port))
|
296
274
|
if query_string:
|
297
275
|
# Round trip to ensure proper quoting
|
298
|
-
|
299
|
-
query_string =
|
300
|
-
|
301
|
-
|
302
|
-
query_string = urlencode(
|
303
|
-
parse_qsl(query_string, keep_blank_values=True,
|
304
|
-
encoding='latin1'),
|
305
|
-
encoding='latin1')
|
276
|
+
query_string = urlencode(
|
277
|
+
parse_qsl(query_string, keep_blank_values=True,
|
278
|
+
encoding='latin1'),
|
279
|
+
encoding='latin1')
|
306
280
|
path += '?' + query_string
|
307
281
|
conn.path = path
|
308
282
|
conn.putrequest(method, path, skip_host=(headers and 'Host' in headers))
|
swift/common/constraints.py
CHANGED
@@ -17,9 +17,8 @@ import functools
|
|
17
17
|
import os
|
18
18
|
from os.path import isdir # tighter scoped import for mocking
|
19
19
|
|
20
|
-
import
|
21
|
-
|
22
|
-
from six.moves import urllib
|
20
|
+
from configparser import ConfigParser, NoSectionError, NoOptionError
|
21
|
+
import urllib
|
23
22
|
|
24
23
|
from swift.common import utils, exceptions
|
25
24
|
from swift.common.swob import HTTPBadRequest, HTTPLengthRequired, \
|
@@ -39,6 +38,7 @@ MAX_ACCOUNT_NAME_LENGTH = 256
|
|
39
38
|
MAX_CONTAINER_NAME_LENGTH = 256
|
40
39
|
VALID_API_VERSIONS = ["v1", "v1.0"]
|
41
40
|
EXTRA_HEADER_COUNT = 0
|
41
|
+
AUTO_CREATE_ACCOUNT_PREFIX = '.'
|
42
42
|
|
43
43
|
# If adding an entry to DEFAULT_CONSTRAINTS, note that
|
44
44
|
# these constraints are automatically published by the
|
@@ -58,6 +58,7 @@ DEFAULT_CONSTRAINTS = {
|
|
58
58
|
'max_container_name_length': MAX_CONTAINER_NAME_LENGTH,
|
59
59
|
'valid_api_versions': VALID_API_VERSIONS,
|
60
60
|
'extra_header_count': EXTRA_HEADER_COUNT,
|
61
|
+
'auto_create_account_prefix': AUTO_CREATE_ACCOUNT_PREFIX,
|
61
62
|
}
|
62
63
|
|
63
64
|
SWIFT_CONSTRAINTS_LOADED = False
|
@@ -76,7 +77,7 @@ def reload_constraints():
|
|
76
77
|
constraints_conf = ConfigParser()
|
77
78
|
if constraints_conf.read(utils.SWIFT_CONF_FILE):
|
78
79
|
SWIFT_CONSTRAINTS_LOADED = True
|
79
|
-
for name in DEFAULT_CONSTRAINTS:
|
80
|
+
for name, default in DEFAULT_CONSTRAINTS.items():
|
80
81
|
try:
|
81
82
|
value = constraints_conf.get('swift-constraints', name)
|
82
83
|
except NoOptionError:
|
@@ -85,9 +86,12 @@ def reload_constraints():
|
|
85
86
|
# We are never going to find the section for another option
|
86
87
|
break
|
87
88
|
else:
|
88
|
-
|
89
|
-
value = int(value)
|
90
|
-
|
89
|
+
if isinstance(default, int):
|
90
|
+
value = int(value) # Go ahead and let it error
|
91
|
+
elif isinstance(default, str):
|
92
|
+
pass # No translation needed, I guess
|
93
|
+
else:
|
94
|
+
# Hope we want a list!
|
91
95
|
value = utils.list_from_csv(value)
|
92
96
|
OVERRIDE_CONSTRAINTS[name] = value
|
93
97
|
for name, default in DEFAULT_CONSTRAINTS.items():
|
@@ -125,7 +129,7 @@ def check_metadata(req, target_type):
|
|
125
129
|
meta_count = 0
|
126
130
|
meta_size = 0
|
127
131
|
for key, value in req.headers.items():
|
128
|
-
if (isinstance(value,
|
132
|
+
if (isinstance(value, str)
|
129
133
|
and len(value) > MAX_HEADER_SIZE):
|
130
134
|
|
131
135
|
return HTTPBadRequest(body=b'Header value too long: %s' %
|
@@ -346,19 +350,20 @@ def check_delete_headers(request):
|
|
346
350
|
return request
|
347
351
|
|
348
352
|
|
349
|
-
def check_utf8(string):
|
353
|
+
def check_utf8(string, internal=False):
|
350
354
|
"""
|
351
355
|
Validate if a string is valid UTF-8 str or unicode and that it
|
352
|
-
does not contain any
|
356
|
+
does not contain any reserved characters.
|
353
357
|
|
354
358
|
:param string: string to be validated
|
359
|
+
:param internal: boolean, allows reserved characters if True
|
355
360
|
:returns: True if the string is valid utf-8 str or unicode and
|
356
361
|
contains no null characters, False otherwise
|
357
362
|
"""
|
358
363
|
if not string:
|
359
364
|
return False
|
360
365
|
try:
|
361
|
-
if isinstance(string,
|
366
|
+
if isinstance(string, str):
|
362
367
|
encoded = string.encode('utf-8')
|
363
368
|
decoded = string
|
364
369
|
else:
|
@@ -382,7 +387,9 @@ def check_utf8(string):
|
|
382
387
|
if any(0xD800 <= ord(codepoint) <= 0xDFFF
|
383
388
|
for codepoint in decoded):
|
384
389
|
return False
|
385
|
-
|
390
|
+
if b'\x00' != utils.RESERVED_BYTE and b'\x00' in encoded:
|
391
|
+
return False
|
392
|
+
return True if internal else utils.RESERVED_BYTE not in encoded
|
386
393
|
# If string is unicode, decode() will raise UnicodeEncodeError
|
387
394
|
# So, we should catch both UnicodeDecodeError & UnicodeEncodeError
|
388
395
|
except UnicodeError:
|
@@ -404,15 +411,13 @@ def check_name_format(req, name, target_type):
|
|
404
411
|
raise HTTPPreconditionFailed(
|
405
412
|
request=req,
|
406
413
|
body='%s name cannot be empty' % target_type)
|
407
|
-
if six.PY2:
|
408
|
-
if isinstance(name, six.text_type):
|
409
|
-
name = name.encode('utf-8')
|
410
414
|
if '/' in name:
|
411
415
|
raise HTTPPreconditionFailed(
|
412
416
|
request=req,
|
413
417
|
body='%s name cannot contain slashes' % target_type)
|
414
418
|
return name
|
415
419
|
|
420
|
+
|
416
421
|
check_account_format = functools.partial(check_name_format,
|
417
422
|
target_type='Account')
|
418
423
|
check_container_format = functools.partial(check_name_format,
|
@@ -19,10 +19,8 @@ import hmac
|
|
19
19
|
import os
|
20
20
|
import time
|
21
21
|
|
22
|
-
import
|
23
|
-
from six.moves import configparser
|
22
|
+
import configparser
|
24
23
|
|
25
|
-
from swift import gettext_ as _
|
26
24
|
from swift.common.utils import get_valid_utf8_str
|
27
25
|
|
28
26
|
|
@@ -58,7 +56,7 @@ class ContainerSyncRealms(object):
|
|
58
56
|
log_func = self.logger.debug
|
59
57
|
else:
|
60
58
|
log_func = self.logger.error
|
61
|
-
log_func(
|
59
|
+
log_func('Could not load %(conf)r: %(error)s', {
|
62
60
|
'conf': self.conf_path, 'error': err})
|
63
61
|
else:
|
64
62
|
if mtime != self.conf_path_mtime:
|
@@ -68,11 +66,11 @@ class ContainerSyncRealms(object):
|
|
68
66
|
conf.read(self.conf_path)
|
69
67
|
except configparser.ParsingError as err:
|
70
68
|
self.logger.error(
|
71
|
-
|
72
|
-
|
69
|
+
'Could not load %(conf)r: %(error)s',
|
70
|
+
{'conf': self.conf_path, 'error': err})
|
73
71
|
else:
|
74
72
|
try:
|
75
|
-
self.mtime_check_interval = conf.
|
73
|
+
self.mtime_check_interval = conf.getfloat(
|
76
74
|
'DEFAULT', 'mtime_check_interval')
|
77
75
|
self.next_mtime_check = \
|
78
76
|
now + self.mtime_check_interval
|
@@ -82,9 +80,9 @@ class ContainerSyncRealms(object):
|
|
82
80
|
now + self.mtime_check_interval
|
83
81
|
except (configparser.ParsingError, ValueError) as err:
|
84
82
|
self.logger.error(
|
85
|
-
|
86
|
-
|
87
|
-
|
83
|
+
'Error in %(conf)r with '
|
84
|
+
'mtime_check_interval: %(error)s',
|
85
|
+
{'conf': self.conf_path, 'error': err})
|
88
86
|
realms = {}
|
89
87
|
for section in conf.sections():
|
90
88
|
realm = {}
|
@@ -159,7 +157,7 @@ class ContainerSyncRealms(object):
|
|
159
157
|
user_key = get_valid_utf8_str(user_key)
|
160
158
|
# XXX We don't know what is the best here yet; wait for container
|
161
159
|
# sync to be tested.
|
162
|
-
if isinstance(path,
|
160
|
+
if isinstance(path, str):
|
163
161
|
path = path.encode('utf-8')
|
164
162
|
return hmac.new(
|
165
163
|
realm_key,
|
swift/common/daemon.py
CHANGED
@@ -20,8 +20,8 @@ import time
|
|
20
20
|
import signal
|
21
21
|
from re import sub
|
22
22
|
|
23
|
+
import eventlet
|
23
24
|
import eventlet.debug
|
24
|
-
from eventlet.hubs import use_hub
|
25
25
|
|
26
26
|
from swift.common import utils
|
27
27
|
|
@@ -45,6 +45,7 @@ class Daemon(object):
|
|
45
45
|
multiple daemonized workers, they simply provide the behavior of the daemon
|
46
46
|
and context specific knowledge about how workers should be started.
|
47
47
|
"""
|
48
|
+
WORKERS_HEALTHCHECK_INTERVAL = 5.0
|
48
49
|
|
49
50
|
def __init__(self, conf):
|
50
51
|
self.conf = conf
|
@@ -132,17 +133,19 @@ class DaemonStrategy(object):
|
|
132
133
|
def setup(self, **kwargs):
|
133
134
|
utils.validate_configuration()
|
134
135
|
utils.drop_privileges(self.daemon.conf.get('user', 'swift'))
|
136
|
+
utils.clean_up_daemon_hygiene()
|
135
137
|
utils.capture_stdio(self.logger, **kwargs)
|
136
138
|
|
137
139
|
def kill_children(*args):
|
138
140
|
self.running = False
|
139
|
-
self.logger.
|
141
|
+
self.logger.notice('SIGTERM received (%s)', os.getpid())
|
140
142
|
signal.signal(signal.SIGTERM, signal.SIG_IGN)
|
141
143
|
os.killpg(0, signal.SIGTERM)
|
142
144
|
os._exit(0)
|
143
145
|
|
144
146
|
signal.signal(signal.SIGTERM, kill_children)
|
145
147
|
self.running = True
|
148
|
+
utils.systemd_notify(self.logger)
|
146
149
|
|
147
150
|
def _run_inline(self, once=False, **kwargs):
|
148
151
|
"""Run the daemon"""
|
@@ -156,7 +159,7 @@ class DaemonStrategy(object):
|
|
156
159
|
except KeyboardInterrupt:
|
157
160
|
self.logger.notice('User quit')
|
158
161
|
finally:
|
159
|
-
self.cleanup()
|
162
|
+
self.cleanup(stopping=True)
|
160
163
|
self.running = False
|
161
164
|
|
162
165
|
def _fork(self, once, **kwargs):
|
@@ -164,6 +167,8 @@ class DaemonStrategy(object):
|
|
164
167
|
if pid == 0:
|
165
168
|
signal.signal(signal.SIGHUP, signal.SIG_DFL)
|
166
169
|
signal.signal(signal.SIGTERM, signal.SIG_DFL)
|
170
|
+
# only MAINPID should be sending notifications
|
171
|
+
os.environ.pop('NOTIFY_SOCKET', None)
|
167
172
|
|
168
173
|
self.daemon.run(once, **kwargs)
|
169
174
|
|
@@ -238,11 +243,19 @@ class DaemonStrategy(object):
|
|
238
243
|
if not self.spawned_pids():
|
239
244
|
self.logger.notice('Finished %s', os.getpid())
|
240
245
|
break
|
241
|
-
time.sleep(
|
246
|
+
time.sleep(self.daemon.WORKERS_HEALTHCHECK_INTERVAL)
|
242
247
|
self.daemon.post_multiprocess_run()
|
243
248
|
return 0
|
244
249
|
|
245
|
-
def cleanup(self):
|
250
|
+
def cleanup(self, stopping=False):
|
251
|
+
"""
|
252
|
+
Cleanup worker processes
|
253
|
+
|
254
|
+
:param stopping: if set, tell systemd we're stopping
|
255
|
+
"""
|
256
|
+
|
257
|
+
if stopping:
|
258
|
+
utils.systemd_notify(self.logger, "STOPPING=1")
|
246
259
|
for p in self.spawned_pids():
|
247
260
|
try:
|
248
261
|
os.kill(p, signal.SIGTERM)
|
@@ -267,7 +280,7 @@ def run_daemon(klass, conf_file, section_name='', once=False, **kwargs):
|
|
267
280
|
"""
|
268
281
|
# very often the config section_name is based on the class name
|
269
282
|
# the None singleton will be passed through to readconf as is
|
270
|
-
if section_name
|
283
|
+
if section_name == '':
|
271
284
|
section_name = sub(r'([a-z])([A-Z])', r'\1-\2',
|
272
285
|
klass.__name__).lower()
|
273
286
|
try:
|
@@ -278,7 +291,9 @@ def run_daemon(klass, conf_file, section_name='', once=False, **kwargs):
|
|
278
291
|
# and results in an exit code of 1.
|
279
292
|
sys.exit(e)
|
280
293
|
|
281
|
-
|
294
|
+
# patch eventlet/logging early
|
295
|
+
utils.monkey_patch()
|
296
|
+
eventlet.hubs.use_hub(utils.get_hub())
|
282
297
|
|
283
298
|
# once on command line (i.e. daemonize=false) will over-ride config
|
284
299
|
once = once or not utils.config_true_value(conf.get('daemonize', 'true'))
|
@@ -312,7 +327,9 @@ def run_daemon(klass, conf_file, section_name='', once=False, **kwargs):
|
|
312
327
|
|
313
328
|
logger.notice('Starting %s', os.getpid())
|
314
329
|
try:
|
315
|
-
|
330
|
+
d = klass(conf)
|
331
|
+
DaemonStrategy(d, logger).run(once=once, **kwargs)
|
316
332
|
except KeyboardInterrupt:
|
317
333
|
logger.info('User quit')
|
318
334
|
logger.notice('Exited %s', os.getpid())
|
335
|
+
return d
|