swift 2.23.3__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 (206) 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.3.data/scripts/swift-account-audit → swift/cli/account_audit.py +23 -13
  9. swift-2.23.3.data/scripts/swift-config → swift/cli/config.py +2 -2
  10. swift/cli/container_deleter.py +5 -11
  11. swift-2.23.3.data/scripts/swift-dispersion-populate → swift/cli/dispersion_populate.py +8 -7
  12. swift/cli/dispersion_report.py +10 -9
  13. swift-2.23.3.data/scripts/swift-drive-audit → swift/cli/drive_audit.py +63 -21
  14. swift/cli/form_signature.py +3 -7
  15. swift-2.23.3.data/scripts/swift-get-nodes → swift/cli/get_nodes.py +8 -2
  16. swift/cli/info.py +154 -14
  17. swift/cli/manage_shard_ranges.py +705 -37
  18. swift-2.23.3.data/scripts/swift-oldies → swift/cli/oldies.py +25 -14
  19. swift-2.23.3.data/scripts/swift-orphans → swift/cli/orphans.py +7 -3
  20. swift/cli/recon.py +196 -67
  21. swift-2.23.3.data/scripts/swift-recon-cron → swift/cli/recon_cron.py +17 -20
  22. swift-2.23.3.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 +195 -128
  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 +390 -145
  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 -95
  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 +51 -18
  102. swift/common/middleware/tempauth.py +76 -58
  103. swift/common/middleware/tempurl.py +191 -173
  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.3.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} +2163 -2772
  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 +553 -535
  130. swift/container/auditor.py +14 -100
  131. swift/container/backend.py +490 -231
  132. swift/container/reconciler.py +126 -37
  133. swift/container/replicator.py +96 -22
  134. swift/container/server.py +358 -165
  135. swift/container/sharder.py +1540 -684
  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 +207 -122
  146. swift/obj/ssync_receiver.py +145 -85
  147. swift/obj/ssync_sender.py +113 -54
  148. swift/obj/updater.py +652 -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 +433 -92
  154. swift/proxy/controllers/info.py +3 -2
  155. swift/proxy/controllers/obj.py +1000 -489
  156. swift/proxy/server.py +185 -112
  157. {swift-2.23.3.dist-info → swift-2.35.0.dist-info}/AUTHORS +58 -11
  158. {swift-2.23.3.dist-info → swift-2.35.0.dist-info}/METADATA +51 -56
  159. swift-2.35.0.dist-info/RECORD +201 -0
  160. {swift-2.23.3.dist-info → swift-2.35.0.dist-info}/WHEEL +1 -1
  161. {swift-2.23.3.dist-info → swift-2.35.0.dist-info}/entry_points.txt +43 -0
  162. swift-2.35.0.dist-info/pbr.json +1 -0
  163. swift/locale/de/LC_MESSAGES/swift.po +0 -1216
  164. swift/locale/en_GB/LC_MESSAGES/swift.po +0 -1207
  165. swift/locale/es/LC_MESSAGES/swift.po +0 -1085
  166. swift/locale/fr/LC_MESSAGES/swift.po +0 -909
  167. swift/locale/it/LC_MESSAGES/swift.po +0 -894
  168. swift/locale/ja/LC_MESSAGES/swift.po +0 -965
  169. swift/locale/ko_KR/LC_MESSAGES/swift.po +0 -964
  170. swift/locale/pt_BR/LC_MESSAGES/swift.po +0 -881
  171. swift/locale/ru/LC_MESSAGES/swift.po +0 -891
  172. swift/locale/tr_TR/LC_MESSAGES/swift.po +0 -832
  173. swift/locale/zh_CN/LC_MESSAGES/swift.po +0 -833
  174. swift/locale/zh_TW/LC_MESSAGES/swift.po +0 -838
  175. swift-2.23.3.data/scripts/swift-account-auditor +0 -23
  176. swift-2.23.3.data/scripts/swift-account-info +0 -51
  177. swift-2.23.3.data/scripts/swift-account-reaper +0 -23
  178. swift-2.23.3.data/scripts/swift-account-replicator +0 -34
  179. swift-2.23.3.data/scripts/swift-account-server +0 -23
  180. swift-2.23.3.data/scripts/swift-container-auditor +0 -23
  181. swift-2.23.3.data/scripts/swift-container-info +0 -55
  182. swift-2.23.3.data/scripts/swift-container-reconciler +0 -21
  183. swift-2.23.3.data/scripts/swift-container-replicator +0 -34
  184. swift-2.23.3.data/scripts/swift-container-sharder +0 -37
  185. swift-2.23.3.data/scripts/swift-container-sync +0 -23
  186. swift-2.23.3.data/scripts/swift-container-updater +0 -23
  187. swift-2.23.3.data/scripts/swift-dispersion-report +0 -24
  188. swift-2.23.3.data/scripts/swift-form-signature +0 -20
  189. swift-2.23.3.data/scripts/swift-init +0 -119
  190. swift-2.23.3.data/scripts/swift-object-auditor +0 -29
  191. swift-2.23.3.data/scripts/swift-object-expirer +0 -33
  192. swift-2.23.3.data/scripts/swift-object-info +0 -60
  193. swift-2.23.3.data/scripts/swift-object-reconstructor +0 -33
  194. swift-2.23.3.data/scripts/swift-object-relinker +0 -41
  195. swift-2.23.3.data/scripts/swift-object-replicator +0 -37
  196. swift-2.23.3.data/scripts/swift-object-server +0 -27
  197. swift-2.23.3.data/scripts/swift-object-updater +0 -23
  198. swift-2.23.3.data/scripts/swift-proxy-server +0 -23
  199. swift-2.23.3.data/scripts/swift-recon +0 -24
  200. swift-2.23.3.data/scripts/swift-ring-builder +0 -24
  201. swift-2.23.3.data/scripts/swift-ring-builder-analyzer +0 -22
  202. swift-2.23.3.data/scripts/swift-ring-composer +0 -22
  203. swift-2.23.3.dist-info/RECORD +0 -220
  204. swift-2.23.3.dist-info/pbr.json +0 -1
  205. {swift-2.23.3.dist-info → swift-2.35.0.dist-info}/LICENSE +0 -0
  206. {swift-2.23.3.dist-info → swift-2.35.0.dist-info}/top_level.txt +0 -0
