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/common/manager.py CHANGED
@@ -13,18 +13,19 @@
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
16
+
17
17
  import functools
18
18
  import errno
19
+ from optparse import OptionParser
19
20
  import os
20
21
  import resource
21
22
  import signal
22
23
  import time
23
24
  import subprocess
24
25
  import re
25
- import six
26
- from swift import gettext_ as _
26
+ import sys
27
27
  import tempfile
28
+ from shutil import which
28
29
 
29
30
  from swift.common.utils import search_tree, remove_file, write_file, readconf
30
31
  from swift.common.exceptions import InvalidPidFileException
@@ -46,6 +47,7 @@ REST_SERVERS = [s for s in ALL_SERVERS if s not in MAIN_SERVERS]
46
47
  # aliases mapping
47
48
  ALIASES = {'all': ALL_SERVERS, 'main': MAIN_SERVERS, 'rest': REST_SERVERS}
48
49
  GRACEFUL_SHUTDOWN_SERVERS = MAIN_SERVERS
50
+ SEAMLESS_SHUTDOWN_SERVERS = MAIN_SERVERS
49
51
  START_ONCE_SERVERS = REST_SERVERS
50
52
  # These are servers that match a type (account-*, container-*, object-*) but
51
53
  # don't use that type-server.conf file and instead use their own.
@@ -66,22 +68,22 @@ def setup_env():
66
68
  resource.setrlimit(resource.RLIMIT_NOFILE,
67
69
  (MAX_DESCRIPTORS, MAX_DESCRIPTORS))
68
70
  except ValueError:
69
- print(_("WARNING: Unable to modify file descriptor limit. "
70
- "Running as non-root?"))
71
+ print("WARNING: Unable to modify file descriptor limit. "
72
+ "Running as non-root?")
71
73
 
72
74
  try:
73
75
  resource.setrlimit(resource.RLIMIT_DATA,
74
76
  (MAX_MEMORY, MAX_MEMORY))
75
77
  except ValueError:
76
- print(_("WARNING: Unable to modify memory limit. "
77
- "Running as non-root?"))
78
+ print("WARNING: Unable to modify memory limit. "
79
+ "Running as non-root?")
78
80
 
79
81
  try:
80
82
  resource.setrlimit(resource.RLIMIT_NPROC,
81
83
  (MAX_PROCS, MAX_PROCS))
82
84
  except ValueError:
83
- print(_("WARNING: Unable to modify max process limit. "
84
- "Running as non-root?"))
85
+ print("WARNING: Unable to modify max process limit. "
86
+ "Running as non-root?")
85
87
 
86
88
  # Set PYTHON_EGG_CACHE if it isn't already set
87
89
  os.environ.setdefault('PYTHON_EGG_CACHE', tempfile.gettempdir())
@@ -97,8 +99,10 @@ def command(func):
97
99
  func.publicly_accessible = True
98
100
 
99
101
  @functools.wraps(func)
100
- def wrapped(*a, **kw):
101
- rv = func(*a, **kw)
102
+ def wrapped(self, *a, **kw):
103
+ rv = func(self, *a, **kw)
104
+ if len(self.servers) == 0:
105
+ return 1
102
106
  return 1 if rv else 0
103
107
  return wrapped
104
108
 
@@ -173,6 +177,50 @@ def kill_group(pid, sig):
173
177
  os.kill(-pid, sig)
174
178
 
175
179
 
180
+ def get_child_pids(pid):
181
+ """
182
+ Get the current set of all child PIDs for a PID.
183
+
184
+ :param pid: process id
185
+ """
186
+ output = subprocess.check_output(
187
+ ["ps", "--ppid", str(pid), "--no-headers", "-o", "pid"])
188
+ return {int(pid) for pid in output.split()}
189
+
190
+
191
+ def format_server_name(servername):
192
+ """
193
+ Formats server name as swift compatible server names
194
+ E.g. swift-object-server
195
+
196
+ :param servername: server name
197
+ :returns: swift compatible server name and its binary name
198
+ """
199
+ if '.' in servername:
200
+ servername = servername.split('.', 1)[0]
201
+ if '-' not in servername:
202
+ servername = '%s-server' % servername
203
+ cmd = 'swift-%s' % servername
204
+ return servername, cmd
205
+
206
+
207
+ def verify_server(server):
208
+ """
209
+ Check whether the server is among swift servers or not, and also
210
+ checks whether the server's binaries are installed or not.
211
+
212
+ :param server: name of the server
213
+ :returns: True, when the server name is valid and its binaries are found.
214
+ False, otherwise.
215
+ """
216
+ if not server:
217
+ return False
218
+ _, cmd = format_server_name(server)
219
+ if which(cmd) is None:
220
+ return False
221
+ return True
222
+
223
+
176
224
  class UnknownCommandError(Exception):
