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/__init__.py CHANGED
@@ -13,20 +13,32 @@
13
13
  # See the License for the specific language governing permissions and
14
14
  # limitations under the License.
15
15
 
16
- import os
17
- import sys
18
- import gettext
16
+ import warnings
19
17
 
20
- import pkg_resources
18
+ __version__ = None
21
19
 
20
+ # First, try to get our version out of PKG-INFO. If we're installed,
21
+ # this'll let us find our version without pulling in pbr. After all, if
22
+ # we're installed on a system, we're not in a Git-managed source tree, so
23
+ # pbr doesn't really buy us anything.
22
24
  try:
23
- # First, try to get our version out of PKG-INFO. If we're installed,
24
- # this'll let us find our version without pulling in pbr. After all, if
25
- # we're installed on a system, we're not in a Git-managed source tree, so
26
- # pbr doesn't really buy us anything.
27
- __version__ = __canonical_version__ = pkg_resources.get_provider(
28
- pkg_resources.Requirement.parse('swift')).version
29
- except pkg_resources.DistributionNotFound:
25
+ import importlib.metadata
26
+ except ImportError:
27
+ # python < 3.8
28
+ import pkg_resources
29
+ try:
30
+ __version__ = __canonical_version__ = pkg_resources.get_provider(
31
+ pkg_resources.Requirement.parse('swift')).version
32
+ except pkg_resources.DistributionNotFound:
33
+ pass
34
+ else:
35
+ try:
36
+ __version__ = __canonical_version__ = importlib.metadata.distribution(
37
+ 'swift').version
38
+ except importlib.metadata.PackageNotFoundError:
39
+ pass
40
+
41
+ if __version__ is None:
30
42
  # No PKG-INFO? We're probably running from a checkout, then. Let pbr do
31
43
  # its thing to figure out a version number.
32
44
  import pbr.version
@@ -34,43 +46,10 @@ except pkg_resources.DistributionNotFound:
34
46
  __version__ = _version_info.release_string()
35
47
  __canonical_version__ = _version_info.version_string()
36
48
 
37
- _localedir = os.environ.get('SWIFT_LOCALEDIR')
38
- _t = gettext.translation('swift', localedir=_localedir, fallback=True)
39
49
 
40
-
41
- def gettext_(msg):
42
- return _t.gettext(msg)
43
-
44
-
45
- if (3, 0) <= sys.version_info[:2] <= (3, 5):
46
- # In the development of py3, json.loads() stopped accepting byte strings
47
- # for a while. https://bugs.python.org/issue17909 got fixed for py36, but
48
- # since it was termed an enhancement and not a regression, we don't expect
49
- # any backports. At the same time, it'd be better if we could avoid
50
- # leaving a whole bunch of json.loads(resp.body.decode(...)) scars in the
51
- # code that'd probably persist even *after* we drop support for 3.5 and
52
- # earlier. So, monkey patch stdlib.
53
- import json
54
- if not getattr(json.loads, 'patched_to_decode', False):
55
- class JsonLoadsPatcher(object):
56
- def __init__(self, orig):
57
- self._orig = orig
58
-
59
- def __call__(self, s, **kw):
60
- if isinstance(s, bytes):
61
- # No fancy byte-order mark detection for us; just assume
62
- # UTF-8 and raise a UnicodeDecodeError if appropriate.
63
- s = s.decode('utf8')
64
- return self._orig(s, **kw)
65
-
66
- def __getattribute__(self, attr):
67
- if attr == 'patched_to_decode':
68
- return True
69
- if attr == '_orig':
70
- return super().__getattribute__(attr)
71
- # Pass through all other attrs to the original; among other
72
- # things, this preserves doc strings, etc.
73
- return getattr(self._orig, attr)
74
-
75
- json.loads = JsonLoadsPatcher(json.loads)
76
- del JsonLoadsPatcher
50
+ warnings.filterwarnings('ignore', module='cryptography|OpenSSL', message=(
51
+ 'Python 2 is no longer supported by the Python core team. '
52
+ 'Support for it is now deprecated in cryptography'))
53
+ warnings.filterwarnings('ignore', message=(
54
+ 'Python 3.6 is no longer supported by the Python core team. '
55
+ 'Therefore, support for it is deprecated in cryptography'))
swift/account/auditor.py CHANGED
@@ -13,100 +13,22 @@
13
13
  # See the License for the specific language governing permissions and
14
14
  # limitations under the License.
15
15
 
16
- import os
17
- import time
18
- from swift import gettext_ as _
19
- from random import random
20
16
 