swift/container/sync.py CHANGED
@@ -17,84 +17,59 @@ import collections
17
17
  import errno
18
18
  import os
19
19
  import uuid
20
- from swift import gettext_ as _
21
20
  from time import ctime, time
22
21
  from random import choice, random
23
22
  from struct import unpack_from
24
23
 
25
24
  from eventlet import sleep, Timeout
26
- from six.moves.urllib.parse import urlparse
25
+ from urllib.parse import urlparse
27
26
 
28
27
  import swift.common.db
29
28
  from swift.common.db import DatabaseConnectionError
30
29
  from swift.container.backend import ContainerBroker
31
30
  from swift.container.sync_store import ContainerSyncStore
32
31
  from swift.common.container_sync_realms import ContainerSyncRealms
32
+ from swift.common.daemon import run_daemon
33
33
  from swift.common.internal_client import (
34
34
  delete_object, put_object, head_object,
35
35
  InternalClient, UnexpectedResponse)
36
36
  from swift.common.exceptions import ClientException
37
37
  from swift.common.ring import Ring
38
38
  from swift.common.ring.utils import is_local_device
39
+ from swift.common.swob import normalize_etag
39
40
  from swift.common.utils import (
40
41
  clean_content_type, config_true_value,
41
42
  FileLikeIter, get_logger, hash_path, quote, validate_sync_to,
42
- whataremyips, Timestamp, decode_timestamps)
43
+ whataremyips, Timestamp, decode_timestamps, parse_options)
43
44
  from swift.common.daemon import Daemon
44
- from swift.common.http import HTTP_UNAUTHORIZED, HTTP_NOT_FOUND
45
+ from swift.common.http import HTTP_UNAUTHORIZED, HTTP_NOT_FOUND, HTTP_CONFLICT
45
46
  from swift.common.wsgi import ConfigString
47
+ from swift.common.middleware.versioned_writes.object_versioning import (
48
+ SYSMETA_VERSIONS_CONT, SYSMETA_VERSIONS_SYMLINK)
46
49
 
47
50
 
48
51
  # The default internal client config body is to support upgrades without
49
52
  # requiring deployment of the new /etc/swift/internal-client.conf
