diff --git a/.vscode/tasks.json b/.vscode/tasks.json index a1dcad207..0c7116529 100644 --- a/.vscode/tasks.json +++ b/.vscode/tasks.json @@ -129,6 +129,12 @@ "cwd": "${workspaceFolder}/tests" }, "problemMatcher": [] + }, + { + "type": "shell", + "command": "typeshare ./lib/types --lang=typescript --output-file=types.d.ts", + "label": "generate typescript types", + "problemMatcher": [] } ] } \ No newline at end of file diff --git a/Cargo.lock b/Cargo.lock index c60855ef5..2678505c8 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -282,9 +282,9 @@ checksum = "baf1de4339761588bc0619e3cbc0120ee582ebb74b53b4efbf79117bd2da40fd" [[package]] name = "chrono" -version = "0.4.22" +version = "0.4.23" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "bfd4d1b31faaa3a89d7934dbded3111da0d2ef28e3ebccdb4f0179f5929d1ef1" +checksum = "16b0a3d9ed01224b22057780a37bb8c5dbfe1be8ba48678e7bf57ec4b385411f" dependencies = [ "iana-time-zone", "js-sys", @@ -1350,15 +1350,18 @@ dependencies = [ name = "monitor_types" version = "0.1.1" dependencies = [ + "anyhow", "async_timing_util", "bollard", "bson", + "chrono", "derive_builder", "diff-struct", "serde", "serde_derive", "strum", "strum_macros", + "typeshare", ] [[package]] @@ -2597,6 +2600,28 @@ version = "1.15.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "dcf81ac59edc17cc8697ff311e8f5ef2d99fcbd9817b34cec66f90b6c3dfd987" +[[package]] +name = "typeshare" +version = "1.0.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d7f096d7253207ace684191e2c22d6480345975c15bbccd7c14d5de713f08bd6" +dependencies = [ + "chrono", + "serde", + "serde_json", + "typeshare-annotation", +] + +[[package]] +name = "typeshare-annotation" +version = "1.0.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "389b0235d70d7c762268e3b693e5efbe0879b036de868a39188309e2ced169ec" +dependencies = [ + "quote", + "syn", +] + [[package]] name = "unicase" version = "2.6.0" diff --git a/cli/Cargo.toml b/cli/Cargo.toml index fc8ed73e8..779771960 100644 --- a/cli/Cargo.toml +++ b/cli/Cargo.toml @@ -3,6 +3,10 @@ name = "monitor_cli" version = "0.1.0" edition = "2021" +[[bin]] +name = "monitor" +path = "src/main.rs" + # See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html [dependencies] diff --git a/core/src/actions/build.rs b/core/src/actions/build.rs index 266828dae..242c11ef4 100644 --- a/core/src/actions/build.rs +++ b/core/src/actions/build.rs @@ -1,11 +1,10 @@ use anyhow::{anyhow, Context}; -use async_timing_util::unix_timestamp_ms; use diff::Diff; use helpers::to_monitor_name; use mungos::{doc, to_bson}; use types::{ traits::Permissioned, Build, Log, Operation, PermissionLevel, Update, UpdateStatus, - UpdateTarget, + UpdateTarget, monitor_timestamp, }; use crate::{ @@ -40,18 +39,17 @@ impl State { ) -> anyhow::Result { self.get_server_check_permissions(&server_id, user, PermissionLevel::Write) .await?; - let start_ts = unix_timestamp_ms() as i64; + let start_ts = monitor_timestamp(); let build = Build { name: to_monitor_name(name), server_id, permissions: [(user.id.clone(), PermissionLevel::Write)] .into_iter() .collect(), - created_at: start_ts, - updated_at: start_ts, + created_at: start_ts.clone(), + updated_at: start_ts.clone(), ..Default::default() }; - let start_ts = unix_timestamp_ms() as i64; let build_id = self .db .builds @@ -63,7 +61,7 @@ impl State { target: UpdateTarget::Build(build_id), operation: Operation::CreateBuild, start_ts, - end_ts: Some(unix_timestamp_ms() as i64), + end_ts: Some(monitor_timestamp()), operator: user.id.clone(), success: true, ..Default::default() @@ -89,7 +87,7 @@ impl State { let build = self .get_build_check_permissions(build_id, user, PermissionLevel::Write) .await?; - let start_ts = unix_timestamp_ms() as i64; + let start_ts = monitor_timestamp(); let server = self.db.get_server(&build.server_id).await?; let delete_repo_log = self .periphery @@ -101,7 +99,7 @@ impl State { target: UpdateTarget::System, operation: Operation::DeleteDeployment, start_ts, - end_ts: Some(unix_timestamp_ms() as i64), + end_ts: Some(monitor_timestamp()), operator: user.id.clone(), logs: vec![ delete_repo_log, @@ -125,14 +123,14 @@ impl State { let current_build = self .get_build_check_permissions(&new_build.id, user, PermissionLevel::Write) .await?; - let start_ts = unix_timestamp_ms() as i64; + let start_ts = monitor_timestamp(); // none of these should be changed through this method new_build.name = current_build.name.clone(); new_build.permissions = current_build.permissions.clone(); new_build.server_id = current_build.server_id.clone(); - new_build.created_at = current_build.created_at; - new_build.updated_at = start_ts; + new_build.created_at = current_build.created_at.clone(); + new_build.updated_at = start_ts.clone(); self.db .builds @@ -172,7 +170,7 @@ impl State { } } - update.end_ts = Some(unix_timestamp_ms() as i64); + update.end_ts = Some(monitor_timestamp()); update.success = all_logs_success(&update.logs); update.status = UpdateStatus::Complete; @@ -191,7 +189,7 @@ impl State { let mut update = Update { target: UpdateTarget::Build(build_id.to_string()), operation: Operation::BuildBuild, - start_ts: unix_timestamp_ms() as i64, + start_ts: monitor_timestamp(), status: UpdateStatus::InProgress, operator: user.id.clone(), success: true, @@ -231,7 +229,7 @@ impl State { } } update.status = UpdateStatus::Complete; - update.end_ts = Some(unix_timestamp_ms() as i64); + update.end_ts = Some(monitor_timestamp()); self.update_update(update.clone()).await?; Ok(update) } @@ -248,7 +246,7 @@ impl State { let mut update = Update { target: UpdateTarget::Build(build_id.to_string()), operation: Operation::RecloneBuild, - start_ts: unix_timestamp_ms() as i64, + start_ts: monitor_timestamp(), status: UpdateStatus::InProgress, operator: user.id.clone(), success: true, @@ -270,7 +268,7 @@ impl State { }; update.status = UpdateStatus::Complete; - update.end_ts = Some(unix_timestamp_ms() as i64); + update.end_ts = Some(monitor_timestamp()); self.update_update(update.clone()).await?; diff --git a/core/src/actions/deployment.rs b/core/src/actions/deployment.rs index 96ec6278c..74e6cbbd4 100644 --- a/core/src/actions/deployment.rs +++ b/core/src/actions/deployment.rs @@ -1,10 +1,9 @@ use anyhow::{anyhow, Context}; -use async_timing_util::unix_timestamp_ms; use diff::Diff; use helpers::to_monitor_name; use types::{ traits::Permissioned, Deployment, Log, Operation, PermissionLevel, Update, UpdateStatus, - UpdateTarget, + UpdateTarget, monitor_timestamp, }; use crate::{ @@ -39,15 +38,15 @@ impl State { ) -> anyhow::Result { self.get_server_check_permissions(&server_id, user, PermissionLevel::Write) .await?; - let start_ts = unix_timestamp_ms() as i64; + let start_ts = monitor_timestamp(); let deployment = Deployment { name: to_monitor_name(name), server_id, permissions: [(user.id.clone(), PermissionLevel::Write)] .into_iter() .collect(), - created_at: start_ts, - updated_at: start_ts, + created_at: start_ts.clone(), + updated_at: start_ts.clone(), ..Default::default() }; let deployment_id = self @@ -61,7 +60,7 @@ impl State { target: UpdateTarget::Deployment(deployment_id), operation: Operation::CreateDeployment, start_ts, - end_ts: Some(unix_timestamp_ms() as i64), + end_ts: Some(monitor_timestamp()), operator: user.id.clone(), success: true, ..Default::default() @@ -91,7 +90,7 @@ impl State { let deployment = self .get_deployment_check_permissions(deployment_id, user, PermissionLevel::Write) .await?; - let start_ts = unix_timestamp_ms() as i64; + let start_ts = monitor_timestamp(); let server = self.db.get_server(&deployment.server_id).await?; let log = self .periphery @@ -108,7 +107,7 @@ impl State { target: UpdateTarget::System, operation: Operation::DeleteDeployment, start_ts, - end_ts: Some(unix_timestamp_ms() as i64), + end_ts: Some(monitor_timestamp()), operator: user.id.clone(), logs: vec![ log, @@ -135,14 +134,14 @@ impl State { let current_deployment = self .get_deployment_check_permissions(&new_deployment.id, user, PermissionLevel::Write) .await?; - let start_ts = unix_timestamp_ms() as i64; + let start_ts = monitor_timestamp(); // none of these should be changed through this method new_deployment.name = current_deployment.name.clone(); new_deployment.permissions = current_deployment.permissions.clone(); new_deployment.server_id = current_deployment.server_id.clone(); - new_deployment.created_at = current_deployment.created_at; - new_deployment.updated_at = start_ts; + new_deployment.created_at = current_deployment.created_at.clone(); + new_deployment.updated_at = start_ts.clone(); self.db .deployments @@ -185,7 +184,7 @@ impl State { } } - update.end_ts = Some(unix_timestamp_ms() as i64); + update.end_ts = Some(monitor_timestamp()); update.success = all_logs_success(&update.logs); update.status = UpdateStatus::Complete; @@ -206,7 +205,7 @@ impl State { let mut update = Update { target: UpdateTarget::Deployment(deployment_id.to_string()), operation: Operation::RecloneDeployment, - start_ts: unix_timestamp_ms() as i64, + start_ts: monitor_timestamp(), status: UpdateStatus::InProgress, operator: user.id.clone(), success: true, @@ -228,7 +227,7 @@ impl State { }; update.status = UpdateStatus::Complete; - update.end_ts = Some(unix_timestamp_ms() as i64); + update.end_ts = Some(monitor_timestamp()); self.update_update(update.clone()).await?; @@ -264,7 +263,7 @@ impl State { let mut update = Update { target: UpdateTarget::Deployment(deployment_id.to_string()), operation: Operation::DeployContainer, - start_ts: unix_timestamp_ms() as i64, + start_ts: monitor_timestamp(), status: UpdateStatus::InProgress, operator: user.id.clone(), success: true, @@ -278,7 +277,7 @@ impl State { update.success = deploy_log.success; update.logs.push(deploy_log); update.status = UpdateStatus::Complete; - update.end_ts = Some(unix_timestamp_ms() as i64); + update.end_ts = Some(monitor_timestamp()); self.update_update(update.clone()).await?; @@ -290,7 +289,7 @@ impl State { deployment_id: &str, user: &RequestUser, ) -> anyhow::Result { - let start_ts = unix_timestamp_ms() as i64; + let start_ts = monitor_timestamp(); let deployment = self .get_deployment_check_permissions(deployment_id, user, PermissionLevel::Write) .await?; @@ -325,7 +324,7 @@ impl State { } }; - update.end_ts = Some(unix_timestamp_ms() as i64); + update.end_ts = Some(monitor_timestamp()); update.status = UpdateStatus::Complete; self.update_update(update.clone()).await?; @@ -338,7 +337,7 @@ impl State { deployment_id: &str, user: &RequestUser, ) -> anyhow::Result { - let start_ts = unix_timestamp_ms() as i64; + let start_ts = monitor_timestamp(); let deployment = self .get_deployment_check_permissions(deployment_id, user, PermissionLevel::Write) .await?; @@ -373,7 +372,7 @@ impl State { } }; - update.end_ts = Some(unix_timestamp_ms() as i64); + update.end_ts = Some(monitor_timestamp()); update.status = UpdateStatus::Complete; self.update_update(update.clone()).await?; @@ -386,7 +385,7 @@ impl State { deployment_id: &str, user: &RequestUser, ) -> anyhow::Result { - let start_ts = unix_timestamp_ms() as i64; + let start_ts = monitor_timestamp(); let deployment = self .get_deployment_check_permissions(deployment_id, user, PermissionLevel::Write) .await?; @@ -421,7 +420,7 @@ impl State { } }; - update.end_ts = Some(unix_timestamp_ms() as i64); + update.end_ts = Some(monitor_timestamp()); update.status = UpdateStatus::Complete; self.update_update(update.clone()).await?; diff --git a/core/src/actions/procedure.rs b/core/src/actions/procedure.rs index 70f060885..9f07c5470 100644 --- a/core/src/actions/procedure.rs +++ b/core/src/actions/procedure.rs @@ -1,10 +1,9 @@ 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, ProcedureOperation::*, - ProcedureStage, Update, UpdateStatus, UpdateTarget, + ProcedureStage, Update, UpdateStatus, UpdateTarget, monitor_timestamp, }; use crate::{auth::RequestUser, state::State}; @@ -32,14 +31,14 @@ impl State { name: &str, user: &RequestUser, ) -> anyhow::Result { - let start_ts = unix_timestamp_ms() as i64; + let start_ts = monitor_timestamp(); let procedure = Procedure { name: to_monitor_name(name), permissions: [(user.id.clone(), PermissionLevel::Write)] .into_iter() .collect(), - created_at: start_ts, - updated_at: start_ts, + created_at: start_ts.clone(), + updated_at: start_ts.clone(), ..Default::default() }; let procedure_id = self @@ -53,7 +52,7 @@ impl State { target: UpdateTarget::Procedure(procedure_id), operation: Operation::CreateProcedure, start_ts, - end_ts: Some(unix_timestamp_ms() as i64), + end_ts: Some(monitor_timestamp()), operator: user.id.clone(), success: true, ..Default::default() @@ -81,7 +80,7 @@ impl State { let procedure = self .get_procedure_check_permissions(id, user, PermissionLevel::Write) .await?; - let start_ts = unix_timestamp_ms() as i64; + let start_ts = monitor_timestamp(); self.db .procedures .delete_one(id) @@ -91,7 +90,7 @@ impl State { target: UpdateTarget::System, operation: Operation::DeleteProcedure, start_ts, - end_ts: Some(unix_timestamp_ms() as i64), + end_ts: Some(monitor_timestamp()), operator: user.id.clone(), logs: vec![Log::simple( "delete deployment", @@ -112,13 +111,13 @@ impl State { let current_procedure = self .get_procedure_check_permissions(&new_procedure.id, user, PermissionLevel::Write) .await?; - let start_ts = unix_timestamp_ms() as i64; + let start_ts = monitor_timestamp(); // 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; + new_procedure.created_at = current_procedure.created_at.clone(); + new_procedure.updated_at = start_ts.clone(); // check to make sure no stages have been added that user does not have access to @@ -136,7 +135,7 @@ impl State { let update = Update { operation: Operation::UpdateProcedure, target: UpdateTarget::Procedure(new_procedure.id.clone()), - end_ts: Some(start_ts), + end_ts: Some(start_ts.clone()), start_ts, status: UpdateStatus::Complete, logs: vec![Log::simple( diff --git a/core/src/actions/server.rs b/core/src/actions/server.rs index 531d3fd71..82851fa8a 100644 --- a/core/src/actions/server.rs +++ b/core/src/actions/server.rs @@ -1,10 +1,9 @@ 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, Server, Update, UpdateStatus, - UpdateTarget, + UpdateTarget, monitor_timestamp, }; use crate::{auth::RequestUser, state::State}; @@ -38,15 +37,15 @@ impl State { "user does not have permissions to add server (not admin)" )); } - let start_ts = unix_timestamp_ms() as i64; + let start_ts = monitor_timestamp(); let server = Server { name: to_monitor_name(name), address, permissions: [(user.id.clone(), PermissionLevel::Write)] .into_iter() .collect(), - created_at: start_ts, - updated_at: start_ts, + created_at: start_ts.clone(), + updated_at: start_ts.clone(), ..Default::default() }; let server_id = self @@ -60,7 +59,7 @@ impl State { target: UpdateTarget::Server(server_id), operation: Operation::CreateServer, start_ts, - end_ts: Some(unix_timestamp_ms() as i64), + end_ts: Some(monitor_timestamp()), operator: user.id.clone(), success: true, ..Default::default() @@ -91,13 +90,13 @@ impl State { let server = self .get_server_check_permissions(server_id, user, PermissionLevel::Write) .await?; - let start_ts = unix_timestamp_ms() as i64; + let start_ts = monitor_timestamp(); self.db.servers.delete_one(&server_id).await?; let update = Update { target: UpdateTarget::System, operation: Operation::DeleteServer, start_ts, - end_ts: Some(unix_timestamp_ms() as i64), + end_ts: Some(monitor_timestamp()), operator: user.id.clone(), logs: vec![Log::simple( "delete server", @@ -118,11 +117,11 @@ impl State { let current_server = self .get_server_check_permissions(&new_server.id, user, PermissionLevel::Write) .await?; - let start_ts = unix_timestamp_ms() as i64; + let start_ts = monitor_timestamp(); new_server.permissions = current_server.permissions.clone(); - new_server.created_at = current_server.created_at; - new_server.updated_at = start_ts; + new_server.created_at = current_server.created_at.clone(); + new_server.updated_at = start_ts.clone(); let diff = current_server.diff(&new_server); @@ -136,7 +135,7 @@ impl State { operation: Operation::UpdateServer, target: UpdateTarget::Server(new_server.id.clone()), start_ts, - end_ts: Some(unix_timestamp_ms() as i64), + end_ts: Some(monitor_timestamp()), status: UpdateStatus::Complete, logs: vec![Log::simple( "server update", diff --git a/core/src/api/secret.rs b/core/src/api/secret.rs index 7715a0dc3..9f979c764 100644 --- a/core/src/api/secret.rs +++ b/core/src/api/secret.rs @@ -1,5 +1,4 @@ use anyhow::{anyhow, Context}; -use async_timing_util::unix_timestamp_ms; use axum::{ extract::Path, routing::{delete, post}, @@ -7,7 +6,7 @@ use axum::{ }; use helpers::{generate_secret, handle_anyhow_error}; use mungos::{doc, to_bson, Deserialize, Document, Update}; -use types::ApiSecret; +use types::{monitor_timestamp, ApiSecret}; use crate::{auth::RequestUserExtension, state::StateExtension}; @@ -17,7 +16,7 @@ const BCRYPT_COST: u32 = 10; #[derive(Deserialize)] struct CreateSecretBody { name: String, - expires: Option, + expires: Option, } #[derive(Deserialize)] @@ -50,7 +49,7 @@ impl Into for CreateSecretBody { ApiSecret { name: self.name, expires: self.expires, - created_at: unix_timestamp_ms() as i64, + created_at: monitor_timestamp(), ..Default::default() } } diff --git a/core/src/auth/jwt.rs b/core/src/auth/jwt.rs index 634d82311..67b10e0df 100644 --- a/core/src/auth/jwt.rs +++ b/core/src/auth/jwt.rs @@ -7,7 +7,7 @@ use hmac::{Hmac, Mac}; use jwt::{SignWithKey, VerifyWithKey}; use mungos::{Deserialize, Serialize}; use sha2::Sha256; -use types::{CoreConfig, UserId}; +use types::CoreConfig; use crate::state::State; @@ -22,7 +22,7 @@ pub struct RequestUser { #[derive(Serialize, Deserialize)] pub struct JwtClaims { - pub id: UserId, + pub id: String, pub iat: u128, pub exp: u128, } diff --git a/core/src/auth/secret.rs b/core/src/auth/secret.rs index c575cd883..0f9e8d768 100644 --- a/core/src/auth/secret.rs +++ b/core/src/auth/secret.rs @@ -3,6 +3,7 @@ use async_timing_util::unix_timestamp_ms; use axum::{routing::post, Extension, Json, Router}; use helpers::handle_anyhow_error; use mungos::{doc, Deserialize, Document, Update}; +use types::unix_from_monitor_ts; use crate::state::StateExtension; @@ -36,6 +37,7 @@ pub async fn login( let ts = unix_timestamp_ms() as i64; for s in user.secrets { if let Some(expires) = s.expires { + let expires = unix_from_monitor_ts(&expires)?; if expires < ts { state .db diff --git a/lib/helpers/Cargo.toml b/lib/helpers/Cargo.toml index 8ebe81680..da74ef4a3 100644 --- a/lib/helpers/Cargo.toml +++ b/lib/helpers/Cargo.toml @@ -18,4 +18,4 @@ toml = "0.5" run_command = { version = "0.0.5", features = ["async_tokio"] } rand = "0.8" futures = "0.3" -futures-util = "0.3.25" \ No newline at end of file +futures-util = "0.3.25" diff --git a/lib/helpers/src/git.rs b/lib/helpers/src/git.rs index d035cf285..cc9fdf00c 100644 --- a/lib/helpers/src/git.rs +++ b/lib/helpers/src/git.rs @@ -2,9 +2,8 @@ use std::{path::PathBuf, str::FromStr}; use ::run_command::async_run_command; use anyhow::anyhow; -use async_timing_util::unix_timestamp_ms; use serde::{Deserialize, Serialize}; -use types::{Build, Command, Deployment, GithubToken, GithubUsername, Log}; +use types::{monitor_timestamp, Build, Command, Deployment, GithubToken, GithubUsername, Log}; use crate::{run_monitor_command, to_monitor_name}; @@ -98,7 +97,7 @@ async fn clone( }; let repo_url = format!("https://{access_token}github.com/{repo}.git"); let command = format!("git clone {repo_url} {destination}{branch}"); - let start_ts = unix_timestamp_ms() as i64; + let start_ts = monitor_timestamp(); let output = async_run_command(&command).await; let command = if access_token.len() > 0 { command.replace(&access_token, "") @@ -112,6 +111,6 @@ async fn clone( stdout: output.stdout, stderr: output.stderr, start_ts, - end_ts: unix_timestamp_ms() as i64, + end_ts: monitor_timestamp(), } } diff --git a/lib/helpers/src/lib.rs b/lib/helpers/src/lib.rs index e0c82d0f1..fc0bbdc98 100644 --- a/lib/helpers/src/lib.rs +++ b/lib/helpers/src/lib.rs @@ -1,12 +1,11 @@ use std::{fs::File, io::Read, net::SocketAddr, str::FromStr}; use anyhow::Context; -use async_timing_util::unix_timestamp_ms; use axum::http::StatusCode; use rand::{distributions::Alphanumeric, Rng}; use run_command::{async_run_command, CommandOutput}; use serde::de::DeserializeOwned; -use types::Log; +use types::{monitor_timestamp, Log}; pub mod docker; pub mod git; @@ -26,7 +25,12 @@ pub fn parse_config_file(path: &str) -> anyhow::Result { Ok(config) } -pub fn output_into_log(stage: &str, command: String, start_ts: i64, output: CommandOutput) -> Log { +pub fn output_into_log( + stage: &str, + command: String, + start_ts: String, + output: CommandOutput, +) -> Log { let success = output.success(); Log { stage: stage.to_string(), @@ -35,7 +39,7 @@ pub fn output_into_log(stage: &str, command: String, start_ts: i64, output: Comm command, success, start_ts, - end_ts: unix_timestamp_ms() as i64, + end_ts: monitor_timestamp(), } } @@ -48,7 +52,7 @@ pub fn to_monitor_name(name: &str) -> String { } pub async fn run_monitor_command(stage: &str, command: String) -> Log { - let start_ts = unix_timestamp_ms() as i64; + let start_ts = monitor_timestamp(); let output = async_run_command(&command).await; output_into_log(stage, command, start_ts, output) } diff --git a/lib/types/Cargo.toml b/lib/types/Cargo.toml index 1ffa51142..90419d872 100644 --- a/lib/types/Cargo.toml +++ b/lib/types/Cargo.toml @@ -17,4 +17,7 @@ strum_macros = "0.24" async_timing_util = "0.1.12" diff-struct = "0.5" bollard = "0.13" -derive_builder = "0.12" \ No newline at end of file +derive_builder = "0.12" +typeshare = "1.0.0" +chrono = "0.4" +anyhow = "1.0" \ No newline at end of file diff --git a/lib/types/src/lib.rs b/lib/types/src/lib.rs index a9663e086..725b57f12 100644 --- a/lib/types/src/lib.rs +++ b/lib/types/src/lib.rs @@ -1,24 +1,21 @@ use std::{collections::HashMap, path::PathBuf}; -use async_timing_util::{unix_timestamp_ms, Timelength}; +use anyhow::Context; +use async_timing_util::Timelength; use bson::serde_helpers::hex_string_as_object_id; +use chrono::{DateTime, Utc}; use derive_builder::Builder; use diff::{Diff, HashMapDiff, OptionDiff, VecDiff}; use serde::{Deserialize, Serialize}; use strum_macros::{Display, EnumString}; pub use bollard::service::{ImageSummary, Network}; +use typeshare::typeshare; pub mod traits; pub const PERIPHERY_BUILDER_BUSY: &str = "builder is busy"; -pub type UserId = String; -pub type ServerId = String; -pub type DeploymentId = String; -pub type BuildId = String; -pub type ProcedureId = String; - pub type GithubUsername = String; pub type GithubToken = String; pub type GithubAccounts = HashMap; @@ -29,8 +26,10 @@ pub type DockerAccounts = HashMap; pub type SecretsMap = HashMap; // these are used for injection into deployments run commands -pub type PermissionsMap = HashMap; +#[typeshare] +pub type PermissionsMap = HashMap; +#[typeshare] #[derive(Serialize, Deserialize, Debug, Clone, Default, Diff)] #[diff(attr(#[derive(Debug, Serialize)]))] pub struct User { @@ -70,7 +69,7 @@ pub struct User { #[serde(skip_serializing_if = "Option::is_none")] #[diff(attr(#[serde(skip_serializing_if = "option_diff_no_change")]))] - pub github_id: Option, + pub github_id: Option, #[serde(skip_serializing_if = "Option::is_none")] #[diff(attr(#[serde(skip_serializing_if = "option_diff_no_change")]))] @@ -78,21 +77,23 @@ pub struct User { #[serde(default)] #[diff(attr(#[serde(skip)]))] - pub created_at: i64, + pub created_at: String, #[serde(default)] #[diff(attr(#[serde(skip)]))] - pub updated_at: i64, + pub updated_at: String, } +#[typeshare] #[derive(Serialize, Deserialize, Debug, Clone, Default, PartialEq, Diff)] #[diff(attr(#[derive(Debug, Serialize)]))] pub struct ApiSecret { pub name: String, pub hash: String, - pub created_at: i64, - pub expires: Option, + pub created_at: String, + pub expires: Option, } +#[typeshare] #[derive(Serialize, Deserialize, Debug, Clone, Diff, Builder)] #[diff(attr(#[derive(Debug, Serialize)]))] pub struct Server { @@ -130,7 +131,7 @@ pub struct Server { #[serde(skip_serializing_if = "Option::is_none")] #[diff(attr(#[serde(skip_serializing_if = "option_diff_no_change")]))] - pub stats_interval: Option, + pub stats_interval: Option, #[serde(skip_serializing_if = "Option::is_none")] #[diff(attr(#[serde(skip_serializing_if = "option_diff_no_change")]))] @@ -143,11 +144,11 @@ pub struct Server { #[serde(default)] #[diff(attr(#[serde(skip)]))] #[builder(setter(skip))] - pub created_at: i64, + pub created_at: String, #[serde(default)] #[diff(attr(#[serde(skip)]))] #[builder(setter(skip))] - pub updated_at: i64, + pub updated_at: String, } impl Default for Server { @@ -182,6 +183,7 @@ fn default_disk_alert() -> f64 { 75.0 } +#[typeshare] #[derive(Serialize, Deserialize, Debug, Clone, Default, Diff, Builder)] #[diff(attr(#[derive(Debug, Serialize)]))] pub struct Deployment { @@ -199,7 +201,7 @@ pub struct Deployment { pub name: String, // must be formatted to be compat with docker #[diff(attr(#[serde(skip_serializing_if = "Option::is_none")]))] - pub server_id: ServerId, + pub server_id: String, #[serde(default)] #[diff(attr(#[serde(skip_serializing_if = "hashmap_diff_no_change")]))] @@ -211,7 +213,7 @@ pub struct Deployment { #[serde(skip_serializing_if = "Option::is_none")] #[diff(attr(#[serde(skip_serializing_if = "option_diff_no_change")]))] - pub build_id: Option, + pub build_id: Option, #[serde(skip_serializing_if = "Option::is_none")] #[diff(attr(#[serde(skip_serializing_if = "option_diff_no_change")]))] @@ -237,19 +239,21 @@ pub struct Deployment { #[serde(default)] #[diff(attr(#[serde(skip)]))] #[builder(setter(skip))] - pub created_at: i64, + pub created_at: String, #[serde(default)] #[diff(attr(#[serde(skip)]))] #[builder(setter(skip))] - pub updated_at: i64, + pub updated_at: String, } +#[typeshare] #[derive(Serialize, Deserialize, Debug, Clone, Default)] pub struct DeploymentWithContainer { pub deployment: Deployment, pub container: Option, } +#[typeshare] #[derive(Serialize, Deserialize, Debug, Clone, Default, Diff, Builder)] #[diff(attr(#[derive(Debug, Serialize)]))] pub struct Build { @@ -304,13 +308,14 @@ pub struct Build { #[serde(default)] #[diff(attr(#[serde(skip)]))] #[builder(setter(skip))] - pub created_at: i64, + pub created_at: String, #[serde(default)] #[diff(attr(#[serde(skip)]))] #[builder(setter(skip))] - pub updated_at: i64, + pub updated_at: String, } +#[typeshare] #[derive(Serialize, Deserialize, Debug, Clone, Default)] pub struct Update { #[serde( @@ -323,8 +328,8 @@ pub struct Update { pub target: UpdateTarget, pub operation: Operation, pub logs: Vec, - pub start_ts: i64, - pub end_ts: Option, + pub start_ts: String, + pub end_ts: Option, pub status: UpdateStatus, pub success: bool, pub operator: String, @@ -332,6 +337,7 @@ pub struct Update { pub version: Option, } +#[typeshare] #[derive(Serialize, Deserialize, Debug, Clone, Default, Diff, Builder)] #[diff(attr(#[derive(Debug, Serialize)]))] pub struct Procedure { @@ -351,13 +357,14 @@ pub struct Procedure { #[serde(default)] #[diff(attr(#[serde(skip)]))] #[builder(setter(skip))] - pub created_at: i64, + pub created_at: String, #[serde(default)] #[diff(attr(#[serde(skip)]))] #[builder(setter(skip))] - pub updated_at: i64, + pub updated_at: String, } +#[typeshare] #[derive(Serialize, Deserialize, Debug, Clone, Default, PartialEq, Diff)] #[diff(attr(#[derive(Debug, Serialize)]))] pub struct ProcedureStage { @@ -365,6 +372,7 @@ pub struct ProcedureStage { pub target_id: String, } +#[typeshare] #[derive(Serialize, Deserialize, Debug, Clone, PartialEq, Default, Diff, Builder)] #[diff(attr(#[derive(Debug, Serialize, PartialEq)]))] pub struct DockerBuildArgs { @@ -373,6 +381,7 @@ pub struct DockerBuildArgs { pub build_args: Vec, } +#[typeshare] #[derive(Serialize, Deserialize, Debug, Clone, Default, Diff, Builder)] #[diff(attr(#[derive(Debug, PartialEq, Serialize)]))] pub struct DockerRunArgs { @@ -404,6 +413,7 @@ pub struct DockerRunArgs { pub docker_account: Option, // the username of the dockerhub account } +#[typeshare] #[derive(Serialize, Deserialize, Debug, Clone)] pub struct BasicContainerInfo { pub name: String, @@ -412,6 +422,7 @@ pub struct BasicContainerInfo { pub status: Option, } +#[typeshare] #[derive(Serialize, Deserialize, Debug, Clone)] pub struct DockerContainerStats { #[serde(alias = "Name")] @@ -430,6 +441,7 @@ pub struct DockerContainerStats { pub pids: String, } +#[typeshare] #[derive(Serialize, Deserialize, Debug, Clone, Default)] pub struct Log { pub stage: String, @@ -437,29 +449,29 @@ pub struct Log { pub stdout: String, pub stderr: String, pub success: bool, - pub start_ts: i64, - pub end_ts: i64, + pub start_ts: String, + pub end_ts: String, } impl Log { pub fn simple(stage: &str, msg: String) -> Log { - let ts = unix_timestamp_ms() as i64; + let ts = monitor_timestamp(); Log { stage: stage.to_string(), stdout: msg, success: true, - start_ts: ts, + start_ts: ts.clone(), end_ts: ts, ..Default::default() } } pub fn error(stage: &str, msg: String) -> Log { - let ts = unix_timestamp_ms() as i64; + let ts = monitor_timestamp(); Log { stage: stage.to_string(), stderr: msg, - start_ts: ts, + start_ts: ts.clone(), end_ts: ts, success: false, ..Default::default() @@ -467,6 +479,7 @@ impl Log { } } +#[typeshare] #[derive(Serialize, Deserialize, Debug, Clone, PartialEq, Eq, Diff)] #[diff(attr(#[derive(Debug, PartialEq, Serialize)]))] pub struct Command { @@ -474,12 +487,13 @@ pub struct Command { pub command: String, } +#[typeshare] #[derive(Serialize, Deserialize, Debug, Clone, Default, PartialEq, Diff)] #[diff(attr(#[derive(Debug, PartialEq, Serialize)]))] pub struct Version { - pub major: u64, - pub minor: u64, - pub patch: u64, + pub major: i32, + pub minor: i32, + pub patch: i32, } impl ToString for Version { @@ -494,6 +508,7 @@ impl Version { } } +#[typeshare] #[derive(Serialize, Deserialize, Debug, Clone, Default, PartialEq, Diff)] #[diff(attr(#[derive(Debug, PartialEq, Serialize)]))] pub struct Conversion { @@ -501,6 +516,7 @@ pub struct Conversion { pub container: String, } +#[typeshare] #[derive(Serialize, Deserialize, Debug, Clone, Default, PartialEq, Diff)] #[diff(attr(#[derive(Debug, PartialEq, Serialize)]))] pub struct EnvironmentVar { @@ -583,12 +599,14 @@ fn default_repo_dir() -> String { "/repos".to_string() } +#[typeshare] #[derive(Deserialize, Debug)] pub struct UserCredentials { pub username: String, pub password: String, } +#[typeshare] #[derive(Serialize, Deserialize, Debug)] pub struct SystemStats { pub cpu_perc: f32, // in % @@ -598,6 +616,7 @@ pub struct SystemStats { pub networks: Vec, } +#[typeshare] #[derive(Serialize, Deserialize, Debug)] pub struct DiskUsage { pub used_gb: f64, // in GB @@ -607,6 +626,7 @@ pub struct DiskUsage { pub disks: Vec, } +#[typeshare] #[derive(Serialize, Deserialize, Debug)] pub struct SingleDiskUsage { pub mount: PathBuf, @@ -614,6 +634,7 @@ pub struct SingleDiskUsage { pub total_gb: f64, // in GB } +#[typeshare] #[derive(Serialize, Deserialize, Debug)] pub struct SystemNetwork { pub name: String, @@ -621,6 +642,7 @@ pub struct SystemNetwork { pub transmitted_kb: f64, // in kB } +#[typeshare] #[derive(Serialize, Deserialize, Debug, Display, EnumString, PartialEq, Hash, Eq, Clone, Copy)] #[serde(rename_all = "snake_case")] #[strum(serialize_all = "snake_case")] @@ -629,14 +651,15 @@ pub enum AccountType { Docker, } +#[typeshare] #[derive(Serialize, Deserialize, Debug, Clone)] #[serde(tag = "type", content = "id")] pub enum UpdateTarget { System, - Build(BuildId), - Deployment(DeploymentId), - Server(ServerId), - Procedure(ProcedureId), + Build(String), + Deployment(String), + Server(String), + Procedure(String), } impl Default for UpdateTarget { @@ -645,6 +668,7 @@ impl Default for UpdateTarget { } } +#[typeshare] #[derive(Serialize, Deserialize, Debug, Display, EnumString, PartialEq, Hash, Eq, Clone, Copy)] #[serde(rename_all = "snake_case")] #[strum(serialize_all = "snake_case")] @@ -660,6 +684,7 @@ impl Default for UpdateStatus { } } +#[typeshare] #[derive( Serialize, Deserialize, Debug, Display, EnumString, PartialEq, Hash, Eq, Clone, Copy, Diff, )] @@ -708,6 +733,7 @@ impl Default for Operation { } } +#[typeshare] #[derive( Serialize, Deserialize, Debug, Display, EnumString, PartialEq, Hash, Eq, Clone, Copy, Diff, )] @@ -745,6 +771,7 @@ impl Default for ProcedureOperation { } } +#[typeshare] #[derive( Serialize, Deserialize, @@ -781,6 +808,7 @@ impl Default for &PermissionLevel { } } +#[typeshare] #[derive(Serialize, Deserialize, Debug, Display, EnumString, PartialEq, Hash, Eq, Clone, Copy)] #[serde(rename_all = "snake_case")] #[strum(serialize_all = "snake_case")] @@ -790,6 +818,7 @@ pub enum PermissionsTarget { Build, } +#[typeshare] #[derive(Serialize, Deserialize, Debug, Display, EnumString, PartialEq, Hash, Eq, Clone, Copy)] #[serde(rename_all = "snake_case")] #[strum(serialize_all = "snake_case")] @@ -803,6 +832,7 @@ pub enum DockerContainerState { Dead, } +#[typeshare] #[derive( Serialize, Deserialize, Debug, Display, EnumString, PartialEq, Hash, Eq, Clone, Copy, Diff, )] @@ -858,3 +888,13 @@ fn docker_run_args_diff_no_change(dra: &DockerRunArgsDiff) -> bool { fn restart_mode_diff_no_change(restart_mode: &RestartModeDiff) -> bool { restart_mode == &RestartModeDiff::NoChange } + +pub fn monitor_timestamp() -> String { + Utc::now().to_rfc3339() +} + +pub fn unix_from_monitor_ts(ts: &str) -> anyhow::Result { + Ok(DateTime::parse_from_rfc3339(ts) + .context("failed to parse rfc3339 timestamp")? + .timestamp_millis()) +} diff --git a/types.d.ts b/types.d.ts new file mode 100644 index 000000000..2365cc7db --- /dev/null +++ b/types.d.ts @@ -0,0 +1,298 @@ +/* + Generated by typeshare 1.0.0 +*/ + +export type PermissionsMap = Record; + +export interface User { + _id?: string; + username: string; + enabled: boolean; + admin: boolean; + create_server_permissions: boolean; + avatar?: string; + secrets?: ApiSecret[]; + password?: string; + github_id?: string; + google_id?: string; + created_at?: string; + updated_at?: string; +} + +export interface ApiSecret { + name: string; + hash: string; + created_at: string; + expires?: string; +} + +export interface Server { + _id?: string; + name: string; + address: string; + permissions?: PermissionsMap; + to_notify?: string[]; + cpu_alert?: number; + mem_alert?: number; + disk_alert?: number; + stats_interval?: number; + region?: string; + instance_id?: string; + created_at?: string; + updated_at?: string; +} + +export interface Deployment { + _id?: string; + name: string; + server_id: string; + permissions?: PermissionsMap; + docker_run_args: DockerRunArgs; + build_id?: string; + build_version?: Version; + repo?: string; + branch?: string; + github_account?: string; + on_clone?: Command; + created_at?: string; + updated_at?: string; +} + +export interface DeploymentWithContainer { + deployment: Deployment; + container?: BasicContainerInfo; +} + +export interface Build { + _id?: string; + name: string; + permissions: PermissionsMap; + server_id: string; + version: Version; + repo?: string; + branch?: string; + github_account?: string; + on_clone?: Command; + pre_build?: Command; + docker_build_args?: DockerBuildArgs; + docker_account?: string; + created_at?: string; + updated_at?: string; +} + +export interface Update { + _id?: string; + target: UpdateTarget; + operation: Operation; + logs: Log[]; + start_ts: string; + end_ts?: string; + status: UpdateStatus; + success: boolean; + operator: string; + version?: Version; +} + +export interface Procedure { + _id?: string; + name: string; + stages: ProcedureStage[]; + permissions: PermissionsMap; + created_at?: string; + updated_at?: string; +} + +export interface ProcedureStage { + operation: ProcedureOperation; + target_id: string; +} + +export interface DockerBuildArgs { + build_path: string; + dockerfile_path?: string; + build_args: EnvironmentVar[]; +} + +export interface DockerRunArgs { + image: string; + ports: Conversion[]; + volumes: Conversion[]; + environment: EnvironmentVar[]; + network?: string; + restart: RestartMode; + post_image?: string; + container_user?: string; + docker_account?: string; +} + +export interface BasicContainerInfo { + name: string; + id: string; + state: DockerContainerState; + status?: string; +} + +export interface DockerContainerStats { + name: string; + cpu_perc: string; + mem_perc: string; + mem_usage: string; + net_io: string; + block_io: string; + pids: string; +} + +export interface Log { + stage: string; + command: string; + stdout: string; + stderr: string; + success: boolean; + start_ts: string; + end_ts: string; +} + +export interface Command { + path: string; + command: string; +} + +export interface Version { + major: number; + minor: number; + patch: number; +} + +export interface Conversion { + local: string; + container: string; +} + +export interface EnvironmentVar { + variable: string; + value: string; +} + +export interface UserCredentials { + username: string; + password: string; +} + +export interface SystemStats { + cpu_perc: number; + mem_used_gb: number; + mem_total_gb: number; + disk: DiskUsage; + networks: SystemNetwork[]; +} + +export interface DiskUsage { + used_gb: number; + total_gb: number; + read_kb: number; + write_kb: number; + disks: SingleDiskUsage[]; +} + +export interface SingleDiskUsage { + mount: string; + used_gb: number; + total_gb: number; +} + +export interface SystemNetwork { + name: string; + recieved_kb: number; + transmitted_kb: number; +} + +export enum AccountType { + Github = "github", + Docker = "docker", +} + +export type UpdateTarget = + | { type: "System", id?: undefined } + | { type: "Build", id: string } + | { type: "Deployment", id: string } + | { type: "Server", id: string } + | { type: "Procedure", id: string }; + +export enum UpdateStatus { + Queued = "queued", + InProgress = "in_progress", + Complete = "complete", +} + +export enum Operation { + None = "none", + CreateServer = "create_server", + UpdateServer = "update_server", + DeleteServer = "delete_server", + PruneImagesServer = "prune_images_server", + PruneContainersServer = "prune_containers_server", + PruneNetworksServer = "prune_networks_server", + CreateBuild = "create_build", + UpdateBuild = "update_build", + DeleteBuild = "delete_build", + BuildBuild = "build_build", + RecloneBuild = "reclone_build", + CreateDeployment = "create_deployment", + UpdateDeployment = "update_deployment", + DeleteDeployment = "delete_deployment", + DeployContainer = "deploy_container", + StopContainer = "stop_container", + StartContainer = "start_container", + RemoveContainer = "remove_container", + PullDeployment = "pull_deployment", + RecloneDeployment = "reclone_deployment", + CreateProcedure = "create_procedure", + UpdateProcedure = "update_procedure", + DeleteProcedure = "delete_procedure", +} + +export enum ProcedureOperation { + None = "none", + PruneImagesServer = "prune_images_server", + PruneContainersServer = "prune_containers_server", + PruneNetworksServer = "prune_networks_server", + BuildBuild = "build_build", + RecloneBuild = "reclone_build", + DeployContainer = "deploy_container", + StopContainer = "stop_container", + StartContainer = "start_container", + RemoveContainer = "remove_container", + PullDeployment = "pull_deployment", + RecloneDeployment = "reclone_deployment", + RunProcedure = "run_procedure", +} + +export enum PermissionLevel { + None = "none", + Read = "read", + Write = "write", +} + +export enum PermissionsTarget { + Server = "server", + Deployment = "deployment", + Build = "build", +} + +export enum DockerContainerState { + Created = "created", + Restarting = "restarting", + Running = "running", + Removing = "removing", + Paused = "paused", + Exited = "exited", + Dead = "dead", +} + +export enum RestartMode { + NoRestart = "no", + OnFailure = "on-failure", + Always = "always", + UnlessStopped = "unless-stopped", +} + diff --git a/typeshare.toml b/typeshare.toml new file mode 100644 index 000000000..e6d414b4a --- /dev/null +++ b/typeshare.toml @@ -0,0 +1,2 @@ +[typescript.type_mappings] +"PathBuf" = "string" \ No newline at end of file