add start stop remove container

This commit is contained in:
beckerinj
2022-12-17 01:27:06 -05:00
parent 839af15311
commit be58cec1c9
11 changed files with 404 additions and 90 deletions
+194 -47
View File
@@ -194,53 +194,6 @@ impl State {
Ok(new_deployment)
}
pub async fn deploy(&self, deployment_id: &str, user: &RequestUser) -> anyhow::Result<Update> {
let mut deployment = self
.get_deployment_check_permissions(deployment_id, user, PermissionLevel::Write)
.await?;
if let Some(build_id) = &deployment.build_id {
let build = self.db.get_build(build_id).await?;
let image = if let Some(docker_account) = &build.docker_account {
if deployment.docker_run_args.docker_account.is_none() {
deployment.docker_run_args.docker_account = Some(docker_account.to_string())
}
format!("{docker_account}/{}", to_monitor_name(&build.name))
} else {
to_monitor_name(&build.name)
};
let version = if let Some(version) = &deployment.build_version {
version.to_string()
} else {
"latest".to_string()
};
deployment.docker_run_args.image = format!("{image}:{version}");
};
let server = self.db.get_server(&deployment.server_id).await?;
let mut update = Update {
target: UpdateTarget::Deployment(deployment_id.to_string()),
operation: Operation::DeployDeployment,
start_ts: unix_timestamp_ms() as i64,
status: UpdateStatus::InProgress,
operator: user.id.clone(),
success: true,
// version: deployment.docker_run_args.,
..Default::default()
};
update.id = self.add_update(update.clone()).await?;
let deploy_log = self.periphery.deploy(&server, &deployment).await?;
update.success = deploy_log.success;
update.logs.push(deploy_log);
update.status = UpdateStatus::Complete;
update.end_ts = Some(unix_timestamp_ms() as i64);
self.update_update(update.clone()).await?;
Ok(update)
}
pub async fn reclone_deployment(
&self,
deployment_id: &str,
@@ -281,4 +234,198 @@ impl State {
Ok(update)
}
pub async fn deploy_container(
&self,
deployment_id: &str,
user: &RequestUser,
) -> anyhow::Result<Update> {
let mut deployment = self
.get_deployment_check_permissions(deployment_id, user, PermissionLevel::Write)
.await?;
if let Some(build_id) = &deployment.build_id {
let build = self.db.get_build(build_id).await?;
let image = if let Some(docker_account) = &build.docker_account {
if deployment.docker_run_args.docker_account.is_none() {
deployment.docker_run_args.docker_account = Some(docker_account.to_string())
}
format!("{docker_account}/{}", to_monitor_name(&build.name))
} else {
to_monitor_name(&build.name)
};
let version = if let Some(version) = &deployment.build_version {
version.to_string()
} else {
"latest".to_string()
};
deployment.docker_run_args.image = format!("{image}:{version}");
};
let server = self.db.get_server(&deployment.server_id).await?;
let mut update = Update {
target: UpdateTarget::Deployment(deployment_id.to_string()),
operation: Operation::DeployContainer,
start_ts: unix_timestamp_ms() as i64,
status: UpdateStatus::InProgress,
operator: user.id.clone(),
success: true,
..Default::default()
};
update.id = self.add_update(update.clone()).await?;
let deploy_log = self.periphery.deploy(&server, &deployment).await?;
update.success = deploy_log.success;
update.logs.push(deploy_log);
update.status = UpdateStatus::Complete;
update.end_ts = Some(unix_timestamp_ms() as i64);
self.update_update(update.clone()).await?;
Ok(update)
}
pub async fn start_container(
&self,
deployment_id: &str,
user: &RequestUser,
) -> anyhow::Result<Update> {
let start_ts = unix_timestamp_ms() as i64;
let deployment = self
.get_deployment_check_permissions(deployment_id, user, PermissionLevel::Write)
.await?;
let server = self.db.get_server(&deployment.server_id).await?;
let mut update = Update {
target: UpdateTarget::Deployment(deployment_id.to_string()),
operation: Operation::StartContainer,
start_ts,
status: UpdateStatus::InProgress,
success: true,
operator: user.id.clone(),
..Default::default()
};
update.id = self.add_update(update.clone()).await?;
let log = self
.periphery
.container_start(&server, &deployment.name)
.await;
update.success = match log {
Ok(log) => {
let success = log.success;
update.logs.push(log);
success
}
Err(e) => {
update
.logs
.push(Log::error("start container", format!("{e:#?}")));
false
}
};
update.end_ts = Some(unix_timestamp_ms() as i64);
update.status = UpdateStatus::Complete;
self.update_update(update.clone()).await?;
Ok(update)
}
pub async fn stop_container(
&self,
deployment_id: &str,
user: &RequestUser,
) -> anyhow::Result<Update> {
let start_ts = unix_timestamp_ms() as i64;
let deployment = self
.get_deployment_check_permissions(deployment_id, user, PermissionLevel::Write)
.await?;
let server = self.db.get_server(&deployment.server_id).await?;
let mut update = Update {
target: UpdateTarget::Deployment(deployment_id.to_string()),
operation: Operation::StopContainer,
start_ts,
status: UpdateStatus::InProgress,
success: true,
operator: user.id.clone(),
..Default::default()
};
update.id = self.add_update(update.clone()).await?;
let log = self
.periphery
.container_stop(&server, &deployment.name)
.await;
update.success = match log {
Ok(log) => {
let success = log.success;
update.logs.push(log);
success
}
Err(e) => {
update
.logs
.push(Log::error("stop container", format!("{e:#?}")));
false
}
};
update.end_ts = Some(unix_timestamp_ms() as i64);
update.status = UpdateStatus::Complete;
self.update_update(update.clone()).await?;
Ok(update)
}
pub async fn remove_container(
&self,
deployment_id: &str,
user: &RequestUser,
) -> anyhow::Result<Update> {
let start_ts = unix_timestamp_ms() as i64;
let deployment = self
.get_deployment_check_permissions(deployment_id, user, PermissionLevel::Write)
.await?;
let server = self.db.get_server(&deployment.server_id).await?;
let mut update = Update {
target: UpdateTarget::Deployment(deployment_id.to_string()),
operation: Operation::RemoveContainer,
start_ts,
status: UpdateStatus::InProgress,
success: true,
operator: user.id.clone(),
..Default::default()
};
update.id = self.add_update(update.clone()).await?;
let log = self
.periphery
.container_remove(&server, &deployment.name)
.await;
update.success = match log {
Ok(log) => {
let success = log.success;
update.logs.push(log);
success
}
Err(e) => {
update
.logs
.push(Log::error("remove container", format!("{e:#?}")));
false
}
};
update.end_ts = Some(unix_timestamp_ms() as i64);
update.status = UpdateStatus::Complete;
self.update_update(update.clone()).await?;
Ok(update)
}
}
+53 -4
View File
@@ -1,9 +1,10 @@
use anyhow::{anyhow, Context};
use async_timing_util::unix_timestamp_ms;
use diff::Diff;
use helpers::to_monitor_name;
use types::{
traits::Permissioned, Log, Operation, PermissionLevel, Procedure, ProcedureStage, Update,
UpdateTarget,
traits::Permissioned, Log, Operation, PermissionLevel, Procedure, ProcedureOperation::*,
ProcedureStage, Update, UpdateStatus, UpdateTarget,
};
use crate::{auth::RequestUser, state::State};
@@ -105,13 +106,51 @@ impl State {
pub async fn update_procedure(
&self,
new_procedure: Procedure,
mut new_procedure: Procedure,
user: &RequestUser,
) -> anyhow::Result<Procedure> {
let current_procedure = self
.get_procedure_check_permissions(&new_procedure.id, user, PermissionLevel::Write)
.await?;
todo!()
let start_ts = unix_timestamp_ms() as i64;
// none of these should be changed through this method
new_procedure.name = current_procedure.name.clone();
new_procedure.permissions = current_procedure.permissions.clone();
new_procedure.created_at = current_procedure.created_at;
new_procedure.updated_at = start_ts;
// check to make sure no stages have been added that user does not have access to
self.db
.procedures
.update_one(
&new_procedure.id,
mungos::Update::Regular(new_procedure.clone()),
)
.await
.context("failed at update one deployment")?;
let diff = current_procedure.diff(&new_procedure);
let update = Update {
operation: Operation::UpdateProcedure,
target: UpdateTarget::Procedure(new_procedure.id.clone()),
end_ts: Some(start_ts),
start_ts,
status: UpdateStatus::Complete,
logs: vec![Log::simple(
"procedure update",
serde_json::to_string_pretty(&diff).unwrap(),
)],
operator: user.id.clone(),
success: true,
..Default::default()
};
self.add_update(update).await?;
Ok(new_procedure)
}
pub async fn run_procedure(&self, id: &str, user: &RequestUser) -> anyhow::Result<Vec<Update>> {
@@ -125,6 +164,16 @@ impl State {
} in procedure.stages
{
match operation {
StartContainer => {}
StopContainer => {}
RemoveContainer => {}
DeployContainer => {}
RecloneDeployment => {}
BuildBuild => {}
RecloneBuild => {}
PruneImagesServer => {}
_ => {}
}
}
+56 -14
View File
@@ -114,20 +114,6 @@ pub fn router() -> Router {
},
),
)
.route(
"/:id/deploy",
post(
|Extension(state): StateExtension,
Extension(user): RequestUserExtension,
Path(deployment_id): Path<DeploymentId>| async move {
let update = state
.deploy(&deployment_id.id, &user)
.await
.map_err(handle_anyhow_error)?;
response!(Json(update))
},
),
)
.route(
"/:id/reclone",
post(
@@ -142,6 +128,62 @@ pub fn router() -> Router {
},
),
)
.route(
"/:id/deploy",
post(
|Extension(state): StateExtension,
Extension(user): RequestUserExtension,
Path(deployment_id): Path<DeploymentId>| async move {
let update = state
.deploy_container(&deployment_id.id, &user)
.await
.map_err(handle_anyhow_error)?;
response!(Json(update))
},
),
)
.route(
"/:id/start_container",
post(
|Extension(state): StateExtension,
Extension(user): RequestUserExtension,
Path(deployment_id): Path<DeploymentId>| async move {
let update = state
.start_container(&deployment_id.id, &user)
.await
.map_err(handle_anyhow_error)?;
response!(Json(update))
},
),
)
.route(
"/:id/stop_container",
post(
|Extension(state): StateExtension,
Extension(user): RequestUserExtension,
Path(deployment_id): Path<DeploymentId>| async move {
let update = state
.stop_container(&deployment_id.id, &user)
.await
.map_err(handle_anyhow_error)?;
response!(Json(update))
},
),
)
.route(
"/:id/remove_container",
post(
|Extension(state): StateExtension,
Extension(user): RequestUserExtension,
Path(deployment_id): Path<DeploymentId>| async move {
let update = state
.remove_container(&deployment_id.id, &user)
.await
.map_err(handle_anyhow_error)?;
response!(Json(update))
},
),
)
}
impl State {
+40 -6
View File
@@ -23,6 +23,7 @@ impl MonitorClient {
Option::<()>::None,
)
.await
.context(format!("failed at get deployment {deployment_id}"))
}
pub async fn create_deployment(
@@ -61,15 +62,48 @@ impl MonitorClient {
.context("failed at updating deployment")
}
pub async fn deploy(&self, deployment_id: &str) -> anyhow::Result<Update> {
self.post::<(), _>(&format!("/api/deployment/{deployment_id}/deploy"), None)
.await
.context(format!("failed at deploy deployment {deployment_id}"))
}
pub async fn reclone_deployment(&self, id: &str) -> anyhow::Result<Update> {
self.post::<(), _>(&format!("/api/deployment/{id}/reclone"), None)
.await
.context(format!("failed at reclone deployment {id}"))
}
pub async fn deploy_container(&self, deployment_id: &str) -> anyhow::Result<Update> {
self.post::<(), _>(&format!("/api/deployment/{deployment_id}/deploy"), None)
.await
.context(format!("failed at deploy deployment {deployment_id}"))
}
pub async fn start_container(&self, deployment_id: &str) -> anyhow::Result<Update> {
self.post::<(), _>(
&format!("/api/deployment/{deployment_id}/start_container"),
None,
)
.await
.context(format!(
"failed at start container for deployment {deployment_id}"
))
}
pub async fn stop_container(&self, deployment_id: &str) -> anyhow::Result<Update> {
self.post::<(), _>(
&format!("/api/deployment/{deployment_id}/stop_container"),
None,
)
.await
.context(format!(
"failed at stop container for deployment {deployment_id}"
))
}
pub async fn remove_container(&self, deployment_id: &str) -> anyhow::Result<Update> {
self.post::<(), _>(
&format!("/api/deployment/{deployment_id}/remove_container"),
None,
)
.await
.context(format!(
"failed at remove container for deployment {deployment_id}"
))
}
}
+5 -1
View File
@@ -1,10 +1,14 @@
use anyhow::Context;
use types::{Build, Log, Server, PERIPHERY_BUILDER_BUSY};
use crate::PeripheryClient;
impl PeripheryClient {
pub async fn build(&self, server: &Server, build: &Build) -> anyhow::Result<Option<Vec<Log>>> {
let res = self.post_json::<_, Vec<Log>>(server, "/build", build).await;
let res = self
.post_json::<_, Vec<Log>>(server, "/build", build)
.await
.context("failed to build image on periphery");
match res {
Ok(logs) => Ok(Some(logs)),
Err(e) => {
+15 -3
View File
@@ -1,3 +1,4 @@
use anyhow::Context;
use serde_json::json;
use types::{BasicContainerInfo, Deployment, DockerContainerStats, Log, Server};
@@ -5,7 +6,9 @@ use crate::PeripheryClient;
impl PeripheryClient {
pub async fn container_list(&self, server: &Server) -> anyhow::Result<Vec<BasicContainerInfo>> {
self.get_json(server, "/container/list").await
self.get_json(server, "/container/list")
.await
.context("failed to get container list on periphery")
}
pub async fn container_start(
@@ -19,6 +22,7 @@ impl PeripheryClient {
&json!({ "name": container_name }),
)
.await
.context("failed to start container on periphery")
}
pub async fn container_stop(
@@ -32,6 +36,7 @@ impl PeripheryClient {
&json!({ "name": container_name }),
)
.await
.context("failed to stop container on periphery")
}
pub async fn container_remove(
@@ -45,15 +50,19 @@ impl PeripheryClient {
&json!({ "name": container_name }),
)
.await
.context("failed to remove container on periphery")
}
pub async fn deploy(&self, server: &Server, deployment: &Deployment) -> anyhow::Result<Log> {
self.post_json(server, "/container/deploy", deployment)
.await
.context("failed to deploy container on periphery")
}
pub async fn container_prune(&self, server: &Server) -> anyhow::Result<Log> {
self.post_json(server, "/container/prune", &json!({})).await
self.post_json(server, "/container/prune", &json!({}))
.await
.context("failed to prune containers on periphery")
}
pub async fn container_stats(
@@ -63,12 +72,15 @@ impl PeripheryClient {
) -> anyhow::Result<Vec<DockerContainerStats>> {
self.get_json(server, &format!("/container/stats/{container_name}"))
.await
.context("failed to get container stats from periphery")
}
pub async fn container_stats_list(
&self,
server: &Server,
) -> anyhow::Result<Vec<DockerContainerStats>> {
self.get_json(server, "/container/stats/list").await
self.get_json(server, "/container/stats/list")
.await
.context("failed to get stats list from periphery")
}
}
+5 -1
View File
@@ -1,3 +1,4 @@
use anyhow::Context;
use helpers::git::CloneArgs;
use serde_json::json;
use types::{Log, Server};
@@ -11,11 +12,14 @@ impl PeripheryClient {
clone_args: impl Into<CloneArgs>,
) -> anyhow::Result<Vec<Log>> {
let clone_args: CloneArgs = clone_args.into();
self.post_json(server, "/git/clone", &clone_args).await
self.post_json(server, "/git/clone", &clone_args)
.await
.context("failed to clone repo on periphery")
}
pub async fn delete_repo(&self, server: &Server, build_name: &str) -> anyhow::Result<Log> {
self.post_json(server, "/git/delete", &json!({ "name": build_name }))
.await
.context("failed to delete repo on periphery")
}
}
+7 -2
View File
@@ -1,13 +1,18 @@
use anyhow::Context;
use types::{ImageSummary, Log, Server};
use crate::PeripheryClient;
impl PeripheryClient {
pub async fn image_list(&self, server: &Server) -> anyhow::Result<Vec<ImageSummary>> {
self.get_json(server, "/image/list").await
self.get_json(server, "/image/list")
.await
.context("failed to get image list from periphery")
}
pub async fn image_prune(&self, server: &Server) -> anyhow::Result<Log> {
self.post_json(server, &format!("/image/prune"), &()).await
self.post_json(server, &format!("/image/prune"), &())
.await
.context("failed to prune images on periphery")
}
}
+12 -4
View File
@@ -21,19 +21,27 @@ impl PeripheryClient {
}
pub async fn health_check(&self, server: &Server) -> anyhow::Result<String> {
self.get_text(server, "health").await
self.get_text(server, "health")
.await
.context("failed at health check on periphery")
}
pub async fn get_github_accounts(&self, server: &Server) -> anyhow::Result<Vec<String>> {
self.get_json(server, "/accounts/github").await
self.get_json(server, "/accounts/github")
.await
.context("failed to get github accounts from periphery")
}
pub async fn get_docker_accounts(&self, server: &Server) -> anyhow::Result<Vec<String>> {
self.get_json(server, "/accounts/docker").await
self.get_json(server, "/accounts/docker")
.await
.context("failed to get docker accounts from periphery")
}
pub async fn get_system_stats(&self, server: &Server) -> anyhow::Result<SystemStats> {
self.get_json(server, "/stats/system").await
self.get_json(server, "/stats/system")
.await
.context("failed to get system stats from periphery")
}
async fn get_text(&self, server: &Server, endpoint: &str) -> anyhow::Result<String> {
+9 -2
View File
@@ -1,3 +1,4 @@
use anyhow::Context;
use serde_json::json;
use types::{Log, Network, Server};
@@ -5,7 +6,9 @@ use crate::PeripheryClient;
impl PeripheryClient {
pub async fn network_list(&self, server: &Server) -> anyhow::Result<Vec<Network>> {
self.get_json(server, "/network/list").await
self.get_json(server, "/network/list")
.await
.context("failed to get network list from periphery")
}
pub async fn network_create(
@@ -23,14 +26,18 @@ impl PeripheryClient {
}),
)
.await
.context("failed to create network on periphery")
}
pub async fn network_delete(&self, server: &Server, name: &str) -> anyhow::Result<Log> {
self.post_json(server, "/network/delete", &json!({ "name": name }))
.await
.context("failed to delete network on periphery")
}
pub async fn network_prune(&self, server: &Server) -> anyhow::Result<Log> {
self.post_json(server, "/network/prune", &json!({})).await
self.post_json(server, "/network/prune", &json!({}))
.await
.context("failed to prune networks on periphery")
}
}
+8 -6
View File
@@ -689,9 +689,10 @@ pub enum Operation {
CreateDeployment,
UpdateDeployment,
DeleteDeployment,
DeployDeployment,
StopDeployment,
StartDeployment,
DeployContainer,
StopContainer,
StartContainer,
RemoveContainer,
PullDeployment,
RecloneDeployment,
@@ -727,9 +728,10 @@ pub enum ProcedureOperation {
RecloneBuild,
// deployment
DeployDeployment,
StopDeployment,
StartDeployment,
DeployContainer,
StopContainer,
StartContainer,
RemoveContainer,
PullDeployment,
RecloneDeployment,