Skip to content
This repository was archived by the owner on Dec 15, 2025. It is now read-only.

Commit 8a6acfd

Browse files
committed
created zinit client library
1 parent c86e96a commit 8a6acfd

File tree

8 files changed

+1656
-31
lines changed

8 files changed

+1656
-31
lines changed

Cargo.lock

Lines changed: 882 additions & 31 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

Cargo.toml

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,9 @@
1+
[workspace]
2+
members = [
3+
".",
4+
"zinit-client"
5+
]
6+
17
[package]
28
name = "zinit"
39
version = "0.2.0"

zinit-client/Cargo.toml

Lines changed: 25 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,25 @@
1+
[package]
2+
name = "zinit-client"
3+
version = "0.1.0"
4+
edition = "2021"
5+
description = "A client library for interacting with Zinit process manager"
6+
license = "MIT"
7+
authors = ["ThreeFold Tech, https://github.com/threefoldtech"]
8+
9+
[dependencies]
10+
anyhow = "1.0"
11+
tokio = { version = "1.14.0", features = ["full"] }
12+
serde = { version = "1.0", features = ["derive"] }
13+
serde_json = "1.0"
14+
reqwest = { version = "0.11", features = ["json"] }
15+
thiserror = "1.0"
16+
log = "0.4"
17+
18+
[[example]]
19+
name = "basic_usage"
20+
path = "examples/basic_usage.rs"
21+
22+
[[example]]
23+
name = "http_client"
24+
path = "examples/http_client.rs"
25+
log = "0.4"

zinit-client/README.md