21
- import swift.common.db
22
- from swift.account.backend import AccountBroker, DATADIR
17
+ from swift.account.backend import AccountBroker
23
18
  from swift.common.exceptions import InvalidAccountInfo
24
- from swift.common.utils import get_logger, audit_location_generator, \
25
- config_true_value, dump_recon_cache, ratelimit_sleep
26
- from swift.common.daemon import Daemon
19
+ from swift.common.daemon import run_daemon
20
+ from swift.common.db_auditor import DatabaseAuditor
21
+ from swift.common.utils import parse_options
27
22
 
28
- from eventlet import Timeout
29
23
 
30
-
31
- class AccountAuditor(Daemon):
24
+ class AccountAuditor(DatabaseAuditor):
32
25
  """Audit accounts."""
33
26
 
34
- def __init__(self, conf, logger=None):
35
- self.conf = conf
36
- self.logger = logger or get_logger(conf, log_route='account-auditor')
37
- self.devices = conf.get('devices', '/srv/node')
38
- self.mount_check = config_true_value(conf.get('mount_check', 'true'))
39
- self.interval = int(conf.get('interval', 1800))
40
- self.logging_interval = 3600 # once an hour
41
- self.account_passes = 0
42
- self.account_failures = 0
43
- self.accounts_running_time = 0
44
- self.max_accounts_per_second = \
45
- float(conf.get('accounts_per_second', 200))
46
- swift.common.db.DB_PREALLOCATION = \
47
- config_true_value(conf.get('db_preallocation', 'f'))
48
- self.recon_cache_path = conf.get('recon_cache_path',
49
- '/var/cache/swift')
50
- self.rcache = os.path.join(self.recon_cache_path, "account.recon")
51
-
52
- def _one_audit_pass(self, reported):
53
- all_locs = audit_location_generator(self.devices, DATADIR, '.db',
54
- mount_check=self.mount_check,
55
- logger=self.logger)
56
- for path, device, partition in all_locs:
57
- self.account_audit(path)
58
- if time.time() - reported >= self.logging_interval:
59
- self.logger.info(_('Since %(time)s: Account audits: '
60
- '%(passed)s passed audit,'
61
- '%(failed)s failed audit'),
62
- {'time': time.ctime(reported),
63
- 'passed': self.account_passes,
64
- 'failed': self.account_failures})
65
- dump_recon_cache({'account_audits_since': reported,
66
- 'account_audits_passed': self.account_passes,
67
- 'account_audits_failed':
68
- self.account_failures},
69
- self.rcache, self.logger)
70
- reported = time.time()
71
- self.account_passes = 0
72
- self.account_failures = 0
73
- self.accounts_running_time = ratelimit_sleep(
74
- self.accounts_running_time, self.max_accounts_per_second)
75
- return reported
76
-
77
- def run_forever(self, *args, **kwargs):
78
- """Run the account audit until stopped."""
79
- reported = time.time()
80
- time.sleep(random() * self.interval)
81
- while True:
82
- self.logger.info(_('Begin account audit pass.'))
83
- begin = time.time()
84
- try:
85
- reported = self._one_audit_pass(reported)
86
- except (Exception, Timeout):
87
- self.logger.increment('errors')
88
- self.logger.exception(_('ERROR auditing'))
89
- elapsed = time.time() - begin
90
- if elapsed < self.interval:
91
- time.sleep(self.interval - elapsed)
92
- self.logger.info(
93
- _('Account audit pass completed: %.02fs'), elapsed)
94
- dump_recon_cache({'account_auditor_pass_completed': elapsed},
95
- self.rcache, self.logger)
27
+ server_type = "account"
28
+ broker_class = AccountBroker
96
29
 
97
- def run_once(self, *args, **kwargs):
98
- """Run the account audit once."""
99
- self.logger.info(_('Begin account audit "once" mode'))
100
- begin = reported = time.time()
101
- self._one_audit_pass(reported)
102
- elapsed = time.time() - begin
103
- self.logger.info(
104
- _('Account audit "once" mode completed: %.02fs'), elapsed)
105
- dump_recon_cache({'account_auditor_pass_completed': elapsed},
106
- self.rcache, self.logger)
107
-
108
- def validate_per_policy_counts(self, broker):
109
- info = broker.get_info()
30
+ def _audit(self, info, broker):
31
+ # Validate per policy counts
110
32
  policy_stats = broker.get_policy_stats(do_migrations=True)