177
225
  pass
178
226
 
@@ -202,7 +250,8 @@ class Manager(object):
202
250
 
203
251
  self.servers = set()
204
252
  for name in self.server_names:
205
- self.servers.add(Server(name, run_dir))
253
+ if verify_server(name):
254
+ self.servers.add(Server(name, run_dir))
206
255
 
207
256
  def __iter__(self):
208
257
  return iter(self.servers)
@@ -239,7 +288,7 @@ class Manager(object):
239
288
  try:
240
289
  status += server.interact(**kwargs)
241
290
  except KeyboardInterrupt:
242
- print(_('\nuser quit'))
291
+ print('\nuser quit')
243
292
  self.stop(**kwargs)
244
293
  break
245
294
  elif kwargs.get('wait', True):
@@ -276,7 +325,7 @@ class Manager(object):
276
325
  for server in self.servers:
277
326
  signaled_pids = server.stop(**kwargs)
278
327
  if not signaled_pids:
279
- print(_('No %s running') % server)
328
+ print('No %s running' % server)
280
329
  else:
281
330
  server_pids[server] = signaled_pids
282
331
 
@@ -289,7 +338,7 @@ class Manager(object):
289
338
  for server, killed_pid in watch_server_pids(server_pids,
290
339
  interval=kill_wait,
291
340
  **kwargs):
