diff --git a/bin/swift-init b/bin/swift-init index b9e5680949..1d6059e4e8 100755 --- a/bin/swift-init +++ b/bin/swift-init @@ -17,8 +17,8 @@ import sys from optparse import OptionParser -from swift.common.manager import Server, Manager, UnknownCommandError, \ - KILL_WAIT +from swift.common.manager import Manager, UnknownCommandError, \ + KILL_WAIT, RUN_DIR USAGE = """%prog [ ...] [options] @@ -46,6 +46,11 @@ def main(): parser.add_option('-k', '--kill-wait', metavar="N", type="int", dest="kill_wait", default=KILL_WAIT, help="wait N seconds for processes to die (default 15)") + parser.add_option('-r', '--run-dir', type="str", + dest="run_dir", default=RUN_DIR, + help="alternative directory to store running pid files " + "default: %s" % RUN_DIR) + options, args = parser.parse_args() if len(args) < 2: @@ -62,7 +67,7 @@ def main(): servers.append(command) command = servers.pop(0) - manager = Manager(servers) + manager = Manager(servers, run_dir=options.run_dir) try: status = manager.run_command(command, **options.__dict__) except UnknownCommandError: diff --git a/bin/swift-orphans b/bin/swift-orphans index 3eb799c0e5..baf8be73ca 100755 --- a/bin/swift-orphans +++ b/bin/swift-orphans @@ -6,6 +6,7 @@ import signal import subprocess import sys +from swift.common.manager import RUN_DIR if __name__ == '__main__': parser = optparse.OptionParser(usage='''%prog [options] @@ -28,10 +29,15 @@ Example (sends SIGTERM to all orphaned Swift processes older than two hours): parser.add_option('-w', '--wide', dest='wide', default=False, action='store_true', help="don't clip the listing at 80 characters") + parser.add_option('-r', '--run-dir', type="str", + dest="run_dir", default=RUN_DIR, + help="alternative directory to store running pid files " + "default: %s" % RUN_DIR) (options, args) = parser.parse_args() pids = [] - for root, directories, files in os.walk('/var/run/swift'): + + for root, directories, files in os.walk(options.run_dir): for name in files: if name.endswith('.pid'): pids.append(open(os.path.join(root, name)).read().strip()) diff --git a/doc/manpages/swift-init.1 b/doc/manpages/swift-init.1 index 6c83ff4391..d1de6609b7 100644 --- a/doc/manpages/swift-init.1 +++ b/doc/manpages/swift-init.1 @@ -108,6 +108,7 @@ allows one to use the keywords such as "all", "main" and "rest" for the .IP "-g, --graceful \t\t send SIGHUP to supporting servers .IP "-c N, --config-num=N \t send command to the Nth server only .IP "-k N, --kill-wait=N \t wait N seconds for processes to die (default 15) +.IP "-r RUN_DIR, --run-dir=RUN_DIR directory where the pids will be stored (default /var/run/swift) .PD .RE diff --git a/doc/manpages/swift-orphans.1 b/doc/manpages/swift-orphans.1 index b4b6158bdc..d274753d8d 100644 --- a/doc/manpages/swift-orphans.1 +++ b/doc/manpages/swift-orphans.1 @@ -25,16 +25,17 @@ .SH SYNOPSIS .LP .B swift-orphans -[-h|--help] [-a|--age] [-k|--kill] [-w|--wide] +[-h|--help] [-a|--age] [-k|--kill] [-w|--wide] [-r|--run-dir] .SH DESCRIPTION .PP Lists and optionally kills orphaned Swift processes. This is done by scanning -/var/run/swift for .pid files and listing any processes that look like Swift -processes but aren't associated with the pids in those .pid files. Any Swift -processes running with the 'once' parameter are ignored, as those are usually -for full-speed audit scans and such. +/var/run/swift or the directory specified to the -r switch for .pid files and +listing any processes that look like Swift processes but aren't associated with +the pids in those .pid files. Any Swift processes running with the 'once' +parameter are ignored, as those are usually for full-speed audit scans and +such. Example (sends SIGTERM to all orphaned Swift processes older than two hours): swift-orphans -a 2 -k TERM diff --git a/swift/common/manager.py b/swift/common/manager.py index 0d380b822b..0232fef554 100644 --- a/swift/common/manager.py +++ b/swift/common/manager.py @@ -129,7 +129,7 @@ class Manager(): """ - def __init__(self, servers): + def __init__(self, servers, run_dir=RUN_DIR): server_names = set() for server in servers: if server == 'all': @@ -147,7 +147,7 @@ class Manager(): self.servers = set() for name in server_names: - self.servers.add(Server(name)) + self.servers.add(Server(name, run_dir)) @command def status(self, **kwargs): @@ -316,13 +316,14 @@ class Server(): :param server: name of server """ - def __init__(self, server): + def __init__(self, server, run_dir=RUN_DIR): if '-' not in server: server = '%s-server' % server self.server = server.lower() self.type = server.rsplit('-', 1)[0] self.cmd = 'swift-%s' % server self.procs = [] + self.run_dir = run_dir def __str__(self): return self.server @@ -348,7 +349,7 @@ class Server(): """ return conf_file.replace( - os.path.normpath(SWIFT_DIR), RUN_DIR, 1).replace( + os.path.normpath(SWIFT_DIR), self.run_dir, 1).replace( '%s-server' % self.type, self.server, 1).rsplit( '.conf', 1)[0] + '.pid' @@ -362,11 +363,11 @@ class Server(): """ if self.server in STANDALONE_SERVERS: return pid_file.replace( - os.path.normpath(RUN_DIR), SWIFT_DIR, 1)\ + os.path.normpath(self.run_dir), SWIFT_DIR, 1)\ .rsplit('.pid', 1)[0] + '.conf' else: return pid_file.replace( - os.path.normpath(RUN_DIR), SWIFT_DIR, 1).replace( + os.path.normpath(self.run_dir), SWIFT_DIR, 1).replace( self.server, '%s-server' % self.type, 1).rsplit( '.pid', 1)[0] + '.conf' @@ -411,7 +412,7 @@ class Server(): :returns: list of pid files """ - pid_files = search_tree(RUN_DIR, '%s*' % self.server, '.pid') + pid_files = search_tree(self.run_dir, '%s*' % self.server, '.pid') if kwargs.get('number', 0): conf_files = self.conf_files(**kwargs) # filter pid_files to match the index of numbered conf_file diff --git a/test/unit/common/test_manager.py b/test/unit/common/test_manager.py index 15f0b9761e..2c70516c7a 100644 --- a/test/unit/common/test_manager.py +++ b/test/unit/common/test_manager.py @@ -181,7 +181,7 @@ class TestManagerModule(unittest.TestCase): class MockServer(): - def __init__(self, pids, zombie=0): + def __init__(self, pids, run_dir=manager.RUN_DIR, zombie=0): self.heartbeat = (pids for _ in range(zombie)) def get_running_pids(self): @@ -311,6 +311,24 @@ class TestServer(unittest.TestCase): 'container-auditor/1/container-auditor.pid') self.assertEquals(pid_file, server.get_pid_file_name(conf_file)) + def test_get_custom_pid_file_name(self): + random_run_dir = "/random/dir" + get_random_run_dir = lambda x: os.path.join(random_run_dir, x) + server = manager.Server('proxy', run_dir=random_run_dir) + conf_file = self.join_swift_dir('proxy-server.conf') + pid_file = get_random_run_dir('proxy-server.pid') + self.assertEquals(pid_file, server.get_pid_file_name(conf_file)) + server = manager.Server('object-replicator', run_dir=random_run_dir) + conf_file = self.join_swift_dir('object-server/1.conf') + pid_file = get_random_run_dir('object-replicator/1.pid') + self.assertEquals(pid_file, server.get_pid_file_name(conf_file)) + server = manager.Server('container-auditor', run_dir=random_run_dir) + conf_file = self.join_swift_dir( + 'container-server/1/container-auditor.conf') + pid_file = get_random_run_dir( + 'container-auditor/1/container-auditor.pid') + self.assertEquals(pid_file, server.get_pid_file_name(conf_file)) + def test_get_conf_file_name(self): server = manager.Server('proxy') conf_file = self.join_swift_dir('proxy-server.conf') @@ -450,7 +468,7 @@ class TestServer(unittest.TestCase): files, contents = zip(*pid_files) with temptree(files, contents) as t: manager.RUN_DIR = t - server = manager.Server('proxy') + server = manager.Server('proxy', run_dir=t) # test get one file iter = server.iter_pid_files() pid_file, pid = iter.next() @@ -459,13 +477,13 @@ class TestServer(unittest.TestCase): # ... and only one file self.assertRaises(StopIteration, iter.next) # test invalid value in pid file - server = manager.Server('auth') + server = manager.Server('auth', run_dir=t) self.assertRaises(ValueError, server.iter_pid_files().next) # test object-server doesn't steal pids from object-replicator - server = manager.Server('object') + server = manager.Server('object', run_dir=t) self.assertRaises(StopIteration, server.iter_pid_files().next) # test multi-pid iter - server = manager.Server('object-replicator') + server = manager.Server('object-replicator', run_dir=t) real_map = { 11: self.join_run_dir('object-replicator/1.pid'), 12: self.join_run_dir('object-replicator/2.pid'), @@ -494,7 +512,7 @@ class TestServer(unittest.TestCase): files, pids = zip(*pid_files) with temptree(files, pids) as t: manager.RUN_DIR = t - server = manager.Server('object') + server = manager.Server('object', run_dir=t) # test get all pid files real_map = { 1: self.join_run_dir('object-server/1.pid'), @@ -530,7 +548,7 @@ class TestServer(unittest.TestCase): manager.RUN_DIR = t # mock os with both pids running manager.os = MockOs([1, 2]) - server = manager.Server('proxy') + server = manager.Server('proxy', run_dir=t) pids = server.signal_pids(DUMMY_SIG) self.assertEquals(len(pids), 1) self.assert_(1 in pids) @@ -562,7 +580,7 @@ class TestServer(unittest.TestCase): self.join_run_dir('proxy-server.pid'))) # reset mock os with no running pids manager.os = MockOs([]) - server = manager.Server('auth') + server = manager.Server('auth', run_dir=t) # test verbose warns on removing pid file pids = server.signal_pids(signal.SIG_DFL, verbose=True) output = pop_stream(f) @@ -570,7 +588,7 @@ class TestServer(unittest.TestCase): auth_pid = self.join_run_dir('auth-server.pid') self.assert_(auth_pid in output) # test warning with insufficient permissions - server = manager.Server('object') + server = manager.Server('object', run_dir=t) pids = server.signal_pids(manager.os.RAISE_EPERM_SIG) output = pop_stream(f) self.assert_('no permission to signal pid 3' in @@ -586,7 +604,7 @@ class TestServer(unittest.TestCase): ) with temptree(*zip(*pid_files)) as t: manager.RUN_DIR = t - server = manager.Server('test-server') + server = manager.Server('test-server', run_dir=t) # mock os, only pid '1' is running manager.os = MockOs([1]) running_pids = server.get_running_pids() @@ -620,7 +638,7 @@ class TestServer(unittest.TestCase): manager.RUN_DIR = t # all pids are running manager.os = MockOs(pids) - server = manager.Server('thing-doer') + server = manager.Server('thing-doer', run_dir=t) running_pids = server.get_running_pids() # only thing-doer.pid, 1 self.assertEquals(len(running_pids), 1) @@ -636,7 +654,7 @@ class TestServer(unittest.TestCase): self.assert_(os.path.exists, os.path.join(t, f)) # verify that servers are in fact not running for server_name in ('thing-sayer', 'other-doer', 'other-sayer'): - server = manager.Server(server_name) + server = manager.Server(server_name, run_dir=t) running_pids = server.get_running_pids() self.assertFalse(running_pids) # and now all OTHER pid files are cleaned out @@ -653,7 +671,7 @@ class TestServer(unittest.TestCase): files, running_pids = zip(*pid_files) with temptree(files, running_pids) as t: manager.RUN_DIR = t - server = manager.Server('object') + server = manager.Server('object', run_dir=t) # test no servers running manager.os = MockOs([]) pids = server.kill_running_pids() @@ -661,8 +679,10 @@ class TestServer(unittest.TestCase): files, running_pids = zip(*pid_files) with temptree(files, running_pids) as t: manager.RUN_DIR = t + server.run_dir = t # start up pid manager.os = MockOs([1]) + server = manager.Server('object', run_dir=t) # test kill one pid pids = server.kill_running_pids() self.assertEquals(len(pids), 1) @@ -682,7 +702,7 @@ class TestServer(unittest.TestCase): # test multi server kill & ignore graceful on unsupported server self.assertFalse('object-replicator' in manager.GRACEFUL_SHUTDOWN_SERVERS) - server = manager.Server('object-replicator') + server = manager.Server('object-replicator', run_dir=t) pids = server.kill_running_pids(graceful=True) self.assertEquals(len(pids), 2) for pid in (11, 12): @@ -713,7 +733,7 @@ class TestServer(unittest.TestCase): with temptree(files, pids) as t: manager.RUN_DIR = t # setup running servers - server = manager.Server('test') + server = manager.Server('test', run_dir=t) # capture stdio old_stdout = sys.stdout try: @@ -812,6 +832,7 @@ class TestServer(unittest.TestCase): manager.SWIFT_DIR = swift_dir with temptree([]) as t: manager.RUN_DIR = t + server.run_dir = t old_subprocess = manager.subprocess try: # test single server process calls spawn once @@ -842,7 +863,7 @@ class TestServer(unittest.TestCase): conf2 = self.join_swift_dir('test-server/2.conf') conf3 = self.join_swift_dir('test-server/3.conf') conf4 = self.join_swift_dir('test-server/4.conf') - server = manager.Server('test') + server = manager.Server('test', run_dir=t) # test server run once server.spawn(conf1, once=True) self.assert_(server.procs) @@ -1080,11 +1101,11 @@ class TestServer(unittest.TestCase): with open(os.path.join(t, 'output'), 'w+') as f: sys.stdout = f # can't start server w/o an conf - server = manager.Server('test') + server = manager.Server('test', run_dir=t) self.assertFalse(server.launch()) # start mock os running all pids manager.os = MockOs(pids) - server = manager.Server('proxy') + server = manager.Server('proxy', run_dir=t) # can't start server if it's already running self.assertFalse(server.launch()) output = pop_stream(f) @@ -1178,7 +1199,7 @@ class TestServer(unittest.TestCase): manager.RUN_DIR = t # start all pids in mock os manager.os = MockOs(pids) - server = manager.Server('account-reaper') + server = manager.Server('account-reaper', run_dir=t) # test kill all running pids pids = server.stop() self.assertEquals(len(pids), 4) @@ -1269,7 +1290,7 @@ class TestManager(unittest.TestCase): def test_status(self): class MockServer(): - def __init__(self, server): + def __init__(self, server, run_dir=manager.RUN_DIR): self.server = server self.called_kwargs = [] @@ -1304,7 +1325,7 @@ class TestManager(unittest.TestCase): getattr(mock_setup_env, 'called', []).append(True) class MockServer(): - def __init__(self, server): + def __init__(self, server, run_dir=manager.RUN_DIR): self.server = server self.called = defaultdict(list) @@ -1366,7 +1387,7 @@ class TestManager(unittest.TestCase): def test_no_wait(self): class MockServer(): - def __init__(self, server): + def __init__(self, server, run_dir=manager.RUN_DIR): self.server = server self.called = defaultdict(list) @@ -1417,7 +1438,7 @@ class TestManager(unittest.TestCase): def test_no_daemon(self): class MockServer(): - def __init__(self, server): + def __init__(self, server, run_dir=manager.RUN_DIR): self.server = server self.called = defaultdict(list) @@ -1452,7 +1473,7 @@ class TestManager(unittest.TestCase): def test_once(self): class MockServer(): - def __init__(self, server): + def __init__(self, server, run_dir=manager.RUN_DIR): self.server = server self.called = defaultdict(list) @@ -1489,16 +1510,16 @@ class TestManager(unittest.TestCase): def test_stop(self): class MockServerFactory(): class MockServer(): - def __init__(self, pids): + def __init__(self, pids, run_dir=manager.RUN_DIR): self.pids = pids def stop(self, **kwargs): return self.pids - def __init__(self, server_pids): + def __init__(self, server_pids, run_dir=manager.RUN_DIR): self.server_pids = server_pids - def __call__(self, server): + def __call__(self, server, run_dir=manager.RUN_DIR): return MockServerFactory.MockServer(self.server_pids[server]) def mock_watch_server_pids(server_pids, **kwargs):