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.
Files changed (208) hide show
  1. swift/__init__.py +29 -50
  2. swift/account/auditor.py +21 -118
  3. swift/account/backend.py +33 -28
  4. swift/account/reaper.py +37 -28
  5. swift/account/replicator.py +22 -0
  6. swift/account/server.py +60 -26
  7. swift/account/utils.py +28 -11
  8. swift-2.23.2.data/scripts/swift-account-audit → swift/cli/account_audit.py +23 -13
  9. swift-2.23.2.data/scripts/swift-config → swift/cli/config.py +2 -2
  10. swift/cli/container_deleter.py +5 -11
  11. swift-2.23.2.data/scripts/swift-dispersion-populate → swift/cli/dispersion_populate.py +8 -7
  12. swift/cli/dispersion_report.py +10 -9
  13. swift-2.23.2.data/scripts/swift-drive-audit → swift/cli/drive_audit.py +63 -21
  14. swift/cli/form_signature.py +3 -7
  15. swift-2.23.2.data/scripts/swift-get-nodes → swift/cli/get_nodes.py +8 -2
  16. swift/cli/info.py +183 -29
  17. swift/cli/manage_shard_ranges.py +708 -37
  18. swift-2.23.2.data/scripts/swift-oldies → swift/cli/oldies.py +25 -14
  19. swift-2.23.2.data/scripts/swift-orphans → swift/cli/orphans.py +7 -3
  20. swift/cli/recon.py +196 -67
  21. swift-2.23.2.data/scripts/swift-recon-cron → swift/cli/recon_cron.py +17 -20
  22. swift-2.23.2.data/scripts/swift-reconciler-enqueue → swift/cli/reconciler_enqueue.py +2 -3
  23. swift/cli/relinker.py +807 -126
  24. swift/cli/reload.py +135 -0
  25. swift/cli/ringbuilder.py +217 -20
  26. swift/cli/ringcomposer.py +0 -1
  27. swift/cli/shard-info.py +4 -3
  28. swift/common/base_storage_server.py +9 -20
  29. swift/common/bufferedhttp.py +48 -74
  30. swift/common/constraints.py +20 -15
  31. swift/common/container_sync_realms.py +9 -11
  32. swift/common/daemon.py +25 -8
  33. swift/common/db.py +198 -127
  34. swift/common/db_auditor.py +168 -0
  35. swift/common/db_replicator.py +95 -55
  36. swift/common/digest.py +141 -0
  37. swift/common/direct_client.py +144 -33
  38. swift/common/error_limiter.py +93 -0
  39. swift/common/exceptions.py +25 -1
  40. swift/common/header_key_dict.py +2 -9
  41. swift/common/http_protocol.py +373 -0
  42. swift/common/internal_client.py +129 -59
  43. swift/common/linkat.py +3 -4
  44. swift/common/manager.py +284 -67
  45. swift/common/memcached.py +396 -147
  46. swift/common/middleware/__init__.py +4 -0
  47. swift/common/middleware/account_quotas.py +211 -46
  48. swift/common/middleware/acl.py +3 -8
  49. swift/common/middleware/backend_ratelimit.py +230 -0
  50. swift/common/middleware/bulk.py +22 -34
  51. swift/common/middleware/catch_errors.py +1 -3
  52. swift/common/middleware/cname_lookup.py +6 -11
  53. swift/common/middleware/container_quotas.py +1 -1
  54. swift/common/middleware/container_sync.py +39 -17
  55. swift/common/middleware/copy.py +12 -0
  56. swift/common/middleware/crossdomain.py +22 -9
  57. swift/common/middleware/crypto/__init__.py +2 -1
  58. swift/common/middleware/crypto/crypto_utils.py +11 -15
  59. swift/common/middleware/crypto/decrypter.py +28 -11
  60. swift/common/middleware/crypto/encrypter.py +12 -17
  61. swift/common/middleware/crypto/keymaster.py +8 -15
  62. swift/common/middleware/crypto/kms_keymaster.py +2 -1
  63. swift/common/middleware/dlo.py +15 -11
  64. swift/common/middleware/domain_remap.py +5 -4
  65. swift/common/middleware/etag_quoter.py +128 -0
  66. swift/common/middleware/formpost.py +73 -70
  67. swift/common/middleware/gatekeeper.py +8 -1
  68. swift/common/middleware/keystoneauth.py +33 -3
  69. swift/common/middleware/list_endpoints.py +4 -4
  70. swift/common/middleware/listing_formats.py +85 -49
  71. swift/common/middleware/memcache.py +4 -81
  72. swift/common/middleware/name_check.py +3 -2
  73. swift/common/middleware/proxy_logging.py +160 -92
  74. swift/common/middleware/ratelimit.py +17 -10
  75. swift/common/middleware/read_only.py +6 -4
  76. swift/common/middleware/recon.py +59 -22
  77. swift/common/middleware/s3api/acl_handlers.py +25 -3
  78. swift/common/middleware/s3api/acl_utils.py +6 -1
  79. swift/common/middleware/s3api/controllers/__init__.py +6 -0
  80. swift/common/middleware/s3api/controllers/acl.py +3 -2
  81. swift/common/middleware/s3api/controllers/bucket.py +242 -137
  82. swift/common/middleware/s3api/controllers/logging.py +2 -2
  83. swift/common/middleware/s3api/controllers/multi_delete.py +43 -20
  84. swift/common/middleware/s3api/controllers/multi_upload.py +219 -133
  85. swift/common/middleware/s3api/controllers/obj.py +112 -8
  86. swift/common/middleware/s3api/controllers/object_lock.py +44 -0
  87. swift/common/middleware/s3api/controllers/s3_acl.py +2 -2
  88. swift/common/middleware/s3api/controllers/tagging.py +57 -0
  89. swift/common/middleware/s3api/controllers/versioning.py +36 -7
  90. swift/common/middleware/s3api/etree.py +22 -9
  91. swift/common/middleware/s3api/exception.py +0 -4
  92. swift/common/middleware/s3api/s3api.py +113 -41
  93. swift/common/middleware/s3api/s3request.py +384 -218
  94. swift/common/middleware/s3api/s3response.py +126 -23
  95. swift/common/middleware/s3api/s3token.py +16 -17
  96. swift/common/middleware/s3api/schema/delete.rng +1 -1
  97. swift/common/middleware/s3api/subresource.py +7 -10
  98. swift/common/middleware/s3api/utils.py +27 -10
  99. swift/common/middleware/slo.py +665 -358
  100. swift/common/middleware/staticweb.py +64 -37
  101. swift/common/middleware/symlink.py +52 -19
  102. swift/common/middleware/tempauth.py +76 -58
  103. swift/common/middleware/tempurl.py +192 -174
  104. swift/common/middleware/versioned_writes/__init__.py +51 -0
  105. swift/common/middleware/{versioned_writes.py → versioned_writes/legacy.py} +27 -26
  106. swift/common/middleware/versioned_writes/object_versioning.py +1482 -0
  107. swift/common/middleware/x_profile/exceptions.py +1 -4
  108. swift/common/middleware/x_profile/html_viewer.py +18 -19
  109. swift/common/middleware/x_profile/profile_model.py +1 -2
  110. swift/common/middleware/xprofile.py +10 -10
  111. swift-2.23.2.data/scripts/swift-container-server → swift/common/recon.py +13 -8
  112. swift/common/registry.py +147 -0
  113. swift/common/request_helpers.py +324 -57
  114. swift/common/ring/builder.py +67 -25
  115. swift/common/ring/composite_builder.py +1 -1
  116. swift/common/ring/ring.py +177 -51
  117. swift/common/ring/utils.py +1 -1
  118. swift/common/splice.py +10 -6
  119. swift/common/statsd_client.py +205 -0
  120. swift/common/storage_policy.py +49 -44
  121. swift/common/swob.py +86 -102
  122. swift/common/{utils.py → utils/__init__.py} +2191 -2762
  123. swift/common/utils/base.py +131 -0
  124. swift/common/utils/config.py +433 -0
  125. swift/common/utils/ipaddrs.py +256 -0
  126. swift/common/utils/libc.py +345 -0
  127. swift/common/utils/logs.py +859 -0
  128. swift/common/utils/timestamp.py +412 -0
  129. swift/common/wsgi.py +555 -536
  130. swift/container/auditor.py +14 -100
  131. swift/container/backend.py +552 -227
  132. swift/container/reconciler.py +126 -37
  133. swift/container/replicator.py +96 -22
  134. swift/container/server.py +397 -176
  135. swift/container/sharder.py +1580 -639
  136. swift/container/sync.py +94 -88
  137. swift/container/updater.py +53 -32
  138. swift/obj/auditor.py +153 -35
  139. swift/obj/diskfile.py +466 -217
  140. swift/obj/expirer.py +406 -124
  141. swift/obj/mem_diskfile.py +7 -4
  142. swift/obj/mem_server.py +1 -0
  143. swift/obj/reconstructor.py +523 -262
  144. swift/obj/replicator.py +249 -188
  145. swift/obj/server.py +213 -122
  146. swift/obj/ssync_receiver.py +145 -85
  147. swift/obj/ssync_sender.py +113 -54
  148. swift/obj/updater.py +653 -139
  149. swift/obj/watchers/__init__.py +0 -0
  150. swift/obj/watchers/dark_data.py +213 -0
  151. swift/proxy/controllers/account.py +11 -11
  152. swift/proxy/controllers/base.py +848 -604
  153. swift/proxy/controllers/container.py +452 -86
  154. swift/proxy/controllers/info.py +3 -2
  155. swift/proxy/controllers/obj.py +1009 -490
  156. swift/proxy/server.py +185 -112
  157. swift-2.35.0.dist-info/AUTHORS +501 -0
  158. swift-2.35.0.dist-info/LICENSE +202 -0
  159. {swift-2.23.2.dist-info → swift-2.35.0.dist-info}/METADATA +52 -61
  160. swift-2.35.0.dist-info/RECORD +201 -0
  161. {swift-2.23.2.dist-info → swift-2.35.0.dist-info}/WHEEL +1 -1
  162. {swift-2.23.2.dist-info → swift-2.35.0.dist-info}/entry_points.txt +43 -0
  163. swift-2.35.0.dist-info/pbr.json +1 -0
  164. swift/locale/de/LC_MESSAGES/swift.po +0 -1216
  165. swift/locale/en_GB/LC_MESSAGES/swift.po +0 -1207
  166. swift/locale/es/LC_MESSAGES/swift.po +0 -1085
  167. swift/locale/fr/LC_MESSAGES/swift.po +0 -909
  168. swift/locale/it/LC_MESSAGES/swift.po +0 -894
  169. swift/locale/ja/LC_MESSAGES/swift.po +0 -965
  170. swift/locale/ko_KR/LC_MESSAGES/swift.po +0 -964
  171. swift/locale/pt_BR/LC_MESSAGES/swift.po +0 -881
  172. swift/locale/ru/LC_MESSAGES/swift.po +0 -891
  173. swift/locale/tr_TR/LC_MESSAGES/swift.po +0 -832
  174. swift/locale/zh_CN/LC_MESSAGES/swift.po +0 -833
  175. swift/locale/zh_TW/LC_MESSAGES/swift.po +0 -838
  176. swift-2.23.2.data/scripts/swift-account-auditor +0 -23
  177. swift-2.23.2.data/scripts/swift-account-info +0 -51
  178. swift-2.23.2.data/scripts/swift-account-reaper +0 -23
  179. swift-2.23.2.data/scripts/swift-account-replicator +0 -34
  180. swift-2.23.2.data/scripts/swift-account-server +0 -23
  181. swift-2.23.2.data/scripts/swift-container-auditor +0 -23
  182. swift-2.23.2.data/scripts/swift-container-info +0 -51
  183. swift-2.23.2.data/scripts/swift-container-reconciler +0 -21
  184. swift-2.23.2.data/scripts/swift-container-replicator +0 -34
  185. swift-2.23.2.data/scripts/swift-container-sharder +0 -33
  186. swift-2.23.2.data/scripts/swift-container-sync +0 -23
  187. swift-2.23.2.data/scripts/swift-container-updater +0 -23
  188. swift-2.23.2.data/scripts/swift-dispersion-report +0 -24
  189. swift-2.23.2.data/scripts/swift-form-signature +0 -20
  190. swift-2.23.2.data/scripts/swift-init +0 -119
  191. swift-2.23.2.data/scripts/swift-object-auditor +0 -29
  192. swift-2.23.2.data/scripts/swift-object-expirer +0 -33
  193. swift-2.23.2.data/scripts/swift-object-info +0 -60
  194. swift-2.23.2.data/scripts/swift-object-reconstructor +0 -33
  195. swift-2.23.2.data/scripts/swift-object-relinker +0 -41
  196. swift-2.23.2.data/scripts/swift-object-replicator +0 -37
  197. swift-2.23.2.data/scripts/swift-object-server +0 -27
  198. swift-2.23.2.data/scripts/swift-object-updater +0 -23
  199. swift-2.23.2.data/scripts/swift-proxy-server +0 -23
  200. swift-2.23.2.data/scripts/swift-recon +0 -24
  201. swift-2.23.2.data/scripts/swift-ring-builder +0 -24
  202. swift-2.23.2.data/scripts/swift-ring-builder-analyzer +0 -22
  203. swift-2.23.2.data/scripts/swift-ring-composer +0 -22
  204. swift-2.23.2.dist-info/DESCRIPTION.rst +0 -166
  205. swift-2.23.2.dist-info/RECORD +0 -220
  206. swift-2.23.2.dist-info/metadata.json +0 -1
  207. swift-2.23.2.dist-info/pbr.json +0 -1
  208. {swift-2.23.2.dist-info → swift-2.35.0.dist-info}/top_level.txt +0 -0
