forked from github-starred/komodo
update build
This commit is contained in:
Generated
+1
@@ -361,6 +361,7 @@ dependencies = [
|
||||
"axum-extra",
|
||||
"bcrypt",
|
||||
"db_client",
|
||||
"diff-struct",
|
||||
"dotenv",
|
||||
"envy",
|
||||
"futures-util",
|
||||
|
||||
+2
-1
@@ -30,4 +30,5 @@ jwt = "0.16"
|
||||
hmac = "0.12"
|
||||
sha2 = "0.10"
|
||||
async_timing_util = "0.1.11"
|
||||
futures-util = "0.3"
|
||||
futures-util = "0.3"
|
||||
diff-struct = "0.5"
|
||||
+66
-11
@@ -2,17 +2,22 @@ use anyhow::{anyhow, Context};
|
||||
use async_timing_util::unix_timestamp_ms;
|
||||
use axum::{
|
||||
extract::Path,
|
||||
routing::{delete, post},
|
||||
routing::{delete, patch, post},
|
||||
Extension, Json, Router,
|
||||
};
|
||||
use db::DbExtension;
|
||||
use diff::Diff;
|
||||
use helpers::handle_anyhow_error;
|
||||
use mungos::Deserialize;
|
||||
use types::{traits::Permissioned, Build, Log, Operation, PermissionLevel, Update, UpdateTarget};
|
||||
|
||||
use crate::{auth::RequestUserExtension, ws::update};
|
||||
use crate::{
|
||||
auth::RequestUserExtension,
|
||||
helpers::{add_update, all_logs_success, any_option_diff_is_some, option_diff_is_some},
|
||||
ws::update,
|
||||
};
|
||||
|
||||
use super::{add_update, PeripheryExtension};
|
||||
use super::PeripheryExtension;
|
||||
|
||||
#[derive(Deserialize)]
|
||||
struct BuildId {
|
||||
@@ -43,6 +48,14 @@ pub fn router() -> Router {
|
||||
.map_err(handle_anyhow_error)
|
||||
}),
|
||||
)
|
||||
.route(
|
||||
"/update",
|
||||
patch(|db, user, update_ws, periphery, build| async {
|
||||
update(db, user, update_ws, periphery, build)
|
||||
.await
|
||||
.map_err(handle_anyhow_error)
|
||||
}),
|
||||
)
|
||||
}
|
||||
|
||||
impl Into<Build> for CreateBuildBody {
|
||||
@@ -80,9 +93,11 @@ async fn create(
|
||||
start_ts,
|
||||
end_ts: Some(unix_timestamp_ms() as i64),
|
||||
operator: user.id.clone(),
|
||||
success: true,
|
||||
..Default::default()
|
||||
};
|
||||
add_update(update, &db, &update_ws).await
|
||||
add_update(update, &db, &update_ws).await?;
|
||||
Ok(())
|
||||
}
|
||||
|
||||
async fn delete_one(
|
||||
@@ -94,7 +109,7 @@ async fn delete_one(
|
||||
) -> anyhow::Result<()> {
|
||||
let build = db.get_build(&id).await?;
|
||||
let permissions = build.get_user_permissions(&user.id);
|
||||
if permissions != PermissionLevel::Write {
|
||||
if !user.is_admin && permissions != PermissionLevel::Write {
|
||||
return Err(anyhow!(
|
||||
"user does not have permissions to delete build {} ({id})",
|
||||
build.name
|
||||
@@ -113,16 +128,18 @@ async fn delete_one(
|
||||
start_ts,
|
||||
end_ts: Some(unix_timestamp_ms() as i64),
|
||||
operator: user.id.clone(),
|
||||
log: vec![
|
||||
logs: vec![
|
||||
delete_repo_log,
|
||||
Log::simple(format!(
|
||||
"deleted build {} on server {}",
|
||||
build.name, server.name
|
||||
)),
|
||||
],
|
||||
success: true,
|
||||
..Default::default()
|
||||
};
|
||||
add_update(update, &db, &update_ws).await
|
||||
add_update(update, &db, &update_ws).await?;
|
||||
Ok(())
|
||||
}
|
||||
|
||||
async fn update(
|
||||
@@ -130,7 +147,45 @@ async fn update(
|
||||
Extension(user): RequestUserExtension,
|
||||
Extension(update_ws): update::UpdateWsSenderExtension,
|
||||
Extension(periphery): PeripheryExtension,
|
||||
Path(build): Path<Build>,
|
||||
) {
|
||||
|
||||
}
|
||||
Json(mut new_build): Json<Build>,
|
||||
) -> anyhow::Result<()> {
|
||||
let current_build = db.get_build(&new_build.id).await?;
|
||||
let permissions = current_build.get_user_permissions(&user.id);
|
||||
if !user.is_admin && permissions != PermissionLevel::Write {
|
||||
return Err(anyhow!(
|
||||
"user does not have permissions to update build {} ({})",
|
||||
current_build.name,
|
||||
current_build.id
|
||||
));
|
||||
}
|
||||
let start_ts = unix_timestamp_ms() as i64;
|
||||
let server = db.get_server(¤t_build.server_id).await?;
|
||||
|
||||
new_build.permissions = current_build.permissions.clone();
|
||||
let diff = current_build.diff(&new_build);
|
||||
let mut logs = vec![Log::simple(format!("{diff:#?}"))];
|
||||
|
||||
if any_option_diff_is_some(&[&diff.repo, &diff.branch, &diff.github_account])
|
||||
|| option_diff_is_some(&diff.on_clone)
|
||||
{
|
||||
match periphery.clone_repo(&server, &new_build).await {
|
||||
Ok(clone_logs) => {
|
||||
logs.extend(clone_logs);
|
||||
}
|
||||
Err(e) => logs.push(Log::error("cloning repo", format!("{e:#?}"))),
|
||||
}
|
||||
}
|
||||
|
||||
let update = Update {
|
||||
operation: Operation::UpdateBuild,
|
||||
target: UpdateTarget::Build(new_build.id),
|
||||
start_ts,
|
||||
end_ts: Some(unix_timestamp_ms() as i64),
|
||||
success: all_logs_success(&logs),
|
||||
logs,
|
||||
operator: user.id.clone(),
|
||||
..Default::default()
|
||||
};
|
||||
add_update(update, &db, &update_ws).await?;
|
||||
Ok(())
|
||||
}
|
||||
|
||||
@@ -12,9 +12,9 @@ use types::{
|
||||
traits::Permissioned, Deployment, Log, Operation, PermissionLevel, Update, UpdateTarget,
|
||||
};
|
||||
|
||||
use crate::{auth::RequestUserExtension, ws::update};
|
||||
use crate::{auth::RequestUserExtension, helpers::add_update, ws::update};
|
||||
|
||||
use super::{add_update, PeripheryExtension};
|
||||
use super::PeripheryExtension;
|
||||
|
||||
#[derive(Deserialize)]
|
||||
pub struct DeploymentId {
|
||||
@@ -86,9 +86,11 @@ async fn create(
|
||||
start_ts,
|
||||
end_ts: Some(unix_timestamp_ms() as i64),
|
||||
operator: user.id.clone(),
|
||||
success: true,
|
||||
..Default::default()
|
||||
};
|
||||
add_update(update, &db, &update_ws).await
|
||||
add_update(update, &db, &update_ws).await?;
|
||||
Ok(())
|
||||
}
|
||||
|
||||
async fn delete_one(
|
||||
@@ -118,14 +120,16 @@ async fn delete_one(
|
||||
start_ts,
|
||||
end_ts: Some(unix_timestamp_ms() as i64),
|
||||
operator: user.id.clone(),
|
||||
log: vec![
|
||||
logs: vec![
|
||||
log,
|
||||
Log::simple(format!(
|
||||
"deleted deployment {} on server {}",
|
||||
deployment.name, server.name
|
||||
)),
|
||||
],
|
||||
success: true,
|
||||
..Default::default()
|
||||
};
|
||||
add_update(update, &db, &update_ws).await
|
||||
add_update(update, &db, &update_ws).await?;
|
||||
Ok(())
|
||||
}
|
||||
|
||||
+4
-22
@@ -1,16 +1,13 @@
|
||||
use std::sync::Arc;
|
||||
|
||||
use anyhow::{anyhow, Context};
|
||||
use anyhow::anyhow;
|
||||
use axum::{middleware, routing::get, Extension, Json, Router};
|
||||
use db::{DbClient, DbExtension};
|
||||
use db::DbExtension;
|
||||
use helpers::handle_anyhow_error;
|
||||
use periphery::PeripheryClient;
|
||||
use types::{Update, User};
|
||||
use types::User;
|
||||
|
||||
use crate::{
|
||||
auth::{auth_request, RequestUserExtension},
|
||||
ws::update,
|
||||
};
|
||||
use crate::auth::{auth_request, RequestUserExtension};
|
||||
|
||||
mod build;
|
||||
mod deployment;
|
||||
@@ -50,18 +47,3 @@ async fn get_user(
|
||||
}
|
||||
Ok(Json(user))
|
||||
}
|
||||
|
||||
async fn add_update(
|
||||
mut update: Update,
|
||||
db: &DbClient,
|
||||
update_ws: &update::UpdateWsSender,
|
||||
) -> anyhow::Result<()> {
|
||||
update.id = db
|
||||
.updates
|
||||
.create_one(update.clone())
|
||||
.await
|
||||
.context("failed to insert update into db. the create build process was completed.")?
|
||||
.to_string();
|
||||
let _ = update_ws.lock().await.send(update);
|
||||
Ok(())
|
||||
}
|
||||
|
||||
@@ -13,9 +13,9 @@ use types::{
|
||||
UpdateTarget,
|
||||
};
|
||||
|
||||
use crate::{auth::RequestUserExtension, ws::update};
|
||||
use crate::{auth::RequestUserExtension, helpers::add_update, ws::update};
|
||||
|
||||
use super::{add_update, PeripheryExtension};
|
||||
use super::PeripheryExtension;
|
||||
|
||||
#[derive(Deserialize)]
|
||||
struct ServerId {
|
||||
@@ -120,9 +120,11 @@ async fn create(
|
||||
start_ts,
|
||||
end_ts: Some(unix_timestamp_ms() as i64),
|
||||
operator: user.id.clone(),
|
||||
success: true,
|
||||
..Default::default()
|
||||
};
|
||||
add_update(update, &db, &update_ws).await
|
||||
add_update(update, &db, &update_ws).await?;
|
||||
Ok(())
|
||||
}
|
||||
|
||||
async fn delete_one(
|
||||
@@ -147,10 +149,12 @@ async fn delete_one(
|
||||
start_ts,
|
||||
end_ts: Some(unix_timestamp_ms() as i64),
|
||||
operator: user.id.clone(),
|
||||
log: vec![Log::simple(format!("deleted server {}", server.name))],
|
||||
logs: vec![Log::simple(format!("deleted server {}", server.name))],
|
||||
success: true,
|
||||
..Default::default()
|
||||
};
|
||||
add_update(update, &db, &update_ws).await
|
||||
add_update(update, &db, &update_ws).await?;
|
||||
Ok(())
|
||||
}
|
||||
|
||||
async fn stats(
|
||||
|
||||
@@ -1,6 +1,73 @@
|
||||
use anyhow::Context;
|
||||
use db::DbClient;
|
||||
use diff::{Diff, OptionDiff};
|
||||
use types::{Log, Update};
|
||||
|
||||
use crate::ws::update;
|
||||
|
||||
#[macro_export]
|
||||
macro_rules! response {
|
||||
($x:expr) => {
|
||||
Ok::<_, (axum::http::StatusCode, String)>($x)
|
||||
};
|
||||
}
|
||||
|
||||
pub fn option_diff_is_some<T: Diff>(diff: &OptionDiff<T>) -> bool
|
||||
where
|
||||
<T as Diff>::Repr: PartialEq,
|
||||
{
|
||||
diff != &OptionDiff::NoChange && diff != &OptionDiff::None
|
||||
}
|
||||
|
||||
pub fn any_option_diff_is_some<T: Diff>(diffs: &[&OptionDiff<T>]) -> bool
|
||||
where
|
||||
<T as Diff>::Repr: PartialEq,
|
||||
{
|
||||
for diff in diffs {
|
||||
if diff != &&OptionDiff::NoChange && diff != &&OptionDiff::None {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
pub fn all_logs_success(logs: &Vec<Log>) -> bool {
|
||||
for log in logs {
|
||||
if !log.success {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
true
|
||||
}
|
||||
|
||||
pub async fn add_update(
|
||||
mut update: Update,
|
||||
db: &DbClient,
|
||||
update_ws: &update::UpdateWsSender,
|
||||
) -> anyhow::Result<String> {
|
||||
update.id = db
|
||||
.updates
|
||||
.create_one(update.clone())
|
||||
.await
|
||||
.context("failed to insert update into db")?
|
||||
.to_string();
|
||||
let id = update.id.clone();
|
||||
let _ = update_ws.lock().await.send(update);
|
||||
Ok(id)
|
||||
}
|
||||
|
||||
pub async fn update_update(
|
||||
mut update: Update,
|
||||
db: &DbClient,
|
||||
update_ws: &update::UpdateWsSender,
|
||||
) -> anyhow::Result<()> {
|
||||
let mut update_id = String::new();
|
||||
std::mem::swap(&mut update.id, &mut update_id);
|
||||
db.updates
|
||||
.update_one(&update_id, mungos::Update::Regular(update.clone()))
|
||||
.await
|
||||
.context("failed to update the update on db. the update build process was deleted")?;
|
||||
std::mem::swap(&mut update.id, &mut update_id);
|
||||
let _ = update_ws.lock().await.send(update);
|
||||
Ok(())
|
||||
}
|
||||
|
||||
+26
-6
@@ -28,6 +28,7 @@ pub type SecretsMap = HashMap<String, String>; // these are used for injection i
|
||||
pub type PermissionsMap = HashMap<UserId, PermissionLevel>;
|
||||
|
||||
#[derive(Serialize, Deserialize, Debug, Clone, Default, Diff)]
|
||||
#[diff(attr(#[derive(Debug, Serialize)]))]
|
||||
pub struct User {
|
||||
#[serde(
|
||||
default,
|
||||
@@ -54,6 +55,7 @@ pub struct User {
|
||||
}
|
||||
|
||||
#[derive(Serialize, Deserialize, Debug, Clone, Default, PartialEq, Diff)]
|
||||
#[diff(attr(#[derive(Debug, Serialize)]))]
|
||||
pub struct ApiSecret {
|
||||
pub name: String,
|
||||
pub hash: String,
|
||||
@@ -62,6 +64,7 @@ pub struct ApiSecret {
|
||||
}
|
||||
|
||||
#[derive(Serialize, Deserialize, Debug, Clone, Diff)]
|
||||
#[diff(attr(#[derive(Debug, Serialize)]))]
|
||||
pub struct Server {
|
||||
#[serde(
|
||||
default,
|
||||
@@ -121,6 +124,7 @@ fn default_disk_alert() -> f64 {
|
||||
}
|
||||
|
||||
#[derive(Serialize, Deserialize, Debug, Clone, Default, Diff)]
|
||||
#[diff(attr(#[derive(Debug, Serialize)]))]
|
||||
pub struct Deployment {
|
||||
#[serde(
|
||||
default,
|
||||
@@ -146,6 +150,7 @@ pub struct Deployment {
|
||||
}
|
||||
|
||||
#[derive(Serialize, Deserialize, Debug, Clone, Default, Diff)]
|
||||
#[diff(attr(#[derive(Debug, Serialize)]))]
|
||||
pub struct Build {
|
||||
#[serde(
|
||||
default,
|
||||
@@ -192,15 +197,16 @@ pub struct Update {
|
||||
pub id: String,
|
||||
pub target: UpdateTarget,
|
||||
pub operation: Operation,
|
||||
pub log: Vec<Log>,
|
||||
pub logs: Vec<Log>,
|
||||
pub start_ts: i64,
|
||||
pub end_ts: Option<i64>,
|
||||
pub status: UpdateStatus,
|
||||
pub is_error: bool,
|
||||
pub success: bool,
|
||||
pub operator: String,
|
||||
}
|
||||
|
||||
#[derive(Serialize, Deserialize, Debug, Clone, Diff)]
|
||||
#[diff(attr(#[derive(Debug, Serialize)]))]
|
||||
pub struct Procedure {
|
||||
#[serde(
|
||||
default,
|
||||
@@ -215,12 +221,14 @@ pub struct Procedure {
|
||||
}
|
||||
|
||||
#[derive(Serialize, Deserialize, Debug, Clone, PartialEq, Diff)]
|
||||
#[diff(attr(#[derive(Debug, Serialize)]))]
|
||||
pub struct DockerBuildArgs {
|
||||
pub build_path: String,
|
||||
pub dockerfile_path: Option<String>,
|
||||
}
|
||||
|
||||
#[derive(Serialize, Deserialize, Debug, Clone, Default, Diff)]
|
||||
#[diff(attr(#[derive(Debug, PartialEq, Serialize)]))]
|
||||
pub struct DockerRunArgs {
|
||||
pub image: String,
|
||||
pub ports: Vec<Conversion>,
|
||||
@@ -282,9 +290,10 @@ impl Log {
|
||||
}
|
||||
}
|
||||
|
||||
pub fn error(msg: String) -> Log {
|
||||
pub fn error(stage: &str, msg: String) -> Log {
|
||||
let ts = unix_timestamp_ms() as i64;
|
||||
Log {
|
||||
stage: stage.to_string(),
|
||||
stderr: msg,
|
||||
start_ts: ts,
|
||||
end_ts: ts,
|
||||
@@ -294,13 +303,15 @@ impl Log {
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Serialize, Deserialize, Debug, Clone, PartialEq, Diff)]
|
||||
#[derive(Serialize, Deserialize, Debug, Clone, PartialEq, Eq, Diff)]
|
||||
#[diff(attr(#[derive(Debug, PartialEq, Serialize)]))]
|
||||
pub struct Command {
|
||||
pub path: String,
|
||||
pub command: String,
|
||||
}
|
||||
|
||||
#[derive(Serialize, Deserialize, Debug, Clone, Default, PartialEq, Diff)]
|
||||
#[diff(attr(#[derive(Debug, PartialEq, Serialize)]))]
|
||||
pub struct Version {
|
||||
pub major: u64,
|
||||
pub minor: u64,
|
||||
@@ -313,12 +324,14 @@ impl ToString for Version {
|
||||
}
|
||||
|
||||
#[derive(Serialize, Deserialize, Debug, Clone, Default, PartialEq, Diff)]
|
||||
#[diff(attr(#[derive(Debug, PartialEq, Serialize)]))]
|
||||
pub struct Conversion {
|
||||
pub local: String,
|
||||
pub container: String,
|
||||
}
|
||||
|
||||
#[derive(Serialize, Deserialize, Debug, Clone, Default, PartialEq, Diff)]
|
||||
#[diff(attr(#[derive(Debug, PartialEq, Serialize)]))]
|
||||
pub struct EnvironmentVar {
|
||||
pub variable: String,
|
||||
pub value: String,
|
||||
@@ -477,9 +490,12 @@ impl Default for UpdateStatus {
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Serialize, Deserialize, Debug, Display, EnumString, PartialEq, Hash, Eq, Clone, Copy, Diff)]
|
||||
#[derive(
|
||||
Serialize, Deserialize, Debug, Display, EnumString, PartialEq, Hash, Eq, Clone, Copy, Diff,
|
||||
)]
|
||||
#[serde(rename_all = "snake_case")]
|
||||
#[strum(serialize_all = "snake_case")]
|
||||
#[diff(attr(#[derive(Debug, PartialEq, Serialize)]))]
|
||||
pub enum Operation {
|
||||
// do nothing
|
||||
None,
|
||||
@@ -521,6 +537,7 @@ impl Default for Operation {
|
||||
)]
|
||||
#[serde(rename_all = "snake_case")]
|
||||
#[strum(serialize_all = "snake_case")]
|
||||
#[diff(attr(#[derive(Debug, PartialEq, Serialize)]))]
|
||||
pub enum PermissionLevel {
|
||||
None,
|
||||
Read,
|
||||
@@ -561,7 +578,10 @@ pub enum DockerContainerState {
|
||||
Dead,
|
||||
}
|
||||
|
||||
#[derive(Serialize, Deserialize, Debug, Display, EnumString, PartialEq, Hash, Eq, Clone, Copy, Diff)]
|
||||
#[derive(
|
||||
Serialize, Deserialize, Debug, Display, EnumString, PartialEq, Hash, Eq, Clone, Copy, Diff,
|
||||
)]
|
||||
#[diff(attr(#[derive(Debug, PartialEq, Serialize)]))]
|
||||
pub enum RestartMode {
|
||||
#[serde(rename = "no")]
|
||||
NoRestart,
|
||||
|
||||
Reference in New Issue
Block a user