pyinfra
pyinfra copied to clipboard
systemd.service() does not support wildcards
Is your feature request related to a problem? Please describe
Commands like systemctl stop abc*
support glob-style wildcards.
However, systemd.service()
does not.
Describe the solution you'd like
The obvious "user space" solution is probably something like this:
from fnmatch import fnmatch
from pyinfra import host
from pyinfra.facts.systemd import SystemdEnabled
from pyinfra.operations import systemd
def services(pattern, name=None, **kwargs):
"""
Manage the state of all systemd services matching a glob pattern
"""
services = get_enabled_services()
for service in services:
if fnmatch(service, pattern):
iname = None if name is None else f"{name}: {service}"
systemd.service(
name=iname,
service=service,
**kwargs
)
def get_enabled_services():
"""
Return a list of enabled systemd services
"""
units = host.get_fact(SystemdEnabled)
return [name for name, enabled in units.items() if enabled and name.endswith(".service")]
However, this works through the list of services step by step, which means it accumulates the run time. Doing the same operation via the systemctl
command will perform all changes in parallel and needs only approximately the longest run time of any of the changes.
Reading the underlying code, it turns out that this basically already works. The smallest possible change that resolves the issue would be the following:
In pyinfra/pyinfra/operations/util/service.py
replace line 19
is_running = statuses.get(name, None)
with
is_running = any(s for n, s in statuses.items() if fnmatch(n, name))
I.e., if any of the services that match the pattern is running, treat the pattern as running. This is compatible with the current non-wildcard name behavior since fnmatch matches non-wildcard strings to themselves.
The question is whether this is enough or if it is wished that the list of services that is interacted with is shown in the printed output. This would need a much bigger change, I fear.
Either way, I would be happy to provide a PR for the above solution (plus the needed docs changes, etc.) or work on a more complex solution as I would really like this feature to exist.