@@ -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 eventlet
35
- from eventlet.green.httplib import CONTINUE, HTTPConnection, HTTPMessage, \
36
- HTTPResponse, HTTPSConnection, _UNKNOWN
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
- if six.PY2:
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
- httplib._MAXHEADERS = constraints.MAX_HEADER_COUNT * 1.6
51
- green_httplib._MAXHEADERS = constraints.MAX_HEADER_COUNT * 1.6
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
- # sock is an eventlet.greenio.GreenSocket
61
- if six.PY2:
62
- # sock.fd is a socket._socketobject
63
- # sock.fd._sock is a _socket.socket object, which is what we want.
64
- self._real_socket = sock.fd._sock
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
- self.fp = sock.makefile('rb')
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.headers = self.msg = None
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
- if not six.PY2:
87
- def begin(self):
88
- HTTPResponse.begin(self)
89
- header_payload = self.headers.get_payload()
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
- self.headers.add_header(header, value)
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
- if six.PY2:
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
- if six.PY2:
180
- # this is idempotent; see sock_close in Modules/socketmodule.c
181
- # in the Python source for details.
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, six.text_type):
239
+ if isinstance(path, str):
262
240
  path = path.encode("utf-8")
263
- if isinstance(device, six.text_type):
241
+ if isinstance(device, str):
264
242
  device = device.encode("utf-8")
265
- if isinstance(partition, six.text_type):
243
+ if isinstance(partition, str):
266
244
  partition = partition.encode('utf-8')
267
- elif isinstance(partition, six.integer_types):
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
- if six.PY2:
299
- query_string = urlencode(parse_qsl(
300
- query_string, keep_blank_values=True))
301
- else:
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))
@@ -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 six
21
- from six.moves.configparser import ConfigParser, NoSectionError, NoOptionError
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
- try:
89
- value = int(value)
90
- except ValueError:
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, six.string_types)
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 null character.
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, six.text_type):
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
- return b'\x00' not in encoded
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 six
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(_('Could not load %(conf)r: %(error)s') % {
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
- _('Could not load %(conf)r: %(error)s')
72
- % {'conf': self.conf_path, 'error': err})
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.getint(
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
- _('Error in %(conf)r with '
86
- 'mtime_check_interval: %(error)s')
87
- % {'conf': self.conf_path, 'error': err})
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, six.text_type):
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.info('SIGTERM received')
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(0.1)
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 is '':
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
- use_hub(utils.get_hub())
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
- DaemonStrategy(klass(conf), logger).run(once=once, **kwargs)
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