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/cli/reload.py ADDED
@@ -0,0 +1,135 @@
1
+ # Copyright (c) 2022 NVIDIA
2
+ #
3
+ # Licensed under the Apache License, Version 2.0 (the "License");
4
+ # you may not use this file except in compliance with the License.
5
+ # You may obtain a copy of the License at
6
+ #
7
+ # http://www.apache.org/licenses/LICENSE-2.0
8
+ #
9
+ # Unless required by applicable law or agreed to in writing, software
10
+ # distributed under the License is distributed on an "AS IS" BASIS,
11
+ # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or
12
+ # implied.
13
+ # See the License for the specific language governing permissions and
14
+ # limitations under the License.
15
+
16
+ """
17
+ Safely reload WSGI servers while minimizing client downtime and errors by
18
+
19
+ * validating that the process is a Swift WSGI server manager,
20
+ * checking that the configuration file used is valid,
21
+ * sending the "seamless reload" signal, and
22
+ * waiting for the reload to complete.
23
+ """
24
+
25
+ import argparse
26
+ import errno
27
+ import os
28
+ import os.path
29
+ import signal
30
+ import socket
31
+ import subprocess
32
+ import sys
33
+
34
+ from swift.common.utils import NotificationServer
35
+
36
+
37
+ EXIT_BAD_PID = 2 # similar to argparse exiting 2 on an unknown arg
38
+ EXIT_RELOAD_FAILED = 1
39
+ EXIT_RELOAD_TIMEOUT = 128 + errno.ETIMEDOUT
40
+
41
+
42
+ def validate_manager_pid(pid):
43
+ try:
44
+ with open('/proc/%d/cmdline' % pid, 'r') as fp:
45
+ cmd = fp.read().strip('\x00').split('\x00')
46
+ sid = os.getsid(pid)
47
+ except (IOError, OSError):
48
+ print("Failed to get process information for %s" % pid,
49
+ file=sys.stderr)
50
+ exit(EXIT_BAD_PID)
51
+
52
+ scripts = [os.path.basename(c) for c in cmd
53
+ if '/bin/' in c and '/bin/python' not in c]
54
+
55
+ if len(scripts) != 1 or not scripts[0].startswith("swift-"):
56
+ print("Non-swift process: %r" % ' '.join(cmd), file=sys.stderr)
57
+ exit(EXIT_BAD_PID)
58
+
59
+ if scripts[0] not in {"swift-proxy-server", "swift-account-server",
60
+ "swift-container-server", "swift-object-server"}:
61
+ print("Process does not support config checks: %s" % scripts[0],
62
+ file=sys.stderr)
63
+ exit(EXIT_BAD_PID)
64
+
65
+ if sid != pid:
66
+ print("Process appears to be a %s worker, not a manager. "
67
+ "Did you mean %s?" % (scripts[0], sid), file=sys.stderr)
68
+ exit(EXIT_BAD_PID)
69
+
70
+ return cmd, scripts[0]
71
+
72
+
73
+ def main(args=None):
74
+ parser = argparse.ArgumentParser(__doc__)
75
+ parser.add_argument("pid", type=int,
76
+ help="server PID which should be reloaded")
77
+ wait_group = parser.add_mutually_exclusive_group()
78
+ wait_group.add_argument("-t", "--timeout", type=float, default=300.0,
79
+ help="max time to wait for reload to complete")
80
+ wait_group.add_argument("-w", "--no-wait",
81
+ action="store_false", dest="wait",
82
+ help="skip waiting for reload to complete")
83
+ parser.add_argument("-v", "--verbose", action="store_true",
84
+ help="display more information as the process reloads")
85
+ args = parser.parse_args(args)
86
+
87
+ cmd, script = validate_manager_pid(args.pid)
88
+
89
+ if args.verbose:
90
+ print("Checking config for %s" % script)
91
+ try:
92
+ subprocess.check_call(cmd + ["--test-config"])
93
+ except subprocess.CalledProcessError:
94
+ print("Failed to validate config", file=sys.stderr)
95
+ exit(EXIT_RELOAD_FAILED)
96
+
97
+ if args.wait:
98
+ try:
99
+ with NotificationServer(args.pid, args.timeout) as notifications:
100
+ if args.verbose:
101
+ print("Sending USR1 signal")
102
+ os.kill(args.pid, signal.SIGUSR1)
103
+
104
+ try:
105
+ ready = False
106
+ while not ready:
107
+ data = notifications.receive()
108
+ for data in data.split(b"\n"):
109
+ if args.verbose:
110
+ if data in (b"READY=1", b"RELOADING=1",
111
+ b"STOPPING=1"):
112
+ print("Process is %s" %
113
+ data.decode("ascii")[:-2])
114
+ else:
115
+ print("Received notification %r" % data)
116
+
117
+ if data == b"READY=1":
118
+ ready = True
119
+ except socket.timeout:
120
+ print("Timed out reloading %s" % script, file=sys.stderr)
121
+ exit(EXIT_RELOAD_TIMEOUT)
122
+ except OSError as e:
123
+ print("Could not bind notification socket: %s" % e,
124
+ file=sys.stderr)
125
+ exit(EXIT_RELOAD_FAILED)
126
+ else: # --no-wait
127
+ if args.verbose:
128
+ print("Sending USR1 signal")
129
+ os.kill(args.pid, signal.SIGUSR1)
130
+
131
+ print("Reloaded %s" % script)
132
+
133
+
134
+ if __name__ == "__main__":
135
+ main()
swift/cli/ringbuilder.py CHANGED
@@ -13,7 +13,6 @@
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
 
