sal/zinit_client
Mahmoud-Emad e125bb6511
Some checks failed
Rhai Tests / Run Rhai Tests (push) Has been cancelled
Rhai Tests / Run Rhai Tests (pull_request) Has been cancelled
feat: Migrate SAL to Cargo workspace
- Migrate individual modules to independent crates
- Refactor dependencies for improved modularity
- Update build system and testing infrastructure
- Update documentation to reflect new structure
2025-06-24 12:39:18 +03:00
..
src feat: Add zinit_client package to workspace 2025-06-22 10:59:19 +03:00
tests feat: Migrate SAL to Cargo workspace 2025-06-24 12:39:18 +03:00
Cargo.toml feat: Add zinit_client package to workspace 2025-06-22 10:59:19 +03:00
README.md feat: Add zinit_client package to workspace 2025-06-22 10:59:19 +03:00

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