50
53
  ic_conf_body = """
51
54
  [DEFAULT]
52
- # swift_dir = /etc/swift
53
- # user = swift
54
- # You can specify default log routing here if you want:
55
- # log_name = swift
56
- # log_facility = LOG_LOCAL0
57
- # log_level = INFO
58
- # log_address = /dev/log
59
- #
60
- # comma separated list of functions to call to setup custom log handlers.
61
- # functions get passed: conf, name, log_to_console, log_route, fmt, logger,
62
- # adapted_logger
63
- # log_custom_handlers =
64
- #
65
- # If set, log_udp_host will override log_address
66
- # log_udp_host =
67
- # log_udp_port = 514
68
- #
69
- # You can enable StatsD logging here:
70
- # log_statsd_host =
71
- # log_statsd_port = 8125
72
- # log_statsd_default_sample_rate = 1.0
73
- # log_statsd_sample_rate_factor = 1.0
74
- # log_statsd_metric_prefix =
75
-
76
55
  [pipeline:main]
77
56
  pipeline = catch_errors proxy-logging cache symlink proxy-server
78
57
 
79
58
  [app:proxy-server]
80
59
  use = egg:swift#proxy
81
60
  account_autocreate = true
82
- # See proxy-server.conf-sample for options
83
61
 
84
62
  [filter:symlink]
85
63
  use = egg:swift#symlink
86
- # See proxy-server.conf-sample for options
87
64
 
88
65
  [filter:cache]
89
66
  use = egg:swift#memcache
90
- # See proxy-server.conf-sample for options
91
67
 
92
68
  [filter:proxy-logging]
93
69
  use = egg:swift#proxy_logging
94
70
 
95
71
  [filter:catch_errors]
96
72
  use = egg:swift#catch_errors
97
- # See proxy-server.conf-sample for options
98
73
  """.lstrip()
99
74
 
100
75
 
@@ -122,28 +97,28 @@ class ContainerSync(Daemon):
122
97
  An example may help. Assume replica count is 3 and perfectly matching
123
98
  ROWIDs starting at 1.
124
99
 
125
- First sync run, database has 6 rows:
126
-
127
- * SyncPoint1 starts as -1.
128
- * SyncPoint2 starts as -1.
129
- * No rows between points, so no "all updates" rows.
130
- * Six rows newer than SyncPoint1, so a third of the rows are sent
131
- by node 1, another third by node 2, remaining third by node 3.
132
- * SyncPoint1 is set as 6 (the newest ROWID known).
133
- * SyncPoint2 is left as -1 since no "all updates" rows were synced.
134
-
135
- Next sync run, database has 12 rows:
136
-
137
- * SyncPoint1 starts as 6.
138
- * SyncPoint2 starts as -1.
139
- * The rows between -1 and 6 all trigger updates (most of which
140
- should short-circuit on the remote end as having already been
141
- done).
142
- * Six more rows newer than SyncPoint1, so a third of the rows are
143
- sent by node 1, another third by node 2, remaining third by node
144
- 3.
145
- * SyncPoint1 is set as 12 (the newest ROWID known).
146
- * SyncPoint2 is set as 6 (the newest "all updates" ROWID).
100
+ First sync run, database has 6 rows:
101
+
102
+ * SyncPoint1 starts as -1.
103
+ * SyncPoint2 starts as -1.
104
+ * No rows between points, so no "all updates" rows.
105
+ * Six rows newer than SyncPoint1, so a third of the rows are sent
106
+ by node 1, another third by node 2, remaining third by node 3.
107
+ * SyncPoint1 is set as 6 (the newest ROWID known).
108
+ * SyncPoint2 is left as -1 since no "all updates" rows were synced.
109
+
110
+ Next sync run, database has 12 rows:
111
+
112
+ * SyncPoint1 starts as 6.
113
+ * SyncPoint2 starts as -1.
114
+ * The rows between -1 and 6 all trigger updates (most of which
115
+ should short-circuit on the remote end as having already been
116
+ done).
117
+ * Six more rows newer than SyncPoint1, so a third of the rows are
118
+ sent by node 1, another third by node 2, remaining third by node
119
+ 3.
120
+ * SyncPoint1 is set as 12 (the newest ROWID known).
121
+ * SyncPoint2 is set as 6 (the newest "all updates" ROWID).
147
122
 
148
123
  In this way, under normal circumstances each node sends its share of
149
124
  updates each run and just sends a batch of older updates to ensure nothing
@@ -154,13 +129,14 @@ class ContainerSync(Daemon):
154
129
  :param container_ring: If None, the <swift_dir>/container.ring.gz will be
155
130
  loaded. This is overridden by unit tests.
