-
Notifications
You must be signed in to change notification settings - Fork 59
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Monitoring all systemd units status change #61
Comments
The issue is that the path of the properties interface that emitted the signal is |
Right, that's what I figured but I means I have to create a new proxy object for every systemd unit and register a signal callback for Isn't there a way to do a "wildcard" subscription to signals? Like |
I think what you're doing is beyond the scope of the high level client. Look at the low level interface which can be used to install a single callback for multiple paths. You'll need to add a match rule with the The docs and test cases provide plenty of examples on how to do that. If you need more support, you can ask questions here or go to my discord channel. |
Hi @acrisci, thanks for your advice, here is a working script that monitors all systemd units import asyncio
import os
import signal
from dbus_next.message import Message
from dbus_next.constants import BusType
from dbus_next.aio import MessageBus
def dbus_path_to_name(path):
name = os.path.basename(path)
name = name.replace('_40', '@')
name = name.replace('_2e', '.')
name = name.replace('_5f', '_')
name = name.replace('_2d', '-')
name = name.replace('_5c', '\\')
return name
def message_handler(msg):
name = dbus_path_to_name(msg.path)
properties = msg.body[1]
if 'ActiveState' not in properties:
return False
print('unit: %s, ActiveState: %s' % (name, properties['ActiveState'].value))
return True
loop = asyncio.get_event_loop()
stop_event = asyncio.Event()
async def main():
bus = await MessageBus(bus_type=BusType.SYSTEM).connect()
rules = [
{
'type': 'signal',
'interface': 'org.freedesktop.DBus.Properties',
'path_namespace': '/org/freedesktop/systemd1/unit',
'member': 'PropertiesChanged',
},
]
match = [','.join('%s=%r' % i for i in r.items()) for r in rules]
msg = Message(
destination='org.freedesktop.DBus',
path='/org/freedesktop/DBus',
interface='org.freedesktop.DBus.Monitoring',
member='BecomeMonitor',
signature='asu',
body=[match, 0],
serial=bus.next_serial(),
)
await bus.call(msg)
bus.add_message_handler(message_handler)
await stop_event.wait()
loop.add_signal_handler(signal.SIGINT, stop_event.set)
loop.add_signal_handler(signal.SIGTERM, stop_event.set)
loop.run_until_complete(main()) This is not very pretty API but I can live with it. It would be awesome if this could be integrated in the "high-level API" somehow. Cheers 👍 |
I would advise against using If you do use the monitor api, report bugs with that because I don't have any testing for it right now. |
Could you provide a concrete code example for the use of Thanks. |
Unlike someone else, I decided to spend some time figuring this out @rjarry here's how your example would look using AddMatch: import asyncio
import signal
import os
from dbus_next.aio import MessageBus
from dbus_next.message import Message
from dbus_next.constants import BusType, MessageType
def dbus_path_to_name(path):
name = os.path.basename(path)
name = name.replace('_40', '@')
name = name.replace('_2e', '.')
name = name.replace('_5f', '_')
name = name.replace('_2d', '-')
name = name.replace('_5c', '\\')
return name
def message_handler(msg):
name = dbus_path_to_name(msg.path)
properties = msg.body[1]
if 'ActiveState' not in properties:
return False
print('unit: %s, ActiveState: %s' % (name, properties['ActiveState'].value))
return True
async def main():
stop_event = asyncio.Event()
loop = asyncio.get_event_loop()
loop.add_signal_handler(signal.SIGINT, stop_event.set)
loop.add_signal_handler(signal.SIGTERM, stop_event.set)
bus = await MessageBus(bus_type=BusType.SYSTEM).connect()
reply = await bus.call(Message(
destination='org.freedesktop.DBus',
path='/org/freedesktop/DBus',
interface='org.freedesktop.DBus',
member='AddMatch',
signature='s',
body=["path_namespace='/org/freedesktop/systemd1/unit',type='signal',interface='org.freedesktop.DBus.Properties'"],
serial=bus.next_serial()
))
assert reply.message_type == MessageType.METHOD_RETURN
bus.add_message_handler(message_handler)
await stop_event.wait()
asyncio.run(main()) However, instead of watching the unit namespace, systemd's dbus interface can be used directly reply = await bus.call(Message(
# ...
body=["interface='org.freedesktop.systemd1.Manager'"],
# ...
)) The message handler could look like: def message_handler(msg):
body = msg.body
if msg.member == 'JobNew':
print(f'New Job: {body[2]}')
if msg.member == 'JobRemoved':
print(f'Job Finished: {body[2]}, result: {body[3]}') See the systemd dbus docs for the possible job results and more: https://www.freedesktop.org/software/systemd/man/org.freedesktop.systemd1.html#Signals Another option for monitoring systemd units would be to parse the journal using |
Hi,
When running the following commands, I can see
PropertiesChanged
signals that are printed when systemd units are restarted:I have written a simple program that attempts to do the same thing:
However, the callback is never called when I restart services. Is there something I missed?
I have very little knowledge of DBus. Is it even possible to monitor all units with a single signal? Searching on the net did not help much, neither did reading the official freedesktop documentation.
Any help will be appreciated, thanks!
The text was updated successfully, but these errors were encountered: