Skip to content

threefoldtech/zinit-client-rs

Folders and files

NameName
Last commit message
Last commit date

Latest commit

 

History

12 Commits
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 

Repository files navigation

Zinit Client

Rust CI Rust Examples Code Coverage Security Scan

A Rust client library for interacting with the Zinit service manager.

Features

  • Complete API coverage for all Zinit operations
  • Robust error handling with custom error types
  • Automatic reconnection on socket errors
  • Retry mechanisms for transient failures
  • Async/await support using Tokio
  • Strongly typed service states and responses
  • Efficient log streaming

Installation

Add this to your Cargo.toml:

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

Building

To build the library, you need Rust and Cargo installed. Then run:

# Build the library
cargo build

# Build with optimizations
cargo build --release

# Build the examples
cargo build --examples

Usage

use zinit_client_rs::{ZinitClient, Result};

#[tokio::main]
async fn main() -> Result<()> {
    // Create a client with default configuration
    let client = ZinitClient::new("/var/run/zinit.sock");
    
    // List all services
    let services = client.list().await?;
    println!("Services: {:?}", services);
    
    // Start a service
    client.start("nginx").await?;
    
    // Get service status
    let status = client.status("nginx").await?;
    println!("Nginx status: {:?}", status);
    
    // Stream logs
    let mut logs = client.logs(true, Some("nginx")).await?;
    while let Some(log) = logs.next().await {
        println!("{}: {}", log?.timestamp, log?.message);
    }
    
    Ok(())
}

Configuration

You can customize the client behavior using ClientConfig:

use zinit_client_rs::{ZinitClient, ClientConfig};
use std::time::Duration;

let config = ClientConfig {
    socket_path: "/var/run/zinit.sock".into(),
    connection_timeout: Duration::from_secs(5),
    operation_timeout: Duration::from_secs(30),
    max_retries: 3,
    retry_delay: Duration::from_millis(100),
    max_retry_delay: Duration::from_secs(5),
    retry_jitter: true,
};

let client = ZinitClient::with_config(config);

Examples

See the examples directory for more usage examples:

Running Examples

To run the examples, you need a running Zinit instance. The examples will try to connect to Zinit at the default socket path (/var/run/zinit.sock).

# Basic usage example (requires Zinit)
cargo run --example basic_usage

# Service management example (interactive, requires Zinit)
cargo run --example service_management

# Log streaming example (interactive, requires Zinit)
cargo run --example log_streaming

# Mock server demo (doesn't require Zinit)
cargo run --example mock_server_demo

If you want to use a different socket path, you'll need to modify the examples. Open the example file and change the socket path in the ZinitClient::new() call:

// Change this line
let client = ZinitClient::new("/var/run/zinit.sock");

// To use a custom socket path
let client = ZinitClient::new("/path/to/your/zinit.sock");

Running Without Zinit

If you don't have Zinit running, you can still test the client by using the mock server provided in the tests directory. The mock server simulates a Zinit instance for testing purposes.

Here's how to use it:

use std::path::PathBuf;
use tempfile::tempdir;
use zinit_client_rs::ZinitClient;
use zinit_client_rs::tests::MockZinitServer;

#[tokio::main]
async fn main() -> Result<()> {
    // Create a temporary directory for the socket
    let temp_dir = tempdir().expect("Failed to create temp dir");
    let socket_path = temp_dir.path().join("mock-zinit.sock");
    
    // Create and start the mock server
    let mut server = MockZinitServer::new(&socket_path).await;
    server.start().await.expect("Failed to start mock server");
    
    // Add some mock services
    server.add_service(MockService {
        name: "test-service".to_string(),
        pid: 1001,
        state: MockServiceState::Running,
        target: MockServiceTarget::Up,
        after: HashMap::new(),
    });
    
    // Create a client to connect to the mock server
    let client = ZinitClient::new(&socket_path);
    
    // Use the client as normal
    let services = client.list().await?;
    println!("Services: {:?}", services);
    
    // Stop the mock server when done
    server.stop().await;
    
    Ok(())
}

Note: The examples assume Zinit is running and listening on the default socket path (/var/run/zinit.sock). If your Zinit instance is using a different socket path, you'll need to modify the examples accordingly.

Testing

The library includes both integration tests and a mock server for testing without requiring a real Zinit instance.

Running Tests

# Run all tests
cargo test

# Run a specific test
cargo test test_client_reconnection

All tests use the mock server, so they can be run without requiring a real Zinit instance. The mock server simulates a Zinit instance for testing purposes, allowing for reliable and reproducible tests.

CI/CD

This project uses GitHub Actions for continuous integration and delivery:

  • Rust CI: Builds the project, runs tests, and checks code formatting and linting
  • Rust Examples: Builds and runs all examples to ensure they work correctly
  • Code Coverage: Generates code coverage reports and uploads them to Codecov
  • Security Scan: Performs security audits on dependencies using cargo-audit and cargo-deny
  • Publish: Automatically publishes the crate to crates.io when a new release is created

All workflows run on every push to any branch and on all pull requests.

License

See LICENSE file for details.

Releases

No releases published

Packages

No packages published

Languages