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

start/stop accept arguments, start defaults to {store,gateway} #398

Merged
merged 2 commits into from
Oct 24, 2022
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
63 changes: 39 additions & 24 deletions iroh/src/doc.rs
Original file line number Diff line number Diff line change
Expand Up @@ -12,36 +12,51 @@ For more info see https://iroh.computer/docs";
pub const START_LONG_DESCRIPTION: &str = "
Iroh start kicks off 'daemons' on your local machine: long-running processes
that make iroh work. Iroh requires a running daemon to do anything meaningful
like add or get content, and `iroh start` is the fastest way to get iroh up &
running locally. Once running, stop iroh with `iroh stop`.
like get or add content, and `iroh start` is the fastest way to get iroh up &
running locally

Use the start, stop, and status commands to monitor iroh on your local machine,
and control it's uptime.

Daemons provide 'services' like storage, peer-2-peer networking, and a gateway
to bridge IPFS to HTTP. Services work together to fullfill API requests. In this
v0.1.0 release iroh is hard-coded to start three deamons: iroh-gateway,
iroh-p2p, and iroh-store. Each daemon provides gateway, p2p, and store services,
respectively. To learn more about each service, see:
https://iroh.computer/docs/services

Iroh start is a simple command, under the hood it just kicks off daemons to run
in the background. On startup each deamon writes its process identifier (PID) to
a lock file, which iroh stop uses to lookup and terminate. Iroh start is by no
means the only way to get iroh up & running. Long running local deployments
should be scheduled by your operating systems daemon supervisior, and cloud
deployments should invoke daemon binaries directly. Regardless of how iroh is
started, you can always use `iroh status` to monitor service health.
and control it's uptime. start runs daemons in the background, so there's no
need to keep your terminal open after running start. Once running, stop iroh
with `iroh stop`.

Daemons provide 'services'. Services work together to fullfill requests.
There are three services:

storage - a database of IPFS content
p2p - peer-2-peer networking functionality
gateway - bridge the IPFS network to HTTP

By default iroh start spins up storage & gateway services. Start the p2p service
with `iroh start p2p`. To learn more about each service, see:
https://iroh.computer/docs/services

Iroh start is by no means the only way to get iroh up & running. Long running
local deployments should be scheduled by your operating systems daemon
supervisior, and cloud deployments should invoke daemon binaries directly.
Regardless of how iroh is started, you can always use `iroh status` to monitor
service health.
";

pub const STOP_LONG_DESCRIPTION: &str = "
stop turns local iroh services off by killing daemon processes. When a deamon
starts it creates a lockfile and writes it's process identifier (PID) to the
lock. Iroh stop uses this lock to lookup the process & send an interrupt signal
to the daemon, which halts the service.
stop turns local iroh services off by killing daemon processes. There are three
iroh services, each backed by a daemon:

iroh stop will also try to clean up any stray lock files in the even that a
program crash fails to remove the lockfile from the file system.
storage - a database of IPFS content
p2p - peer-2-peer networking functionality
gateway - bridge the IPFS network to HTTP

By default `iroh stop` attempts to stop all three services. To stop specific
services, provide service names as arguments, eg: `iroh stop p2p`.

When a deamon starts it creates a lockfile and writes it's process identifier
(PID) to the lock. Iroh stop uses this lock to lookup the process & send an
interrupt signal to the daemon, which halts the service. Stop will also try to
clean up any stray lock files in the even that a program crash fails to remove
the lockfile from the file system.

Stop only works for local processes, and cannot be used to interact with remote
services.
";

pub const STATUS_LONG_DESCRIPTION: &str = "
Expand Down
20 changes: 12 additions & 8 deletions iroh/src/run.rs
Original file line number Diff line number Diff line change
Expand Up @@ -57,9 +57,11 @@ enum Commands {
/// filesystem path to write to. Optional and defaults to $CID
output: Option<PathBuf>,
},
#[clap(about = "Start iroh services locally")]
#[clap(about = "Start local iroh services")]
#[clap(after_help = doc::START_LONG_DESCRIPTION )]
Start {},
Start {
service: Vec<String>,
},
/// status checks the health of the different processes
#[clap(about = "Check the health of the different iroh services")]
#[clap(after_help = doc::STATUS_LONG_DESCRIPTION)]
Expand All @@ -68,9 +70,11 @@ enum Commands {
/// when true, updates the status table whenever a change in a process's status occurs
watch: bool,
},
#[clap(about = "Stop all local iroh services")]
#[clap(about = "Stop local iroh services")]
#[clap(after_help = doc::STOP_LONG_DESCRIPTION )]
Stop {},
Stop {
service: Vec<String>,
},
}

