systemd / pystemd

A thin Cython-based wrapper on top of libsystemd, focused on exposing the dbus API via sd-bus in an automated and easy to consume way.
GNU Lesser General Public License v2.1
411 stars 36 forks source link

Is there any way to listen to service state changes? #43

Closed fnoop closed 4 years ago

fnoop commented 4 years ago

Hi, is there any mechanism for callbacks if a service ActiveState (or other properties) change?

davide125 commented 4 years ago

Yes, you want to hook on the PropertiesChanged signal, see https://github.com/facebookincubator/pystemd/blob/master/examples/monitor_all_units_from_signal.py and https://github.com/facebookincubator/pystemd/blob/master/examples/monitor_from_signal.py for examples.

SamuelDudley commented 4 years ago

Hi @davide125, I'm working with @fnoop on a project and wanted to add some more detail to the question he posed above (and that you have answered, thanks :) ).

As you pointed out the we can "subscribe" to changes in the service state e.g. running -> stopped using the monitor_from_signal example provided. The issue we are facing is achieving something similar but for the enabled and disabled change events (e.g. we are interested in status in the example below).

from pystemd.systemd1 import Manager

with Manager() as manager:
    for unit, status in manager.Manager.ListUnitFilesByPatterns(["enabled", "disabled", "indirect"], ["maverick-*"]):
        print(f"unit:{unit}, status:{status}")

output

path:b'/etc/systemd/system/maverick-vision_landing.service', status:b'disabled'
path:b'/etc/systemd/system/maverick-mavros@.service', status:b'indirect'
path:b'/etc/systemd/system/maverick-api@.service', status:b'indirect'
path:b'/etc/systemd/system/maverick-mavlogd.service', status:b'enabled'
path:b'/etc/systemd/system/maverick-influxd.service', status:b'enabled'
path:b'/etc/systemd/system/maverick-webrtc.service', status:b'disabled'
...

Perhaps the best we can do is watch for a UnitFilesChanged signal as per the snippet below and then use the Manager to get the enabled / disabled status of all services we are interested in?

bus.match_signal(
    b"org.freedesktop.systemd1",
    None,
    None,
    b"UnitFilesChanged",
    process,  # callback for this message
    None,
)

Note: where we have indirect services (such as the maverick-api@.service service above) there does not appear to be a way of extracting the enabled / disabled status of the instances from the Manager ( maverick-api@dev and maverick-api@fc in this case).

If you could provide some guidance on adding a callback like mechanism for the disabled / enabled status of services (with bonus points for instances of indirect services) it would be greatly appreciated.

Thanks!

SamuelDudley commented 4 years ago

For what it is worth the code ended up looking like this: https://github.com/goodrobots/maverick-api/blob/master/maverick_api/modules/api/maverick/maverick_service.py

Thanks for the library, it seems to work quite well.

@fnoop feel free to close