19
18
  from collections import defaultdict
@@ -22,16 +21,15 @@ from itertools import islice
22
21
  from operator import itemgetter
23
22
  from os import mkdir
24
23
  from os.path import basename, abspath, dirname, exists, join as pathjoin
24
+ import sys
25
25
  from sys import argv as sys_argv, exit, stderr, stdout
26
26
  from textwrap import wrap
27
27
  from time import time
28
+ import traceback
28
29
  from datetime import timedelta
29
30
  import optparse
30
31
  import math
31
32
 
32
- from six.moves import zip as izip
33
- from six.moves import input
34
-
35
33
  from swift.common import exceptions
36
34
  from swift.common.ring import RingBuilder, Ring, RingData
37
35
  from swift.common.ring.builder import MAX_BALANCE
@@ -154,8 +152,8 @@ def _parse_add_values(argvish):
154
152
  print(Commands.add.__doc__.strip())
155
153
  exit(EXIT_ERROR)
156
154
 
157
- devs_and_weights = izip(islice(args, 0, len(args), 2),
158
- islice(args, 1, len(args), 2))
155
+ devs_and_weights = zip(islice(args, 0, len(args), 2),
156
+ islice(args, 1, len(args), 2))
159
157
 
160
158
  for devstr, weightstr in devs_and_weights:
161
159
  dev_dict = parse_add_value(devstr)
@@ -194,7 +192,11 @@ def check_devs(devs, input_question, opts, abort_msg):
194
192
  print('Matched more than one device:')
195
193
  for dev in devs:
196
194
  print(' %s' % format_device(dev))
197
- if not opts.yes and input(input_question) != 'y':
195
+ try:
196
+ abort = not opts.yes and input(input_question) != 'y'
197
+ except (EOFError, KeyboardInterrupt):
198
+ abort = True
199
+ if abort:
198
200
  print(abort_msg)
199
201
  exit(EXIT_ERROR)
200
202
 
@@ -212,6 +214,32 @@ def _set_weight_values(devs, weight, opts):
212
214
  dev['weight']))
213
215
 
214
216
 
