用户Crontab安装Buildout配方
项目描述
z3c.recipe.usercrontab
问题
在部署应用程序时,定期启动维护任务可能很有用。在 Unix 平台上,这通常是通过使用 cron 来完成的,它会启动 cronjobs。通过将文件放置在 /etc/cron.d(例如)向系统范围的 cron 目录添加 cronjobs 可以使用 zc.recipe.deployment 包来处理,但它不支持通过普通用户添加 cronjobs。(因为 /etc/cron.d 通常是对所有人可写的)。
解决方案
z3c.recipe.usercrontab 通过使用 crontab(1) 与 cron 进行接口,允许普通用户安装他们自己的 cronjobs。这是通过在安装和卸载软件包时添加和删除 cronjobs 来实现的。
如何使用
要使用 z3c.recipe.usercrontab,您需要将以下内容添加到您的 buildout.cfg 中
[mycronjob] recipe = z3c.recipe.usercrontab times = 0 12 * * * command = echo nothing happens at noon
并最后将 mycronjob 添加到您的 buildout.cfg 的 parts 行中
为您的 cron-entry 添加注释
[mycronjob] recipe = z3c.recipe.usercrontab times = 0 12 * * * command = echo nothing happens at noon comment = Run daily at noon
如果您更喜欢手动启用 cronjobs,可以通过将 enabled 设置为 False 来生成一个被注释掉的 cron-entry
[mycronjob] recipe = z3c.recipe.usercrontab times = 0 12 * * * command = echo nothing happens at noon enabled = false
运行 buildout 后,您可以通过 crontab -l 检查生成的 cron-entries。
致谢
原始作者:Jasper Spaans 和 Jan-Jaap Driessen。
最新版本和当前维护者:Reinout van Rees。
详细文档
z3c.recipe.usercrontab 脚本是用于方便将 cronjobs 安装到用户 crontabs 的小型脚本来。
>>> from z3c.recipe.usercrontab.usercrontab import UserCrontabManager
条目处理
一个用户 crontab 管理器管理一个特定 buildout 部分的用户的 crontab。该部分最终在标识符中结束。我们将在这里使用“test”。
>>> c = UserCrontabManager(identifier='test')
在这些测试中,我们可以通过手动填写 cron 条目的列表来模拟 crontab
>>> c.crontab = ['@reboot echo "hello world"'] >>> print(c) # Handy shortcut @reboot echo "hello world"
现在,我们使用官方方式向其中添加一个条目。该条目被标记包围
>>> c.add_entry('@reboot echo "I just got added"') >>> print(c) @reboot echo "hello world" <BLANKLINE> # Generated by test @reboot echo "I just got added" # END test <BLANKLINE>
删除条目也有效。只要存在“由生成的”标记,就不重要您删除哪个条目:所有被标记包围的内容都会被清除
>>> c.del_entry('bla bla') == 1 True >>> print(c) @reboot echo "hello world"
一个条目也可以包含一个解释性的注释行
>>> c.add_entry('@reboot echo "I just got added"', ... comment="This ought to happen first") >>> print(c) @reboot echo "hello world" <BLANKLINE> # Generated by test # This ought to happen first @reboot echo "I just got added" # END test <BLANKLINE>
在 0.6 版本之前,使用了一个 WARNING 环境变量。一个条目(现在的内容很重要!)在那里找到
>>> c.crontab = ['@reboot echo "hello world"', ... 'WARNING="Everything below is added by bla bla', ... '@reboot echo "old entry 1"', ... '@reboot echo "old entry 2"'] >>> print(c) @reboot echo "hello world" WARNING="Everything below is added by bla bla @reboot echo "old entry 1" @reboot echo "old entry 2" >>> c.del_entry('@reboot echo "old entry 1"') 1 >>> print(c) @reboot echo "hello world" WARNING="Everything below is added by bla bla @reboot echo "old entry 2"
删除最后一个剩余的 WARNING 条目也会删除 WARNING
>>> c.del_entry('@reboot echo "old entry 2"') 1 >>> print(c) @reboot echo "hello world"
简要地,在 0.5 版本中,使用了一个 ‘BUILDOUT’ 环境变量来按 buildout 对项目进行分组。现在进行一些升级/降级测试。0.5.1 再次删除了环境变量。我们将添加一个带有这样的(现在已弃用的)“分组环境变量”的条目。首先是起始情况
>>> c.crontab=[ ... 'WARNING="Everything below is added by bla bla', ... 'BUILDOUT=my/buildout', ... '@reboot echo nothing happens'] >>> print(c) WARNING="Everything below is added by bla bla BUILDOUT=my/buildout @reboot echo nothing happens
进行任何操作(添加/删除)都会清除 BUILDOUT 语句
>>> c.del_entry('nonexisting') 0 >>> print(c) WARNING="Everything below is added by bla bla @reboot echo nothing happens
并且为了确保这一点,删除该条目会清空整个文件
>>> c.del_entry('@reboot echo nothing happens') 1 >>> print(c) <BLANKLINE>
读写 crontab 方法
接下来,测试 read_crontab 和 write_crontab 方法;我们将使用 cat 和一个临时文件,以不修改运行这些测试的用户的 crontab
>>> import tempfile >>> t = tempfile.NamedTemporaryFile('w') >>> crontestfile = t.name >>> dont_care = t.write("#dummy\n")>>> c = UserCrontabManager(readcrontab="cat %s" % crontestfile, ... writecrontab="cat >%s" % crontestfile, ... identifier='test') >>> c.read_crontab() >>> a = repr(c) >>> c.add_entry('# improbable entry') >>> c.write_crontab() >>> c.read_crontab() >>> b =repr(c) >>> a == b False
现在,再次删除此条目,并确保恢复旧 crontab
>>> c.del_entry('# improbable entry') == 1 True >>> c.write_crontab() >>> c.read_crontab() >>> b = repr(c) >>> a == b True
Buildout 脚本使用
进行 buildout 交换
>>> write('buildout.cfg', ... ''' ... [buildout] ... parts = foo ... ... [foo] ... recipe = z3c.recipe.usercrontab ... times = @reboot ... command = echo nothing happens ... readcrontab = cat %(crontest)s ... writecrontab = cat >%(crontest)s ... ''' % ( { 'crontest': crontestfile } ))>>> import os >>> 'Installing foo' in system(buildout) True
检查它是否确实已添加到 crontab 中
>>> c.read_crontab() >>> b = repr(c) >>> a == b False>>> '@reboot\techo nothing happens' in c.crontab True >>> print(c) # Generated by /sample-buildout [foo] @reboot echo nothing happens # END /sample-buildout [foo]
重新运行 buildout 即使没有变化也会运行 crontab 脚本
>>> output = system(buildout) >>> 'Updating foo' in output or 'Installing foo' in output True >>> c.read_crontab() >>> print(c) # Generated by /sample-buildout [foo] @reboot echo nothing happens # END /sample-buildout [foo]
这意味着如果手动弄乱了 crontab,则可以修复 crontab
>>> c.crontab = [] >>> c.write_crontab() >>> c.read_crontab() >>> print(c) >>> output = system(buildout) >>> 'Updating foo' in output or 'Installing foo' in output True >>> c.read_crontab() >>> print(c) # Generated by /sample-buildout [foo] @reboot echo nothing happens # END /sample-buildout [foo]
您还可以向 crontab 条目添加注释
>>> write('buildout.cfg', ... ''' ... [buildout] ... parts = foo ... ... [foo] ... recipe = z3c.recipe.usercrontab ... times = @reboot ... command = echo nothing happens ... comment = Step 1: mention that nothing happens ... readcrontab = cat %(crontest)s ... writecrontab = cat >%(crontest)s ... ''' % ( { 'crontest': crontestfile } )) >>> 'Installing foo' in system(buildout) True >>> c.read_crontab() >>> print(c) # Generated by /sample-buildout [foo] # Step 1: mention that nothing happens @reboot echo nothing happens # END /sample-buildout [foo]
默认情况下,条目是启用的,导致 cronjob 激活
>>> write('buildout.cfg', ... ''' ... [buildout] ... parts = foo ... ... [foo] ... recipe = z3c.recipe.usercrontab ... times = @reboot ... command = echo nothing happens ... enabled = true ... readcrontab = cat %(crontest)s ... writecrontab = cat >%(crontest)s ... ''' % ( { 'crontest': crontestfile } )) >>> 'Installing foo' in system(buildout) True >>> c.read_crontab() >>> print(c) # Generated by /sample-buildout [foo] @reboot echo nothing happens # END /sample-buildout [foo]
您还可以生成一个已禁用的、被注释掉的cronjob,通过设置启用选项为False。
>>> write('buildout.cfg', ... ''' ... [buildout] ... parts = foo ... ... [foo] ... recipe = z3c.recipe.usercrontab ... times = @reboot ... command = echo nothing happens ... enabled = false ... readcrontab = cat %(crontest)s ... writecrontab = cat >%(crontest)s ... ''' % ( { 'crontest': crontestfile } )) >>> 'Installing foo' in system(buildout) True >>> c.read_crontab() >>> print(c) # Generated by /sample-buildout [foo] # @reboot echo nothing happens # END /sample-buildout [foo]
卸载食谱
>>> write('buildout.cfg', ... ''' ... [buildout] ... parts = ... ''' % ( { 'crontest': crontestfile } )) >>> 'Uninstalling foo' in system(buildout) True
并检查其条目已被删除(即,crontab的内容与测试开始时相同;无论如何,testrunner的拆卸确保旧状态被恢复)
>>> c.read_crontab() >>> b = repr(c) >>> a == b True
第二部分安装正常
>>> write('buildout.cfg', ... ''' ... [buildout] ... parts = foo bar ... ... [foo] ... recipe = z3c.recipe.usercrontab ... times = @reboot ... command = echo nothing happens ... readcrontab = cat %(crontest)s ... writecrontab = cat >%(crontest)s ... ... [bar] ... recipe = z3c.recipe.usercrontab ... times = @reboot ... command = echo something happens ... readcrontab = cat %(crontest)s ... writecrontab = cat >%(crontest)s ... ''' % ( { 'crontest': crontestfile } )) >>> output = system(buildout) >>> 'Installing foo' in output True >>> 'Installing bar' in output True >>> c.read_crontab() >>> print(c) <BLANKLINE> # Generated by /sample-buildout [foo] @reboot echo nothing happens # END /sample-buildout [foo] <BLANKLINE> <BLANKLINE> # Generated by /sample-buildout [bar] @reboot echo something happens # END /sample-buildout [bar] <BLANKLINE>
卸载也正常工作
>>> write('buildout.cfg', ... ''' ... [buildout] ... parts = ... ''' % ( { 'crontest': crontestfile } )) >>> output = system(buildout) >>> 'Uninstalling bar' in output True >>> 'Uninstalling foo' in output True
安全阀
如果该部分已被删除,卸载将找不到任何内容。您将收到警告。
>>> write('buildout.cfg', ... ''' ... [buildout] ... parts = foo ... ... [foo] ... recipe = z3c.recipe.usercrontab ... times = @reboot ... command = echo nothing happens ... readcrontab = cat %(crontest)s ... writecrontab = cat >%(crontest)s ... ''' % ( { 'crontest': crontestfile } ))>>> import os >>> 'Installing foo' in system(buildout) True >>> c.crontab = [] >>> c.write_crontab() >>> write('buildout.cfg', ... ''' ... [buildout] ... parts = ... ''' % ( { 'crontest': crontestfile } )) >>> 'WARNING: Did not find a crontab-entry during uninstall' in system(buildout) True
另一个测试:0.6之前的配置模拟
>>> write('buildout.cfg', ... ''' ... [buildout] ... parts = foo ... ... [foo] ... recipe = z3c.recipe.usercrontab ... times = @reboot ... command = echo nothing happens ... readcrontab = cat %(crontest)s ... writecrontab = cat >%(crontest)s ... ''' % ( { 'crontest': crontestfile } ))>>> import os >>> 'Installing foo' in system(buildout) True >>> c.crontab = ['WARNING="Everything below is added by bla bla"', ... 'BUILDOUT=/somewhere/out/there', ... '@reboot\techo nothing happens'] >>> c.write_crontab() >>> write('buildout.cfg', ... ''' ... [buildout] ... parts = ... ''' % ( { 'crontest': crontestfile } )) >>> 'Running uninstall recipe' in system(buildout) True >>> c.read_crontab() >>> print(c) <BLANKLINE>
z3c.recipe.usercrontab更改
1.5 (2018-12-20)
官方支持Python 3.5、3.6、3.7、PyPy和PyPy3。
1.4 (2015-10-29)
增加了一个默认开启的启用选项。通过将其设置为false,您可以生成被注释掉的cronjob。
如果您必须在cronjob被开启(通过手动取消注释或脚本)之前在部署中执行其他任务,这将很有用。[WouterVH]
1.3 (2015-10-05)
新增了一个‘comment’选项。这样您可以为您的crontab条目添加一行简短的说明。[reinout]
1.2.1 (2015-09-11)
将开发迁移到https://github.com/reinout/z3c.recipe.usercrontab [reinout]
进行了一些小修改,以确保一切在python 3上运行。[reinout]
1.1 (2010-11-09)
每个cron条目减少前后空白空格,这样在每次运行bin/buildout时都不会有越来越多的额外空格。[maurits]
1.0 (2009-11-10)
仅对文档进行了小的修改;版本提升到1.0以表示稳定性。[reinout]
0.7 (2009-08-24)
现在每次buildout运行时都会检查crontab,而不仅仅是配置发生变化时。[reinout]
0.6.1 (2009-06-17)
文档修复。[reinout]
0.6 (2009-06-16)
删除了基本上未使用的完整环境变量处理。[reinout]
现在添加带有描述性注释的条目:包括buildout文件和部分名称。[reinout]
0.5.1 (2009-06-16)
撤销了“BUILDOUT=…”环境变量,包括迁移。我将在这次发布后添加更好的方法。[reinout]
0.5 (2009-06-15)
为没有BUILDOUT变量的0.5之前的条目添加了迁移代码。[reinout]
在“BUILDOUT=…”变量前面添加了额外的空白行,以便于更好的可读性。[reinout]
将每个由一个buildout处理的crontab行的“BUILDOUT=…”作为环境变量添加。这使得更容易找出哪个buildout添加了什么(如果您有多个),或者哪个buildout(如果您不知道buildout在哪里)。
0.4 (2008-02-25)
修复了UserCrontabs带有空readcrontab和writecrontab构造函数参数时的错误
0.3 (2008-02-23)
重命名为z3c.recipe.usercrontab
添加了一个选项来更改用于读取和写入crontabs的命令
改进了测试,以不修改真实的crontab
0.2 (2008-01-12)
如果buildout卸载中无法删除条目,则发出警告
如果buildout卸载中要删除多个条目,则中断
让del_entry返回删除的数量
0.1 (2008-01-12)
初始发布。