sal/zinit_client/README.md
Mahmoud-Emad 511729c477
Some checks are pending
Rhai Tests / Run Rhai Tests (push) Waiting to run
feat: Add zinit_client package to workspace
- Add `zinit_client` package to the workspace, enabling its use
  in the SAL monorepo.  This allows for better organization and
  dependency management.
- Update `MONOREPO_CONVERSION_PLAN.md` to reflect the addition
  of `zinit_client` and its status.  This ensures the conversion
  plan stays up-to-date.
- Move `src/zinit_client/` directory to `zinit_client/` for better
   organization.  This improves the overall structure of the
   project.
- Update references to `zinit_client` to use the new path.  This
  ensures the codebase correctly links to the `zinit_client`
  package.
2025-06-22 10:59:19 +03:00

7.6 KiB

SAL Zinit Client (sal-zinit-client)

A Rust client library for interacting with Zinit, a process supervisor daemon for Linux systems. This package provides both a Rust API and Rhai scripting integration for comprehensive service management.

Features

  • Async Operations: Built on tokio for non-blocking communication
  • Unix Socket Communication: Connects to Zinit daemon via Unix domain sockets
  • Global Client Management: Efficient connection reuse with lazy initialization
  • Comprehensive Service Management: Full lifecycle control (start, stop, restart, monitor, etc.)
  • Service Configuration: Create, delete, and retrieve service configurations
  • Real-time Log Streaming: Retrieve logs with filtering support
  • Rhai Integration: Complete scripting support for automation
  • Production Ready: Real-world tested with comprehensive error handling

Installation

Add this to your Cargo.toml:

[dependencies]
sal-zinit-client = "0.1.0"

Quick Start

Rust API

use sal_zinit_client::{list, status, create_service, start, stop};

#[tokio::main]
async fn main() -> Result<(), Box<dyn std::error::Error>> {
    let socket_path = "/var/run/zinit.sock";
    
    // List all services
    let services = list(socket_path).await?;
    println!("Services: {:?}", services);
    
    // Create a new service
    create_service(socket_path, "my-service", "echo 'Hello World'", true).await?;
    
    // Start the service
    start(socket_path, "my-service").await?;
    
    // Get service status
    let service_status = status(socket_path, "my-service").await?;
    println!("Status: {:?}", service_status);
    
    Ok(())
}

Rhai Scripting

// Zinit socket path
let socket_path = "/var/run/zinit.sock";

// List all services
let services = zinit_list(socket_path);
print(`Found ${services.len()} services`);

// Create and manage a service
let service_name = "rhai-test-service";
let exec_command = "echo 'Hello from Rhai'";

// Create service
zinit_create_service(socket_path, service_name, exec_command, true);

// Monitor and start
zinit_monitor(socket_path, service_name);
zinit_start(socket_path, service_name);

// Get status
let status = zinit_status(socket_path, service_name);
print(`Service state: ${status.state}`);

// Clean up
zinit_stop(socket_path, service_name);
zinit_forget(socket_path, service_name);
zinit_delete_service(socket_path, service_name);

API Reference

Core Functions

Service Management

  • list(socket_path) - List all services and their states
  • status(socket_path, name) - Get detailed status of a specific service
  • start(socket_path, name) - Start a service
  • stop(socket_path, name) - Stop a service
  • restart(socket_path, name) - Restart a service
  • monitor(socket_path, name) - Start monitoring a service
  • forget(socket_path, name) - Stop monitoring a service
  • kill(socket_path, name, signal) - Send a signal to a service

Service Configuration

  • create_service(socket_path, name, exec, oneshot) - Create a simple service
  • create_service_full(socket_path, name, exec, oneshot, after, env, log, test) - Create service with full options
  • delete_service(socket_path, name) - Delete a service
  • get_service(socket_path, name) - Get service configuration

Logs

  • logs(socket_path, filter) - Get logs with optional filtering
  • logs(socket_path, None) - Get all logs

Rhai Functions