217
+ def _set_region_values(devs, region, opts):
218
+
219
+ input_question = 'Are you sure you want to update the region for these ' \
220
+ '%s devices? (y/N) ' % len(devs)
221
+ abort_msg = 'Aborting device modifications'
222
+ check_devs(devs, input_question, opts, abort_msg)
223
+
224
+ for dev in devs:
225
+ builder.set_dev_region(dev['id'], region)
226
+ print('%s region set to %s' % (format_device(dev),
227
+ dev['region']))
228
+
229
+
230
+ def _set_zone_values(devs, zone, opts):
231
+
232
+ input_question = 'Are you sure you want to update the zone for these ' \
233
+ '%s devices? (y/N) ' % len(devs)
234
+ abort_msg = 'Aborting device modifications'
235
+ check_devs(devs, input_question, opts, abort_msg)
236
+
237
+ for dev in devs:
238
+ builder.set_dev_zone(dev['id'], zone)
239
+ print('%s zone set to %s' % (format_device(dev),
240
+ dev['zone']))
241
+
242
+
215
243
  def _parse_set_weight_values(argvish):
216
244
 
217
245
  new_cmd_format, opts, args = validate_args(argvish)
@@ -225,8 +253,8 @@ def _parse_set_weight_values(argvish):
225
253
  print(Commands.set_weight.__doc__.strip())
226
254
  exit(EXIT_ERROR)
227
255
 
228
- devs_and_weights = izip(islice(argvish, 0, len(argvish), 2),
229
- islice(argvish, 1, len(argvish), 2))
256
+ devs_and_weights = zip(islice(argvish, 0, len(argvish), 2),
257
+ islice(argvish, 1, len(argvish), 2))
230
258
  for devstr, weightstr in devs_and_weights:
231
259
  devs = (builder.search_devs(
232
260
  parse_search_value(devstr)) or [])
@@ -301,6 +329,76 @@ def calculate_change_value(change_value, change, v_name, v_name_port):
301
329
  return change_value
302
330
 
303
331
 
332
+ def _parse_set_region_values(argvish):
333
+
334
+ new_cmd_format, opts, args = validate_args(argvish)
335
+
336
+ # We'll either parse the all-in-one-string format or the
337
+ # --options format,
338
+ # but not both. If both are specified, raise an error.
339
+ try:
340
+ devs = []
341
+ if not new_cmd_format:
342
+ if len(args) % 2 != 0:
343
+ print(Commands.set_region.__doc__.strip())
344
+ exit(EXIT_ERROR)
345
+
346
+ devs_and_regions = zip(islice(argvish, 0, len(argvish), 2),
347
+ islice(argvish, 1, len(argvish), 2))
348
+ for devstr, regionstr in devs_and_regions:
349
+ devs.extend(builder.search_devs(
350
+ parse_search_value(devstr)) or [])
351
+ region = int(regionstr)
352
+ _set_region_values(devs, region, opts)
353
+ else:
354
+ if len(args) != 1:
355
+ print(Commands.set_region.__doc__.strip())
356
+ exit(EXIT_ERROR)
357
+
358
+ devs.extend(builder.search_devs(
359
+ parse_search_values_from_opts(opts)) or [])
360
+ region = int(args[0])
361
+ _set_region_values(devs, region, opts)
362
+ except ValueError as e:
363
+ print(e)
364
+ exit(EXIT_ERROR)
365
+
366
+
367
+ def _parse_set_zone_values(argvish):
368
+
369
+ new_cmd_format, opts, args = validate_args(argvish)
370
+
371
+ # We'll either parse the all-in-one-string format or the
372
+ # --options format,
373
+ # but not both. If both are specified, raise an error.
374
+ try:
375
+ devs = []
376
+ if not new_cmd_format:
377
+ if len(args) % 2 != 0:
378
+ print(Commands.set_zone.__doc__.strip())
379
+ exit(EXIT_ERROR)
380
+
381
+ devs_and_zones = zip(islice(argvish, 0, len(argvish), 2),
382
+ islice(argvish, 1, len(argvish), 2))
383
+ for devstr, zonestr in devs_and_zones:
384
+ devs.extend(builder.search_devs(
385
+ parse_search_value(devstr)) or [])
386
+ zone = int(zonestr)
387
+ _set_zone_values(devs, zone, opts)
388
+ else:
389
+ if len(args) != 1:
390
+ print(Commands.set_zone.__doc__.strip())
391
+ exit(EXIT_ERROR)
392
+
393
+ devs.extend(builder.search_devs(
394
+ parse_search_values_from_opts(opts)) or [])
395
+ zone = int(args[0])
396
+ _set_zone_values(devs, zone, opts)
397
+ except ValueError as e:
398
+ print(e)
399
+ exit(EXIT_ERROR)
400
+
401
+
304
402
  def _parse_set_info_values(argvish):
