Skip to main content

High-level Python client for systemd user services: unit management, journal reading, sync + async

Project description

systemd-client

PyPI Python License Tests Docs

The definitive Python library for systemd. Manage services, create units, read journals, analyze security, control resources, and monitor everything — from Python or the terminal.

Documentation: kalexnolasco.github.io/systemd-client

Features

Category What you can do
Unit Management list, status, cat, start, stop, restart, reload, try-restart, reload-or-restart, enable, disable, mask, unmask, reset-failed, kill
Unit File Builder Create .service, .timer, .socket, .path files with a fluent Python API
Install / Uninstall Deploy unit files, create drop-in overrides, uninstall units
Transient Units Run commands as systemd services without creating files (systemd-run)
Journal Query with filters (unit, priority, time range, grep) + real-time follow
Resource Control Set cgroup limits (CPU, memory, IO), monitor usage, list timers/sockets/dependencies
Security Analysis Boot blame, security scoring (0-10 exposure), unit file verification
sd_notify Notify systemd from your Python service (READY, STATUS, WATCHDOG)
Power Management poweroff, reboot, suspend, hibernate
Environment show/set/unset manager environment variables
Sessions List login sessions and users (loginctl)
Interactive TUI Full dashboard powered by Ratatui (Rust rendering engine)
Dual API Async-first + sync wrappers, identical interfaces
Scope User session (--user) or system-wide (--system)
Zero Dependencies Core library needs nothing beyond Python 3.11+ stdlib

Install

pip install systemd-client            # Core (zero deps)
pip install systemd-client[tui]       # + Interactive TUI (ratatui-py)
pip install systemd-client[dbus]      # + D-Bus backend (dasbus)
pip install systemd-client[all]       # Everything

Quick Start

Manage services

from systemd_client import SystemdClient

with SystemdClient() as client:
    # List all running services
    for unit in client.list_units(unit_type="service"):
        print(f"{unit.name}: {unit.active_state} ({unit.sub_state})")

    # Get detailed status
    status = client.status("my-app.service")
    print(f"PID: {status.main_pid}, Since: {status.active_enter_timestamp}")

    # Control services
    client.restart("my-app.service")
    client.restart_units(["app.service", "worker.service"])  # batch

    # Quick checks
    print(f"Active: {client.is_active('my-app.service')}")

Create services from Python

from systemd_client import ServiceBuilder, TimerBuilder, SystemdClient

# Build a .service file with a fluent API
unit = (ServiceBuilder("my-app")
    .description("My FastAPI Application")
    .exec_start("/usr/bin/python3 /opt/app/main.py")
    .working_directory("/opt/app")
    .user("appuser")
    .environment({"PORT": "8080", "ENV": "production"})
    .restart("on-failure")
    .restart_sec(5)
    .wanted_by("default.target")
    .build())

# Deploy in one step
with SystemdClient() as client:
    client.install(unit)
    client.enable("my-app.service")
    client.start("my-app.service")

# Create a timer (cron replacement)
timer = (TimerBuilder("backup")
    .description("Daily backup")
    .on_calendar("*-*-* 02:00:00")
    .persistent(True)
    .wanted_by("timers.target")
    .build())

Run transient units (systemd-run)

with SystemdClient() as client:
    # One-off command as a systemd service
    result = client.run("/usr/bin/python3 /opt/backup.py", name="backup-task")
    print(f"Running: {result.unit_name}")

    # Schedule a recurring timer
    client.run_on_calendar("daily", "/usr/bin/python3 /opt/cleanup.py")

    # With resource limits
    client.run("make -j8", properties={"MemoryMax": "2G", "CPUQuota": "50%"})

Monitor resources

with SystemdClient() as client:
    # Set cgroup limits
    client.set_property("my-app.service", {"MemoryMax": "512M", "CPUQuota": "25%"})

    # Check resource usage
    usage = client.get_resource_usage("my-app.service")
    print(f"CPU: {usage.cpu_usage_nsec / 1e9:.1f}s")
    print(f"Memory: {usage.memory_current / 1024**2:.0f}MB")

    # List timers
    for timer in client.list_timers():
        print(f"{timer.name}: {timer.time_left}")

Security analysis

with SystemdClient() as client:
    # What's slow at boot?
    for entry in client.analyze_blame()[:5]:
        print(f"{entry.time_us / 1e6:.3f}s  {entry.unit}")

    # Security audit (0 = hardened, 10 = exposed)
    sec = client.analyze_security("my-app.service")
    print(f"Exposure: {sec.exposure}/10.0")

    # Verify unit files before deploying
    errors = client.analyze_verify("my-app.service")

sd_notify — from your Python service

# In a Type=notify systemd service:
from systemd_client.notify import SystemdNotifier

notifier = SystemdNotifier()
notifier.ready()                       # Tell systemd we're up
notifier.status("Listening on :8080")  # Update status text
notifier.watchdog()                    # Keep-alive ping
notifier.stopping()                    # Graceful shutdown

Async API

import asyncio
from systemd_client import AsyncSystemdClient

async def main():
    async with AsyncSystemdClient() as client:
        # Concurrent health check
        services = ["app.service", "worker.service", "scheduler.service"]
        results = await asyncio.gather(
            *(client.is_active(svc) for svc in services)
        )
        for svc, active in zip(services, results):
            print(f"{svc}: {'UP' if active else 'DOWN'}")

asyncio.run(main())

System scope

from systemd_client import SystemdClient, SystemdScope

# Manage system-wide services (requires root)
with SystemdClient(scope=SystemdScope.SYSTEM) as client:
    units = client.list_units(unit_type="service")

CLI

