Skip to content

Commit

Permalink
refactor/nanocld: mutualised kill
Browse files Browse the repository at this point in the history
  • Loading branch information
leon3s committed Jan 8, 2024
1 parent d468b0c commit f0ba2ff
Show file tree
Hide file tree
Showing 8 changed files with 143 additions and 113 deletions.
72 changes: 40 additions & 32 deletions bin/nanocld/specs/swagger.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -441,38 +441,6 @@ paths:
application/json:
schema:
$ref: '#/components/schemas/CargoInspect'
/cargoes/{name}/kill:
post:
tags:
- Cargoes
summary: Send a signal to a cargo this will kill the cargo if the signal is SIGKILL
description: Send a signal to a cargo this will kill the cargo if the signal is SIGKILL
operationId: kill_cargo
parameters:
- name: name
in: path
description: Name of the cargo
required: true
schema:
type: string
- name: namespace
in: query
description: Namespace where the cargo belongs
required: false
schema:
type: string
nullable: true
requestBody:
content:
application/json:
schema:
$ref: '#/components/schemas/CargoKillOptions'
required: true
responses:
'200':
description: Cargo killed
'404':
description: Cargo does not exist
/cargoes/{name}/stats:
get:
tags:
Expand Down Expand Up @@ -1078,6 +1046,46 @@ paths:
description: Process stopped
'404':
description: Process does not exist
/processes/{name}/kill:
post:
tags:
- Processes
summary: Send a signal to processes of given kind and name
description: Send a signal to processes of given kind and name
operationId: kill_process
parameters:
- name: kind
in: path
description: Kind of the process
required: true
schema:
type: string
example: cargo
- name: name
in: path
description: Name of the process
required: true
schema:
type: string
example: deploy-example
- name: namespace
in: query
description: Namespace where the process belongs is needed
required: false
schema:
type: string
nullable: true
requestBody:
content:
application/json:
schema:
$ref: '#/components/schemas/CargoKillOptions'
required: true
responses:
'200':
description: Cargo killed
'404':
description: Cargo does not exist
/resource/kinds:
get:
tags:
Expand Down
26 changes: 26 additions & 0 deletions bin/nanocld/src/objects/generic/process.rs
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,7 @@ use nanocl_error::{
use nanocl_stubs::{
system::NativeEventAction,
process::{ProcessKind, ProcessPartial, Process},
cargo::CargoKillOptions,
};

use crate::{
Expand Down Expand Up @@ -175,6 +176,31 @@ pub trait ObjProcess {
Ok(())
}

async fn kill_process_by_kind_pk(
pk: &str,
opts: &CargoKillOptions,
state: &SystemState,
) -> HttpResult<()> {
let processes = ProcessDb::read_by_kind_key(pk, &state.pool).await?;
processes
.into_iter()
.map(|process| async move {
let id = process.data.id.clone().unwrap_or_default();
let options = opts.clone().into();
state
.docker_api
.kill_container(&id, Some(options))
.await
.map_err(HttpError::from)
})
.collect::<FuturesUnordered<_>>()
.collect::<Vec<HttpResult<()>>>()
.await
.into_iter()
.collect::<HttpResult<Vec<_>>>()?;
Ok(())
}

/// Delete a process by pk
async fn del_process_by_pk(
pk: &str,
Expand Down
33 changes: 2 additions & 31 deletions bin/nanocld/src/services/cargo.rs
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@ use nanocl_error::{http::HttpResult, io::IoResult};

use nanocl_stubs::{
generic::{GenericNspQuery, GenericListNspQuery},
cargo::{CargoDeleteQuery, CargoKillOptions, CargoStatsQuery},
cargo::{CargoDeleteQuery, CargoStatsQuery},
cargo_spec::{CargoSpecPartial, CargoSpecUpdate},
};

Expand Down Expand Up @@ -187,34 +187,6 @@ pub async fn patch_cargo(
Ok(web::HttpResponse::Ok().json(&cargo))
}

/// Send a signal to a cargo this will kill the cargo if the signal is SIGKILL
#[cfg_attr(feature = "dev", utoipa::path(
post,
tag = "Cargoes",
request_body = CargoKillOptions,
path = "/cargoes/{name}/kill",
params(
("name" = String, Path, description = "Name of the cargo"),
("namespace" = Option<String>, Query, description = "Namespace where the cargo belongs"),
),
responses(
(status = 200, description = "Cargo killed"),
(status = 404, description = "Cargo does not exist"),
),
))]
#[web::post("/cargoes/{name}/kill")]
pub async fn kill_cargo(
state: web::types::State<SystemState>,
path: web::types::Path<(String, String)>,
payload: web::types::Json<CargoKillOptions>,
qs: web::types::Query<GenericNspQuery>,
) -> HttpResult<web::HttpResponse> {
let namespace = utils::key::resolve_nsp(&qs.namespace);
let key = utils::key::gen_key(&namespace, &path.1);
utils::cargo::kill_by_key(&key, &payload, &state).await?;
Ok(web::HttpResponse::Ok().into())
}