Lines changed: 123 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,123 @@
1+
# Zinit Client Library
2+
3+
A simple Rust client library for interacting with the Zinit process manager.
4+
5+
## Features
6+
7+
- Connect to Zinit via Unix socket or HTTP
8+
- Manage services (start, stop, restart, monitor)
9+
- Query service status and information
10+
- Create and delete service configurations
11+
- System operations (shutdown, reboot)
12+
13+
## Installation
14+
15+
Add this to your `Cargo.toml`:
16+
17+
```toml
18+
[dependencies]
19+
zinit-client = "0.1.0"
20+
```
21+
22+
## Usage
23+
24+
### Creating a Client
25+
26+
You can create a client using either Unix socket or HTTP transport:
27+
28+
```rust
29+
use zinit_client::Client;
30+
31+
// Using Unix socket (local only)
32+
let client = Client::unix_socket("/var/run/zinit.sock");
33+
34+
// Using HTTP (works for remote Zinit instances)
35+
let client = Client::http("http://localhost:8080");
36+
```
37+
38+
### Service Management
39+
40+
```rust
41+
// List all services
42+
let services = client.list().await?;
43+
for (name, state) in services {
44+
println!("{}: {}", name, state);
45+
}
46+
47+
// Get status of a specific service
48+
let status = client.status("my-service").await?;
49+
println!("PID: {}, State: {}", status.pid, status.state);
50+
51+
// Start a service
52+
client.start("my-service").await?;
53+
54+
// Stop a service
55+
client.stop("my-service").await?;
56+
57+
// Restart a service
58+
client.restart("my-service").await?;
59+
60+
// Monitor a service
61+
client.monitor("my-service").await?;
62+
63+
// Forget a service
64+
client.forget("my-service").await?;
65+
66+
// Send a signal to a service
67+
client.kill("my-service", "SIGTERM").await?;
68+
```
69+
70+
### Service Configuration
71+
72+
```rust
73+
use serde_json::json;
74+
75+
// Create a new service
76+
let config = json!({
77+
"exec": "nginx",
78+
"oneshot": false,
79+
"after": ["network"]
80+
}).as_object().unwrap().clone();
81+
82+
client.create_service("nginx", config).await?;
83+
84+
// Get service configuration
85+
let config = client.get_service("nginx").await?;
86+
println!("Config: {:?}", config);
87+
88+
// Delete a service
89+
client.delete_service("nginx").await?;
90+
```
91+
92+
### System Operations
93+
94+
```rust
95+
// Shutdown the system
96+
client.shutdown().await?;
97+
98+
// Reboot the system
99+
client.reboot().await?;
100+
```
101+
102+
## Error Handling
103+
104+
The library provides a `ClientError` enum for handling errors:
105+
106+
```rust
107+
match client.status("non-existent-service").await {
108+
Ok(status) => println!("Service status: {}", status.state),
109+
Err(e) => match e {
110+
ClientError::ServiceNotFound(_) => println!("Service not found"),
111+
ClientError::ConnectionError(_) => println!("Failed to connect to Zinit"),
112+
_ => println!("Other error: {}", e),
113+
},
114+
}
115+
```
116+
117+
## Examples
118+
119+
See the [examples](examples) directory for complete usage examples.
120+
121+
## License
122+
123+
This project is licensed under the MIT License.
Lines changed: 99 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,99 @@
1+
use anyhow::Result;
2+
use serde_json::json;
3+
use std::time::Duration;
4+
use tokio::time;
5+
use zinit_client::Client;
6+
7+
#[tokio::main]
8+
async fn main() -> Result<()> {
9+
// Create a client using Unix socket transport
10+
// let unix_client = Client::unix_socket("/var/run/zinit.sock");
11+
12+
// Or create a client using HTTP transport
13+
let http_client = Client::http("http://localhost:8080");
14+
15+
// Choose which client to use for this example
16+
let client = http_client;
17+
18+
// Service name for our example
19+
let service_name = "test123";
20+
21+
// Step 1: List existing services
22+
println!("Listing all services before creating our test service:");
23+
let services = client.list().await?;
24+
25+
// Print all services
26+
for (name, state) in &services {
27+
println!("- {}: {}", name, state);
28+
}
29+
30+
// Step 2: Create a new service
31+
println!("\n--- Creating service '{}' ---", service_name);
32+
33+
// Create the service configuration
34+
let service_config = json!({
35+
"exec": "echo 'test123 hello'",
36+
"oneshot": false,
37+
"log": "stdout"
38+
}).as_object().unwrap().clone();
39+
40+
// Create the service
41+
let result = client.create_service(service_name, service_config).await?;
42+
println!("Create result: {}", result);
43+
44+
// Step 3: Monitor the service
45+
println!("\n--- Monitoring service '{}' ---", service_name);
46+
client.monitor(service_name).await?;
47+
println!("Service is now being monitored");
48+
49+
// Wait a moment for the service to start
50+
println!("Waiting for service to start...");
51+
time::sleep(Duration::from_secs(2)).await;
52+
53+
// Step 4: Get the status of the service
54+
println!("\n--- Getting status for '{}' ---", service_name);
55+
let status = client.status(service_name).await?;
56+
println!("Name: {}", status.name);
57+
println!("PID: {}", status.pid);
58+
println!("State: {}", status.state);
59+
println!("Target: {}", status.target);
60+
println!("Dependencies:");
61+
for (dep, state) in &status.after {
62+
println!(" - {}: {}", dep, state);
63+
}
64+
65+
// Step 5: Stop the service
66+
println!("\n--- Stopping service '{}' ---", service_name);
67+
client.stop(service_name).await?;
68+
println!("Service stopped");
69+
70+
// Wait a moment for the service to stop
71+
time::sleep(Duration::from_secs(1)).await;
72+
73+
// Check status after stopping
74+
println!("\n--- Status after stopping ---");
75+
let status = client.status(service_name).await?;
76+
println!("State: {}", status.state);
77+
println!("Target: {}", status.target);
78+
79+
// Step 6: Delete the service
80+
println!("\n--- Deleting service '{}' ---", service_name);
81+
let delete_result = client.delete_service(service_name).await?;
82+
println!("Delete result: {}", delete_result);
83+
84+
// Step 7: Verify the service is gone
85+
println!("\n--- Listing services after deletion ---");
86+
let services_after = client.list().await?;
87+
for (name, state) in &services_after {
88+
println!("- {}: {}", name, state);
89+
}
90+
91+
// Check if our service was deleted
92+
if !services_after.contains_key(service_name) {
93+
println!("\nService '{}' was successfully deleted", service_name);
94+
} else {
95+
println!("\nWarning: Service '{}' still exists", service_name);
96+
}
97+
98+
Ok(())
99+
}
Lines changed: 45 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,45 @@
1+
use anyhow::Result;
2+
use zinit_client::Client;
3+
4+
#[tokio::main]
5+
async fn main() -> Result<()> {
6+
// Create a client using HTTP transport
7+
let client = Client::http("http://localhost:8080");
8+
9+
println!("Connecting to Zinit via HTTP...");
10+
11+
// List all services
12+
println!("Listing all services:");
13+
match client.list().await {
14+
Ok(services) => {
15+
if services.is_empty() {
16+
println!("No services found.");
17+
} else {
18+
for (name, state) in &services {
19+
println!("- {}: {}", name, state);
20+
}
21+
22+
// Try to get the first service for a status example
23+
if let Some(service_name) = services.keys().next() {
24+
println!("\nGetting status for {}:", service_name);
25+
match client.status(service_name).await {
26+
Ok(status) => {
27+
println!("Name: {}", status.name);
28+
println!("PID: {}", status.pid);
29+
println!("State: {}", status.state);
30+
println!("Target: {}", status.target);
31+
println!("Dependencies: {}", status.after.len());
32+
},
33+
Err(e) => println!("Error getting status: {}", e),
34+
}
35+
}
36+
}
37+
},
38+
Err(e) => {
39+
println!("Error connecting to Zinit HTTP proxy: {}", e);
40+
println!("Make sure the Zinit HTTP proxy is running on http://localhost:8080");
41+
}
42+
}
43+
44+
Ok(())
45+
}

0 commit comments

Comments
 (0)