All Rust functions are available in Rhai with zinit_ prefix:

  • zinit_list(socket_path) → Map
  • zinit_status(socket_path, name) → Map
  • zinit_start(socket_path, name) → bool
  • zinit_stop(socket_path, name) → bool
  • zinit_restart(socket_path, name) → bool
  • zinit_monitor(socket_path, name) → bool
  • zinit_forget(socket_path, name) → bool
  • zinit_kill(socket_path, name, signal) → bool
  • zinit_create_service(socket_path, name, exec, oneshot) → String
  • zinit_delete_service(socket_path, name) → String
  • zinit_get_service(socket_path, name) → Dynamic
  • zinit_logs(socket_path, filter) → Array
  • zinit_logs_all(socket_path) → Array

Configuration

Socket Paths

Common Zinit socket locations:

  • /var/run/zinit.sock (default system location)
  • /tmp/zinit.sock (temporary/testing)
  • /run/zinit.sock (alternative system location)

Environment Variables

The client respects standard environment configurations and handles connection failures gracefully.

Testing

The package includes comprehensive tests that work with real Zinit servers:

# Run all tests
cargo test

# Run only unit tests
cargo test --test zinit_client_tests

# Run only Rhai integration tests
cargo test --test rhai_integration_tests

Test Requirements

IMPORTANT: For full test coverage, you must start a Zinit server before running tests:

# Start Zinit for testing (recommended for development)
zinit -s /tmp/zinit.sock init

# Alternative: Start with system socket (requires sudo)
sudo zinit --socket /var/run/zinit.sock init

# Or use systemd (if available)
sudo systemctl start zinit

Without a running Zinit server:

  • Tests will gracefully skip when no socket is available
  • You'll see messages like "⚠ No Zinit socket found. Tests will be skipped."
  • This is expected behavior and not a test failure

With a running Zinit server:

  • Tests will connect to the server and perform real operations
  • Service creation, management, and deletion will be tested
  • Log retrieval and signal handling will be validated

Examples

Service Lifecycle Management

use sal_zinit_client::*;

async fn manage_web_server() -> Result<(), Box<dyn std::error::Error>> {
    let socket = "/var/run/zinit.sock";
    let service = "web-server";
    
    // Create web server service
    create_service(socket, service, "python3 -m http.server 8080", false).await?;
    
    // Start monitoring and run
    monitor(socket, service).await?;
    start(socket, service).await?;
    
    // Check if running
    let status = status(socket, service).await?;
    println!("Web server PID: {}", status.pid);
    
    // Graceful shutdown
    stop(socket, service).await?;
    forget(socket, service).await?;
    delete_service(socket, service).await?;
    
    Ok(())
}

Log Monitoring

use sal_zinit_client::logs;

async fn monitor_logs() -> Result<(), Box<dyn std::error::Error>> {
    let socket = "/var/run/zinit.sock";
    
    // Get all logs
    let all_logs = logs(socket, None).await?;
    println!("Total log entries: {}", all_logs.len());
    
    // Get filtered logs
    let error_logs = logs(socket, Some("error".to_string())).await?;
    println!("Error log entries: {}", error_logs.len());
    
    Ok(())
}

Error Handling

The client provides comprehensive error handling:

use sal_zinit_client::{list, ZinitError};

async fn handle_errors() {
    let socket = "/invalid/path/zinit.sock";
    
    match list(socket).await {
        Ok(services) => println!("Services: {:?}", services),
        Err(e) => {
            eprintln!("Zinit error: {}", e);
            // Handle specific error types
        }
    }
}

Integration with SAL

This package is part of the SAL (System Abstraction Layer) ecosystem:

use sal::zinit_client;

// Access through SAL
let services = sal::zinit_client::list("/var/run/zinit.sock").await?;

Contributing

This package follows SAL's strict quality standards:

  • Real functionality only (no placeholders or stubs)
  • Comprehensive test coverage with actual behavior validation
  • Production-ready error handling and logging
  • Security considerations for credential handling

License

Apache-2.0