Merge lp:~cthier/swift/drybins into lp:~hudson-openstack/swift/trunk

Proposed by Chuck Thier
Status: Merged
Approved by: gholt
Approved revision: 68
Merged at revision: 67
Proposed branch: lp:~cthier/swift/drybins
Merge into: lp:~hudson-openstack/swift/trunk
Diff against target: 1152 lines (+241/-320)
26 files modified
bin/swift-account-auditor (+1/-30)
bin/swift-account-reaper (+1/-30)
bin/swift-account-replicator (+8/-25)
bin/swift-container-auditor (+1/-30)
bin/swift-container-replicator (+8/-24)
bin/swift-container-updater (+1/-23)
bin/swift-object-auditor (+1/-27)
bin/swift-object-replicator (+5/-44)
bin/swift-object-updater (+1/-24)
etc/proxy-server.conf-sample (+2/-2)
swift/account/auditor.py (+5/-4)
swift/account/reaper.py (+9/-7)
swift/account/replicator.py (+26/-0)
swift/common/daemon.py (+60/-0)
swift/common/db_replicator.py (+7/-6)
swift/common/utils.py (+2/-0)
swift/container/auditor.py (+5/-3)
swift/container/replicator.py (+25/-0)
swift/container/updater.py (+7/-5)
swift/obj/auditor.py (+8/-6)
swift/obj/replicator.py (+34/-8)
swift/obj/updater.py (+6/-4)
test/unit/common/test_db_replicator.py (+2/-2)
test/unit/container/test_updater.py (+7/-7)
test/unit/obj/test_replicator.py (+3/-3)
test/unit/obj/test_updater.py (+6/-6)
To merge this branch: bzr merge lp:~cthier/swift/drybins
Reviewer Review Type Date Requested Status
gholt (community) Approve
Review via email: mp+34256@code.launchpad.net

Description of the change

Refactored bin files to be more DRY

To post a comment you must log in.
Revision history for this message
Chuck Thier (cthier) wrote :

unit tests, functest, and probe tests all ran on my vm

Revision history for this message
gholt (gholt) wrote :

swift/account/reaper.py 110 has reference to self.reap_once()
swift/account/reaper.py 119 has reference to reap_forever
swift/common/db_replicator.py 435 has reference to self.replicate_once()

review: Needs Fixing
Revision history for this message
Chuck Thier (cthier) wrote :

> swift/account/reaper.py 110 has reference to self.reap_once()
> swift/account/reaper.py 119 has reference to reap_forever
> swift/common/db_replicator.py 435 has reference to self.replicate_once()

oops... thanks for catching that, should be fixed now

Revision history for this message
Jay Pipes (jaypipes) wrote :

Hi! You may want to use the existing daemon Python library instead of rewriting that stuff ;)

http://pypi.python.org/pypi/python-daemon/

Also, a litte nit: the standard way of passing options for daemonizing a process is not to pass "once" as a CLI arg, but to use CLI options, such as --nodaemon

Revision history for this message
Chuck Thier (cthier) wrote :

> Hi! You may want to use the existing daemon Python library instead of
> rewriting that stuff ;)
>
> http://pypi.python.org/pypi/python-daemon/
>
> Also, a litte nit: the standard way of passing options for daemonizing a
> process is not to pass "once" as a CLI arg, but to use CLI options, such as
> --nodaemon

Hey Jay, The main purpose of this was to refactor what we have currently to be more DRY. I'm not against moving to a standard lib for doing the daemon stuff, but don't have time to evaulate them. And as to the CLI args, I would like for those to change eventually as well, but that requires other changes as well, and was trying to keep the changes as minimal as possible.

Revision history for this message
gholt (gholt) wrote :

Thanks Chuck!

review: Approve

Preview Diff

[H/L] Next/Prev Comment, [J/K] Next/Prev File, [N/P] Next/Prev Hunk
1=== modified file 'bin/swift-account-auditor'
2--- bin/swift-account-auditor 2010-08-24 13:41:58 +0000
3+++ bin/swift-account-auditor 2010-09-01 15:57:44 +0000
4@@ -14,10 +14,7 @@
5 # See the License for the specific language governing permissions and
6 # limitations under the License.
7
8-import os
9-import signal
10 import sys
11-from ConfigParser import ConfigParser
12
13 from swift.account.auditor import AccountAuditor
14 from swift.common import utils
15@@ -26,32 +23,6 @@
16 if len(sys.argv) < 2:
17 print "Usage: swift-account-auditor CONFIG_FILE [once]"
18 sys.exit()
19-
20 once = len(sys.argv) > 2 and sys.argv[2] == 'once'
21-
22 conf = utils.readconf(sys.argv[1], 'account-auditor')
23- logger = utils.get_logger(conf)
24- # log uncaught exceptions
25- sys.excepthook = lambda *exc_info: \
26- logger.critical('UNCAUGHT EXCEPTION', exc_info=exc_info)
27- sys.stdout = sys.stderr = utils.LoggerFileObject(logger)
28-
29- utils.drop_privileges(conf.get('user', 'swift'))
30-
31- try:
32- os.setsid()
33- except OSError:
34- pass
35-
36- def kill_children(*args):
37- signal.signal(signal.SIGTERM, signal.SIG_IGN)
38- os.killpg(0, signal.SIGTERM)
39- sys.exit()
40-
41- signal.signal(signal.SIGTERM, kill_children)
42-
43- auditor = AccountAuditor(conf)
44- if once:
45- auditor.audit_once()
46- else:
47- auditor.audit_forever()
48+ auditor = AccountAuditor(conf).run(once)
49
50=== modified file 'bin/swift-account-reaper'
51--- bin/swift-account-reaper 2010-08-24 13:41:58 +0000
52+++ bin/swift-account-reaper 2010-09-01 15:57:44 +0000
53@@ -14,10 +14,7 @@
54 # See the License for the specific language governing permissions and
55 # limitations under the License.
56
57-import os
58-import signal
59 import sys
60-from ConfigParser import ConfigParser
61
62 from swift.account.reaper import AccountReaper
63 from swift.common import utils
64@@ -26,32 +23,6 @@
65 if len(sys.argv) < 2:
66 print "Usage: account-reaper CONFIG_FILE [once]"
67 sys.exit()
68-
69 once = len(sys.argv) > 2 and sys.argv[2] == 'once'
70-
71 conf = utils.readconf(sys.argv[1], 'account-reaper')
72- logger = utils.get_logger(conf)
73- # log uncaught exceptions
74- sys.excepthook = lambda *exc_info: \
75- logger.critical('UNCAUGHT EXCEPTION', exc_info=exc_info)
76- sys.stdout = sys.stderr = utils.LoggerFileObject(logger)
77-
78- utils.drop_privileges(conf.get('user', 'swift'))
79-
80- try:
81- os.setsid()
82- except OSError:
83- pass
84-
85- def kill_children(*args):
86- signal.signal(signal.SIGTERM, signal.SIG_IGN)
87- os.killpg(0, signal.SIGTERM)
88- sys.exit()
89-
90- signal.signal(signal.SIGTERM, kill_children)
91-
92- reaper = AccountReaper(conf)
93- if once:
94- reaper.reap_once()
95- else:
96- reaper.reap_forever()
97+ reaper = AccountReaper(conf).run(once)
98
99=== modified file 'bin/swift-account-replicator'
100--- bin/swift-account-replicator 2010-08-24 13:41:58 +0000
101+++ bin/swift-account-replicator 2010-09-01 15:57:44 +0000
102@@ -15,31 +15,14 @@
103 # limitations under the License.
104
105 import sys
106-from ConfigParser import ConfigParser
107-import getopt
108-
109-from swift.account import server as account_server
110-from swift.common import db, db_replicator, utils
111-
112-class AccountReplicator(db_replicator.Replicator):
113- server_type = 'account'
114- ring_file = 'account.ring.gz'
115- brokerclass = db.AccountBroker
116- datadir = account_server.DATADIR
117- default_port = 6002
118+
119+from swift.common import utils
120+from swift.account.replicator import AccountReplicator
121
122 if __name__ == '__main__':
123- optlist, args = getopt.getopt(sys.argv[1:], '', ['once'])
124-
125- if not args:
126- print "Usage: swift-account-replicator <--once> CONFIG_FILE [once]"
127- sys.exit()
128-
129- once = len(args) > 1 and args[1] == 'once'
130+ if len(sys.argv) < 2:
131+ print "Usage: swift-account-replicator CONFIG_FILE [once]"
132+ sys.exit(1)
133+ once = len(sys.argv) > 2 and sys.argv[2] == 'once'
134 conf = utils.readconf(sys.argv[1], 'account-replicator')
135- utils.drop_privileges(conf.get('user', 'swift'))
136- if once or '--once' in [opt[0] for opt in optlist]:
137- AccountReplicator(conf).replicate_once()
138- else:
139- AccountReplicator(conf).replicate_forever()
140-
141+ AccountReplicator(conf).run(once)
142
143=== modified file 'bin/swift-container-auditor'
144--- bin/swift-container-auditor 2010-08-24 13:41:58 +0000
145+++ bin/swift-container-auditor 2010-09-01 15:57:44 +0000
146@@ -14,10 +14,7 @@
147 # See the License for the specific language governing permissions and
148 # limitations under the License.
149
150-import os
151-import signal
152 import sys
153-from ConfigParser import ConfigParser
154
155 from swift.container.auditor import ContainerAuditor
156 from swift.common import utils
157@@ -26,32 +23,6 @@
158 if len(sys.argv) < 2:
159 print "Usage: swift-container-auditor CONFIG_FILE [once]"
160 sys.exit()
161-
162 once = len(sys.argv) > 2 and sys.argv[2] == 'once'
163-
164 conf = utils.readconf(sys.argv[1], 'container-auditor')
165- logger = utils.get_logger(conf)
166- # log uncaught exceptions
167- sys.excepthook = lambda *exc_info: \
168- logger.critical('UNCAUGHT EXCEPTION', exc_info=exc_info)
169- sys.stdout = sys.stderr = utils.LoggerFileObject(logger)
170-
171- utils.drop_privileges(conf.get('user', 'swift'))
172-
173- try:
174- os.setsid()
175- except OSError:
176- pass
177-
178- def kill_children(*args):
179- signal.signal(signal.SIGTERM, signal.SIG_IGN)
180- os.killpg(0, signal.SIGTERM)
181- sys.exit()
182-
183- signal.signal(signal.SIGTERM, kill_children)
184-
185- auditor = ContainerAuditor(conf)
186- if once:
187- auditor.audit_once()
188- else:
189- auditor.audit_forever()
190+ ContainerAuditor(conf).run(once)
191
192=== modified file 'bin/swift-container-replicator'
193--- bin/swift-container-replicator 2010-08-24 13:41:58 +0000
194+++ bin/swift-container-replicator 2010-09-01 15:57:44 +0000
195@@ -15,31 +15,15 @@
196 # limitations under the License.
197
198 import sys
199-from ConfigParser import ConfigParser
200-import getopt
201-
202-from swift.container import server as container_server
203-from swift.common import db, db_replicator, utils
204-
205-class ContainerReplicator(db_replicator.Replicator):
206- server_type = 'container'
207- ring_file = 'container.ring.gz'
208- brokerclass = db.ContainerBroker
209- datadir = container_server.DATADIR
210- default_port = 6001
211+
212+from swift.common import db, utils
213+from swift.container.replicator import ContainerReplicator
214
215 if __name__ == '__main__':
216- optlist, args = getopt.getopt(sys.argv[1:], '', ['once'])
217-
218- if not args:
219- print "Usage: swift-container-replicator <--once> CONFIG_FILE [once]"
220+ if len(sys.argv) < 2:
221+ print "Usage: swift-container-replicator CONFIG_FILE [once]"
222 sys.exit(1)
223-
224- once = len(args) > 1 and args[1] == 'once'
225- conf = utils.readconf(args[0], 'container-replicator')
226- utils.drop_privileges(conf.get('user', 'swift'))
227- if once or '--once' in [opt[0] for opt in optlist]:
228- ContainerReplicator(conf).replicate_once()
229- else:
230- ContainerReplicator(conf).replicate_forever()
231+ once = len(sys.argv) > 2 and sys.argv[2] == 'once'
232+ conf = utils.readconf(sys.argv[1], 'container-replicator')
233+ ContainerReplicator(conf).run(once)
234
235
236=== modified file 'bin/swift-container-updater'
237--- bin/swift-container-updater 2010-08-24 14:55:20 +0000
238+++ bin/swift-container-updater 2010-09-01 15:57:44 +0000
239@@ -14,10 +14,7 @@
240 # See the License for the specific language governing permissions and
241 # limitations under the License.
242
243-import os
244-import signal
245 import sys
246-from ConfigParser import ConfigParser
247
248 from swift.container.updater import ContainerUpdater
249 from swift.common import utils
250@@ -26,25 +23,6 @@
251 if len(sys.argv) < 2:
252 print "Usage: swift-container-updater CONFIG_FILE [once]"
253 sys.exit()
254-
255 once = len(sys.argv) > 2 and sys.argv[2] == 'once'
256 conf = utils.readconf(sys.argv[1], 'container-updater')
257- utils.drop_privileges(conf.get('user', 'swift'))
258-
259- try:
260- os.setsid()
261- except OSError:
262- pass
263-
264- def kill_children(*args):
265- signal.signal(signal.SIGTERM, signal.SIG_IGN)
266- os.killpg(0, signal.SIGTERM)
267- sys.exit()
268-
269- signal.signal(signal.SIGTERM, kill_children)
270-
271- updater = ContainerUpdater(conf)
272- if once:
273- updater.update_once_single_threaded()
274- else:
275- updater.update_forever()
276+ ContainerUpdater(conf).run(once)
277
278=== modified file 'bin/swift-object-auditor'
279--- bin/swift-object-auditor 2010-08-24 13:41:58 +0000
280+++ bin/swift-object-auditor 2010-09-01 15:57:44 +0000
281@@ -14,8 +14,6 @@
282 # See the License for the specific language governing permissions and
283 # limitations under the License.
284
285-import os
286-import signal
287 import sys
288
289 from swift.obj.auditor import ObjectAuditor
290@@ -28,28 +26,4 @@
291
292 once = len(sys.argv) > 2 and sys.argv[2] == 'once'
293 conf = utils.readconf(sys.argv[1], 'object-auditor')
294- logger = utils.get_logger(conf)
295- # log uncaught exceptions
296- sys.excepthook = lambda *exc_info: \
297- logger.critical('UNCAUGHT EXCEPTION', exc_info=exc_info)
298- sys.stdout = sys.stderr = utils.LoggerFileObject(logger)
299-
300- utils.drop_privileges(conf.get('user', 'swift'))
301-
302- try:
303- os.setsid()
304- except OSError:
305- pass
306-
307- def kill_children(*args):
308- signal.signal(signal.SIGTERM, signal.SIG_IGN)
309- os.killpg(0, signal.SIGTERM)
310- sys.exit()
311-
312- signal.signal(signal.SIGTERM, kill_children)
313-
314- auditor = ObjectAuditor(conf)
315- if once:
316- auditor.audit_once()
317- else:
318- auditor.audit_forever()
319+ ObjectAuditor(conf).run(once)
320
321=== modified file 'bin/swift-object-replicator'
322--- bin/swift-object-replicator 2010-08-24 13:41:58 +0000
323+++ bin/swift-object-replicator 2010-09-01 15:57:44 +0000
324@@ -15,54 +15,15 @@
325 # limitations under the License.
326
327 import sys
328-import logging
329-import time
330-
331-from eventlet import sleep, hubs
332-hubs.use_hub('poll')
333
334 from swift.obj.replicator import ObjectReplicator
335-from swift.common.utils import get_logger, drop_privileges, LoggerFileObject, \
336- readconf
337-
338-TRUE_VALUES = set(('true', '1', 'yes', 'True', 'Yes'))
339+from swift.common import utils
340
341 if __name__ == '__main__':
342 if len(sys.argv) < 2:
343 print "Usage: swift-object-replicator CONFIG_FILE [once]"
344 sys.exit()
345- conf = readconf(sys.argv[1], "object-replicator")
346- once = len(sys.argv) > 2 and sys.argv[2] == 'once'
347- logger = get_logger(conf)
348- # log uncaught exceptions
349- sys.excepthook = lambda *exc_info: \
350- logger.critical('UNCAUGHT EXCEPTION', exc_info=exc_info)
351- sys.stdout = sys.stderr = LoggerFileObject(logger)
352- drop_privileges(conf.get('user', 'swift'))
353- if not once and conf.get('daemonize', 'true') in TRUE_VALUES:
354- logger.info("Starting object replicator in daemon mode.")
355- # Run the replicator continually
356- while True:
357- start = time.time()
358- logger.info("Starting object replication pass.")
359- # Run the replicator
360- replicator = ObjectReplicator(conf, logger)
361- replicator.run()
362- total = (time.time() - start)/60
363- # Reload the config
364- logger.info("Object replication complete. (%.02f minutes)" % total)
365- conf = read_configs(sys.argv[1])
366- if conf.get('daemonize', 'true') not in TRUE_VALUES:
367- # Stop running
368- logger.info("Daemon mode turned off in config, stopping.")
369- break
370- logger.debug('Replication sleeping for %s seconds.' %
371- conf['run_pause'])
372- sleep(int(conf['run_pause']))
373- else:
374- start = time.time()
375- logger.info("Running object replicator in script mode.")
376- replicator = ObjectReplicator(conf, logger)
377- replicator.run()
378- total = (time.time() - start)/60
379- logger.info("Object replication complete. (%.02f minutes)" % total)
380+ conf = utils.readconf(sys.argv[1], "object-replicator")
381+ once = (len(sys.argv) > 2 and sys.argv[2] == 'once') or \
382+ conf.get('daemonize', 'true') not in utils.TRUE_VALUES
383+ ObjectReplicator(conf).run(once)
384
385=== modified file 'bin/swift-object-updater'
386--- bin/swift-object-updater 2010-08-24 13:41:58 +0000
387+++ bin/swift-object-updater 2010-09-01 15:57:44 +0000
388@@ -14,8 +14,6 @@
389 # See the License for the specific language governing permissions and
390 # limitations under the License.
391
392-import os
393-import signal
394 import sys
395
396 from swift.obj.updater import ObjectUpdater
397@@ -25,27 +23,6 @@
398 if len(sys.argv) < 2:
399 print "Usage: swift-object-updater CONFIG_FILE [once]"
400 sys.exit(1)
401-
402 once = len(sys.argv) > 2 and sys.argv[2] == 'once'
403-
404 conf = utils.readconf(sys.argv[1], 'object-updater')
405- utils.drop_privileges(conf.get('user', 'swift'))
406-
407- try:
408- os.setsid()
409- except OSError:
410- pass
411-
412- def kill_children(*args):
413- signal.signal(signal.SIGTERM, signal.SIG_IGN)
414- os.killpg(0, signal.SIGTERM)
415- sys.exit()
416-
417- signal.signal(signal.SIGTERM, kill_children)
418-
419- updater = ObjectUpdater(conf)
420- if once:
421- updater.update_once_single_threaded()
422- else:
423- updater.update_forever()
424-
425+ ObjectUpdater(conf).run(once)
426
427=== modified file 'etc/proxy-server.conf-sample'
428--- etc/proxy-server.conf-sample 2010-08-24 13:58:32 +0000
429+++ etc/proxy-server.conf-sample 2010-09-01 15:57:44 +0000
430@@ -8,9 +8,9 @@
431 # key_file = /etc/swift/proxy.key
432
433 [pipeline:main]
434-pipeline = healthcheck cache auth proxy
435+pipeline = healthcheck cache auth proxy-server
436
437-[app:proxy]
438+[app:proxy-server]
439 use = egg:swift#proxy
440 # log_name = proxy-server
441 # log_facility = LOG_LOCAL0
442
443=== modified file 'swift/account/auditor.py'
444--- swift/account/auditor.py 2010-08-20 00:42:38 +0000
445+++ swift/account/auditor.py 2010-09-01 15:57:44 +0000
446@@ -26,16 +26,18 @@
447 from swift.common.exceptions import ConnectionTimeout
448 from swift.common.ring import Ring
449 from swift.common.utils import get_logger
450+from swift.common.daemon import Daemon
451
452
453 class AuditException(Exception):
454 pass
455
456
457-class AccountAuditor(object):
458+class AccountAuditor(Daemon):
459 """Audit accounts."""
460
461 def __init__(self, conf):
462+ self.conf = conf
463 self.logger = get_logger(conf, 'account-auditor')
464 self.devices = conf.get('devices', '/srv/node')
465 self.mount_check = conf.get('mount_check', 'true').lower() in \
466@@ -60,12 +62,11 @@
467 """
468 if not self.container_ring:
469 self.logger.debug(
470-
471 'Loading container ring from %s' % self.container_ring_path)
472 self.container_ring = Ring(self.container_ring_path)
473 return self.container_ring
474
475- def audit_forever(self): # pragma: no cover
476+ def run_forever(self): # pragma: no cover
477 """Run the account audit until stopped."""
478 reported = time.time()
479 time.sleep(random() * self.interval)
480@@ -92,7 +93,7 @@
481 if elapsed < self.interval:
482 time.sleep(self.interval - elapsed)
483
484- def audit_once(self):
485+ def run_once(self):
486 """Run the account audit once."""
487 self.logger.info('Begin account audit "once" mode')
488 begin = time.time()
489
490=== modified file 'swift/account/reaper.py'
491--- swift/account/reaper.py 2010-08-20 00:42:38 +0000
492+++ swift/account/reaper.py 2010-09-01 15:57:44 +0000
493@@ -27,9 +27,10 @@
494 direct_delete_container, direct_delete_object, direct_get_container
495 from swift.common.ring import Ring
496 from swift.common.utils import get_logger, whataremyips
497-
498-
499-class AccountReaper(object):
500+from swift.common.daemon import Daemon
501+
502+
503+class AccountReaper(Daemon):
504 """
505 Removes data from status=DELETED accounts. These are accounts that have
506 been asked to be removed by the reseller via services
507@@ -51,6 +52,7 @@
508 """
509
510 def __init__(self, conf):
511+ self.conf = conf
512 self.logger = get_logger(conf)
513 self.devices = conf.get('devices', '/srv/node')
514 self.mount_check = conf.get('mount_check', 'true').lower() in \
515@@ -95,7 +97,7 @@
516 self.object_ring = Ring(self.object_ring_path)
517 return self.object_ring
518
519- def reap_forever(self):
520+ def run_forever(self):
521 """
522 Main entry point when running the reaper in its normal daemon mode.
523 This repeatedly calls :func:`reap_once` no quicker than the
524@@ -105,16 +107,16 @@
525 sleep(random.random() * self.interval)
526 while True:
527 begin = time()
528- self.reap_once()
529+ self.run_once()
530 elapsed = time() - begin
531 if elapsed < self.interval:
532 sleep(self.interval - elapsed)
533
534- def reap_once(self):
535+ def run_once(self):
536 """
537 Main entry point when running the reaper in 'once' mode, where it will
538 do a single pass over all accounts on the server. This is called
539- repeatedly by :func:`reap_forever`. This will call :func:`reap_device`
540+ repeatedly by :func:`run_forever`. This will call :func:`reap_device`
541 once for each device on the server.
542 """
543 self.logger.debug('Begin devices pass: %s' % self.devices)
544
545=== added file 'swift/account/replicator.py'
546--- swift/account/replicator.py 1970-01-01 00:00:00 +0000
547+++ swift/account/replicator.py 2010-09-01 15:57:44 +0000
548@@ -0,0 +1,26 @@
549+# Copyright (c) 2010 OpenStack, LLC.
550+#
551+# Licensed under the Apache License, Version 2.0 (the "License");
552+# you may not use this file except in compliance with the License.
553+# You may obtain a copy of the License at
554+#
555+# http://www.apache.org/licenses/LICENSE-2.0
556+#
557+# Unless required by applicable law or agreed to in writing, software
558+# distributed under the License is distributed on an "AS IS" BASIS,
559+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or
560+# implied.
561+# See the License for the specific language governing permissions and
562+# limitations under the License.
563+
564+from swift.account import server as account_server
565+from swift.common import db, db_replicator
566+
567+
568+class AccountReplicator(db_replicator.Replicator):
569+ server_type = 'account'
570+ ring_file = 'account.ring.gz'
571+ brokerclass = db.AccountBroker
572+ datadir = account_server.DATADIR
573+ default_port = 6002
574+
575
576=== added file 'swift/common/daemon.py'
577--- swift/common/daemon.py 1970-01-01 00:00:00 +0000
578+++ swift/common/daemon.py 2010-09-01 15:57:44 +0000
579@@ -0,0 +1,60 @@
580+# Copyright (c) 2010 OpenStack, LLC.
581+#
582+# Licensed under the Apache License, Version 2.0 (the "License");
583+# you may not use this file except in compliance with the License.
584+# You may obtain a copy of the License at
585+#
586+# http://www.apache.org/licenses/LICENSE-2.0
587+#
588+# Unless required by applicable law or agreed to in writing, software
589+# distributed under the License is distributed on an "AS IS" BASIS,
590+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or
591+# implied.
592+# See the License for the specific language governing permissions and
593+# limitations under the License.
594+
595+import os
596+import sys
597+import signal
598+from swift.common import utils
599+
600+class Daemon(object):
601+ """Daemon base class"""
602+
603+ def __init__(self, conf):
604+ self.conf = conf
605+ self.logger = utils.get_logger(conf, 'swift-daemon')
606+
607+ def run_once(self):
608+ """Override this to run the script once"""
609+ raise NotImplementedError('run_once not implemented')
610+
611+ def run_forever(self):
612+ """Override this to run forever"""
613+ raise NotImplementedError('run_forever not implemented')
614+
615+ def run(self, once=False):
616+ """Run the daemon"""
617+ # log uncaught exceptions
618+ sys.excepthook = lambda *exc_info: \
619+ self.logger.critical('UNCAUGHT EXCEPTION', exc_info=exc_info)
620+ sys.stdout = sys.stderr = utils.LoggerFileObject(self.logger)
621+
622+ utils.drop_privileges(self.conf.get('user', 'swift'))
623+
624+ try:
625+ os.setsid()
626+ except OSError:
627+ pass
628+
629+ def kill_children(*args):
630+ signal.signal(signal.SIGTERM, signal.SIG_IGN)
631+ os.killpg(0, signal.SIGTERM)
632+ sys.exit()
633+
634+ signal.signal(signal.SIGTERM, kill_children)
635+
636+ if once:
637+ self.run_once()
638+ else:
639+ self.run_forever()
640
641=== modified file 'swift/common/db_replicator.py'
642--- swift/common/db_replicator.py 2010-08-20 00:50:12 +0000
643+++ swift/common/db_replicator.py 2010-09-01 15:57:44 +0000
644@@ -33,6 +33,7 @@
645 from swift.common import ring
646 from swift.common.bufferedhttp import BufferedHTTPConnection
647 from swift.common.exceptions import DriveNotMounted, ConnectionTimeout
648+from swift.common.daemon import Daemon
649
650
651 def quarantine_db(object_file, server_type):
652@@ -84,14 +85,14 @@
653 return None
654
655
656-class Replicator(object):
657+class Replicator(Daemon):
658 """
659 Implements the logic for directing db replication.
660 """
661
662 def __init__(self, conf):
663- self.logger = \
664- get_logger(conf)
665+ self.conf = conf
666+ self.logger = get_logger(conf)
667 # log uncaught exceptions
668 sys.excepthook = lambda * exc_info: \
669 self.logger.critical('UNCAUGHT EXCEPTION', exc_info=exc_info)
670@@ -396,7 +397,7 @@
671 except StopIteration:
672 its.remove(it)
673
674- def replicate_once(self):
675+ def run_once(self):
676 """Run a replication pass once."""
677 self._zero_stats()
678 dirs = []
679@@ -425,13 +426,13 @@
680 self.logger.info('Replication run OVER')
681 self._report_stats()
682
683- def replicate_forever(self):
684+ def run_forever(self):
685 """
686 Replicate dbs under the given root in an infinite loop.
687 """
688 while True:
689 try:
690- self.replicate_once()
691+ self.run_once()
692 except:
693 self.logger.exception('ERROR trying to replicate')
694 sleep(self.run_pause)
695
696=== modified file 'swift/common/utils.py'
697--- swift/common/utils.py 2010-08-24 13:41:58 +0000
698+++ swift/common/utils.py 2010-09-01 15:57:44 +0000
699@@ -55,6 +55,8 @@
700 # will end up with would also require knowing this suffix.
701 HASH_PATH_SUFFIX = os.environ.get('SWIFT_HASH_PATH_SUFFIX', 'endcap')
702
703+# Used when reading config values
704+TRUE_VALUES = set(('true', '1', 'yes', 'True', 'Yes'))
705
706 def load_libc_function(func_name):
707 """
708
709=== modified file 'swift/container/auditor.py'
710--- swift/container/auditor.py 2010-08-20 00:42:38 +0000
711+++ swift/container/auditor.py 2010-09-01 15:57:44 +0000
712@@ -27,16 +27,18 @@
713 from swift.common.exceptions import ConnectionTimeout
714 from swift.common.ring import Ring
715 from swift.common.utils import get_logger
716+from swift.common.daemon import Daemon
717
718
719 class AuditException(Exception):
720 pass
721
722
723-class ContainerAuditor(object):
724+class ContainerAuditor(Daemon):
725 """Audit containers."""
726
727 def __init__(self, conf):
728+ self.conf = conf
729 self.logger = get_logger(conf)
730 self.devices = conf.get('devices', '/srv/node')
731 self.mount_check = conf.get('mount_check', 'true').lower() in \
732@@ -81,7 +83,7 @@
733 self.object_ring = Ring(self.object_ring_path)
734 return self.object_ring
735
736- def audit_forever(self): # pragma: no cover
737+ def run_forever(self): # pragma: no cover
738 """Run the container audit until stopped."""
739 reported = time.time()
740 time.sleep(random() * self.interval)
741@@ -114,7 +116,7 @@
742 if elapsed < self.interval:
743 time.sleep(self.interval - elapsed)
744
745- def audit_once(self):
746+ def run_once(self):
747 """Run the container audit once."""
748 self.logger.info('Begin container audit "once" mode')
749 begin = time.time()
750
751=== added file 'swift/container/replicator.py'
752--- swift/container/replicator.py 1970-01-01 00:00:00 +0000
753+++ swift/container/replicator.py 2010-09-01 15:57:44 +0000
754@@ -0,0 +1,25 @@
755+# Copyright (c) 2010 OpenStack, LLC.
756+#
757+# Licensed under the Apache License, Version 2.0 (the "License");
758+# you may not use this file except in compliance with the License.
759+# You may obtain a copy of the License at
760+#
761+# http://www.apache.org/licenses/LICENSE-2.0
762+#
763+# Unless required by applicable law or agreed to in writing, software
764+# distributed under the License is distributed on an "AS IS" BASIS,
765+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or
766+# implied.
767+# See the License for the specific language governing permissions and
768+# limitations under the License.
769+
770+from swift.container import server as container_server
771+from swift.common import db, db_replicator
772+
773+class ContainerReplicator(db_replicator.Replicator):
774+ server_type = 'container'
775+ ring_file = 'container.ring.gz'
776+ brokerclass = db.ContainerBroker
777+ datadir = container_server.DATADIR
778+ default_port = 6001
779+
780
781=== modified file 'swift/container/updater.py'
782--- swift/container/updater.py 2010-08-20 00:42:38 +0000
783+++ swift/container/updater.py 2010-09-01 15:57:44 +0000
784@@ -28,12 +28,14 @@
785 from swift.common.exceptions import ConnectionTimeout
786 from swift.common.ring import Ring
787 from swift.common.utils import get_logger, whataremyips
788-
789-
790-class ContainerUpdater(object):
791+from swift.common.daemon import Daemon
792+
793+
794+class ContainerUpdater(Daemon):
795 """Update container information in account listings."""
796
797 def __init__(self, conf):
798+ self.conf = conf
799 self.logger = get_logger(conf, 'container-updater')
800 self.devices = conf.get('devices', '/srv/node')
801 self.mount_check = conf.get('mount_check', 'true').lower() in \
802@@ -78,7 +80,7 @@
803 shuffle(paths)
804 return paths
805
806- def update_forever(self): # pragma: no cover
807+ def run_forever(self): # pragma: no cover
808 """
809 Run the updator continuously.
810 """
811@@ -118,7 +120,7 @@
812 if elapsed < self.interval:
813 time.sleep(self.interval - elapsed)
814
815- def update_once_single_threaded(self):
816+ def run_once(self):
817 """
818 Run the updater once.
819 """
820
821=== modified file 'swift/obj/auditor.py'
822--- swift/obj/auditor.py 2010-08-20 00:42:38 +0000
823+++ swift/obj/auditor.py 2010-09-01 15:57:44 +0000
824@@ -28,13 +28,15 @@
825 from swift.common.ring import Ring
826 from swift.common.utils import get_logger, renamer
827 from swift.common.exceptions import AuditException
828-
829-
830-class ObjectAuditor(object):
831+from swift.common.daemon import Daemon
832+
833+
834+class ObjectAuditor(Daemon):
835 """Audit objects."""
836
837 def __init__(self, conf):
838- self.logger = get_logger(conf)
839+ self.conf = conf
840+ self.logger = get_logger(conf, 'object-auditor')
841 self.devices = conf.get('devices', '/srv/node')
842 self.mount_check = conf.get('mount_check', 'true').lower() in \
843 ('true', 't', '1', 'on', 'yes', 'y')
844@@ -63,7 +65,7 @@
845 self.container_ring = Ring(self.container_ring_path)
846 return self.container_ring
847
848- def audit_forever(self): # pragma: no cover
849+ def run_forever(self): # pragma: no cover
850 """Run the object audit until stopped."""
851 reported = time.time()
852 time.sleep(random() * self.interval)
853@@ -97,7 +99,7 @@
854 if elapsed < self.interval:
855 time.sleep(self.interval - elapsed)
856
857- def audit_once(self):
858+ def run_once(self):
859 """Run the object audit once."""
860 self.logger.info('Begin object audit "once" mode')
861 begin = time.time()
862
863=== modified file 'swift/obj/replicator.py'
864--- swift/obj/replicator.py 2010-08-24 18:27:38 +0000
865+++ swift/obj/replicator.py 2010-09-01 15:57:44 +0000
866@@ -24,15 +24,17 @@
867 import cPickle as pickle
868
869 import eventlet
870-from eventlet import GreenPool, tpool, Timeout, sleep
871+from eventlet import GreenPool, tpool, Timeout, sleep, hubs
872 from eventlet.green import subprocess
873 from eventlet.support.greenlets import GreenletExit
874
875 from swift.common.ring import Ring
876 from swift.common.utils import whataremyips, unlink_older_than, lock_path, \
877- renamer, compute_eta
878+ renamer, compute_eta, get_logger
879 from swift.common.bufferedhttp import http_connect
880+from swift.common.daemon import Daemon
881
882+hubs.use_hub('poll')
883
884 PICKLE_PROTOCOL = 2
885 ONE_WEEK = 604800
886@@ -190,22 +192,22 @@
887 return hashed, hashes
888
889
890-class ObjectReplicator(object):
891+class ObjectReplicator(Daemon):
892 """
893 Replicate objects.
894
895 Encapsulates most logic and data needed by the object replication process.
896- Each call to .run() performs one replication pass. It's up to the caller
897- to do this in a loop.
898+ Each call to .replicate() performs one replication pass. It's up to the
899+ caller to do this in a loop.
900 """
901
902- def __init__(self, conf, logger):
903+ def __init__(self, conf):
904 """
905 :param conf: configuration object obtained from ConfigParser
906 :param logger: logging object
907 """
908 self.conf = conf
909- self.logger = logger
910+ self.logger = get_logger(conf, 'object-replicator')
911 self.devices_dir = conf.get('devices', '/srv/node')
912 self.mount_check = conf.get('mount_check', 'true').lower() in \
913 ('true', 't', '1', 'on', 'yes', 'y')
914@@ -221,6 +223,7 @@
915 self.next_check = time.time() + self.ring_check_interval
916 self.reclaim_age = int(conf.get('reclaim_age', 86400 * 7))
917 self.partition_times = []
918+ self.run_pause = int(conf.get('run_pause', 30))
919
920 def _rsync(self, args):
921 """
922@@ -450,7 +453,7 @@
923 eventlet.sleep(300)
924 self.stats_line()
925
926- def run(self):
927+ def replicate(self):
928 """Run a replication pass"""
929 self.start = time.time()
930 self.suffix_count = 0
931@@ -506,3 +509,26 @@
932 self.kill_coros()
933 self.stats_line()
934 stats.kill()
935+
936+ def run_once(self):
937+ start = time.time()
938+ self.logger.info("Running object replicator in script mode.")
939+ self.replicate()
940+ total = (time.time() - start)/60
941+ self.logger.info(
942+ "Object replication complete. (%.02f minutes)" % total)
943+
944+ def run_forever(self):
945+ self.logger.info("Starting object replicator in daemon mode.")
946+ # Run the replicator continually
947+ while True:
948+ start = time.time()
949+ self.logger.info("Starting object replication pass.")
950+ # Run the replicator
951+ self.replicate()
952+ total = (time.time() - start)/60
953+ self.logger.info(
954+ "Object replication complete. (%.02f minutes)" % total)
955+ self.logger.debug('Replication sleeping for %s seconds.' %
956+ self.run_pause)
957+ sleep(self.run_pause)
958
959=== modified file 'swift/obj/updater.py'
960--- swift/obj/updater.py 2010-08-20 00:42:38 +0000
961+++ swift/obj/updater.py 2010-09-01 15:57:44 +0000
962@@ -26,14 +26,16 @@
963 from swift.common.exceptions import ConnectionTimeout
964 from swift.common.ring import Ring
965 from swift.common.utils import get_logger, renamer
966+from swift.common.daemon import Daemon
967 from swift.obj.server import ASYNCDIR
968
969
970-class ObjectUpdater(object):
971+class ObjectUpdater(Daemon):
972 """Update object information in container listings."""
973
974 def __init__(self, conf):
975- self.logger = get_logger(conf)
976+ self.conf = conf
977+ self.logger = get_logger(conf, 'object-updater')
978 self.devices = conf.get('devices', '/srv/node')
979 self.mount_check = conf.get('mount_check', 'true').lower() in \
980 ('true', 't', '1', 'on', 'yes', 'y')
981@@ -56,7 +58,7 @@
982 self.container_ring = Ring(self.container_ring_path)
983 return self.container_ring
984
985- def update_forever(self): # pragma: no cover
986+ def run_forever(self): # pragma: no cover
987 """Run the updater continuously."""
988 time.sleep(random() * self.interval)
989 while True:
990@@ -95,7 +97,7 @@
991 if elapsed < self.interval:
992 time.sleep(self.interval - elapsed)
993
994- def update_once_single_threaded(self):
995+ def run_once(self):
996 """Run the updater once"""
997 self.logger.info('Begin object update single threaded sweep')
998 begin = time.time()
999
1000=== modified file 'test/unit/common/test_db_replicator.py'
1001--- test/unit/common/test_db_replicator.py 2010-08-20 00:50:12 +0000
1002+++ test/unit/common/test_db_replicator.py 2010-09-01 15:57:44 +0000
1003@@ -170,9 +170,9 @@
1004 {'id': 'a', 'point': -1, 'max_row': 10, 'hash': 'd'},
1005 FakeBroker(), -1)), False)
1006
1007- def test_replicate_once(self):
1008+ def test_run_once(self):
1009 replicator = TestReplicator({})
1010- replicator.replicate_once()
1011+ replicator.run_once()
1012
1013 def test_usync(self):
1014 fake_http = ReplHttp()
1015
1016=== modified file 'test/unit/container/test_updater.py'
1017--- test/unit/container/test_updater.py 2010-08-20 00:42:38 +0000
1018+++ test/unit/container/test_updater.py 2010-09-01 15:57:44 +0000
1019@@ -77,7 +77,7 @@
1020 self.assertEquals(cu.node_timeout, 5)
1021 self.assert_(cu.get_account_ring() is not None)
1022
1023- def test_update_once_single_threaded(self):
1024+ def test_run_once(self):
1025 cu = container_updater.ContainerUpdater({
1026 'devices': self.devices_dir,
1027 'mount_check': 'false',
1028@@ -86,17 +86,17 @@
1029 'concurrency': '1',
1030 'node_timeout': '15',
1031 })
1032- cu.update_once_single_threaded()
1033+ cu.run_once()
1034 containers_dir = os.path.join(self.sda1, container_server.DATADIR)
1035 os.mkdir(containers_dir)
1036- cu.update_once_single_threaded()
1037+ cu.run_once()
1038 self.assert_(os.path.exists(containers_dir))
1039 subdir = os.path.join(containers_dir, 'subdir')
1040 os.mkdir(subdir)
1041 cb = ContainerBroker(os.path.join(subdir, 'hash.db'), account='a',
1042 container='c')
1043 cb.initialize(normalize_timestamp(1))
1044- cu.update_once_single_threaded()
1045+ cu.run_once()
1046 info = cb.get_info()
1047 self.assertEquals(info['object_count'], 0)
1048 self.assertEquals(info['bytes_used'], 0)
1049@@ -105,7 +105,7 @@
1050
1051 cb.put_object('o', normalize_timestamp(2), 3, 'text/plain',
1052 '68b329da9893e34099c7d8ad5cb9c940')
1053- cu.update_once_single_threaded()
1054+ cu.run_once()
1055 info = cb.get_info()
1056 self.assertEquals(info['object_count'], 1)
1057 self.assertEquals(info['bytes_used'], 3)
1058@@ -148,7 +148,7 @@
1059 for dev in cu.get_account_ring().devs:
1060 if dev is not None:
1061 dev['port'] = bindsock.getsockname()[1]
1062- cu.update_once_single_threaded()
1063+ cu.run_once()
1064 for event in spawned.wait():
1065 err = event.wait()
1066 if err:
1067@@ -202,7 +202,7 @@
1068 for dev in cu.get_account_ring().devs:
1069 if dev is not None:
1070 dev['port'] = bindsock.getsockname()[1]
1071- cu.update_once_single_threaded()
1072+ cu.run_once()
1073 for event in spawned.wait():
1074 err = event.wait()
1075 if err:
1076
1077=== modified file 'test/unit/obj/test_replicator.py'
1078--- test/unit/obj/test_replicator.py 2010-07-19 16:25:18 +0000
1079+++ test/unit/obj/test_replicator.py 2010-09-01 15:57:44 +0000
1080@@ -105,7 +105,7 @@
1081 swift_dir=self.testdir, devices=self.devices, mount_check='false',
1082 timeout='300', stats_interval='1')
1083 self.replicator = object_replicator.ObjectReplicator(
1084- self.conf, null_logger)
1085+ self.conf)
1086
1087 # def test_check_ring(self):
1088 # self.replicator.collect_jobs('sda', 0, self.ring)
1089@@ -184,11 +184,11 @@
1090
1091 def test_run(self):
1092 with _mock_process([(0,'')]*100):
1093- self.replicator.run()
1094+ self.replicator.replicate()
1095
1096 def test_run_withlog(self):
1097 with _mock_process([(0,"stuff in log")]*100):
1098- self.replicator.run()
1099+ self.replicator.replicate()
1100
1101 if __name__ == '__main__':
1102 unittest.main()
1103
1104=== modified file 'test/unit/obj/test_updater.py'
1105--- test/unit/obj/test_updater.py 2010-08-26 16:03:08 +0000
1106+++ test/unit/obj/test_updater.py 2010-09-01 15:57:44 +0000
1107@@ -69,7 +69,7 @@
1108 self.assertEquals(cu.node_timeout, 5)
1109 self.assert_(cu.get_container_ring() is not None)
1110
1111- def test_update_once_single_threaded(self):
1112+ def test_run_once(self):
1113 cu = object_updater.ObjectUpdater({
1114 'devices': self.devices_dir,
1115 'mount_check': 'false',
1116@@ -78,15 +78,15 @@
1117 'concurrency': '1',
1118 'node_timeout': '15',
1119 })
1120- cu.update_once_single_threaded()
1121+ cu.run_once()
1122 async_dir = os.path.join(self.sda1, object_server.ASYNCDIR)
1123 os.mkdir(async_dir)
1124- cu.update_once_single_threaded()
1125+ cu.run_once()
1126 self.assert_(os.path.exists(async_dir))
1127
1128 odd_dir = os.path.join(async_dir, 'not really supposed to be here')
1129 os.mkdir(odd_dir)
1130- cu.update_once_single_threaded()
1131+ cu.run_once()
1132 self.assert_(os.path.exists(async_dir))
1133 self.assert_(not os.path.exists(odd_dir))
1134
1135@@ -98,7 +98,7 @@
1136 pickle.dump({'op': 'PUT', 'account': 'a', 'container': 'c', 'obj': 'o',
1137 'headers': {'X-Container-Timestamp': normalize_timestamp(0)}},
1138 open(op_path, 'wb'))
1139- cu.update_once_single_threaded()
1140+ cu.run_once()
1141 self.assert_(os.path.exists(op_path))
1142
1143 bindsock = listen(('127.0.0.1', 0))
1144@@ -140,7 +140,7 @@
1145 for dev in cu.get_container_ring().devs:
1146 if dev is not None:
1147 dev['port'] = bindsock.getsockname()[1]
1148- cu.update_once_single_threaded()
1149+ cu.run_once()
1150 err = event.wait()
1151 if err:
1152 raise err