gpt4 book ai didi

python - Upstart - 如何将重新加载信号发送到以不同用户身份启动的脚本?

转载 作者:太空宇宙 更新时间:2023-11-04 11:19:53 27 4
gpt4 key购买 nike

我有 python 程序(几个脚本)需要在 CentOS 6.4 远程机器上作为守护进程运行。所以,我认为 Upstart 是正确的选择。

基本要求是:

  • 启动/停止守护程序的简单方法
  • 如果应用程序崩溃,请重新生成应用程序
  • 应用程序必须在非特权用户下运行
  • 能够处理 SIGHUP 以重新加载配置

该服务器上的 Upstart 版本是 0.6.5,所以节 setuidsetgid不可用(它们仅出现在 1.4 中)。所以我使用 official workaround来自食谱。我可以启动/停止我的应用程序,但我的主要问题是我的应用程序没有收到重新加载信号。

我将提供可以重现该问题的剥离脚本。

Python 脚本(app.py):

import os
import time
import signal
import logging

logging.basicConfig(filename='hup.log', level=logging.INFO,
format="%(asctime)s: %(levelname)s: %(message)s")
log = logging.getLogger(__name__)


running = True

def run():
log.info('PROGRAM STARTUP')
log.info('Current pid: %d' % os.getpid())

while running:
log.info('Doing some hard work')
time.sleep(10)
else:
log.info('PROGRAM TEARDOWN')

def signal_handler(signum, frame):
log.info("Received Signal: %s at frame: %s" % (signum, frame))

if signum == signal.SIGTERM:
log.info('Received request to terminate daemon (SIGTERM)')
global running
running = False
elif signum == signal.SIGHUP:
log.info('Received reload config request (SIGHUP)')
pass # reload config here


signal.signal(signal.SIGHUP, signal_handler)
signal.signal(signal.SIGTERM, signal_handler)

run()

和 Upstart 配置(hup.conf):

start on runlevel [2345]
stop on runlevel [!2345]

respawn
respawn limit 10 5

chdir /home/dev/prj/im

script
# activate the virtual environment
. /home/dev/.virtualenvs/myvenv/bin/activate

# This line runs script as root
# exec python app.py

# this is official workaround for running prcesses as different
# user in upstart version prior to 1.4
# Run as user 'dev'
exec su -s /bin/sh -c 'exec "$0" "$@"' dev -- python app.py
end script

输出(如您所见,使用 python app.py 的实际过程与 upstart 显示的 PID 不同):

[dev@localhost ~]$ sudo start hup
hup start/running, process 8608
[dev@localhost ~]$ ps -elf | grep app.py
F S UID PID PPID C PRI NI ADDR SZ WCHAN STIME TTY TIME CMD
4 S root 8608 1 0 80 0 - 16143 wait 19:53 ? 00:00:00 su -s /bin/sh -c exec "$0" "$@" dev -- python app.py
4 S dev 8613 8608 0 80 0 - 7866 poll_s 19:53 ? 00:00:00 python app.py
[dev@localhost ~]$ sudo reload hup
[dev@localhost ~]$ sudo stop hup
hup stop/waiting

日志显示没有收到重载信号:

2013-09-19 20:00:36,092: INFO: PROGRAM STARTUP
2013-09-19 20:00:36,093: INFO: Current pid: 8613
2013-09-19 20:00:36,093: INFO: Doing some hard work
2013-09-19 20:00:45,287: INFO: Received Signal: 15 at frame: <frame object at 0xba2dd0>
2013-09-19 20:00:45,287: INFO: Received request to terminate daemon (SIGTERM)
2013-09-19 20:00:45,287: INFO: PROGRAM TEARDOWN

但是当我用 exec python app.py 取消注释 hup.conf 中的行时(并用 exec su... 注释一行),一切正常,除了应用程序以根用户身份运行。

[dev@localhost ~]$ sudo start hup
hup start/running, process 8811
[dev@localhost ~]$ ps -elf | grep app.py
F S UID PID PPID C PRI NI ADDR SZ WCHAN STIME TTY TIME CMD
4 S root 8811 1 0 80 0 - 8412 poll_s 20:13 ? 00:00:00 python app.py
[dev@localhost ~]$ sudo reload hup
[dev@localhost ~]$ sudo stop hup
hup stop/waiting

日志文件显示已收到 SIGHUP 信号:

2013-09-19 20:13:40,290: INFO: PROGRAM STARTUP
2013-09-19 20:13:40,290: INFO: Current pid: 8811
2013-09-19 20:13:40,291: INFO: Doing some hard work
2013-09-19 20:13:59,739: INFO: Received Signal: 1 at frame: <frame object at 0x7d44c0>
2013-09-19 20:13:59,739: INFO: Received reload config request (SIGHUP)
2013-09-19 20:13:59,739: INFO: Doing some hard work
2013-09-19 20:14:04,313: INFO: Received Signal: 15 at frame: <frame object at 0x7d44c0>
2013-09-19 20:14:04,313: INFO: Received request to terminate daemon (SIGTERM)
2013-09-19 20:14:04,313: INFO: PROGRAM TEARDOWN

我的主要问题是,当我在这个旧版本的 upstart 上以不同用户运行脚本时,如何使 reload 命令工作?

最佳答案

我最终以 root 身份运行我的脚本,然后将特权授予所需用户。为了以 root 身份运行脚本,我取消了上面 Upstart 配置中的 exec python app.py 注释。为了放弃特权,我使用了来自 this 的稍微修改过的代码回答:

def drop_privileges(uid_name, gid_name):
'''If running as root, this function will try to change current uid and gid
to given values.
May raise OSError in case of error.
:param uid_name: Name of the user we need to be running as.
:param gid_name: Name of the group we need to be running as.
'''

starting_uid = os.getuid()
starting_gid = os.getgid()

log.info('drop_privileges: started as %s/%s' %
(pwd.getpwuid(starting_uid).pw_name,
grp.getgrgid(starting_gid).gr_name))

if starting_uid == 0:
# If we started as root, drop privs and become the specified user/group
log.info("drop_privileges: trying to drop provileges to '%s'" % uid_name)

# Get the uid/gid from the name
running_uid = pwd.getpwnam(uid_name).pw_uid
running_gid = grp.getgrnam(gid_name).gr_gid

# Try setting the new uid/gid
# These calls may result in exception, let it propagate back
# Exception thrown is: OSError (e.errno == 1 means 'Operation not
# permitted')
os.setgid(running_gid)
os.setuid(running_uid)

final_uid = os.getuid()
final_gid = os.getgid()
log.info('drop_privileges: running as %s/%s' %
(pwd.getpwuid(final_uid).pw_name,
grp.getgrgid(final_gid).gr_name))

关于python - Upstart - 如何将重新加载信号发送到以不同用户身份启动的脚本?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/18901445/

27 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com