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

Commit 407e730

Browse files
authored
Adds zini restart subcommand (#55)
* Adds zini restart subcommand Signed-off-by: Ashraf Fouda <ashraf.m.fouda@gmail.com> * improve implementation of zinit restart Signed-off-by: Ashraf Fouda <ashraf.m.fouda@gmail.com> * updating docs Signed-off-by: Ashraf Fouda <ashraf.m.fouda@gmail.com> * updates docs for zinit restart Signed-off-by: Ashraf Fouda <ashraf.m.fouda@gmail.com> --------- Signed-off-by: Ashraf Fouda <ashraf.m.fouda@gmail.com>
1 parent 116dcf3 commit 407e730

File tree

3 files changed

+66
-16
lines changed

3 files changed

+66
-16
lines changed

docs/readme.md

Lines changed: 34 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -1,9 +1,11 @@
11
# Command line interface
2+
23
`zinit` provides sub commands to run as init process, and ctrl commands to start, stop, and query running services.
34
Run `zinit --help` to show a list of the current implemented sub-commands.
45

56
## init
6-
the init sub-command is the main mode for zinit.
7+
8+
the init sub-command is the main mode for zinit.
79
It reads the configured services files in available in the config directory`/etc/zinit` or anopther one provided by the`-c` flag. Then it auto monitors those services.
810

911
When a service is monitored, it means that it's auto started, and then watched in case the service exited for any reason. When a service exits, it's automatically restarted, unless it's marked as a `oneshot`
@@ -14,15 +16,15 @@ If you want to read more about `zinit` process manager please check [here](imple
1416

1517
When running zinit in a container, supply the `--container` argument to the init command.
1618

17-
1819
### Service configuration
20+
1921
```yaml
2022
exec: "command line to start service"
2123
test: "command line to test service is running" # optional
2224
oneshot: true or false (false by default)
2325
after: # list of services that we depend on (optional)
24-
- service1_name
25-
- service2_name
26+
- service1_name
27+
- service2_name
2628
signal: # optional section
2729
stop: SIGKILL # the signal sent on `stop` action. default to SIGTERM
2830
log: null | ring | stdout
@@ -44,18 +46,22 @@ env:
4446
- env (dict) is an extra set of env variables (KEY, VALUE) paris that would be available on a service
4547

4648
> Note: to use `ring` inside docker make sure you add the `kmsg` device to the list of allowed devices
49+
4750
```
4851
docker run -dt --device=/dev/kmsg:/dev/kmsg:wm zinit
4952
```
5053
5154
#### Examples
55+
5256
redis-init.yaml
57+
5358
```yaml
5459
exec: sh -c "echo 'prepare db files for redis!'"
5560
oneshot: true
5661
```
5762

5863
redis.yaml
64+
5965
```yaml
6066
exec: redis-server --port 7777
6167
test: redis-cli -p 7777 PING
@@ -64,6 +70,7 @@ after:
6470
```
6571
6672
redis-after.yaml
73+
6774
```yaml
6875
exec: sh -c "populate redis with seed data"
6976
oneshot: true
@@ -72,6 +79,7 @@ after:
7279
```
7380
7481
## Controlling commands
82+
7583
```bash
7684
zinit --help
7785
```
@@ -82,23 +90,30 @@ ThreeFold Tech, https://github.com/threefoldtech
8290
A runit replacement
8391
8492
USAGE:
85-
zinit [SUBCOMMAND]
93+
zinit [FLAGS] [OPTIONS] [SUBCOMMAND]
8694
8795
FLAGS:
96+
-d, --debug run in debug mode
8897
-h, --help Prints help information
8998
-V, --version Prints version information
9099
100+
OPTIONS:
101+
-s, --socket <SOCKET> path to unix socket [default: /var/run/zinit.sock]
102+
91103
SUBCOMMANDS:
92-
forget forget a service. you can only forget a stopped service
93-
help Prints this message or the help of the given subcommand(s)
94-
init run in init mode, start and maintain configured services
95-
kill send a signal to a running service.
96-
list quick view of current known services and their status
97-
log view services logs from zinit ring buffer
98-
monitor start monitoring a service. configuration is loaded from server config directory
99-
start start service. has no effect if the service is already running
100-
status show detailed service status
101-
stop stop service
104+
forget forget a service. you can only forget a stopped service
105+
help Prints this message or the help of the given subcommand(s)
106+
init run in init mode, start and maintain configured services
107+
kill send a signal to a running service.
108+
list quick view of current known services and their status
109+
log view services logs from zinit ring buffer
110+
monitor start monitoring a service. configuration is loaded from server config directory
111+
reboot stop all services and reboot
112+
restart restart service.
113+
shutdown stop all services and power off
114+
start start service. has no effect if the service is already running
115+
status show detailed service status
116+
stop stop service
102117
103118
```
104119

@@ -107,13 +122,16 @@ As already described above, once zinit starts in init mode, it auto monitor all
107122
- `kill`: Similar to the unix `kill` command, it sends a signal to a named service (default to `sigterm`). If the signal terminates the service, `zinit` will auto start it since the service target state is still `up`
108123
- `stop`: Stop sets the target state of the service to `down`, and send the `stop` signal. The stop signal is defaulted to `sigterm` but can be overwritten in the service configuration file. A `stop` action doesn't wait for the service to exit nor grantee that it's killed. It grantees that once the service is down, it won't re-spawn. A caller to the `stop` action can poll on the service state until it's down, or decide to send another signal (for example `kill <service> SIGKILL`) to fully stop it.
109124
- `start`: start is the opposite of `stop`. it will set the target state to `up` and will re-spawn the service if it's not already running.
125+
- `restart`: restart restarting the service. it will first try to stop and put the service status to `Down` and start it again, if it failed to stop it, it will kill the service and then start it again.
110126
- `status`: shows detailed status of a named service.
111127
- `forget`: works only on a `stopped` service (means that the target state is set to `down` by a previous call to `stop`). Also no process must be associated with the service (if the `stop` call didn't do it, a `kill` might)
112128
- `list`: show a quick view of all monitored services.
113129
- `log`: show services logs from the zinit ring buffer. The buffer size is configured in `init`
114130
- `monitor`: monitor will load config of a service `name` from the configuration directory. and monitor it, this will allow you to add new
115-
service to the configuration directory in runtime.
131+
service to the configuration directory in runtime.
116132

117133
## Config Files
134+
118135
zinit does not require any other config files other that the service unit files. But zinit respects some of the global unix standard files:
136+
119137
- `/etc/environment` . The file is read one time during boot, changes to this file in runtime has no effect (even for new services)

src/app/mod.rs

Lines changed: 19 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -5,6 +5,7 @@ use anyhow::{Context, Result};
55
use serde_yaml as encoder;
66
use std::path::{Path, PathBuf};
77
use tokio::fs;
8+
use tokio::time;
89

910
fn logger(level: log::LevelFilter) -> Result<()> {
1011
let logger = fern::Dispatch::new()
@@ -129,6 +130,24 @@ pub async fn stop(socket: &str, name: &str) -> Result<()> {
129130
Ok(())
130131
}
131132

133+
pub async fn restart(socket: &str, name: &str) -> Result<()> {
134+
let client = api::Client::new(socket);
135+
client.stop(name).await?;
136+
//pull status
137+
for _ in 0..20 {
138+
let result = client.status(name).await?;
139+
if result.pid == 0 && result.target == "Down" {
140+
client.start(name).await?;
141+
return Ok(());
142+
}
143+
time::sleep(std::time::Duration::from_secs(1)).await;
144+
}
145+
// process not stopped try to kill it
146+
client.kill(name, "SIGKILL").await?;
147+
client.start(name).await?;
148+
Ok(())
149+
}
150+
132151
pub async fn forget(socket: &str, name: &str) -> Result<()> {
133152
let client = api::Client::new(socket);
134153
client.forget(name).await?;

src/main.rs

Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -139,6 +139,16 @@ async fn main() -> Result<()> {
139139
)
140140
.about("send a signal to a running service."),
141141
)
142+
.subcommand(
143+
SubCommand::with_name("restart")
144+
.arg(
145+
Arg::with_name("service")
146+
.value_name("SERVICE")
147+
.required(true)
148+
.help("service name"),
149+
)
150+
.about("restart a service."),
151+
)
142152
.get_matches();
143153

144154
let socket = matches.value_of("socket").unwrap();
@@ -186,6 +196,9 @@ async fn main() -> Result<()> {
186196
)
187197
.await
188198
}
199+
("restart", Some(matches)) => {
200+
app::restart(socket, matches.value_of("service").unwrap()).await
201+
}
189202
_ => app::list(socket).await, // default command
190203
};
191204

0 commit comments

Comments
 (0)