diff options
Diffstat (limited to 'scripts/scriptmgr.py')
-rwxr-xr-x | scripts/scriptmgr.py | 75 |
1 files changed, 64 insertions, 11 deletions
diff --git a/scripts/scriptmgr.py b/scripts/scriptmgr.py index 5cba34c0..6aa82c78 100755 --- a/scripts/scriptmgr.py +++ b/scripts/scriptmgr.py @@ -47,9 +47,13 @@ import sys, os, signal, glob, ConfigParser, time import pkgloader pkgloader.require('skytools', '3.0') - import skytools +try: + import pwd +except ImportError: + pwd = None + command_usage = """ %prog [options] INI CMD [subcmd args] @@ -68,6 +72,37 @@ def job_sort_cmp(j1, j2): elif d1 > d2: return 1 else: return 0 +def launch_cmd(job, cmd): + if job['user']: + cmd = 'sudo -u "%s" %s' % (job['user'], cmd) + return os.system(cmd) + +def full_path(job, fn): + """Like os.path.expanduser() but works for other users. + """ + if not fn: + return fn + if fn[0] == '~': + user, rest = fn.split('/',1)[0] + user = user[1:] + if not user: + user = job['user'] + + # find home + if user: + home = pwd.getpwuid(os.getuid()).pw_dir + elif 'HOME' in os.environ: + home = os.environ['HOME'] + else: + home = os.pwd.getpwuid(os.getuid()).pw_dir + + if rest: + return os.path.join(home, rest) + else: + return home + # always return full path + return os.path.join(job['cwd'], fn) + class ScriptMgr(skytools.DBScript): __doc__ = __doc__ svc_list = [] @@ -91,6 +126,8 @@ class ScriptMgr(skytools.DBScript): # load services svc_list = self.cf.sections() svc_list.remove(self.service_name) + with_user = 0 + without_user = 0 for svc_name in svc_list: cf = self.cf.clone(svc_name) disabled = cf.getboolean('disabled', 0) @@ -103,9 +140,16 @@ class ScriptMgr(skytools.DBScript): 'cwd': cf.getfile('cwd'), 'disabled': disabled, 'args': cf.get('args', ''), + 'user': cf.get('user', ''), } + if svc['user']: + with_user += 1 + else: + without_user += 1 self.svc_list.append(svc) self.svc_map[svc_name] = svc + if with_user and without_user: + raise skytools.UsageError("Invalid config - some jobs have user=, some don't") # generate config list for tmp in self.cf.getlist('config_list'): @@ -143,10 +187,15 @@ class ScriptMgr(skytools.DBScript): 'cwd': svc['cwd'], 'script': svc['script'], 'args': svc['args'], + 'user': svc['user'], 'service': svc['service'], 'job_name': cf.get('job_name'), - 'pidfile': cf.getfile('pidfile', ''), + 'pidfile': cf.get('pidfile', ''), } + + if job['pidfile']: + job['pidfile'] = full_path(job, job['pidfile']) + self.job_list.append(job) self.job_map[job['job_name']] = job @@ -157,8 +206,6 @@ class ScriptMgr(skytools.DBScript): except KeyError: self.log.error ("Unknown job: %s", jn) continue - os.chdir(job['cwd']) - cf = skytools.Config(job['service'], job['config']) pidfile = job['pidfile'] name = job['job_name'] svc = job['service'] @@ -186,7 +233,6 @@ class ScriptMgr(skytools.DBScript): if isinstance (job, int): return job # ret.code self.log.info('Starting %s' % job_name) - os.chdir(job['cwd']) pidfile = job['pidfile'] if not pidfile: self.log.warning("No pidfile for %s, cannot launch" % job_name) @@ -197,8 +243,9 @@ class ScriptMgr(skytools.DBScript): return 0 else: self.log.info("Ignoring stale pidfile for %s" % job_name) + os.chdir(job['cwd']) cmd = "%(script)s %(config)s %(args)s -d" % job - res = os.system(cmd) + res = launch_cmd(job, cmd) self.log.debug(res) if res != 0: self.log.error('startup failed: %s' % job_name) @@ -245,17 +292,23 @@ class ScriptMgr(skytools.DBScript): return 0 def signal_job(self, job, sig): - os.chdir(job['cwd']) pidfile = job['pidfile'] if not pidfile: self.log.warning("No pidfile for %s (%s)" % (job['job_name'], job['config'])) return if os.path.isfile(pidfile): pid = int(open(pidfile).read()) - try: - os.kill(pid, sig) - except Exception, det: - self.log.warning("Signaling %s failed: %s" % (job['job_name'], str(det))) + if job['user']: + # run sudo + kill to avoid killing unrelated processes + res = os.system("sudo -u %s kill %d" % (job['user'], pid)) + if res: + self.log.warning("Signaling %s failed" % (job['job_name'],)) + else: + # direct kill + try: + os.kill(pid, sig) + except Exception, det: + self.log.warning("Signaling %s failed: %s" % (job['job_name'], str(det))) else: self.log.warning("Job %s not running" % job['job_name']) |