305
403
 
306
404
  new_cmd_format, opts, args = validate_args(argvish)
@@ -313,8 +411,8 @@ def _parse_set_info_values(argvish):
313
411
  print(Commands.search.__doc__.strip())
314
412
  exit(EXIT_ERROR)
315
413
 
316
- searches_and_changes = izip(islice(argvish, 0, len(argvish), 2),
317
- islice(argvish, 1, len(argvish), 2))
414
+ searches_and_changes = zip(islice(argvish, 0, len(argvish), 2),
415
+ islice(argvish, 1, len(argvish), 2))
318
416
 
319
417
  for search_value, change_value in searches_and_changes:
320
418
  devs = builder.search_devs(parse_search_value(search_value))
@@ -380,6 +478,7 @@ def _make_display_device_table(builder):
380
478
  rep_ip_width = 14
381
479
  rep_port_width = 4
382
480
  ip_ipv6 = rep_ipv6 = False
481
+ weight_width = 6
383
482
  for dev in builder._iter_devs():
384
483
  if is_valid_ipv6(dev['ip']):
385
484
  ip_ipv6 = True
@@ -390,6 +489,8 @@ def _make_display_device_table(builder):
390
489
  port_width = max(len(str(dev['port'])), port_width)
391
490
  rep_port_width = max(len(str(dev['replication_port'])),
392
491
  rep_port_width)
492
+ weight_width = max(len('%6.02f' % dev['weight']),
493
+ weight_width)
393
494
  if ip_ipv6:
394
495
  ip_width += 2
395
496
  if rep_ipv6:
@@ -397,7 +498,7 @@ def _make_display_device_table(builder):
397
498
  header_line = ('Devices:%5s %6s %4s %' + str(ip_width)
398
499
  + 's:%-' + str(port_width) + 's %' +
399
500
  str(rep_ip_width) + 's:%-' + str(rep_port_width) +
400
- 's %5s %6s %10s %7s %5s %s') % (
501
+ 's %5s %' + str(weight_width) + 's %10s %7s %5s %s') % (
401
502
  'id', 'region', 'zone', 'ip address',
402
503
  'port', 'replication ip', 'port', 'name',
403
504
  'weight', 'partitions', 'balance', 'flags',
@@ -415,7 +516,8 @@ def _make_display_device_table(builder):
415
516
  '%', str(ip_width), 's:%-',
416
517
  str(port_width), 'd ', '%',
417
518
  str(rep_ip_width), 's', ':%-',
418
- str(rep_port_width), 'd %5s %6.02f'
519
+ str(rep_port_width), 'd %5s %',
520
+ str(weight_width), '.02f'
419
521
  ' %10s %7.02f %5s %s'])