156
131
  """
132
+ log_route = 'container-sync'
157
133
 
158
134
  def __init__(self, conf, container_ring=None, logger=None):
159
135
  #: The dict of configuration values from the [container-sync] section
160
136
  #: of the container-server.conf.
161
137
  self.conf = conf
162
138
  #: Logger to use for container-sync log lines.
163
- self.logger = logger or get_logger(conf, log_route='container-sync')
139
+ self.logger = logger or get_logger(conf, log_route=self.log_route)
164
140
  #: Path to the local device mount points.
165
141
  self.devices = conf.get('devices', '/srv/node')
166
142
  #: Indicates whether mount points should be verified as actual mount
@@ -168,7 +144,7 @@ class ContainerSync(Daemon):
168
144
  self.mount_check = config_true_value(conf.get('mount_check', 'true'))
169
145
  #: Minimum time between full scans. This is to keep the daemon from
170
146
  #: running wild on near empty systems.
171
- self.interval = int(conf.get('interval', 300))
147
+ self.interval = float(conf.get('interval', 300))
172
148
  #: Maximum amount of time to spend syncing a container before moving on
173
149
  #: to the next one. If a container sync hasn't finished in this time,
174
150
  #: it'll just be resumed next scan.
@@ -230,22 +206,25 @@ class ContainerSync(Daemon):
230
206
  internal_client_conf_path = conf.get('internal_client_conf_path')
231
207
  if not internal_client_conf_path:
232
208
  self.logger.warning(
233
- _('Configuration option internal_client_conf_path not '
234
- 'defined. Using default configuration, See '
235
- 'internal-client.conf-sample for options'))
209
+ 'Configuration option internal_client_conf_path not '
210
+ 'defined. Using default configuration, See '
211
+ 'internal-client.conf-sample for options')
236
212
  internal_client_conf = ConfigString(ic_conf_body)
237
213
  else:
238
214
  internal_client_conf = internal_client_conf_path
239
215
  try:
240
216
  self.swift = InternalClient(
241
- internal_client_conf, 'Swift Container Sync', request_tries)
217
+ internal_client_conf, 'Swift Container Sync', request_tries,
218
+ use_replication_network=True,
219
+ global_conf={'log_name': '%s-ic' % conf.get(
220
+ 'log_name', self.log_route)})
242
221
  except (OSError, IOError) as err:
243
222
  if err.errno != errno.ENOENT and \
244
223
  not str(err).endswith(' not found'):
245
224
  raise
246
225
  raise SystemExit(
247
- _('Unable to load internal client from config: '
248
- '%(conf)r (%(error)s)')
226
+ 'Unable to load internal client from config: '
227
+ '%(conf)r (%(error)s)'
249
228
  % {'conf': internal_client_conf_path, 'error': err})
250
229
 
251
230
  def run_forever(self, *args, **kwargs):
@@ -268,7 +247,7 @@ class ContainerSync(Daemon):
268
247
  """
269
248
  Runs a single container sync scan.
270
249
  """
271
- self.logger.info(_('Begin container sync "once" mode'))
250
+ self.logger.info('Begin container sync "once" mode')
272
251
  begin = time()
273
252
  for path in self.sync_store.synced_containers_generator():
274
253
  self.container_sync(path)
@@ -277,7 +256,7 @@ class ContainerSync(Daemon):
277
256
  self.report()
278
257
  elapsed = time() - begin
279
258
  self.logger.info(
280
- _('Container sync "once" mode completed: %.02fs'), elapsed)
259
+ 'Container sync "once" mode completed: %.02fs', elapsed)
281
260
 
282
261
  def report(self):
283
262
  """
@@ -285,8 +264,8 @@ class ContainerSync(Daemon):
285
264
  next report.