/// List cargo histories
#[cfg_attr(feature = "dev", utoipa::path(
get,
Expand Down Expand Up @@ -314,7 +286,6 @@ pub async fn stats_cargo(
pub fn ntex_config(config: &mut web::ServiceConfig) {
config.service(create_cargo);
config.service(delete_cargo);
config.service(kill_cargo);
config.service(patch_cargo);
config.service(put_cargo);
config.service(list_cargo);
Expand Down Expand Up @@ -415,7 +386,7 @@ mod tests {
);
let res = client
.send_post(
&format!("{ENDPOINT}/{main_test_cargo}/kill"),
&format!("/processes/cargo/{main_test_cargo}/kill"),
Some(&CargoKillOptions {
signal: "SIGINT".to_owned(),
}),
Expand Down
2 changes: 1 addition & 1 deletion bin/nanocld/src/services/openapi.rs
Original file line number Diff line number Diff line change
Expand Up @@ -252,7 +252,6 @@ impl Modify for VersionModifier {
cargo::delete_cargo,
cargo::put_cargo,
cargo::patch_cargo,
cargo::kill_cargo,
cargo::list_cargo_history,
cargo::revert_cargo,
cargo::stats_cargo,
Expand Down Expand Up @@ -304,6 +303,7 @@ impl Modify for VersionModifier {
process::stop_process,
process::list_process,
process::restart_process,
process::kill_process,
// Event
event::list_event,
),
Expand Down
42 changes: 42 additions & 0 deletions bin/nanocld/src/services/process.rs
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,7 @@ use bollard_next::container::LogsOptions;
use nanocl_stubs::{
generic::{GenericNspQuery, GenericFilter, GenericListQuery},
process::{ProcessLogQuery, ProcessOutputLog, ProcessKind},
cargo::CargoKillOptions,
};

use crate::{
Expand Down Expand Up @@ -220,12 +221,53 @@ pub async fn stop_process(
Ok(web::HttpResponse::Accepted().finish())
}

/// Send a signal to processes of given kind and name
#[cfg_attr(feature = "dev", utoipa::path(
post,
tag = "Processes",
request_body = CargoKillOptions,
path = "/processes/{name}/kill",
params(
("kind" = String, Path, description = "Kind of the process", example = "cargo"),
("name" = String, Path, description = "Name of the process", example = "deploy-example"),
("namespace" = Option<String>, Query, description = "Namespace where the process belongs is needed"),
),
responses(
(status = 200, description = "Cargo killed"),
(status = 404, description = "Cargo does not exist"),
),
))]
#[web::post("/processes/kind/{name}/kill")]
pub async fn kill_process(
state: web::types::State<SystemState>,
path: web::types::Path<(String, String, String)>,
payload: web::types::Json<CargoKillOptions>,
qs: web::types::Query<GenericNspQuery>,
) -> HttpResult<web::HttpResponse> {
let (_, kind, name) = path.into_inner();
let kind = kind.parse().map_err(HttpError::bad_request)?;
let kind_pk = utils::key::gen_kind_key(&kind, &name, &qs.namespace);
match &kind {
ProcessKind::Vm => {
VmDb::kill_process_by_kind_pk(&kind_pk, &payload, &state).await?;
}
ProcessKind::Job => {
JobDb::kill_process_by_kind_pk(&kind_pk, &payload, &state).await?;
}
ProcessKind::Cargo => {
CargoDb::kill_process_by_kind_pk(&kind_pk, &payload, &state).await?;
}
}
Ok(web::HttpResponse::Ok().into())
}

pub fn ntex_config(config: &mut web::ServiceConfig) {
config.service(list_process);
config.service(logs_process);
config.service(restart_process);
config.service(start_process);
config.service(stop_process);
config.service(kill_process);
}

#[cfg(test)]
Expand Down
21 changes: 1 addition & 20 deletions bin/nanocld/src/utils/cargo.rs
Original file line number Diff line number Diff line change
Expand Up @@ -13,7 +13,7 @@ use bollard_next::{
use nanocl_stubs::{
process::Process,
generic::{GenericListNspQuery, GenericClause, GenericFilter},
cargo::{Cargo, CargoSummary, CargoKillOptions, CargoStats, CargoStatsQuery},
cargo::{Cargo, CargoSummary, CargoStats, CargoStatsQuery},
};

use crate::{
Expand Down Expand Up @@ -282,25 +282,6 @@ pub async fn list(
Ok(cargo_summaries)
}

/// Send a signal to a cargo instance the cargo name can be used if the cargo has only one instance
/// The signal is send to one instance only
pub async fn kill_by_key(
key: &str,
options: &CargoKillOptions,
state: &SystemState,
) -> HttpResult<()> {
let instances = ProcessDb::read_by_kind_key(key, &state.pool).await?;
if instances.is_empty() {
return Err(HttpError::not_found(format!(
"Cargo instance not found: {key}"
)));
}
let id = instances[0].data.id.clone().unwrap_or_default();
let options = options.clone().into();
state.docker_api.kill_container(&id, Some(options)).await?;
Ok(())
}

/// Get the stats of a cargo instance
/// The cargo name can be used if the cargo has only one instance
pub fn get_stats(
Expand Down
30 changes: 2 additions & 28 deletions crates/nanocld_client/src/cargo.rs
Original file line number Diff line number Diff line change
Expand Up @@ -6,8 +6,8 @@ use nanocl_error::http_client::HttpClientResult;
use bollard_next::service::ContainerSummary;
use nanocl_stubs::generic::GenericNspQuery;
use nanocl_stubs::cargo::{
Cargo, CargoSummary, CargoInspect, CargoKillOptions, CargoDeleteQuery,
CargoStatsQuery, CargoStats,
Cargo, CargoSummary, CargoInspect, CargoDeleteQuery, CargoStatsQuery,
CargoStats,
};
use nanocl_stubs::cargo_spec::{CargoSpecUpdate, CargoSpecPartial, CargoSpec};

Expand Down Expand Up @@ -237,32 +237,6 @@ impl NanocldClient {
Ok(Self::res_stream(res).await)
}

/// Kill a cargo by it's name
///
/// ## Example
///
/// ```no_run,ignore
/// use nanocld_client::NanocldClient;
///
/// let client = NanocldClient::connect_to("http://localhost:8585", None);
/// let res = client.kill_cargo("my-cargo", None, None).await;
/// ```
pub async fn kill_cargo(
&self,
name: &str,
query: Option<&CargoKillOptions>,
namespace: Option<&str>,
) -> HttpClientResult<()> {
self
.send_post(
&format!("{}/{name}/kill", Self::CARGO_PATH),
query,
Some(GenericNspQuery::new(namespace)),
)
.await?;
Ok(())
}

/// List all the instances of a cargo by it's name and namespace
///
/// ## Example
Expand Down
30 changes: 29 additions & 1 deletion crates/nanocld_client/src/process.rs
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
use nanocl_error::io::IoError;
use nanocl_stubs::cargo::CargoKillOptions;
use ntex::channel::mpsc::Receiver;

use nanocl_error::http::HttpResult;
Expand Down Expand Up @@ -84,7 +85,7 @@ impl NanocldClient {
/// use nanocld_client::NanocldClient;
///
/// let client = NanocldClient::connect_to("http://localhost:8585", None);
/// let res = client.start_process("cargo", "my-cargo", None).await;
/// let res = client.restart_process("cargo", "my-cargo", None).await;
/// ```
pub async fn restart_process(
&self,
Expand Down Expand Up @@ -127,6 +128,33 @@ impl NanocldClient {
.await?;
Ok(())
}

/// Kill processes by it's kind and name and namespace
///
/// ## Example
///
/// ```no_run,ignore
/// use nanocld_client::NanocldClient;
///
/// let client = NanocldClient::connect_to("http://localhost:8585", None);
/// let res = client.kill_process("cargo", "my-cargo", None, None).await;
/// ```
pub async fn kill_cargo(
&self,
kind: &str,
name: &str,
query: Option<&CargoKillOptions>,
namespace: Option<&str>,
) -> HttpClientResult<()> {
self
.send_post(
&format!("{}/{kind}/{name}/kill", Self::PROCESS_PATH),
query,
Some(GenericNspQuery::new(namespace)),
)
.await?;
Ok(())
}
}

#[cfg(test)]
Expand Down

0 comments on commit f0ba2ff

Please sign in to comment.