111
33
  policy_totals = {
112
34
  'container_count': 0,
@@ -120,36 +42,17 @@ class AccountAuditor(Daemon):
120
42
  for key in policy_totals:
121
43
  if policy_totals[key] == info[key]:
122
44
  continue
123
- raise InvalidAccountInfo(_(
124
- 'The total %(key)s for the container (%(total)s) does not '
125
- 'match the sum of %(key)s across policies (%(sum)s)')
126
- % {'key': key,
127
- 'total': info[key],
128
- 'sum': policy_totals[key]})
45
+ return InvalidAccountInfo(
46
+ 'The total %(key)s for the account %(account)s (%(total)s) '
47
+ 'does not match the sum of %(key)s across policies (%(sum)s)'
48
+ % {'key': key, 'account': info.get('account'),
49
+ 'total': info[key], 'sum': policy_totals[key]})
50
+
51
+
52
+ def main():
53
+ conf_file, options = parse_options(once=True)
54
+ run_daemon(AccountAuditor, conf_file, **options)
129
55
 
130
- def account_audit(self, path):
131
- """
132
- Audits the given account path
133
56
 
134
- :param path: the path to an account db
135
- """
136
- start_time = time.time()
137
- try:
138
- broker = AccountBroker(path, logger=self.logger)
139
- if not broker.is_deleted():
140
- self.validate_per_policy_counts(broker)
141
- self.logger.increment('passes')
142
- self.account_passes += 1
143
- self.logger.debug(_('Audit passed for %s'), broker)
144
- except InvalidAccountInfo as e:
145
- self.logger.increment('failures')
146
- self.account_failures += 1
147
- self.logger.error(
148
- _('Audit Failed for %(path)s: %(err)s'),
149
- {'path': path, 'err': str(e)})
150
- except (Exception, Timeout):
151
- self.logger.increment('failures')
152
- self.account_failures += 1
153
- self.logger.exception(_('ERROR Could not get account info %s'),
154
- path)
155
- self.logger.timing_since('timing', start_time)
57
+ if __name__ == '__main__':
58
+ main()
swift/account/backend.py CHANGED
@@ -16,14 +16,11 @@
16
16
  Pluggable Back-end for Account Server
17
17
  """
18
18
 
19
- from uuid import uuid4
20
19
 
21
20
  import sqlite3
22
21
 
23
- import six
24
-
25
- from swift.common.utils import Timestamp
26
- from swift.common.db import DatabaseBroker, utf8encode, zero_like
22
+ from swift.common.utils import Timestamp, RESERVED_BYTE
23
+ from swift.common.db import DatabaseBroker, zero_like
27
24
 
28
25
  DATADIR = 'accounts'
29
26
 
@@ -154,7 +151,7 @@ class AccountBroker(DatabaseBroker):
154
151
  conn.execute('''
155
152
  UPDATE account_stat SET account = ?, created_at = ?, id = ?,
156
153
  put_timestamp = ?, status_changed_at = ?
157
- ''', (self.account, Timestamp.now().internal, str(uuid4()),
154
+ ''', (self.account, Timestamp.now().internal, self._new_db_id(),
158
155
  put_timestamp, put_timestamp))
159
156
 
160
157
  def create_policy_stat_table(self, conn):
@@ -189,20 +186,6 @@ class AccountBroker(DatabaseBroker):
189
186
  self._db_version = 1
190
187
  return self._db_version
191
188
 
192
- def _delete_db(self, conn, timestamp, force=False):
193
- """
194
- Mark the DB as deleted.
195
-
196
- :param conn: DB connection object
197
- :param timestamp: timestamp to mark as deleted
198
- """
199
- conn.execute("""
200
- UPDATE account_stat
201
- SET delete_timestamp = ?,
202
- status = 'DELETED',
203
- status_changed_at = ?
204
- WHERE delete_timestamp < ? """, (timestamp, timestamp, timestamp))
205
-
206
189
  def _commit_puts_load(self, item_list, entry):
207
190
  """See :func:`swift.common.db.DatabaseBroker._commit_puts_load`"""
208
191
  # check to see if the update includes policy_index or not
@@ -369,7 +352,7 @@ class AccountBroker(DatabaseBroker):
369
352
  ''').fetchone())
370
353
 
371
354
  def list_containers_iter(self, limit, marker, end_marker, prefix,
372
- delimiter, reverse=False):
355
+ delimiter, reverse=False, allow_reserved=False):
373
356
  """
374
357
  Get a list of containers sorted by name starting at marker onward, up
375
358
  to limit entries. Entries will begin with the prefix and will not have
@@ -381,14 +364,12 @@ class AccountBroker(DatabaseBroker):
381
364
  :param prefix: prefix query
382
365
  :param delimiter: delimiter for query
383
366
  :param reverse: reverse the result order.
367
+ :param allow_reserved: exclude names with reserved-byte by default
384
368
 
385
369
  :returns: list of tuples of (name, object_count, bytes_used,
386
- put_timestamp, 0)
370
+ put_timestamp, storage_policy_index, is_subdir)
387
371
  """
388
372
  delim_force_gte = False
389
- if six.PY2:
390
- (marker, end_marker, prefix, delimiter) = utf8encode(
391
- marker, end_marker, prefix, delimiter)
392
373
  if reverse:
393
374
  # Reverse the markers if we are reversing the listing.
394
375
  marker, end_marker = end_marker, marker
@@ -402,7 +383,8 @@ class AccountBroker(DatabaseBroker):
402
383
  results = []
403
384
  while len(results) < limit:
404
385
  query = """
