Compare commits

...

6 Commits

Author SHA1 Message Date
mbecker20
575aa62625 update versions to 0.1.16 2023-02-21 04:32:41 +00:00
mbecker20
ac88a2c4ed testing and fixes for aws build 2023-02-21 04:27:30 +00:00
mbecker20
f1dcb71a8a poll periphery on build instance to ensure connectivity before moving on 2023-02-20 22:56:22 +00:00
mbecker20
30d04bc201 support building on epheral ec2 2023-02-20 09:41:15 +00:00
mbecker20
33a00bb1a2 poll when instance running 2023-02-20 04:55:44 +00:00
mbecker20
ccca44ea89 start working on build instance spawn on aws 2023-02-20 01:19:07 +00:00
33 changed files with 1255 additions and 319 deletions

526
Cargo.lock generated
View File

@@ -19,6 +19,15 @@ dependencies = [
"version_check",
]
[[package]]
name = "aho-corasick"
version = "0.7.20"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "cc936419f96fa211c1b9166887b38e5e40b19958e5b895be7c1f93adec7071ac"
dependencies = [
"memchr",
]
[[package]]
name = "android_system_properties"
version = "0.1.5"
@@ -75,6 +84,322 @@ version = "1.1.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "d468802bab17cbc0cc575e9b053f41e72aa36bfa6b7f55e3529ffa43161b97fa"
[[package]]
name = "aws-config"
version = "0.54.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "3c3d1e2a1f1ab3ac6c4b884e37413eaa03eb9d901e4fc68ee8f5c1d49721680e"
dependencies = [
"aws-credential-types",
"aws-http",
"aws-sdk-sso",
"aws-sdk-sts",
"aws-smithy-async",
"aws-smithy-client",
"aws-smithy-http",
"aws-smithy-http-tower",
"aws-smithy-json",
"aws-smithy-types",
"aws-types",
"bytes",
"hex",
"http",
"hyper",
"ring",
"time 0.3.17",
"tokio",
"tower",
"tracing",
"zeroize",
]
[[package]]
name = "aws-credential-types"
version = "0.54.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "bb0696a0523a39a19087747e4dafda0362dc867531e3d72a3f195564c84e5e08"
dependencies = [
"aws-smithy-async",
"aws-smithy-types",
"tokio",
"tracing",
"zeroize",
]
[[package]]
name = "aws-endpoint"
version = "0.54.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "80a4f935ab6a1919fbfd6102a80c4fccd9ff5f47f94ba154074afe1051903261"
dependencies = [
"aws-smithy-http",
"aws-smithy-types",
"aws-types",
"http",
"regex",
"tracing",
]
[[package]]
name = "aws-http"
version = "0.54.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "82976ca4e426ee9ca3ffcf919d9b2c8d14d0cd80d43cc02173737a8f07f28d4d"
dependencies = [
"aws-credential-types",
"aws-smithy-http",
"aws-smithy-types",
"aws-types",
"bytes",
"http",
"http-body",
"lazy_static",
"percent-encoding",
"pin-project-lite",
"tracing",
]
[[package]]
name = "aws-sdk-ec2"
version = "0.24.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "b40ee2d853d8300a49513778beb79b1574ff9e9c94b30b1531bc0171d730ad64"
dependencies = [
"aws-credential-types",
"aws-endpoint",
"aws-http",
"aws-sig-auth",
"aws-smithy-async",
"aws-smithy-client",
"aws-smithy-http",
"aws-smithy-http-tower",
"aws-smithy-json",
"aws-smithy-query",
"aws-smithy-types",
"aws-smithy-xml",
"aws-types",
"bytes",
"fastrand",
"http",
"regex",
"tokio-stream",
"tower",
"tracing",
]
[[package]]
name = "aws-sdk-sso"
version = "0.24.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "ca0119bacf0c42f587506769390983223ba834e605f049babe514b2bd646dbb2"
dependencies = [
"aws-credential-types",
"aws-endpoint",
"aws-http",
"aws-sig-auth",
"aws-smithy-async",
"aws-smithy-client",
"aws-smithy-http",
"aws-smithy-http-tower",
"aws-smithy-json",
"aws-smithy-types",
"aws-types",
"bytes",
"http",
"regex",
"tokio-stream",
"tower",
]
[[package]]
name = "aws-sdk-sts"
version = "0.24.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "270b6a33969ebfcb193512fbd5e8ee5306888ad6c6d5d775cdbfb2d50d94de26"
dependencies = [
"aws-credential-types",
"aws-endpoint",
"aws-http",
"aws-sig-auth",
"aws-smithy-async",
"aws-smithy-client",
"aws-smithy-http",
"aws-smithy-http-tower",
"aws-smithy-json",
"aws-smithy-query",
"aws-smithy-types",
"aws-smithy-xml",
"aws-types",
"bytes",
"http",
"regex",
"tower",
"tracing",
]
[[package]]
name = "aws-sig-auth"
version = "0.54.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "660a02a98ab1af83bd8d714afbab2d502ba9b18c49e7e4cddd6bf8837ff778cb"
dependencies = [
"aws-credential-types",
"aws-sigv4",
"aws-smithy-http",
"aws-types",
"http",
"tracing",
]
[[package]]
name = "aws-sigv4"
version = "0.54.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "cdaf11005b7444e6cd66f600d09861a3aeb6eb89a0f003c7c9820dbab2d15297"
dependencies = [
"aws-smithy-http",
"form_urlencoded",
"hex",
"hmac",
"http",
"once_cell",
"percent-encoding",
"regex",
"sha2",
"time 0.3.17",
"tracing",
]
[[package]]
name = "aws-smithy-async"
version = "0.54.3"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "00e8615bf58d144dec3fcdb5110941b84e904c68054cb74ed240b9588fc337a5"
dependencies = [
"futures-util",
"pin-project-lite",
"tokio",
"tokio-stream",
]
[[package]]
name = "aws-smithy-client"
version = "0.54.3"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "d8c1df4c1d03e1ce299ae4e24c19d0f4cd8bebceac60828530e579977d70289a"
dependencies = [
"aws-smithy-async",
"aws-smithy-http",
"aws-smithy-http-tower",
"aws-smithy-types",
"bytes",
"fastrand",
"http",
"http-body",
"hyper",
"hyper-rustls",
"lazy_static",
"pin-project-lite",
"tokio",
"tower",
"tracing",
]
[[package]]
name = "aws-smithy-http"
version = "0.54.3"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "78abf16f8667b9176737cfffd1dd4ad07d350ef5dba01d01fdec5f31265f7134"
dependencies = [
"aws-smithy-types",
"bytes",
"bytes-utils",
"futures-core",
"http",
"http-body",
"hyper",
"once_cell",
"percent-encoding",
"pin-project-lite",
"pin-utils",
"tokio",
"tokio-util",
"tracing",
]
[[package]]
name = "aws-smithy-http-tower"
version = "0.54.3"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "d517ac2476efc1820228c2fdfdcb17d3bea8695558bd67584a62a47c12b41918"
dependencies = [
"aws-smithy-http",
"aws-smithy-types",
"bytes",
"http",
"http-body",
"pin-project-lite",
"tower",
"tracing",
]
[[package]]
name = "aws-smithy-json"
version = "0.54.3"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "1a23cc091168c5d969b150d7cc11a5a202bfa88dc36494e6659d2499b0cf227b"
dependencies = [
"aws-smithy-types",
]
[[package]]
name = "aws-smithy-query"
version = "0.54.3"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "92a1218021362bc1faa56648397b8cc4ac7631a3944e087d314d0187ef88d782"
dependencies = [
"aws-smithy-types",
"urlencoding",
]
[[package]]
name = "aws-smithy-types"
version = "0.54.3"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "ee8d2056dc5f10094d5e753ac5c649e8996869f0649b641e470950151596db73"
dependencies = [
"base64-simd",
"itoa",
"num-integer",
"ryu",
"time 0.3.17",
]
[[package]]
name = "aws-smithy-xml"
version = "0.54.3"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "1a3029cbb4a49656456b3f2b34daee7f68dd93c61cc5d03fa90788cb1d25d5b4"
dependencies = [
"xmlparser",
]
[[package]]
name = "aws-types"
version = "0.54.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "f8f15b34253b68cde08e39b0627cc6101bcca64351229484b4743392c035d057"
dependencies = [
"aws-credential-types",
"aws-smithy-async",
"aws-smithy-client",
"aws-smithy-http",
"aws-smithy-types",
"http",
"rustc_version 0.4.0",
"tracing",
]
[[package]]
name = "axum"
version = "0.6.4"
@@ -180,6 +505,15 @@ version = "0.21.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "a4a4ddaa51a5bc52a6948f74c06d20aaaddb71924eab79b8c97a8c556e942d6a"
[[package]]
name = "base64-simd"
version = "0.7.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "781dd20c3aff0bd194fe7d2a977dd92f21c173891f3a03b677359e5fa457e5d5"
dependencies = [
"simd-abstraction",
]
[[package]]
name = "bcrypt"
version = "0.14.0"
@@ -299,6 +633,16 @@ version = "1.3.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "dfb24e866b15a1af2a1b663f10c6b6b8f397a84aadb828f12e5b289ec23a3a3c"
[[package]]
name = "bytes-utils"
version = "0.1.3"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "e47d3a8076e283f3acd27400535992edb3ba4b5bb72f8891ad8fbe7932a7d4b9"
dependencies = [
"bytes",
"either",
]
[[package]]
name = "cc"
version = "1.0.79"
@@ -399,7 +743,7 @@ dependencies = [
[[package]]
name = "core"
version = "0.1.15"
version = "0.1.16"
dependencies = [
"anyhow",
"async_timing_util",
@@ -415,8 +759,8 @@ dependencies = [
"hex",
"hmac",
"jwt",
"monitor_helpers 0.1.15 (registry+https://github.com/rust-lang/crates.io-index)",
"monitor_types 0.1.15 (registry+https://github.com/rust-lang/crates.io-index)",
"monitor_helpers",
"monitor_types 0.1.16",
"mungos",
"periphery_client",
"serde",
@@ -651,10 +995,10 @@ checksum = "23d8666cb01533c39dde32bcbab8e227b4ed6679b2c925eba05feabea39508fb"
[[package]]
name = "db_client"
version = "0.1.15"
version = "0.1.16"
dependencies = [
"anyhow",
"monitor_types 0.1.15 (registry+https://github.com/rust-lang/crates.io-index)",
"monitor_types 0.1.16",
"mungos",
]
@@ -1104,6 +1448,21 @@ dependencies = [
"want",
]
[[package]]
name = "hyper-rustls"
version = "0.23.2"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "1788965e61b367cd03a62950836d5cd41560c3577d90e40e0819373194d1661c"
dependencies = [
"http",
"hyper",
"log",
"rustls",
"rustls-native-certs",
"tokio",
"tokio-rustls",
]
[[package]]
name = "hyper-tls"
version = "0.5.0"
@@ -1454,7 +1813,7 @@ dependencies = [
"rand",
"rustc_version_runtime",
"rustls",
"rustls-pemfile",
"rustls-pemfile 0.3.0",
"serde",
"serde_bytes",
"serde_with",
@@ -1479,7 +1838,7 @@ dependencies = [
[[package]]
name = "monitor_cli"
version = "0.1.21"
version = "0.1.22"
dependencies = [
"async_timing_util",
"clap",
@@ -1495,12 +1854,12 @@ dependencies = [
[[package]]
name = "monitor_client"
version = "0.1.15"
version = "0.1.16"
dependencies = [
"anyhow",
"envy",
"futures-util",
"monitor_types 0.1.15 (registry+https://github.com/rust-lang/crates.io-index)",
"monitor_types 0.1.16 (registry+https://github.com/rust-lang/crates.io-index)",
"reqwest",
"serde",
"serde_derive",
@@ -1512,47 +1871,30 @@ dependencies = [
[[package]]
name = "monitor_helpers"
version = "0.1.15"
version = "0.1.16"
dependencies = [
"anyhow",
"async_timing_util",
"aws-config",
"aws-sdk-ec2",
"axum",
"bollard",
"futures",
"futures-util",
"monitor_types 0.1.15 (registry+https://github.com/rust-lang/crates.io-index)",
"rand",
"run_command",
"serde",
"serde_derive",
"serde_json",
"toml",
]
[[package]]
name = "monitor_helpers"
version = "0.1.15"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "f2e58a1c8a1e92c967b5c4ba10511bc4bbf65c824230d234b78ad9d3ed992b75"
dependencies = [
"anyhow",
"async_timing_util",
"axum",
"bollard",
"futures",
"futures-util",
"monitor_types 0.1.15 (registry+https://github.com/rust-lang/crates.io-index)",
"monitor_types 0.1.16",
"periphery_client",
"rand",
"run_command",
"serde",
"serde_derive",
"serde_json",
"tokio",
"toml",
]
[[package]]
name = "monitor_periphery"
version = "0.1.15"
version = "0.1.16"
dependencies = [
"anyhow",
"async_timing_util",
@@ -1563,8 +1905,8 @@ dependencies = [
"dotenv",
"envy",
"futures-util",
"monitor_helpers 0.1.15 (registry+https://github.com/rust-lang/crates.io-index)",
"monitor_types 0.1.15 (registry+https://github.com/rust-lang/crates.io-index)",
"monitor_helpers",
"monitor_types 0.1.16",
"run_command",
"serde",
"serde_derive",
@@ -1578,7 +1920,7 @@ dependencies = [
[[package]]
name = "monitor_types"
version = "0.1.15"
version = "0.1.16"
dependencies = [
"anyhow",
"bollard",
@@ -1595,9 +1937,9 @@ dependencies = [
[[package]]
name = "monitor_types"
version = "0.1.15"
version = "0.1.16"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "bc2fc31230469c5a56e57eacf0200422897d4e0808ba176a767ceb59a872d543"
checksum = "e4d1444216d1585f466d0591cedbdf84d1c810a4f45586362108219e7c943267"
dependencies = [
"anyhow",
"bollard",
@@ -1816,6 +2158,12 @@ version = "6.4.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "9b7820b9daea5457c9f21c69448905d723fbd21136ccf521748f23fd49e723ee"
[[package]]
name = "outref"
version = "0.1.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "7f222829ae9293e33a9f5e9f440c6760a3d450a64affe1846486b140db81c1f4"
[[package]]
name = "parking_lot"
version = "0.12.1"
@@ -1856,12 +2204,11 @@ checksum = "478c572c3d73181ff3c2539045f6eb99e5491218eae919370993b890cdbdd98e"
[[package]]
name = "periphery_client"
version = "0.1.15"
version = "0.1.16"
dependencies = [
"anyhow",
"futures-util",
"monitor_helpers 0.1.15 (registry+https://github.com/rust-lang/crates.io-index)",
"monitor_types 0.1.15 (registry+https://github.com/rust-lang/crates.io-index)",
"monitor_types 0.1.16",
"reqwest",
"serde",
"serde_json",
@@ -2022,6 +2369,23 @@ dependencies = [
"bitflags",
]
[[package]]
name = "regex"
version = "1.7.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "48aaa5748ba571fb95cd2c85c09f629215d3a6ece942baa100950af03a34f733"
dependencies = [
"aho-corasick",
"memchr",
"regex-syntax",
]
[[package]]
name = "regex-syntax"
version = "0.6.28"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "456c603be3e8d448b072f410900c09faf164fbce2d480456f50eea6e25f9c848"
[[package]]
name = "remove_dir_all"
version = "0.5.3"
@@ -2108,7 +2472,16 @@ version = "0.2.3"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "138e3e0acb6c9fb258b19b67cb8abd63c00679d2851805ea151465464fe9030a"
dependencies = [
"semver",
"semver 0.9.0",
]
[[package]]
name = "rustc_version"
version = "0.4.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "bfa0f585226d2e68097d4f95d113b15b83a82e819ab25717ec0590d9584ef366"
dependencies = [
"semver 1.0.16",
]
[[package]]
@@ -2117,8 +2490,8 @@ version = "0.2.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "d31b7153270ebf48bf91c65ae5b0c00e749c4cfad505f66530ac74950249582f"
dependencies = [
"rustc_version",
"semver",
"rustc_version 0.2.3",
"semver 0.9.0",
]
[[package]]
@@ -2147,6 +2520,18 @@ dependencies = [
"webpki",
]
[[package]]
name = "rustls-native-certs"
version = "0.6.2"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "0167bac7a9f490495f3c33013e7722b53cb087ecbe082fb0c6387c96f634ea50"
dependencies = [
"openssl-probe",
"rustls-pemfile 1.0.2",
"schannel",
"security-framework",
]
[[package]]
name = "rustls-pemfile"
version = "0.3.0"
@@ -2156,6 +2541,15 @@ dependencies = [
"base64 0.13.1",
]
[[package]]
name = "rustls-pemfile"
version = "1.0.2"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "d194b56d58803a43635bdc398cd17e383d6f71f9182b9a192c127ca42494a59b"
dependencies = [
"base64 0.21.0",
]
[[package]]
name = "rustversion"
version = "1.0.11"
@@ -2231,6 +2625,12 @@ dependencies = [
"semver-parser",
]
[[package]]
name = "semver"
version = "1.0.16"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "58bc9567378fc7690d6b2addae4e60ac2eeea07becb2c64b9f218b53865cba2a"
[[package]]
name = "semver-parser"
version = "0.7.0"
@@ -2372,6 +2772,15 @@ dependencies = [
"libc",
]
[[package]]
name = "simd-abstraction"
version = "0.7.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "9cadb29c57caadc51ff8346233b5cec1d240b68ce55cf1afc764818791876987"
dependencies = [
"outref",
]
[[package]]
name = "slab"
version = "0.4.7"
@@ -2666,6 +3075,17 @@ dependencies = [
"webpki",
]
[[package]]
name = "tokio-stream"
version = "0.1.11"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "d660770404473ccd7bc9f8b28494a811bc18542b915c0855c51e8f419d5223ce"
dependencies = [
"futures-core",
"pin-project-lite",
"tokio",
]
[[package]]
name = "tokio-tungstenite"
version = "0.18.0"
@@ -2795,9 +3215,21 @@ dependencies = [
"cfg-if",
"log",
"pin-project-lite",
"tracing-attributes",
"tracing-core",
]
[[package]]
name = "tracing-attributes"
version = "0.1.23"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "4017f8f45139870ca7e672686113917c71c7a6e02d4924eda67186083c03081a"
dependencies = [
"proc-macro2",
"quote",
"syn",
]
[[package]]
name = "tracing-core"
version = "0.1.30"
@@ -3233,6 +3665,12 @@ dependencies = [
"winapi",
]
[[package]]
name = "xmlparser"
version = "0.13.5"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "4d25c75bf9ea12c4040a97f829154768bbbce366287e2dc044af160cd79a13fd"
[[package]]
name = "zeroize"
version = "1.5.7"

View File

@@ -1,6 +1,6 @@
[package]
name = "monitor_cli"
version = "0.1.21"
version = "0.1.22"
edition = "2021"
authors = ["MoghTech"]
description = "monitor cli | tools to setup monitor system"

View File

@@ -74,6 +74,7 @@ pub fn gen_core_config(sub_matches: &ArgMatches) {
local_auth: true,
github_oauth: Default::default(),
google_oauth: Default::default(),
aws: Default::default(),
mongo: MongoConfig {
uri: mongo_uri,
db_name: mongo_db_name,

View File

@@ -21,7 +21,6 @@ pub struct CoreConfig {
#[serde(default)]
pub keep_stats_for_days: u64, // 0 means never prune
// jwt config
pub jwt_secret: String,
#[serde(default = "default_jwt_valid_for")]
pub jwt_valid_for: Timelength,
@@ -41,14 +40,16 @@ pub struct CoreConfig {
// enable login with local auth
pub local_auth: bool,
// github integration
pub mongo: MongoConfig,
#[serde(default)]
pub github_oauth: OauthCredentials,
// google integration
#[serde(default)]
pub google_oauth: OauthCredentials,
// mongo config
pub mongo: MongoConfig,
#[serde(default)]
pub aws: AwsBuilderConfig,
}
fn default_core_port() -> u16 {
@@ -86,6 +87,37 @@ fn default_core_mongo_db_name() -> String {
"monitor".to_string()
}
#[derive(Serialize, Deserialize, Debug, Clone, Default)]
pub struct AwsBuilderConfig {
pub access_key_id: String,
pub secret_access_key: String,
pub default_ami_id: String,
pub default_subnet_id: String,
pub default_key_pair_name: String,
#[serde(default = "default_aws_region")]
pub default_region: String,
#[serde(default = "default_volume_gb")]
pub default_volume_gb: i32,
#[serde(default = "default_instance_type")]
pub default_instance_type: String,
#[serde(default)]
pub default_security_group_ids: Vec<String>,
#[serde(default)]
pub default_assign_public_ip: bool,
}
fn default_aws_region() -> String {
String::from("us-east-1")
}
fn default_volume_gb() -> i32 {
8
}
fn default_instance_type() -> String {
String::from("m5.2xlarge")
}
pub type GithubUsername = String;
pub type GithubToken = String;
pub type GithubAccounts = HashMap<GithubUsername, GithubToken>;

View File

@@ -31,6 +31,18 @@ monitoring_interval = "1-min"
# allow or deny user login with username / password
local_auth = true
[aws]
access_key_id = "your_aws_key_id"
secret_access_key = "your_aws_secret_key"
default_region = "us-east-1"
default_ami_id = "your_periphery_ami"
default_key_pair_name = "your_default_key_pair_name"
default_instance_type = "m5.2xlarge"
default_volume_gb = 8
default_subnet_id = "your_default_subnet_id"
default_security_group_ids = ["sg_id_1", "sg_id_2"]
default_assign_public_ip = false
[github_oauth]
enabled = true
id = "your_github_client_id"

View File

@@ -1,15 +1,13 @@
[package]
name = "core"
version = "0.1.15"
version = "0.1.16"
edition = "2021"
# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html
[dependencies]
# helpers = { package = "monitor_helpers", path = "../lib/helpers" }
# types = { package = "monitor_types", path = "../lib/types" }
helpers = { package = "monitor_helpers", version = "0.1.15" }
types = { package = "monitor_types", version = "0.1.15" }
helpers = { package = "monitor_helpers", path = "../lib/helpers" }
types = { package = "monitor_types", path = "../lib/types" }
db = { package = "db_client", path = "../lib/db_client" }
periphery = { package = "periphery_client", path = "../lib/periphery_client" }
axum_oauth2 = { path = "../lib/axum_oauth2" }

View File

@@ -1,6 +1,12 @@
use std::time::Duration;
use anyhow::{anyhow, Context};
use diff::Diff;
use helpers::{all_logs_success, to_monitor_name};
use helpers::{
all_logs_success,
aws::{self, create_ec2_client, create_instance_with_ami, terminate_ec2_instance, Ec2Instance},
to_monitor_name,
};
use mungos::{doc, to_bson};
use types::{
monitor_timestamp,
@@ -8,11 +14,10 @@ use types::{
Build, Log, Operation, PermissionLevel, Update, UpdateStatus, UpdateTarget, Version,
};
use crate::{
auth::RequestUser,
helpers::{any_option_diff_is_some, option_diff_is_some},
state::State,
};
use crate::{auth::RequestUser, state::State};
const BUILDER_POLL_RATE_SECS: u64 = 2;
const BUILDER_POLL_MAX_TRIES: usize = 30;
impl State {
pub async fn get_build_check_permissions(
@@ -39,18 +44,13 @@ impl State {
}
}
pub async fn create_build(
&self,
name: &str,
server_id: String,
user: &RequestUser,
) -> anyhow::Result<Build> {
self.get_server_check_permissions(&server_id, user, PermissionLevel::Update)
.await?;
pub async fn create_build(&self, name: &str, user: &RequestUser) -> anyhow::Result<Build> {
if !user.is_admin && !user.create_build_permissions {
return Err(anyhow!("user does not have permission to create builds"));
}
let start_ts = monitor_timestamp();
let build = Build {
name: to_monitor_name(name),
server_id,
permissions: [(user.id.clone(), PermissionLevel::Update)]
.into_iter()
.collect(),
@@ -84,10 +84,7 @@ impl State {
mut build: Build,
user: &RequestUser,
) -> anyhow::Result<Build> {
build.id = self
.create_build(&build.name, build.server_id.clone(), user)
.await?
.id;
build.id = self.create_build(&build.name, user).await?.id;
let build = self.update_build(build, user).await?;
Ok(build)
}
@@ -96,14 +93,12 @@ impl State {
&self,
target_id: &str,
new_name: String,
new_server_id: String,
user: &RequestUser,
) -> anyhow::Result<Build> {
let mut build = self
.get_build_check_permissions(target_id, user, PermissionLevel::Update)
.await?;
build.name = new_name;
build.server_id = new_server_id;
build.version = Version::default();
let build = self.create_full_build(build, user).await?;
Ok(build)
@@ -117,11 +112,6 @@ impl State {
.get_build_check_permissions(build_id, user, PermissionLevel::Update)
.await?;
let start_ts = monitor_timestamp();
let server = self.db.get_server(&build.server_id).await?;
let delete_repo_log = match self.periphery.delete_repo(&server, &build.name).await {
Ok(log) => log,
Err(e) => Log::error("delete repo", format!("{e:#?}")),
};
self.db.builds.delete_one(build_id).await?;
let update = Update {
target: UpdateTarget::Build(build_id.to_string()),
@@ -129,13 +119,10 @@ impl State {
start_ts,
end_ts: Some(monitor_timestamp()),
operator: user.id.clone(),
logs: vec![
delete_repo_log,
Log::simple(
"delete build",
format!("deleted build {} on server {}", build.name, server.name),
),
],
logs: vec![Log::simple(
"delete build",
format!("deleted build {}", build.name),
)],
success: true,
..Default::default()
};
@@ -179,7 +166,6 @@ impl State {
// 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.last_built_at = String::new();
new_build.created_at = current_build.created_at.clone();
new_build.updated_at = start_ts.clone();
@@ -192,41 +178,42 @@ impl State {
let diff = current_build.diff(&new_build);
let mut update = Update {
let update = Update {
operation: Operation::UpdateBuild,
target: UpdateTarget::Build(new_build.id.clone()),
start_ts,
status: UpdateStatus::InProgress,
status: UpdateStatus::Complete,
logs: vec![Log::simple(
"build update",
serde_json::to_string_pretty(&diff).unwrap(),
)],
operator: user.id.clone(),
end_ts: Some(monitor_timestamp()),
success: true,
..Default::default()
};
update.id = self.add_update(update.clone()).await?;
// update.id = self.add_update(update.clone()).await?;
if any_option_diff_is_some(&[&diff.repo, &diff.branch, &diff.github_account])
|| option_diff_is_some(&diff.on_clone)
{
let server = self.db.get_server(&current_build.server_id).await?;
match self.periphery.clone_repo(&server, &new_build).await {
Ok(clone_logs) => {
update.logs.extend(clone_logs);
}
Err(e) => update
.logs
.push(Log::error("cloning repo", format!("{e:#?}"))),
}
}
// if any_option_diff_is_some(&[&diff.repo, &diff.branch, &diff.github_account])
// || option_diff_is_some(&diff.on_clone)
// {
// let server = self.db.get_server(&current_build.server_id).await?;
// match self.periphery.clone_repo(&server, &new_build).await {
// Ok(clone_logs) => {
// update.logs.extend(clone_logs);
// }
// Err(e) => update
// .logs
// .push(Log::error("cloning repo", format!("{e:#?}"))),
// }
// }
update.end_ts = Some(monitor_timestamp());
update.success = all_logs_success(&update.logs);
update.status = UpdateStatus::Complete;
// update.end_ts = Some(monitor_timestamp());
// update.success = all_logs_success(&update.logs);
// update.status = UpdateStatus::Complete;
self.update_update(update).await?;
self.add_update(update).await?;
Ok(new_build)
}
@@ -253,10 +240,7 @@ impl State {
let mut build = self
.get_build_check_permissions(build_id, user, PermissionLevel::Update)
.await?;
let server = self.db.get_server(&build.server_id).await?;
build.version.increment();
let mut update = Update {
target: UpdateTarget::Build(build_id.to_string()),
operation: Operation::BuildBuild,
@@ -267,12 +251,95 @@ impl State {
version: build.version.clone().into(),
..Default::default()
};
update.id = self.add_update(update.clone()).await?;
let (server, aws_client) = if let Some(server_id) = &build.server_id {
let server = self.db.get_server(server_id).await;
if let Err(e) = server {
update.status = UpdateStatus::Complete;
update.end_ts = Some(monitor_timestamp());
update.success = false;
update
.logs
.push(Log::error("get build server", format!("{e:#?}")));
self.update_update(update.clone()).await?;
return Err(e);
}
let server = Ec2Instance {
instance_id: String::new(),
server: server.unwrap(),
};
(server, None)
} else if build.aws_config.is_some() {
let start_ts = monitor_timestamp();
let res = self.create_ec2_instance_for_build(&build).await;
if let Err(e) = res {
update.status = UpdateStatus::Complete;
update.end_ts = Some(monitor_timestamp());
update.success = false;
update.logs.push(Log {
stage: "start build server".to_string(),
stderr: format!("{e:#?}"),
success: false,
start_ts,
end_ts: monitor_timestamp(),
..Default::default()
});
self.update_update(update).await?;
return Err(e);
}
let (server, aws_client, log) = res.unwrap();
update.logs.push(log);
self.update_update(update.clone()).await?;
(server, aws_client)
} else {
update.status = UpdateStatus::Complete;
update.end_ts = Some(monitor_timestamp());
update.success = false;
update.logs.push(Log::error(
"start build",
"build has neither server_id nor aws_config attached".to_string(),
));
self.update_update(update).await?;
return Err(anyhow!(
"build has neither server_id or aws_config attached"
));
};
let clone_success = match self.periphery.clone_repo(&server.server, &build).await {
Ok(clone_logs) => {
update.logs.extend(clone_logs);
true
}
Err(e) => {
update
.logs
.push(Log::error("clone repo", format!("{e:#?}")));
false
}
};
if !clone_success {
let _ = self
.periphery
.delete_repo(&server.server, &build.name)
.await;
if let Some(aws_client) = aws_client {
self.terminate_ec2_instance(aws_client, &server, &mut update)
.await;
}
update.status = UpdateStatus::Complete;
update.end_ts = Some(monitor_timestamp());
update.success = false;
self.update_update(update.clone()).await?;
return Ok(update);
}
self.update_update(update.clone()).await?;
let build_logs = match self
.periphery
.build(&server, &build)
.build(&server.server, &build)
.await
.context("failed at call to periphery to build")
{
@@ -282,9 +349,9 @@ impl State {
match build_logs {
Some(logs) => {
let success = all_logs_success(&logs);
update.logs.extend(logs);
update.success = all_logs_success(&update.logs);
if update.success {
if success {
let _ = self
.db
.builds
@@ -305,68 +372,18 @@ impl State {
.push(Log::error("build", "builder busy".to_string()));
}
}
update.status = UpdateStatus::Complete;
update.end_ts = Some(monitor_timestamp());
self.update_update(update.clone()).await?;
Ok(update)
}
let _ = self
.periphery
.delete_repo(&server.server, &build.name)
.await;
pub async fn reclone_build(
&self,
build_id: &str,
user: &RequestUser,
) -> anyhow::Result<Update> {
if self.build_busy(build_id).await {
return Err(anyhow!("build busy"));
if let Some(aws_client) = aws_client {
self.terminate_ec2_instance(aws_client, &server, &mut update)
.await;
}
{
let mut lock = self.build_action_states.lock().await;
let entry = lock.entry(build_id.to_string()).or_default();
entry.recloning = true;
}
let res = self.reclone_build_inner(build_id, user).await;
{
let mut lock = self.build_action_states.lock().await;
let entry = lock.entry(build_id.to_string()).or_default();
entry.recloning = false;
}
res
}
async fn reclone_build_inner(
&self,
build_id: &str,
user: &RequestUser,
) -> anyhow::Result<Update> {
let build = self
.get_build_check_permissions(build_id, user, PermissionLevel::Update)
.await?;
let server = self.db.get_server(&build.server_id).await?;
let mut update = Update {
target: UpdateTarget::Build(build_id.to_string()),
operation: Operation::RecloneBuild,
start_ts: monitor_timestamp(),
status: UpdateStatus::InProgress,
operator: user.id.clone(),
success: true,
..Default::default()
};
update.id = self.add_update(update.clone()).await?;
update.success = match self.periphery.clone_repo(&server, &build).await {
Ok(clone_logs) => {
update.logs.extend(clone_logs);
true
}
Err(e) => {
update
.logs
.push(Log::error("clone repo", format!("{e:#?}")));
false
}
};
update.success = all_logs_success(&update.logs);
update.status = UpdateStatus::Complete;
update.end_ts = Some(monitor_timestamp());
@@ -374,4 +391,170 @@ impl State {
Ok(update)
}
async fn create_ec2_instance_for_build(
&self,
build: &Build,
) -> anyhow::Result<(Ec2Instance, Option<aws::Client>, Log)> {
if build.aws_config.is_none() {
return Err(anyhow!("build has no aws_config attached"));
}
let start_ts = monitor_timestamp();
let aws_config = build.aws_config.as_ref().unwrap();
let region = aws_config
.region
.as_ref()
.unwrap_or(&self.config.aws.default_region)
.to_string();
let aws_client = create_ec2_client(
region,
&self.config.aws.access_key_id,
self.config.aws.secret_access_key.clone(),
)
.await;
let ami_id = aws_config
.ami_id
.as_ref()
.unwrap_or(&self.config.aws.default_ami_id);
let instance_type = aws_config
.instance_type
.as_ref()
.unwrap_or(&self.config.aws.default_instance_type);
let subnet_id = aws_config
.subnet_id
.as_ref()
.unwrap_or(&self.config.aws.default_subnet_id);
let security_group_ids = aws_config
.security_group_ids
.as_ref()
.unwrap_or(&self.config.aws.default_security_group_ids)
.to_owned();
let readable_sec_group_ids = security_group_ids.join(", ");
let volume_size_gb = *aws_config
.volume_gb
.as_ref()
.unwrap_or(&self.config.aws.default_volume_gb);
let key_pair_name = aws_config
.key_pair_name
.as_ref()
.unwrap_or(&self.config.aws.default_key_pair_name);
let assign_public_ip = *aws_config
.assign_public_ip
.as_ref()
.unwrap_or(&self.config.aws.default_assign_public_ip);
let instance = create_instance_with_ami(
&aws_client,
&format!("BUILDER-{}-v{}", build.name, build.version.to_string()),
ami_id,
instance_type,
subnet_id,
security_group_ids,
volume_size_gb,
key_pair_name,
assign_public_ip,
)
.await?;
let mut res = Ok(String::new());
for _ in 0..BUILDER_POLL_MAX_TRIES {
let status = self.periphery.health_check(&instance.server).await;
if let Ok(_) = status {
let instance_id = &instance.instance_id;
let log = Log {
stage: "start build instance".to_string(),
success: true,
stdout: format!("instance id: {instance_id}\nami id: {ami_id}\ninstance type: {instance_type}\nvolume size: {volume_size_gb} GB\nsubnet id: {subnet_id}\nsecurity groups: {readable_sec_group_ids}"),
start_ts,
end_ts: monitor_timestamp(),
..Default::default()
};
return Ok((instance, Some(aws_client), log));
}
res = status;
tokio::time::sleep(Duration::from_secs(BUILDER_POLL_RATE_SECS)).await;
}
let _ = terminate_ec2_instance(&aws_client, &instance.instance_id).await;
Err(anyhow!("unable to reach periphery agent on build server\n{res:#?}"))
}
async fn terminate_ec2_instance(
&self,
aws_client: aws::Client,
server: &Ec2Instance,
update: &mut Update,
) {
let res = terminate_ec2_instance(&aws_client, &server.instance_id).await;
if let Err(e) = res {
update
.logs
.push(Log::error("terminate instance", format!("{e:#?}")))
} else {
update.logs.push(Log::simple(
"terminate instance",
format!("terminate instance id {}", server.instance_id),
))
}
}
// pub async fn reclone_build(
// &self,
// build_id: &str,
// user: &RequestUser,
// ) -> anyhow::Result<Update> {
// if self.build_busy(build_id).await {
// return Err(anyhow!("build busy"));
// }
// {
// let mut lock = self.build_action_states.lock().await;
// let entry = lock.entry(build_id.to_string()).or_default();
// entry.recloning = true;
// }
// let res = self.reclone_build_inner(build_id, user).await;
// {
// let mut lock = self.build_action_states.lock().await;
// let entry = lock.entry(build_id.to_string()).or_default();
// entry.recloning = false;
// }
// res
// }
// async fn reclone_build_inner(
// &self,
// build_id: &str,
// user: &RequestUser,
// ) -> anyhow::Result<Update> {
// let build = self
// .get_build_check_permissions(build_id, user, PermissionLevel::Update)
// .await?;
// let server = self.db.get_server(&build.server_id).await?;
// let mut update = Update {
// target: UpdateTarget::Build(build_id.to_string()),
// operation: Operation::RecloneBuild,
// start_ts: monitor_timestamp(),
// status: UpdateStatus::InProgress,
// operator: user.id.clone(),
// success: true,
// ..Default::default()
// };
// update.id = self.add_update(update.clone()).await?;
// update.success = match self.periphery.clone_repo(&server, &build).await {
// Ok(clone_logs) => {
// update.logs.extend(clone_logs);
// true
// }
// Err(e) => {
// update
// .logs
// .push(Log::error("clone repo", format!("{e:#?}")));
// false
// }
// };
// update.status = UpdateStatus::Complete;
// update.end_ts = Some(monitor_timestamp());
// self.update_update(update.clone()).await?;
// Ok(update)
// }
}

View File

@@ -125,7 +125,7 @@ impl State {
} in &new_procedure.stages
{
match operation {
BuildBuild | RecloneBuild => {
BuildBuild => {
self.get_build_check_permissions(&target_id, user, PermissionLevel::Execute)
.await?;
}
@@ -253,13 +253,6 @@ impl State {
.context(format!("failed at build (id: {target_id})"))?;
updates.push(update);
}
RecloneBuild => {
let update = self
.reclone_build(&target_id, user)
.await
.context(format!("failed at reclone build (id: {target_id})"))?;
updates.push(update);
}
// server
PruneImagesServer => {
let update = self.prune_images(&target_id, user).await.context(format!(

View File

@@ -31,14 +31,12 @@ struct BuildId {
#[derive(Serialize, Deserialize)]
struct CreateBuildBody {
name: String,
server_id: String,
}
#[typeshare]
#[derive(Serialize, Deserialize)]
struct CopyBuildBody {
name: String,
server_id: String,
}
#[typeshare]
@@ -88,7 +86,7 @@ pub fn router() -> Router {
Extension(user): RequestUserExtension,
Json(build): Json<CreateBuildBody>| async move {
let build = state
.create_build(&build.name, build.server_id, &user)
.create_build(&build.name, &user)
.await
.map_err(handle_anyhow_error)?;
response!(Json(build))
@@ -121,7 +119,7 @@ pub fn router() -> Router {
Json(build): Json<CopyBuildBody>| async move {
let build = spawn_request_action(async move {
state
.copy_build(&id, build.name, build.server_id, &user)
.copy_build(&id, build.name, &user)
.await
.map_err(handle_anyhow_error)
})
@@ -181,23 +179,6 @@ pub fn router() -> Router {
},
),
)
.route(
"/:id/reclone",
post(
|Extension(state): StateExtension,
Extension(user): RequestUserExtension,
Path(build_id): Path<BuildId>| async move {
let update = spawn_request_action(async move {
state
.reclone_build(&build_id.id, &user)
.await
.map_err(handle_anyhow_error)
})
.await??;
response!(Json(update))
},
),
)
.route(
"/:id/action_state",
get(

View File

@@ -74,6 +74,7 @@ impl State {
id: String::from(GITHUB_WEBHOOK_USER_ID),
is_admin: true,
create_server_permissions: false,
create_build_permissions: false,
},
)
.await?;
@@ -103,6 +104,7 @@ impl State {
id: String::from(GITHUB_WEBHOOK_USER_ID),
is_admin: true,
create_server_permissions: false,
create_build_permissions: false,
},
)
.await?;
@@ -127,6 +129,7 @@ impl State {
id: String::from(GITHUB_WEBHOOK_USER_ID),
is_admin: true,
create_server_permissions: false,
create_build_permissions: false,
},
)
.await?;

View File

@@ -24,6 +24,7 @@ pub struct RequestUser {
pub id: String,
pub is_admin: bool,
pub create_server_permissions: bool,
pub create_build_permissions: bool,
}
#[derive(Serialize, Deserialize)]
@@ -109,6 +110,7 @@ impl JwtClient {
id: claims.id,
is_admin: user.admin,
create_server_permissions: user.create_server_permissions,
create_build_permissions: user.create_build_permissions,
};
Ok(user)
} else {

View File

@@ -1,12 +1,11 @@
[package]
name = "db_client"
version = "0.1.15"
version = "0.1.16"
edition = "2021"
# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html
[dependencies]
types = { package = "monitor_types", version = "0.1.15" }
# types = { package = "monitor_types", path = "../types" }
types = { package = "monitor_types", path = "../types" }
mungos = "0.3.0"
anyhow = "1.0"

View File

@@ -1,6 +1,6 @@
[package]
name = "monitor_helpers"
version = "0.1.15"
version = "0.1.16"
edition = "2021"
authors = ["MoghTech"]
description = "helpers used as dependency for mogh tech monitor"
@@ -9,8 +9,9 @@ license = "GPL-3.0-or-later"
# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html
[dependencies]
# types = { package = "monitor_types", path = "../types" }
types = { package = "monitor_types", version = "0.1.15" }
tokio = "1.25"
types = { package = "monitor_types", path = "../types" }
periphery_client = { path = "../periphery_client" }
async_timing_util = "0.1.14"
bollard = "0.13"
anyhow = "1.0"
@@ -23,3 +24,5 @@ run_command = { version = "0.0.5", features = ["async_tokio"] }
rand = "0.8"
futures = "0.3"
futures-util = "0.3.25"
aws-config = "0.54"
aws-sdk-ec2 = "0.24"

199
lib/helpers/src/aws/mod.rs Normal file
View File

@@ -0,0 +1,199 @@
use std::time::Duration;
use anyhow::{anyhow, Context};
use aws_sdk_ec2::model::{
BlockDeviceMapping, EbsBlockDevice, InstanceNetworkInterfaceSpecification, InstanceStateChange,
InstanceStateName, InstanceStatus, ResourceType, Tag, TagSpecification,
};
pub use aws_sdk_ec2::{
model::InstanceType,
output::{DescribeInstanceStatusOutput, TerminateInstancesOutput},
Client, Region,
};
use types::Server;
pub async fn create_ec2_client(
region: String,
access_key_id: &str,
secret_access_key: String,
) -> Client {
// There may be a better way to pass these keys to client
std::env::set_var("AWS_ACCESS_KEY_ID", access_key_id);
std::env::set_var("AWS_SECRET_ACCESS_KEY", secret_access_key);
let region = Region::new(region);
let config = aws_config::from_env().region(region).load().await;
let client = Client::new(&config);
client
}
pub struct Ec2Instance {
pub instance_id: String,
pub server: Server,
}
const POLL_RATE_SECS: u64 = 2;
const MAX_POLL_TRIES: usize = 30;
/// this will only resolve after the instance is running
/// should still poll the periphery agent after creation
pub async fn create_instance_with_ami(
client: &Client,
instance_name: &str,
ami_id: &str,
instance_type: &str,
subnet_id: &str,
security_group_ids: Vec<String>,
volume_size_gb: i32,
key_pair_name: &str,
assign_public_ip: bool,
) -> anyhow::Result<Ec2Instance> {
let instance_type = InstanceType::from(instance_type);
if let InstanceType::Unknown(t) = instance_type {
return Err(anyhow!("unknown instance type {t:?}"));
}
let res = client
.run_instances()
.image_id(ami_id)
.instance_type(instance_type)
.block_device_mappings(
BlockDeviceMapping::builder()
.set_device_name(String::from("/dev/sda1").into())
.set_ebs(
EbsBlockDevice::builder()
.volume_size(volume_size_gb)
.build()
.into(),
)
.build(),
)
.network_interfaces(
InstanceNetworkInterfaceSpecification::builder()
.subnet_id(subnet_id)
.associate_public_ip_address(assign_public_ip)
.set_groups(security_group_ids.into())
.device_index(0)
.build(),
)
.key_name(key_pair_name)
.tag_specifications(
TagSpecification::builder()
.tags(Tag::builder().key("Name").value(instance_name).build())
.resource_type(ResourceType::Instance)
.build(),
)
.min_count(1)
.max_count(1)
.send()
.await
.context("failed to start builder ec2 instance")?;
let instance = res
.instances()
.ok_or(anyhow!("got None for created instances"))?
.get(0)
.ok_or(anyhow!("instances array is empty"))?;
let instance_id = instance
.instance_id()
.ok_or(anyhow!("instance does not have instance_id"))?
.to_string();
for _ in 0..MAX_POLL_TRIES {
let state_name = get_ec2_instance_state_name(&client, &instance_id).await?;
if state_name == Some(InstanceStateName::Running) {
let ip = if assign_public_ip {
get_ec2_instance_public_ip(client, &instance_id).await?
} else {
instance
.private_ip_address()
.ok_or(anyhow!("instance does not have private ip"))?
.to_string()
};
let server = Server {
address: format!("http://{ip}:8000"),
..Default::default()
};
return Ok(Ec2Instance {
instance_id,
server,
});
}
tokio::time::sleep(Duration::from_secs(POLL_RATE_SECS)).await;
}
Err(anyhow!("instance not running after polling"))
}
pub async fn get_ec2_instance_status(
client: &Client,
instance_id: &str,
) -> anyhow::Result<Option<InstanceStatus>> {
let status = client
.describe_instance_status()
.instance_ids(instance_id)
.send()
.await
.context("failed to get instance status from aws")?
.instance_statuses()
.ok_or(anyhow!("instance statuses is None"))?
.get(0)
.map(|s| s.to_owned());
Ok(status)
}
pub async fn get_ec2_instance_state_name(
client: &Client,
instance_id: &str,
) -> anyhow::Result<Option<InstanceStateName>> {
let status = get_ec2_instance_status(client, instance_id).await?;
if status.is_none() {
return Ok(None);
}
let state = status
.unwrap()
.instance_state()
.ok_or(anyhow!("instance state is None"))?
.name()
.ok_or(anyhow!("instance state name is None"))?
.to_owned();
Ok(Some(state))
}
pub async fn get_ec2_instance_public_ip(
client: &Client,
instance_id: &str,
) -> anyhow::Result<String> {
let ip = client
.describe_instances()
.instance_ids(instance_id)
.send()
.await
.context("failed to get instance status from aws")?
.reservations()
.ok_or(anyhow!("instance reservations is None"))?
.get(0)
.ok_or(anyhow!("instance reservations is empty"))?
.instances()
.ok_or(anyhow!("instances is None"))?
.get(0)
.ok_or(anyhow!("instances is empty"))?
.public_ip_address()
.ok_or(anyhow!("instance has no public ip"))?
.to_string();
Ok(ip)
}
pub async fn terminate_ec2_instance(
client: &Client,
instance_id: &str,
) -> anyhow::Result<InstanceStateChange> {
let res = client
.terminate_instances()
.instance_ids(instance_id)
.send()
.await
.context("failed to terminate instance from aws")?
.terminating_instances()
.ok_or(anyhow!("terminating instances is None"))?
.get(0)
.ok_or(anyhow!("terminating instances is empty"))?
.to_owned();
Ok(res)
}

View File

@@ -3,7 +3,7 @@ use std::path::PathBuf;
use anyhow::{anyhow, Context};
use types::{Build, DockerBuildArgs, EnvironmentVar, Log, Version};
use crate::{all_logs_success, git, run_monitor_command, to_monitor_name};
use crate::{run_monitor_command, to_monitor_name};
use super::docker_login;
@@ -17,9 +17,7 @@ pub async fn build(
name,
version,
docker_build_args,
branch,
docker_account,
pre_build,
..
}: &Build,
mut repo_dir: PathBuf,
@@ -38,25 +36,25 @@ pub async fn build(
.await
.context("failed to login to docker")?;
repo_dir.push(&name);
let pull_logs = git::pull(repo_dir.clone(), branch, &None).await;
if !all_logs_success(&pull_logs) {
logs.extend(pull_logs);
return Ok(logs);
}
logs.extend(pull_logs);
if let Some(command) = pre_build {
let dir = repo_dir.join(&command.path);
let pre_build_log = run_monitor_command(
"pre build",
format!("cd {} && {}", dir.display(), command.command),
)
.await;
if !pre_build_log.success {
logs.push(pre_build_log);
return Ok(logs);
}
logs.push(pre_build_log);
}
// let pull_logs = git::pull(repo_dir.clone(), branch, &None).await;
// if !all_logs_success(&pull_logs) {
// logs.extend(pull_logs);
// return Ok(logs);
// }
// logs.extend(pull_logs);
// if let Some(command) = pre_build {
// let dir = repo_dir.join(&command.path);
// let pre_build_log = run_monitor_command(
// "pre build",
// format!("cd {} && {}", dir.display(), command.command),
// )
// .await;
// if !pre_build_log.success {
// logs.push(pre_build_log);
// return Ok(logs);
// }
// logs.push(pre_build_log);
// }
let build_dir = repo_dir.join(build_path);
let dockerfile_path = match dockerfile_path {
Some(dockerfile_path) => dockerfile_path.to_owned(),

View File

@@ -2,47 +2,10 @@ use std::path::PathBuf;
use ::run_command::async_run_command;
use anyhow::anyhow;
use serde::{Deserialize, Serialize};
use types::{monitor_timestamp, Build, Command, Deployment, GithubToken, GithubUsername, Log};
use types::{monitor_timestamp, CloneArgs, Command, GithubToken, Log};
use crate::{run_monitor_command, to_monitor_name};
#[derive(Serialize, Deserialize, Clone, Debug)]
pub struct CloneArgs {
name: String,
repo: Option<String>,
branch: Option<String>,
on_clone: Option<Command>,
on_pull: Option<Command>,
pub github_account: Option<GithubUsername>,
}
impl From<&Deployment> for CloneArgs {
fn from(d: &Deployment) -> Self {
CloneArgs {
name: d.name.clone(),
repo: d.repo.clone(),
branch: d.branch.clone(),
on_clone: d.on_clone.clone(),
on_pull: d.on_pull.clone(),
github_account: d.github_account.clone(),
}
}
}
impl From<&Build> for CloneArgs {
fn from(b: &Build) -> Self {
CloneArgs {
name: b.name.clone(),
repo: b.repo.clone(),
branch: b.branch.clone(),
on_clone: b.on_clone.clone(),
on_pull: None,
github_account: b.github_account.clone(),
}
}
}
pub async fn pull(
mut path: PathBuf,
branch: &Option<String>,

View File

@@ -7,6 +7,7 @@ use run_command::{async_run_command, CommandOutput};
use serde::de::DeserializeOwned;
use types::{monitor_timestamp, Log};
pub mod aws;
pub mod docker;
pub mod git;

View File

@@ -1,6 +1,6 @@
[package]
name = "monitor_client"
version = "0.1.15"
version = "0.1.16"
edition = "2021"
authors = ["MoghTech"]
description = "a client to interact with the monitor system"
@@ -9,7 +9,7 @@ license = "GPL-3.0-or-later"
# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html
[dependencies]
monitor_types = "0.1.15"
monitor_types = "0.1.16"
# monitor_types = { path = "../types" }
reqwest = { version = "0.11", features = ["json"] }
tokio-tungstenite = { version = "0.18", features=["native-tls"] }

View File

@@ -88,9 +88,9 @@ impl MonitorClient {
.context(format!("failed at building build {build_id}"))
}
pub async fn reclone_build(&self, id: &str) -> anyhow::Result<Update> {
self.post::<(), _>(&format!("/api/build/{id}/reclone"), None)
.await
.context(format!("failed at recloning build {id}"))
}
// pub async fn reclone_build(&self, id: &str) -> anyhow::Result<Update> {
// self.post::<(), _>(&format!("/api/build/{id}/reclone"), None)
// .await
// .context(format!("failed at recloning build {id}"))
// }
}

View File

@@ -1,15 +1,12 @@
[package]
name = "periphery_client"
version = "0.1.15"
version = "0.1.16"
edition = "2021"
# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html
[dependencies]
helpers = { package = "monitor_helpers", version = "0.1.15" }
types = { package = "monitor_types", version = "0.1.15" }
# types = { package = "monitor_types", path = "../types" }
# helpers = { package = "monitor_helpers", path = "../helpers" }
types = { package = "monitor_types", path = "../types" }
tokio-tungstenite = { version = "0.18", features=["native-tls"] }
tokio = "1.25"
reqwest = { version = "0.11", features = ["json"] }

View File

@@ -1,7 +1,6 @@
use anyhow::Context;
use helpers::git::CloneArgs;
use serde_json::json;
use types::{Command, Log, Server};
use types::{CloneArgs, Command, Log, Server};
use crate::PeripheryClient;

View File

@@ -23,7 +23,7 @@ impl PeripheryClient {
pub fn new(passkey: String) -> PeripheryClient {
PeripheryClient {
http_client: Default::default(),
passkey
passkey,
}
}

View File

@@ -1,6 +1,6 @@
[package]
name = "monitor_types"
version = "0.1.15"
version = "0.1.16"
edition = "2021"
authors = ["MoghTech"]
description = "types for the mogh tech monitor"

View File

@@ -32,8 +32,13 @@ pub struct Build {
#[builder(setter(skip))]
pub permissions: PermissionsMap,
#[diff(attr(#[serde(skip_serializing_if = "Option::is_none")]))]
pub server_id: String, // server which this image should be built on
#[builder(default)]
#[diff(attr(#[serde(skip_serializing_if = "option_diff_no_change")]))]
pub server_id: Option<String>, // server which this image should be built on
#[builder(default)]
#[diff(attr(#[serde(skip_serializing_if = "option_diff_no_change")]))]
pub aws_config: Option<AwsBuilderConfig>,
#[builder(default)]
pub version: Version,
@@ -51,10 +56,6 @@ pub struct Build {
#[diff(attr(#[serde(skip_serializing_if = "option_diff_no_change")]))]
pub github_account: Option<String>,
#[builder(default)]
#[diff(attr(#[serde(skip_serializing_if = "option_diff_no_change")]))]
pub on_clone: Option<Command>,
// build related
#[builder(default)]
#[diff(attr(#[serde(skip_serializing_if = "option_diff_no_change")]))]
@@ -149,3 +150,40 @@ pub struct BuildVersionsReponse {
pub version: Version,
pub ts: String,
}
#[typeshare]
#[derive(Serialize, Deserialize, Debug, Clone, PartialEq, Default, Diff, Builder)]
#[diff(attr(#[derive(Debug, Serialize, PartialEq)]))]
pub struct AwsBuilderConfig {
#[builder(default)]
#[diff(attr(#[serde(skip_serializing_if = "option_diff_no_change")]))]
pub region: Option<String>,
#[builder(default)]
#[diff(attr(#[serde(skip_serializing_if = "option_diff_no_change")]))]
pub instance_type: Option<String>,
#[builder(default)]
#[diff(attr(#[serde(skip_serializing_if = "option_diff_no_change")]))]
pub ami_id: Option<String>,
#[builder(default)]
#[diff(attr(#[serde(skip_serializing_if = "option_diff_no_change")]))]
pub volume_gb: Option<i32>,
#[builder(default)]
#[diff(attr(#[serde(skip_serializing_if = "option_diff_no_change")]))]
pub subnet_id: Option<String>,
#[builder(default)]
#[diff(attr(#[serde(skip_serializing_if = "option_diff_no_change")]))]
pub security_group_ids: Option<Vec<String>>,
#[builder(default)]
#[diff(attr(#[serde(skip_serializing_if = "option_diff_no_change")]))]
pub key_pair_name: Option<String>,
#[builder(default)]
#[diff(attr(#[serde(skip_serializing_if = "option_diff_no_change")]))]
pub assign_public_ip: Option<bool>,
}

View File

@@ -23,8 +23,8 @@ pub struct CoreConfig {
#[serde(default = "default_core_port")]
pub port: u16,
// jwt config
pub jwt_secret: String,
#[serde(default = "default_jwt_valid_for")]
pub jwt_valid_for: Timelength,
@@ -51,14 +51,16 @@ pub struct CoreConfig {
// enable login with local auth
pub local_auth: bool,
// github integration
pub mongo: MongoConfig,
#[serde(default)]
pub github_oauth: OauthCredentials,
// google integration
#[serde(default)]
pub google_oauth: OauthCredentials,
// mongo config
pub mongo: MongoConfig,
#[serde(default)]
pub aws: AwsBuilderConfig,
}
fn default_core_port() -> u16 {
@@ -96,6 +98,37 @@ fn default_core_mongo_db_name() -> String {
"monitor".to_string()
}
#[derive(Serialize, Deserialize, Debug, Clone, Default)]
pub struct AwsBuilderConfig {
pub access_key_id: String,
pub secret_access_key: String,
pub default_ami_id: String,
pub default_subnet_id: String,
pub default_key_pair_name: String,
#[serde(default = "default_aws_region")]
pub default_region: String,
#[serde(default = "default_volume_gb")]
pub default_volume_gb: i32,
#[serde(default = "default_instance_type")]
pub default_instance_type: String,
#[serde(default)]
pub default_security_group_ids: Vec<String>,
#[serde(default)]
pub default_assign_public_ip: bool,
}
fn default_aws_region() -> String {
String::from("us-east-1")
}
fn default_volume_gb() -> i32 {
8
}
fn default_instance_type() -> String {
String::from("m5.2xlarge")
}
#[derive(Serialize, Deserialize, Debug, Clone)]
pub struct PeripheryConfig {
#[serde(default = "default_periphery_port")]

View File

@@ -38,6 +38,16 @@ pub const GITHUB_WEBHOOK_USER_ID: &str = "github";
#[typeshare]
pub type PermissionsMap = HashMap<String, PermissionLevel>;
#[derive(Serialize, Deserialize, Clone, Debug)]
pub struct CloneArgs {
pub name: String,
pub repo: Option<String>,
pub branch: Option<String>,
pub on_clone: Option<Command>,
pub on_pull: Option<Command>,
pub github_account: Option<GithubUsername>,
}
#[typeshare]
#[derive(Serialize, Deserialize, Debug, Clone, PartialEq, Eq, Diff)]
#[diff(attr(#[derive(Debug, PartialEq, Serialize)]))]
@@ -96,7 +106,6 @@ pub enum Operation {
UpdateBuild,
DeleteBuild,
BuildBuild,
RecloneBuild,
// deployment
CreateDeployment,

View File

@@ -74,7 +74,6 @@ pub enum ProcedureOperation {
// build
BuildBuild,
RecloneBuild,
// deployment
DeployContainer,

View File

@@ -1,5 +1,5 @@
use crate::{
Build, BuildActionState, Deployment, DeploymentActionState, Group, PermissionLevel,
Build, BuildActionState, CloneArgs, Deployment, DeploymentActionState, Group, PermissionLevel,
PermissionsMap, Procedure, Server, ServerActionState,
};
@@ -68,3 +68,29 @@ impl Busy for BuildActionState {
self.building || self.recloning || self.updating
}
}
impl From<&Deployment> for CloneArgs {
fn from(d: &Deployment) -> Self {
CloneArgs {
name: d.name.clone(),
repo: d.repo.clone(),
branch: d.branch.clone(),
on_clone: d.on_clone.clone(),
on_pull: d.on_pull.clone(),
github_account: d.github_account.clone(),
}
}
}
impl From<&Build> for CloneArgs {
fn from(b: &Build) -> Self {
CloneArgs {
name: b.name.clone(),
repo: b.repo.clone(),
branch: b.branch.clone(),
on_clone: b.pre_build.clone(),
on_pull: None,
github_account: b.github_account.clone(),
}
}
}

View File

@@ -21,15 +21,22 @@ pub struct User {
#[diff(attr(#[serde(skip_serializing_if = "Option::is_none")]))]
pub username: String,
#[serde(default)]
#[diff(attr(#[serde(skip_serializing_if = "Option::is_none")]))]
pub enabled: bool,
#[serde(default)]
#[diff(attr(#[serde(skip_serializing_if = "Option::is_none")]))]
pub admin: bool,
#[serde(default)]
#[diff(attr(#[serde(skip_serializing_if = "Option::is_none")]))]
pub create_server_permissions: bool,
#[serde(default)]
#[diff(attr(#[serde(skip_serializing_if = "Option::is_none")]))]
pub create_build_permissions: bool,
#[serde(skip_serializing_if = "Option::is_none")]
#[diff(attr(#[serde(skip_serializing_if = "option_diff_no_change")]))]
pub avatar: Option<String>,

View File

@@ -1,6 +1,6 @@
[package]
name = "monitor_periphery"
version = "0.1.15"
version = "0.1.16"
edition = "2021"
authors = ["MoghTech"]
description = "monitor periphery binary | run monitor periphery as system daemon"
@@ -13,10 +13,8 @@ path = "src/main.rs"
# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html
[dependencies]
# helpers = { package = "monitor_helpers", path = "../lib/helpers" }
# types = { package = "monitor_types", path = "../lib/types" }
helpers = { package = "monitor_helpers", version = "0.1.15" }
types = { package = "monitor_types", version = "0.1.15" }
helpers = { package = "monitor_helpers", path = "../lib/helpers" }
types = { package = "monitor_types", path = "../lib/types" }
run_command = { version = "0.0.5", features = ["async_tokio"] }
async_timing_util = "0.1.14"
tokio = { version = "1.25", features = ["full"] }

View File

@@ -1,10 +1,7 @@
use axum::{routing::post, Extension, Json, Router};
use helpers::{
git::{self, CloneArgs},
handle_anyhow_error, to_monitor_name,
};
use helpers::{git, handle_anyhow_error, to_monitor_name};
use serde::Deserialize;
use types::{Command, Log};
use types::{CloneArgs, Command, Log};
use crate::{helpers::get_github_token, PeripheryConfigExtension};

View File

@@ -30,11 +30,13 @@ async fn main() -> anyhow::Result<()> {
// container.container
// );
let update = test_build(&monitor).await?;
println!("build update:\n{update:#?}");
// let update = test_build(&monitor).await?;
// println!("build update:\n{update:#?}");
// test_updates(&monitor).await.unwrap();
let update = test_aws_build(&monitor).await?;
let end_ts = unix_timestamp_ms();
let finished_in = (end_ts - start_ts) as f64 / 1000.0;
println!("\nfinished in {finished_in} s");

View File

@@ -3,8 +3,9 @@ use monitor_client::{
futures_util::StreamExt,
tokio_tungstenite::tungstenite::Message,
types::{
Build, Command, Conversion, Deployment, DeploymentWithContainerState, DockerBuildArgs,
Server, SystemStats, Update,
AwsBuilderConfigBuilder, Build, BuildBuilder, Command, Conversion, Deployment,
DeploymentWithContainerState, DockerBuildArgs, DockerBuildArgsBuilder, Server, SystemStats,
Update,
},
MonitorClient,
};
@@ -101,13 +102,9 @@ pub async fn test_build(monitor: &MonitorClient) -> anyhow::Result<Update> {
println!("created build. updating...");
build.repo = Some("mbecker20/monitor".to_string());
// build.branch = Some("");
build.on_clone = Some(Command {
path: ".".to_string(),
command: "yarn".to_string(),
});
build.pre_build = Some(Command {
path: "periphery".to_string(),
command: "yarn build".to_string(),
path: ".".to_string(),
command: "yarn && cd periphery && yarn build".to_string(),
});
build.docker_build_args = Some(DockerBuildArgs {
build_path: "periphery".to_string(),
@@ -129,3 +126,31 @@ pub async fn test_updates(monitor: &MonitorClient) -> anyhow::Result<()> {
println!("{build_updates:#?}");
Ok(())
}
pub async fn test_aws_build(monitor: &MonitorClient) -> anyhow::Result<()> {
let build = BuildBuilder::default()
.name("test_tram".to_string())
.repo(Some(String::from("SocialSocialTrading/master")))
.branch(Some(String::from("master")))
.docker_build_args(
DockerBuildArgsBuilder::default()
.build_path("backend".to_string())
.dockerfile_path("Dockerfile".to_string().into())
.build()
.context("failed to construct DockerBuildArgs struct")?
.into(),
)
.aws_config(
AwsBuilderConfigBuilder::default()
.build()
.context("failed to construct AwsBuilderConfig struct")?
.into(),
)
.build()
.context("failed to construct Build struct")?;
let build = monitor.create_full_build(&build).await?;
println!("{build:#?}\n");
let update = monitor.build(&build.id).await?;
println!("{update:#?}");
Ok(())
}