286
265
  """
287
266
  self.logger.info(
288
- _('Since %(time)s: %(sync)s synced [%(delete)s deletes, %(put)s '
289
- 'puts], %(skip)s skipped, %(fail)s failed'),
267
+ 'Since %(time)s: %(sync)s synced [%(delete)s deletes, %(put)s '
268
+ 'puts], %(skip)s skipped, %(fail)s failed',
290
269
  {'time': ctime(self.reported),
291
270
  'sync': self.container_syncs,
292
271
  'delete': self.container_deletes,
@@ -302,16 +281,16 @@ class ContainerSync(Daemon):
302
281
 
303
282
  def container_report(self, start, end, sync_point1, sync_point2, info,
304
283
  max_row):
305
- self.logger.info(_('Container sync report: %(container)s, '
306
- 'time window start: %(start)s, '
307
- 'time window end: %(end)s, '
308
- 'puts: %(puts)s, '
309
- 'posts: %(posts)s, '
310
- 'deletes: %(deletes)s, '
311
- 'bytes: %(bytes)s, '
312
- 'sync_point1: %(point1)s, '
313
- 'sync_point2: %(point2)s, '
314
- 'total_rows: %(total)s'),
284
+ self.logger.info('Container sync report: %(container)s, '
285
+ 'time window start: %(start)s, '
286
+ 'time window end: %(end)s, '
287
+ 'puts: %(puts)s, '
288
+ 'posts: %(posts)s, '
289
+ 'deletes: %(deletes)s, '
290
+ 'bytes: %(bytes)s, '
291
+ 'sync_point1: %(point1)s, '
292
+ 'sync_point2: %(point2)s, '
293
+ 'total_rows: %(total)s',
315
294
  {'container': '%s/%s' % (info['account'],
316
295
  info['container']),
317
296
  'start': start,
@@ -357,6 +336,13 @@ class ContainerSync(Daemon):
357
336
  break
358
337
  else:
359
338
  return
339
+ if broker.metadata.get(SYSMETA_VERSIONS_CONT):
340
+ self.container_skips += 1
341
+ self.logger.increment('skips')
342
+ self.logger.warning('Skipping container %s/%s with '
343
+ 'object versioning configured' % (
344
+ info['account'], info['container']))
345
+ return
360
346
  if not broker.is_deleted():
361
347
  sync_to = None
362
348
  user_key = None
@@ -375,7 +361,7 @@ class ContainerSync(Daemon):
375
361
  sync_to, self.allowed_sync_hosts, self.realms_conf)
376
362
  if err:
377
363
  self.logger.info(
378
- _('ERROR %(db_file)s: %(validate_sync_to_err)s'),
364
+ 'ERROR %(db_file)s: %(validate_sync_to_err)s',
379
365
  {'db_file': str(broker),
380
366
  'validate_sync_to_err': err})
381
367
  self.container_failures += 1
@@ -444,7 +430,7 @@ class ContainerSync(Daemon):
444
430
  except (Exception, Timeout):
445
431
  self.container_failures += 1
446
432
  self.logger.increment('failures')
447
- self.logger.exception(_('ERROR Syncing %s'),
433
+ self.logger.exception('ERROR Syncing %s',
448
434
  broker if broker else path)
449
435
 
450
436
  def _update_sync_to_headers(self, name, sync_to, user_key,
@@ -560,7 +546,8 @@ class ContainerSync(Daemon):
560
546
  logger=self.logger,
561
547
  timeout=self.conn_timeout)
562
548
  except ClientException as err:
563
- if err.http_status != HTTP_NOT_FOUND:
549
+ if err.http_status not in (
550
+ HTTP_NOT_FOUND, HTTP_CONFLICT):
564
551
  raise
565
552
  self.container_deletes += 1
566
553
  self.container_stats['deletes'] += 1
@@ -593,13 +580,23 @@ class ContainerSync(Daemon):
593
580
  headers = {}
594
581
  body = None
595
582
  exc = err
583
+
584
+ # skip object_versioning links; this is in case the container
585
+ # metadata is out of date
586
+ if headers.get(SYSMETA_VERSIONS_SYMLINK):
587
+ self.logger.info(
588
+ 'Skipping versioning symlink %s/%s/%s ' % (
589
+ info['account'], info['container'],
590
+ row['name']))
591
+ return True
592
+
596
593
  timestamp = Timestamp(headers.get('x-timestamp', 0))
597
594
  if timestamp < ts_meta:
598
595
  if exc:
599
596
  raise exc
600
597
  raise Exception(
601
- _('Unknown exception trying to GET: '
602
- '%(account)r %(container)r %(object)r'),
598
+ 'Unknown exception trying to GET: '
599
+ '%(account)r %(container)r %(object)r' %
603
600
  {'account': info['account'],
604
601
  'container': info['container'],
605
602
  'object': row['name']})
@@ -607,7 +604,7 @@ class ContainerSync(Daemon):
607
604
  if key in headers:
608
605
  del headers[key]
609
606
  if 'etag' in headers:
610
- headers['etag'] = headers['etag'].strip('"')
607
+ headers['etag'] = normalize_etag(headers['etag'])
611
608
  if 'content-type' in headers:
612
609
  headers['content-type'] = clean_content_type(
613
610
  headers['content-type'])
@@ -625,27 +622,27 @@ class ContainerSync(Daemon):
625
622
  except ClientException as err:
626
623
  if err.http_status == HTTP_UNAUTHORIZED:
627
624
  self.logger.info(
628
- _('Unauth %(sync_from)r => %(sync_to)r'),
625
+ 'Unauth %(sync_from)r => %(sync_to)r',
629
626
  {'sync_from': '%s/%s' %
630
627
  (quote(info['account']), quote(info['container'])),
631
628
  'sync_to': sync_to})
632
629
  elif err.http_status == HTTP_NOT_FOUND:
633
630
  self.logger.info(
634
- _('Not found %(sync_from)r => %(sync_to)r \
635
- - object %(obj_name)r'),
631
+ 'Not found %(sync_from)r => %(sync_to)r \
632
+ - object %(obj_name)r',
636
633
  {'sync_from': '%s/%s' %
637
634
  (quote(info['account']), quote(info['container'])),
638
635
  'sync_to': sync_to, 'obj_name': row['name']})
639
636
  else:
640
637
  self.logger.exception(
641
- _('ERROR Syncing %(db_file)s %(row)s'),
638
+ 'ERROR Syncing %(db_file)s %(row)s',
642
639
  {'db_file': str(broker), 'row': row})
643
640
  self.container_failures += 1
644
641
  self.logger.increment('failures')
645
642
  return False
646
- except (Exception, Timeout) as err:
643
+ except (Exception, Timeout):
647
644
  self.logger.exception(
648
- _('ERROR Syncing %(db_file)s %(row)s'),
645
+ 'ERROR Syncing %(db_file)s %(row)s',
649
646
  {'db_file': str(broker), 'row': row})
650
647
  self.container_failures += 1
651
648
  self.logger.increment('failures')
@@ -654,3 +651,12 @@ class ContainerSync(Daemon):
654
651
 
655
652
  def select_http_proxy(self):
656
653
  return choice(self.http_proxies) if self.http_proxies else None
654
+
655
+
656
+ def main():
657
+ conf_file, options = parse_options(once=True)
658
+ run_daemon(ContainerSync, conf_file, **options)
659
+
660
+
661
+ if __name__ == '__main__':
662
+ main()
@@ -13,13 +13,11 @@
13
13
  # See the License for the specific language governing permissions and
14
14
  # limitations under the License.
15
15
 
16
- from __future__ import print_function
17
16
  import logging
18
17
  import os
19
18
  import signal
20
19
  import sys
21
20
  import time
22
- from swift import gettext_ as _
23
21
  from random import random, shuffle
24
22
  from tempfile import mkstemp
25
23
 
@@ -32,10 +30,11 @@ from swift.common.bufferedhttp import http_connect
32
30
  from swift.common.exceptions import ConnectionTimeout, LockTimeout
33
31
  from swift.common.ring import Ring
34
32
  from swift.common.utils import get_logger, config_true_value, \
35
- dump_recon_cache, majority_size, Timestamp, ratelimit_sleep, \
36
- eventlet_monkey_patch
37
- from swift.common.daemon import Daemon
33
+ dump_recon_cache, majority_size, Timestamp, EventletRateLimiter, \
34
+ eventlet_monkey_patch, node_to_string, parse_options
35
+ from swift.common.daemon import Daemon, run_daemon
38
36
  from swift.common.http import is_success, HTTP_INTERNAL_SERVER_ERROR
37
+ from swift.common.recon import RECON_CONTAINER_FILE, DEFAULT_RECON_CACHE_PATH
39
38
 
40
39
 
41
40
  class ContainerUpdater(Daemon):
@@ -47,7 +46,7 @@ class ContainerUpdater(Daemon):
47
46
  self.devices = conf.get('devices', '/srv/node')
48
47
  self.mount_check = config_true_value(conf.get('mount_check', 'true'))
49
48
  self.swift_dir = conf.get('swift_dir', '/etc/swift')
50
- self.interval = int(conf.get('interval', 300))
49
+ self.interval = float(conf.get('interval', 300))
51
50
  self.account_ring = None
52
51
  self.concurrency = int(conf.get('concurrency', 4))
53
52
  if 'slowdown' in conf:
@@ -59,10 +58,10 @@ class ContainerUpdater(Daemon):
59
58
  float(conf.get('slowdown', '0.01')) + 0.01)
60
59
  else:
61
60
  containers_per_second = 50
62
- self.containers_running_time = 0
63
61
  self.max_containers_per_second = \
64
62
  float(conf.get('containers_per_second',
65
63
  containers_per_second))
64
+ self.rate_limiter = EventletRateLimiter(self.max_containers_per_second)
66
65
  self.node_timeout = float(conf.get('node_timeout', 3))
67
66
  self.conn_timeout = float(conf.get('conn_timeout', 0.5))
68
67
  self.no_changes = 0
@@ -75,8 +74,8 @@ class ContainerUpdater(Daemon):
75
74
  swift.common.db.DB_PREALLOCATION = \
76
75
  config_true_value(conf.get('db_preallocation', 'f'))
77
76
  self.recon_cache_path = conf.get('recon_cache_path',
78
- '/var/cache/swift')
79
- self.rcache = os.path.join(self.recon_cache_path, "container.recon")
77
+ DEFAULT_RECON_CACHE_PATH)
78
+ self.rcache = os.path.join(self.recon_cache_path, RECON_CONTAINER_FILE)
80
79
  self.user_agent = 'container-updater %s' % os.getpid()
81
80
 
82
81
  def get_account_ring(self):
@@ -89,8 +88,8 @@ class ContainerUpdater(Daemon):
89
88
  try:
90
89
  return os.listdir(path)
91
90
  except OSError as e:
92
- self.logger.error(_('ERROR: Failed to get paths to drive '
93
- 'partitions: %s') % e)
91
+ self.logger.error('ERROR: Failed to get paths to drive '
92
+ 'partitions: %s', e)
94
93
  return []
95
94
 
96
95
  def get_paths(self):
@@ -123,7 +122,7 @@ class ContainerUpdater(Daemon):
123
122
  self.account_suppressions[account] = until
124
123
  except Exception:
125
124
  self.logger.exception(
126
- _('ERROR with loading suppressions from %s: ') % filename)
125
+ 'ERROR with loading suppressions from %s: ', filename)
127
126
  finally:
128
127
  os.unlink(filename)
129
128
 
@@ -133,7 +132,7 @@ class ContainerUpdater(Daemon):
133
132
  """
