Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Adds zini restart subcommand #55

Merged
merged 4 commits into from
Oct 16, 2023
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
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
Loading