使用DBus在Python中启用和禁用一个systemd服务
即将推出的picockpit-client会对来自前端的删除事件做出反应 通过停用它的服务 (然而,该应用程序将保持安装)。
同样,当你决定再次运行picockpit-client connect时,该服务将被重新启用并自动为你启动。
这可以通过使用 Python DBus接口.
DBus是一个用于与其他应用程序交互的总线系统。应用程序和系统服务在DBus上发布某种接口,你可以使用它。
以下是如何做到这一点的。
停用一项服务。
输入dbus
system_bus = dbus.SystemBus()
systemd1 = system_bus.get_object('org.freedesktop.systemd1', '/org/freedesktop/systemd1')
manager = dbus.Interface(systemd1, 'org.freedesktop.systemd1.Manager')
manager.DisableUnitFiles(['picockpit-client.service'], False)manager.Reload()
我们打开 系统总线 - 也有一个SessionBus(dbus.SessionBus()),用于与用户会话交互。然而,在这种情况下,我们要访问系统服务。
对经理来说,这些都是 "标准 "调用--为了访问systemd,你需要通过它们。
下一行是我们指示管理器禁用UnitFiles的地方。这里有一些关于这个的说明。
- 第一个变量是一个字符串数组--即使你只想禁用一个服务,你也要把它作为一个数组传递。
- 你传入你的服务的名称,包括'.service'部分--比如说 picockpit-client.service
- 第二个变量是必需的,如果是假的,则在每次启动时禁用(如果是真的,则只在这个运行时禁用)。
这里是DisableUnitFiles的签名,来自于 DBus / systemd / Freedesktop.org的官方文档:
注意,在与DBus接口进行交互时,提供所有的变量是非常重要的。 他们是 不是 可选的,并且 "设置为合理的默认值",因为你可能从许多其他接口/API中使用。
最后,我在网上看到,修改需要通过使用 manager.Reload() (文件中说。可以调用Reload()来重新加载所有单元文件)
启用并启动一个服务。
输入dbus
system_bus = dbus.SystemBus()
systemd1 = system_bus.get_object('org.freedesktop.systemd1', '/org/freedesktop/systemd1')
manager = dbus.Interface(systemd1, 'org.freedesktop.systemd1.Manager')
manager.EnableUnitFiles(['picockpit-client.service'], False, True)
manager.Reload()
job = manager.RestartUnit('picockpit-client.service', 'fail')
与上述类似,EnableUnitFiles有以下不同。
- 在字符串数组后面有两个布尔变量,它们需要被传入
- 第一个布尔变量,如上所述,决定了该服务是否只在这个运行时启用(True)或普遍启用(False)。
- 第二个布尔变量,有点隐晦地被描述为。"第二个变量控制指向其他单位的符号链接在必要时是否应被替换"。我决定将其设置为 "真"。
下面是文档中的EnableUnitFiles签名。
仔细想想,我选择的 "True "对于其他应用来说可能并不合适("Force "意味着一种对安全的覆盖)。
最后。 重新启动单位 来实际启动该服务。
- 注意,这需要一个字符串值,而不是一个字符串数组。
- 第二个值是一个指定模式的字符串。请参考 正式文件 为不同的模式,这是可能的。
这里是RestartUnit的签名。
注意:我没有处理返回值,理想情况下,特别是对于关键的应用,你会想要研究这个问题--请参考 正式文件.
误区
签名不匹配
ERROR:dbus.connection:无法根据签名'asb'设置参数(['picockpit-client.service'],)。:在D-Bus签名中发现的项目比Python参数中的多
如果你得到类似上述的错误,请检查你是否按照文档中的签名要求传递了所有参数。
在这种情况下,我有(错误)。
manager.DisableUnitFiles(['picockpit-client.service'] )
而不是正确的。
manager.DisableUnitFiles(['picockpit-client.service'], False)
也要确保检查你是否传入了一个字符串(s),其中一个字符串数组(作为)是必需的。