134
133
  time.sleep(random() * self.interval)
135
134
  while True:
136
- self.logger.info(_('Begin container update sweep'))
135
+ self.logger.info('Begin container update sweep')
137
136
  begin = time.time()
138
137
  now = time.time()
139
138
  expired_suppressions = \
@@ -158,6 +157,7 @@ class ContainerUpdater(Daemon):
158
157
  pid2filename[pid] = tmpfilename
159
158
  else:
160
159
  signal.signal(signal.SIGTERM, signal.SIG_DFL)
160
+ os.environ.pop('NOTIFY_SOCKET', None)
161
161
  eventlet_monkey_patch()
162
162
  self.no_changes = 0
163
163
  self.successes = 0
@@ -167,9 +167,9 @@ class ContainerUpdater(Daemon):
167
167
  self.container_sweep(path)
168
168
  elapsed = time.time() - forkbegin
169
169
  self.logger.debug(
170
- _('Container update sweep of %(path)s completed: '
171
- '%(elapsed).02fs, %(success)s successes, %(fail)s '
172
- 'failures, %(no_change)s with no changes'),
170
+ 'Container update sweep of %(path)s completed: '
171
+ '%(elapsed).02fs, %(success)s successes, %(fail)s '
172
+ 'failures, %(no_change)s with no changes',
173
173
  {'path': path, 'elapsed': elapsed,
174
174
  'success': self.successes, 'fail': self.failures,
175
175
  'no_change': self.no_changes})