405
- SELECT name, object_count, bytes_used, put_timestamp, 0
386
+ SELECT name, object_count, bytes_used, put_timestamp,
387
+ {storage_policy_index}, 0
406
388
  FROM container
407
389
  WHERE """
408
390
  query_args = []
@@ -424,6 +406,9 @@ class AccountBroker(DatabaseBroker):
424
406
  elif prefix:
425
407
  query += ' name >= ? AND'
426
408
  query_args.append(prefix)
409
+ if not allow_reserved:
410
+ query += ' name >= ? AND'
411
+ query_args.append(chr(ord(RESERVED_BYTE) + 1))
427
412
  if self.get_db_version(conn) < 1:
428
413
  query += ' +deleted = 0'
429
414
  else:
@@ -431,7 +416,27 @@ class AccountBroker(DatabaseBroker):
431
416
  query += ' ORDER BY name %s LIMIT ?' % \
432
417
  ('DESC' if reverse else '')
433
418
  query_args.append(limit - len(results))
434
- curs = conn.execute(query, query_args)
419
+ try:
420
+ # First, try querying with the storage policy index.
421
+ curs = conn.execute(
422
+ query.format(
423
+ storage_policy_index="storage_policy_index"),
424
+ query_args)
425
+ except sqlite3.OperationalError as err:
426
+ # If the storage policy column is not available,
427
+ # the database has not been migrated to the new schema
428
+ # with storage_policy_index. Re-run the query with
429
+ # storage_policy_index set to 0, which is what
430
+ # would be set once the database is migrated.
431
+ # TODO(callumdickinson): If support for migrating
432
+ # pre-storage policy versions of Swift is dropped,
433
+ # then this special handling can be removed.
434
+ if "no such column: storage_policy_index" in str(err):
435
+ curs = conn.execute(
436
+ query.format(storage_policy_index="0"),
437
+ query_args)
438
+ else:
439
+ raise
435
440
  curs.row_factory = None
436
441
 
437
442
  # Delimiters without a prefix is ignored, further if there
@@ -468,7 +473,7 @@ class AccountBroker(DatabaseBroker):
468
473
  delim_force_gte = True
469
474
  dir_name = name[:end + len(delimiter)]
470
475
  if dir_name != orig_marker:
471
- results.append([dir_name, 0, 0, '0', 1])
476
+ results.append([dir_name, 0, 0, '0', -1, 1])
472
477
  curs.close()
473
478
  break
474
479
  results.append(row)
swift/account/reaper.py CHANGED
@@ -19,22 +19,22 @@ import socket
19
19
  from logging import DEBUG
20
20
  from math import sqrt
21
21
  from time import time
22
- from hashlib import md5
23
22
  import itertools
24
23
 
25
24
  from eventlet import GreenPool, sleep, Timeout
26
- import six
27
25
 
28
26
  import swift.common.db
29
27
  from swift.account.backend import AccountBroker, DATADIR
30
28
  from swift.common.constraints import check_drive
29
+ from swift.common.daemon import run_daemon
31
30
  from swift.common.direct_client import direct_delete_container, \
32
31
  direct_delete_object, direct_get_container
33
32
  from swift.common.exceptions import ClientException
33
+ from swift.common.request_helpers import USE_REPLICATION_NETWORK_HEADER
34
34
  from swift.common.ring import Ring
35
35
  from swift.common.ring.utils import is_local_device
36
36
  from swift.common.utils import get_logger, whataremyips, config_true_value, \
37
- Timestamp
37
+ Timestamp, md5, node_to_string, parse_options
38
38
  from swift.common.daemon import Daemon
39
39
  from swift.common.storage_policy import POLICIES, PolicyError
40
40
 
@@ -65,7 +65,7 @@ class AccountReaper(Daemon):
65
65
  self.logger = logger or get_logger(conf, log_route='account-reaper')
66
66
  self.devices = conf.get('devices', '/srv/node')
67
67
  self.mount_check = config_true_value(conf.get('mount_check', 'true'))
68
- self.interval = int(conf.get('interval', 3600))
68
+ self.interval = float(conf.get('interval', 3600))
69
69
  self.swift_dir = conf.get('swift_dir', '/etc/swift')
70
70
  self.account_ring = None
71
71
  self.container_ring = None
@@ -262,16 +262,15 @@ class AccountReaper(Daemon):
262
262
  container_limit *= len(nodes)
263
263
  try:
264
264
  containers = list(broker.list_containers_iter(
265
- container_limit, '', None, None, None))
265
+ container_limit, '', None, None, None, allow_reserved=True))
266
266
  while containers:
267
267
  try:
268
- for (container, _junk, _junk, _junk, _junk) in containers:
269
- if six.PY3:
270
- container_ = container.encode('utf-8')
271
- else:
272
- container_ = container
273
- this_shard = int(md5(container_).hexdigest(), 16) % \
274
- len(nodes)
268
+ for row in containers:
269
+ container = row[0]
270
+ this_shard = (
271
+ int(md5(container.encode('utf-8'),
272
+ usedforsecurity=False)
273
+ .hexdigest(), 16) % len(nodes))
275
274
  if container_shard not in (this_shard, None):
276
275
  continue
277
276
 
@@ -282,7 +281,8 @@ class AccountReaper(Daemon):
282
281
  self.logger.exception(
283
282
  'Exception with containers for account %s', account)
284
283
  containers = list(broker.list_containers_iter(
285
- container_limit, containers[-1][0], None, None, None))
284
+ container_limit, containers[-1][0], None, None, None,
285
+ allow_reserved=True))
286
286
  log_buf = ['Completed pass on account %s' % account]
287
287
  except (Exception, Timeout):
288
288
  self.logger.exception('Exception with account %s', account)
@@ -369,22 +369,22 @@ class AccountReaper(Daemon):
369
369
  node, part, account, container,
370
370
  marker=marker,
371
371
  conn_timeout=self.conn_timeout,
372
- response_timeout=self.node_timeout)
372
+ response_timeout=self.node_timeout,
373
+ headers={USE_REPLICATION_NETWORK_HEADER: 'true'})
373
374
  self.stats_return_codes[2] = \
374
375
  self.stats_return_codes.get(2, 0) + 1
375
376
  self.logger.increment('return_codes.2')
376
377
  except ClientException as err:
377
378
  if self.logger.getEffectiveLevel() <= DEBUG:
378
379
  self.logger.exception(
379
- 'Exception with %(ip)s:%(port)s/%(device)s', node)
380
+ 'Exception with %s', node_to_string(node))
380
381
  self.stats_return_codes[err.http_status // 100] = \
381
382
  self.stats_return_codes.get(err.http_status // 100, 0) + 1
382
383
  self.logger.increment(
383
384
  'return_codes.%d' % (err.http_status // 100,))
384
- except (Timeout, socket.error) as err:
385
+ except (Timeout, socket.error):
385
386
  self.logger.error(
386
- 'Timeout Exception with %(ip)s:%(port)s/%(device)s',
387
- node)
387
+ 'Timeout Exception with %s', node_to_string(node))
388
388
  if not objects:
389
389
  break
390
390
  try:
@@ -417,7 +417,8 @@ class AccountReaper(Daemon):
417
417
  'X-Account-Partition': str(account_partition),
418
418
  'X-Account-Device': anode['device'],
419
419
  'X-Account-Override-Deleted': 'yes',
420
- 'X-Timestamp': timestamp.internal})
420
+ 'X-Timestamp': timestamp.internal,
421
+ USE_REPLICATION_NETWORK_HEADER: 'true'})
421
422
  successes += 1
422
423
  self.stats_return_codes[2] = \
423
424
  self.stats_return_codes.get(2, 0) + 1
@@ -425,17 +426,16 @@ class AccountReaper(Daemon):
425
426
  except ClientException as err:
426
427
  if self.logger.getEffectiveLevel() <= DEBUG:
427
428
  self.logger.exception(
428
- 'Exception with %(ip)s:%(port)s/%(device)s', node)
429
+ 'Exception with %s', node_to_string(node))
429
430
  failures += 1
430
431
  self.logger.increment('containers_failures')
431
432
  self.stats_return_codes[err.http_status // 100] = \
432
433
  self.stats_return_codes.get(err.http_status // 100, 0) + 1
433
434
  self.logger.increment(
434
435
  'return_codes.%d' % (err.http_status // 100,))
435
- except (Timeout, socket.error) as err:
436
+ except (Timeout, socket.error):
436
437
  self.logger.error(
437
- 'Timeout Exception with %(ip)s:%(port)s/%(device)s',
438
- node)
438
+ 'Timeout Exception with %s', node_to_string(node))
439
439
  failures += 1
440
440
  self.logger.increment('containers_failures')
441
441
  if successes > failures:
@@ -493,7 +493,8 @@ class AccountReaper(Daemon):
493
493
  'X-Container-Partition': str(container_partition),
494
494
  'X-Container-Device': cnode['device'],
495
495
  'X-Backend-Storage-Policy-Index': policy_index,
496
- 'X-Timestamp': timestamp.internal})
496
+ 'X-Timestamp': timestamp.internal,
497
+ USE_REPLICATION_NETWORK_HEADER: 'true'})
497
498
  successes += 1
498
499
  self.stats_return_codes[2] = \
499
500
  self.stats_return_codes.get(2, 0) + 1
@@ -501,19 +502,18 @@ class AccountReaper(Daemon):
501
502
  except ClientException as err:
502
503
  if self.logger.getEffectiveLevel() <= DEBUG:
503
504
  self.logger.exception(
504
- 'Exception with %(ip)s:%(port)s/%(device)s', node)
505
+ 'Exception with %s', node_to_string(node))
505
506
  failures += 1
506
507
  self.logger.increment('objects_failures')
507
508
  self.stats_return_codes[err.http_status // 100] = \
508
509
  self.stats_return_codes.get(err.http_status // 100, 0) + 1
509
510
  self.logger.increment(
510
511
  'return_codes.%d' % (err.http_status // 100,))
511
- except (Timeout, socket.error) as err:
512
+ except (Timeout, socket.error):
512
513
  failures += 1
513
514
  self.logger.increment('objects_failures')
514
515
  self.logger.error(
515
- 'Timeout Exception with %(ip)s:%(port)s/%(device)s',
516
- node)
516
+ 'Timeout Exception with %s', node_to_string(node))
517
517
  if successes > failures:
518
518
  self.stats_objects_deleted += 1
519
519
  self.logger.increment('objects_deleted')
@@ -523,3 +523,12 @@ class AccountReaper(Daemon):
523
523
  else:
524
524
  self.stats_objects_possibly_remaining += 1
525
525
  self.logger.increment('objects_possibly_remaining')
526
+
527
+
528
+ def main():
529
+ conf_file, options = parse_options(once=True)
530
+ run_daemon(AccountReaper, conf_file, **options)
531
+
532
+
533
+ if __name__ == '__main__':
534
+ main()
@@ -13,8 +13,12 @@
13
13
  # See the License for the specific language governing permissions and
14
14
  # limitations under the License.
15
15
 
16
+ import optparse
17
+
16
18
  from swift.account.backend import AccountBroker, DATADIR
17
19
  from swift.common import db_replicator
20
+ from swift.common.daemon import run_daemon
21
+ from swift.common.utils import parse_options
18
22
 
19
23
 
20
24
  class AccountReplicator(db_replicator.Replicator):
@@ -22,3 +26,21 @@ class AccountReplicator(db_replicator.Replicator):
22
26
  brokerclass = AccountBroker
23
27
  datadir = DATADIR
24
28
  default_port = 6202
29
+
30
+
31
+ def main():
32
+ parser = optparse.OptionParser("%prog CONFIG [options]")
33
+ parser.add_option('-d', '--devices',
34
+ help=('Replicate only given devices. '
35
+ 'Comma-separated list. '
36
+ 'Only has effect if --once is used.'))
37
+ parser.add_option('-p', '--partitions',
38
+ help=('Replicate only given partitions. '
39
+ 'Comma-separated list. '
40
+ 'Only has effect if --once is used.'))
41
+ conf_file, options = parse_options(parser=parser, once=True)
42
+ run_daemon(AccountReplicator, conf_file, **options)
43
+
44
+
45
+ if __name__ == '__main__':
46
+ main()