# Unit management
systemd-client list --type service
systemd-client list-unit-files --state enabled
systemd-client status my-app.service
systemd-client cat my-app.service
systemd-client start my-app.service
systemd-client stop my-app.service
systemd-client restart a.service b.service c.service  # batch
systemd-client restart --no-block my-app.service
systemd-client try-restart my-app.service
systemd-client reload-or-restart my-app.service
systemd-client enable my-app.service
systemd-client reset-failed my-app.service
systemd-client kill my-app.service --signal SIGHUP

# Create and deploy unit files
systemd-client create-service --name my-app --exec-start /bin/app --restart on-failure --install
systemd-client create-timer --name backup --on-calendar daily --install
systemd-client install my-app.service --from-file ./my-app.service
systemd-client uninstall my-app.service

# Transient units (systemd-run)
systemd-client run /bin/echo hello --name my-task --wait
systemd-client run /opt/backup.py --on-calendar daily

# Resource monitoring
systemd-client resources my-app.service
systemd-client list-timers
systemd-client list-sockets
systemd-client list-dependencies my-app.service

# Analysis
systemd-client analyze-blame
systemd-client analyze-security my-app.service
systemd-client analyze-verify my-app.service

# Environment and sessions
systemd-client show-environment
systemd-client set-environment MY_VAR=hello
systemd-client list-sessions
systemd-client list-users

# Power management
systemd-client poweroff
systemd-client reboot
systemd-client suspend

# System scope
systemd-client --scope system list --type service
systemd-client --scope system restart nginx.service

# Interactive TUI dashboard
systemd-client tui
systemd-client --scope system tui

# Output formats
systemd-client --json list
systemd-client --no-color status my-app.service

Interactive TUI

Launch the full interactive dashboard:

systemd-client tui

Features:

  • Real-time unit list with color-coded states (green=active, red=failed)
  • Keyboard-driven: s=start, S=stop, r=restart, e=enable, d=disable
  • Journal viewer per unit with j
  • Scope toggle with Tab
  • Auto-refresh every 2 seconds
  • Powered by Ratatui (Rust rendering engine, 30-60 FPS)

Requires: pip install systemd-client[tui]

Architecture

Your Application
    |
    +-- SystemdClient (sync)
    |       |
    +-- AsyncSystemdClient (async)
            |
            +-- SubprocessBackend ---- systemctl --user/--system ----> systemd
            |     (default, zero deps)
            +-- DBusBackend ---------- D-Bus session/system bus ----> systemd
            |     (optional, dasbus)
            +-- AsyncJournalReader --- journalctl --output=json -----> journal
            +-- Builders ------------- .service/.timer/.socket/.path -> unit files
            +-- Analyze -------------- systemd-analyze ----------------> boot/security
            +-- Notify --------------- $NOTIFY_SOCKET -----------------> sd_notify

Requirements

  • Python >= 3.11
  • Linux with systemd
  • systemctl and journalctl on PATH

License

LGPL-2.1-or-later


systemd-client · Documentation · GitHub · PyPI

Project details


Download files

Download the file for your platform. If you're not sure which to choose, learn more about installing packages.

Source Distribution

systemd_client-0.9.0.tar.gz (82.0 kB view details)

Uploaded Source

Built Distribution

If you're not sure about the file name format, learn more about wheel file names.

systemd_client-0.9.0-py3-none-any.whl (52.2 kB view details)

Uploaded Python 3

File details

Details for the file systemd_client-0.9.0.tar.gz.

File metadata

  • Download URL: systemd_client-0.9.0.tar.gz
  • Upload date:
  • Size: 82.0 kB
  • Tags: Source
  • Uploaded using Trusted Publishing? Yes
  • Uploaded via: twine/6.1.0 CPython/3.13.7

File hashes

Hashes for systemd_client-0.9.0.tar.gz
Algorithm Hash digest
SHA256 16deec05dad94ab5cc675e76c764563d10f032ef6d55076a045707939be1113d
MD5 e322c3d1bd818bc837a0bcbd9430153d
BLAKE2b-256 f0b00e40c2fa9be64740ecef9dc90a9c5bc45d17a58da53093ef289e44d0c75a

See more details on using hashes here.

Provenance

The following attestation bundles were made for systemd_client-0.9.0.tar.gz:

Publisher: publish.yml on kalexnolasco/systemd-client

Attestations: Values shown here reflect the state when the release was signed and may no longer be current.

File details

Details for the file systemd_client-0.9.0-py3-none-any.whl.

File metadata

  • Download URL: systemd_client-0.9.0-py3-none-any.whl
  • Upload date:
  • Size: 52.2 kB
  • Tags: Python 3
  • Uploaded using Trusted Publishing? Yes
  • Uploaded via: twine/6.1.0 CPython/3.13.7

File hashes

Hashes for systemd_client-0.9.0-py3-none-any.whl
Algorithm Hash digest
SHA256 88b536a0d800ca5b2cfd019f810f3c2b6a2a14421cfcf79de6332d520b5ad2da
MD5 ab382bcae02e978948155da9ad5c193a
BLAKE2b-256 897c0a116062d11f675066bdb5f6a63ce3b2eb0aeb2efead0be79999e0f56025

See more details on using hashes here.

Provenance

The following attestation bundles were made for systemd_client-0.9.0-py3-none-any.whl:

Publisher: publish.yml on kalexnolasco/systemd-client

Attestations: Values shown here reflect the state when the release was signed and may no longer be current.

Supported by

AWS Cloud computing and Security Sponsor Datadog Monitoring Depot Continuous Integration Fastly CDN Google Download Analytics Pingdom Monitoring Sentry Error logging StatusPage Status page