@@ -181,7 +181,7 @@ class ContainerUpdater(Daemon):
181
181
  finally:
182
182
  del pid2filename[pid]
183
183
  elapsed = time.time() - begin
184
- self.logger.info(_('Container update sweep completed: %.02fs'),
184
+ self.logger.info('Container update sweep completed: %.02fs',
185
185
  elapsed)
186
186
  dump_recon_cache({'container_updater_sweep': elapsed},
187
187
  self.rcache, self.logger)
@@ -193,7 +193,7 @@ class ContainerUpdater(Daemon):
193
193
  Run the updater once.
194
194
  """
195
195
  eventlet_monkey_patch()
196
- self.logger.info(_('Begin container update single threaded sweep'))
196
+ self.logger.info('Begin container update single threaded sweep')
197
197
  begin = time.time()
198
198
  self.no_changes = 0
199
199
  self.successes = 0
@@ -201,10 +201,10 @@ class ContainerUpdater(Daemon):
201
201
  for path in self.get_paths():
202
202
  self.container_sweep(path)
203
203
  elapsed = time.time() - begin
204
- self.logger.info(_(
204
+ self.logger.info(
205
205
  'Container update single threaded sweep completed: '
206
206
  '%(elapsed).02fs, %(success)s successes, %(fail)s failures, '
207
- '%(no_change)s with no changes'),
207
+ '%(no_change)s with no changes',
208
208
  {'elapsed': elapsed, 'success': self.successes,
209
209
  'fail': self.failures, 'no_change': self.no_changes})
210
210
  dump_recon_cache({'container_updater_sweep': elapsed},
@@ -226,9 +226,7 @@ class ContainerUpdater(Daemon):
226
226
  self.logger.exception(
227
227
  "Error processing container %s: %s", dbfile, e)
228
228
 
229
- self.containers_running_time = ratelimit_sleep(
230
- self.containers_running_time,
231
- self.max_containers_per_second)
229
+ self.rate_limiter.wait()
232
230
 
233
231
  def process_container(self, dbfile):
234
232
  """
@@ -270,23 +268,36 @@ class ContainerUpdater(Daemon):
270
268
  info['storage_policy_index'])
