{"id":27958802,"url":"https://github.com/foo290/sysinit","last_synced_at":"2026-02-21T16:02:47.978Z","repository":{"id":288811136,"uuid":"963314376","full_name":"foo290/sysinit","owner":"foo290","description":"A python wrapper around systemctl to deal with systemd services","archived":false,"fork":false,"pushed_at":"2025-04-19T19:28:18.000Z","size":100,"stargazers_count":0,"open_issues_count":0,"forks_count":0,"subscribers_count":1,"default_branch":"main","last_synced_at":"2025-06-09T09:56:30.966Z","etag":null,"topics":[],"latest_commit_sha":null,"homepage":null,"language":"Python","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":"mit","status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/foo290.png","metadata":{"files":{"readme":"README.md","changelog":null,"contributing":null,"funding":null,"license":"LICENSE","code_of_conduct":null,"threat_model":null,"audit":null,"citation":null,"codeowners":null,"security":null,"support":null,"governance":null,"roadmap":null,"authors":null,"dei":null,"publiccode":null,"codemeta":null,"zenodo":null}},"created_at":"2025-04-09T13:44:02.000Z","updated_at":"2025-04-19T19:28:21.000Z","dependencies_parsed_at":"2025-04-20T15:15:37.245Z","dependency_job_id":null,"html_url":"https://github.com/foo290/sysinit","commit_stats":null,"previous_names":["foo290/sysinit"],"tags_count":0,"template":false,"template_full_name":null,"purl":"pkg:github/foo290/sysinit","repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/foo290%2Fsysinit","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/foo290%2Fsysinit/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/foo290%2Fsysinit/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/foo290%2Fsysinit/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/foo290","download_url":"https://codeload.github.com/foo290/sysinit/tar.gz/refs/heads/main","sbom_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/foo290%2Fsysinit/sbom","host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":260318656,"owners_count":22991118,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2022-07-04T15:15:14.044Z","host_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub","repositories_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories","repository_names_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repository_names","owners_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners"}},"keywords":[],"created_at":"2025-05-07T18:26:20.156Z","updated_at":"2026-02-21T16:02:47.972Z","avatar_url":"https://github.com/foo290.png","language":"Python","funding_links":[],"categories":[],"sub_categories":[],"readme":"# SysInit - Lightweight Python Service Unit Manager\n\n[![PyPI version](https://badge.fury.io/py/sysinit.svg)](https://badge.fury.io/py/sysinit) \u003c!-- Replace 'sysinit' if needed --\u003e\n[![License: MIT](https://img.shields.io/badge/License-MIT-yellow.svg)](https://opensource.org/licenses/MIT)\n\u003c!-- Add other badges like build status if you have CI --\u003e\n\n`sysinit` is a Python library for defining, managing, and interacting with systemd-like service units using simple YAML configurations. It allows you to programmatically control the lifecycle (start, stop, enable, disable, reload) of background processes or tasks.\n\n---\n\n## ⚠️ Important Prerequisites \u0026 Warnings\n\n*   **Operating System:** This library **only works on Linux distributions that use systemd**. It fundamentally relies on the `systemctl` command and the systemd directory structure. It will **not** work on macOS, Windows, or non-systemd Linux systems.\n*   **System Mode (`sudo` Required):** By default, or when `manage_as_user: false` is set for a service, `sysinit` interacts with the **system-wide systemd instance**. This requires **`sudo` (root) privileges** for most operations:\n    *   Placing/removing service files in `/etc/systemd/system/`.\n    *   Running `systemctl start/stop/enable/disable/restart/daemon-reload` for system services.\n    *   **Security Risk:** Granting `sudo` access to any script carries inherent security risks. Understand the commands being run (primarily `systemctl` and file operations in system directories) before using this mode. `sysinit` attempts to use `sudo` only when necessary for system-level interaction.\n\n---\n\n## ✨ Features\n\n*   Define services declaratively in YAML.\n*   Manage systemd **system** services (requires `sudo`).\n*   Manage systemd **user** services (`sudo`-free).\n*   Control service lifecycle: `start`, `stop`, `restart`, `reload`.\n*   Enable/disable services for boot/login start.\n*   Load/unload service definition files.\n*   Pythonic API for programmatic control (`Unit`, `UnitManager`).\n*   Dry-run mode for safe testing.\n*   Basic logging of operations.\n\n---\n\n## 💾 Installation\n\n```bash\n# Install from PyPI\npip install sysinit\n\n# uv install\nuv add sysinit\n\n# For development (includes testing and formatting tools)\npip install \"sysinit[dev]\"\n# Or: pip install black pytest pyyaml\n```\n\n## 🚀 Quick Start (CLI / Terminal)\n\nThe primary way to interact via the command line is through the `sysinit-term` command, which provides an interactive shell.\n\n1.  **Ensure `ipython` is installed** (see Installation section above).\n2.  **(Optional) Create `config.yaml`:** Define your services as described in the sections below. If `config.yaml` doesn't exist in the current directory, the shell will start with an empty manager.\n3.  **Launch the Interactive Shell:**\n    ```bash\n    # Use default config.yaml (if it exists)\n    sysinit-term shell\n\n    # Specify a different configuration file\n    sysinit-term --config /path/to/your/config.yaml shell\n\n    # Get help\n    sysinit-term --help\n    sysinit-term shell --help\n    ```\n4.  **Inside the Shell:** You'll get an IPython prompt. Use the available objects and helper functions (like `manager`, `Unit`, `Command`, `start()`, `stop()`, `status()`, `services()`, `add_unit()`) to manage your services interactively. Type `exit()` or press `Ctrl+D` to quit.\n\n    ```ipython\n    # Example session inside the shell:\n    In [1]: services() # List services loaded from config (or 'No services...')\n    Managed services:\n    - my-web-server\n    - my-dev-tool\n\n    In [2]: status('my-dev-tool')\n    # Status output...\n\n    In [3]: stop('my-web-server') # May require sudo password if not run as root\n    Stopping 'my-web-server'...\n    Service 'my-web-server' stopped.\n\n    In [4]: u = Unit(name='temp-ls', exec_start='ls -l /tmp', manage_as_user=True)\n\n    In [5]: add_unit(u)\n    Unit 'temp-ls' added to manager.\n\n    In [6]: start('temp-ls')\n    Starting 'temp-ls'...\n    # Output...\n    Service 'temp-ls' started.\n    ```\n\n*(Note: While the interactive shell is the primary focus of `sysinit-term`, you could extend `sysinit/term.py` to include direct, non-interactive commands like `sysinit-term start \u003cservice\u003e` if desired.)*\n\n\n# 🚀 Usage\n\n### 1. Define Services (config.yaml)\nCreate a YAML file (e.g., config.yaml) to define your services. Specify whether each service should be managed at the system level or user level.\n\n```yaml\nservices:\n  # Example 1: A system-wide service (requires sudo)\n  - my-web-server:\n      unit_config:\n        name: my-web-server              # Base name for service file (my-web-server.service)\n        description: My Sample Web Server\n        exec_start: \"/usr/bin/python -m http.server 8000\" # Command to start\n        working_directory: \"/opt/my-web-app\"     # Optional: Directory to run in\n        user: \"www-data\"                  # Optional: Run as specific user\n        Type: \"simple\"                    # Systemd service type\n        Restart: \"on-failure\"             # Optional: Restart policy\n        # WantedBy: \"multi-user.target\"   # Default for system services\n      command_config:\n        dry_run: false                    # Set to true to just print commands\n        verbose: true                     # More detailed logging\n        manage_as_user: false             # Explicitly system mode (default)\n        enable_service: true              # Attempt to enable on first start\n\n  # Example 2: A user-specific service (sudo-free)\n  - my-dev-tool:\n      unit_config:\n        name: my-dev-tool                 # my-dev-tool.service\n        description: My Development Helper Tool\n        exec_start: \"/home/user/scripts/my_dev_tool.py\" # MUST be accessible by the user\n        working_directory: \"/home/user/dev/my-tool\"\n        Type: \"oneshot\"\n        RemainAfterExit: yes\n        # WantedBy: \"default.target\"       # Default for user services\n      command_config:\n        dry_run: false\n        verbose: true\n        manage_as_user: true              # CRITICAL: Run as systemd --user service\n        enable_service: true              # Enable for user login start\n\n  # Add more services as needed...\n```\n\n### 2. Initialize and Control via Python\n\n```py\nfrom sysinit.core.unit_manager import UnitManager\nimport logging\n\n# Configure logging level if needed (optional)\n# logging.basicConfig(level=logging.DEBUG)\n\n# Initialize the manager, loading services from the config\ntry:\n    manager = UnitManager(\"config.yaml\")\nexcept FileNotFoundError:\n    print(\"Error: config.yaml not found!\")\n    exit(1)\nexcept ValueError as e:\n    print(f\"Error loading config: {e}\")\n    exit(1)\n\n# --- Lifecycle Operations ---\n\n# Start all defined services (respects manage_as_user for each)\nprint(\"Starting all services...\")\nmanager.start_all()\n# Note: Starting system services will likely prompt for sudo password if not run as root\n\n# Start a specific service\nprint(\"\\nStarting my-dev-tool...\")\ntry:\n    manager.start_service(\"my-dev-tool\")\nexcept Exception as e:\n    print(f\"Error starting service: {e}\")\n\n# Stop a specific service\nprint(\"\\nStopping my-web-server...\")\ntry:\n    manager.stop_service(\"my-web-server\") # This will likely require sudo\nexcept Exception as e:\n    print(f\"Error stopping service: {e}\")\n\n# Check status of all services\nprint(\"\\nChecking status...\")\nmanager.status_all()\n\n# Restart a specific service\nprint(\"\\nRestarting my-dev-tool...\")\nmanager.restart_service(\"my-dev-tool\")\n\n# Disable a service (won't start on boot/login)\nprint(\"\\nDisabling my-web-server...\")\nmanager.disable_service(\"my-web-server\") # Requires sudo\n\n# Enable a service (will start on boot/login)\nprint(\"\\nEnabling my-web-server...\")\nmanager.enable_service(\"my-web-server\") # Requires sudo\n\n# Reload configuration for a service (rewrites .service file, reloads daemon)\n# Use after changing config in code or if the service file needs refreshing\nprint(\"\\nReloading my-dev-tool definition...\")\nmanager.reload_service(\"my-dev-tool\")\n\n# Stop all services\nprint(\"\\nStopping all services...\")\nmanager.stop_all()\n\n# Unload all service files (removes from systemd dirs)\nprint(\"\\nUnloading all services...\")\nmanager.unload_all() # Requires sudo for system services\n```\n\n---\n\n## ⚙️ Configuration (`config.yaml` Details)\n\nThe `config.yaml` file has a top-level `services` key, which is a list of service definitions. Each service definition is a dictionary with a single key being the **logical service name** used within `sysinit` (e.g., `my-web-server`). The value is another dictionary containing `unit_config` and `command_config`.\n\n### `unit_config`\n\nThese parameters map closely to systemd `.service` file options within the `[Unit]` and `[Service]` sections.\n\n*   `name`: (Required) The base name for the service (e.g., `my-app` results in `my-app.service`).\n*   `description`: (Optional) Service description (`Description=`).\n*   `exec_start`: (Required) The command to run to start the service (`ExecStart=`).\n*   `exec_stop`: (Optional) The command to run to stop the service (`ExecStop=`).\n*   `working_directory`: (Optional) The working directory for the service (`WorkingDirectory=`).\n*   `user`: (Optional) System user to run the service as (`User=`). Only effective in system mode.\n*   `group`: (Optional) System group to run the service as (`Group=`). Only effective in system mode.\n*   `Type`: (Optional) Service type (`simple`, `forking`, `oneshot`, etc.). Defaults to `oneshot`. (`Type=`).\n*   `Restart`: (Optional) Restart policy (`no`, `on-success`, `on-failure`, `always`, etc.) (`Restart=`).\n*   `RemainAfterExit`: (Optional, boolean) Useful for `oneshot` services. Defaults to `false`. (`RemainAfterExit=`).\n*   `Environment`: (Optional, dict) Environment variables (`Environment=\"KEY=value\"`).\n*   `After`: (Optional, string) Run after specified units (`After=`).\n*   `Requires`: (Optional, string) Depends on specified units (`Requires=`).\n*   `WantedBy`: (Optional) Install target. Defaults to `multi-user.target` (system) or `default.target` (user). (`WantedBy=`).\n*   `unit`: (Optional) Explicitly set the service filename (e.g., `my-custom-name.service`). Overrides `name`.\n\n### `command_config`\n\nThese parameters control how `sysinit` itself behaves when managing the unit.\n\n\n*   `dry_run`: (Optional, boolean) If `true`, print commands instead of executing them. Defaults to `false`.\n*   `verbose`: (Optional, boolean) Enable more detailed logging output. Defaults to `false`.\n*   `enable_service`: (Optional, boolean) If `true`, `sysinit` will attempt to `enable` the service during the first `start` operation if it's not already enabled. Defaults to `false`.\n\n---","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Ffoo290%2Fsysinit","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Ffoo290%2Fsysinit","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Ffoo290%2Fsysinit/lists"}