impl Cli {
Expand Down Expand Up @@ -127,14 +131,14 @@ impl Cli {
println!("Saving file(s) to {}", root_path.to_str().unwrap());
}
Commands::P2p(p2p) => run_p2p_command(&api.p2p()?, p2p).await?,
Commands::Start {} => {
crate::services::start(api).await?;
Commands::Start { service } => {
crate::services::start(api, service).await?;
}
Commands::Status { watch } => {
crate::services::status(api, *watch).await?;
}
Commands::Stop {} => {
crate::services::stop(api).await?;
Commands::Stop { service } => {
crate::services::stop(api, service).await?;
}
};

Expand Down
36 changes: 28 additions & 8 deletions iroh/src/services.rs
Original file line number Diff line number Diff line change
Expand Up @@ -15,8 +15,18 @@ const SERVICE_START_TIMEOUT_SECONDS: u64 = 15;

/// start any of {iroh-gateway,iroh-store,iroh-p2p} that aren't currently
/// running.
pub async fn start(api: &impl Api) -> Result<()> {
start_services(api, HashSet::from(["store", "p2p", "gateway"])).await
pub async fn start(api: &impl Api, services: &Vec<String>) -> Result<()> {
let services = match services.is_empty() {
true => HashSet::from(["gateway", "store"]),
false => {
let mut hs: HashSet<&str> = HashSet::new();
for s in services {
hs.insert(s.as_str());
}
hs
}
};
start_services(api, services).await
}

// TODO(b5) - should check for configuration mismatch between iroh CLI configuration
Expand Down Expand Up @@ -98,8 +108,18 @@ async fn start_services(api: &impl Api, services: HashSet<&str>) -> Result<()> {

/// stop the default set of services by sending SIGINT to any active daemons
/// identified by lockfiles
pub async fn stop(api: &impl Api) -> Result<()> {
stop_services(api, HashSet::from(["gateway", "p2p", "store"])).await
pub async fn stop(api: &impl Api, services: &Vec<String>) -> Result<()> {
let services = match services.is_empty() {
true => HashSet::from(["store", "p2p", "gateway"]),
false => {
let mut hs: HashSet<&str> = HashSet::new();
for s in services {
hs.insert(s.as_str());
}
hs
}
};
stop_services(api, services).await
}

pub async fn stop_services(api: &impl Api, services: HashSet<&str>) -> Result<()> {
Expand Down Expand Up @@ -134,7 +154,7 @@ pub async fn stop_services(api: &impl Api, services: HashSet<&str>) -> Result<()
}
Err(e) => match e {
LockError::NoLock(_) => {
eprintln!("{}", format!("{} is already stopped", daemon_name).red());
eprintln!("{}", format!("{} is already stopped", daemon_name).white());
}
LockError::ZombieLock(_) => {
lock.destroy_without_checking().unwrap();
Expand Down Expand Up @@ -222,7 +242,7 @@ where
.queue(style::Print("\tThe service has been interupted"))?;
}
code => {
w.queue(style::PrintStyledContent("Down".red()))?
w.queue(style::PrintStyledContent("Down".grey()))?
.queue(style::Print(format!("\t{}", code)))?;
}
},
Expand Down Expand Up @@ -266,7 +286,7 @@ mod tests {

#[test]
fn status_table_queue() {
let expect = format!("{}gateway\t\t\t1/1\t{}\np2p\t\t\t1/1\t{}\nstore\t\t\t1/1\t{}\tThe service is currently unavailable\n", "Process\t\t\tNumber\tStatus\n".bold(), "Unknown".dark_yellow(), "Serving".green(), "Down".red());
let expect = format!("{}gateway\t\t\t1/1\t{}\np2p\t\t\t1/1\t{}\nstore\t\t\t1/1\t{}\tThe service is currently unavailable\n", "Process\t\t\tNumber\tStatus\n".bold(), "Unknown".dark_yellow(), "Serving".green(), "Down".grey());
let table = StatusTable::new(
Some(StatusRow::new("gateway", 1, ServiceStatus::Unknown)),
Some(StatusRow::new("p2p", 1, ServiceStatus::Serving)),
Expand Down Expand Up @@ -330,7 +350,7 @@ mod tests {
),
output: format!(
"test\t\t\t1/1\t{}\tThe service is currently unavailable\n",
"Down".red()
"Down".grey()
),
},
];
Expand Down