164 lines
7.5 KiB
Markdown
164 lines
7.5 KiB
Markdown
# SAL Zinit Client Module (`sal::zinit_client`)
|
|
|
|
## Overview
|
|
|
|
The `sal::zinit_client` module provides a Rust interface for interacting with a [Zinit](https://github.com/systeminit/zinit) process supervisor daemon. Zinit is a process and service manager for Linux systems, designed for simplicity and robustness.
|
|
|
|
This SAL module allows Rust applications and `herodo` Rhai scripts to:
|
|
- List and manage Zinit services (get status, start, stop, restart, monitor, forget, kill).
|
|
- Define and manage service configurations (create, delete, get).
|
|
- Retrieve logs from Zinit.
|
|
|
|
The client communicates with the Zinit daemon over a Unix domain socket. All operations are performed asynchronously.
|
|
|
|
## Key Design Points
|
|
|
|
- **Async Operations**: Leverages `tokio` for asynchronous communication with the Zinit daemon, ensuring non-blocking calls suitable for concurrent applications.
|
|
- **Unix Socket Communication**: Connects to the Zinit daemon via a specified Unix domain socket path (e.g., `/var/run/zinit.sock`).
|
|
- **Global Client Instance**: Manages a global, lazily-initialized `Arc<ZinitClientWrapper>` to reuse the Zinit client connection across multiple calls within the same process, improving efficiency.
|
|
- **Comprehensive Service Management**: Exposes a wide range of Zinit's service management capabilities, from basic lifecycle control to service definition and log retrieval.
|
|
- **Rhai Scriptability**: A significant portion of the Zinit client's functionality is exposed to Rhai scripts via `herodo` through the `sal::rhai::zinit` bridge, enabling automation of service management tasks.
|
|
- **Error Handling**: Converts errors from the underlying `zinit_client` crate into `zinit_client::ClientError`, which are then translated to `EvalAltResult` for Rhai, providing clear feedback.
|
|
- **Simplified Rhai Interface**: For some operations like service creation, the Rhai interface offers a simplified parameter set compared to the direct Rust API for ease of use in scripts.
|
|
|
|
## Rhai Scripting with `herodo`
|
|
|
|
The `sal::zinit_client` module is scriptable via `herodo`. The following functions are available in Rhai, prefixed with `zinit_`. All functions require `socket_path` (String) as their first argument, specifying the path to the Zinit Unix domain socket.
|
|
|
|
- `zinit_list(socket_path: String) -> Map`
|
|
- Lists all services managed by Zinit and their states.
|
|
- Returns a map where keys are service names and values are their current states (e.g., "Running", "Stopped").
|
|
|
|
- `zinit_status(socket_path: String, name: String) -> Map`
|
|
- Retrieves the detailed status of a specific service.
|
|
- `name`: The name of the service.
|
|
- Returns a map containing status details like PID, state, target state, and dependencies.
|
|
|
|
- `zinit_start(socket_path: String, name: String) -> bool`
|
|
- Starts the specified service.
|
|
- Returns `true` on success.
|
|
|
|
- `zinit_stop(socket_path: String, name: String) -> bool`
|
|
- Stops the specified service.
|
|
- Returns `true` on success.
|
|
|
|
- `zinit_restart(socket_path: String, name: String) -> bool`
|
|
- Restarts the specified service.
|
|
- Returns `true` on success.
|
|
|
|
- `zinit_monitor(socket_path: String, name: String) -> bool`
|
|
- Enables monitoring for the specified service (Zinit will attempt to keep it running).
|
|
- Returns `true` on success.
|
|
|
|
- `zinit_forget(socket_path: String, name: String) -> bool`
|
|
- Disables monitoring for the specified service (Zinit will no longer attempt to restart it if it stops).
|
|
- Returns `true` on success.
|
|
|
|
- `zinit_kill(socket_path: String, name: String, signal: String) -> bool`
|
|
- Sends a specific signal (e.g., "TERM", "KILL", "HUP") to the specified service.
|
|
- Returns `true` on success.
|
|
|
|
- `zinit_create_service(socket_path: String, name: String, exec: String, oneshot: bool) -> String`
|
|
- Creates a new service configuration in Zinit.
|
|
- `name`: The name for the new service.
|
|
- `exec`: The command to execute for the service.
|
|
- `oneshot`: A boolean indicating if the service is a one-shot task (true) or a long-running process (false).
|
|
- Returns a confirmation message or an error.
|
|
|
|
- `zinit_delete_service(socket_path: String, name: String) -> String`
|
|
- Deletes the specified service configuration from Zinit.
|
|
- Returns a confirmation message or an error.
|
|
|
|
- `zinit_get_service(socket_path: String, name: String) -> Dynamic`
|
|
- Retrieves the configuration of the specified service as a dynamic map.
|
|
|
|
- `zinit_logs(socket_path: String, filter: String) -> Array`
|
|
- Retrieves logs for a specific service or component matching the filter.
|
|
- `filter`: The name of the service/component to get logs for.
|
|
- Returns an array of log lines.
|
|
|
|
- `zinit_logs_all(socket_path: String) -> Array`
|
|
- Retrieves all available logs from Zinit.
|
|
- Returns an array of log lines.
|
|
|
|
### Rhai Example
|
|
|
|
```rhai
|
|
// Default Zinit socket path
|
|
let zinit_socket = "/var/run/zinit.sock";
|
|
|
|
// Ensure Zinit is running and socket exists before running this script.
|
|
|
|
// List all services
|
|
print("Listing Zinit services...");
|
|
let services = zinit_list(zinit_socket);
|
|
if services.is_ok() {
|
|
print(`Services: ${services}`);
|
|
} else {
|
|
print(`Error listing services: ${services}`);
|
|
// exit(); // Or handle error appropriately
|
|
}
|
|
|
|
// Define a test service
|
|
let service_name = "my_test_app";
|
|
let service_exec = "/usr/bin/sleep 300"; // Example command
|
|
|
|
// Try to get service info first, to see if it exists
|
|
let existing_service = zinit_get_service(zinit_socket, service_name);
|
|
if !existing_service.is_ok() { // Assuming error means it doesn't exist or can't be fetched
|
|
print(`\nService '${service_name}' not found or error. Attempting to create...`);
|
|
let create_result = zinit_create_service(zinit_socket, service_name, service_exec, false);
|
|
if create_result.is_ok() {
|
|
print(`Service '${service_name}' created successfully.`);
|
|
} else {
|
|
print(`Error creating service '${service_name}': ${create_result}`);
|
|
// exit();
|
|
}
|
|
} else {
|
|
print(`\nService '${service_name}' already exists: ${existing_service}`);
|
|
}
|
|
|
|
// Get status of the service
|
|
print(`\nFetching status for '${service_name}'...`);
|
|
let status = zinit_status(zinit_socket, service_name);
|
|
if status.is_ok() {
|
|
print(`Status for '${service_name}': ${status}`);
|
|
// Example: Start if not running (simplified check)
|
|
if status.state != "Running" && status.state != "Starting" {
|
|
print(`Attempting to start '${service_name}'...`);
|
|
zinit_start(zinit_socket, service_name);
|
|
}
|
|
} else {
|
|
print(`Error fetching status for '${service_name}': ${status}`);
|
|
}
|
|
|
|
// Get some logs for the service (if it produced any)
|
|
// Note: Logs might be empty if service just started or hasn't output anything.
|
|
print(`\nFetching logs for '${service_name}'...`);
|
|
let logs = zinit_logs(zinit_socket, service_name);
|
|
if logs.is_ok() {
|
|
if logs.len() > 0 {
|
|
print(`Logs for '${service_name}':`);
|
|
for log_line in logs {
|
|
print(` ${log_line}`);
|
|
}
|
|
} else {
|
|
print(`No logs found for '${service_name}'.`);
|
|
}
|
|
} else {
|
|
print(`Error fetching logs for '${service_name}': ${logs}`);
|
|
}
|
|
|
|
// Example: Stop and delete the service (cleanup)
|
|
// print(`\nStopping service '${service_name}'...`);
|
|
// zinit_stop(zinit_socket, service_name);
|
|
// print(`Forgetting service '${service_name}'...`);
|
|
// zinit_forget(zinit_socket, service_name); // Stop monitoring before delete
|
|
// print(`Deleting service '${service_name}'...`);
|
|
// zinit_delete_service(zinit_socket, service_name);
|
|
|
|
print("\nZinit Rhai script finished.");
|
|
```
|
|
|
|
This module provides a powerful way to automate service management and interaction with Zinit-supervised systems directly from Rust or `herodo` scripts.
|