Redhat RC脚本的ZC Buildout配方
项目描述
此软件包提供了一种zc.buildout配方,用于创建与Red-Hat Linux兼容的运行控制脚本。
变更
1.4.2 (2012-12-20)
- 修复:如果在卸载过程中停止运行脚本失败时引发错误。
这可能导致buildout卡住,因为您无法卸载损坏的/丢失的运行脚本。
1.4.1 (2012-08-31)
修复:更新时未启动进程。
在理想的世界里,这不会是必要的,因为在更新情况下,进程已经正在运行,但是,尝试启动进程以确保进程正在运行是有帮助的。
1.4.0 (2012-05-18)
添加了可选的进程管理支持。如果请求,则运行脚本作为安装和卸载的一部分运行。
修复:缺少对zope.testing的测试依赖关系。
1.3.0 (2010/05/26)
新功能
一个新的独立进程选项导致多个进程独立重新启动,而不是停止所有进程然后重新启动所有进程。
已修复的漏洞
生成的运行脚本有尾随空格。
1.2.0 (2009/04/06)
显示在启动、停止或重新启动时每个脚本正在运行的脚本名称
1.1.0 (2008/02/01)
在生成脚本名称时,如果存在,请使用部署名称选项(由zc.recipe.deployment 0.6.0及以后版本提供)。
当使用部署时,请使用部署rc目录作为目标。
请使用/sbin/chkconfig而不是chkconfig,因为据说它始终在该位置,很少在任何人路径中。 :)
1.0.0 (2008/01/15)
首次公开发布
详细文档
创建Red-Hat Linux(chkconfig)rc脚本
zc.recipes.rhrc 食谱创建 Red Hat Linux (chkconfig) rc 脚本。它可以创建单个 rc 脚本,以及启动多个应用程序的组合 rc 脚本。
该食谱有一个 parts 选项,它接受定义运行脚本的节名称。它们应该是
定义一个包含单行 shell 脚本的运行脚本选项,或者
存在文件 /etc/init.d/PART,其中 PART 是部分名称。
一个简单的例子可能会使这一点更加清晰。
>>> demo = tmpdir('demo')>>> write('buildout.cfg', ... """ ... [buildout] ... parts = zoperc ... ... [zoperc] ... recipe = zc.recipe.rhrc ... parts = zope ... dest = %(dest)s ... ... [zope] ... run-script = /opt/zope/bin/zopectl -C /etc/zope.conf ... """ % dict(dest=demo))
通常,该食谱会将脚本写入 /etc/init.d。我们可以覆盖目标,就像我们在这里所做的那样,使用演示目录。我们指定了它应该从 zope 节获取运行脚本源。在这里,zope 节只是一个配置节,其中运行脚本选项被直接设置,但它也可以是一个具有从食谱计算出的运行脚本选项的部分。
如果我们运行 buildout
>>> print system('bin/buildout'), Installing zoperc.
我们将在我们的演示目录中获得 zoperc 脚本
>>> ls(demo) - zoperc>>> cat(demo, 'zoperc') #!/bin/sh <BLANKLINE> # This script is for adminstrator convenience. It should # NOT be installed as a system startup script! <BLANKLINE> <BLANKLINE> case $1 in stop) <BLANKLINE> /opt/zope/bin/zopectl -C /etc/zope.conf $* <BLANKLINE> ;; restart) <BLANKLINE> ${0} stop sleep 1 ${0} start <BLANKLINE> ;; *) <BLANKLINE> /opt/zope/bin/zopectl -C /etc/zope.conf $* <BLANKLINE> ;; esac <BLANKLINE>
关于生成的脚本有几个需要注意的地方
它使用 $* 传递参数,因此参数不能被引号括起来。这是可以的,因为参数将是简单的动词,如启动和停止。
它包括一条注释,说明该脚本不应作为系统启动脚本使用。
为了使脚本用于系统启动,我们需要指定运行级别信息。我们可以使用 chkconfig 选项来做到这一点
>>> write('buildout.cfg', ... """ ... [buildout] ... parts = zoperc ... ... [zoperc] ... recipe = zc.recipe.rhrc ... parts = zope ... dest = %(dest)s ... chkconfig = 345 90 10 ... chkconfigcommand = echo ... ... [zope] ... run-script = /opt/zope/bin/zopectl -C /etc/zope.conf ... """ % dict(dest=demo))
在这里,我们包括了一个 chkconfig 选项,表示 Zope 应该在运行级别 3、4 和 5 上启动,并且它的启动和停止顺序应该是 90 和 10。
出于演示目的,我们并不真的想运行 chkconfig,所以我们使用 chkconfigcommand 选项告诉食谱运行 echo。
>>> print system('bin/buildout'), Uninstalling zoperc. Running uninstall recipe. Installing zoperc. --add zoperc
现在脚本包含一个 chkconfig 注释
>>> cat(demo, 'zoperc') #!/bin/sh <BLANKLINE> # the next line is for chkconfig # chkconfig: 345 90 10 # description: please, please work <BLANKLINE> <BLANKLINE> case $1 in stop) <BLANKLINE> /opt/zope/bin/zopectl -C /etc/zope.conf $* \ </dev/null <BLANKLINE> ;; restart) <BLANKLINE> ${0} stop sleep 1 ${0} start <BLANKLINE> ;; *) <BLANKLINE> /opt/zope/bin/zopectl -C /etc/zope.conf $* \ </dev/null <BLANKLINE> ;; esac <BLANKLINE>
我们可以指定脚本应该以哪个用户运行
>>> write('buildout.cfg', ... """ ... [buildout] ... parts = zoperc ... ... [zoperc] ... recipe = zc.recipe.rhrc ... parts = zope ... dest = %(dest)s ... chkconfig = 345 90 10 ... chkconfigcommand = echo ... user = zope ... ... [zope] ... run-script = /opt/zope/bin/zopectl -C /etc/zope.conf ... """ % dict(dest=demo))>>> print system('bin/buildout'), Uninstalling zoperc. Running uninstall recipe. --del zoperc Installing zoperc. --add zoperc
注意 –del 输出。如果我们没有将 chkconfigcommand 设置为 echo,那么 chkconfig –del 就会在 zoperc 脚本上运行。
>>> cat(demo, 'zoperc') #!/bin/sh <BLANKLINE> # the next line is for chkconfig # chkconfig: 345 90 10 # description: please, please work <BLANKLINE> <BLANKLINE> if [ $(whoami) != "root" ]; then echo "You must be root." exit 1 fi <BLANKLINE> case $1 in stop) <BLANKLINE> su zope -c \ "/opt/zope/bin/zopectl -C /etc/zope.conf $*" \ </dev/null <BLANKLINE> ;; restart) <BLANKLINE> ${0} stop sleep 1 ${0} start <BLANKLINE> ;; *) <BLANKLINE> su zope -c \ "/opt/zope/bin/zopectl -C /etc/zope.conf $*" \ </dev/null <BLANKLINE> ;; esac <BLANKLINE>
注意现在使用 su 命令来运行脚本。因为脚本被包含在双引号中,所以它不能包含双引号。(食谱不尝试转义双引号。)
还请注意,现在脚本必须以 root 用户运行,所以生成的脚本会检查 root 是否在运行它。
如果我们说用户是 root
>>> write('buildout.cfg', ... """ ... [buildout] ... parts = zoperc ... ... [zoperc] ... recipe = zc.recipe.rhrc ... parts = zope ... dest = %(dest)s ... chkconfig = 345 90 10 ... chkconfigcommand = echo ... user = root ... ... [zope] ... run-script = /opt/zope/bin/zopectl -C /etc/zope.conf ... """ % dict(dest=demo))
那么生成的脚本将不会使用 su,但它仍然会检查 root 是否在运行它
>>> print system('bin/buildout'), Uninstalling zoperc. Running uninstall recipe. --del zoperc Installing zoperc. --add zoperc>>> cat(demo, 'zoperc') #!/bin/sh <BLANKLINE> # the next line is for chkconfig # chkconfig: 345 90 10 # description: please, please work <BLANKLINE> <BLANKLINE> if [ $(whoami) != "root" ]; then echo "You must be root." exit 1 fi <BLANKLINE> case $1 in stop) <BLANKLINE> /opt/zope/bin/zopectl -C /etc/zope.conf $* \ </dev/null <BLANKLINE> ;; restart) <BLANKLINE> ${0} stop sleep 1 ${0} start <BLANKLINE> ;; *) <BLANKLINE> /opt/zope/bin/zopectl -C /etc/zope.conf $* \ </dev/null <BLANKLINE> ;; esac <BLANKLINE>
定义运行脚本的部件还可以通过提供 env 选项来定义用于 rc 脚本的环境变量设置
>>> write('buildout.cfg', ... """ ... [buildout] ... parts = zoperc ... ... [zoperc] ... recipe = zc.recipe.rhrc ... parts = zope ... dest = %(dest)s ... chkconfig = 345 90 10 ... chkconfigcommand = echo ... user = zope ... ... [zope] ... run-script = /opt/zope/bin/zopectl -C /etc/zope.conf ... env = LD_LIBRARY_PATH=/opt/foolib ... """ % dict(dest=demo))>>> print system('bin/buildout'), Uninstalling zoperc. Running uninstall recipe. --del zoperc Installing zoperc. --add zoperc>>> cat(demo, 'zoperc') #!/bin/sh <BLANKLINE> # the next line is for chkconfig # chkconfig: 345 90 10 # description: please, please work <BLANKLINE> <BLANKLINE> if [ $(whoami) != "root" ]; then echo "You must be root." exit 1 fi <BLANKLINE> case $1 in stop) <BLANKLINE> LD_LIBRARY_PATH=/opt/foolib \ su zope -c \ "/opt/zope/bin/zopectl -C /etc/zope.conf $*" \ </dev/null <BLANKLINE> ;; restart) <BLANKLINE> ${0} stop sleep 1 ${0} start <BLANKLINE> ;; *) <BLANKLINE> LD_LIBRARY_PATH=/opt/foolib \ su zope -c \ "/opt/zope/bin/zopectl -C /etc/zope.conf $*" \ </dev/null <BLANKLINE> ;; esac <BLANKLINE>
与现有控制脚本一起工作
在上面的例子中,我们基于命令行生成了一个脚本。如果我们有一个创建控制脚本的部件,那么它可以省略运行脚本选项,并且它已经创建的运行脚本将被使用。让我们自己创建一个运行脚本
>>> write(demo, 'zope', '/opt/zope/bin/zopectl -C /etc/zope.conf $*')
现在我们可以从 Zope 节中删除运行脚本选项
>>> write('buildout.cfg', ... """ ... [buildout] ... parts = zoperc ... ... [zoperc] ... recipe = zc.recipe.rhrc ... parts = zope ... dest = %(dest)s ... chkconfig = 345 90 10 ... chkconfigcommand = echo ... user = zope ... ... [zope] ... env = LD_LIBRARY_PATH=/opt/foolib ... """ % dict(dest=demo))>>> print system('bin/buildout'), Uninstalling zoperc. Running uninstall recipe. --del zoperc Installing zoperc. --add zoperc>>> cat(demo, 'zoperc') #!/bin/sh <BLANKLINE> # the next line is for chkconfig # chkconfig: 345 90 10 # description: please, please work <BLANKLINE> <BLANKLINE> if [ $(whoami) != "root" ]; then echo "You must be root." exit 1 fi <BLANKLINE> case $1 in stop) <BLANKLINE> echo zope: /demo/zope "$@" \ </dev/null <BLANKLINE> ;; restart) <BLANKLINE> ${0} stop sleep 1 ${0} start <BLANKLINE> ;; *) <BLANKLINE> echo zope: /demo/zope "$@" \ </dev/null <BLANKLINE> ;; esac <BLANKLINE>
在这里我们只是调用现有的脚本。注意脚本中没有反映 env 或用户选项。当使用现有脚本时,假定它是完整的。
>>> import os >>> os.remove(join(demo, 'zope'))
多个进程
有时,你需要启动多个进程。你可以指定多个部分。例如,假设我们想要启动 2 个 Zope 实例
>>> write('buildout.cfg', ... """ ... [buildout] ... parts = zoperc ... ... [zoperc] ... recipe = zc.recipe.rhrc ... parts = instance1 instance2 ... dest = %(dest)s ... chkconfig = 345 90 10 ... chkconfigcommand = echo ... user = zope ... ... [instance1] ... run-script = /opt/zope/bin/zopectl -C /etc/instance1.conf ... env = LD_LIBRARY_PATH=/opt/foolib ... ... [instance2] ... """ % dict(dest=demo))>>> write(demo, 'instance2', '')
注意对于实例 2,我们正在安排脚本已经存在。
>>> print system('bin/buildout'), Uninstalling zoperc. Running uninstall recipe. --del zoperc Installing zoperc. --add zoperc>>> cat(demo, 'zoperc') #!/bin/sh <BLANKLINE> # the next line is for chkconfig # chkconfig: 345 90 10 # description: please, please work <BLANKLINE> <BLANKLINE> if [ $(whoami) != "root" ]; then echo "You must be root." exit 1 fi <BLANKLINE> case $1 in stop) <BLANKLINE> echo instance2: /demo/instance2 "$@" \ </dev/null <BLANKLINE> LD_LIBRARY_PATH=/opt/foolib \ su zope -c \ "/opt/zope/bin/zopectl -C /etc/instance1.conf $*" \ </dev/null <BLANKLINE> ;; restart) <BLANKLINE> ${0} stop sleep 1 ${0} start <BLANKLINE> ;; *) <BLANKLINE> LD_LIBRARY_PATH=/opt/foolib \ su zope -c \ "/opt/zope/bin/zopectl -C /etc/instance1.conf $*" \ </dev/null <BLANKLINE> echo instance2: /demo/instance2 "$@" \ </dev/null <BLANKLINE> ;; esac <BLANKLINE>
现在 rc 脚本启动了这两个实例。注意它以相反的顺序停止它们。在这种情况下,这并不那么重要,但如果后面的脚本依赖于前面的脚本,那么这就会更加重要。
除了 zoperc 脚本之外,我们还获得了具有运行脚本选项的实例脚本
>>> ls(demo) - instance2 - zoperc - zoperc-instance1>>> cat(demo, 'zoperc-instance1') #!/bin/sh <BLANKLINE> # This script is for adminstrator convenience. It should # NOT be installed as a system startup script! <BLANKLINE> <BLANKLINE> if [ $(whoami) != "root" ]; then echo "You must be root." exit 1 fi <BLANKLINE> case $1 in stop) <BLANKLINE> LD_LIBRARY_PATH=/opt/foolib \ su zope -c \ "/opt/zope/bin/zopectl -C /etc/instance1.conf $*" <BLANKLINE> ;; restart) <BLANKLINE> ${0} stop sleep 1 ${0} start <BLANKLINE> ;; *) <BLANKLINE> LD_LIBRARY_PATH=/opt/foolib \ su zope -c \ "/opt/zope/bin/zopectl -C /etc/instance1.conf $*" <BLANKLINE> ;; esac <BLANKLINE>
单个脚本没有 chkconfig 信息。
独立进程
通常,假定进程是相互依赖的,并且按顺序启动,按相反的顺序停止,在重启时,所有进程都停止然后全部启动。
如果使用独立进程选项,则生成的主运行脚本将把进程视为独立的,并分别重启处理。对于大量的独立进程,这可以减少单个进程关闭的时间。
>>> write('buildout.cfg', ... """ ... [buildout] ... parts = zoperc ... ... [zoperc] ... recipe = zc.recipe.rhrc ... parts = instance1 instance2 ... dest = %(dest)s ... chkconfig = 345 90 10 ... chkconfigcommand = echo ... user = zope ... independent-processes = true ... ... [instance1] ... run-script = /opt/zope/bin/zopectl -C /etc/instance1.conf ... env = LD_LIBRARY_PATH=/opt/foolib ... ... [instance2] ... """ % dict(dest=demo))>>> print system('bin/buildout'), Uninstalling zoperc. Running uninstall recipe. --del zoperc Installing zoperc. --add zoperc>>> cat(demo, 'zoperc') #!/bin/sh <BLANKLINE> # the next line is for chkconfig # chkconfig: 345 90 10 # description: please, please work <BLANKLINE> <BLANKLINE> if [ $(whoami) != "root" ]; then echo "You must be root." exit 1 fi <BLANKLINE> LD_LIBRARY_PATH=/opt/foolib \ su zope -c \ "/opt/zope/bin/zopectl -C /etc/instance1.conf $*" \ </dev/null <BLANKLINE> echo instance2: /demo/instance2 "$@" \ </dev/null
部署
zc.recipe.rhrc配方是为了与zc.recipe.deployment配方一起工作而设计的。您可以指定部署部分的名称。如果指定了部署部分,则
部署名称将用于rc脚本
如果rc脚本自己的部分中没有指定用户,则将使用部署部分中的用户。
如果未指定目标,则将使用部署中的rc-directory选项。
>>> write('buildout.cfg', ... """ ... [buildout] ... parts = zoperc ... ... [deployment] ... name = acme ... user = acme ... rc-directory = %(dest)s ... ... [zoperc] ... recipe = zc.recipe.rhrc ... parts = instance1 instance2 ... chkconfig = 345 90 10 ... chkconfigcommand = echo ... deployment = deployment ... ... [instance1] ... run-script = /opt/zope/bin/zopectl -C /etc/instance1.conf ... env = LD_LIBRARY_PATH=/opt/foolib ... ... [instance2] ... """ % dict(dest=demo))
如果使用部署,则任何现有脚本都必须以部署名称为前缀。我们将重命名instance2脚本以反映这一点
>>> os.rename(join(demo, 'instance2'), join(demo, 'acme-instance2'))>>> print system('bin/buildout'), Uninstalling zoperc. Running uninstall recipe. --del zoperc Installing zoperc. --add acme>>> ls(demo) - acme - acme-instance1 - acme-instance2>>> cat(demo, 'acme') #!/bin/sh <BLANKLINE> # the next line is for chkconfig # chkconfig: 345 90 10 # description: please, please work <BLANKLINE> <BLANKLINE> if [ $(whoami) != "root" ]; then echo "You must be root." exit 1 fi <BLANKLINE> case $1 in stop) <BLANKLINE> echo acme-instance2: /demo/acme-instance2 "$@" \ </dev/null <BLANKLINE> LD_LIBRARY_PATH=/opt/foolib \ su acme -c \ "/opt/zope/bin/zopectl -C /etc/instance1.conf $*" \ </dev/null <BLANKLINE> ;; restart) <BLANKLINE> ${0} stop sleep 1 ${0} start <BLANKLINE> ;; *) <BLANKLINE> LD_LIBRARY_PATH=/opt/foolib \ su acme -c \ "/opt/zope/bin/zopectl -C /etc/instance1.conf $*" \ </dev/null <BLANKLINE> echo acme-instance2: /demo/acme-instance2 "$@" \ </dev/null <BLANKLINE> ;; esac <BLANKLINE>边缘情况,当我们删除部分时,我们卸载acme
>>> write('buildout.cfg', ... """ ... [buildout] ... parts = ... """) >>> print system('bin/buildout'), Uninstalling zoperc. Running uninstall recipe. --del acme
进程管理
通常,该配方不会启动和停止进程。如果我们想让它这样做,我们可以使用带有“true”值的进程管理选项。
>>> write('buildout.cfg', ... """ ... [buildout] ... parts = zoperc ... ... [zoperc] ... recipe = zc.recipe.rhrc ... parts = zope ... dest = %(dest)s ... process-management = true ... ... [zope] ... run-script = echo zope ... """ % dict(dest=demo))
当部分安装时,进程将被启动
>>> print system('bin/buildout'), Installing zoperc. zope start
当部分更新时,它也会被启动。这只是为了确保它在运行。
>>> print system('bin/buildout'), Updating zoperc. zope start
如果我们更新部分,那么当部分被卸载和重新安装时,进程将被停止和启动。我们通常会通过添加仅用于强制重新安装的摘要选项来强制这样做,通常是因为构建out中的其他某些内容已更改。
>>> write('buildout.cfg', ... """ ... [buildout] ... parts = zoperc ... ... [zoperc] ... recipe = zc.recipe.rhrc ... parts = zope ... dest = %(dest)s ... process-management = true ... digest = 1 ... ... [zope] ... run-script = echo zope ... """ % dict(dest=demo))>>> print system('bin/buildout'), Uninstalling zoperc. Running uninstall recipe. zope stop Installing zoperc. zope start>>> print system('bin/buildout buildout:parts='), Uninstalling zoperc. Running uninstall recipe. zope stop
回归测试
异常格式化错误
如果我们不提供运行脚本,我们会得到一个异常(错误:格式错误的异常字符串,包含字面量‘%s’)
>>> write('buildout.cfg', ... """ ... [buildout] ... parts = zoperc ... ... [zoperc] ... recipe = zc.recipe.rhrc ... parts = zope ... dest = %(dest)s ... ... [zope] ... """ % dict(dest=demo)) >>> print system('bin/buildout'), Installing zoperc. zc.recipe.rhrc: Part zope doesn't define run-script and /demo/zope doesn't exist. While: Installing zoperc. Error: No script for zope
下载
项目详情
zc.recipe.rhrc-1.4.2.tar.gz的散列
算法 | 散列摘要 | |
---|---|---|
SHA256 | 33bd3809cafe01af40a5187dd003450b823f75bc3b5e62a3e7dc710c79a3e3f3 |
|
MD5 | 97e03cf373886a140f2b09aaba01ea23 |
|
BLAKE2b-256 | 3f4ef9894a63808a72cb0e63efb5aa142acb3f701e030170eba5c6f5de8e2d64 |