diff --git a/core/src/actions/build.rs b/core/src/actions/build.rs index c49f78214..f5f6ceabc 100644 --- a/core/src/actions/build.rs +++ b/core/src/actions/build.rs @@ -93,7 +93,7 @@ impl State { pub async fn delete_build(&self, build_id: &str, user: &RequestUser) -> anyhow::Result { if self.build_busy(build_id) { - return Err(anyhow!("build busy")) + return Err(anyhow!("build busy")); } let build = self .get_build_check_permissions(build_id, user, PermissionLevel::Update) @@ -132,7 +132,7 @@ impl State { user: &RequestUser, ) -> anyhow::Result { if self.build_busy(&new_build.id) { - return Err(anyhow!("build busy")) + return Err(anyhow!("build busy")); } let id = new_build.id.clone(); { @@ -215,7 +215,7 @@ impl State { pub async fn build(&self, build_id: &str, user: &RequestUser) -> anyhow::Result { if self.build_busy(build_id) { - return Err(anyhow!("build busy")) + return Err(anyhow!("build busy")); } { let mut lock = self.build_action_states.lock().unwrap(); @@ -288,9 +288,13 @@ impl State { Ok(update) } - pub async fn reclone_build(&self, build_id: &str, user: &RequestUser) -> anyhow::Result { + pub async fn reclone_build( + &self, + build_id: &str, + user: &RequestUser, + ) -> anyhow::Result { if self.build_busy(build_id) { - return Err(anyhow!("build busy")) + return Err(anyhow!("build busy")); } { let mut lock = self.build_action_states.lock().unwrap(); diff --git a/core/src/actions/deployment.rs b/core/src/actions/deployment.rs index 2598d3b49..afb8d4f07 100644 --- a/core/src/actions/deployment.rs +++ b/core/src/actions/deployment.rs @@ -96,7 +96,7 @@ impl State { user: &RequestUser, ) -> anyhow::Result { if self.deployment_busy(deployment_id) { - return Err(anyhow!("deployment busy")) + return Err(anyhow!("deployment busy")); } let deployment = self .get_deployment_check_permissions(deployment_id, user, PermissionLevel::Update) @@ -143,7 +143,7 @@ impl State { user: &RequestUser, ) -> anyhow::Result { if self.deployment_busy(&new_deployment.id) { - return Err(anyhow!("deployment busy")) + return Err(anyhow!("deployment busy")); } let id = new_deployment.id.clone(); { @@ -233,7 +233,7 @@ impl State { user: &RequestUser, ) -> anyhow::Result { if self.deployment_busy(deployment_id) { - return Err(anyhow!("deployment busy")) + return Err(anyhow!("deployment busy")); } { let mut lock = self.deployment_action_states.lock().unwrap(); @@ -296,7 +296,7 @@ impl State { user: &RequestUser, ) -> anyhow::Result { if self.deployment_busy(deployment_id) { - return Err(anyhow!("deployment busy")) + return Err(anyhow!("deployment busy")); } { let mut lock = self.deployment_action_states.lock().unwrap(); @@ -317,6 +317,7 @@ impl State { deployment_id: &str, user: &RequestUser, ) -> anyhow::Result { + let start_ts = monitor_timestamp(); let mut deployment = self .get_deployment_check_permissions(deployment_id, user, PermissionLevel::Execute) .await?; @@ -341,7 +342,7 @@ impl State { let mut update = Update { target: UpdateTarget::Deployment(deployment_id.to_string()), operation: Operation::DeployContainer, - start_ts: monitor_timestamp(), + start_ts, status: UpdateStatus::InProgress, operator: user.id.clone(), success: true, @@ -368,7 +369,7 @@ impl State { user: &RequestUser, ) -> anyhow::Result { if self.deployment_busy(deployment_id) { - return Err(anyhow!("deployment busy")) + return Err(anyhow!("deployment busy")); } { let mut lock = self.deployment_action_states.lock().unwrap(); @@ -438,7 +439,7 @@ impl State { user: &RequestUser, ) -> anyhow::Result { if self.deployment_busy(deployment_id) { - return Err(anyhow!("deployment busy")) + return Err(anyhow!("deployment busy")); } { let mut lock = self.deployment_action_states.lock().unwrap(); @@ -508,7 +509,7 @@ impl State { user: &RequestUser, ) -> anyhow::Result { if self.deployment_busy(deployment_id) { - return Err(anyhow!("deployment busy")) + return Err(anyhow!("deployment busy")); } { let mut lock = self.deployment_action_states.lock().unwrap(); @@ -571,4 +572,63 @@ impl State { Ok(update) } + + pub async fn pull_deployment_repo( + &self, + deployment_id: &str, + user: &RequestUser, + ) -> anyhow::Result { + if self.deployment_busy(deployment_id) { + return Err(anyhow!("deployment busy")); + } + { + let mut lock = self.deployment_action_states.lock().unwrap(); + let entry = lock.entry(deployment_id.to_string()).or_default(); + entry.pulling = true; + } + let res = self.pull_deployment_repo_inner(deployment_id, user).await; + { + let mut lock = self.deployment_action_states.lock().unwrap(); + let entry = lock.entry(deployment_id.to_string()).or_default(); + entry.pulling = false; + } + res + } + + async fn pull_deployment_repo_inner( + &self, + deployment_id: &str, + user: &RequestUser, + ) -> anyhow::Result { + let start_ts = monitor_timestamp(); + let deployment = self + .get_deployment_check_permissions(deployment_id, user, PermissionLevel::Execute) + .await?; + let server = self.db.get_server(&deployment.server_id).await?; + let mut update = Update { + target: UpdateTarget::Deployment(deployment_id.to_string()), + operation: Operation::PullDeployment, + start_ts, + status: UpdateStatus::InProgress, + operator: user.id.clone(), + success: true, + ..Default::default() + }; + + update.id = self.add_update(update.clone()).await?; + + let log = self + .periphery + .pull_repo(&server, &deployment.name, &deployment.branch) + .await?; + + update.success = log.success; + update.logs.push(log); + update.end_ts = Some(monitor_timestamp()); + update.status = UpdateStatus::Complete; + + self.update_update(update.clone()).await?; + + Ok(update) + } } diff --git a/core/src/actions/server.rs b/core/src/actions/server.rs index 2d871ab55..eedf56c35 100644 --- a/core/src/actions/server.rs +++ b/core/src/actions/server.rs @@ -96,7 +96,7 @@ impl State { user: &RequestUser, ) -> anyhow::Result { if self.server_busy(server_id) { - return Err(anyhow!("server busy")) + return Err(anyhow!("server busy")); } let server = self .get_server_check_permissions(server_id, user, PermissionLevel::Update) @@ -126,7 +126,7 @@ impl State { user: &RequestUser, ) -> anyhow::Result { if self.server_busy(&new_server.id) { - return Err(anyhow!("server busy")) + return Err(anyhow!("server busy")); } let current_server = self .get_server_check_permissions(&new_server.id, user, PermissionLevel::Update) @@ -170,7 +170,7 @@ impl State { user: &RequestUser, ) -> anyhow::Result { if self.server_busy(server_id) { - return Err(anyhow!("server busy")) + return Err(anyhow!("server busy")); } { let mut lock = self.server_action_states.lock().unwrap(); @@ -231,7 +231,7 @@ impl State { user: &RequestUser, ) -> anyhow::Result { if self.server_busy(server_id) { - return Err(anyhow!("server busy")) + return Err(anyhow!("server busy")); } { let mut lock = self.server_action_states.lock().unwrap(); @@ -293,7 +293,7 @@ impl State { user: &RequestUser, ) -> anyhow::Result { if self.server_busy(server_id) { - return Err(anyhow!("server busy")) + return Err(anyhow!("server busy")); } { let mut lock = self.server_action_states.lock().unwrap(); diff --git a/core/src/api/deployment.rs b/core/src/api/deployment.rs index 884d08926..0a555c411 100644 --- a/core/src/api/deployment.rs +++ b/core/src/api/deployment.rs @@ -189,6 +189,20 @@ pub fn router() -> Router { }, ), ) + .route( + "/:id/pull", + post( + |Extension(state): StateExtension, + Extension(user): RequestUserExtension, + Path(deployment_id): Path| async move { + let update = state + .pull_deployment_repo(&deployment_id.id, &user) + .await + .map_err(handle_anyhow_error)?; + response!(Json(update)) + }, + ), + ) .route( "/:id/action_state", get( diff --git a/lib/monitor_client/src/build.rs b/lib/monitor_client/src/build.rs index 65b41e65f..4bccd37ae 100644 --- a/lib/monitor_client/src/build.rs +++ b/lib/monitor_client/src/build.rs @@ -1,5 +1,5 @@ use anyhow::Context; -use monitor_types::{Build, Update}; +use monitor_types::{Build, BuildActionState, Update}; use serde_json::{json, Value}; use crate::MonitorClient; @@ -16,6 +16,14 @@ impl MonitorClient { .await } + pub async fn get_build_action_state(&self, build_id: &str) -> anyhow::Result { + self.get( + &format!("/api/build/{build_id}/action_state"), + Option::<()>::None, + ) + .await + } + pub async fn create_build(&self, name: &str, server_id: &str) -> anyhow::Result { self.post( "/api/build/create", diff --git a/lib/monitor_client/src/deployment.rs b/lib/monitor_client/src/deployment.rs index e1e3514ac..f585ecd2c 100644 --- a/lib/monitor_client/src/deployment.rs +++ b/lib/monitor_client/src/deployment.rs @@ -1,5 +1,5 @@ use anyhow::Context; -use monitor_types::{Deployment, DeploymentWithContainer, Update}; +use monitor_types::{Deployment, DeploymentActionState, DeploymentWithContainer, Update}; use serde_json::{json, Value}; use crate::MonitorClient; @@ -26,6 +26,17 @@ impl MonitorClient { .context(format!("failed at get deployment {deployment_id}")) } + pub async fn get_deployment_action_state( + &self, + deployment_id: &str, + ) -> anyhow::Result { + self.get( + &format!("/api/deployment/{deployment_id}/action_state"), + Option::<()>::None, + ) + .await + } + pub async fn create_deployment( &self, name: &str, @@ -106,4 +117,12 @@ impl MonitorClient { "failed at remove container for deployment {deployment_id}" )) } + + pub async fn pull_deployment_repo(&self, deployment_id: &str) -> anyhow::Result { + self.post::<(), _>(&format!("/api/deployment/{deployment_id}/pull"), None) + .await + .context(format!( + "failed at remove container for deployment {deployment_id}" + )) + } } diff --git a/lib/monitor_client/src/server.rs b/lib/monitor_client/src/server.rs index c6ce7629e..6bb882ab6 100644 --- a/lib/monitor_client/src/server.rs +++ b/lib/monitor_client/src/server.rs @@ -1,5 +1,7 @@ use anyhow::Context; -use monitor_types::{BasicContainerInfo, ImageSummary, Log, Network, Server, SystemStats}; +use monitor_types::{ + BasicContainerInfo, ImageSummary, Log, Network, Server, ServerActionState, SystemStats, +}; use serde_json::{json, Value}; use crate::MonitorClient; @@ -19,6 +21,17 @@ impl MonitorClient { .await } + pub async fn get_server_action_state( + &self, + server_id: &str, + ) -> anyhow::Result { + self.get( + &format!("/api/server/{server_id}/action_state"), + Option::<()>::None, + ) + .await + } + pub async fn create_server(&self, name: &str, address: &str) -> anyhow::Result { self.post( "/api/server/create", diff --git a/lib/periphery_client/src/git.rs b/lib/periphery_client/src/git.rs index 9a6b7c7b3..2103f0af6 100644 --- a/lib/periphery_client/src/git.rs +++ b/lib/periphery_client/src/git.rs @@ -17,6 +17,21 @@ impl PeripheryClient { .context("failed to clone repo on periphery") } + pub async fn pull_repo( + &self, + server: &Server, + name: &str, + branch: &Option, + ) -> anyhow::Result { + self.post_json( + server, + "/git/pull", + &json!({ "name": name, "branch": branch }), + ) + .await + .context("failed to pull repo on periphery") + } + pub async fn delete_repo(&self, server: &Server, build_name: &str) -> anyhow::Result { self.post_json(server, "/git/delete", &json!({ "name": build_name })) .await diff --git a/periphery/src/api/git.rs b/periphery/src/api/git.rs index 10ebcc842..055717608 100644 --- a/periphery/src/api/git.rs +++ b/periphery/src/api/git.rs @@ -15,6 +15,12 @@ pub struct DeleteRepoBody { name: String, } +#[derive(Deserialize)] +pub struct PullBody { + name: String, + branch: Option, +} + pub fn router() -> Router { Router::new() .route( @@ -25,6 +31,12 @@ pub fn router() -> Router { .map_err(handle_anyhow_error) }), ) + .route( + "/pull", + post(|config, body| async move { + pull_repo(config, body).await.map_err(handle_anyhow_error) + }), + ) .route( "/delete", post(|config, body| async move { @@ -58,3 +70,15 @@ async fn delete_repo( let log = Log::simple("delete repo", msg); Ok(Json(log)) } + +async fn pull_repo( + Extension(config): PeripheryConfigExtension, + Json(PullBody { name, branch }): Json, +) -> anyhow::Result> { + let mut repo_dir = PathBuf::from_str(&config.repo_dir)?; + let name = to_monitor_name(&name); + repo_dir.push(&name); + let path = repo_dir.display().to_string(); + let log = git::pull(&path, &branch).await; + Ok(Json(log)) +}