420
522
  args = (dev['id'], dev['region'], dev['zone'], dev_ip, dev['port'],
421
523
  dev_replication_ip, dev['replication_port'], dev['device'],
@@ -444,7 +546,11 @@ swift-ring-builder <builder_file> create <part_power> <replicas>
444
546
  if len(argv) < 6:
445
547
  print(Commands.create.__doc__.strip())
446
548
  exit(EXIT_ERROR)
447
- builder = RingBuilder(int(argv[3]), float(argv[4]), int(argv[5]))
549
+ try:
550
+ builder = RingBuilder(int(argv[3]), float(argv[4]), int(argv[5]))
551
+ except ValueError as e:
552
+ print(e)
553
+ exit(EXIT_ERROR)
448
554
  backup_dir = pathjoin(dirname(builder_file), 'backups')
449
555
  try:
450
556
  mkdir(backup_dir)
@@ -681,7 +787,7 @@ swift-ring-builder <builder_file> add
681
787
  if builder.next_part_power:
682
788
  print('Partition power increase in progress. You need ')
683
789
  print('to finish the increase first before adding devices.')
684
- exit(EXIT_WARNING)
790
+ exit(EXIT_ERROR)
685
791
 
686
792
  try:
687
793
  for new_dev in _parse_add_values(argv[3:]):
@@ -745,6 +851,75 @@ swift-ring-builder <builder_file> set_weight
745
851
  builder.save(builder_file)
746
852
  exit(EXIT_SUCCESS)
747
853
 
854
+ @staticmethod
855
+ def set_region():
856
+ """
857
+ swift-ring-builder <builder_file> set_region <search-value> <region>
858
+ [<search-value> <region] ...
859
+
860
+ or
861
+
862
+ swift-ring-builder <builder_file> set_region
863
+ --region <region> --zone <zone> --ip <ip or hostname> --port <port>
864
+ --replication-ip <r_ip or r_hostname> --replication-port <r_port>
865
+ --device <device_name> --meta <meta> <new region> [--yes]
866
+
867
+ Where <r_ip>, <r_hostname> and <r_port> are replication ip, hostname
868
+ and port.
869
+ Any of the options are optional in both cases.
870
+
871
+ Resets the devices' regions. No partitions will be reassigned to or from
872
+ the device until after running 'rebalance'. This is so you can make
873
+ multiple device changes and rebalance them all just once.
874
+
875
+ Option --yes assume a yes response to all questions.
876
+ """
877
+ if len(argv) < 5:
878
+ print(Commands.set_region.__doc__.strip())
879
+ print()
880
+ print(parse_search_value.__doc__.strip())
881
+ exit(EXIT_ERROR)
882
+
883
+ _parse_set_region_values(argv[3:])
884
+
885
+ builder.save(builder_file)
886
+ exit(EXIT_SUCCESS)
887
+
888
+ @staticmethod
889
+ def set_zone():
890
+ """
891
+ swift-ring-builder <builder_file> set_zone <search-value> <zone>
892
+ [<search-value> <zone] ...
893
+
894
+ or
895
+
896
+ swift-ring-builder <builder_file> set_zone
897
+ --region <region> --zone <zone> --ip <ip or hostname> --port <port>
898
+ --replication-ip <r_ip or r_hostname> --replication-port <r_port>
899
+ --device <device_name> --meta <meta> <new zone> [--yes]
900
+
901
+ Where <r_ip>, <r_hostname> and <r_port> are replication ip, hostname
902
+ and port.
903
+ Any of the options are optional in both cases.
904
+
905
+ Resets the devices' zones. No partitions will be reassigned to or from
906
+ the device until after running 'rebalance'. This is so you can make
907
+ multiple device changes and rebalance them all just once.
908
+
909
+ Option --yes assume a yes response to all questions.
910
+ """
911
+ # if len(argv) < 5 or len(argv) % 2 != 1:
912
+ if len(argv) < 5:
913
+ print(Commands.set_zone.__doc__.strip())
914
+ print()
915
+ print(parse_search_value.__doc__.strip())
916
+ exit(EXIT_ERROR)
917
+
918
+ _parse_set_zone_values(argv[3:])
919
+
920
+ builder.save(builder_file)
921
+ exit(EXIT_SUCCESS)
922
+
748
923
  @staticmethod
749
924
  def set_info():
750
925
  """
@@ -831,7 +1006,7 @@ swift-ring-builder <builder_file> remove
831
1006
  if builder.next_part_power:
832
1007
  print('Partition power increase in progress. You need ')
833
1008
  print('to finish the increase first before removing devices.')
834
- exit(EXIT_WARNING)
1009
+ exit(EXIT_ERROR)
835
1010
 
836
1011
  devs, opts = _parse_remove_values(argv[3:])
837
1012
 
@@ -898,7 +1073,7 @@ swift-ring-builder <builder_file> rebalance [options]
898
1073
  if builder.next_part_power:
899
1074
  print('Partition power increase in progress.')
900
1075
  print('You need to finish the increase first before rebalancing.')
901
- exit(EXIT_WARNING)
1076
+ exit(EXIT_ERROR)
902
1077
 
903
1078
  devs_changed = builder.devs_changed
904
1079
  min_part_seconds_left = builder.min_part_seconds_left
@@ -999,7 +1174,7 @@ swift-ring-builder <builder_file> rebalance [options]
999
1174
 
1000
1175
  @staticmethod
1001
1176
  def dispersion():
1002
- """
1177
+ r"""
1003
1178
  swift-ring-builder <builder_file> dispersion <search_filter> [options]
1004
1179
 
1005
1180
  Output report on dispersion.
@@ -1167,7 +1342,7 @@ swift-ring-builder <ring_file> write_builder [min_part_hours]
1167
1342
  'parts': ring.partition_count,
1168
1343
  'devs': ring.devs,
1169
1344
  'devs_changed': False,
1170
- 'version': 0,
1345
+ 'version': ring.version or 0,
1171
1346
  '_replica2part2dev': ring._replica2part2dev_id,
1172
1347
  '_last_part_moves_epoch': None,
1173
1348
  '_last_part_moves': None,
@@ -1493,7 +1668,7 @@ def main(arguments=None):
1493
1668
  print(msg)
1494
1669
  exit(EXIT_ERROR)
1495
1670
  except (exceptions.FileNotFoundError, exceptions.PermissionError) as e:
1496
- if len(argv) < 3 or argv[2] not in('create', 'write_builder'):
1671
+ if len(argv) < 3 or argv[2] not in ('create', 'write_builder'):
1497
1672
  print(e)
1498
1673
  exit(EXIT_ERROR)
1499
1674
  except Exception as e:
@@ -1521,3 +1696,25 @@ def main(arguments=None):
1521
1696
  exit(2)
1522
1697
  else:
1523
1698
  getattr(Commands, command, Commands.unknown)()
1699
+
1700
+
1701
+ def error_handling_main():
1702
+ # We exit code 1 on WARNING statuses, 2 on ERROR. This means we need
1703
+ # to handle any uncaught exceptions by printing the usual backtrace,
1704
+ # but then exiting 2 (not 1 as is usual for a python
1705
+ # exception).
1706
+
1707
+ # We *don't* want to do this in main(), however, because we don't want to
1708
+ # pollute the test environment or cause a bunch of test churn to mock out
1709
+ # sys.excepthook
1710
+
1711
+ def exit_with_status_two(tp, val, tb):
1712
+ traceback.print_exception(tp, val, tb)
1713
+ exit(2)
1714
+
1715
+ sys.excepthook = exit_with_status_two
1716
+ main()
1717
+
1718
+
1719
+ if __name__ == '__main__':
1720
+ error_handling_main()
swift/cli/ringcomposer.py CHANGED
@@ -65,7 +65,6 @@ For further details use::
65
65
 
66
66
  swift-ring-composer -h
67
67
  """
68
- from __future__ import print_function
69
68
  import argparse
70
69
  import json
71
70
  import os
swift/cli/shard-info.py CHANGED
@@ -89,7 +89,7 @@ def print_own_shard_range(node, sr, indent_level):
89
89
  indent = indent_level * TAB
90
90
  range = '%r - %r' % (sr.lower, sr.upper)
91
91
  print('%s(%s) %23s, objs: %3s, bytes: %3s, timestamp: %s (%s), '
92
- 'modified: %s (%s), %7s: %s (%s), deleted: %s epoch: %s' %
92
+ 'modified: %s (%s), %7s: %s (%s), deleted: %s, epoch: %s' %
93
93
  (indent, node[1][0], range, sr.object_count, sr.bytes_used,
94
94
  sr.timestamp.isoformat, sr.timestamp.internal,
95
95
  sr.meta_timestamp.isoformat, sr.meta_timestamp.internal,
@@ -108,12 +108,13 @@ def print_shard_range(node, sr, indent_level):
108
108
  indent = indent_level * TAB
109
109
  range = '%r - %r' % (sr.lower, sr.upper)
110
110
  print('%s(%s) %23s, objs: %3s, bytes: %3s, timestamp: %s (%s), '
111
- 'modified: %s (%s), %7s: %s (%s), deleted: %s %s' %
111
+ 'modified: %s (%s), %7s: %s (%s), deleted: %s, epoch: %s %s' %
112
112
  (indent, node[1][0], range, sr.object_count, sr.bytes_used,
113
113
  sr.timestamp.isoformat, sr.timestamp.internal,
114
114
  sr.meta_timestamp.isoformat, sr.meta_timestamp.internal,
115
115
  sr.state_text, sr.state_timestamp.isoformat,
116
- sr.state_timestamp.internal, sr.deleted, sr.name))
116
+ sr.state_timestamp.internal, sr.deleted,
117
+ sr.epoch.internal if sr.epoch else None, sr.name))
117
118
 
118
119
 
119
120
  def print_shard_range_info(node, shard_ranges, indent_level=0):
@@ -27,10 +27,8 @@ class BaseStorageServer(object):
27
27
 
28
28
  def __init__(self, conf, **kwargs):
29
29
  self._allowed_methods = None
30
- replication_server = conf.get('replication_server', None)
31
- if replication_server is not None:
32
- replication_server = config_true_value(replication_server)
33
- self.replication_server = replication_server
30
+ self.replication_server = config_true_value(
31
+ conf.get('replication_server', 'true'))
34
32
  self.log_format = conf.get('log_format', LOG_LINE_DEFAULT_FORMAT)
35
33
  self.anonymization_method = conf.get('log_anonymization_method', 'md5')
36
34
  self.anonymization_salt = conf.get('log_anonymization_salt', '')
@@ -45,22 +43,13 @@ class BaseStorageServer(object):
45
43
  if self._allowed_methods is None:
46
44
  self._allowed_methods = []
47
45
  all_methods = inspect.getmembers(self, predicate=callable)
48
-
49
- if self.replication_server is True:
50
- for name, m in all_methods:
51
- if (getattr(m, 'publicly_accessible', False) and
52
- getattr(m, 'replication', False)):
53
- self._allowed_methods.append(name)
54
- elif self.replication_server is False:
55
- for name, m in all_methods:
56
- if (getattr(m, 'publicly_accessible', False) and not
57
- getattr(m, 'replication', False)):
58
- self._allowed_methods.append(name)
59
- elif self.replication_server is None:
60
- for name, m in all_methods:
61
- if getattr(m, 'publicly_accessible', False):
62
- self._allowed_methods.append(name)
63
-
46
+ for name, m in all_methods:
47
+ if not getattr(m, 'publicly_accessible', False):
48
+ continue
49
+ if getattr(m, 'replication', False) and \
50
+ not self.replication_server:
51
+ continue
52
+ self._allowed_methods.append(name)
64
53
  self._allowed_methods.sort()
65
54
  return self._allowed_methods
66
55