在 supervisord 启动的 Python 进程下获取用户的主文件夹
Get user's home folder under Python process started by supervisord
我想将登录密码存储在 Django 配置中当前用户帐户的文件中。我正在使用推荐的便携方式获取主文件夹,如:
os.path.expanduser("~")
这适用于所有环境,包括本地环境和在服务器上使用 gunicorn -D config.wsgi
启动时的环境。
我的问题是,我引入了 supervisord 来控制 gunicorn 进程,现在这个功能不起作用,它只是 returns /
.
这是supervisord.conf
的相关部分
[program:kek_django]
command=.../venv/bin/gunicorn config.wsgi
directory=.../django
user=testuser
在此环境下,os.path.expanduser("~") 变为 /
。
你能告诉我如何通过修复环境或用于检测主目录的函数来解决这个问题吗?
注意:OS 是 FreeBSD 10,如果相关的话
更新:os.environ 在 运行 进程下报告以下内容:
'SUPERVISOR_SERVER_URL': 'unix:///var/run/supervisor/supervisor.sock',
'RC_PID': '84177',
'SERVER_SOFTWARE': 'gunicorn/19.3.0',
'SUPERVISOR_ENABLED': '1',
'SUPERVISOR_PROCESS_NAME': 'test_django',
'PWD': '/',
'DJANGO_SETTINGS_MODULE': 'config.settings.production',
'SUPERVISOR_GROUP_NAME': 'test_django',
'PATH': '/sbin:/bin:/usr/sbin:/usr/bin',
'HOME': '/'
正如 supervisord
的 Subprocess Environment 文档所说:
No shell is executed by supervisord
when it runs a subprocess, so environment variables such as USER
, PATH
, HOME
, SHELL
, LOGNAME
, etc. are not changed from their defaults or otherwise reassigned. This is particularly important to note when you are running a program from a supervisord
run as root with a user=
stanza in the configuration. Unlike cron
, supervisord
does not attempt to divine and override “fundamental” environment variables like USER
, PATH
, HOME
, and LOGNAME
when it performs a setuid
to the user defined within the user=
program config option. If you need to set environment variables for a particular program that might otherwise be set by a shell invocation for a particular user, you must do it explicitly within the environment=
program config option. An example of setting these enviroment variables is as below.
[program:apache2]
command=/home/chrism/bin/httpd -c "ErrorLog /dev/stdout" -DFOREGROUND
user=chrism
environment=HOME="/home/chrism",USER="chrism"
所以,这才是真正的解决方法。 (如果您动态构建 supervisord.conf
文件并且需要知道如何动态查找这些值,我可以解释一下,但这很简单,而且我认为您无论如何都不需要它。)
[program:kek_django]
command=.../venv/bin/gunicorn config.wsgi
directory=.../django
user=testuser
environment=HOME="/home/testuser"
如果这对您没有意义,请考虑:
如果你是 运行 supervisord
作为 root,它没有 testuser
的 HOME
或其他任何东西。它所做的只是setuid(testuser)
,这只是改变了它的用户ID;它不会给 shell 或系统的任何其他部分任何机会来设置 testuser
的变量。大多数类似的工具都有伪造它的变通方法,遵循 cron
如何工作的老套路,但 supervisord
有意选择不这样做。
或者,正如 expanduser
的文档所说:
On Unix, an initial ~
is replaced by the environment variable HOME if it is set; otherwise the current user’s home directory is looked up in the password directory through the built-in module pwd. An initial ~user
is looked up directly in the password directory.
快速浏览一下 the source 就会发现它以最明显的方式做到了这一点。
因此,您的代码中存在三个明显的解决方法:
- 使用
~testuser
而不是 ~
(如果需要,您甚至可以通过用户名以编程方式生成)。
- 编写您自己的
expanduser
函数,只执行 pwd.getpwuid(os.getuid()).pw_dir
而不检查 HOME
。
- 如果是
/
,则在启动时手动将 HOME
设置为 pwd.getpwuid(os.getuid()).pw_dir
。
我想将登录密码存储在 Django 配置中当前用户帐户的文件中。我正在使用推荐的便携方式获取主文件夹,如:
os.path.expanduser("~")
这适用于所有环境,包括本地环境和在服务器上使用 gunicorn -D config.wsgi
启动时的环境。
我的问题是,我引入了 supervisord 来控制 gunicorn 进程,现在这个功能不起作用,它只是 returns /
.
这是supervisord.conf
的相关部分[program:kek_django]
command=.../venv/bin/gunicorn config.wsgi
directory=.../django
user=testuser
在此环境下,os.path.expanduser("~") 变为 /
。
你能告诉我如何通过修复环境或用于检测主目录的函数来解决这个问题吗?
注意:OS 是 FreeBSD 10,如果相关的话
更新:os.environ 在 运行 进程下报告以下内容:
'SUPERVISOR_SERVER_URL': 'unix:///var/run/supervisor/supervisor.sock',
'RC_PID': '84177',
'SERVER_SOFTWARE': 'gunicorn/19.3.0',
'SUPERVISOR_ENABLED': '1',
'SUPERVISOR_PROCESS_NAME': 'test_django',
'PWD': '/',
'DJANGO_SETTINGS_MODULE': 'config.settings.production',
'SUPERVISOR_GROUP_NAME': 'test_django',
'PATH': '/sbin:/bin:/usr/sbin:/usr/bin',
'HOME': '/'
正如 supervisord
的 Subprocess Environment 文档所说:
No shell is executed by
supervisord
when it runs a subprocess, so environment variables such asUSER
,PATH
,HOME
,SHELL
,LOGNAME
, etc. are not changed from their defaults or otherwise reassigned. This is particularly important to note when you are running a program from asupervisord
run as root with auser=
stanza in the configuration. Unlikecron
,supervisord
does not attempt to divine and override “fundamental” environment variables likeUSER
,PATH
,HOME
, andLOGNAME
when it performs asetuid
to the user defined within theuser=
program config option. If you need to set environment variables for a particular program that might otherwise be set by a shell invocation for a particular user, you must do it explicitly within theenvironment=
program config option. An example of setting these enviroment variables is as below.
[program:apache2]
command=/home/chrism/bin/httpd -c "ErrorLog /dev/stdout" -DFOREGROUND
user=chrism
environment=HOME="/home/chrism",USER="chrism"
所以,这才是真正的解决方法。 (如果您动态构建 supervisord.conf
文件并且需要知道如何动态查找这些值,我可以解释一下,但这很简单,而且我认为您无论如何都不需要它。)
[program:kek_django]
command=.../venv/bin/gunicorn config.wsgi
directory=.../django
user=testuser
environment=HOME="/home/testuser"
如果这对您没有意义,请考虑:
如果你是 运行 supervisord
作为 root,它没有 testuser
的 HOME
或其他任何东西。它所做的只是setuid(testuser)
,这只是改变了它的用户ID;它不会给 shell 或系统的任何其他部分任何机会来设置 testuser
的变量。大多数类似的工具都有伪造它的变通方法,遵循 cron
如何工作的老套路,但 supervisord
有意选择不这样做。
或者,正如 expanduser
的文档所说:
On Unix, an initial
~
is replaced by the environment variable HOME if it is set; otherwise the current user’s home directory is looked up in the password directory through the built-in module pwd. An initial~user
is looked up directly in the password directory.
快速浏览一下 the source 就会发现它以最明显的方式做到了这一点。
因此,您的代码中存在三个明显的解决方法:
- 使用
~testuser
而不是~
(如果需要,您甚至可以通过用户名以编程方式生成)。 - 编写您自己的
expanduser
函数,只执行pwd.getpwuid(os.getuid()).pw_dir
而不检查HOME
。 - 如果是
/
,则在启动时手动将HOME
设置为pwd.getpwuid(os.getuid()).pw_dir
。