292
- print(_("%(server)s (%(pid)s) appears to have stopped") %
341
+ print("%(server)s (%(pid)s) appears to have stopped" %
293
342
  {'server': server, 'pid': killed_pid})
294
343
  killed_pids.add(killed_pid)
295
344
  if not killed_pids.symmetric_difference(signaled_pids):
@@ -302,15 +351,15 @@ class Manager(object):
302
351
  if not killed_pids.issuperset(pids):
303
352
  # some pids of this server were not killed
304
353
  if kill_after_timeout:
305
- print(_('Waited %(kill_wait)s seconds for %(server)s '
306
- 'to die; killing') %
354
+ print('Waited %(kill_wait)s seconds for %(server)s '
355
+ 'to die; killing' %
307
356
  {'kill_wait': kill_wait, 'server': server})
308
357
  # Send SIGKILL to all remaining pids
309
358
  for pid in set(pids.keys()) - killed_pids:
310
- print(_('Signal %(server)s pid: %(pid)s signal: '
311
- '%(signal)s') % {'server': server,
312
- 'pid': pid,
313
- 'signal': signal.SIGKILL})
359
+ print('Signal %(server)s pid: %(pid)s signal: '
360
+ '%(signal)s' % {'server': server,
361
+ 'pid': pid,
362
+ 'signal': signal.SIGKILL})
314
363
  # Send SIGKILL to process group
315
364
  try:
316
365
  kill_group(pid, signal.SIGKILL)
@@ -319,8 +368,8 @@ class Manager(object):
319
368
  if e.errno != errno.ESRCH:
320
369
  raise
321
370
  else:
322
- print(_('Waited %(kill_wait)s seconds for %(server)s '
323
- 'to die; giving up') %
371
+ print('Waited %(kill_wait)s seconds for %(server)s '
372
+ 'to die; giving up' %
324
373
  {'kill_wait': kill_wait, 'server': server})
325
374
  return 1
326
375
 
@@ -365,6 +414,31 @@ class Manager(object):
365
414
  status += m.start(**kwargs)
366
415
  return status
367
416
 
417
+ @command
418
+ def reload_seamless(self, **kwargs):
419
+ """seamlessly re-exec, then shutdown of old listen sockets on
420
+ supporting servers
421
+ """
422
+ kwargs.pop('graceful', None)
423
+ kwargs['seamless'] = True
424
+ status = 0
425
+ for server in self.servers:
426
+ signaled_pids = server.stop(**kwargs)
427
+ if not signaled_pids:
428
+ print('No %s running' % server)
429
+ status += 1
430
+ return status
431
+
432
+ def kill_child_pids(self, **kwargs):
433
+ """kill child pids, optionally servicing accepted connections"""
434
+ status = 0
435
+ for server in self.servers:
436
+ signaled_pids = server.kill_child_pids(**kwargs)
437
+ if not signaled_pids:
438
+ print('No %s running' % server)
439
+ status += 1
440
+ return status
441
+
368
442
  @command
369
443
  def force_reload(self, **kwargs):
370
444
  """alias for reload
@@ -420,10 +494,8 @@ class Server(object):
420
494
  self.server, self.conf = self.server.rsplit('.', 1)
421
495
  else:
422
496
  self.conf = None
423
- if '-' not in self.server:
424
- self.server = '%s-server' % self.server
497
+ self.server, self.cmd = format_server_name(self.server)
425
498
  self.type = self.server.rsplit('-', 1)[0]
426
- self.cmd = 'swift-%s' % self.server
427
499
  self.procs = []
428
500
  self.run_dir = run_dir
429
501
 
@@ -523,7 +595,7 @@ class Server(object):
523
595
 
524
596
  def dump_found_configs():
525
597
  if found_conf_files:
526
- print(_('Found configs:'))
598
+ print('Found configs:')
527
599
  for i, conf_file in enumerate(found_conf_files):
528
600
  print(' %d) %s' % (i + 1, conf_file))
529
601
 
@@ -531,18 +603,18 @@ class Server(object):
531
603
  # maybe there's a config file(s) out there, but I couldn't find it!
532
604
  if not kwargs.get('quiet'):
533
605
  if number:
534
- print(_('Unable to locate config number %(number)s for'
535
- ' %(server)s') %
606
+ print('Unable to locate config number %(number)s for'
607
+ ' %(server)s' %
536
608
  {'number': number, 'server': self.server})
537
609
  else:
538
- print(_('Unable to locate config for %s') % self.server)
610
+ print('Unable to locate config for %s' % self.server)
539
611
  if kwargs.get('verbose') and not kwargs.get('quiet'):
540
612
  dump_found_configs()
541
613
  elif any(["object-expirer" in name for name in conf_files]) and \
542
614
  not kwargs.get('quiet'):
543
- print(_("WARNING: object-expirer.conf is deprecated. "
544
- "Move object-expirers' configuration into "
545
- "object-server.conf."))
615
+ print("WARNING: object-expirer.conf is deprecated. "
616
+ "Move object-expirers' configuration into "
617
+ "object-server.conf.")
546
618
  if kwargs.get('verbose'):
547
619
  dump_found_configs()
548
620
 
@@ -578,6 +650,32 @@ class Server(object):
578
650
  pid = None
579
651
  yield pid_file, pid
580
652
 
653
+ def _signal_pid(self, sig, pid, pid_file, verbose):
654
+ try:
655
+ if sig != signal.SIG_DFL:
656
+ print('Signal %(server)s pid: %(pid)s signal: '
657
+ '%(signal)s' %
658
+ {'server': self.server, 'pid': pid, 'signal': sig})
659
+ safe_kill(pid, sig, 'swift-%s' % self.server)
660
+ except InvalidPidFileException:
661
+ if verbose:
662
+ print('Removing pid file %(pid_file)s with wrong pid '
663
+ '%(pid)d' % {'pid_file': pid_file, 'pid': pid})
664
+ remove_file(pid_file)
665
+ return False
666
+ except OSError as e:
667
+ if e.errno == errno.ESRCH:
668
+ # pid does not exist
669
+ if verbose:
670
+ print("Removing stale pid file %s" % pid_file)
671
+ remove_file(pid_file)
672
+ elif e.errno == errno.EPERM:
673
+ print("No permission to signal PID %d" % pid)
674
+ return False
675
+ else:
676
+ # process exists
677
+ return True
678
+
581
679
  def signal_pids(self, sig, **kwargs):
582
680
  """Send a signal to pids for this server
583
681
 
@@ -589,33 +687,32 @@ class Server(object):
589
687
  pids = {}
590
688
  for pid_file, pid in self.iter_pid_files(**kwargs):
591
689
  if not pid: # Catches None and 0
592
- print(_('Removing pid file %s with invalid pid') % pid_file)
690
+ print('Removing pid file %s with invalid pid' % pid_file)
593
691
  remove_file(pid_file)
594
692
  continue
595
- try:
596
- if sig != signal.SIG_DFL:
597
- print(_('Signal %(server)s pid: %(pid)s signal: '
598
- '%(signal)s') %
599
- {'server': self.server, 'pid': pid, 'signal': sig})
600
- safe_kill(pid, sig, 'swift-%s' % self.server)
601
- except InvalidPidFileException as e:
602
- if kwargs.get('verbose'):
603
- print(_('Removing pid file %(pid_file)s with wrong pid '
604
- '%(pid)d') % {'pid_file': pid_file, 'pid': pid})
605
- remove_file(pid_file)
606
- except OSError as e:
607
- if e.errno == errno.ESRCH:
608
- # pid does not exist
609
- if kwargs.get('verbose'):
610
- print(_("Removing stale pid file %s") % pid_file)
611
- remove_file(pid_file)
612
- elif e.errno == errno.EPERM:
613
- print(_("No permission to signal PID %d") % pid)
614
- else:
615
- # process exists
693
+ if self._signal_pid(sig, pid, pid_file, kwargs.get('verbose')):
616
694
  pids[pid] = pid_file
617
695
  return pids
618
696
 
697
+ def signal_children(self, sig, **kwargs):
698
+ """Send a signal to child pids for this server
699
+
700
+ :param sig: signal to send
701
+
702
+ :returns: a dict mapping pids (ints) to pid_files (paths)
703
+
704
+ """
705
+ pids = {}
706
+ for pid_file, pid in self.iter_pid_files(**kwargs):
707
+ if not pid: # Catches None and 0
708
+ print('Removing pid file %s with invalid pid' % pid_file)
709
+ remove_file(pid_file)
710
+ continue
711
+ for pid in get_child_pids(pid):
712
+ if self._signal_pid(sig, pid, pid_file, kwargs.get('verbose')):
713
+ pids[pid] = pid_file
714
+ return pids
715
+
619
716
  def get_running_pids(self, **kwargs):
620
717
  """Get running pids
621
718
 
@@ -628,17 +725,40 @@ class Server(object):
628
725
  """Kill running pids
629
726
 
630
727
  :param graceful: if True, attempt SIGHUP on supporting servers
728
+ :param seamless: if True, attempt SIGUSR1 on supporting servers
631
729
 
632
730
  :returns: a dict mapping pids (ints) to pid_files (paths)
633
731
 
634
732
  """
635
733
  graceful = kwargs.get('graceful')
734
+ seamless = kwargs.get('seamless')
636
735
  if graceful and self.server in GRACEFUL_SHUTDOWN_SERVERS:
637
736
  sig = signal.SIGHUP
737
+ elif seamless and self.server in SEAMLESS_SHUTDOWN_SERVERS:
738
+ sig = signal.SIGUSR1
638
739
  else:
639
740
  sig = signal.SIGTERM
640
741
  return self.signal_pids(sig, **kwargs)
641
742
 
743
+ def kill_child_pids(self, **kwargs):
744
+ """Kill child pids, leaving server overseer to respawn them
745
+
746
+ :param graceful: if True, attempt SIGHUP on supporting servers
747
+ :param seamless: if True, attempt SIGUSR1 on supporting servers
748
+
749
+ :returns: a dict mapping pids (ints) to pid_files (paths)
750
+
751
+ """
752
+ graceful = kwargs.get('graceful')
753
+ seamless = kwargs.get('seamless')
754
+ if graceful and self.server in GRACEFUL_SHUTDOWN_SERVERS:
755
+ sig = signal.SIGHUP
756
+ elif seamless and self.server in SEAMLESS_SHUTDOWN_SERVERS:
757
+ sig = signal.SIGUSR1
758
+ else:
759
+ sig = signal.SIGTERM
760
+ return self.signal_children(sig, **kwargs)
761
+
642
762
  def status(self, pids=None, **kwargs):
643
763
  """Display status of server
644
764
 
@@ -655,15 +775,15 @@ class Server(object):
655
775
  kwargs['quiet'] = True
656
776
  conf_files = self.conf_files(**kwargs)
657
777
  if conf_files:
658
- print(_("%(server)s #%(number)d not running (%(conf)s)") %
778
+ print("%(server)s #%(number)d not running (%(conf)s)" %
659
779
  {'server': self.server, 'number': number,
660
780
  'conf': conf_files[0]})
661
781
  else:
662
- print(_("No %s running") % self.server)
782
+ print("No %s running" % self.server)
663
783
  return 1
664
784
  for pid, pid_file in pids.items():
665
785
  conf_file = self.get_conf_file_name(pid_file)
666
- print(_("%(server)s running (%(pid)s - %(conf)s)") %
786
+ print("%(server)s running (%(pid)s - %(conf)s)" %
667
787
  {'server': self.server, 'pid': pid, 'conf': conf_file})
668
788
  return 0
669
789
 
@@ -719,10 +839,8 @@ class Server(object):
719
839
  if proc.stdout.closed:
720
840
  output = ''
721
841
  else:
722
- output = proc.stdout.read()
842
+ output = proc.stdout.read().decode('utf8', 'backslashreplace')
723
843
  proc.stdout.close()
724
- if not six.PY2:
725
- output = output.decode('utf8', 'backslashreplace')
726
844
 
727
845
  if kwargs.get('once', False):
728
846
  # if you don't want once to wait you can send it to the
@@ -771,16 +889,16 @@ class Server(object):
771
889
  # any unstarted instances
772
890
  if conf_file in conf_files:
773
891
  already_started = True
774
- print(_("%(server)s running (%(pid)s - %(conf)s)") %
892
+ print("%(server)s running (%(pid)s - %(conf)s)" %
775
893
  {'server': self.server, 'pid': pid, 'conf': conf_file})
776
894
  elif not kwargs.get('number', 0):
777
895
  already_started = True
778
- print(_("%(server)s running (%(pid)s - %(pid_file)s)") %
896
+ print("%(server)s running (%(pid)s - %(pid_file)s)" %
779
897
  {'server': self.server, 'pid': pid,
780
898
  'pid_file': pid_file})
781
899
 
782
900
  if already_started:
783
- print(_("%s already started...") % self.server)
901
+ print("%s already started..." % self.server)
784
902
  return {}
785
903
 
786
904
  if self.server not in START_ONCE_SERVERS:
@@ -789,16 +907,16 @@ class Server(object):
789
907
  pids = {}
790
908
  for conf_file in conf_files:
791
909
  if kwargs.get('once'):
792
- msg = _('Running %s once') % self.server
910
+ msg = 'Running %s once' % self.server
793
911
  else:
794
- msg = _('Starting %s') % self.server
912
+ msg = 'Starting %s' % self.server
795
913
  print('%s...(%s)' % (msg, conf_file))
796
914
  try:
797
915
  pid = self.spawn(conf_file, **kwargs)
798
916
  except OSError as e:
799
917
  if e.errno == errno.ENOENT:
800
918
  # TODO(clayg): should I check if self.cmd exists earlier?
801
- print(_("%s does not exist") % self.cmd)
919
+ print("%s does not exist" % self.cmd)
802
920
  break
803
921
  else:
804
922
  raise
@@ -813,3 +931,102 @@ class Server(object):
813
931
 
814
932
  """
815
933
  return self.kill_running_pids(**kwargs)
934
+
935
+
936
+ USAGE = \
937
+ """%prog <server>[.<config>] [<server>[.<config>] ...] <command> [options]
938
+
939
+ where:
940
+ <server> is the name of a swift service e.g. proxy-server.
941
+ The '-server' part of the name may be omitted.
942
+ 'all', 'main' and 'rest' are reserved words that represent a
943
+ group of services.
944
+ all: Expands to all swift daemons.
945
+ main: Expands to main swift daemons.
946
+ (proxy, container, account, object)
947
+ rest: Expands to all remaining background daemons (beyond
948
+ "main").
949
+ (updater, replicator, auditor, etc)
950
+ <config> is an explicit configuration filename without the
951
+ .conf extension. If <config> is specified then <server> should
952
+ refer to a directory containing the configuration file, e.g.:
953
+
954
+ swift-init object.1 start
955
+
956
+ will start an object-server using the configuration file
957
+ /etc/swift/object-server/1.conf
958
+ <command> is a command from the list below.
959
+
960
+ Commands:
961
+ """ + '\n'.join(["%16s: %s" % x for x in Manager.list_commands()])
962
+
963
+
964
+ def main():
965
+ parser = OptionParser(USAGE)
966
+ parser.add_option('-v', '--verbose', action="store_true",
967
+ default=False, help="display verbose output")
968
+ parser.add_option('-w', '--no-wait', action="store_false", dest="wait",
969
+ default=True, help="won't wait for server to start "
970
+ "before returning")
971
+ parser.add_option('-o', '--once', action="store_true",
972
+ default=False, help="only run one pass of daemon")
973
+ # this is a negative option, default is options.daemon = True
974
+ parser.add_option('-n', '--no-daemon', action="store_false", dest="daemon",
975
+ default=True, help="start server interactively")
976
+ parser.add_option('-g', '--graceful', action="store_true",
977
+ default=False, help="send SIGHUP to supporting servers")
978
+ parser.add_option('-c', '--config-num', metavar="N", type="int",
979
+ dest="number", default=0,
980
+ help="send command to the Nth server only")
981
+ parser.add_option('-k', '--kill-wait', metavar="N", type="int",
982
+ dest="kill_wait", default=KILL_WAIT,
983
+ help="wait N seconds for processes to die (default 15)")
984
+ parser.add_option('-r', '--run-dir', type="str",
985
+ dest="run_dir", default=RUN_DIR,
986
+ help="alternative directory to store running pid files "
987
+ "default: %s" % RUN_DIR)
988
+ # Changing behaviour if missing config
989
+ parser.add_option('--strict', dest='strict', action='store_true',
990
+ help="Return non-zero status code if some config is "
991
+ "missing. Default mode if all servers are "
992
+ "explicitly named.")
993
+ # a negative option for strict
994
+ parser.add_option('--non-strict', dest='strict', action='store_false',
995
+ help="Return zero status code even if some config is "
996
+ "missing. Default mode if any server is a glob or "
997
+ "one of aliases `all`, `main` or `rest`.")
998
+ # SIGKILL daemon after kill_wait period
999
+ parser.add_option('--kill-after-timeout', dest='kill_after_timeout',
1000
+ action='store_true',
1001
+ help="Kill daemon and all children after kill-wait "
1002
+ "period.")
1003
+
1004
+ options, args = parser.parse_args()
1005
+
1006
+ if len(args) < 2:
1007
+ parser.print_help()
1008
+ print('ERROR: specify server(s) and command')
1009
+ return 1
1010
+
1011
+ command = args[-1]
1012
+ servers = args[:-1]
1013
+
1014
+ # this is just a silly swap for me cause I always try to "start main"
1015
+ commands = dict(Manager.list_commands()).keys()
1016
+ if command not in commands and servers[0] in commands:
1017
+ servers.append(command)
1018
+ command = servers.pop(0)
1019
+
1020
+ manager = Manager(servers, run_dir=options.run_dir)
1021
+ try:
1022
+ status = manager.run_command(command, **options.__dict__)
1023
+ except UnknownCommandError:
1024
+ parser.print_help()
1025
+ print('ERROR: unknown command, %s' % command)
1026
+ status = 1
1027
+
1028
+ return 1 if status else 0
1029
+
1030
+
1031
+ if __name__ == "__main__":
1032
+ sys.exit(main())