271
269
  for node in nodes]
272
270
  successes = 0
271
+ stub404s = 0
273
272
  for event in events:
274
- if is_success(event.wait()):
273
+ result = event.wait()
274
+ if is_success(result):
275
275
  successes += 1
276
+ if result == 404:
277
+ stub404s += 1
276
278
  if successes >= majority_size(len(events)):
277
279
  self.logger.increment('successes')
278
280
  self.successes += 1
279
281
  self.logger.debug(
280
- _('Update report sent for %(container)s %(dbfile)s'),
282
+ 'Update report sent for %(container)s %(dbfile)s',
281
283
  {'container': container, 'dbfile': dbfile})
282
284
  broker.reported(info['put_timestamp'],
283
285
  info['delete_timestamp'], info['object_count'],
284
286
  info['bytes_used'])
287
+ elif stub404s == len(events):
288
+ self.logger.increment('failures')
289
+ self.failures += 1
290
+ self.logger.debug(
291
+ 'Update report stub for %(container)s %(dbfile)s',
292
+ {'container': container, 'dbfile': dbfile})
293
+ broker.quarantine('no account replicas exist')
294
+ # All that's left at this point is a few sacks of Gnocchi,
295
+ # easily collected by the dark data watcher in object auditor.
285
296
  else:
286
297
  self.logger.increment('failures')
287
298
  self.failures += 1
288
299
  self.logger.debug(
289
- _('Update report failed for %(container)s %(dbfile)s'),
300
+ 'Update report failed for %(container)s %(dbfile)s',
290
301
  {'container': container, 'dbfile': dbfile})
291
302
  self.account_suppressions[info['account']] = until = \
292
303
  time.time() + self.account_suppression_time
@@ -325,12 +336,12 @@ class ContainerUpdater(Daemon):
325
336
  'X-Backend-Storage-Policy-Index': storage_policy_index,
326
337
  'user-agent': self.user_agent}
327
338
  conn = http_connect(
328
- node['ip'], node['port'], node['device'], part,
329
- 'PUT', container, headers=headers)
339
+ node['replication_ip'], node['replication_port'],
340
+ node['device'], part, 'PUT', container, headers=headers)
330
341
  except (Exception, Timeout):
331
- self.logger.exception(_(
332
- 'ERROR account update failed with '
333
- '%(ip)s:%(port)s/%(device)s (will retry later): '), node)
342
+ self.logger.exception(
343
+ 'ERROR account update failed with %s (will retry later):',
344
+ node_to_string(node, replication=True))
334
345
  return HTTP_INTERNAL_SERVER_ERROR
335
346
  with Timeout(self.node_timeout):
336
347
  try:
@@ -340,7 +351,17 @@ class ContainerUpdater(Daemon):
340
351
  except (Exception, Timeout):
341
352
  if self.logger.getEffectiveLevel() <= logging.DEBUG:
342
353
  self.logger.exception(
343
- _('Exception with %(ip)s:%(port)s/%(device)s'), node)
354
+ 'Exception with %s',
355
+ node_to_string(node, replication=True))
344
356
  return HTTP_INTERNAL_SERVER_ERROR
345
357
  finally:
346
358
  conn.close()
359
+
360
+
361
+ def main():
362
+ conf_file, options = parse_options(once=True)
363
+ run_daemon(ContainerUpdater, conf_file, **options)
364
+
365
+
366
+ if __name__ == '__main__':
367
+ main()