Skip to content

Commit fea919e

Browse files
committed
Merge branch 'development_dual_protocols' into development
2 parents f0fcd73 + d10d37a commit fea919e

File tree

1 file changed

+36
-256
lines changed

1 file changed

+36
-256
lines changed

README.md

Lines changed: 36 additions & 256 deletions
Original file line numberDiff line numberDiff line change
@@ -1,42 +1,21 @@
1-
# Universal Zinit Client
1+
# Zinit Client
22

3-
[![Rust CI](https://github.com/threefoldtech/zinit-client/actions/workflows/ci.yml/badge.svg)](https://github.com/threefoldtech/zinit-client/actions/workflows/ci.yml)
4-
[![Rust Examples](https://github.com/threefoldtech/zinit-client/actions/workflows/examples.yml/badge.svg)](https://github.com/threefoldtech/zinit-client/actions/workflows/examples.yml)
5-
[![Code Coverage](https://codecov.io/gh/threefoldtech/zinit-client/branch/development/graph/badge.svg)](https://codecov.io/gh/threefoldtech/zinit-client)
6-
[![Security Scan](https://github.com/threefoldtech/zinit-client/actions/workflows/security.yml/badge.svg)](https://github.com/threefoldtech/zinit-client/actions/workflows/security.yml)
3+
[![Crates.io](https://img.shields.io/crates/v/zinit-client.svg)](https://crates.io/crates/zinit-client)
4+
[![Documentation](https://docs.rs/zinit-client/badge.svg)](https://docs.rs/zinit-client)
5+
[![License: MIT](https://img.shields.io/badge/License-MIT-yellow.svg)](https://opensource.org/licenses/MIT)
76

8-
A universal Rust client library for interacting with the [Zinit](https://github.com/threefoldtech/zinit) service manager that works seamlessly with both old and new server versions.
7+
A Rust client library for the [Zinit](https://github.com/threefoldtech/zinit) service manager.
98

10-
## 🌟 Universal Compatibility
11-
12-
This client automatically detects and adapts to different Zinit server versions:
13-
14-
- **Old Servers (v0.2.14)**: Uses raw command protocol with graceful feature degradation
15-
- **New Servers (v0.2.25+)**: Uses JSON-RPC protocol with full feature support
16-
- **Automatic Detection**: No configuration needed - the client detects the server type automatically
17-
- **Consistent API**: Same client code works with both server versions
9+
**Universal Compatibility**: Automatically works with both old (v0.2.14) and new (v0.2.25+) Zinit servers through automatic protocol detection.
1810

1911
## Features
2012

21-
### Universal Interface
22-
23-
- **Automatic Protocol Detection**: Seamlessly switches between JSON-RPC and raw commands
24-
- **Feature Awareness**: Knows what each server version supports
25-
- **Graceful Degradation**: Helpful error messages for unsupported features
26-
- **Backward Compatibility**: Full support for legacy zinit installations
27-
28-
### Complete Service Management
29-
30-
- Complete API coverage for all Zinit operations
31-
- Service lifecycle management (create, start, stop, restart, monitor, forget, delete)
32-
- Real-time service status monitoring with PID tracking
33-
- Signal management (SIGTERM, SIGKILL, etc.)
34-
- Robust error handling with custom error types
35-
- Automatic reconnection on socket errors
36-
- Retry mechanisms for transient failures
37-
- Async/await support using Tokio
38-
- Strongly typed service states and responses
39-
- Efficient log streaming with filtering
13+
- **Zero Configuration**: Automatically detects server version and protocol
14+
- **Complete API**: All Zinit operations (list, start, stop, create, delete, etc.)
15+
- **Async/Await**: Built on Tokio for high performance
16+
- **Type Safe**: Strongly typed service states and responses
17+
- **Error Handling**: Comprehensive error types with helpful messages
18+
- **Backward Compatible**: Works with legacy Zinit installations
4019

4120
## Installation
4221

@@ -49,260 +28,61 @@ zinit-client = "0.4.0"
4928

5029
## Quick Start
5130

52-
The universal client automatically detects your zinit server version and adapts accordingly:
53-
5431
```rust
5532
use zinit_client::ZinitClient;
5633

5734
#[tokio::main]
5835
async fn main() -> Result<(), Box<dyn std::error::Error>> {
59-
// Works with both old and new zinit servers
6036
let client = ZinitClient::new("/var/run/zinit.sock");
6137

62-
// List services (works on all server versions)
63-
let services = client.list().await?;
64-
println!("Found {} services", services.len());
65-
66-
// Create service (automatically detects if supported)
67-
match client.create_service("my-service", serde_json::json!({
68-
"exec": "echo 'Hello World'",
69-
"oneshot": true
70-
})).await {
71-
Ok(_) => println!("Service created successfully"),
72-
Err(e) if e.to_string().contains("not supported") => {
73-
println!("Dynamic service creation not supported on this server");
74-
println!("Please create /etc/zinit/my-service.yaml manually");
75-
}
76-
Err(e) => return Err(e.into()),
77-
}
78-
79-
Ok(())
80-
}
81-
```
82-
83-
## Demo
84-
85-
Run the comprehensive demo to see the universal interface in action:
86-
87-
```bash
88-
# Test with new server (JSON-RPC)
89-
cargo run --example universal_client_demo /tmp/zinit.sock
90-
91-
# Test with old server (Raw Commands)
92-
cargo run --example universal_client_demo /run/zinit.sock
93-
```
94-
95-
## Building
96-
97-
To build the library, you need Rust and Cargo installed. Then run:
98-
99-
```bash
100-
# Build the library
101-
cargo build
102-
103-
# Build with optimizations
104-
cargo build --release
105-
106-
# Build the examples
107-
cargo build --examples
108-
```
109-
110-
## Usage
111-
112-
```rust
113-
use zinit_client::{ZinitClient, Result};
114-
115-
#[tokio::main]
116-
async fn main() -> Result<()> {
117-
// Create a client with default configuration
118-
let client = ZinitClient::new("/var/run/zinit.sock");
119-
12038
// List all services
12139
let services = client.list().await?;
12240
println!("Services: {:?}", services);
123-
124-
// Start a service
125-
client.start("nginx").await?;
126-
127-
// Get service status
128-
let status = client.status("nginx").await?;
129-
println!("Nginx status: {:?}", status);
130-
131-
// Stream logs
132-
let mut logs = client.logs(true, Some("nginx")).await?;
133-
while let Some(log) = logs.next().await {
134-
println!("{}: {}", log?.timestamp, log?.message);
135-
}
136-
137-
Ok(())
138-
}
139-
```
140-
141-
### Service CRUD Operations
142-
143-
The client supports creating, reading, updating, and deleting service configurations:
144-
145-
```rust
146-
use serde_json::json;
147-
use zinit_client::{ZinitClient, Result};
148-
149-
#[tokio::main]
150-
async fn main() -> Result<()> {
151-
let client = ZinitClient::new("/var/run/zinit.sock");
152-
153-
// Create a new service
154-
let service_config = json!({
155-
"exec": "/usr/bin/my-app",
156-
"args": ["--port", "8080"],
157-
"env": {
158-
"PORT": "8080",
159-
"ENV": "production"
160-
},
161-
"oneshot": false,
162-
"working_dir": "/opt/my-app"
163-
});
16441

165-
client.create_service("my-app", service_config).await?;
166-
167-
// Get service configuration
168-
let config = client.get_service("my-app").await?;
169-
println!("Service config: {}", serde_json::to_string_pretty(&config)?);
42+
// Start a service
43+
client.start("my-service").await?;
17044

171-
// Delete a service (stops it first if running)
172-
client.delete_service("my-app").await?;
45+
// Get service status
46+
let status = client.status("my-service").await?;
47+
println!("Status: {:?}", status);
17348

17449
Ok(())
17550
}
17651
```
17752

178-
## Configuration
53+
## API Overview
17954

180-
You can customize the client behavior using `ClientConfig`:
55+
### Service Management
18156

18257
```rust
183-
use zinit_client::{ZinitClient, ClientConfig};
184-
use std::time::Duration;
185-
186-
let config = ClientConfig {
187-
socket_path: "/var/run/zinit.sock".into(),
188-
connection_timeout: Duration::from_secs(5),
189-
operation_timeout: Duration::from_secs(30),
190-
max_retries: 3,
191-
retry_delay: Duration::from_millis(100),
192-
max_retry_delay: Duration::from_secs(5),
193-
retry_jitter: true,
194-
};
195-
196-
let client = ZinitClient::with_config(config);
197-
```
198-
199-
## Examples
58+
// List all services
59+
let services = client.list().await?;
20060

201-
See the [examples](./examples) directory for more usage examples:
61+
// Service lifecycle
62+
client.start("service-name").await?;
63+
client.stop("service-name").await?;
64+
client.restart("service-name").await?;
20265

203-
### Running Examples
204-
205-
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`).
206-
207-
```bash
208-
# Basic usage example (requires Zinit)
209-
cargo run --example basic_usage
210-
211-
# Comprehensive service management with CRUD operations (interactive, requires Zinit)
212-
cargo run --example service_management
213-
214-
# Log streaming example (interactive, requires Zinit)
215-
cargo run --example log_streaming
216-
217-
# Mock server demo (doesn't require Zinit)
218-
cargo run --example mock_server_demo
219-
```
220-
221-
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:
222-
223-
```rust
224-
// Change this line
225-
let client = ZinitClient::new("/var/run/zinit.sock");
66+
// Get detailed status
67+
let status = client.status("service-name").await?;
22668

227-
// To use a custom socket path
228-
let client = ZinitClient::new("/path/to/your/zinit.sock");
69+
// Create/delete services (if supported by server)
70+
client.create_service("name", config).await?;
71+
client.delete_service("name").await?;
22972
```
23073

231-
### Running Without Zinit
232-
233-
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.
234-
235-
Here's how to use it:
236-
237-
```rust
238-
use std::path::PathBuf;
239-
use tempfile::tempdir;
240-
use zinit_client::ZinitClient;
241-
use zinit_client::tests::MockZinitServer;
242-
243-
#[tokio::main]
244-
async fn main() -> Result<()> {
245-
// Create a temporary directory for the socket
246-
let temp_dir = tempdir().expect("Failed to create temp dir");
247-
let socket_path = temp_dir.path().join("mock-zinit.sock");
248-
249-
// Create and start the mock server
250-
let mut server = MockZinitServer::new(&socket_path).await;
251-
server.start().await.expect("Failed to start mock server");
252-
253-
// Add some mock services
254-
server.add_service(MockService {
255-
name: "test-service".to_string(),
256-
pid: 1001,
257-
state: MockServiceState::Running,
258-
target: MockServiceTarget::Up,
259-
after: HashMap::new(),
260-
});
261-
262-
// Create a client to connect to the mock server
263-
let client = ZinitClient::new(&socket_path);
264-
265-
// Use the client as normal
266-
let services = client.list().await?;
267-
println!("Services: {:?}", services);
268-
269-
// Stop the mock server when done
270-
server.stop().await;
271-
272-
Ok(())
273-
}
274-
```
275-
276-
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.
277-
278-
## Testing
279-
280-
The library includes both integration tests and a mock server for testing without requiring a real Zinit instance.
74+
## Examples
28175

282-
### Running Tests
76+
Run the demo to see the universal interface in action:
28377

28478
```bash
285-
# Run all tests
286-
cargo test
287-
288-
# Run a specific test
289-
cargo test test_client_reconnection
79+
cargo run --example <example_name> <sock_path>
29080
```
29181

292-
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.
293-
294-
## CI/CD
295-
296-
This project uses GitHub Actions for continuous integration and delivery:
297-
298-
- **Rust CI**: Builds the project, runs tests, and checks code formatting and linting
299-
- **Rust Examples**: Builds and runs all examples to ensure they work correctly
300-
- **Code Coverage**: Generates code coverage reports and uploads them to Codecov
301-
- **Security Scan**: Performs security audits on dependencies using cargo-audit and cargo-deny
302-
- **Publish**: Automatically publishes the crate to crates.io when a new release is created
82+
## Documentation
30383

304-
All workflows run on every push to any branch and on all pull requests.
84+
For detailed API documentation, visit [docs.rs/zinit-client](https://docs.rs/zinit-client).
30585

30686
## License
30787

308-
See [LICENSE](LICENSE) file for details.
88+
This project is licensed under the MIT License - see the [LICENSE](LICENSE) file for details.

0 commit comments

Comments
 (0)