Skip to content

Commit

Permalink
Adds zini restart subcommand (#55)
Browse files Browse the repository at this point in the history
* Adds zini restart subcommand

Signed-off-by: Ashraf Fouda <[email protected]>

* improve implementation of zinit restart

Signed-off-by: Ashraf Fouda <[email protected]>

* updating docs

Signed-off-by: Ashraf Fouda <[email protected]>

* updates docs for zinit restart

Signed-off-by: Ashraf Fouda <[email protected]>

---------

Signed-off-by: Ashraf Fouda <[email protected]>
  • Loading branch information
ashraffouda authored Oct 16, 2023
1 parent 116dcf3 commit 407e730
Show file tree
Hide file tree
Showing 3 changed files with 66 additions and 16 deletions.
50 changes: 34 additions & 16 deletions docs/readme.md
Original file line number Diff line number Diff line change
@@ -1,9 +1,11 @@
# Command line interface

`zinit` provides sub commands to run as init process, and ctrl commands to start, stop, and query running services.
Run `zinit --help` to show a list of the current implemented sub-commands.

## init
the init sub-command is the main mode for zinit.

the init sub-command is the main mode for zinit.
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.

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`
Expand All @@ -14,15 +16,15 @@ If you want to read more about `zinit` process manager please check [here](imple

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


### Service configuration

```yaml
exec: "command line to start service"
test: "command line to test service is running" # optional
oneshot: true or false (false by default)
after: # list of services that we depend on (optional)
- service1_name
- service2_name
- service1_name
- service2_name
signal: # optional section
stop: SIGKILL # the signal sent on `stop` action. default to SIGTERM
log: null | ring | stdout
Expand All @@ -44,18 +46,22 @@ env:
- env (dict) is an extra set of env variables (KEY, VALUE) paris that would be available on a service

> Note: to use `ring` inside docker make sure you add the `kmsg` device to the list of allowed devices

```
docker run -dt --device=/dev/kmsg:/dev/kmsg:wm zinit
```
#### Examples
redis-init.yaml
```yaml
exec: sh -c "echo 'prepare db files for redis!'"
oneshot: true
```

redis.yaml

```yaml
exec: redis-server --port 7777
test: redis-cli -p 7777 PING
Expand All @@ -64,6 +70,7 @@ after:
```
redis-after.yaml
```yaml
exec: sh -c "populate redis with seed data"
oneshot: true
Expand All @@ -72,6 +79,7 @@ after:
```
## Controlling commands
```bash
zinit --help
```
Expand All @@ -82,23 +90,30 @@ ThreeFold Tech, https://github.com/threefoldtech
A runit replacement
USAGE:
zinit [SUBCOMMAND]
zinit [FLAGS] [OPTIONS] [SUBCOMMAND]
FLAGS:
-d, --debug run in debug mode
-h, --help Prints help information
-V, --version Prints version information
OPTIONS:
-s, --socket <SOCKET> path to unix socket [default: /var/run/zinit.sock]
SUBCOMMANDS:
forget forget a service. you can only forget a stopped service
help Prints this message or the help of the given subcommand(s)
init run in init mode, start and maintain configured services
kill send a signal to a running service.
list quick view of current known services and their status
log view services logs from zinit ring buffer
monitor start monitoring a service. configuration is loaded from server config directory
start start service. has no effect if the service is already running
status show detailed service status
stop stop service
forget forget a service. you can only forget a stopped service
help Prints this message or the help of the given subcommand(s)
init run in init mode, start and maintain configured services
kill send a signal to a running service.
list quick view of current known services and their status
log view services logs from zinit ring buffer
monitor start monitoring a service. configuration is loaded from server config directory
reboot stop all services and reboot
restart restart service.
shutdown stop all services and power off
start start service. has no effect if the service is already running
status show detailed service status
stop stop service
```

Expand All @@ -107,13 +122,16 @@ As already described above, once zinit starts in init mode, it auto monitor all
- `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`
- `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.
- `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.
- `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.
- `status`: shows detailed status of a named service.
- `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)
- `list`: show a quick view of all monitored services.
- `log`: show services logs from the zinit ring buffer. The buffer size is configured in `init`
- `monitor`: monitor will load config of a service `name` from the configuration directory. and monitor it, this will allow you to add new
service to the configuration directory in runtime.
service to the configuration directory in runtime.

## Config Files

zinit does not require any other config files other that the service unit files. But zinit respects some of the global unix standard files:

- `/etc/environment` . The file is read one time during boot, changes to this file in runtime has no effect (even for new services)
19 changes: 19 additions & 0 deletions src/app/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@ use anyhow::{Context, Result};
use serde_yaml as encoder;
use std::path::{Path, PathBuf};
use tokio::fs;
use tokio::time;

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

pub async fn restart(socket: &str, name: &str) -> Result<()> {
let client = api::Client::new(socket);
client.stop(name).await?;
//pull status
for _ in 0..20 {
let result = client.status(name).await?;
if result.pid == 0 && result.target == "Down" {
client.start(name).await?;
return Ok(());
}
time::sleep(std::time::Duration::from_secs(1)).await;
}
// process not stopped try to kill it
client.kill(name, "SIGKILL").await?;
client.start(name).await?;
Ok(())
}

pub async fn forget(socket: &str, name: &str) -> Result<()> {
let client = api::Client::new(socket);
client.forget(name).await?;
Expand Down
13 changes: 13 additions & 0 deletions src/main.rs
Original file line number Diff line number Diff line change
Expand Up @@ -139,6 +139,16 @@ async fn main() -> Result<()> {
)
.about("send a signal to a running service."),
)
.subcommand(
SubCommand::with_name("restart")
.arg(
Arg::with_name("service")
.value_name("SERVICE")
.required(true)
.help("service name"),
)
.about("restart a service."),
)
.get_matches();

let socket = matches.value_of("socket").unwrap();
Expand Down Expand Up @@ -186,6 +196,9 @@ async fn main() -> Result<()> {
)
.await
}
("restart", Some(matches)) => {
app::restart(socket, matches.value_of("service").unwrap()).await
}
_ => app::list(socket).await, // default command
};

Expand Down

0 comments on commit 407e730

Please sign in to comment.