update build

This commit is contained in:
beckerinj
2022-12-05 02:58:04 -05:00
parent 1674825a94
commit 16aa58482f
8 changed files with 184 additions and 50 deletions
Generated
+1
View File
@@ -361,6 +361,7 @@ dependencies = [
"axum-extra",
"bcrypt",
"db_client",
"diff-struct",
"dotenv",
"envy",
"futures-util",
+2 -1
View File
@@ -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
View File
@@ -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(&current_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(())
}
+9 -5
View File
@@ -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
View File
@@ -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(())
}
+9 -5
View File
@@ -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(
+67
View File
@@ -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
View File
@@ -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,