forked from github-starred/komodo
Compare commits
12 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
d99cf87da0 | ||
|
|
8e19eb7b0f | ||
|
|
78a0b56c73 | ||
|
|
bf5dc52237 | ||
|
|
482ea59d4c | ||
|
|
7740d36f49 | ||
|
|
820754deda | ||
|
|
4219884198 | ||
|
|
d9e24cc35a | ||
|
|
8d2ce884d9 | ||
|
|
313b000e64 | ||
|
|
c2f9e29605 |
176
Cargo.lock
generated
176
Cargo.lock
generated
@@ -41,7 +41,7 @@ dependencies = [
|
||||
|
||||
[[package]]
|
||||
name = "alerter"
|
||||
version = "1.11.0"
|
||||
version = "1.12.0"
|
||||
dependencies = [
|
||||
"anyhow",
|
||||
"axum 0.7.5",
|
||||
@@ -176,8 +176,8 @@ checksum = "4ecbb56dce3eb772cfb3f5a29e802838b3ba1fdb06303d4f1ff54e0d278dc876"
|
||||
dependencies = [
|
||||
"serde",
|
||||
"serde_derive",
|
||||
"strum 0.26.2",
|
||||
"strum_macros 0.26.2",
|
||||
"strum 0.26.3",
|
||||
"strum_macros 0.26.4",
|
||||
"tokio",
|
||||
]
|
||||
|
||||
@@ -195,9 +195,9 @@ checksum = "0c4b4d0bd25bd0b74681c0ad21497610ce1b7c91b1022cd21c80c6fbdd9476b0"
|
||||
|
||||
[[package]]
|
||||
name = "aws-config"
|
||||
version = "1.5.3"
|
||||
version = "1.5.4"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "2368fb843e9eec932f7789d64d0e05850f4a79067188c657e572f1f5a7589df0"
|
||||
checksum = "caf6cfe2881cb1fcbba9ae946fb9a6480d3b7a714ca84c74925014a89ef3387a"
|
||||
dependencies = [
|
||||
"aws-credential-types",
|
||||
"aws-runtime",
|
||||
@@ -238,9 +238,9 @@ dependencies = [
|
||||
|
||||
[[package]]
|
||||
name = "aws-runtime"
|
||||
version = "1.3.0"
|
||||
version = "1.3.1"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "9a4a5e448145999d7de17bf44a886900ecb834953408dae8aaf90465ce91c1dd"
|
||||
checksum = "87c5f920ffd1e0526ec9e70e50bf444db50b204395a0fa7016bbf9e31ea1698f"
|
||||
dependencies = [
|
||||
"aws-credential-types",
|
||||
"aws-sigv4",
|
||||
@@ -261,9 +261,9 @@ dependencies = [
|
||||
|
||||
[[package]]
|
||||
name = "aws-sdk-ec2"
|
||||
version = "1.55.0"
|
||||
version = "1.61.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "e2fd9674e7f6fd95c7df47694c7826ea34d0c997529b62708df886de4bab6887"
|
||||
checksum = "7e31b40d3fc7f1f2165f4705c4293f74890bfd8a9bef37d481e7b45957a051f2"
|
||||
dependencies = [
|
||||
"aws-credential-types",
|
||||
"aws-runtime",
|
||||
@@ -285,9 +285,9 @@ dependencies = [
|
||||
|
||||
[[package]]
|
||||
name = "aws-sdk-ecr"
|
||||
version = "1.33.0"
|
||||
version = "1.36.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "23c7734480f3e434de256544f534cda7ac08742808dd485f64ab86782cbb5c48"
|
||||
checksum = "fa6847b27655b7f8c7ad505c3cc49493b3bbde0915e47bfe5071dd1d56bac760"
|
||||
dependencies = [
|
||||
"aws-credential-types",
|
||||
"aws-runtime",
|
||||
@@ -307,9 +307,9 @@ dependencies = [
|
||||
|
||||
[[package]]
|
||||
name = "aws-sdk-sso"
|
||||
version = "1.33.0"
|
||||
version = "1.36.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "b8aee358b755b2738b3ffb8a5b54ee991b28c8a07483a0ff7d49a58305cc2609"
|
||||
checksum = "6acca681c53374bf1d9af0e317a41d12a44902ca0f2d1e10e5cb5bb98ed74f35"
|
||||
dependencies = [
|
||||
"aws-credential-types",
|
||||
"aws-runtime",
|
||||
@@ -329,9 +329,9 @@ dependencies = [
|
||||
|
||||
[[package]]
|
||||
name = "aws-sdk-ssooidc"
|
||||
version = "1.34.0"
|
||||
version = "1.37.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "1d5ce026f0ae73e06b20be5932150dd0e9b063417fd7c3acf5ca97018b9cbd64"
|
||||
checksum = "b79c6bdfe612503a526059c05c9ccccbf6bd9530b003673cb863e547fd7c0c9a"
|
||||
dependencies = [
|
||||
"aws-credential-types",
|
||||
"aws-runtime",
|
||||
@@ -351,9 +351,9 @@ dependencies = [
|
||||
|
||||
[[package]]
|
||||
name = "aws-sdk-sts"
|
||||
version = "1.33.0"
|
||||
version = "1.36.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "c820248cb02e4ea83630ad2e43d0721cdbccedba5ac902cd0b6fb84d7271f205"
|
||||
checksum = "32e6ecdb2bd756f3b2383e6f0588dc10a4e65f5d551e70a56e0bfe0c884673ce"
|
||||
dependencies = [
|
||||
"aws-credential-types",
|
||||
"aws-runtime",
|
||||
@@ -374,9 +374,9 @@ dependencies = [
|
||||
|
||||
[[package]]
|
||||
name = "aws-sigv4"
|
||||
version = "1.2.2"
|
||||
version = "1.2.3"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "31eed8d45759b2c5fe7fd304dd70739060e9e0de509209036eabea14d0720cce"
|
||||
checksum = "5df1b0fa6be58efe9d4ccc257df0a53b89cd8909e86591a13ca54817c87517be"
|
||||
dependencies = [
|
||||
"aws-credential-types",
|
||||
"aws-smithy-http",
|
||||
@@ -408,9 +408,9 @@ dependencies = [
|
||||
|
||||
[[package]]
|
||||
name = "aws-smithy-http"
|
||||
version = "0.60.8"
|
||||
version = "0.60.9"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "4a7de001a1b9a25601016d8057ea16e31a45fdca3751304c8edf4ad72e706c08"
|
||||
checksum = "d9cd0ae3d97daa0a2bf377a4d8e8e1362cae590c4a1aad0d40058ebca18eb91e"
|
||||
dependencies = [
|
||||
"aws-smithy-runtime-api",
|
||||
"aws-smithy-types",
|
||||
@@ -447,9 +447,9 @@ dependencies = [
|
||||
|
||||
[[package]]
|
||||
name = "aws-smithy-runtime"
|
||||
version = "1.6.0"
|
||||
version = "1.6.2"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "db83b08939838d18e33b5dbaf1a0f048f28c10bd28071ab7ce6f245451855414"
|
||||
checksum = "ce87155eba55e11768b8c1afa607f3e864ae82f03caf63258b37455b0ad02537"
|
||||
dependencies = [
|
||||
"aws-smithy-async",
|
||||
"aws-smithy-http",
|
||||
@@ -474,9 +474,9 @@ dependencies = [
|
||||
|
||||
[[package]]
|
||||
name = "aws-smithy-runtime-api"
|
||||
version = "1.7.0"
|
||||
version = "1.7.1"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "1b570ea39eb95bd32543f6e4032bce172cb6209b9bc8c83c770d08169e875afc"
|
||||
checksum = "30819352ed0a04ecf6a2f3477e344d2d1ba33d43e0f09ad9047c12e0d923616f"
|
||||
dependencies = [
|
||||
"aws-smithy-async",
|
||||
"aws-smithy-types",
|
||||
@@ -526,9 +526,9 @@ dependencies = [
|
||||
|
||||
[[package]]
|
||||
name = "aws-types"
|
||||
version = "1.3.2"
|
||||
version = "1.3.3"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "2009a9733865d0ebf428a314440bbe357cc10d0c16d86a8e15d32e9b47c1e80e"
|
||||
checksum = "5221b91b3e441e6675310829fd8984801b772cb1546ef6c0e54dec9f1ac13fef"
|
||||
dependencies = [
|
||||
"aws-credential-types",
|
||||
"aws-smithy-async",
|
||||
@@ -581,7 +581,7 @@ dependencies = [
|
||||
"http 1.1.0",
|
||||
"http-body 1.0.0",
|
||||
"http-body-util",
|
||||
"hyper 1.3.1",
|
||||
"hyper 1.4.1",
|
||||
"hyper-util",
|
||||
"itoa",
|
||||
"matchit",
|
||||
@@ -790,7 +790,7 @@ dependencies = [
|
||||
"hex",
|
||||
"http 1.1.0",
|
||||
"http-body-util",
|
||||
"hyper 1.3.1",
|
||||
"hyper 1.4.1",
|
||||
"hyper-named-pipe",
|
||||
"hyper-util",
|
||||
"hyperlocal-next",
|
||||
@@ -911,9 +911,9 @@ dependencies = [
|
||||
|
||||
[[package]]
|
||||
name = "clap"
|
||||
version = "4.5.7"
|
||||
version = "4.5.9"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "5db83dced34638ad474f39f250d7fea9598bdd239eaced1bdf45d597da0f433f"
|
||||
checksum = "64acc1846d54c1fe936a78dc189c34e28d3f5afc348403f28ecf53660b9b8462"
|
||||
dependencies = [
|
||||
"clap_builder",
|
||||
"clap_derive",
|
||||
@@ -921,9 +921,9 @@ dependencies = [
|
||||
|
||||
[[package]]
|
||||
name = "clap_builder"
|
||||
version = "4.5.7"
|
||||
version = "4.5.9"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "f7e204572485eb3fbf28f871612191521df159bc3e15a9f5064c66dba3a8c05f"
|
||||
checksum = "6fb8393d67ba2e7bfaf28a23458e4e2b543cc73a99595511eb207fdb8aede942"
|
||||
dependencies = [
|
||||
"anstream",
|
||||
"anstyle",
|
||||
@@ -933,9 +933,9 @@ dependencies = [
|
||||
|
||||
[[package]]
|
||||
name = "clap_derive"
|
||||
version = "4.5.5"
|
||||
version = "4.5.8"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "c780290ccf4fb26629baa7a1081e68ced113f1d3ec302fa5948f1c381ebf06c6"
|
||||
checksum = "2bac35c6dafb060fd4d275d9a4ffae97917c13a6327903a8be2153cd964f7085"
|
||||
dependencies = [
|
||||
"heck 0.5.0",
|
||||
"proc-macro2",
|
||||
@@ -967,7 +967,7 @@ dependencies = [
|
||||
|
||||
[[package]]
|
||||
name = "command"
|
||||
version = "1.11.0"
|
||||
version = "1.12.0"
|
||||
dependencies = [
|
||||
"monitor_client",
|
||||
"run_command",
|
||||
@@ -1351,7 +1351,7 @@ dependencies = [
|
||||
|
||||
[[package]]
|
||||
name = "formatting"
|
||||
version = "1.11.0"
|
||||
version = "1.12.0"
|
||||
dependencies = [
|
||||
"serror",
|
||||
]
|
||||
@@ -1482,7 +1482,7 @@ checksum = "4271d37baee1b8c7e4b708028c57d816cf9d2434acb33a549475f78c181f6253"
|
||||
|
||||
[[package]]
|
||||
name = "git"
|
||||
version = "1.11.0"
|
||||
version = "1.12.0"
|
||||
dependencies = [
|
||||
"anyhow",
|
||||
"command",
|
||||
@@ -1725,9 +1725,9 @@ dependencies = [
|
||||
|
||||
[[package]]
|
||||
name = "hyper"
|
||||
version = "1.3.1"
|
||||
version = "1.4.1"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "fe575dd17d0862a9a33781c8c4696a55c320909004a67a00fb286ba8b1bc496d"
|
||||
checksum = "50dfd22e0e76d0f662d429a5f80fcaf3855009297eab6a0a9f8543834744ba05"
|
||||
dependencies = [
|
||||
"bytes",
|
||||
"futures-channel",
|
||||
@@ -1751,7 +1751,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "73b7d8abf35697b81a825e386fc151e0d503e8cb5fcb93cc8669c376dfd6f278"
|
||||
dependencies = [
|
||||
"hex",
|
||||
"hyper 1.3.1",
|
||||
"hyper 1.4.1",
|
||||
"hyper-util",
|
||||
"pin-project-lite",
|
||||
"tokio",
|
||||
@@ -1783,7 +1783,7 @@ checksum = "5ee4be2c948921a1a5320b629c4193916ed787a7f7f293fd3f7f5a6c9de74155"
|
||||
dependencies = [
|
||||
"futures-util",
|
||||
"http 1.1.0",
|
||||
"hyper 1.3.1",
|
||||
"hyper 1.4.1",
|
||||
"hyper-util",
|
||||
"rustls 0.23.10",
|
||||
"rustls-pki-types",
|
||||
@@ -1825,7 +1825,7 @@ checksum = "70206fc6890eaca9fde8a0bf71caa2ddfc9fe045ac9e5c70df101a7dbde866e0"
|
||||
dependencies = [
|
||||
"bytes",
|
||||
"http-body-util",
|
||||
"hyper 1.3.1",
|
||||
"hyper 1.4.1",
|
||||
"hyper-util",
|
||||
"native-tls",
|
||||
"tokio",
|
||||
@@ -1835,16 +1835,16 @@ dependencies = [
|
||||
|
||||
[[package]]
|
||||
name = "hyper-util"
|
||||
version = "0.1.3"
|
||||
version = "0.1.6"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "ca38ef113da30126bbff9cd1705f9273e15d45498615d138b0c20279ac7a76aa"
|
||||
checksum = "3ab92f4f49ee4fb4f997c784b7a2e0fa70050211e0b6a287f898c3c9785ca956"
|
||||
dependencies = [
|
||||
"bytes",
|
||||
"futures-channel",
|
||||
"futures-util",
|
||||
"http 1.1.0",
|
||||
"http-body 1.0.0",
|
||||
"hyper 1.3.1",
|
||||
"hyper 1.4.1",
|
||||
"pin-project-lite",
|
||||
"socket2",
|
||||
"tokio",
|
||||
@@ -1861,7 +1861,7 @@ checksum = "acf569d43fa9848e510358c07b80f4adf34084ddc28c6a4a651ee8474c070dcc"
|
||||
dependencies = [
|
||||
"hex",
|
||||
"http-body-util",
|
||||
"hyper 1.3.1",
|
||||
"hyper 1.4.1",
|
||||
"hyper-util",
|
||||
"pin-project-lite",
|
||||
"tokio",
|
||||
@@ -2083,7 +2083,7 @@ dependencies = [
|
||||
|
||||
[[package]]
|
||||
name = "logger"
|
||||
version = "1.11.0"
|
||||
version = "1.12.0"
|
||||
dependencies = [
|
||||
"anyhow",
|
||||
"monitor_client",
|
||||
@@ -2152,7 +2152,7 @@ dependencies = [
|
||||
|
||||
[[package]]
|
||||
name = "migrator"
|
||||
version = "1.11.0"
|
||||
version = "1.12.0"
|
||||
dependencies = [
|
||||
"anyhow",
|
||||
"chrono",
|
||||
@@ -2286,7 +2286,7 @@ dependencies = [
|
||||
|
||||
[[package]]
|
||||
name = "monitor_cli"
|
||||
version = "1.11.0"
|
||||
version = "1.12.0"
|
||||
dependencies = [
|
||||
"anyhow",
|
||||
"clap",
|
||||
@@ -2297,7 +2297,7 @@ dependencies = [
|
||||
"partial_derive2",
|
||||
"serde",
|
||||
"serde_json",
|
||||
"strum 0.26.2",
|
||||
"strum 0.26.3",
|
||||
"tokio",
|
||||
"toml",
|
||||
"tracing",
|
||||
@@ -2306,7 +2306,7 @@ dependencies = [
|
||||
|
||||
[[package]]
|
||||
name = "monitor_client"
|
||||
version = "1.11.0"
|
||||
version = "1.12.0"
|
||||
dependencies = [
|
||||
"anyhow",
|
||||
"async_timing_util",
|
||||
@@ -2326,7 +2326,7 @@ dependencies = [
|
||||
"serde",
|
||||
"serde_json",
|
||||
"serror",
|
||||
"strum 0.26.2",
|
||||
"strum 0.26.3",
|
||||
"thiserror",
|
||||
"tokio",
|
||||
"tokio-tungstenite 0.23.1",
|
||||
@@ -2338,7 +2338,7 @@ dependencies = [
|
||||
|
||||
[[package]]
|
||||
name = "monitor_core"
|
||||
version = "1.11.0"
|
||||
version = "1.12.0"
|
||||
dependencies = [
|
||||
"anyhow",
|
||||
"async_timing_util",
|
||||
@@ -2379,7 +2379,7 @@ dependencies = [
|
||||
"serror",
|
||||
"sha2",
|
||||
"slack_client_rs",
|
||||
"strum 0.26.2",
|
||||
"strum 0.26.3",
|
||||
"svi",
|
||||
"tokio",
|
||||
"tokio-util",
|
||||
@@ -2395,7 +2395,7 @@ dependencies = [
|
||||
|
||||
[[package]]
|
||||
name = "monitor_periphery"
|
||||
version = "1.11.0"
|
||||
version = "1.12.0"
|
||||
dependencies = [
|
||||
"anyhow",
|
||||
"async_timing_util",
|
||||
@@ -2839,7 +2839,7 @@ checksum = "e3148f5046208a5d56bcfc03053e3ca6334e51da8dfb19b6cdc8b306fae3283e"
|
||||
|
||||
[[package]]
|
||||
name = "periphery_client"
|
||||
version = "1.11.0"
|
||||
version = "1.12.0"
|
||||
dependencies = [
|
||||
"anyhow",
|
||||
"monitor_client",
|
||||
@@ -3117,7 +3117,7 @@ dependencies = [
|
||||
"http 1.1.0",
|
||||
"http-body 1.0.0",
|
||||
"http-body-util",
|
||||
"hyper 1.3.1",
|
||||
"hyper 1.4.1",
|
||||
"hyper-rustls 0.27.2",
|
||||
"hyper-tls 0.6.0",
|
||||
"hyper-util",
|
||||
@@ -3536,9 +3536,9 @@ checksum = "388a1df253eca08550bef6c72392cfe7c30914bf41df5269b68cbd6ff8f570a3"
|
||||
|
||||
[[package]]
|
||||
name = "serde"
|
||||
version = "1.0.203"
|
||||
version = "1.0.204"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "7253ab4de971e72fb7be983802300c30b5a7f0c2e56fab8abfc6a214307c0094"
|
||||
checksum = "bc76f558e0cbb2a839d37354c575f1dc3fdc6546b5be373ba43d95f231bf7c12"
|
||||
dependencies = [
|
||||
"serde_derive",
|
||||
]
|
||||
@@ -3554,9 +3554,9 @@ dependencies = [
|
||||
|
||||
[[package]]
|
||||
name = "serde_derive"
|
||||
version = "1.0.203"
|
||||
version = "1.0.204"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "500cbc0ebeb6f46627f50f3f5811ccf6bf00643be300b4c3eabc0ef55dc5b5ba"
|
||||
checksum = "e0cd7e117be63d3c3678776753929474f3b04a43a080c744d6b0ae2a8c28e222"
|
||||
dependencies = [
|
||||
"proc-macro2",
|
||||
"quote",
|
||||
@@ -3576,9 +3576,9 @@ dependencies = [
|
||||
|
||||
[[package]]
|
||||
name = "serde_json"
|
||||
version = "1.0.119"
|
||||
version = "1.0.120"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "e8eddb61f0697cc3989c5d64b452f5488e2b8a60fd7d5076a3045076ffef8cb0"
|
||||
checksum = "4e0d21c9a8cae1235ad58a00c11cb40d4b1e5c784f1ef2c537876ed6ffd8b7c5"
|
||||
dependencies = [
|
||||
"indexmap 2.2.6",
|
||||
"itoa",
|
||||
@@ -3669,9 +3669,9 @@ dependencies = [
|
||||
|
||||
[[package]]
|
||||
name = "serror"
|
||||
version = "0.4.3"
|
||||
version = "0.4.6"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "a58297fe0d139a2950d2f474c3f5d0614eecc2b90f3bfe3ee28dca36dfcfd78d"
|
||||
checksum = "d8f432d878d404110352cfbaa031d8a6878a166cb7f50e00ab87d0508f8f68a0"
|
||||
dependencies = [
|
||||
"anyhow",
|
||||
"axum 0.7.5",
|
||||
@@ -3825,11 +3825,11 @@ checksum = "290d54ea6f91c969195bdbcd7442c8c2a2ba87da8bf60a7ee86a235d4bc1e125"
|
||||
|
||||
[[package]]
|
||||
name = "strum"
|
||||
version = "0.26.2"
|
||||
version = "0.26.3"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "5d8cec3501a5194c432b2b7976db6b7d10ec95c253208b45f83f7136aa985e29"
|
||||
checksum = "8fec0f0aef304996cf250b31b5a10dee7980c85da9d759361292b8bca5a18f06"
|
||||
dependencies = [
|
||||
"strum_macros 0.26.2",
|
||||
"strum_macros 0.26.4",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
@@ -3847,11 +3847,11 @@ dependencies = [
|
||||
|
||||
[[package]]
|
||||
name = "strum_macros"
|
||||
version = "0.26.2"
|
||||
version = "0.26.4"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "c6cf59daf282c0a494ba14fd21610a0325f9f90ec9d1231dea26bcb1d696c946"
|
||||
checksum = "4c6bee85a5a24955dc440386795aa378cd9cf82acd5f764469152d2270e581be"
|
||||
dependencies = [
|
||||
"heck 0.4.1",
|
||||
"heck 0.5.0",
|
||||
"proc-macro2",
|
||||
"quote",
|
||||
"rustversion",
|
||||
@@ -3909,9 +3909,9 @@ checksum = "a7065abeca94b6a8a577f9bd45aa0867a2238b74e8eb67cf10d492bc39351394"
|
||||
|
||||
[[package]]
|
||||
name = "sysinfo"
|
||||
version = "0.30.12"
|
||||
version = "0.30.13"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "732ffa00f53e6b2af46208fba5718d9662a421049204e156328b66791ffa15ae"
|
||||
checksum = "0a5b4ddaee55fb2bea2bf0e5000747e5f5c0de765e5a5ff87f4cd106439f4bb3"
|
||||
dependencies = [
|
||||
"cfg-if",
|
||||
"core-foundation-sys",
|
||||
@@ -3978,7 +3978,7 @@ dependencies = [
|
||||
|
||||
[[package]]
|
||||
name = "tests"
|
||||
version = "1.11.0"
|
||||
version = "1.12.0"
|
||||
dependencies = [
|
||||
"anyhow",
|
||||
"dotenv",
|
||||
@@ -3996,18 +3996,18 @@ dependencies = [
|
||||
|
||||
[[package]]
|
||||
name = "thiserror"
|
||||
version = "1.0.61"
|
||||
version = "1.0.63"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "c546c80d6be4bc6a00c0f01730c08df82eaa7a7a61f11d656526506112cc1709"
|
||||
checksum = "c0342370b38b6a11b6cc11d6a805569958d54cfa061a29969c3b5ce2ea405724"
|
||||
dependencies = [
|
||||
"thiserror-impl",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "thiserror-impl"
|
||||
version = "1.0.61"
|
||||
version = "1.0.63"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "46c3384250002a6d5af4d114f2845d37b57521033f30d5c3f46c4d70e1197533"
|
||||
checksum = "a4558b58466b9ad7ca0f102865eccc95938dca1a74a856f2b57b6629050da261"
|
||||
dependencies = [
|
||||
"proc-macro2",
|
||||
"quote",
|
||||
@@ -4072,9 +4072,9 @@ checksum = "1f3ccbac311fea05f86f61904b462b55fb3df8837a366dfc601a0161d0532f20"
|
||||
|
||||
[[package]]
|
||||
name = "tokio"
|
||||
version = "1.38.0"
|
||||
version = "1.38.1"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "ba4f4a02a7a80d6f274636f0aa95c7e383b912d41fe721a31f29e29698585a4a"
|
||||
checksum = "eb2caba9f80616f438e09748d5acda951967e1ea58508ef53d9c6402485a46df"
|
||||
dependencies = [
|
||||
"backtrace",
|
||||
"bytes",
|
||||
@@ -4192,9 +4192,9 @@ dependencies = [
|
||||
|
||||
[[package]]
|
||||
name = "toml"
|
||||
version = "0.8.14"
|
||||
version = "0.8.15"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "6f49eb2ab21d2f26bd6db7bf383edc527a7ebaee412d17af4d40fdccd442f335"
|
||||
checksum = "ac2caab0bf757388c6c0ae23b3293fdb463fee59434529014f85e3263b995c28"
|
||||
dependencies = [
|
||||
"serde",
|
||||
"serde_spanned",
|
||||
@@ -4213,9 +4213,9 @@ dependencies = [
|
||||
|
||||
[[package]]
|
||||
name = "toml_edit"
|
||||
version = "0.22.14"
|
||||
version = "0.22.16"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "f21c7aaf97f1bd9ca9d4f9e73b0a6c74bd5afef56f2bc931943a6e1c37e04e38"
|
||||
checksum = "278f3d518e152219c994ce877758516bca5e118eaed6996192a774fb9fbf0788"
|
||||
dependencies = [
|
||||
"indexmap 2.2.6",
|
||||
"serde",
|
||||
@@ -4580,7 +4580,7 @@ checksum = "8ecb6da28b8a351d773b68d5825ac39017e680750f980f3a1a85cd8dd28a47c1"
|
||||
|
||||
[[package]]
|
||||
name = "update_logger"
|
||||
version = "1.11.0"
|
||||
version = "1.12.0"
|
||||
dependencies = [
|
||||
"anyhow",
|
||||
"logger",
|
||||
@@ -4621,9 +4621,9 @@ checksum = "711b9620af191e0cdc7468a8d14e709c3dcdb115b36f838e601583af800a370a"
|
||||
|
||||
[[package]]
|
||||
name = "uuid"
|
||||
version = "1.9.1"
|
||||
version = "1.10.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "5de17fd2f7da591098415cff336e12965a28061ddace43b59cb3c430179c9439"
|
||||
checksum = "81dfa00651efa65069b0b6b651f4aaa31ba9e3c3ce0137aaad053604ee7e0314"
|
||||
dependencies = [
|
||||
"getrandom",
|
||||
"rand",
|
||||
|
||||
30
Cargo.toml
30
Cargo.toml
@@ -3,7 +3,7 @@ resolver = "2"
|
||||
members = ["bin/*", "lib/*", "client/core/rs", "client/periphery/rs"]
|
||||
|
||||
[workspace.package]
|
||||
version = "1.11.0"
|
||||
version = "1.12.0"
|
||||
edition = "2021"
|
||||
authors = ["mbecker20 <becker.maxh@gmail.com>"]
|
||||
license = "GPL-3.0-or-later"
|
||||
@@ -15,7 +15,7 @@ monitor_client = { path = "client/core/rs" }
|
||||
|
||||
[workspace.dependencies]
|
||||
# LOCAL
|
||||
monitor_client = "1.11.0"
|
||||
monitor_client = "1.12.0"
|
||||
periphery_client = { path = "client/periphery/rs" }
|
||||
formatting = { path = "lib/formatting" }
|
||||
command = { path = "lib/command" }
|
||||
@@ -24,7 +24,7 @@ git = { path = "lib/git" }
|
||||
|
||||
# MOGH
|
||||
run_command = { version = "0.0.6", features = ["async_tokio"] }
|
||||
serror = { version = "0.4.3", default-features = false }
|
||||
serror = { version = "0.4.6", default-features = false }
|
||||
slack = { version = "0.1.0", package = "slack_client_rs" }
|
||||
derive_default_builder = "0.1.8"
|
||||
derive_empty_traits = "0.1.0"
|
||||
@@ -40,7 +40,7 @@ mungos = "1.0.0"
|
||||
svi = "1.0.1"
|
||||
|
||||
# ASYNC
|
||||
tokio = { version = "1.38.0", features = ["full"] }
|
||||
tokio = { version = "1.38.1", features = ["full"] }
|
||||
reqwest = { version = "0.12.5", features = ["json"] }
|
||||
tokio-util = "0.7.11"
|
||||
futures = "0.3.30"
|
||||
@@ -55,14 +55,14 @@ tokio-tungstenite = "0.23.1"
|
||||
|
||||
# SER/DE
|
||||
ordered_hash_map = { version = "0.4.0", features = ["serde"] }
|
||||
serde = { version = "1.0.203", features = ["derive"] }
|
||||
strum = { version = "0.26.2", features = ["derive"] }
|
||||
serde_json = "1.0.118"
|
||||
toml = "0.8.14"
|
||||
serde = { version = "1.0.204", features = ["derive"] }
|
||||
strum = { version = "0.26.3", features = ["derive"] }
|
||||
serde_json = "1.0.120"
|
||||
toml = "0.8.15"
|
||||
|
||||
# ERROR
|
||||
anyhow = "1.0.86"
|
||||
thiserror = "1.0.61"
|
||||
thiserror = "1.0.63"
|
||||
|
||||
# LOGGING
|
||||
opentelemetry_sdk = { version = "0.23.0", features = ["rt-tokio"] }
|
||||
@@ -73,12 +73,12 @@ opentelemetry = "0.23.0"
|
||||
tracing = "0.1.40"
|
||||
|
||||
# CONFIG
|
||||
clap = { version = "4.5.7", features = ["derive"] }
|
||||
clap = { version = "4.5.9", features = ["derive"] }
|
||||
dotenv = "0.15.0"
|
||||
envy = "0.4.2"
|
||||
|
||||
# CRYPTO
|
||||
uuid = { version = "1.9.1", features = ["v4", "fast-rng", "serde"] }
|
||||
uuid = { version = "1.10.0", features = ["v4", "fast-rng", "serde"] }
|
||||
urlencoding = "2.1.3"
|
||||
nom_pem = "4.0.0"
|
||||
bcrypt = "0.15.1"
|
||||
@@ -91,12 +91,12 @@ hex = "0.4.3"
|
||||
|
||||
# SYSTEM
|
||||
bollard = "0.16.1"
|
||||
sysinfo = "0.30.12"
|
||||
sysinfo = "0.30.13"
|
||||
|
||||
# CLOUD
|
||||
aws-config = "1.5.3"
|
||||
aws-sdk-ec2 = "1.53.0"
|
||||
aws-sdk-ecr = "1.33.0"
|
||||
aws-config = "1.5.4"
|
||||
aws-sdk-ec2 = "1.60.0"
|
||||
aws-sdk-ecr = "1.35.0"
|
||||
|
||||
# MISC
|
||||
derive_builder = "0.20.0"
|
||||
|
||||
@@ -20,7 +20,7 @@ pub fn name_to_build() -> &'static HashMap<String, Build> {
|
||||
futures::executor::block_on(
|
||||
monitor_client().read(read::ListFullBuilds::default()),
|
||||
)
|
||||
.expect("failed to get builds from monitor")
|
||||
.expect("failed to get builds")
|
||||
.into_iter()
|
||||
.map(|build| (build.name.clone(), build))
|
||||
.collect()
|
||||
@@ -34,7 +34,7 @@ pub fn id_to_build() -> &'static HashMap<String, Build> {
|
||||
futures::executor::block_on(
|
||||
monitor_client().read(read::ListFullBuilds::default()),
|
||||
)
|
||||
.expect("failed to get builds from monitor")
|
||||
.expect("failed to get builds")
|
||||
.into_iter()
|
||||
.map(|build| (build.id.clone(), build))
|
||||
.collect()
|
||||
@@ -48,7 +48,7 @@ pub fn name_to_deployment() -> &'static HashMap<String, Deployment> {
|
||||
futures::executor::block_on(
|
||||
monitor_client().read(read::ListFullDeployments::default()),
|
||||
)
|
||||
.expect("failed to get deployments from monitor")
|
||||
.expect("failed to get deployments")
|
||||
.into_iter()
|
||||
.map(|deployment| (deployment.name.clone(), deployment))
|
||||
.collect()
|
||||
@@ -62,7 +62,7 @@ pub fn id_to_deployment() -> &'static HashMap<String, Deployment> {
|
||||
futures::executor::block_on(
|
||||
monitor_client().read(read::ListFullDeployments::default()),
|
||||
)
|
||||
.expect("failed to get deployments from monitor")
|
||||
.expect("failed to get deployments")
|
||||
.into_iter()
|
||||
.map(|deployment| (deployment.id.clone(), deployment))
|
||||
.collect()
|
||||
@@ -76,7 +76,7 @@ pub fn name_to_server() -> &'static HashMap<String, Server> {
|
||||
futures::executor::block_on(
|
||||
monitor_client().read(read::ListFullServers::default()),
|
||||
)
|
||||
.expect("failed to get servers from monitor")
|
||||
.expect("failed to get servers")
|
||||
.into_iter()
|
||||
.map(|server| (server.name.clone(), server))
|
||||
.collect()
|
||||
@@ -90,7 +90,7 @@ pub fn id_to_server() -> &'static HashMap<String, Server> {
|
||||
futures::executor::block_on(
|
||||
monitor_client().read(read::ListFullServers::default()),
|
||||
)
|
||||
.expect("failed to get servers from monitor")
|
||||
.expect("failed to get servers")
|
||||
.into_iter()
|
||||
.map(|server| (server.id.clone(), server))
|
||||
.collect()
|
||||
@@ -104,7 +104,7 @@ pub fn name_to_builder() -> &'static HashMap<String, Builder> {
|
||||
futures::executor::block_on(
|
||||
monitor_client().read(read::ListFullBuilders::default()),
|
||||
)
|
||||
.expect("failed to get builders from monitor")
|
||||
.expect("failed to get builders")
|
||||
.into_iter()
|
||||
.map(|builder| (builder.name.clone(), builder))
|
||||
.collect()
|
||||
@@ -118,7 +118,7 @@ pub fn id_to_builder() -> &'static HashMap<String, Builder> {
|
||||
futures::executor::block_on(
|
||||
monitor_client().read(read::ListFullBuilders::default()),
|
||||
)
|
||||
.expect("failed to get builders from monitor")
|
||||
.expect("failed to get builders")
|
||||
.into_iter()
|
||||
.map(|builder| (builder.id.clone(), builder))
|
||||
.collect()
|
||||
@@ -132,7 +132,7 @@ pub fn name_to_alerter() -> &'static HashMap<String, Alerter> {
|
||||
futures::executor::block_on(
|
||||
monitor_client().read(read::ListFullAlerters::default()),
|
||||
)
|
||||
.expect("failed to get alerters from monitor")
|
||||
.expect("failed to get alerters")
|
||||
.into_iter()
|
||||
.map(|alerter| (alerter.name.clone(), alerter))
|
||||
.collect()
|
||||
@@ -146,7 +146,7 @@ pub fn id_to_alerter() -> &'static HashMap<String, Alerter> {
|
||||
futures::executor::block_on(
|
||||
monitor_client().read(read::ListFullAlerters::default()),
|
||||
)
|
||||
.expect("failed to get alerters from monitor")
|
||||
.expect("failed to get alerters")
|
||||
.into_iter()
|
||||
.map(|alerter| (alerter.id.clone(), alerter))
|
||||
.collect()
|
||||
@@ -160,7 +160,7 @@ pub fn name_to_repo() -> &'static HashMap<String, Repo> {
|
||||
futures::executor::block_on(
|
||||
monitor_client().read(read::ListFullRepos::default()),
|
||||
)
|
||||
.expect("failed to get repos from monitor")
|
||||
.expect("failed to get repos")
|
||||
.into_iter()
|
||||
.map(|repo| (repo.name.clone(), repo))
|
||||
.collect()
|
||||
@@ -174,7 +174,7 @@ pub fn id_to_repo() -> &'static HashMap<String, Repo> {
|
||||
futures::executor::block_on(
|
||||
monitor_client().read(read::ListFullRepos::default()),
|
||||
)
|
||||
.expect("failed to get repos from monitor")
|
||||
.expect("failed to get repos")
|
||||
.into_iter()
|
||||
.map(|repo| (repo.id.clone(), repo))
|
||||
.collect()
|
||||
@@ -188,7 +188,7 @@ pub fn name_to_procedure() -> &'static HashMap<String, Procedure> {
|
||||
futures::executor::block_on(
|
||||
monitor_client().read(read::ListFullProcedures::default()),
|
||||
)
|
||||
.expect("failed to get procedures from monitor")
|
||||
.expect("failed to get procedures")
|
||||
.into_iter()
|
||||
.map(|procedure| (procedure.name.clone(), procedure))
|
||||
.collect()
|
||||
@@ -202,7 +202,7 @@ pub fn id_to_procedure() -> &'static HashMap<String, Procedure> {
|
||||
futures::executor::block_on(
|
||||
monitor_client().read(read::ListFullProcedures::default()),
|
||||
)
|
||||
.expect("failed to get procedures from monitor")
|
||||
.expect("failed to get procedures")
|
||||
.into_iter()
|
||||
.map(|procedure| (procedure.id.clone(), procedure))
|
||||
.collect()
|
||||
@@ -218,7 +218,7 @@ pub fn name_to_server_template(
|
||||
futures::executor::block_on(
|
||||
monitor_client().read(read::ListFullServerTemplates::default()),
|
||||
)
|
||||
.expect("failed to get server templates from monitor")
|
||||
.expect("failed to get server templates")
|
||||
.into_iter()
|
||||
.map(|procedure| (procedure.name.clone(), procedure))
|
||||
.collect()
|
||||
@@ -234,7 +234,7 @@ pub fn id_to_server_template(
|
||||
futures::executor::block_on(
|
||||
monitor_client().read(read::ListFullServerTemplates::default()),
|
||||
)
|
||||
.expect("failed to get server templates from monitor")
|
||||
.expect("failed to get server templates")
|
||||
.into_iter()
|
||||
.map(|procedure| (procedure.id.clone(), procedure))
|
||||
.collect()
|
||||
@@ -249,7 +249,7 @@ pub fn name_to_resource_sync(
|
||||
futures::executor::block_on(
|
||||
monitor_client().read(read::ListFullResourceSyncs::default()),
|
||||
)
|
||||
.expect("failed to get syncs from monitor")
|
||||
.expect("failed to get syncs")
|
||||
.into_iter()
|
||||
.map(|sync| (sync.name.clone(), sync))
|
||||
.collect()
|
||||
@@ -264,7 +264,7 @@ pub fn id_to_resource_sync() -> &'static HashMap<String, ResourceSync>
|
||||
futures::executor::block_on(
|
||||
monitor_client().read(read::ListFullResourceSyncs::default()),
|
||||
)
|
||||
.expect("failed to get syncs from monitor")
|
||||
.expect("failed to get syncs")
|
||||
.into_iter()
|
||||
.map(|sync| (sync.id.clone(), sync))
|
||||
.collect()
|
||||
@@ -278,7 +278,7 @@ pub fn name_to_user_group() -> &'static HashMap<String, UserGroup> {
|
||||
futures::executor::block_on(
|
||||
monitor_client().read(read::ListUserGroups::default()),
|
||||
)
|
||||
.expect("failed to get user groups from monitor")
|
||||
.expect("failed to get user groups")
|
||||
.into_iter()
|
||||
.map(|user_group| (user_group.name.clone(), user_group))
|
||||
.collect()
|
||||
@@ -292,8 +292,7 @@ pub fn name_to_variable() -> &'static HashMap<String, Variable> {
|
||||
futures::executor::block_on(
|
||||
monitor_client().read(read::ListVariables::default()),
|
||||
)
|
||||
.expect("failed to get user groups from monitor")
|
||||
.variables
|
||||
.expect("failed to get variables")
|
||||
.into_iter()
|
||||
.map(|variable| (variable.name.clone(), variable))
|
||||
.collect()
|
||||
@@ -307,7 +306,7 @@ pub fn id_to_user() -> &'static HashMap<String, User> {
|
||||
futures::executor::block_on(
|
||||
monitor_client().read(read::ListUsers::default()),
|
||||
)
|
||||
.expect("failed to get users from monitor")
|
||||
.expect("failed to get users")
|
||||
.into_iter()
|
||||
.map(|user| (user.id.clone(), user))
|
||||
.collect()
|
||||
@@ -320,7 +319,7 @@ pub fn id_to_tag() -> &'static HashMap<String, Tag> {
|
||||
futures::executor::block_on(
|
||||
monitor_client().read(read::ListTags::default()),
|
||||
)
|
||||
.expect("failed to get tags from monitor")
|
||||
.expect("failed to get tags")
|
||||
.into_iter()
|
||||
.map(|tag| (tag.id.clone(), tag))
|
||||
.collect()
|
||||
|
||||
@@ -10,7 +10,7 @@ use monitor_client::{
|
||||
entities::{
|
||||
alert::{Alert, AlertData},
|
||||
all_logs_success,
|
||||
build::{Build, CloudRegistryConfig, ImageRegistry},
|
||||
build::{Build, ImageRegistry, StandardRegistryConfig},
|
||||
builder::{AwsBuilderConfig, Builder, BuilderConfig},
|
||||
config::core::{AwsEcrConfig, AwsEcrConfigWithCredentials},
|
||||
deployment::DeploymentState,
|
||||
@@ -79,9 +79,6 @@ impl Resolve<RunBuild, (User, Update)> for State {
|
||||
)
|
||||
.await?;
|
||||
|
||||
let (registry_token, aws_ecr) =
|
||||
validate_account_extract_registry_token_aws_ecr(&build).await?;
|
||||
|
||||
// get the action state for the build (or insert default).
|
||||
let action_state =
|
||||
action_states().build.get_or_insert_default(&build.id).await;
|
||||
@@ -91,6 +88,9 @@ impl Resolve<RunBuild, (User, Update)> for State {
|
||||
let _action_guard =
|
||||
action_state.update(|state| state.building = true)?;
|
||||
|
||||
let (registry_token, aws_ecr) =
|
||||
validate_account_extract_registry_token_aws_ecr(&build).await?;
|
||||
|
||||
build.config.version.increment();
|
||||
update.version = build.config.version;
|
||||
update_update(update.clone()).await?;
|
||||
@@ -156,17 +156,26 @@ impl Resolve<RunBuild, (User, Update)> for State {
|
||||
let variables = get_global_variables().await?;
|
||||
|
||||
// CLONE REPO
|
||||
|
||||
let github_token = core_config
|
||||
.github_accounts
|
||||
.get(&build.config.github_account)
|
||||
.cloned();
|
||||
let git_token = core_config
|
||||
.git_providers
|
||||
.iter()
|
||||
.find(|provider| provider.domain == build.config.git_provider)
|
||||
.and_then(|provider| {
|
||||
build.config.git_https = provider.https;
|
||||
provider
|
||||
.accounts
|
||||
.iter()
|
||||
.find(|account| {
|
||||
account.username == build.config.git_account
|
||||
})
|
||||
.map(|account| account.token.clone())
|
||||
});
|
||||
|
||||
let res = tokio::select! {
|
||||
res = periphery
|
||||
.request(api::git::CloneRepo {
|
||||
args: (&build).into(),
|
||||
github_token,
|
||||
git_token,
|
||||
}) => res,
|
||||
_ = cancel.cancelled() => {
|
||||
info!("build cancelled during clone, cleaning up builder");
|
||||
@@ -779,28 +788,15 @@ fn start_aws_builder_log(
|
||||
async fn validate_account_extract_registry_token_aws_ecr(
|
||||
build: &Build,
|
||||
) -> anyhow::Result<(Option<String>, Option<AwsEcrConfig>)> {
|
||||
match &build.config.image_registry {
|
||||
ImageRegistry::None(_) => Ok((None, None)),
|
||||
ImageRegistry::DockerHub(CloudRegistryConfig {
|
||||
account, ..
|
||||
}) => {
|
||||
if account.is_empty() {
|
||||
return Err(anyhow!(
|
||||
"Must attach account to use DockerHub image registry"
|
||||
));
|
||||
}
|
||||
Ok((core_config().docker_accounts.get(account).cloned(), None))
|
||||
}
|
||||
ImageRegistry::Ghcr(CloudRegistryConfig { account, .. }) => {
|
||||
if account.is_empty() {
|
||||
return Err(anyhow!(
|
||||
"Must attach account to use GithubContainerRegistry"
|
||||
));
|
||||
}
|
||||
Ok((core_config().github_accounts.get(account).cloned(), None))
|
||||
}
|
||||
let (domain, account) = match &build.config.image_registry {
|
||||
// Early return for None
|
||||
ImageRegistry::None(_) => return Ok((None, None)),
|
||||
// Early return for AwsEcr
|
||||
ImageRegistry::AwsEcr(label) => {
|
||||
let config = core_config().aws_ecr_registries.get(label);
|
||||
let config = core_config()
|
||||
.aws_ecr_registries
|
||||
.iter()
|
||||
.find(|reg| ®.label == label);
|
||||
let token = match config {
|
||||
Some(AwsEcrConfigWithCredentials {
|
||||
region,
|
||||
@@ -827,10 +823,33 @@ async fn validate_account_extract_registry_token_aws_ecr(
|
||||
}
|
||||
None => None,
|
||||
};
|
||||
Ok((token, config.map(AwsEcrConfig::from)))
|
||||
}
|
||||
ImageRegistry::Custom(_) => {
|
||||
Err(anyhow!("Custom image registry is not implemented"))
|
||||
return Ok((token, config.map(AwsEcrConfig::from)));
|
||||
}
|
||||
ImageRegistry::Standard(StandardRegistryConfig {
|
||||
domain,
|
||||
account,
|
||||
..
|
||||
}) => (domain.as_str(), account),
|
||||
};
|
||||
|
||||
if account.is_empty() {
|
||||
return Err(anyhow!(
|
||||
"Must attach account to use registry provider {domain}"
|
||||
));
|
||||
}
|
||||
|
||||
Ok((
|
||||
core_config()
|
||||
.docker_registries
|
||||
.iter()
|
||||
.find(|provider| provider.domain == domain)
|
||||
.and_then(|provider| {
|
||||
provider
|
||||
.accounts
|
||||
.iter()
|
||||
.find(|_account| &_account.username == account)
|
||||
.map(|account| account.token.clone())
|
||||
}),
|
||||
None,
|
||||
))
|
||||
}
|
||||
|
||||
@@ -8,7 +8,9 @@ use monitor_client::{
|
||||
entities::{
|
||||
build::{Build, ImageRegistry},
|
||||
config::core::AwsEcrConfig,
|
||||
deployment::{Deployment, DeploymentImage},
|
||||
deployment::{
|
||||
extract_registry_domain, Deployment, DeploymentImage,
|
||||
},
|
||||
get_image_name,
|
||||
permission::PermissionLevel,
|
||||
server::ServerState,
|
||||
@@ -80,39 +82,101 @@ impl Resolve<Deploy, (User, Update)> for State {
|
||||
|
||||
let periphery = periphery_client(&server)?;
|
||||
|
||||
// This block gets the version of the image to deploy in the Build case.
|
||||
// It also gets the name of the image from the build and attaches it directly.
|
||||
let version = match deployment.config.image {
|
||||
DeploymentImage::Build { build_id, version } => {
|
||||
let build = resource::get::<Build>(&build_id).await?;
|
||||
let image_name = get_image_name(&build, |label| {
|
||||
core_config()
|
||||
.aws_ecr_registries
|
||||
.get(label)
|
||||
.map(AwsEcrConfig::from)
|
||||
})
|
||||
.context("failed to create image name")?;
|
||||
let version = if version.is_none() {
|
||||
build.config.version
|
||||
} else {
|
||||
version
|
||||
};
|
||||
// replace image with corresponding build image.
|
||||
deployment.config.image = DeploymentImage::Image {
|
||||
image: format!("{image_name}:{version}"),
|
||||
};
|
||||
// set image registry to match build docker account if it's not overridden by deployment
|
||||
if matches!(
|
||||
&deployment.config.image_registry,
|
||||
ImageRegistry::None(_)
|
||||
) {
|
||||
deployment.config.image_registry =
|
||||
build.config.image_registry;
|
||||
let (version, registry_token, aws_ecr) =
|
||||
match &deployment.config.image {
|
||||
DeploymentImage::Build { build_id, version } => {
|
||||
let build = resource::get::<Build>(build_id).await?;
|
||||
let image_name = get_image_name(&build, |label| {
|
||||
core_config()
|
||||
.aws_ecr_registries
|
||||
.iter()
|
||||
.find(|reg| ®.label == label)
|
||||
.map(AwsEcrConfig::from)
|
||||
})
|
||||
.context("failed to create image name")?;
|
||||
let version = if version.is_none() {
|
||||
build.config.version
|
||||
} else {
|
||||
*version
|
||||
};
|
||||
// Remove ending patch if it is 0, this means use latest patch.
|
||||
let version_str = if version.patch == 0 {
|
||||
format!("{}.{}", version.major, version.minor)
|
||||
} else {
|
||||
version.to_string()
|
||||
};
|
||||
// replace image with corresponding build image.
|
||||
deployment.config.image = DeploymentImage::Image {
|
||||
image: format!("{image_name}:{version_str}"),
|
||||
};
|
||||
match build.config.image_registry {
|
||||
ImageRegistry::None(_) => (version, None, None),
|
||||
ImageRegistry::AwsEcr(label) => {
|
||||
let config = core_config()
|
||||
.aws_ecr_registries
|
||||
.iter()
|
||||
.find(|reg| reg.label == label)
|
||||
.with_context(|| {
|
||||
format!(
|
||||
"did not find config for aws ecr registry {label}"
|
||||
)
|
||||
})?;
|
||||
let token = ecr::get_ecr_token(
|
||||
&config.region,
|
||||
&config.access_key_id,
|
||||
&config.secret_access_key,
|
||||
)
|
||||
.await
|
||||
.context("failed to create aws ecr login token")?;
|
||||
(version, Some(token), Some(AwsEcrConfig::from(config)))
|
||||
}
|
||||
ImageRegistry::Standard(params) => {
|
||||
if deployment.config.image_registry_account.is_empty() {
|
||||
deployment.config.image_registry_account =
|
||||
params.account
|
||||
}
|
||||
let token = core_config()
|
||||
.docker_registries
|
||||
.iter()
|
||||
.find(|registry| registry.domain == params.domain)
|
||||
.and_then(|provider| {
|
||||
provider
|
||||
.accounts
|
||||
.iter()
|
||||
.find(|account| {
|
||||
account.username
|
||||
== deployment.config.image_registry_account
|
||||
})
|
||||
.map(|account| account.token.clone())
|
||||
});
|
||||
(version, token, None)
|
||||
}
|
||||
}
|
||||
}
|
||||
version
|
||||
}
|
||||
DeploymentImage::Image { .. } => Version::default(),
|
||||
};
|
||||
DeploymentImage::Image { image } => {
|
||||
let domain = extract_registry_domain(image)?;
|
||||
let token =
|
||||
(!deployment.config.image_registry_account.is_empty())
|
||||
.then(|| {
|
||||
core_config()
|
||||
.docker_registries
|
||||
.iter()
|
||||
.find(|registry| registry.domain == domain)
|
||||
.and_then(|provider| {
|
||||
provider
|
||||
.accounts
|
||||
.iter()
|
||||
.find(|account| {
|
||||
account.username
|
||||
== deployment.config.image_registry_account
|
||||
})
|
||||
.map(|account| account.token.clone())
|
||||
})
|
||||
})
|
||||
.flatten();
|
||||
(Version::default(), token, None)
|
||||
}
|
||||
};
|
||||
|
||||
let variables = get_global_variables().await?;
|
||||
let core_config = core_config();
|
||||
@@ -169,46 +233,6 @@ impl Resolve<Deploy, (User, Update)> for State {
|
||||
update.version = version;
|
||||
update_update(update.clone()).await?;
|
||||
|
||||
let (registry_token, aws_ecr) = match &deployment
|
||||
.config
|
||||
.image_registry
|
||||
{
|
||||
ImageRegistry::None(_) => (None, None),
|
||||
ImageRegistry::DockerHub(params) => (
|
||||
core_config.docker_accounts.get(¶ms.account).cloned(),
|
||||
None,
|
||||
),
|
||||
ImageRegistry::Ghcr(params) => (
|
||||
core_config.github_accounts.get(¶ms.account).cloned(),
|
||||
None,
|
||||
),
|
||||
ImageRegistry::AwsEcr(label) => {
|
||||
let config = core_config
|
||||
.aws_ecr_registries
|
||||
.get(label)
|
||||
.with_context(|| {
|
||||
format!(
|
||||
"did not find config for aws ecr registry {label}"
|
||||
)
|
||||
})?;
|
||||
(
|
||||
Some(
|
||||
ecr::get_ecr_token(
|
||||
&config.region,
|
||||
&config.access_key_id,
|
||||
&config.secret_access_key,
|
||||
)
|
||||
.await
|
||||
.context("failed to create aws ecr login token")?,
|
||||
),
|
||||
Some(AwsEcrConfig::from(config)),
|
||||
)
|
||||
}
|
||||
ImageRegistry::Custom(_) => {
|
||||
return Err(anyhow!("Custom ImageRegistry not yet supported"))
|
||||
}
|
||||
};
|
||||
|
||||
match periphery
|
||||
.request(api::container::Deploy {
|
||||
deployment,
|
||||
|
||||
@@ -32,7 +32,7 @@ impl Resolve<CloneRepo, (User, Update)> for State {
|
||||
CloneRepo { repo }: CloneRepo,
|
||||
(user, mut update): (User, Update),
|
||||
) -> anyhow::Result<Update> {
|
||||
let repo = resource::get_check_permissions::<Repo>(
|
||||
let mut repo = resource::get_check_permissions::<Repo>(
|
||||
&repo,
|
||||
&user,
|
||||
PermissionLevel::Execute,
|
||||
@@ -57,15 +57,23 @@ impl Resolve<CloneRepo, (User, Update)> for State {
|
||||
|
||||
let periphery = periphery_client(&server)?;
|
||||
|
||||
let github_token = core_config()
|
||||
.github_accounts
|
||||
.get(&repo.config.github_account)
|
||||
.cloned();
|
||||
let git_token = core_config()
|
||||
.git_providers
|
||||
.iter()
|
||||
.find(|provider| provider.domain == repo.config.git_provider)
|
||||
.and_then(|provider| {
|
||||
repo.config.git_https = provider.https;
|
||||
provider
|
||||
.accounts
|
||||
.iter()
|
||||
.find(|account| account.username == repo.config.git_account)
|
||||
.map(|account| account.token.clone())
|
||||
});
|
||||
|
||||
let logs = match periphery
|
||||
.request(api::git::CloneRepo {
|
||||
args: (&repo).into(),
|
||||
github_token,
|
||||
git_token,
|
||||
})
|
||||
.await
|
||||
{
|
||||
|
||||
@@ -1,7 +1,4 @@
|
||||
use std::{
|
||||
collections::{HashMap, HashSet},
|
||||
sync::OnceLock,
|
||||
};
|
||||
use std::collections::{HashMap, HashSet};
|
||||
|
||||
use anyhow::Context;
|
||||
use async_timing_util::unix_timestamp_ms;
|
||||
@@ -21,7 +18,7 @@ use mungos::{
|
||||
find::find_collect,
|
||||
mongodb::{bson::doc, options::FindOptions},
|
||||
};
|
||||
use resolver_api::{Resolve, ResolveToString};
|
||||
use resolver_api::Resolve;
|
||||
|
||||
use crate::{
|
||||
config::core_config,
|
||||
@@ -193,16 +190,16 @@ fn ms_to_hour(duration: i64) -> f64 {
|
||||
duration as f64 / MS_TO_HOUR_DIVISOR
|
||||
}
|
||||
|
||||
impl Resolve<GetBuildVersions, User> for State {
|
||||
impl Resolve<ListBuildVersions, User> for State {
|
||||
async fn resolve(
|
||||
&self,
|
||||
GetBuildVersions {
|
||||
ListBuildVersions {
|
||||
build,
|
||||
major,
|
||||
minor,
|
||||
patch,
|
||||
limit,
|
||||
}: GetBuildVersions,
|
||||
}: ListBuildVersions,
|
||||
user: User,
|
||||
) -> anyhow::Result<Vec<BuildVersionResponseItem>> {
|
||||
let build = resource::get_check_permissions::<Build>(
|
||||
@@ -250,42 +247,6 @@ impl Resolve<GetBuildVersions, User> for State {
|
||||
}
|
||||
}
|
||||
|
||||
fn github_organizations() -> &'static String {
|
||||
static GITHUB_ORGANIZATIONS: OnceLock<String> = OnceLock::new();
|
||||
GITHUB_ORGANIZATIONS.get_or_init(|| {
|
||||
serde_json::to_string(&core_config().github_organizations)
|
||||
.expect("failed to serialize github organizations")
|
||||
})
|
||||
}
|
||||
|
||||
impl ResolveToString<ListGithubOrganizations, User> for State {
|
||||
async fn resolve_to_string(
|
||||
&self,
|
||||
ListGithubOrganizations {}: ListGithubOrganizations,
|
||||
_: User,
|
||||
) -> anyhow::Result<String> {
|
||||
Ok(github_organizations().clone())
|
||||
}
|
||||
}
|
||||
|
||||
fn docker_organizations() -> &'static String {
|
||||
static DOCKER_ORGANIZATIONS: OnceLock<String> = OnceLock::new();
|
||||
DOCKER_ORGANIZATIONS.get_or_init(|| {
|
||||
serde_json::to_string(&core_config().docker_organizations)
|
||||
.expect("failed to serialize docker organizations")
|
||||
})
|
||||
}
|
||||
|
||||
impl ResolveToString<ListDockerOrganizations, User> for State {
|
||||
async fn resolve_to_string(
|
||||
&self,
|
||||
ListDockerOrganizations {}: ListDockerOrganizations,
|
||||
_: User,
|
||||
) -> anyhow::Result<String> {
|
||||
Ok(docker_organizations().clone())
|
||||
}
|
||||
}
|
||||
|
||||
impl Resolve<ListCommonBuildExtraArgs, User> for State {
|
||||
async fn resolve(
|
||||
&self,
|
||||
@@ -331,7 +292,9 @@ impl Resolve<GetBuildWebhookEnabled, User> for State {
|
||||
)
|
||||
.await?;
|
||||
|
||||
if build.config.repo.is_empty() {
|
||||
if build.config.git_provider != "github.com"
|
||||
|| build.config.repo.is_empty()
|
||||
{
|
||||
return Ok(GetBuildWebhookEnabledResponse {
|
||||
managed: false,
|
||||
enabled: false,
|
||||
@@ -361,11 +324,11 @@ impl Resolve<GetBuildWebhookEnabled, User> for State {
|
||||
|
||||
let CoreConfig {
|
||||
host,
|
||||
github_webhook_base_url,
|
||||
webhook_base_url,
|
||||
..
|
||||
} = core_config();
|
||||
|
||||
let host = github_webhook_base_url.as_ref().unwrap_or(host);
|
||||
let host = webhook_base_url.as_ref().unwrap_or(host);
|
||||
let url = format!("{host}/listener/github/build/{}", build.id);
|
||||
|
||||
for webhook in webhooks {
|
||||
|
||||
@@ -1,11 +1,9 @@
|
||||
use std::collections::HashSet;
|
||||
|
||||
use anyhow::Context;
|
||||
use mongo_indexed::Document;
|
||||
use monitor_client::{
|
||||
api::read::{self, *},
|
||||
api::read::*,
|
||||
entities::{
|
||||
builder::{Builder, BuilderConfig, BuilderListItem},
|
||||
builder::{Builder, BuilderListItem},
|
||||
permission::PermissionLevel,
|
||||
update::ResourceTargetVariant,
|
||||
user::User,
|
||||
@@ -15,7 +13,6 @@ use mungos::mongodb::bson::doc;
|
||||
use resolver_api::Resolve;
|
||||
|
||||
use crate::{
|
||||
config::core_config,
|
||||
helpers::query::get_resource_ids_for_user,
|
||||
resource,
|
||||
state::{db_client, State},
|
||||
@@ -85,52 +82,3 @@ impl Resolve<GetBuildersSummary, User> for State {
|
||||
Ok(res)
|
||||
}
|
||||
}
|
||||
|
||||
impl Resolve<GetBuilderAvailableAccounts, User> for State {
|
||||
async fn resolve(
|
||||
&self,
|
||||
GetBuilderAvailableAccounts { builder }: GetBuilderAvailableAccounts,
|
||||
user: User,
|
||||
) -> anyhow::Result<GetBuilderAvailableAccountsResponse> {
|
||||
let builder = resource::get_check_permissions::<Builder>(
|
||||
&builder,
|
||||
&user,
|
||||
PermissionLevel::Read,
|
||||
)
|
||||
.await?;
|
||||
let (github, docker) = match builder.config {
|
||||
BuilderConfig::Aws(config) => {
|
||||
(config.github_accounts, config.docker_accounts)
|
||||
}
|
||||
BuilderConfig::Server(config) => {
|
||||
let res = self
|
||||
.resolve(
|
||||
read::GetAvailableAccounts {
|
||||
server: Some(config.server_id),
|
||||
},
|
||||
user,
|
||||
)
|
||||
.await?;
|
||||
(res.github, res.docker)
|
||||
}
|
||||
};
|
||||
|
||||
let mut github_set = HashSet::<String>::new();
|
||||
|
||||
github_set.extend(core_config().github_accounts.keys().cloned());
|
||||
github_set.extend(github);
|
||||
|
||||
let mut github = github_set.into_iter().collect::<Vec<_>>();
|
||||
github.sort();
|
||||
|
||||
let mut docker_set = HashSet::<String>::new();
|
||||
|
||||
docker_set.extend(core_config().docker_accounts.keys().cloned());
|
||||
docker_set.extend(docker);
|
||||
|
||||
let mut docker = docker_set.into_iter().collect::<Vec<_>>();
|
||||
docker.sort();
|
||||
|
||||
Ok(GetBuilderAvailableAccountsResponse { github, docker })
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,16 +1,33 @@
|
||||
use std::{sync::OnceLock, time::Instant};
|
||||
use std::{collections::HashSet, sync::OnceLock, time::Instant};
|
||||
|
||||
use anyhow::{anyhow, Context};
|
||||
use axum::{middleware, routing::post, Extension, Router};
|
||||
use axum_extra::{headers::ContentType, TypedHeader};
|
||||
use monitor_client::{api::read::*, entities::user::User};
|
||||
use resolver_api::{derive::Resolver, ResolveToString, Resolver};
|
||||
use monitor_client::{
|
||||
api::read::*,
|
||||
entities::{
|
||||
build::Build,
|
||||
builder::{Builder, BuilderConfig},
|
||||
config::{DockerRegistry, GitProvider},
|
||||
repo::Repo,
|
||||
server::Server,
|
||||
sync::ResourceSync,
|
||||
update::ResourceTarget,
|
||||
user::User,
|
||||
},
|
||||
};
|
||||
use resolver_api::{
|
||||
derive::Resolver, Resolve, ResolveToString, Resolver,
|
||||
};
|
||||
use serde::{Deserialize, Serialize};
|
||||
use serror::Json;
|
||||
use typeshare::typeshare;
|
||||
use uuid::Uuid;
|
||||
|
||||
use crate::{auth::auth_request, config::core_config, state::State};
|
||||
use crate::{
|
||||
auth::auth_request, config::core_config, helpers::periphery_client,
|
||||
resource, state::State,
|
||||
};
|
||||
|
||||
mod alert;
|
||||
mod alerter;
|
||||
@@ -42,7 +59,10 @@ enum ReadRequest {
|
||||
#[to_string_resolver]
|
||||
GetCoreInfo(GetCoreInfo),
|
||||
#[to_string_resolver]
|
||||
GetAvailableAwsEcrLabels(GetAvailableAwsEcrLabels),
|
||||
ListAwsEcrLabels(ListAwsEcrLabels),
|
||||
ListSecrets(ListSecrets),
|
||||
ListGitProviders(ListGitProviders),
|
||||
ListDockerRegistries(ListDockerRegistries),
|
||||
|
||||
// ==== USER ====
|
||||
GetUsername(GetUsername),
|
||||
@@ -84,8 +104,6 @@ enum ReadRequest {
|
||||
GetDockerNetworks(GetDockerNetworks),
|
||||
GetServerActionState(GetServerActionState),
|
||||
GetHistoricalServerStats(GetHistoricalServerStats),
|
||||
GetAvailableAccounts(GetAvailableAccounts),
|
||||
GetAvailableSecrets(GetAvailableSecrets),
|
||||
ListServers(ListServers),
|
||||
ListFullServers(ListFullServers),
|
||||
|
||||
@@ -106,15 +124,11 @@ enum ReadRequest {
|
||||
GetBuild(GetBuild),
|
||||
GetBuildActionState(GetBuildActionState),
|
||||
GetBuildMonthlyStats(GetBuildMonthlyStats),
|
||||
GetBuildVersions(GetBuildVersions),
|
||||
ListBuildVersions(ListBuildVersions),
|
||||
GetBuildWebhookEnabled(GetBuildWebhookEnabled),
|
||||
ListBuilds(ListBuilds),
|
||||
ListFullBuilds(ListFullBuilds),
|
||||
ListCommonBuildExtraArgs(ListCommonBuildExtraArgs),
|
||||
#[to_string_resolver]
|
||||
ListGithubOrganizations(ListGithubOrganizations),
|
||||
#[to_string_resolver]
|
||||
ListDockerOrganizations(ListDockerOrganizations),
|
||||
|
||||
// ==== REPO ====
|
||||
GetReposSummary(GetReposSummary),
|
||||
@@ -135,7 +149,6 @@ enum ReadRequest {
|
||||
// ==== BUILDER ====
|
||||
GetBuildersSummary(GetBuildersSummary),
|
||||
GetBuilder(GetBuilder),
|
||||
GetBuilderAvailableAccounts(GetBuilderAvailableAccounts),
|
||||
ListBuilders(ListBuilders),
|
||||
ListFullBuilders(ListFullBuilders),
|
||||
|
||||
@@ -234,8 +247,8 @@ fn core_info() -> &'static String {
|
||||
let info = GetCoreInfoResponse {
|
||||
title: config.title.clone(),
|
||||
monitoring_interval: config.monitoring_interval,
|
||||
github_webhook_base_url: config
|
||||
.github_webhook_base_url
|
||||
webhook_base_url: config
|
||||
.webhook_base_url
|
||||
.clone()
|
||||
.unwrap_or_else(|| config.host.clone()),
|
||||
transparent_mode: config.transparent_mode,
|
||||
@@ -269,8 +282,8 @@ fn ecr_labels() -> &'static String {
|
||||
serde_json::to_string(
|
||||
&core_config()
|
||||
.aws_ecr_registries
|
||||
.keys()
|
||||
.cloned()
|
||||
.iter()
|
||||
.map(|reg| reg.label.clone())
|
||||
.collect::<Vec<_>>(),
|
||||
)
|
||||
.context("failed to serialize ecr registries")
|
||||
@@ -278,12 +291,272 @@ fn ecr_labels() -> &'static String {
|
||||
})
|
||||
}
|
||||
|
||||
impl ResolveToString<GetAvailableAwsEcrLabels, User> for State {
|
||||
impl ResolveToString<ListAwsEcrLabels, User> for State {
|
||||
async fn resolve_to_string(
|
||||
&self,
|
||||
GetAvailableAwsEcrLabels {}: GetAvailableAwsEcrLabels,
|
||||
ListAwsEcrLabels {}: ListAwsEcrLabels,
|
||||
_: User,
|
||||
) -> anyhow::Result<String> {
|
||||
Ok(ecr_labels().to_string())
|
||||
}
|
||||
}
|
||||
|
||||
impl Resolve<ListSecrets, User> for State {
|
||||
async fn resolve(
|
||||
&self,
|
||||
ListSecrets { target }: ListSecrets,
|
||||
_: User,
|
||||
) -> anyhow::Result<ListSecretsResponse> {
|
||||
let mut secrets = core_config()
|
||||
.secrets
|
||||
.keys()
|
||||
.cloned()
|
||||
.collect::<HashSet<_>>();
|
||||
|
||||
if let Some(target) = target {
|
||||
let server_id = match target {
|
||||
ResourceTarget::Server(id) => Some(id),
|
||||
ResourceTarget::Builder(id) => {
|
||||
match resource::get::<Builder>(&id).await?.config {
|
||||
BuilderConfig::Server(config) => Some(config.server_id),
|
||||
BuilderConfig::Aws(config) => {
|
||||
secrets.extend(config.secrets);
|
||||
None
|
||||
}
|
||||
}
|
||||
}
|
||||
_ => {
|
||||
return Err(anyhow!("target must be `Server` or `Builder`"))
|
||||
}
|
||||
};
|
||||
if let Some(id) = server_id {
|
||||
let server = resource::get::<Server>(&id).await?;
|
||||
let more = periphery_client(&server)?
|
||||
.request(periphery_client::api::ListSecrets {})
|
||||
.await
|
||||
.with_context(|| {
|
||||
format!(
|
||||
"failed to get secrets from server {}",
|
||||
server.name
|
||||
)
|
||||
})?;
|
||||
secrets.extend(more);
|
||||
}
|
||||
}
|
||||
|
||||
let mut secrets = secrets.into_iter().collect::<Vec<_>>();
|
||||
secrets.sort();
|
||||
|
||||
Ok(secrets)
|
||||
}
|
||||
}
|
||||
|
||||
impl Resolve<ListGitProviders, User> for State {
|
||||
async fn resolve(
|
||||
&self,
|
||||
ListGitProviders { target }: ListGitProviders,
|
||||
user: User,
|
||||
) -> anyhow::Result<ListGitProvidersResponse> {
|
||||
let mut providers = core_config().git_providers.clone();
|
||||
|
||||
if let Some(target) = target {
|
||||
match target {
|
||||
ResourceTarget::Server(id) => {
|
||||
merge_git_providers_for_server(&mut providers, &id).await?;
|
||||
}
|
||||
ResourceTarget::Builder(id) => {
|
||||
match resource::get::<Builder>(&id).await?.config {
|
||||
BuilderConfig::Server(config) => {
|
||||
merge_git_providers_for_server(
|
||||
&mut providers,
|
||||
&config.server_id,
|
||||
)
|
||||
.await?;
|
||||
}
|
||||
BuilderConfig::Aws(config) => {
|
||||
merge_git_providers(
|
||||
&mut providers,
|
||||
config.git_providers,
|
||||
);
|
||||
}
|
||||
}
|
||||
}
|
||||
_ => {
|
||||
return Err(anyhow!("target must be `Server` or `Builder`"))
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
let (builds, repos, syncs) = tokio::try_join!(
|
||||
resource::list_full_for_user::<Build>(
|
||||
Default::default(),
|
||||
&user
|
||||
),
|
||||
resource::list_full_for_user::<Repo>(Default::default(), &user),
|
||||
resource::list_full_for_user::<ResourceSync>(
|
||||
Default::default(),
|
||||
&user
|
||||
),
|
||||
)?;
|
||||
|
||||
for build in builds {
|
||||
if !providers
|
||||
.iter()
|
||||
.any(|provider| provider.domain == build.config.git_provider)
|
||||
{
|
||||
providers.push(GitProvider {
|
||||
domain: build.config.git_provider,
|
||||
https: build.config.git_https,
|
||||
accounts: Default::default(),
|
||||
});
|
||||
}
|
||||
}
|
||||
for repo in repos {
|
||||
if !providers
|
||||
.iter()
|
||||
.any(|provider| provider.domain == repo.config.git_provider)
|
||||
{
|
||||
providers.push(GitProvider {
|
||||
domain: repo.config.git_provider,
|
||||
https: repo.config.git_https,
|
||||
accounts: Default::default(),
|
||||
});
|
||||
}
|
||||
}
|
||||
for sync in syncs {
|
||||
if !providers
|
||||
.iter()
|
||||
.any(|provider| provider.domain == sync.config.git_provider)
|
||||
{
|
||||
providers.push(GitProvider {
|
||||
domain: sync.config.git_provider,
|
||||
https: sync.config.git_https,
|
||||
accounts: Default::default(),
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
providers.sort();
|
||||
|
||||
Ok(providers)
|
||||
}
|
||||
}
|
||||
|
||||
impl Resolve<ListDockerRegistries, User> for State {
|
||||
async fn resolve(
|
||||
&self,
|
||||
ListDockerRegistries { target }: ListDockerRegistries,
|
||||
_: User,
|
||||
) -> anyhow::Result<ListDockerRegistriesResponse> {
|
||||
let mut registries = core_config().docker_registries.clone();
|
||||
|
||||
if let Some(target) = target {
|
||||
match target {
|
||||
ResourceTarget::Server(id) => {
|
||||
merge_docker_registries_for_server(&mut registries, &id)
|
||||
.await?;
|
||||
}
|
||||
ResourceTarget::Builder(id) => {
|
||||
match resource::get::<Builder>(&id).await?.config {
|
||||
BuilderConfig::Server(config) => {
|
||||
merge_docker_registries_for_server(
|
||||
&mut registries,
|
||||
&config.server_id,
|
||||
)
|
||||
.await?;
|
||||
}
|
||||
BuilderConfig::Aws(config) => {
|
||||
merge_docker_registries(
|
||||
&mut registries,
|
||||
config.docker_registries,
|
||||
);
|
||||
}
|
||||
}
|
||||
}
|
||||
_ => {
|
||||
return Err(anyhow!("target must be `Server` or `Builder`"))
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
registries.sort();
|
||||
|
||||
Ok(registries)
|
||||
}
|
||||
}
|
||||
|
||||
async fn merge_git_providers_for_server(
|
||||
providers: &mut Vec<GitProvider>,
|
||||
server_id: &str,
|
||||
) -> anyhow::Result<()> {
|
||||
let server = resource::get::<Server>(server_id).await?;
|
||||
let more = periphery_client(&server)?
|
||||
.request(periphery_client::api::ListGitProviders {})
|
||||
.await
|
||||
.with_context(|| {
|
||||
format!(
|
||||
"failed to get git providers from server {}",
|
||||
server.name
|
||||
)
|
||||
})?;
|
||||
merge_git_providers(providers, more);
|
||||
Ok(())
|
||||
}
|
||||
|
||||
fn merge_git_providers(
|
||||
providers: &mut Vec<GitProvider>,
|
||||
more: Vec<GitProvider>,
|
||||
) {
|
||||
for incoming_provider in more {
|
||||
if let Some(provider) = providers
|
||||
.iter_mut()
|
||||
.find(|provider| provider.domain == incoming_provider.domain)
|
||||
{
|
||||
for account in incoming_provider.accounts {
|
||||
if !provider.accounts.contains(&account) {
|
||||
provider.accounts.push(account);
|
||||
}
|
||||
}
|
||||
} else {
|
||||
providers.push(incoming_provider);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
async fn merge_docker_registries_for_server(
|
||||
registries: &mut Vec<DockerRegistry>,
|
||||
server_id: &str,
|
||||
) -> anyhow::Result<()> {
|
||||
let server = resource::get::<Server>(server_id).await?;
|
||||
let more = periphery_client(&server)?
|
||||
.request(periphery_client::api::ListDockerRegistries {})
|
||||
.await
|
||||
.with_context(|| {
|
||||
format!(
|
||||
"failed to get docker registries from server {}",
|
||||
server.name
|
||||
)
|
||||
})?;
|
||||
merge_docker_registries(registries, more);
|
||||
Ok(())
|
||||
}
|
||||
|
||||
fn merge_docker_registries(
|
||||
registries: &mut Vec<DockerRegistry>,
|
||||
more: Vec<DockerRegistry>,
|
||||
) {
|
||||
for incoming_registry in more {
|
||||
if let Some(registry) = registries
|
||||
.iter_mut()
|
||||
.find(|registry| registry.domain == incoming_registry.domain)
|
||||
{
|
||||
for account in incoming_registry.accounts {
|
||||
if !registry.accounts.contains(&account) {
|
||||
registry.accounts.push(account);
|
||||
}
|
||||
}
|
||||
} else {
|
||||
registries.push(incoming_registry);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -142,7 +142,9 @@ impl Resolve<GetRepoWebhooksEnabled, User> for State {
|
||||
)
|
||||
.await?;
|
||||
|
||||
if repo.config.repo.is_empty() {
|
||||
if repo.config.git_provider != "github.com"
|
||||
|| repo.config.repo.is_empty()
|
||||
{
|
||||
return Ok(GetRepoWebhooksEnabledResponse {
|
||||
managed: false,
|
||||
clone_enabled: false,
|
||||
@@ -174,11 +176,11 @@ impl Resolve<GetRepoWebhooksEnabled, User> for State {
|
||||
|
||||
let CoreConfig {
|
||||
host,
|
||||
github_webhook_base_url,
|
||||
webhook_base_url,
|
||||
..
|
||||
} = core_config();
|
||||
|
||||
let host = github_webhook_base_url.as_ref().unwrap_or(host);
|
||||
let host = webhook_base_url.as_ref().unwrap_or(host);
|
||||
let clone_url =
|
||||
format!("{host}/listener/github/repo/{}/clone", repo.id);
|
||||
let pull_url =
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
use std::{
|
||||
collections::{HashMap, HashSet},
|
||||
collections::HashMap,
|
||||
sync::{Arc, OnceLock},
|
||||
};
|
||||
|
||||
@@ -23,12 +23,11 @@ use mungos::{
|
||||
find::find_collect,
|
||||
mongodb::{bson::doc, options::FindOptions},
|
||||
};
|
||||
use periphery_client::api::{self, GetAccountsResponse};
|
||||
use periphery_client::api as periphery;
|
||||
use resolver_api::{Resolve, ResolveToString};
|
||||
use tokio::sync::Mutex;
|
||||
|
||||
use crate::{
|
||||
config::core_config,
|
||||
helpers::periphery_client,
|
||||
resource,
|
||||
state::{action_states, db_client, server_status_cache, State},
|
||||
@@ -192,7 +191,7 @@ impl ResolveToString<GetSystemInformation, User> for State {
|
||||
}
|
||||
_ => {
|
||||
let stats = periphery_client(&server)?
|
||||
.request(api::stats::GetSystemInformation {})
|
||||
.request(periphery::stats::GetSystemInformation {})
|
||||
.await?;
|
||||
let res = serde_json::to_string(&stats)?;
|
||||
lock.insert(
|
||||
@@ -259,7 +258,7 @@ impl ResolveToString<GetSystemProcesses, User> for State {
|
||||
}
|
||||
_ => {
|
||||
let stats = periphery_client(&server)?
|
||||
.request(api::stats::GetSystemProcesses {})
|
||||
.request(periphery::stats::GetSystemProcesses {})
|
||||
.await?;
|
||||
let res = serde_json::to_string(&stats)?;
|
||||
lock.insert(
|
||||
@@ -342,7 +341,7 @@ impl Resolve<GetDockerImages, User> for State {
|
||||
)
|
||||
.await?;
|
||||
periphery_client(&server)?
|
||||
.request(api::build::GetImageList {})
|
||||
.request(periphery::build::GetImageList {})
|
||||
.await
|
||||
}
|
||||
}
|
||||
@@ -360,7 +359,7 @@ impl Resolve<GetDockerNetworks, User> for State {
|
||||
)
|
||||
.await?;
|
||||
periphery_client(&server)?
|
||||
.request(api::network::GetNetworkList {})
|
||||
.request(periphery::network::GetNetworkList {})
|
||||
.await
|
||||
}
|
||||
}
|
||||
@@ -378,74 +377,7 @@ impl Resolve<GetDockerContainers, User> for State {
|
||||
)
|
||||
.await?;
|
||||
periphery_client(&server)?
|
||||
.request(api::container::GetContainerList {})
|
||||
.request(periphery::container::GetContainerList {})
|
||||
.await
|
||||
}
|
||||
}
|
||||
|
||||
impl Resolve<GetAvailableAccounts, User> for State {
|
||||
async fn resolve(
|
||||
&self,
|
||||
GetAvailableAccounts { server }: GetAvailableAccounts,
|
||||
user: User,
|
||||
) -> anyhow::Result<GetAvailableAccountsResponse> {
|
||||
let (github, docker) = match server {
|
||||
Some(server) => {
|
||||
let server = resource::get_check_permissions::<Server>(
|
||||
&server,
|
||||
&user,
|
||||
PermissionLevel::Read,
|
||||
)
|
||||
.await?;
|
||||
|
||||
let GetAccountsResponse { github, docker } =
|
||||
periphery_client(&server)?
|
||||
.request(api::GetAccounts {})
|
||||
.await
|
||||
.context("failed to get accounts from periphery")?;
|
||||
(github, docker)
|
||||
}
|
||||
None => Default::default(),
|
||||
};
|
||||
|
||||
let mut github_set = HashSet::<String>::new();
|
||||
|
||||
github_set.extend(core_config().github_accounts.keys().cloned());
|
||||
github_set.extend(github);
|
||||
|
||||
let mut github = github_set.into_iter().collect::<Vec<_>>();
|
||||
github.sort();
|
||||
|
||||
let mut docker_set = HashSet::<String>::new();
|
||||
|
||||
docker_set.extend(core_config().docker_accounts.keys().cloned());
|
||||
docker_set.extend(docker);
|
||||
|
||||
let mut docker = docker_set.into_iter().collect::<Vec<_>>();
|
||||
docker.sort();
|
||||
|
||||
let res = GetAvailableAccountsResponse { github, docker };
|
||||
Ok(res)
|
||||
}
|
||||
}
|
||||
|
||||
impl Resolve<GetAvailableSecrets, User> for State {
|
||||
async fn resolve(
|
||||
&self,
|
||||
GetAvailableSecrets { server }: GetAvailableSecrets,
|
||||
user: User,
|
||||
) -> anyhow::Result<GetAvailableSecretsResponse> {
|
||||
let server = resource::get_check_permissions::<Server>(
|
||||
&server,
|
||||
&user,
|
||||
PermissionLevel::Read,
|
||||
)
|
||||
.await?;
|
||||
let mut secrets = periphery_client(&server)?
|
||||
.request(api::GetSecrets {})
|
||||
.await
|
||||
.context("failed to get accounts from periphery")?;
|
||||
secrets.sort();
|
||||
Ok(secrets)
|
||||
}
|
||||
}
|
||||
|
||||
@@ -163,7 +163,9 @@ impl Resolve<GetSyncWebhooksEnabled, User> for State {
|
||||
)
|
||||
.await?;
|
||||
|
||||
if sync.config.repo.is_empty() {
|
||||
if sync.config.git_provider != "github.com"
|
||||
|| sync.config.repo.is_empty()
|
||||
{
|
||||
return Ok(GetSyncWebhooksEnabledResponse {
|
||||
managed: false,
|
||||
refresh_enabled: false,
|
||||
@@ -195,11 +197,11 @@ impl Resolve<GetSyncWebhooksEnabled, User> for State {
|
||||
|
||||
let CoreConfig {
|
||||
host,
|
||||
github_webhook_base_url,
|
||||
webhook_base_url,
|
||||
..
|
||||
} = core_config();
|
||||
|
||||
let host = github_webhook_base_url.as_ref().unwrap_or(host);
|
||||
let host = webhook_base_url.as_ref().unwrap_or(host);
|
||||
let refresh_url =
|
||||
format!("{host}/listener/github/sync/{}/refresh", sync.id);
|
||||
let sync_url =
|
||||
|
||||
@@ -11,7 +11,6 @@ use mungos::{find::find_collect, mongodb::options::FindOptions};
|
||||
use resolver_api::Resolve;
|
||||
|
||||
use crate::{
|
||||
config::core_config,
|
||||
helpers::query::get_variable,
|
||||
state::{db_client, State},
|
||||
};
|
||||
@@ -32,16 +31,12 @@ impl Resolve<ListVariables, User> for State {
|
||||
ListVariables {}: ListVariables,
|
||||
_: User,
|
||||
) -> anyhow::Result<ListVariablesResponse> {
|
||||
let variables = find_collect(
|
||||
find_collect(
|
||||
&db_client().await.variables,
|
||||
None,
|
||||
FindOptions::builder().sort(doc! { "name": 1 }).build(),
|
||||
)
|
||||
.await
|
||||
.context("failed to query db for variables")?;
|
||||
Ok(ListVariablesResponse {
|
||||
variables,
|
||||
secrets: core_config().secrets.keys().cloned().collect(),
|
||||
})
|
||||
.context("failed to query db for variables")
|
||||
}
|
||||
}
|
||||
|
||||
@@ -120,12 +120,12 @@ impl Resolve<CreateBuildWebhook, User> for State {
|
||||
|
||||
let CoreConfig {
|
||||
host,
|
||||
github_webhook_base_url,
|
||||
github_webhook_secret,
|
||||
webhook_base_url,
|
||||
webhook_secret,
|
||||
..
|
||||
} = core_config();
|
||||
|
||||
let host = github_webhook_base_url.as_ref().unwrap_or(host);
|
||||
let host = webhook_base_url.as_ref().unwrap_or(host);
|
||||
let url = format!("{host}/listener/github/build/{}", build.id);
|
||||
|
||||
for webhook in webhooks {
|
||||
@@ -139,7 +139,7 @@ impl Resolve<CreateBuildWebhook, User> for State {
|
||||
active: Some(true),
|
||||
config: Some(ReposCreateWebhookRequestConfig {
|
||||
url,
|
||||
secret: github_webhook_secret.to_string(),
|
||||
secret: webhook_secret.to_string(),
|
||||
content_type: String::from("json"),
|
||||
insecure_ssl: None,
|
||||
digest: Default::default(),
|
||||
@@ -193,6 +193,12 @@ impl Resolve<DeleteBuildWebhook, User> for State {
|
||||
)
|
||||
.await?;
|
||||
|
||||
if build.config.git_provider != "github.com" {
|
||||
return Err(anyhow!(
|
||||
"Can only manage github.com repo webhooks"
|
||||
));
|
||||
}
|
||||
|
||||
if build.config.repo.is_empty() {
|
||||
return Err(anyhow!(
|
||||
"No repo configured, can't delete webhook"
|
||||
@@ -221,11 +227,11 @@ impl Resolve<DeleteBuildWebhook, User> for State {
|
||||
|
||||
let CoreConfig {
|
||||
host,
|
||||
github_webhook_base_url,
|
||||
webhook_base_url,
|
||||
..
|
||||
} = core_config();
|
||||
|
||||
let host = github_webhook_base_url.as_ref().unwrap_or(host);
|
||||
let host = webhook_base_url.as_ref().unwrap_or(host);
|
||||
let url = format!("{host}/listener/github/build/{}", build.id);
|
||||
|
||||
for webhook in webhooks {
|
||||
|
||||
@@ -120,12 +120,12 @@ impl Resolve<CreateRepoWebhook, User> for State {
|
||||
|
||||
let CoreConfig {
|
||||
host,
|
||||
github_webhook_base_url,
|
||||
github_webhook_secret,
|
||||
webhook_base_url,
|
||||
webhook_secret,
|
||||
..
|
||||
} = core_config();
|
||||
|
||||
let host = github_webhook_base_url.as_ref().unwrap_or(host);
|
||||
let host = webhook_base_url.as_ref().unwrap_or(host);
|
||||
let url = match action {
|
||||
RepoWebhookAction::Clone => {
|
||||
format!("{host}/listener/github/repo/{}/clone", repo.id)
|
||||
@@ -146,7 +146,7 @@ impl Resolve<CreateRepoWebhook, User> for State {
|
||||
active: Some(true),
|
||||
config: Some(ReposCreateWebhookRequestConfig {
|
||||
url,
|
||||
secret: github_webhook_secret.to_string(),
|
||||
secret: webhook_secret.to_string(),
|
||||
content_type: String::from("json"),
|
||||
insecure_ssl: None,
|
||||
digest: Default::default(),
|
||||
@@ -200,6 +200,12 @@ impl Resolve<DeleteRepoWebhook, User> for State {
|
||||
)
|
||||
.await?;
|
||||
|
||||
if repo.config.git_provider != "github.com" {
|
||||
return Err(anyhow!(
|
||||
"Can only manage github.com repo webhooks"
|
||||
));
|
||||
}
|
||||
|
||||
if repo.config.repo.is_empty() {
|
||||
return Err(anyhow!(
|
||||
"No repo configured, can't create webhook"
|
||||
@@ -229,11 +235,11 @@ impl Resolve<DeleteRepoWebhook, User> for State {
|
||||
|
||||
let CoreConfig {
|
||||
host,
|
||||
github_webhook_base_url,
|
||||
webhook_base_url,
|
||||
..
|
||||
} = core_config();
|
||||
|
||||
let host = github_webhook_base_url.as_ref().unwrap_or(host);
|
||||
let host = webhook_base_url.as_ref().unwrap_or(host);
|
||||
let url = match action {
|
||||
RepoWebhookAction::Clone => {
|
||||
format!("{host}/listener/github/repo/{}/clone", repo.id)
|
||||
|
||||
@@ -376,12 +376,12 @@ impl Resolve<CreateSyncWebhook, User> for State {
|
||||
|
||||
let CoreConfig {
|
||||
host,
|
||||
github_webhook_base_url,
|
||||
github_webhook_secret,
|
||||
webhook_base_url,
|
||||
webhook_secret,
|
||||
..
|
||||
} = core_config();
|
||||
|
||||
let host = github_webhook_base_url.as_ref().unwrap_or(host);
|
||||
let host = webhook_base_url.as_ref().unwrap_or(host);
|
||||
let url = match action {
|
||||
SyncWebhookAction::Refresh => {
|
||||
format!("{host}/listener/github/sync/{}/refresh", sync.id)
|
||||
@@ -402,7 +402,7 @@ impl Resolve<CreateSyncWebhook, User> for State {
|
||||
active: Some(true),
|
||||
config: Some(ReposCreateWebhookRequestConfig {
|
||||
url,
|
||||
secret: github_webhook_secret.to_string(),
|
||||
secret: webhook_secret.to_string(),
|
||||
content_type: String::from("json"),
|
||||
insecure_ssl: None,
|
||||
digest: Default::default(),
|
||||
@@ -456,6 +456,12 @@ impl Resolve<DeleteSyncWebhook, User> for State {
|
||||
)
|
||||
.await?;
|
||||
|
||||
if sync.config.git_provider != "github.com" {
|
||||
return Err(anyhow!(
|
||||
"Can only manage github.com repo webhooks"
|
||||
));
|
||||
}
|
||||
|
||||
if sync.config.repo.is_empty() {
|
||||
return Err(anyhow!(
|
||||
"No repo configured, can't create webhook"
|
||||
@@ -485,11 +491,11 @@ impl Resolve<DeleteSyncWebhook, User> for State {
|
||||
|
||||
let CoreConfig {
|
||||
host,
|
||||
github_webhook_base_url,
|
||||
webhook_base_url,
|
||||
..
|
||||
} = core_config();
|
||||
|
||||
let host = github_webhook_base_url.as_ref().unwrap_or(host);
|
||||
let host = webhook_base_url.as_ref().unwrap_or(host);
|
||||
let url = match action {
|
||||
SyncWebhookAction::Refresh => {
|
||||
format!("{host}/listener/github/sync/{}/refresh", sync.id)
|
||||
|
||||
@@ -233,32 +233,30 @@ pub enum HetznerActionStatus {
|
||||
#[allow(clippy::enum_variant_names)]
|
||||
pub enum HetznerServerType {
|
||||
// Shared
|
||||
#[serde(rename = "cx11")]
|
||||
SharedIntel1Core2Ram20Disk,
|
||||
#[serde(rename = "cpx11")]
|
||||
SharedAmd2Core2Ram40Disk,
|
||||
#[serde(rename = "cax11")]
|
||||
SharedArm2Core4Ram40Disk,
|
||||
#[serde(rename = "cx21")]
|
||||
#[serde(rename = "cx22")]
|
||||
SharedIntel2Core4Ram40Disk,
|
||||
#[serde(rename = "cpx21")]
|
||||
SharedAmd3Core4Ram80Disk,
|
||||
#[serde(rename = "cax21")]
|
||||
SharedArm4Core8Ram80Disk,
|
||||
#[serde(rename = "cx31")]
|
||||
SharedIntel2Core8Ram80Disk,
|
||||
#[serde(rename = "cx32")]
|
||||
SharedIntel4Core8Ram80Disk,
|
||||
#[serde(rename = "cpx31")]
|
||||
SharedAmd4Core8Ram160Disk,
|
||||
#[serde(rename = "cax31")]
|
||||
SharedArm8Core16Ram160Disk,
|
||||
#[serde(rename = "cx41")]
|
||||
SharedIntel4Core16Ram160Disk,
|
||||
#[serde(rename = "cx42")]
|
||||
SharedIntel8Core16Ram160Disk,
|
||||
#[serde(rename = "cpx41")]
|
||||
SharedAmd8Core16Ram240Disk,
|
||||
#[serde(rename = "cax41")]
|
||||
SharedArm16Core32Ram320Disk,
|
||||
#[serde(rename = "cx51")]
|
||||
SharedIntel8Core32Ram240Disk,
|
||||
#[serde(rename = "cx52")]
|
||||
SharedIntel16Core32Ram320Disk,
|
||||
#[serde(rename = "cpx51")]
|
||||
SharedAmd16Core32Ram360Disk,
|
||||
// Dedicated
|
||||
|
||||
@@ -218,9 +218,6 @@ fn hetzner_server_type(
|
||||
server_type: HetznerServerType,
|
||||
) -> common::HetznerServerType {
|
||||
match server_type {
|
||||
HetznerServerType::SharedIntel1Core2Ram20Disk => {
|
||||
common::HetznerServerType::SharedIntel1Core2Ram20Disk
|
||||
}
|
||||
HetznerServerType::SharedAmd2Core2Ram40Disk => {
|
||||
common::HetznerServerType::SharedAmd2Core2Ram40Disk
|
||||
}
|
||||
@@ -236,8 +233,8 @@ fn hetzner_server_type(
|
||||
HetznerServerType::SharedArm4Core8Ram80Disk => {
|
||||
common::HetznerServerType::SharedArm4Core8Ram80Disk
|
||||
}
|
||||
HetznerServerType::SharedIntel2Core8Ram80Disk => {
|
||||
common::HetznerServerType::SharedIntel2Core8Ram80Disk
|
||||
HetznerServerType::SharedIntel4Core8Ram80Disk => {
|
||||
common::HetznerServerType::SharedIntel4Core8Ram80Disk
|
||||
}
|
||||
HetznerServerType::SharedAmd4Core8Ram160Disk => {
|
||||
common::HetznerServerType::SharedAmd4Core8Ram160Disk
|
||||
@@ -245,8 +242,8 @@ fn hetzner_server_type(
|
||||
HetznerServerType::SharedArm8Core16Ram160Disk => {
|
||||
common::HetznerServerType::SharedArm8Core16Ram160Disk
|
||||
}
|
||||
HetznerServerType::SharedIntel4Core16Ram160Disk => {
|
||||
common::HetznerServerType::SharedIntel4Core16Ram160Disk
|
||||
HetznerServerType::SharedIntel8Core16Ram160Disk => {
|
||||
common::HetznerServerType::SharedIntel8Core16Ram160Disk
|
||||
}
|
||||
HetznerServerType::SharedAmd8Core16Ram240Disk => {
|
||||
common::HetznerServerType::SharedAmd8Core16Ram240Disk
|
||||
@@ -254,8 +251,8 @@ fn hetzner_server_type(
|
||||
HetznerServerType::SharedArm16Core32Ram320Disk => {
|
||||
common::HetznerServerType::SharedArm16Core32Ram320Disk
|
||||
}
|
||||
HetznerServerType::SharedIntel8Core32Ram240Disk => {
|
||||
common::HetznerServerType::SharedIntel8Core32Ram240Disk
|
||||
HetznerServerType::SharedIntel16Core32Ram320Disk => {
|
||||
common::HetznerServerType::SharedIntel16Core32Ram320Disk
|
||||
}
|
||||
HetznerServerType::SharedAmd16Core32Ram360Disk => {
|
||||
common::HetznerServerType::SharedAmd16Core32Ram360Disk
|
||||
|
||||
@@ -37,9 +37,13 @@ pub fn frontend_path() -> &'static String {
|
||||
pub fn core_config() -> &'static CoreConfig {
|
||||
static CORE_CONFIG: OnceLock<CoreConfig> = OnceLock::new();
|
||||
CORE_CONFIG.get_or_init(|| {
|
||||
let env: Env = envy::from_env()
|
||||
.context("failed to parse core Env")
|
||||
.unwrap();
|
||||
let env: Env = match envy::from_env()
|
||||
.context("failed to parse core Env") {
|
||||
Ok(env) => env,
|
||||
Err(e) => {
|
||||
panic!("{e:#?}");
|
||||
}
|
||||
};
|
||||
let config_path = &env.monitor_config_path;
|
||||
let config =
|
||||
parse_config_file::<CoreConfig>(config_path.as_str())
|
||||
@@ -54,7 +58,7 @@ pub fn core_config() -> &'static CoreConfig {
|
||||
ids
|
||||
.into_iter()
|
||||
.zip(namespaces)
|
||||
.map(|(id, namespace)| GithubWebhookAppInstallationConfig {
|
||||
.map(|(id, namespace)| GithubWebhookAppInstallationConfig {
|
||||
id,
|
||||
namespace
|
||||
})
|
||||
@@ -91,17 +95,12 @@ pub fn core_config() -> &'static CoreConfig {
|
||||
keep_alerts_for_days: env
|
||||
.monitor_keep_alerts_for_days
|
||||
.unwrap_or(config.keep_alerts_for_days),
|
||||
github_webhook_secret: env
|
||||
.monitor_github_webhook_secret
|
||||
.unwrap_or(config.github_webhook_secret),
|
||||
github_webhook_base_url: env
|
||||
.monitor_github_webhook_base_url
|
||||
.or(config.github_webhook_base_url),
|
||||
github_organizations: env.monitor_github_organizations
|
||||
.unwrap_or(config.github_organizations),
|
||||
docker_organizations: env
|
||||
.monitor_docker_organizations
|
||||
.unwrap_or(config.docker_organizations),
|
||||
webhook_secret: env
|
||||
.monitor_webhook_secret
|
||||
.unwrap_or(config.webhook_secret),
|
||||
webhook_base_url: env
|
||||
.monitor_webhook_base_url
|
||||
.or(config.webhook_base_url),
|
||||
transparent_mode: env
|
||||
.monitor_transparent_mode
|
||||
.unwrap_or(config.transparent_mode),
|
||||
@@ -186,8 +185,8 @@ pub fn core_config() -> &'static CoreConfig {
|
||||
|
||||
// These can't be overridden on env
|
||||
secrets: config.secrets,
|
||||
github_accounts: config.github_accounts,
|
||||
docker_accounts: config.docker_accounts,
|
||||
git_providers: config.git_providers,
|
||||
docker_registries: config.docker_registries,
|
||||
aws_ecr_registries: config.aws_ecr_registries,
|
||||
}
|
||||
})
|
||||
|
||||
@@ -1,18 +1,24 @@
|
||||
use std::time::{Duration, Instant};
|
||||
|
||||
use anyhow::{anyhow, Context, Ok};
|
||||
use formatting::{bold, colored, muted, Color};
|
||||
use anyhow::{anyhow, Context};
|
||||
use formatting::{bold, colored, format_serror, muted, Color};
|
||||
use futures::future::join_all;
|
||||
use monitor_client::{
|
||||
api::execute::Execution,
|
||||
entities::{
|
||||
procedure::Procedure, update::Update, user::procedure_user,
|
||||
procedure::Procedure,
|
||||
update::{Log, Update},
|
||||
user::procedure_user,
|
||||
},
|
||||
};
|
||||
use mungos::by_id::find_one_by_id;
|
||||
use resolver_api::Resolve;
|
||||
use tokio::sync::Mutex;
|
||||
|
||||
use crate::{api::execute::ExecuteRequest, state::State};
|
||||
use crate::{
|
||||
api::execute::ExecuteRequest,
|
||||
state::{db_client, State},
|
||||
};
|
||||
|
||||
use super::update::{init_execution_update, update_update};
|
||||
|
||||
@@ -49,8 +55,7 @@ pub async fn execute_procedure(
|
||||
.await
|
||||
.with_context(|| {
|
||||
format!(
|
||||
"{}: failed stage '{}' execution after {:?}",
|
||||
colored("ERROR", Color::Red),
|
||||
"failed stage '{}' execution after {:?}",
|
||||
bold(&stage.name),
|
||||
timer.elapsed(),
|
||||
)
|
||||
@@ -130,10 +135,15 @@ async fn execute_execution(
|
||||
let ExecuteRequest::RunProcedure(req) = req else {
|
||||
unreachable!()
|
||||
};
|
||||
State
|
||||
.resolve(req, (user, update))
|
||||
.await
|
||||
.context("failed at RunProcedure")?
|
||||
let update_id = update.id.clone();
|
||||
handle_resolve_result(
|
||||
State
|
||||
.resolve(req, (user, update))
|
||||
.await
|
||||
.context("failed at RunProcedure"),
|
||||
&update_id,
|
||||
)
|
||||
.await?
|
||||
}
|
||||
Execution::RunBuild(req) => {
|
||||
let req = ExecuteRequest::RunBuild(req);
|
||||
@@ -141,10 +151,15 @@ async fn execute_execution(
|
||||
let ExecuteRequest::RunBuild(req) = req else {
|
||||
unreachable!()
|
||||
};
|
||||
State
|
||||
.resolve(req, (user, update))
|
||||
.await
|
||||
.context("failed at RunBuild")?
|
||||
let update_id = update.id.clone();
|
||||
handle_resolve_result(
|
||||
State
|
||||
.resolve(req, (user, update))
|
||||
.await
|
||||
.context("failed at RunBuild"),
|
||||
&update_id,
|
||||
)
|
||||
.await?
|
||||
}
|
||||
Execution::Deploy(req) => {
|
||||
let req = ExecuteRequest::Deploy(req);
|
||||
@@ -152,10 +167,15 @@ async fn execute_execution(
|
||||
let ExecuteRequest::Deploy(req) = req else {
|
||||
unreachable!()
|
||||
};
|
||||
State
|
||||
.resolve(req, (user, update))
|
||||
.await
|
||||
.context("failed at Deploy")?
|
||||
let update_id = update.id.clone();
|
||||
handle_resolve_result(
|
||||
State
|
||||
.resolve(req, (user, update))
|
||||
.await
|
||||
.context("failed at Deploy"),
|
||||
&update_id,
|
||||
)
|
||||
.await?
|
||||
}
|
||||
Execution::StartContainer(req) => {
|
||||
let req = ExecuteRequest::StartContainer(req);
|
||||
@@ -163,10 +183,15 @@ async fn execute_execution(
|
||||
let ExecuteRequest::StartContainer(req) = req else {
|
||||
unreachable!()
|
||||
};
|
||||
State
|
||||
.resolve(req, (user, update))
|
||||
.await
|
||||
.context("failed at StartContainer")?
|
||||
let update_id = update.id.clone();
|
||||
handle_resolve_result(
|
||||
State
|
||||
.resolve(req, (user, update))
|
||||
.await
|
||||
.context("failed at StartContainer"),
|
||||
&update_id,
|
||||
)
|
||||
.await?
|
||||
}
|
||||
Execution::StopContainer(req) => {
|
||||
let req = ExecuteRequest::StopContainer(req);
|
||||
@@ -174,10 +199,15 @@ async fn execute_execution(
|
||||
let ExecuteRequest::StopContainer(req) = req else {
|
||||
unreachable!()
|
||||
};
|
||||
State
|
||||
.resolve(req, (user, update))
|
||||
.await
|
||||
.context("failed at StopContainer")?
|
||||
let update_id = update.id.clone();
|
||||
handle_resolve_result(
|
||||
State
|
||||
.resolve(req, (user, update))
|
||||
.await
|
||||
.context("failed at StopContainer"),
|
||||
&update_id,
|
||||
)
|
||||
.await?
|
||||
}
|
||||
Execution::StopAllContainers(req) => {
|
||||
let req = ExecuteRequest::StopAllContainers(req);
|
||||
@@ -185,10 +215,15 @@ async fn execute_execution(
|
||||
let ExecuteRequest::StopAllContainers(req) = req else {
|
||||
unreachable!()
|
||||
};
|
||||
State
|
||||
.resolve(req, (user, update))
|
||||
.await
|
||||
.context("failed at StopAllContainers")?
|
||||
let update_id = update.id.clone();
|
||||
handle_resolve_result(
|
||||
State
|
||||
.resolve(req, (user, update))
|
||||
.await
|
||||
.context("failed at StopAllContainers"),
|
||||
&update_id,
|
||||
)
|
||||
.await?
|
||||
}
|
||||
Execution::RemoveContainer(req) => {
|
||||
let req = ExecuteRequest::RemoveContainer(req);
|
||||
@@ -196,10 +231,15 @@ async fn execute_execution(
|
||||
let ExecuteRequest::RemoveContainer(req) = req else {
|
||||
unreachable!()
|
||||
};
|
||||
State
|
||||
.resolve(req, (user, update))
|
||||
.await
|
||||
.context("failed at RemoveContainer")?
|
||||
let update_id = update.id.clone();
|
||||
handle_resolve_result(
|
||||
State
|
||||
.resolve(req, (user, update))
|
||||
.await
|
||||
.context("failed at RemoveContainer"),
|
||||
&update_id,
|
||||
)
|
||||
.await?
|
||||
}
|
||||
Execution::CloneRepo(req) => {
|
||||
let req = ExecuteRequest::CloneRepo(req);
|
||||
@@ -207,10 +247,15 @@ async fn execute_execution(
|
||||
let ExecuteRequest::CloneRepo(req) = req else {
|
||||
unreachable!()
|
||||
};
|
||||
State
|
||||
.resolve(req, (user, update))
|
||||
.await
|
||||
.context("failed at CloneRepo")?
|
||||
let update_id = update.id.clone();
|
||||
handle_resolve_result(
|
||||
State
|
||||
.resolve(req, (user, update))
|
||||
.await
|
||||
.context("failed at CloneRepo"),
|
||||
&update_id,
|
||||
)
|
||||
.await?
|
||||
}
|
||||
Execution::PullRepo(req) => {
|
||||
let req = ExecuteRequest::PullRepo(req);
|
||||
@@ -218,10 +263,15 @@ async fn execute_execution(
|
||||
let ExecuteRequest::PullRepo(req) = req else {
|
||||
unreachable!()
|
||||
};
|
||||
State
|
||||
.resolve(req, (user, update))
|
||||
.await
|
||||
.context("failed at PullRepo")?
|
||||
let update_id = update.id.clone();
|
||||
handle_resolve_result(
|
||||
State
|
||||
.resolve(req, (user, update))
|
||||
.await
|
||||
.context("failed at PullRepo"),
|
||||
&update_id,
|
||||
)
|
||||
.await?
|
||||
}
|
||||
Execution::PruneNetworks(req) => {
|
||||
let req = ExecuteRequest::PruneNetworks(req);
|
||||
@@ -229,10 +279,15 @@ async fn execute_execution(
|
||||
let ExecuteRequest::PruneNetworks(req) = req else {
|
||||
unreachable!()
|
||||
};
|
||||
State
|
||||
.resolve(req, (user, update))
|
||||
.await
|
||||
.context("failed at PruneNetworks")?
|
||||
let update_id = update.id.clone();
|
||||
handle_resolve_result(
|
||||
State
|
||||
.resolve(req, (user, update))
|
||||
.await
|
||||
.context("failed at PruneNetworks"),
|
||||
&update_id,
|
||||
)
|
||||
.await?
|
||||
}
|
||||
Execution::PruneImages(req) => {
|
||||
let req = ExecuteRequest::PruneImages(req);
|
||||
@@ -240,10 +295,15 @@ async fn execute_execution(
|
||||
let ExecuteRequest::PruneImages(req) = req else {
|
||||
unreachable!()
|
||||
};
|
||||
State
|
||||
.resolve(req, (user, update))
|
||||
.await
|
||||
.context("failed at PruneImages")?
|
||||
let update_id = update.id.clone();
|
||||
handle_resolve_result(
|
||||
State
|
||||
.resolve(req, (user, update))
|
||||
.await
|
||||
.context("failed at PruneImages"),
|
||||
&update_id,
|
||||
)
|
||||
.await?
|
||||
}
|
||||
Execution::PruneContainers(req) => {
|
||||
let req = ExecuteRequest::PruneContainers(req);
|
||||
@@ -251,10 +311,15 @@ async fn execute_execution(
|
||||
let ExecuteRequest::PruneContainers(req) = req else {
|
||||
unreachable!()
|
||||
};
|
||||
State
|
||||
.resolve(req, (user, update))
|
||||
.await
|
||||
.context("failed at PruneContainers")?
|
||||
let update_id = update.id.clone();
|
||||
handle_resolve_result(
|
||||
State
|
||||
.resolve(req, (user, update))
|
||||
.await
|
||||
.context("failed at PruneContainers"),
|
||||
&update_id,
|
||||
)
|
||||
.await?
|
||||
}
|
||||
Execution::RunSync(req) => {
|
||||
let req = ExecuteRequest::RunSync(req);
|
||||
@@ -262,10 +327,15 @@ async fn execute_execution(
|
||||
let ExecuteRequest::RunSync(req) = req else {
|
||||
unreachable!()
|
||||
};
|
||||
State
|
||||
.resolve(req, (user, update))
|
||||
.await
|
||||
.context("failed at RunSync")?
|
||||
let update_id = update.id.clone();
|
||||
handle_resolve_result(
|
||||
State
|
||||
.resolve(req, (user, update))
|
||||
.await
|
||||
.context("failed at RunSync"),
|
||||
&update_id,
|
||||
)
|
||||
.await?
|
||||
}
|
||||
Execution::Sleep(req) => {
|
||||
tokio::time::sleep(Duration::from_millis(
|
||||
@@ -289,6 +359,30 @@ async fn execute_execution(
|
||||
}
|
||||
}
|
||||
|
||||
/// If the call to .resolve returns Err, the update may not be closed.
|
||||
/// This will ensure it is closed with error log attached.
|
||||
async fn handle_resolve_result(
|
||||
res: anyhow::Result<Update>,
|
||||
update_id: &str,
|
||||
) -> anyhow::Result<Update> {
|
||||
match res {
|
||||
Ok(res) => Ok(res),
|
||||
Err(e) => {
|
||||
let log =
|
||||
Log::error("execution error", format_serror(&e.into()));
|
||||
let mut update =
|
||||
find_one_by_id(&db_client().await.updates, update_id)
|
||||
.await
|
||||
.context("failed to query to db")?
|
||||
.context("no update exists with given id")?;
|
||||
update.logs.push(log);
|
||||
update.finalize();
|
||||
update_update(update.clone()).await?;
|
||||
Ok(update)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/// ASSUMES FIRST LOG IS ALREADY CREATED
|
||||
#[instrument(level = "debug")]
|
||||
async fn add_line_to_update(update: &Mutex<Update>, line: &str) {
|
||||
|
||||
@@ -4,7 +4,7 @@ use anyhow::Context;
|
||||
use formatting::{bold, colored, muted, Color};
|
||||
use futures::future::join_all;
|
||||
use monitor_client::{
|
||||
api::{execute::Deploy, read::GetBuildVersions},
|
||||
api::{execute::Deploy, read::ListBuildVersions},
|
||||
entities::{
|
||||
deployment::{
|
||||
Deployment, DeploymentConfig, DeploymentImage, DeploymentState,
|
||||
@@ -423,7 +423,7 @@ fn extract_to_deploy_and_state<'a>(
|
||||
// Needs to only check config fields that affect docker run
|
||||
let changed = diff.server_id.is_some()
|
||||
|| diff.image.is_some()
|
||||
|| diff.image_registry.is_some()
|
||||
|| diff.image_registry_account.is_some()
|
||||
|| diff.skip_secret_interp.is_some()
|
||||
|| diff.network.is_some()
|
||||
|| diff.restart.is_some()
|
||||
@@ -467,7 +467,7 @@ fn extract_to_deploy_and_state<'a>(
|
||||
None => {
|
||||
let Some(version) = State
|
||||
.resolve(
|
||||
GetBuildVersions {
|
||||
ListBuildVersions {
|
||||
build: build_id.to_string(),
|
||||
limit: Some(1),
|
||||
..Default::default()
|
||||
|
||||
@@ -19,20 +19,27 @@ pub async fn get_remote_resources(
|
||||
String,
|
||||
)> {
|
||||
let name = to_monitor_name(&sync.name);
|
||||
let clone_args: CloneArgs = sync.into();
|
||||
let mut clone_args: CloneArgs = sync.into();
|
||||
|
||||
let config = core_config();
|
||||
|
||||
let github_token = clone_args
|
||||
.github_account
|
||||
.as_ref()
|
||||
.map(|account| {
|
||||
config.github_accounts.get(account).ok_or_else(|| {
|
||||
anyhow!("did not find github token for account {account}")
|
||||
let access_token = match (&clone_args.account, &clone_args.provider) {
|
||||
(None, _) => None,
|
||||
(Some(_), None) => return Err(anyhow!("Account is configured, but provider is empty")),
|
||||
(Some(username), Some(provider)) => config
|
||||
.git_providers
|
||||
.iter()
|
||||
.find(|_provider| {
|
||||
&_provider.domain == provider
|
||||
})
|
||||
})
|
||||
.transpose()?
|
||||
.cloned();
|
||||
.and_then(|provider| {
|
||||
clone_args.https = provider.https;
|
||||
provider.accounts.iter().find(|account| &account.username == username).map(|account| &account.token)
|
||||
})
|
||||
.with_context(|| format!("did not find git token for account {username} | provider: {provider}"))?
|
||||
.to_owned()
|
||||
.into(),
|
||||
};
|
||||
|
||||
fs::create_dir_all(&config.sync_directory)
|
||||
.context("failed to create sync directory")?;
|
||||
@@ -44,7 +51,7 @@ pub async fn get_remote_resources(
|
||||
let _lock = lock.lock().await;
|
||||
|
||||
let mut logs =
|
||||
git::clone(clone_args, &config.sync_directory, github_token)
|
||||
git::clone(clone_args, &config.sync_directory, access_token)
|
||||
.await
|
||||
.context("failed to clone resource repo")?;
|
||||
|
||||
|
||||
@@ -175,7 +175,7 @@ async fn verify_gh_signature(
|
||||
}
|
||||
let signature = signature.unwrap().replace("sha256=", "");
|
||||
let mut mac = HmacSha256::new_from_slice(
|
||||
core_config().github_webhook_secret.as_bytes(),
|
||||
core_config().webhook_secret.as_bytes(),
|
||||
)
|
||||
.expect("github webhook | failed to create hmac sha256");
|
||||
mac.update(body.as_bytes());
|
||||
|
||||
@@ -53,6 +53,7 @@ impl super::MonitorResource for Build {
|
||||
info: BuildListItemInfo {
|
||||
last_built_at: build.info.last_built_at,
|
||||
version: build.config.version,
|
||||
git_provider: build.config.git_provider,
|
||||
repo: build.config.repo,
|
||||
branch: build.config.branch,
|
||||
state,
|
||||
|
||||
@@ -60,6 +60,7 @@ impl super::MonitorResource for Repo {
|
||||
info: RepoListItemInfo {
|
||||
server_id: repo.config.server_id,
|
||||
last_pulled_at: repo.info.last_pulled_at,
|
||||
git_provider: repo.config.git_provider,
|
||||
repo: repo.config.repo,
|
||||
branch: repo.config.branch,
|
||||
state,
|
||||
|
||||
@@ -54,6 +54,7 @@ impl super::MonitorResource for ResourceSync {
|
||||
tags: resource_sync.tags,
|
||||
resource_type: ResourceTargetVariant::ResourceSync,
|
||||
info: ResourceSyncListItemInfo {
|
||||
git_provider: resource_sync.config.git_provider,
|
||||
repo: resource_sync.config.repo,
|
||||
branch: resource_sync.config.branch,
|
||||
last_sync_ts: resource_sync.info.last_sync_ts,
|
||||
|
||||
@@ -1,5 +1,4 @@
|
||||
# Build Core
|
||||
FROM rust:1.79.0-bookworm as builder
|
||||
FROM rust:1.79.0-bookworm AS builder
|
||||
WORKDIR /builder
|
||||
COPY . .
|
||||
RUN cargo build -p migrator --release
|
||||
@@ -9,4 +8,9 @@ FROM gcr.io/distroless/cc-debian12
|
||||
|
||||
COPY --from=builder /builder/target/release/migrator /
|
||||
|
||||
# Label for Ghcr
|
||||
LABEL org.opencontainers.image.source=https://github.com/mbecker20/monitor
|
||||
LABEL org.opencontainers.image.description="Database migrator for Monitor version upgrades"
|
||||
LABEL org.opencontainers.image.licenses=GPL-3.0
|
||||
|
||||
CMD ["./migrator"]
|
||||
@@ -1,5 +1,39 @@
|
||||
# Migrator
|
||||
|
||||
Upgrade data between periphery versions.
|
||||
Performs schema changes on the Monitor database
|
||||
|
||||
Supports v0.x -> v1.x migration.
|
||||
## v1.7 - v1.11 migration
|
||||
Run this before upgrading to latest from versions 1.7 to 1.11.
|
||||
```sh
|
||||
docker run --rm --name monitor-migrator \
|
||||
--env MIGRATION="v1.11" \
|
||||
--env TARGET_URI="mongodb://<USERNAME>:<PASSWORD>@<ADDRESS>" \
|
||||
--env TARGET_DB_NAME="<DB_NAME>" \
|
||||
ghcr.io/mbecker20/monitor_migrator
|
||||
```
|
||||
|
||||
## v1.0 - v1.6 migration
|
||||
Run this before upgrading to latest from versions 1.0 to 1.6.
|
||||
```sh
|
||||
docker run --rm --name monitor-migrator \
|
||||
--env MIGRATION="v1.6" \
|
||||
--env TARGET_URI="mongodb://<USERNAME>:<PASSWORD>@<ADDRESS>" \
|
||||
--env TARGET_DB_NAME="<DB_NAME>" \
|
||||
ghcr.io/mbecker20/monitor_migrator
|
||||
```
|
||||
|
||||
## v0.X migration
|
||||
Run this before upgrading to latest from version 0.X.
|
||||
|
||||
Note. As this is a major upgrade, this migration is not "in place".
|
||||
It will create another database (TARGET) and migrate resources over, leaving the original database (LEGACY) unchanged.
|
||||
|
||||
```sh
|
||||
docker run --rm --name monitor-migrator \
|
||||
--env MIGRATION="v0" \
|
||||
--env TARGET_URI="mongodb://<USERNAME>:<PASSWORD>@<ADDRESS>" \
|
||||
--env TARGET_DB_NAME="<TARGET_DB_NAME>" \
|
||||
--env LEGACY_URI="mongodb://<USERNAME>:<PASSWORD>@<ADDRESS>" \
|
||||
--env LEGACY_DB_NAME="<LEGACY_DB_NAME>" \
|
||||
ghcr.io/mbecker20/monitor_migrator
|
||||
```
|
||||
@@ -1,3 +1,4 @@
|
||||
#[allow(unused)]
|
||||
pub mod v0;
|
||||
pub mod v1_11;
|
||||
pub mod v1_6;
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
use anyhow::{anyhow, Context};
|
||||
use monitor_client::entities::build::{
|
||||
BuildConfig, BuildInfo, CloudRegistryConfig, ImageRegistry,
|
||||
BuildConfig, BuildInfo, ImageRegistry, StandardRegistryConfig,
|
||||
};
|
||||
use mungos::mongodb::bson::serde_helpers::hex_string_as_object_id;
|
||||
use serde::{Deserialize, Serialize};
|
||||
@@ -207,11 +207,14 @@ impl TryFrom<Build> for monitor_client::entities::build::Build {
|
||||
builder_id: String::new(),
|
||||
skip_secret_interp: value.skip_secret_interp,
|
||||
version: value.version.into(),
|
||||
git_provider: String::from("github.com"),
|
||||
git_https: true,
|
||||
repo: value.repo.unwrap_or_default(),
|
||||
branch: value.branch.unwrap_or_default(),
|
||||
github_account: value.github_account.unwrap_or_default(),
|
||||
image_registry: ImageRegistry::DockerHub(
|
||||
CloudRegistryConfig {
|
||||
git_account: value.github_account.unwrap_or_default(),
|
||||
image_registry: ImageRegistry::Standard(
|
||||
StandardRegistryConfig {
|
||||
domain: String::from("docker.io"),
|
||||
account: value.docker_account.unwrap_or_default(),
|
||||
organization: value
|
||||
.docker_organization
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
use monitor_client::entities::{
|
||||
build::{CloudRegistryConfig, ImageRegistry},
|
||||
build::{ImageRegistry, StandardRegistryConfig},
|
||||
NoData,
|
||||
};
|
||||
use mungos::mongodb::bson::serde_helpers::hex_string_as_object_id;
|
||||
@@ -378,15 +378,10 @@ impl TryFrom<Deployment>
|
||||
.post_image
|
||||
.unwrap_or_default(),
|
||||
extra_args: value.docker_run_args.extra_args,
|
||||
image_registry: match value.docker_run_args.docker_account {
|
||||
Some(account) => {
|
||||
ImageRegistry::DockerHub(CloudRegistryConfig {
|
||||
account,
|
||||
..Default::default()
|
||||
})
|
||||
}
|
||||
None => ImageRegistry::None(NoData {}),
|
||||
},
|
||||
image_registry_account: value
|
||||
.docker_run_args
|
||||
.docker_account
|
||||
.unwrap_or_default(),
|
||||
labels: Default::default(),
|
||||
},
|
||||
};
|
||||
|
||||
253
bin/migrator/src/legacy/v1_11/build.rs
Normal file
253
bin/migrator/src/legacy/v1_11/build.rs
Normal file
@@ -0,0 +1,253 @@
|
||||
use monitor_client::entities::{
|
||||
build::StandardRegistryConfig, EnvironmentVar, NoData,
|
||||
SystemCommand, Version, I64,
|
||||
};
|
||||
use serde::{Deserialize, Serialize};
|
||||
|
||||
use super::resource::Resource;
|
||||
|
||||
pub type Build = Resource<BuildConfig, BuildInfo>;
|
||||
|
||||
impl From<Build> for monitor_client::entities::build::Build {
|
||||
fn from(value: Build) -> Self {
|
||||
monitor_client::entities::build::Build {
|
||||
id: value.id,
|
||||
name: value.name,
|
||||
description: value.description,
|
||||
updated_at: value.updated_at,
|
||||
tags: value.tags,
|
||||
info: monitor_client::entities::build::BuildInfo {
|
||||
last_built_at: value.info.last_built_at,
|
||||
},
|
||||
config: value.config.into(),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Serialize, Deserialize, Debug, Clone, Default)]
|
||||
pub struct BuildInfo {
|
||||
pub last_built_at: I64,
|
||||
}
|
||||
|
||||
#[derive(Debug, Clone, Serialize, Deserialize)]
|
||||
pub struct BuildConfig {
|
||||
/// Which builder is used to build the image.
|
||||
#[serde(default, alias = "builder")]
|
||||
pub builder_id: String,
|
||||
|
||||
/// The current version of the build.
|
||||
#[serde(default)]
|
||||
pub version: Version,
|
||||
|
||||
/// The Github repo used as the source of the build.
|
||||
#[serde(default)]
|
||||
pub repo: String,
|
||||
|
||||
/// The branch of the repo.
|
||||
#[serde(default = "default_branch")]
|
||||
pub branch: String,
|
||||
|
||||
/// Optionally set a specific commit hash.
|
||||
#[serde(default)]
|
||||
pub commit: String,
|
||||
|
||||
/// The github account used to clone (used to access private repos).
|
||||
/// Empty string is public clone (only public repos).
|
||||
#[serde(default)]
|
||||
pub github_account: String,
|
||||
|
||||
/// The optional command run after repo clone and before docker build.
|
||||
#[serde(default)]
|
||||
pub pre_build: SystemCommand,
|
||||
|
||||
/// Configuration for the registry to push the built image to.
|
||||
#[serde(default)]
|
||||
pub image_registry: ImageRegistry,
|
||||
|
||||
/// The path of the docker build context relative to the root of the repo.
|
||||
/// Default: "." (the root of the repo).
|
||||
#[serde(default = "default_build_path")]
|
||||
pub build_path: String,
|
||||
|
||||
/// The path of the dockerfile relative to the build path.
|
||||
#[serde(default = "default_dockerfile_path")]
|
||||
pub dockerfile_path: String,
|
||||
|
||||
/// Whether to skip secret interpolation in the build_args.
|
||||
#[serde(default)]
|
||||
pub skip_secret_interp: bool,
|
||||
|
||||
/// Whether to use buildx to build (eg `docker buildx build ...`)
|
||||
#[serde(default)]
|
||||
pub use_buildx: bool,
|
||||
|
||||
/// Whether incoming webhooks actually trigger action.
|
||||
#[serde(default = "default_webhook_enabled")]
|
||||
pub webhook_enabled: bool,
|
||||
|
||||
/// Any extra docker cli arguments to be included in the build command
|
||||
#[serde(default)]
|
||||
pub extra_args: Vec<String>,
|
||||
|
||||
/// Docker build arguments.
|
||||
///
|
||||
/// These values are visible in the final image by running `docker inspect`.
|
||||
#[serde(
|
||||
default,
|
||||
deserialize_with = "monitor_client::entities::env_vars_deserializer"
|
||||
)]
|
||||
pub build_args: Vec<EnvironmentVar>,
|
||||
|
||||
/// Secret arguments.
|
||||
///
|
||||
/// These values remain hidden in the final image by using
|
||||
/// docker secret mounts. See `<https://docs.docker.com/build/building/secrets>`.
|
||||
///
|
||||
/// The values can be used in RUN commands:
|
||||
/// ```
|
||||
/// RUN --mount=type=secret,id=SECRET_KEY \
|
||||
/// SECRET_KEY=$(cat /run/secrets/SECRET_KEY) ...
|
||||
/// ```
|
||||
#[serde(
|
||||
default,
|
||||
deserialize_with = "monitor_client::entities::env_vars_deserializer"
|
||||
)]
|
||||
pub secret_args: Vec<EnvironmentVar>,
|
||||
|
||||
/// Docker labels
|
||||
#[serde(
|
||||
default,
|
||||
deserialize_with = "monitor_client::entities::env_vars_deserializer"
|
||||
)]
|
||||
pub labels: Vec<EnvironmentVar>,
|
||||
}
|
||||
|
||||
impl From<BuildConfig>
|
||||
for monitor_client::entities::build::BuildConfig
|
||||
{
|
||||
fn from(value: BuildConfig) -> Self {
|
||||
monitor_client::entities::build::BuildConfig {
|
||||
builder_id: value.builder_id,
|
||||
skip_secret_interp: value.skip_secret_interp,
|
||||
version: monitor_client::entities::Version {
|
||||
major: value.version.major,
|
||||
minor: value.version.minor,
|
||||
patch: value.version.patch,
|
||||
},
|
||||
git_provider: String::from("github.com"),
|
||||
git_https: true,
|
||||
repo: value.repo,
|
||||
branch: value.branch,
|
||||
commit: value.commit,
|
||||
git_account: value.github_account,
|
||||
pre_build: monitor_client::entities::SystemCommand {
|
||||
path: value.pre_build.path,
|
||||
command: value.pre_build.command,
|
||||
},
|
||||
build_path: value.build_path,
|
||||
dockerfile_path: value.dockerfile_path,
|
||||
build_args: value
|
||||
.build_args
|
||||
.into_iter()
|
||||
.map(Into::into)
|
||||
.collect(),
|
||||
secret_args: Default::default(),
|
||||
labels: value.labels.into_iter().map(Into::into).collect(),
|
||||
extra_args: value.extra_args,
|
||||
use_buildx: value.use_buildx,
|
||||
webhook_enabled: value.webhook_enabled,
|
||||
image_registry: value.image_registry.into(),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
fn default_branch() -> String {
|
||||
String::from("main")
|
||||
}
|
||||
|
||||
fn default_build_path() -> String {
|
||||
String::from(".")
|
||||
}
|
||||
|
||||
fn default_dockerfile_path() -> String {
|
||||
String::from("Dockerfile")
|
||||
}
|
||||
|
||||
fn default_webhook_enabled() -> bool {
|
||||
true
|
||||
}
|
||||
|
||||
#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)]
|
||||
#[serde(tag = "type", content = "params")]
|
||||
pub enum ImageRegistry {
|
||||
/// Don't push the image to any registry
|
||||
None(NoData),
|
||||
/// Push the image to DockerHub
|
||||
DockerHub(CloudRegistryConfig),
|
||||
/// Push the image to the Github Container Registry.
|
||||
///
|
||||
/// See [the Github docs](https://docs.github.com/en/packages/working-with-a-github-packages-registry/working-with-the-container-registry#pushing-container-images)
|
||||
/// for information on creating an access token
|
||||
Ghcr(CloudRegistryConfig),
|
||||
/// Push the image to Aws Elastic Container Registry
|
||||
///
|
||||
/// The string held in 'params' should match a label of an `aws_ecr_registry` in the core config.
|
||||
AwsEcr(String),
|
||||
/// Todo. Will point to a custom "Registry" resource by id
|
||||
Custom(String),
|
||||
}
|
||||
|
||||
impl Default for ImageRegistry {
|
||||
fn default() -> Self {
|
||||
Self::None(NoData {})
|
||||
}
|
||||
}
|
||||
|
||||
impl From<ImageRegistry>
|
||||
for monitor_client::entities::build::ImageRegistry
|
||||
{
|
||||
fn from(value: ImageRegistry) -> Self {
|
||||
match value {
|
||||
ImageRegistry::None(_) | ImageRegistry::Custom(_) => {
|
||||
monitor_client::entities::build::ImageRegistry::None(
|
||||
NoData {},
|
||||
)
|
||||
}
|
||||
ImageRegistry::DockerHub(params) => {
|
||||
monitor_client::entities::build::ImageRegistry::Standard(
|
||||
StandardRegistryConfig {
|
||||
domain: String::from("docker.io"),
|
||||
account: params.account,
|
||||
organization: params.organization,
|
||||
},
|
||||
)
|
||||
}
|
||||
ImageRegistry::Ghcr(params) => {
|
||||
monitor_client::entities::build::ImageRegistry::Standard(
|
||||
StandardRegistryConfig {
|
||||
domain: String::from("ghcr.io"),
|
||||
account: params.account,
|
||||
organization: params.organization,
|
||||
},
|
||||
)
|
||||
}
|
||||
ImageRegistry::AwsEcr(label) => {
|
||||
monitor_client::entities::build::ImageRegistry::AwsEcr(label)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(
|
||||
Debug, Clone, Default, PartialEq, Serialize, Deserialize,
|
||||
)]
|
||||
pub struct CloudRegistryConfig {
|
||||
/// Specify an account to use with the cloud registry.
|
||||
#[serde(default)]
|
||||
pub account: String,
|
||||
|
||||
/// Optional. Specify an organization to push the image under.
|
||||
/// Empty string means no organization.
|
||||
#[serde(default)]
|
||||
pub organization: String,
|
||||
}
|
||||
167
bin/migrator/src/legacy/v1_11/deployment.rs
Normal file
167
bin/migrator/src/legacy/v1_11/deployment.rs
Normal file
@@ -0,0 +1,167 @@
|
||||
use monitor_client::entities::{
|
||||
deployment::{
|
||||
conversions_deserializer, term_labels_deserializer, Conversion,
|
||||
DeploymentImage, RestartMode, TerminationSignal,
|
||||
TerminationSignalLabel,
|
||||
},
|
||||
env_vars_deserializer, EnvironmentVar,
|
||||
};
|
||||
use serde::{Deserialize, Serialize};
|
||||
|
||||
use super::{build::ImageRegistry, resource::Resource};
|
||||
|
||||
pub type Deployment = Resource<DeploymentConfig, ()>;
|
||||
|
||||
impl From<Deployment>
|
||||
for monitor_client::entities::deployment::Deployment
|
||||
{
|
||||
fn from(value: Deployment) -> Self {
|
||||
monitor_client::entities::deployment::Deployment {
|
||||
id: value.id,
|
||||
name: value.name,
|
||||
description: value.description,
|
||||
updated_at: value.updated_at,
|
||||
tags: value.tags,
|
||||
info: (),
|
||||
config: value.config.into(),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Serialize, Deserialize, Debug, Clone)]
|
||||
pub struct DeploymentConfig {
|
||||
/// The id of server the deployment is deployed on.
|
||||
#[serde(default, alias = "server")]
|
||||
pub server_id: String,
|
||||
|
||||
/// The image which the deployment deploys.
|
||||
/// Can either be a user inputted image, or a Monitor build.
|
||||
#[serde(default)]
|
||||
pub image: DeploymentImage,
|
||||
|
||||
/// Configure the registry used to pull the image from the registry.
|
||||
/// Used with `docker login`.
|
||||
///
|
||||
/// When using attached build as image source:
|
||||
/// - If the field is `None` variant, will use the same ImageRegistry config as the build.
|
||||
/// - Otherwise, it must match the variant of the ImageRegistry build config.
|
||||
/// - Only the account is used, the organization is not needed here
|
||||
#[serde(default)]
|
||||
pub image_registry: ImageRegistry,
|
||||
|
||||
/// Whether to skip secret interpolation into the deployment environment variables.
|
||||
#[serde(default)]
|
||||
pub skip_secret_interp: bool,
|
||||
|
||||
/// Whether to redeploy the deployment whenever the attached build finishes.
|
||||
#[serde(default)]
|
||||
pub redeploy_on_build: bool,
|
||||
|
||||
/// Whether to send ContainerStateChange alerts for this deployment.
|
||||
#[serde(default = "default_send_alerts")]
|
||||
pub send_alerts: bool,
|
||||
|
||||
/// The network attached to the container.
|
||||
/// Default is `host`.
|
||||
#[serde(default = "default_network")]
|
||||
pub network: String,
|
||||
|
||||
/// The restart mode given to the container.
|
||||
#[serde(default)]
|
||||
pub restart: RestartMode,
|
||||
|
||||
/// This is interpolated at the end of the `docker run` command,
|
||||
/// which means they are either passed to the containers inner process,
|
||||
/// or replaces the container command, depending on use of ENTRYPOINT or CMD in dockerfile.
|
||||
/// Empty is no command.
|
||||
#[serde(default)]
|
||||
pub command: String,
|
||||
|
||||
/// The default termination signal to use to stop the deployment. Defaults to SigTerm (default docker signal).
|
||||
#[serde(default)]
|
||||
pub termination_signal: TerminationSignal,
|
||||
|
||||
/// The termination timeout.
|
||||
#[serde(default = "default_termination_timeout")]
|
||||
pub termination_timeout: i32,
|
||||
|
||||
/// Extra args which are interpolated into the `docker run` command,
|
||||
/// and affect the container configuration.
|
||||
#[serde(default)]
|
||||
pub extra_args: Vec<String>,
|
||||
|
||||
/// Labels attached to various termination signal options.
|
||||
/// Used to specify different shutdown functionality depending on the termination signal.
|
||||
#[serde(
|
||||
default = "default_term_signal_labels",
|
||||
deserialize_with = "term_labels_deserializer"
|
||||
)]
|
||||
pub term_signal_labels: Vec<TerminationSignalLabel>,
|
||||
|
||||
/// The container port mapping.
|
||||
/// Irrelevant if container network is `host`.
|
||||
/// Maps ports on host to ports on container.
|
||||
#[serde(default, deserialize_with = "conversions_deserializer")]
|
||||
pub ports: Vec<Conversion>,
|
||||
|
||||
/// The container volume mapping.
|
||||
/// Maps files / folders on host to files / folders in container.
|
||||
#[serde(default, deserialize_with = "conversions_deserializer")]
|
||||
pub volumes: Vec<Conversion>,
|
||||
|
||||
/// The environment variables passed to the container.
|
||||
#[serde(default, deserialize_with = "env_vars_deserializer")]
|
||||
pub environment: Vec<EnvironmentVar>,
|
||||
|
||||
/// The docker labels given to the container.
|
||||
#[serde(default, deserialize_with = "env_vars_deserializer")]
|
||||
pub labels: Vec<EnvironmentVar>,
|
||||
}
|
||||
|
||||
fn default_send_alerts() -> bool {
|
||||
true
|
||||
}
|
||||
|
||||
fn default_term_signal_labels() -> Vec<TerminationSignalLabel> {
|
||||
vec![TerminationSignalLabel::default()]
|
||||
}
|
||||
|
||||
fn default_termination_timeout() -> i32 {
|
||||
10
|
||||
}
|
||||
|
||||
fn default_network() -> String {
|
||||
String::from("host")
|
||||
}
|
||||
|
||||
impl From<DeploymentConfig>
|
||||
for monitor_client::entities::deployment::DeploymentConfig
|
||||
{
|
||||
fn from(value: DeploymentConfig) -> Self {
|
||||
monitor_client::entities::deployment::DeploymentConfig {
|
||||
server_id: value.server_id,
|
||||
image: value.image,
|
||||
image_registry_account: match value.image_registry {
|
||||
ImageRegistry::None(_)
|
||||
| ImageRegistry::AwsEcr(_)
|
||||
| ImageRegistry::Custom(_) => String::new(),
|
||||
ImageRegistry::DockerHub(params) => params.account,
|
||||
ImageRegistry::Ghcr(params) => params.account,
|
||||
},
|
||||
skip_secret_interp: value.skip_secret_interp,
|
||||
redeploy_on_build: value.redeploy_on_build,
|
||||
send_alerts: value.send_alerts,
|
||||
network: value.network,
|
||||
restart: value.restart,
|
||||
command: value.command,
|
||||
termination_signal: value.termination_signal,
|
||||
termination_timeout: value.termination_timeout,
|
||||
extra_args: value.extra_args,
|
||||
term_signal_labels: value.term_signal_labels,
|
||||
ports: value.ports,
|
||||
volumes: value.volumes,
|
||||
environment: value.environment,
|
||||
labels: value.labels,
|
||||
}
|
||||
}
|
||||
}
|
||||
48
bin/migrator/src/legacy/v1_11/mod.rs
Normal file
48
bin/migrator/src/legacy/v1_11/mod.rs
Normal file
@@ -0,0 +1,48 @@
|
||||
use mungos::{init::MongoBuilder, mongodb::Collection};
|
||||
use serde::{Deserialize, Serialize};
|
||||
|
||||
pub mod build;
|
||||
pub mod deployment;
|
||||
pub mod resource;
|
||||
|
||||
pub struct DbClient {
|
||||
pub builds: Collection<build::Build>,
|
||||
pub deployments: Collection<deployment::Deployment>,
|
||||
}
|
||||
|
||||
impl DbClient {
|
||||
pub async fn new(
|
||||
legacy_uri: &str,
|
||||
legacy_db_name: &str,
|
||||
) -> DbClient {
|
||||
let client = MongoBuilder::default()
|
||||
.uri(legacy_uri)
|
||||
.build()
|
||||
.await
|
||||
.expect("failed to init legacy mongo client");
|
||||
let db = client.database(legacy_db_name);
|
||||
DbClient {
|
||||
builds: db.collection("Build"),
|
||||
deployments: db.collection("Deployment"),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(
|
||||
Serialize, Deserialize, Debug, Clone, Default, PartialEq,
|
||||
)]
|
||||
pub struct Version {
|
||||
pub major: i32,
|
||||
pub minor: i32,
|
||||
pub patch: i32,
|
||||
}
|
||||
|
||||
#[derive(
|
||||
Serialize, Deserialize, Debug, Clone, Default, PartialEq, Eq,
|
||||
)]
|
||||
pub struct SystemCommand {
|
||||
#[serde(default)]
|
||||
pub path: String,
|
||||
#[serde(default)]
|
||||
pub command: String,
|
||||
}
|
||||
54
bin/migrator/src/legacy/v1_11/resource.rs
Normal file
54
bin/migrator/src/legacy/v1_11/resource.rs
Normal file
@@ -0,0 +1,54 @@
|
||||
use mungos::mongodb::bson::serde_helpers::hex_string_as_object_id;
|
||||
use serde::{Deserialize, Serialize};
|
||||
|
||||
#[derive(Debug, Clone, Serialize, Deserialize)]
|
||||
pub struct Resource<Config, Info: Default = ()> {
|
||||
/// The Mongo ID of the resource.
|
||||
/// This field is de/serialized from/to JSON as
|
||||
/// `{ "_id": { "$oid": "..." }, ...(rest of serialized Resource<T>) }`
|
||||
#[serde(
|
||||
default,
|
||||
rename = "_id",
|
||||
skip_serializing_if = "String::is_empty",
|
||||
with = "hex_string_as_object_id"
|
||||
)]
|
||||
pub id: String,
|
||||
|
||||
/// The resource name.
|
||||
/// This is guaranteed unique among others of the same resource type.
|
||||
pub name: String,
|
||||
|
||||
/// A description for the resource
|
||||
#[serde(default)]
|
||||
pub description: String,
|
||||
|
||||
/// When description last updated
|
||||
#[serde(default)]
|
||||
pub updated_at: i64,
|
||||
|
||||
/// Tag Ids
|
||||
#[serde(default)]
|
||||
pub tags: Vec<String>,
|
||||
|
||||
/// Resource-specific information (not user configurable).
|
||||
#[serde(default)]
|
||||
pub info: Info,
|
||||
|
||||
/// Resource-specific configuration.
|
||||
pub config: Config,
|
||||
}
|
||||
|
||||
#[derive(Serialize, Deserialize, Debug, Clone)]
|
||||
pub struct ResourceListItem<Info> {
|
||||
/// The resource id
|
||||
pub id: String,
|
||||
/// The resource type, ie `Server` or `Deployment`
|
||||
// #[serde(rename = "type")]
|
||||
// pub resource_type: ResourceTargetVariant,
|
||||
/// The resource name
|
||||
pub name: String,
|
||||
/// Tag Ids
|
||||
pub tags: Vec<String>,
|
||||
/// Resource specific info
|
||||
pub info: Info,
|
||||
}
|
||||
@@ -1,5 +1,5 @@
|
||||
use monitor_client::entities::{
|
||||
build::{CloudRegistryConfig, ImageRegistry},
|
||||
build::{ImageRegistry, StandardRegistryConfig},
|
||||
NoData,
|
||||
};
|
||||
use serde::{Deserialize, Serialize};
|
||||
@@ -119,10 +119,12 @@ impl From<BuildConfig>
|
||||
minor: value.version.minor,
|
||||
patch: value.version.patch,
|
||||
},
|
||||
git_provider: String::from("github.com"),
|
||||
git_https: true,
|
||||
repo: value.repo,
|
||||
branch: value.branch,
|
||||
commit: value.commit,
|
||||
github_account: value.github_account,
|
||||
git_account: value.github_account,
|
||||
pre_build: monitor_client::entities::SystemCommand {
|
||||
path: value.pre_build.path,
|
||||
command: value.pre_build.command,
|
||||
@@ -141,7 +143,8 @@ impl From<BuildConfig>
|
||||
image_registry: if value.docker_account.is_empty() {
|
||||
ImageRegistry::None(NoData {})
|
||||
} else {
|
||||
ImageRegistry::DockerHub(CloudRegistryConfig {
|
||||
ImageRegistry::Standard(StandardRegistryConfig {
|
||||
domain: String::from("docker.io"),
|
||||
account: value.docker_account,
|
||||
organization: value.docker_organization,
|
||||
})
|
||||
|
||||
@@ -1,10 +1,6 @@
|
||||
use monitor_client::entities::{
|
||||
build::{CloudRegistryConfig, ImageRegistry},
|
||||
deployment::{
|
||||
Conversion, DeploymentImage, RestartMode, TerminationSignal,
|
||||
TerminationSignalLabel,
|
||||
},
|
||||
NoData,
|
||||
use monitor_client::entities::deployment::{
|
||||
Conversion, DeploymentImage, RestartMode, TerminationSignal,
|
||||
TerminationSignalLabel,
|
||||
};
|
||||
use serde::{Deserialize, Serialize};
|
||||
|
||||
@@ -118,14 +114,7 @@ impl From<DeploymentConfig>
|
||||
server_id: value.server_id,
|
||||
send_alerts: value.send_alerts,
|
||||
image: value.image,
|
||||
image_registry: if value.docker_account.is_empty() {
|
||||
ImageRegistry::None(NoData {})
|
||||
} else {
|
||||
ImageRegistry::DockerHub(CloudRegistryConfig {
|
||||
account: value.docker_account,
|
||||
..Default::default()
|
||||
})
|
||||
},
|
||||
image_registry_account: value.docker_account,
|
||||
skip_secret_interp: value.skip_secret_interp,
|
||||
redeploy_on_build: value.redeploy_on_build,
|
||||
term_signal_labels: value.term_signal_labels,
|
||||
|
||||
@@ -12,14 +12,18 @@ mod legacy;
|
||||
mod migrate;
|
||||
|
||||
#[derive(Deserialize)]
|
||||
enum AppMode {
|
||||
enum Migration {
|
||||
#[serde(alias = "v0")]
|
||||
V0,
|
||||
#[serde(alias = "v1.6")]
|
||||
V1_6,
|
||||
#[serde(alias = "v1.11")]
|
||||
V1_11,
|
||||
}
|
||||
|
||||
#[derive(Deserialize)]
|
||||
struct Env {
|
||||
app_mode: AppMode,
|
||||
migration: Migration,
|
||||
legacy_uri: String,
|
||||
legacy_db_name: String,
|
||||
target_uri: String,
|
||||
@@ -35,8 +39,8 @@ async fn main() -> anyhow::Result<()> {
|
||||
|
||||
let env: Env = envy::from_env()?;
|
||||
|
||||
match env.app_mode {
|
||||
AppMode::V0 => {
|
||||
match env.migration {
|
||||
Migration::V0 => {
|
||||
let legacy_db = legacy::v0::DbClient::new(
|
||||
&env.legacy_uri,
|
||||
&env.legacy_db_name,
|
||||
@@ -46,7 +50,7 @@ async fn main() -> anyhow::Result<()> {
|
||||
DbClient::new(&env.target_uri, &env.target_db_name).await?;
|
||||
migrate::v0::migrate_all(&legacy_db, &target_db).await?
|
||||
}
|
||||
AppMode::V1_6 => {
|
||||
Migration::V1_6 => {
|
||||
let db = legacy::v1_6::DbClient::new(
|
||||
&env.target_uri,
|
||||
&env.target_db_name,
|
||||
@@ -54,6 +58,14 @@ async fn main() -> anyhow::Result<()> {
|
||||
.await;
|
||||
migrate::v1_6::migrate_all_in_place(&db).await?
|
||||
}
|
||||
Migration::V1_11 => {
|
||||
let db = legacy::v1_11::DbClient::new(
|
||||
&env.target_uri,
|
||||
&env.target_db_name,
|
||||
)
|
||||
.await;
|
||||
migrate::v1_11::migrate_all_in_place(&db).await?
|
||||
}
|
||||
}
|
||||
|
||||
info!("finished!");
|
||||
|
||||
@@ -1,2 +1,3 @@
|
||||
pub mod v0;
|
||||
pub mod v1_11;
|
||||
pub mod v1_6;
|
||||
|
||||
@@ -44,7 +44,8 @@ pub async fn migrate_users(
|
||||
}
|
||||
|
||||
let username = user.username.clone();
|
||||
user.try_into()
|
||||
user
|
||||
.try_into()
|
||||
.inspect_err(|e| {
|
||||
warn!("failed to convert user {username} | {e:#}")
|
||||
})
|
||||
|
||||
72
bin/migrator/src/migrate/v1_11.rs
Normal file
72
bin/migrator/src/migrate/v1_11.rs
Normal file
@@ -0,0 +1,72 @@
|
||||
use anyhow::Context;
|
||||
use monitor_client::entities::{
|
||||
build::Build, deployment::Deployment,
|
||||
};
|
||||
use mungos::{
|
||||
find::find_collect,
|
||||
mongodb::bson::{doc, to_document},
|
||||
};
|
||||
|
||||
use crate::legacy::v1_11;
|
||||
|
||||
pub async fn migrate_all_in_place(
|
||||
db: &v1_11::DbClient,
|
||||
) -> anyhow::Result<()> {
|
||||
migrate_builds_in_place(db).await?;
|
||||
migrate_deployments_in_place(db).await?;
|
||||
Ok(())
|
||||
}
|
||||
|
||||
pub async fn migrate_builds_in_place(
|
||||
db: &v1_11::DbClient,
|
||||
) -> anyhow::Result<()> {
|
||||
let builds = find_collect(&db.builds, None, None)
|
||||
.await
|
||||
.context("failed to get builds")?
|
||||
.into_iter()
|
||||
.map(Into::into)
|
||||
.collect::<Vec<Build>>();
|
||||
|
||||
info!("migrating {} builds...", builds.len());
|
||||
|
||||
for build in builds {
|
||||
db.builds
|
||||
.update_one(
|
||||
doc! { "name": &build.name },
|
||||
doc! { "$set": to_document(&build)? },
|
||||
)
|
||||
.await
|
||||
.context("failed to insert builds on target")?;
|
||||
}
|
||||
|
||||
info!("builds have been migrated\n");
|
||||
|
||||
Ok(())
|
||||
}
|
||||
|
||||
pub async fn migrate_deployments_in_place(
|
||||
db: &v1_11::DbClient,
|
||||
) -> anyhow::Result<()> {
|
||||
let deployments = find_collect(&db.deployments, None, None)
|
||||
.await
|
||||
.context("failed to get deployments")?
|
||||
.into_iter()
|
||||
.map(Into::into)
|
||||
.collect::<Vec<Deployment>>();
|
||||
|
||||
info!("migrating {} deployments...", deployments.len());
|
||||
|
||||
for deployment in deployments {
|
||||
db.deployments
|
||||
.update_one(
|
||||
doc! { "name": &deployment.name },
|
||||
doc! { "$set": to_document(&deployment)? },
|
||||
)
|
||||
.await
|
||||
.context("failed to insert deployments on target")?;
|
||||
}
|
||||
|
||||
info!("deployments have been migrated\n");
|
||||
|
||||
Ok(())
|
||||
}
|
||||
@@ -2,14 +2,15 @@ use anyhow::{anyhow, Context};
|
||||
use command::run_monitor_command;
|
||||
use formatting::format_serror;
|
||||
use monitor_client::entities::{
|
||||
build::{ImageRegistry, StandardRegistryConfig},
|
||||
deployment::{
|
||||
ContainerSummary, Conversion, Deployment, DeploymentConfig,
|
||||
DeploymentImage, DockerContainerStats, RestartMode,
|
||||
TerminationSignal,
|
||||
extract_registry_domain, ContainerSummary, Conversion,
|
||||
Deployment, DeploymentConfig, DeploymentImage,
|
||||
DockerContainerStats, RestartMode, TerminationSignal,
|
||||
},
|
||||
to_monitor_name,
|
||||
update::Log,
|
||||
EnvironmentVar, SearchCombinator,
|
||||
EnvironmentVar, NoData, SearchCombinator,
|
||||
};
|
||||
use periphery_client::api::container::*;
|
||||
use resolver_api::Resolve;
|
||||
@@ -259,21 +260,6 @@ impl Resolve<Deploy> for State {
|
||||
}: Deploy,
|
||||
_: (),
|
||||
) -> anyhow::Result<Log> {
|
||||
if let Err(e) = docker_login(
|
||||
&deployment.config.image_registry,
|
||||
registry_token.as_deref(),
|
||||
aws_ecr.as_ref(),
|
||||
)
|
||||
.await
|
||||
{
|
||||
return Ok(Log::error(
|
||||
"docker login",
|
||||
format_serror(
|
||||
&e.context("failed to login to docker registry").into(),
|
||||
),
|
||||
));
|
||||
}
|
||||
|
||||
let image = if let DeploymentImage::Image { image } =
|
||||
&deployment.config.image
|
||||
{
|
||||
@@ -291,6 +277,33 @@ impl Resolve<Deploy> for State {
|
||||
));
|
||||
};
|
||||
|
||||
let image_registry = if aws_ecr.is_some() {
|
||||
ImageRegistry::AwsEcr(String::new())
|
||||
} else if deployment.config.image_registry_account.is_empty() {
|
||||
ImageRegistry::None(NoData {})
|
||||
} else {
|
||||
ImageRegistry::Standard(StandardRegistryConfig {
|
||||
account: deployment.config.image_registry_account.clone(),
|
||||
domain: extract_registry_domain(image)?,
|
||||
..Default::default()
|
||||
})
|
||||
};
|
||||
|
||||
if let Err(e) = docker_login(
|
||||
&image_registry,
|
||||
registry_token.as_deref(),
|
||||
aws_ecr.as_ref(),
|
||||
)
|
||||
.await
|
||||
{
|
||||
return Ok(Log::error(
|
||||
"docker login",
|
||||
format_serror(
|
||||
&e.context("failed to login to docker registry").into(),
|
||||
),
|
||||
));
|
||||
}
|
||||
|
||||
let _ = pull_image(image).await;
|
||||
debug!("image pulled");
|
||||
let _ = State
|
||||
|
||||
@@ -8,7 +8,7 @@ use periphery_client::api::git::{
|
||||
use resolver_api::Resolve;
|
||||
|
||||
use crate::{
|
||||
config::periphery_config, helpers::get_github_token, State,
|
||||
config::periphery_config, helpers::get_git_token, State,
|
||||
};
|
||||
|
||||
impl Resolve<GetLatestCommit, ()> for State {
|
||||
@@ -31,22 +31,29 @@ impl Resolve<CloneRepo> for State {
|
||||
#[instrument(name = "CloneRepo", skip(self))]
|
||||
async fn resolve(
|
||||
&self,
|
||||
CloneRepo { args, github_token }: CloneRepo,
|
||||
CloneRepo { args, git_token }: CloneRepo,
|
||||
_: (),
|
||||
) -> anyhow::Result<Vec<Log>> {
|
||||
let CloneArgs { github_account, .. } = &args;
|
||||
let github_token = match (github_account, github_token) {
|
||||
(None, _) => None,
|
||||
(Some(_), Some(token)) => Some(token),
|
||||
(Some(account), None) => Some(
|
||||
get_github_token(account)
|
||||
.context(
|
||||
"failed to get github token from periphery config",
|
||||
let CloneArgs {
|
||||
provider, account, ..
|
||||
} = &args;
|
||||
let token = match (account, provider, git_token) {
|
||||
(None, _, _) => None,
|
||||
(Some(_), None, _) => {
|
||||
return Err(anyhow!(
|
||||
"got incoming git account but no git provider"
|
||||
))
|
||||
}
|
||||
(Some(_), Some(_), Some(token)) => Some(token),
|
||||
(Some(account), Some(provider), None) => Some(
|
||||
get_git_token(provider, account)
|
||||
.with_context(
|
||||
|| format!("failed to get git token from periphery config | provider: {provider} | account: {account}")
|
||||
)?
|
||||
.clone(),
|
||||
),
|
||||
};
|
||||
git::clone(args, &periphery_config().repo_dir, github_token).await
|
||||
git::clone(args, &periphery_config().repo_dir, token).await
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -1,16 +1,22 @@
|
||||
use anyhow::Context;
|
||||
use command::run_monitor_command;
|
||||
use monitor_client::entities::{update::Log, SystemCommand};
|
||||
use monitor_client::{
|
||||
api::read::ListGitProviders,
|
||||
entities::{update::Log, SystemCommand},
|
||||
};
|
||||
use periphery_client::api::{
|
||||
build::*, container::*, git::*, network::*, stats::*, GetAccounts,
|
||||
GetHealth, GetSecrets, GetVersion, GetVersionResponse, PruneSystem,
|
||||
RunCommand,
|
||||
build::*, container::*, git::*, network::*, stats::*, GetHealth,
|
||||
GetVersion, GetVersionResponse, ListDockerRegistries, ListSecrets,
|
||||
PruneSystem, RunCommand,
|
||||
};
|
||||
use resolver_api::{derive::Resolver, Resolve, ResolveToString};
|
||||
use serde::{Deserialize, Serialize};
|
||||
|
||||
use crate::{
|
||||
config::{accounts_response, secrets_response},
|
||||
config::{
|
||||
docker_registries_response, git_providers_response,
|
||||
secrets_response,
|
||||
},
|
||||
State,
|
||||
};
|
||||
|
||||
@@ -31,9 +37,11 @@ pub enum PeripheryRequest {
|
||||
|
||||
// Config
|
||||
#[to_string_resolver]
|
||||
GetAccounts(GetAccounts),
|
||||
ListGitProviders(ListGitProviders),
|
||||
#[to_string_resolver]
|
||||
GetSecrets(GetSecrets),
|
||||
ListDockerRegistries(ListDockerRegistries),
|
||||
#[to_string_resolver]
|
||||
ListSecrets(ListSecrets),
|
||||
|
||||
// Stats / Info
|
||||
#[to_string_resolver]
|
||||
@@ -101,24 +109,43 @@ impl Resolve<GetVersion> for State {
|
||||
|
||||
//
|
||||
|
||||
impl ResolveToString<GetAccounts> for State {
|
||||
#[instrument(name = "GetAccounts", level = "debug", skip(self))]
|
||||
impl ResolveToString<ListGitProviders> for State {
|
||||
#[instrument(
|
||||
name = "ListGitProviders",
|
||||
level = "debug",
|
||||
skip(self)
|
||||
)]
|
||||
async fn resolve_to_string(
|
||||
&self,
|
||||
_: GetAccounts,
|
||||
_: ListGitProviders,
|
||||
_: (),
|
||||
) -> anyhow::Result<String> {
|
||||
Ok(accounts_response().clone())
|
||||
Ok(git_providers_response().clone())
|
||||
}
|
||||
}
|
||||
|
||||
impl ResolveToString<ListDockerRegistries> for State {
|
||||
#[instrument(
|
||||
name = "ListDockerRegistries",
|
||||
level = "debug",
|
||||
skip(self)
|
||||
)]
|
||||
async fn resolve_to_string(
|
||||
&self,
|
||||
_: ListDockerRegistries,
|
||||
_: (),
|
||||
) -> anyhow::Result<String> {
|
||||
Ok(docker_registries_response().clone())
|
||||
}
|
||||
}
|
||||
|
||||
//
|
||||
|
||||
impl ResolveToString<GetSecrets> for State {
|
||||
#[instrument(name = "GetSecrets", level = "debug", skip(self))]
|
||||
impl ResolveToString<ListSecrets> for State {
|
||||
#[instrument(name = "ListSecrets", level = "debug", skip(self))]
|
||||
async fn resolve_to_string(
|
||||
&self,
|
||||
_: GetSecrets,
|
||||
_: ListSecrets,
|
||||
_: (),
|
||||
) -> anyhow::Result<String> {
|
||||
Ok(secrets_response().clone())
|
||||
|
||||
@@ -6,7 +6,6 @@ use monitor_client::entities::{
|
||||
config::periphery::{CliArgs, Env, PeripheryConfig},
|
||||
logger::LogLevel,
|
||||
};
|
||||
use serde_json::json;
|
||||
|
||||
pub fn periphery_config() -> &'static PeripheryConfig {
|
||||
static PERIPHERY_CONFIG: OnceLock<PeripheryConfig> =
|
||||
@@ -57,12 +56,21 @@ pub fn periphery_config() -> &'static PeripheryConfig {
|
||||
})
|
||||
}
|
||||
|
||||
pub fn accounts_response() -> &'static String {
|
||||
static ACCOUNTS_RESPONSE: OnceLock<String> = OnceLock::new();
|
||||
ACCOUNTS_RESPONSE.get_or_init(|| json!({
|
||||
"docker": periphery_config().docker_accounts.keys().collect::<Vec<_>>(),
|
||||
"github": periphery_config().github_accounts.keys().collect::<Vec<_>>(),
|
||||
}).to_string())
|
||||
pub fn git_providers_response() -> &'static String {
|
||||
static GIT_PROVIDERS_RESPONSE: OnceLock<String> = OnceLock::new();
|
||||
GIT_PROVIDERS_RESPONSE.get_or_init(|| {
|
||||
let config = periphery_config();
|
||||
serde_json::to_string(&config.git_providers).unwrap()
|
||||
})
|
||||
}
|
||||
|
||||
pub fn docker_registries_response() -> &'static String {
|
||||
static DOCKER_REGISTRIES_RESPONSE: OnceLock<String> =
|
||||
OnceLock::new();
|
||||
DOCKER_REGISTRIES_RESPONSE.get_or_init(|| {
|
||||
let config = periphery_config();
|
||||
serde_json::to_string(&config.docker_registries).unwrap()
|
||||
})
|
||||
}
|
||||
|
||||
pub fn secrets_response() -> &'static String {
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
use anyhow::{anyhow, Context};
|
||||
use monitor_client::entities::{
|
||||
build::{CloudRegistryConfig, ImageRegistry},
|
||||
build::{ImageRegistry, StandardRegistryConfig},
|
||||
config::core::AwsEcrConfig,
|
||||
EnvironmentVar,
|
||||
};
|
||||
@@ -8,22 +8,29 @@ use run_command::async_run_command;
|
||||
|
||||
use crate::config::periphery_config;
|
||||
|
||||
pub fn get_github_token(
|
||||
github_account: &String,
|
||||
pub fn get_git_token(
|
||||
domain: &str,
|
||||
account_username: &str,
|
||||
) -> anyhow::Result<&'static String> {
|
||||
periphery_config()
|
||||
.github_accounts
|
||||
.get(github_account)
|
||||
.with_context(|| format!("did not find token in config for github account {github_account}"))
|
||||
.git_providers
|
||||
.iter()
|
||||
.find(|_provider| _provider.domain == domain)
|
||||
.and_then(|provider| provider.accounts
|
||||
.iter()
|
||||
.find(|account| account.username == account_username).map(|account| &account.token))
|
||||
.with_context(|| format!("did not find token in config for git account {account_username} | domain {domain}"))
|
||||
}
|
||||
|
||||
pub fn get_docker_token(
|
||||
docker_account: &String,
|
||||
domain: &str,
|
||||
account_username: &str,
|
||||
) -> anyhow::Result<&'static String> {
|
||||
periphery_config()
|
||||
.docker_accounts
|
||||
.get(docker_account)
|
||||
.with_context(|| format!("did not find token in config for docker account {docker_account}"))
|
||||
.docker_registries
|
||||
.iter().find(|registry| registry.domain == domain)
|
||||
.and_then(|registry| registry.accounts.iter().find(|account| account.username == account_username).map(|account| &account.token))
|
||||
.with_context(|| format!("did not find token in config for docker account {account_username} | domain {domain}"))
|
||||
}
|
||||
|
||||
pub fn parse_extra_args(extra_args: &[String]) -> String {
|
||||
@@ -52,76 +59,57 @@ pub async fn docker_login(
|
||||
// For local config override from core.
|
||||
aws_ecr: Option<&AwsEcrConfig>,
|
||||
) -> anyhow::Result<bool> {
|
||||
match registry {
|
||||
ImageRegistry::None(_) => Ok(false),
|
||||
ImageRegistry::DockerHub(CloudRegistryConfig {
|
||||
account, ..
|
||||
}) => {
|
||||
if account.is_empty() {
|
||||
return Err(anyhow!(
|
||||
"Must configure account for DockerHub registry"
|
||||
));
|
||||
}
|
||||
let registry_token = match registry_token {
|
||||
Some(token) => token,
|
||||
None => get_docker_token(account)?,
|
||||
};
|
||||
let log = async_run_command(&format!(
|
||||
"docker login -u {account} -p {registry_token}",
|
||||
))
|
||||
.await;
|
||||
if log.success() {
|
||||
Ok(true)
|
||||
} else {
|
||||
Err(anyhow!(
|
||||
"dockerhub login error: stdout: {} | stderr: {}",
|
||||
log.stdout,
|
||||
log.stderr
|
||||
))
|
||||
}
|
||||
}
|
||||
ImageRegistry::Ghcr(CloudRegistryConfig { account, .. }) => {
|
||||
if account.is_empty() {
|
||||
return Err(anyhow!(
|
||||
"Must configure account for GithubContainerRegistry"
|
||||
));
|
||||
}
|
||||
let registry_token = match registry_token {
|
||||
Some(token) => token,
|
||||
None => get_github_token(account)?,
|
||||
};
|
||||
let log = async_run_command(&format!(
|
||||
"docker login ghcr.io -u {account} -p {registry_token}",
|
||||
))
|
||||
.await;
|
||||
if log.success() {
|
||||
Ok(true)
|
||||
} else {
|
||||
Err(anyhow!(
|
||||
"ghcr login error: stdout: {} | stderr: {}",
|
||||
log.stdout,
|
||||
log.stderr
|
||||
))
|
||||
}
|
||||
}
|
||||
let (domain, account) = match registry {
|
||||
// Early return for no login
|
||||
ImageRegistry::None(_) => return Ok(false),
|
||||
// Early return because Ecr is different
|
||||
ImageRegistry::AwsEcr(label) => {
|
||||
let AwsEcrConfig { region, account_id } = aws_ecr
|
||||
.with_context(|| {
|
||||
format!("Could not find aws ecr config for label {label}")
|
||||
if label.is_empty() {
|
||||
String::from("Could not find aws ecr config")
|
||||
} else {
|
||||
format!("Could not find aws ecr config for label {label}")
|
||||
}
|
||||
})?;
|
||||
let registry_token = registry_token
|
||||
.context("aws ecr build missing registry token from core")?;
|
||||
let log = async_run_command(&format!("docker login {account_id}.dkr.ecr.{region}.amazonaws.com -u AWS -p {registry_token}")).await;
|
||||
let command = format!("docker login {account_id}.dkr.ecr.{region}.amazonaws.com -u AWS -p {registry_token}");
|
||||
let log = async_run_command(&command).await;
|
||||
if log.success() {
|
||||
Ok(true)
|
||||
return Ok(true);
|
||||
} else {
|
||||
Err(anyhow!(
|
||||
return Err(anyhow!(
|
||||
"aws ecr login error: stdout: {} | stderr: {}",
|
||||
log.stdout,
|
||||
log.stderr
|
||||
))
|
||||
));
|
||||
}
|
||||
}
|
||||
ImageRegistry::Custom(_) => todo!(),
|
||||
ImageRegistry::Standard(StandardRegistryConfig {
|
||||
domain,
|
||||
account,
|
||||
..
|
||||
}) => (domain.as_str(), account),
|
||||
};
|
||||
if account.is_empty() {
|
||||
return Err(anyhow!("Must configure account for registry domain {domain}, got empty string"));
|
||||
}
|
||||
let registry_token = match registry_token {
|
||||
Some(token) => token,
|
||||
None => get_docker_token(domain, account)?,
|
||||
};
|
||||
let log = async_run_command(&format!(
|
||||
"docker login {domain} -u {account} -p {registry_token}",
|
||||
))
|
||||
.await;
|
||||
if log.success() {
|
||||
Ok(true)
|
||||
} else {
|
||||
Err(anyhow!(
|
||||
"{domain} login error: stdout: {} | stderr: {}",
|
||||
log.stdout,
|
||||
log.stderr
|
||||
))
|
||||
}
|
||||
}
|
||||
|
||||
@@ -185,8 +185,8 @@ impl GetBuildMonthlyStatsResponse {
|
||||
Serialize, Deserialize, Debug, Clone, Default, Request, EmptyTraits,
|
||||
)]
|
||||
#[empty_traits(MonitorReadRequest)]
|
||||
#[response(GetBuildVersionsResponse)]
|
||||
pub struct GetBuildVersions {
|
||||
#[response(ListBuildVersionsResponse)]
|
||||
pub struct ListBuildVersions {
|
||||
/// Id or name
|
||||
#[serde(alias = "id", alias = "name")]
|
||||
pub build: String,
|
||||
@@ -201,7 +201,7 @@ pub struct GetBuildVersions {
|
||||
}
|
||||
|
||||
#[typeshare]
|
||||
pub type GetBuildVersionsResponse = Vec<BuildVersionResponseItem>;
|
||||
pub type ListBuildVersionsResponse = Vec<BuildVersionResponseItem>;
|
||||
|
||||
#[typeshare]
|
||||
#[derive(Serialize, Deserialize, Debug, Clone, Default)]
|
||||
@@ -212,36 +212,6 @@ pub struct BuildVersionResponseItem {
|
||||
|
||||
//
|
||||
|
||||
/// List the available github organizations which can be attached to builds.
|
||||
/// Response: [ListGithubOrganizationsResponse].
|
||||
#[typeshare]
|
||||
#[derive(
|
||||
Serialize, Deserialize, Debug, Clone, Default, Request, EmptyTraits,
|
||||
)]
|
||||
#[empty_traits(MonitorReadRequest)]
|
||||
#[response(ListGithubOrganizationsResponse)]
|
||||
pub struct ListGithubOrganizations {}
|
||||
|
||||
#[typeshare]
|
||||
pub type ListGithubOrganizationsResponse = Vec<String>;
|
||||
|
||||
//
|
||||
|
||||
/// List the available docker organizations which can be attached to builds.
|
||||
/// Response: [ListDockerOrganizationsResponse].
|
||||
#[typeshare]
|
||||
#[derive(
|
||||
Serialize, Deserialize, Debug, Clone, Default, Request, EmptyTraits,
|
||||
)]
|
||||
#[empty_traits(MonitorReadRequest)]
|
||||
#[response(ListDockerOrganizationsResponse)]
|
||||
pub struct ListDockerOrganizations {}
|
||||
|
||||
#[typeshare]
|
||||
pub type ListDockerOrganizationsResponse = Vec<String>;
|
||||
|
||||
//
|
||||
|
||||
/// Gets a list of existing values used as extra args across other builds.
|
||||
/// Useful to offer suggestions. Response: [ListCommonBuildExtraArgsResponse]
|
||||
#[typeshare]
|
||||
|
||||
@@ -80,29 +80,3 @@ pub struct GetBuildersSummaryResponse {
|
||||
/// The total number of builders.
|
||||
pub total: u32,
|
||||
}
|
||||
|
||||
//
|
||||
|
||||
/// Get the docker / github accounts which are available for use on the builder.
|
||||
/// Response: [GetBuilderAvailableAccountsResponse].
|
||||
///
|
||||
/// Note. Builds using this builder can only use the docker / github accounts available in this response.
|
||||
#[typeshare]
|
||||
#[derive(
|
||||
Serialize, Deserialize, Debug, Clone, Request, EmptyTraits,
|
||||
)]
|
||||
#[empty_traits(MonitorReadRequest)]
|
||||
#[response(GetBuilderAvailableAccountsResponse)]
|
||||
pub struct GetBuilderAvailableAccounts {
|
||||
/// Id or name
|
||||
#[serde(alias = "id", alias = "name")]
|
||||
pub builder: String,
|
||||
}
|
||||
|
||||
/// Response for [GetBuilderAvailableAccounts].
|
||||
#[typeshare]
|
||||
#[derive(Serialize, Deserialize, Debug, Clone)]
|
||||
pub struct GetBuilderAvailableAccountsResponse {
|
||||
pub github: Vec<String>,
|
||||
pub docker: Vec<String>,
|
||||
}
|
||||
|
||||
@@ -41,7 +41,11 @@ pub use user::*;
|
||||
pub use user_group::*;
|
||||
pub use variable::*;
|
||||
|
||||
use crate::entities::Timelength;
|
||||
use crate::entities::{
|
||||
config::{DockerRegistry, GitProvider},
|
||||
update::ResourceTarget,
|
||||
Timelength,
|
||||
};
|
||||
|
||||
pub trait MonitorReadRequest: HasResponse {}
|
||||
|
||||
@@ -67,7 +71,7 @@ pub struct GetVersionResponse {
|
||||
|
||||
//
|
||||
|
||||
/// Get info about the core api.
|
||||
/// Get info about the core api configuration.
|
||||
/// Response: [GetCoreInfoResponse].
|
||||
#[typeshare]
|
||||
#[derive(
|
||||
@@ -85,8 +89,8 @@ pub struct GetCoreInfoResponse {
|
||||
pub title: String,
|
||||
/// The monitoring interval of this core api.
|
||||
pub monitoring_interval: Timelength,
|
||||
/// The github webhook base url to use with github webhooks.
|
||||
pub github_webhook_base_url: String,
|
||||
/// The webhook base url.
|
||||
pub webhook_base_url: String,
|
||||
/// Whether transparent mode is enabled, which gives all users read access to all resources.
|
||||
pub transparent_mode: bool,
|
||||
/// Whether UI write access should be disabled
|
||||
@@ -97,15 +101,82 @@ pub struct GetCoreInfoResponse {
|
||||
|
||||
//
|
||||
|
||||
/// Get the available aws ecr config labels from the core config.
|
||||
/// Response: [GetAvailableAwsEcrLabelsResponse].
|
||||
/// List the git providers.
|
||||
/// Response: [ListGitProvidersResponse].
|
||||
///
|
||||
/// Includes:
|
||||
/// - providers in core config
|
||||
/// - providers configured on builds, repos, syncs
|
||||
/// - providers on the optional Server or Builder
|
||||
#[typeshare]
|
||||
#[derive(
|
||||
Serialize, Deserialize, Debug, Clone, Request, EmptyTraits,
|
||||
)]
|
||||
#[empty_traits(MonitorReadRequest)]
|
||||
#[response(GetAvailableAwsEcrLabelsResponse)]
|
||||
pub struct GetAvailableAwsEcrLabels {}
|
||||
#[response(ListGitProvidersResponse)]
|
||||
pub struct ListGitProviders {
|
||||
/// Accepts an optional Server or Builder target to expand the core list with
|
||||
/// providers available on that specific resource.
|
||||
pub target: Option<ResourceTarget>,
|
||||
}
|
||||
|
||||
#[typeshare]
|
||||
pub type GetAvailableAwsEcrLabelsResponse = Vec<String>;
|
||||
pub type ListGitProvidersResponse = Vec<GitProvider>;
|
||||
|
||||
//
|
||||
|
||||
/// List the suggested docker registry providers.
|
||||
/// Response: [ListDockerRegistriesResponse].
|
||||
///
|
||||
/// Includes:
|
||||
/// - registries in core config
|
||||
/// - registries configured on builds, deployments
|
||||
/// - registries on the optional Server or Builder
|
||||
#[typeshare]
|
||||
#[derive(
|
||||
Serialize, Deserialize, Debug, Clone, Request, EmptyTraits,
|
||||
)]
|
||||
#[empty_traits(MonitorReadRequest)]
|
||||
#[response(ListDockerRegistriesResponse)]
|
||||
pub struct ListDockerRegistries {
|
||||
/// Accepts an optional Server or Builder target to expand the core list with
|
||||
/// providers available on that specific resource.
|
||||
pub target: Option<ResourceTarget>,
|
||||
}
|
||||
|
||||
#[typeshare]
|
||||
pub type ListDockerRegistriesResponse = Vec<DockerRegistry>;
|
||||
|
||||
//
|
||||
|
||||
/// List the available aws ecr config labels from the core config.
|
||||
/// Response: [ListAwsEcrLabelsResponse].
|
||||
#[typeshare]
|
||||
#[derive(
|
||||
Serialize, Deserialize, Debug, Clone, Request, EmptyTraits,
|
||||
)]
|
||||
#[empty_traits(MonitorReadRequest)]
|
||||
#[response(ListAwsEcrLabelsResponse)]
|
||||
pub struct ListAwsEcrLabels {}
|
||||
|
||||
#[typeshare]
|
||||
pub type ListAwsEcrLabelsResponse = Vec<String>;
|
||||
|
||||
//
|
||||
|
||||
/// List the available secrets from the core config.
|
||||
/// Response: [ListSecretsResponse].
|
||||
#[typeshare]
|
||||
#[derive(
|
||||
Serialize, Deserialize, Debug, Clone, Request, EmptyTraits,
|
||||
)]
|
||||
#[empty_traits(MonitorReadRequest)]
|
||||
#[response(ListSecretsResponse)]
|
||||
pub struct ListSecrets {
|
||||
/// Accepts an optional Server or Builder target to expand the core list with
|
||||
/// providers available on that specific resource.
|
||||
pub target: Option<ResourceTarget>,
|
||||
}
|
||||
|
||||
#[typeshare]
|
||||
pub type ListSecretsResponse = Vec<String>;
|
||||
|
||||
@@ -316,51 +316,3 @@ pub struct GetServersSummaryResponse {
|
||||
/// The number of disabled servers.
|
||||
pub disabled: I64,
|
||||
}
|
||||
|
||||
//
|
||||
|
||||
/// Get the usernames for the available github / docker accounts
|
||||
/// on the target server, or only available globally if no server
|
||||
/// is provided.
|
||||
///
|
||||
/// Response: [GetAvailableAccountsResponse].
|
||||
#[typeshare]
|
||||
#[derive(
|
||||
Serialize, Deserialize, Debug, Clone, Request, EmptyTraits,
|
||||
)]
|
||||
#[empty_traits(MonitorReadRequest)]
|
||||
#[response(GetAvailableAccountsResponse)]
|
||||
pub struct GetAvailableAccounts {
|
||||
/// Id or name
|
||||
#[serde(alias = "id", alias = "name")]
|
||||
pub server: Option<String>,
|
||||
}
|
||||
|
||||
/// Response for [GetAvailableAccounts].
|
||||
#[typeshare]
|
||||
#[derive(Serialize, Deserialize, Debug, Clone)]
|
||||
pub struct GetAvailableAccountsResponse {
|
||||
/// The github usernames
|
||||
pub github: Vec<String>,
|
||||
/// The docker usernames.
|
||||
pub docker: Vec<String>,
|
||||
}
|
||||
|
||||
//
|
||||
|
||||
/// Get the keys for available secrets on the target server.
|
||||
/// Response: [GetAvailableSecretsResponse].
|
||||
#[typeshare]
|
||||
#[derive(
|
||||
Serialize, Deserialize, Debug, Clone, Request, EmptyTraits,
|
||||
)]
|
||||
#[empty_traits(MonitorReadRequest)]
|
||||
#[response(GetAvailableSecretsResponse)]
|
||||
pub struct GetAvailableSecrets {
|
||||
/// Id or name
|
||||
#[serde(alias = "id", alias = "name")]
|
||||
pub server: String,
|
||||
}
|
||||
|
||||
#[typeshare]
|
||||
pub type GetAvailableSecretsResponse = Vec<String>;
|
||||
|
||||
@@ -35,12 +35,5 @@ pub type GetVariableResponse = Variable;
|
||||
#[response(ListVariablesResponse)]
|
||||
pub struct ListVariables {}
|
||||
|
||||
/// The response of [ListVariables].
|
||||
#[typeshare]
|
||||
#[derive(Serialize, Deserialize, Debug, Clone)]
|
||||
pub struct ListVariablesResponse {
|
||||
/// The available global variables.
|
||||
pub variables: Vec<Variable>,
|
||||
/// The available global secret keys
|
||||
pub secrets: Vec<String>,
|
||||
}
|
||||
pub type ListVariablesResponse = Vec<Variable>;
|
||||
|
||||
@@ -26,7 +26,9 @@ pub struct BuildListItemInfo {
|
||||
pub last_built_at: I64,
|
||||
/// The current version of the build
|
||||
pub version: Version,
|
||||
/// The Github repo used as the source of the build
|
||||
/// The git provider domain
|
||||
pub git_provider: String,
|
||||
/// The repo used as the source of the build
|
||||
pub repo: String,
|
||||
/// The branch of the repo
|
||||
pub branch: String,
|
||||
@@ -76,7 +78,21 @@ pub struct BuildConfig {
|
||||
#[builder(default)]
|
||||
pub version: Version,
|
||||
|
||||
/// The Github repo used as the source of the build.
|
||||
/// The git provider domain. Default: github.com
|
||||
#[serde(default = "default_git_provider")]
|
||||
#[builder(default = "default_git_provider()")]
|
||||
#[partial_default(default_git_provider())]
|
||||
pub git_provider: String,
|
||||
|
||||
/// Whether to use https to clone the repo (versus http). Default: true
|
||||
///
|
||||
/// Note. Monitor does not currently support cloning repos via ssh.
|
||||
#[serde(default = "default_git_https")]
|
||||
#[builder(default = "default_git_https()")]
|
||||
#[partial_default(default_git_https())]
|
||||
pub git_https: bool,
|
||||
|
||||
/// The repo used as the source of the build.
|
||||
#[serde(default)]
|
||||
#[builder(default)]
|
||||
pub repo: String,
|
||||
@@ -92,11 +108,14 @@ pub struct BuildConfig {
|
||||
#[builder(default)]
|
||||
pub commit: String,
|
||||
|
||||
/// The github account used to clone (used to access private repos).
|
||||
/// Empty string is public clone (only public repos).
|
||||
#[serde(default)]
|
||||
/// The git account used to access private repos.
|
||||
/// Passing empty string can only clone public repos.
|
||||
///
|
||||
/// Note. A token for the account must be available in the core config or the builder server's periphery config
|
||||
/// for the configured git provider.
|
||||
#[serde(default, alias = "github_account")]
|
||||
#[builder(default)]
|
||||
pub github_account: String,
|
||||
pub git_account: String,
|
||||
|
||||
/// The optional command run after repo clone and before docker build.
|
||||
#[serde(default)]
|
||||
@@ -196,6 +215,14 @@ impl BuildConfig {
|
||||
}
|
||||
}
|
||||
|
||||
fn default_git_provider() -> String {
|
||||
String::from("github.com")
|
||||
}
|
||||
|
||||
fn default_git_https() -> bool {
|
||||
true
|
||||
}
|
||||
|
||||
fn default_branch() -> String {
|
||||
String::from("main")
|
||||
}
|
||||
@@ -218,10 +245,12 @@ impl Default for BuildConfig {
|
||||
builder_id: Default::default(),
|
||||
skip_secret_interp: Default::default(),
|
||||
version: Default::default(),
|
||||
git_provider: default_git_provider(),
|
||||
git_https: default_git_https(),
|
||||
repo: Default::default(),
|
||||
branch: default_branch(),
|
||||
commit: Default::default(),
|
||||
github_account: Default::default(),
|
||||
git_account: Default::default(),
|
||||
pre_build: Default::default(),
|
||||
build_path: default_build_path(),
|
||||
dockerfile_path: default_dockerfile_path(),
|
||||
@@ -243,19 +272,12 @@ impl Default for BuildConfig {
|
||||
pub enum ImageRegistry {
|
||||
/// Don't push the image to any registry
|
||||
None(NoData),
|
||||
/// Push the image to DockerHub
|
||||
DockerHub(CloudRegistryConfig),
|
||||
/// Push the image to the Github Container Registry.
|
||||
///
|
||||
/// See [the Github docs](https://docs.github.com/en/packages/working-with-a-github-packages-registry/working-with-the-container-registry#pushing-container-images)
|
||||
/// for information on creating an access token
|
||||
Ghcr(CloudRegistryConfig),
|
||||
/// Push the image to a standard image registry (any domain)
|
||||
Standard(StandardRegistryConfig),
|
||||
/// Push the image to Aws Elastic Container Registry
|
||||
///
|
||||
/// The string held in 'params' should match a label of an `aws_ecr_registry` in the core config.
|
||||
AwsEcr(String),
|
||||
/// Todo. Will point to a custom "Registry" resource by id
|
||||
Custom(String),
|
||||
}
|
||||
|
||||
impl Default for ImageRegistry {
|
||||
@@ -264,13 +286,17 @@ impl Default for ImageRegistry {
|
||||
}
|
||||
}
|
||||
|
||||
/// Configuration for a cloud image registry, like account and organization.
|
||||
/// Configuration for a standard image registry
|
||||
#[typeshare]
|
||||
#[derive(
|
||||
Debug, Clone, Default, PartialEq, Serialize, Deserialize,
|
||||
)]
|
||||
pub struct CloudRegistryConfig {
|
||||
/// Specify an account to use with the cloud registry.
|
||||
pub struct StandardRegistryConfig {
|
||||
/// Specify the registry provider domain. Default: `docker.io`
|
||||
#[serde(default = "default_registry_domain")]
|
||||
pub domain: String,
|
||||
|
||||
/// Specify an account to use with the registry.
|
||||
#[serde(default)]
|
||||
pub account: String,
|
||||
|
||||
@@ -280,6 +306,10 @@ pub struct CloudRegistryConfig {
|
||||
pub organization: String,
|
||||
}
|
||||
|
||||
fn default_registry_domain() -> String {
|
||||
String::from("docker.io")
|
||||
}
|
||||
|
||||
#[typeshare]
|
||||
#[derive(Debug, Clone, Copy, Default, Serialize, Deserialize)]
|
||||
pub struct BuildActionState {
|
||||
|
||||
@@ -6,6 +6,7 @@ use strum::{Display, EnumString};
|
||||
use typeshare::typeshare;
|
||||
|
||||
use super::{
|
||||
config::{DockerRegistry, GitProvider},
|
||||
resource::{AddFilters, Resource, ResourceListItem, ResourceQuery},
|
||||
MergePartial,
|
||||
};
|
||||
@@ -38,6 +39,7 @@ pub struct BuilderListItemInfo {
|
||||
EnumString
|
||||
)]
|
||||
#[serde(tag = "type", content = "params")]
|
||||
#[allow(clippy::large_enum_variant)]
|
||||
pub enum BuilderConfig {
|
||||
/// Use a connected server an image builder.
|
||||
Server(ServerBuilderConfig),
|
||||
@@ -65,6 +67,7 @@ impl Default for BuilderConfig {
|
||||
EnumString
|
||||
)]
|
||||
#[serde(tag = "type", content = "params")]
|
||||
#[allow(clippy::large_enum_variant)]
|
||||
pub enum PartialBuilderConfig {
|
||||
Server(_PartialServerBuilderConfig),
|
||||
Aws(_PartialAwsBuilderConfig),
|
||||
@@ -224,12 +227,13 @@ impl MergePartial for BuilderConfig {
|
||||
.use_public_ip
|
||||
.unwrap_or(config.use_public_ip),
|
||||
port: partial.port.unwrap_or(config.port),
|
||||
github_accounts: partial
|
||||
.github_accounts
|
||||
.unwrap_or(config.github_accounts),
|
||||
docker_accounts: partial
|
||||
.docker_accounts
|
||||
.unwrap_or(config.docker_accounts),
|
||||
git_providers: partial
|
||||
.git_providers
|
||||
.unwrap_or(config.git_providers),
|
||||
docker_registries: partial
|
||||
.docker_registries
|
||||
.unwrap_or(config.docker_registries),
|
||||
secrets: partial.secrets.unwrap_or(config.secrets),
|
||||
};
|
||||
BuilderConfig::Aws(config)
|
||||
}
|
||||
@@ -308,12 +312,15 @@ pub struct AwsBuilderConfig {
|
||||
/// This should include a security group to allow core inbound access to the periphery port.
|
||||
pub security_group_ids: Vec<String>,
|
||||
|
||||
/// Which github accounts (usernames) are available on the AMI
|
||||
/// Which git providers are available on the AMI
|
||||
#[serde(default)]
|
||||
pub github_accounts: Vec<String>,
|
||||
/// Which dockerhub accounts (usernames) are available on the AMI
|
||||
pub git_providers: Vec<GitProvider>,
|
||||
/// Which docker registries are available on the AMI.
|
||||
#[serde(default)]
|
||||
pub docker_accounts: Vec<String>,
|
||||
pub docker_registries: Vec<DockerRegistry>,
|
||||
/// Which secrets are available on the AMI.
|
||||
#[serde(default)]
|
||||
pub secrets: Vec<String>,
|
||||
}
|
||||
|
||||
impl Default for AwsBuilderConfig {
|
||||
@@ -329,8 +336,9 @@ impl Default for AwsBuilderConfig {
|
||||
key_pair_name: Default::default(),
|
||||
assign_public_ip: false,
|
||||
use_public_ip: false,
|
||||
github_accounts: Default::default(),
|
||||
docker_accounts: Default::default(),
|
||||
git_providers: Default::default(),
|
||||
docker_registries: Default::default(),
|
||||
secrets: Default::default(),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -18,6 +18,8 @@ use crate::entities::{
|
||||
Timelength,
|
||||
};
|
||||
|
||||
use super::{DockerRegistry, GitProvider};
|
||||
|
||||
/// # Monitor Core Environment Variables
|
||||
///
|
||||
/// You can override any fields of the [CoreConfig] by passing the associated
|
||||
@@ -53,14 +55,10 @@ pub struct Env {
|
||||
pub monitor_keep_stats_for_days: Option<u64>,
|
||||
/// Override `keep_alerts_for_days`
|
||||
pub monitor_keep_alerts_for_days: Option<u64>,
|
||||
/// Override `github_webhook_secret`
|
||||
pub monitor_github_webhook_secret: Option<String>,
|
||||
/// Override `github_webhook_base_url`
|
||||
pub monitor_github_webhook_base_url: Option<String>,
|
||||
/// Override `github_organizations`
|
||||
pub monitor_github_organizations: Option<Vec<String>>,
|
||||
/// Override `docker_organizations`
|
||||
pub monitor_docker_organizations: Option<Vec<String>>,
|
||||
/// Override `webhook_secret`
|
||||
pub monitor_webhook_secret: Option<String>,
|
||||
/// Override `webhook_base_url`
|
||||
pub monitor_webhook_base_url: Option<String>,
|
||||
|
||||
/// Override `logging.level`
|
||||
pub monitor_logging_level: Option<LogLevel>,
|
||||
@@ -150,55 +148,59 @@ fn default_config_path() -> String {
|
||||
/// ## default: 'Monitor'
|
||||
/// title = "Monitor"
|
||||
///
|
||||
/// ## required for oauth functionality. this should be the url used to access monitor in browser,
|
||||
/// ## Required for oauth functionality. This should be the url used to access monitor in browser,
|
||||
/// ## potentially behind DNS.
|
||||
/// ## eg https://monitor.dev or http://12.34.56.78:9000.
|
||||
/// ## this should match the address configured in your oauth app.
|
||||
/// ## no default
|
||||
/// ## Eg https://monitor.dev or http://12.34.56.78:9000.
|
||||
/// ## This should match the address configured in your oauth app.
|
||||
/// ## Required (no default).
|
||||
/// host = "https://monitor.dev"
|
||||
///
|
||||
/// ## the port the core system will run on. if running core in docker container,
|
||||
/// ## leave as this port as 9000 and use port bind eg. -p 9001:9000
|
||||
/// ## default: 9000
|
||||
/// ## The port the core system will run on. If running core in docker container,
|
||||
/// ## Leave as this port as 9000 and use port bind eg. -p 9001:9000
|
||||
/// ## Default: 9000
|
||||
/// port = 9000
|
||||
///
|
||||
/// ## required to match a passkey in periphery config.
|
||||
/// ## token used to authenticate core requests to periphery
|
||||
/// ## no default
|
||||
/// ## Must match a passkey in periphery config to communicate with periphery.
|
||||
/// ## Required (No default)
|
||||
/// passkey = "a_random_passkey"
|
||||
///
|
||||
/// ## specify the log level of the monitor core application
|
||||
/// ## default: info
|
||||
/// ## options: off, error, warn, info, debug, trace
|
||||
/// ## Specify the log level of the monitor core application.
|
||||
/// ## Default: `info`.
|
||||
/// ## Options: `off`, `error`, `warn`, `info`, `debug`, `trace`.
|
||||
/// logging.level = "info"
|
||||
///
|
||||
/// ## specify the logging format for stdout / stderr.
|
||||
/// ## default: standard
|
||||
/// ## options: standard, json, none
|
||||
/// ## Specify the logging format for stdout / stderr.
|
||||
/// ## Default: standard
|
||||
/// ## Options: `standard`, `json`, `none`
|
||||
/// logging.stdio = "standard"
|
||||
///
|
||||
/// ## specify a opentelemetry otlp endpoint to send traces to
|
||||
/// ## optional, default unassigned
|
||||
/// ## Specify a opentelemetry otlp endpoint to send traces to.
|
||||
/// ## Optional, default unassigned (don't export telemetry).
|
||||
/// # logging.otlp_endpoint = "http://localhost:4317"
|
||||
///
|
||||
/// ## specify how long an issued jwt stays valid.
|
||||
/// ## all jwts are invalidated on application restart.
|
||||
/// ## default: 1-day.
|
||||
/// ## options: 1-hr, 12-hr, 1-day, 3-day, 1-wk, 2-wk, 30-day
|
||||
/// ## Specify how long an issued jwt stays valid.
|
||||
/// ## All jwts are invalidated on application restart.
|
||||
/// ## Default: `1-day`.
|
||||
/// ## Options: `1-hr`, `12-hr`, `1-day`, `3-day`, `1-wk`, `2-wk`, `30-day`.
|
||||
/// jwt_valid_for = "1-day"
|
||||
///
|
||||
/// ## controls the granularity of the system stats collection by monitor core
|
||||
/// ## default: 15-sec
|
||||
/// ## options: 5-sec, 15-sec, 30-sec, 1-min, 2-min, 5-min, 15-min
|
||||
/// ## Controls the granularity of the system stats collection by monitor core.
|
||||
/// ## Options: `5-sec`, `15-sec`, `30-sec`, `1-min`, `2-min`, `5-min`.
|
||||
/// ## Default: `15-sec`.
|
||||
/// monitoring_interval = "15-sec"
|
||||
///
|
||||
/// ## number of days to keep stats around, or 0 to disable pruning.
|
||||
/// ## stats older than this number of days are deleted daily
|
||||
/// ## default: 0 (pruning disabled)
|
||||
/// keep_stats_for_days = 0
|
||||
/// ## Number of days to store stats, or 0 to disable stats pruning.
|
||||
/// ## Stats older than this number of days are deleted daily
|
||||
/// ## Default: 0 (pruning disabled)
|
||||
/// keep_stats_for_days = 14
|
||||
///
|
||||
/// ## these will be used by the GUI to attach to builds.
|
||||
/// ## when attached to build, image will be pushed to repo under the specified organization.
|
||||
/// ## Number of days to store alerts, or 0 to disable alert pruning.
|
||||
/// ## Alerts older than this number of days are deleted daily
|
||||
/// ## Default: 0 (pruning disabled)
|
||||
/// keep_alerts_for_days = 14
|
||||
///
|
||||
/// ## These will be available .
|
||||
/// ## When attached to build, image will be pushed to repo under the specified organization.
|
||||
/// ## if empty, the "docker organization" config option will not be shown.
|
||||
/// ## default: empty
|
||||
/// # docker_organizations = ["your_docker_org1", "your_docker_org_2"]
|
||||
@@ -269,16 +271,21 @@ fn default_config_path() -> String {
|
||||
/// [secrets]
|
||||
/// # SECRET_1 = "value_1"
|
||||
/// # SECRET_2 = "value_2"
|
||||
///
|
||||
/// ## provide core-based github accounts
|
||||
/// [github_accounts]
|
||||
/// # github_username_1 = "github_token_1"
|
||||
/// # github_username_2 = "github_token_2"
|
||||
///
|
||||
/// ## provide core-based docker accounts
|
||||
/// [docker_accounts]
|
||||
/// # docker_username_1 = "docker_token_1"
|
||||
/// # docker_username_2 = "docker_token_2"
|
||||
///
|
||||
/// ## configure git providers
|
||||
/// # [[git_provider]]
|
||||
/// # domain = "git.mogh.tech" # use a custom provider, like self-hosted gitea
|
||||
/// # accounts = [
|
||||
/// # { username = "mbecker20", token = "access_token_for_account" },
|
||||
/// # ]
|
||||
///
|
||||
/// ## configure docker registries
|
||||
/// # [[docker_registry]]
|
||||
/// # domain = "docker.io"
|
||||
/// # accounts = [
|
||||
/// # { username = "mbecker2020", token = "access_token_for_account" }
|
||||
/// # ]
|
||||
/// # organizations = ["DockerhubOrganization"]
|
||||
///
|
||||
/// ## configure aws ecr registries
|
||||
/// # [aws_ecr_registry.label_1]
|
||||
@@ -341,11 +348,6 @@ pub struct CoreConfig {
|
||||
#[serde(default)]
|
||||
pub keep_alerts_for_days: u64,
|
||||
|
||||
/// Allowed docker orgs used with monitor.
|
||||
/// Default: none.
|
||||
#[serde(default)]
|
||||
pub docker_organizations: Vec<String>,
|
||||
|
||||
/// Configure logging
|
||||
#[serde(default)]
|
||||
pub logging: LogConfig,
|
||||
@@ -370,30 +372,25 @@ pub struct CoreConfig {
|
||||
#[serde(default)]
|
||||
pub github_oauth: OauthCredentials,
|
||||
|
||||
/// Used to verify validity from github webhooks.
|
||||
/// Used to verify validity from webhooks.
|
||||
/// Should be some secure hash maybe 20-40 chars.
|
||||
/// It needs to be given to github when configuring the webhook.
|
||||
/// It is given to git provider when configuring the webhook.
|
||||
#[serde(default)]
|
||||
pub github_webhook_secret: String,
|
||||
pub webhook_secret: String,
|
||||
|
||||
/// Used to form the frontend listener url, if None will use 'host'.
|
||||
/// Override the webhook listener base url, if None will use the address defined as 'host'.
|
||||
/// Example: `https://webhooks.mogh.tech`
|
||||
///
|
||||
/// This can be used if core sits on an internal network which is
|
||||
/// unreachable directly from the open internet.
|
||||
/// A reverse proxy in a public network (with its own DNS)
|
||||
/// can forward webhooks to the internal monitor
|
||||
pub github_webhook_base_url: Option<String>,
|
||||
/// A reverse proxy in a public network can forward webhooks to the internal monitor.
|
||||
pub webhook_base_url: Option<String>,
|
||||
|
||||
/// Configure a Github Webhook app.
|
||||
/// Allows users to manage repo webhooks from within the Monitor UI.
|
||||
#[serde(default)]
|
||||
pub github_webhook_app: GithubWebhookAppConfig,
|
||||
|
||||
/// Allowed github orgs used with monitor.
|
||||
/// Default: none.
|
||||
#[serde(default)]
|
||||
pub github_organizations: Vec<String>,
|
||||
|
||||
/// Configure core mongo connection.
|
||||
///
|
||||
/// An easy deployment method is to use Mongo Atlas to provide
|
||||
@@ -414,22 +411,19 @@ pub struct CoreConfig {
|
||||
#[serde(default)]
|
||||
pub secrets: HashMap<String, String>,
|
||||
|
||||
/// Configure core-based github accounts. These will be preferentially attached to build / repo clone
|
||||
/// requests if they contain a matching github account. Otherwise, the periphery will have to have the
|
||||
/// account configured.
|
||||
#[serde(default)]
|
||||
pub github_accounts: HashMap<String, String>,
|
||||
/// Configure git credentials used to clone private repos.
|
||||
/// Supports any git provider.
|
||||
#[serde(default, alias = "git_provider")]
|
||||
pub git_providers: Vec<GitProvider>,
|
||||
|
||||
/// Configure core-based docker accounts. These will be preferentially attached to build / deploy
|
||||
/// requests if they contain a matching docker account. Otherwise, the periphery will have to have the
|
||||
/// account configured.
|
||||
#[serde(default)]
|
||||
pub docker_accounts: HashMap<String, String>,
|
||||
/// Configure docker credentials used to push / pull images.
|
||||
/// Supports any docker image repository.
|
||||
#[serde(default, alias = "docker_registry")]
|
||||
pub docker_registries: Vec<DockerRegistry>,
|
||||
|
||||
/// Configure aws ecr registries.
|
||||
/// Configure aws ecr registries, which are handled differently than other registries
|
||||
#[serde(default, alias = "aws_ecr_registry")]
|
||||
pub aws_ecr_registries:
|
||||
HashMap<String, AwsEcrConfigWithCredentials>,
|
||||
pub aws_ecr_registries: Vec<AwsEcrConfigWithCredentials>,
|
||||
}
|
||||
|
||||
fn default_title() -> String {
|
||||
@@ -458,8 +452,7 @@ impl CoreConfig {
|
||||
let mut config = self.clone();
|
||||
|
||||
config.passkey = empty_or_redacted(&config.passkey);
|
||||
config.github_webhook_secret =
|
||||
empty_or_redacted(&config.github_webhook_secret);
|
||||
config.webhook_secret = empty_or_redacted(&config.webhook_secret);
|
||||
|
||||
config.github_oauth.id =
|
||||
empty_or_redacted(&config.github_oauth.id);
|
||||
@@ -571,6 +564,8 @@ pub struct HetznerCredentials {
|
||||
/// Provide configuration for an Aws Ecr registry.
|
||||
#[derive(Debug, Clone, Default, Serialize, Deserialize)]
|
||||
pub struct AwsEcrConfigWithCredentials {
|
||||
/// A label for the registry
|
||||
pub label: String,
|
||||
/// The Aws region
|
||||
pub region: String,
|
||||
/// The Aws account id
|
||||
|
||||
@@ -1,2 +1,87 @@
|
||||
use serde::{Deserialize, Serialize};
|
||||
use typeshare::typeshare;
|
||||
|
||||
pub mod core;
|
||||
pub mod periphery;
|
||||
|
||||
#[typeshare]
|
||||
#[derive(
|
||||
Debug,
|
||||
Clone,
|
||||
PartialEq,
|
||||
Eq,
|
||||
Hash,
|
||||
PartialOrd,
|
||||
Ord,
|
||||
Serialize,
|
||||
Deserialize,
|
||||
)]
|
||||
pub struct GitProvider {
|
||||
/// The git provider domain. Default: `github.com`.
|
||||
#[serde(default = "default_git_provider")]
|
||||
pub domain: String,
|
||||
/// Whether to use https. Default: true.
|
||||
#[serde(default = "default_git_https")]
|
||||
pub https: bool,
|
||||
/// The account username. Required.
|
||||
#[serde(alias = "account")]
|
||||
pub accounts: Vec<ProviderAccount>,
|
||||
}
|
||||
|
||||
fn default_git_provider() -> String {
|
||||
String::from("github.com")
|
||||
}
|
||||
|
||||
fn default_git_https() -> bool {
|
||||
true
|
||||
}
|
||||
|
||||
#[typeshare]
|
||||
#[derive(
|
||||
Debug,
|
||||
Clone,
|
||||
PartialEq,
|
||||
Eq,
|
||||
Hash,
|
||||
PartialOrd,
|
||||
Ord,
|
||||
Serialize,
|
||||
Deserialize,
|
||||
)]
|
||||
pub struct DockerRegistry {
|
||||
/// The docker provider domain. Default: `docker.io`.
|
||||
#[serde(default = "default_docker_provider")]
|
||||
pub domain: String,
|
||||
/// The account username. Required.
|
||||
#[serde(default, alias = "account")]
|
||||
pub accounts: Vec<ProviderAccount>,
|
||||
/// Available organizations on the registry provider.
|
||||
/// Used to push an image under an organization's repo rather than an account's repo.
|
||||
#[serde(default, alias = "organization")]
|
||||
pub organizations: Vec<String>,
|
||||
}
|
||||
|
||||
fn default_docker_provider() -> String {
|
||||
String::from("docker.io")
|
||||
}
|
||||
|
||||
#[typeshare]
|
||||
#[derive(
|
||||
Debug,
|
||||
Clone,
|
||||
PartialEq,
|
||||
Eq,
|
||||
Hash,
|
||||
PartialOrd,
|
||||
Ord,
|
||||
Serialize,
|
||||
Deserialize,
|
||||
)]
|
||||
pub struct ProviderAccount {
|
||||
/// The account username. Required.
|
||||
#[serde(alias = "account")]
|
||||
pub username: String,
|
||||
/// The account access token. Required.
|
||||
#[serde(skip_serializing)]
|
||||
pub token: String,
|
||||
}
|
||||
|
||||
@@ -22,6 +22,8 @@ use crate::entities::{
|
||||
Timelength,
|
||||
};
|
||||
|
||||
use super::{DockerRegistry, GitProvider};
|
||||
|
||||
/// # Periphery Command Line Arguments.
|
||||
///
|
||||
/// This structure represents the periphery command line arguments used to
|
||||
@@ -178,21 +180,27 @@ fn default_config_paths() -> Vec<String> {
|
||||
/// ## optional, default 'Monitor'.
|
||||
/// # logging.opentelemetry_service_name = "Monitor"
|
||||
///
|
||||
/// ## optional. can inject these values into your deployments configuration.
|
||||
/// ## configure perihery-based secrets
|
||||
/// [secrets]
|
||||
/// secret_variable = "secret_value"
|
||||
/// # SECRET_1 = "value_1"
|
||||
/// # SECRET_2 = "value_2"
|
||||
///
|
||||
/// ## optional. can use these accounts with deployments / builds.
|
||||
/// [github_accounts]
|
||||
/// github_username1 = "github_token1"
|
||||
/// github_username2 = "github_token2"
|
||||
///
|
||||
/// ## optional. can use these accounts with deployments / builds.
|
||||
/// [docker_accounts]
|
||||
/// docker_username1 = "docker_token1"
|
||||
/// docker_username2 = "docker_token2"
|
||||
/// ## configure periphery-based git providers
|
||||
/// # [[git_provider]]
|
||||
/// # domain = "git.mogh.tech" # use a custom provider, like self-hosted gitea
|
||||
/// # accounts = [
|
||||
/// # { username = "mbecker20", token = "access_token_for_account" },
|
||||
/// # ]
|
||||
///
|
||||
/// ## configure periphery-based docker registries
|
||||
/// # [[docker_registry]]
|
||||
/// # domain = "docker.io"
|
||||
/// # accounts = [
|
||||
/// # { username = "mbecker2020", token = "access_token_for_account" }
|
||||
/// # ]
|
||||
/// # organizations = ["DockerhubOrganization"]
|
||||
/// ```
|
||||
#[derive(Deserialize, Debug, Clone)]
|
||||
#[derive(Debug, Clone, Deserialize)]
|
||||
pub struct PeripheryConfig {
|
||||
/// The port periphery will run on.
|
||||
/// Default: `8120`
|
||||
@@ -232,15 +240,15 @@ pub struct PeripheryConfig {
|
||||
#[serde(default)]
|
||||
pub secrets: HashMap<String, String>,
|
||||
|
||||
/// Mapping of github usernames to access tokens.
|
||||
/// Default: none
|
||||
#[serde(default)]
|
||||
pub github_accounts: HashMap<String, String>,
|
||||
/// Configure git credentials used to clone private repos.
|
||||
/// Supports any git provider.
|
||||
#[serde(default, alias = "git_provider")]
|
||||
pub git_providers: Vec<GitProvider>,
|
||||
|
||||
/// Mapping of docker usernames to access tokens.
|
||||
/// Default: none
|
||||
#[serde(default)]
|
||||
pub docker_accounts: HashMap<String, String>,
|
||||
/// Configure docker credentials used to push / pull images.
|
||||
/// Supports any docker image repository.
|
||||
#[serde(default, alias = "docker_registry")]
|
||||
pub docker_registries: Vec<DockerRegistry>,
|
||||
}
|
||||
|
||||
fn default_periphery_port() -> u16 {
|
||||
|
||||
@@ -14,7 +14,6 @@ use strum::{Display, EnumString};
|
||||
use typeshare::typeshare;
|
||||
|
||||
use super::{
|
||||
build::ImageRegistry,
|
||||
resource::{Resource, ResourceListItem, ResourceQuery},
|
||||
EnvironmentVar, Version,
|
||||
};
|
||||
@@ -61,16 +60,15 @@ pub struct DeploymentConfig {
|
||||
#[builder(default)]
|
||||
pub image: DeploymentImage,
|
||||
|
||||
/// Configure the registry used to pull the image from the registry.
|
||||
/// Configure the account used to pull the image from the registry.
|
||||
/// Used with `docker login`.
|
||||
///
|
||||
/// When using attached build as image source:
|
||||
/// - If the field is `None` variant, will use the same ImageRegistry config as the build.
|
||||
/// - Otherwise, it must match the variant of the ImageRegistry build config.
|
||||
/// - Only the account is used, the organization is not needed here
|
||||
/// - If the field is empty string, will use the same account config as the build, or none at all if using image.
|
||||
/// - If the field contains an account, a token for the account must be available.
|
||||
/// - Will get the registry domain from the build / image
|
||||
#[serde(default)]
|
||||
#[builder(default)]
|
||||
pub image_registry: ImageRegistry,
|
||||
pub image_registry_account: String,
|
||||
|
||||
/// Whether to skip secret interpolation into the deployment environment variables.
|
||||
#[serde(default)]
|
||||
@@ -213,7 +211,7 @@ impl Default for DeploymentConfig {
|
||||
server_id: Default::default(),
|
||||
send_alerts: default_send_alerts(),
|
||||
image: Default::default(),
|
||||
image_registry: Default::default(),
|
||||
image_registry_account: Default::default(),
|
||||
skip_secret_interp: Default::default(),
|
||||
redeploy_on_build: Default::default(),
|
||||
term_signal_labels: default_term_signal_labels(),
|
||||
@@ -779,3 +777,16 @@ impl super::resource::AddFilters for DeploymentQuerySpecifics {
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
pub fn extract_registry_domain(
|
||||
image_name: &str,
|
||||
) -> anyhow::Result<String> {
|
||||
let mut split = image_name.split('/');
|
||||
let maybe_domain =
|
||||
split.next().context("image name cannot be empty string")?;
|
||||
if maybe_domain.contains('.') {
|
||||
Ok(maybe_domain.to_string())
|
||||
} else {
|
||||
Ok(String::from("docker.io"))
|
||||
}
|
||||
}
|
||||
|
||||
@@ -2,7 +2,7 @@ use std::str::FromStr;
|
||||
|
||||
use anyhow::Context;
|
||||
use async_timing_util::unix_timestamp_ms;
|
||||
use build::CloudRegistryConfig;
|
||||
use build::StandardRegistryConfig;
|
||||
use clap::Parser;
|
||||
use config::core::AwsEcrConfig;
|
||||
use derive_empty_traits::EmptyTraits;
|
||||
@@ -117,32 +117,7 @@ pub fn get_image_name(
|
||||
) -> anyhow::Result<String> {
|
||||
let name = to_monitor_name(name);
|
||||
let name = match image_registry {
|
||||
// TODO
|
||||
build::ImageRegistry::None(_) => name,
|
||||
build::ImageRegistry::DockerHub(CloudRegistryConfig {
|
||||
organization,
|
||||
account,
|
||||
}) => {
|
||||
if !organization.is_empty() {
|
||||
format!("{organization}/{name}")
|
||||
} else if !account.is_empty() {
|
||||
format!("{account}/{name}")
|
||||
} else {
|
||||
name
|
||||
}
|
||||
}
|
||||
build::ImageRegistry::Ghcr(CloudRegistryConfig {
|
||||
organization,
|
||||
account,
|
||||
}) => {
|
||||
if !organization.is_empty() {
|
||||
format!("ghcr.io/{organization}/{name}")
|
||||
} else if !account.is_empty() {
|
||||
format!("ghcr.io/{account}/{name}")
|
||||
} else {
|
||||
name
|
||||
}
|
||||
}
|
||||
build::ImageRegistry::AwsEcr(label) => {
|
||||
let AwsEcrConfig {
|
||||
region, account_id, ..
|
||||
@@ -151,16 +126,26 @@ pub fn get_image_name(
|
||||
})?;
|
||||
format!("{account_id}.dkr.ecr.{region}.amazonaws.com/{name}")
|
||||
}
|
||||
build::ImageRegistry::Custom(_) => {
|
||||
// TODO
|
||||
name
|
||||
build::ImageRegistry::Standard(StandardRegistryConfig {
|
||||
domain,
|
||||
account,
|
||||
organization,
|
||||
}) => {
|
||||
if !organization.is_empty() {
|
||||
let org = organization.to_lowercase();
|
||||
format!("{domain}/{org}/{name}")
|
||||
} else if !account.is_empty() {
|
||||
format!("{domain}/{account}/{name}")
|
||||
} else {
|
||||
name
|
||||
}
|
||||
}
|
||||
};
|
||||
Ok(name)
|
||||
}
|
||||
|
||||
pub fn to_monitor_name(name: &str) -> String {
|
||||
name.to_lowercase().replace(' ', "_")
|
||||
name.to_lowercase().replace([' ', '.'], "_")
|
||||
}
|
||||
|
||||
pub fn monitor_timestamp() -> i64 {
|
||||
@@ -494,6 +479,7 @@ impl<'de> Visitor<'de> for OptionEnvVarVisitor {
|
||||
}
|
||||
}
|
||||
|
||||
#[typeshare]
|
||||
#[derive(Debug, Clone, Serialize, Deserialize)]
|
||||
pub struct LatestCommit {
|
||||
pub hash: String,
|
||||
@@ -503,14 +489,26 @@ pub struct LatestCommit {
|
||||
#[typeshare]
|
||||
#[derive(Serialize, Deserialize, Clone, Debug, PartialEq, Eq)]
|
||||
pub struct CloneArgs {
|
||||
/// Resource name (eg Build name, Repo name)
|
||||
pub name: String,
|
||||
/// Git provider domain. Default: `github.com`
|
||||
pub provider: Option<String>,
|
||||
/// Use https (vs http).
|
||||
pub https: bool,
|
||||
/// Full repo identifier. <namespace>/<repo_name>
|
||||
pub repo: Option<String>,
|
||||
/// Git Branch. Default: `main`
|
||||
pub branch: Option<String>,
|
||||
/// Specific commit hash. Optional
|
||||
pub commit: Option<String>,
|
||||
/// The clone destination path
|
||||
pub destination: Option<String>,
|
||||
/// Command to run after the repo has been cloned
|
||||
pub on_clone: Option<SystemCommand>,
|
||||
/// Command to run after the repo has been pulled
|
||||
pub on_pull: Option<SystemCommand>,
|
||||
pub github_account: Option<String>,
|
||||
/// Configure the account used to access repo (if private)
|
||||
pub account: Option<String>,
|
||||
}
|
||||
|
||||
impl From<&self::build::Build> for CloneArgs {
|
||||
@@ -523,7 +521,9 @@ impl From<&self::build::Build> for CloneArgs {
|
||||
destination: None,
|
||||
on_clone: build.config.pre_build.clone().into_option(),
|
||||
on_pull: None,
|
||||
github_account: optional_string(&build.config.github_account),
|
||||
provider: optional_string(&build.config.git_provider),
|
||||
https: build.config.git_https,
|
||||
account: optional_string(&build.config.git_account),
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -538,7 +538,9 @@ impl From<&self::repo::Repo> for CloneArgs {
|
||||
destination: optional_string(&repo.config.path),
|
||||
on_clone: repo.config.on_clone.clone().into_option(),
|
||||
on_pull: repo.config.on_pull.clone().into_option(),
|
||||
github_account: optional_string(&repo.config.github_account),
|
||||
provider: optional_string(&repo.config.git_provider),
|
||||
https: repo.config.git_https,
|
||||
account: optional_string(&repo.config.git_account),
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -550,10 +552,12 @@ impl From<&self::sync::ResourceSync> for CloneArgs {
|
||||
repo: optional_string(&sync.config.repo),
|
||||
branch: optional_string(&sync.config.branch),
|
||||
commit: optional_string(&sync.config.commit),
|
||||
github_account: optional_string(&sync.config.github_account),
|
||||
destination: None,
|
||||
on_clone: None,
|
||||
on_pull: None,
|
||||
provider: Some(String::from("github.com")),
|
||||
https: sync.config.git_https,
|
||||
account: optional_string(&sync.config.git_account),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -23,7 +23,9 @@ pub struct RepoListItemInfo {
|
||||
pub server_id: String,
|
||||
/// Repo last cloned / pulled timestamp in ms.
|
||||
pub last_pulled_at: I64,
|
||||
/// The configured github repo
|
||||
/// The git provider domain
|
||||
pub git_provider: String,
|
||||
/// The configured repo
|
||||
pub repo: String,
|
||||
/// The configured branch
|
||||
pub branch: String,
|
||||
@@ -77,6 +79,12 @@ pub struct RepoConfig {
|
||||
#[builder(default)]
|
||||
pub server_id: String,
|
||||
|
||||
/// The git provider domain. Default: github.com
|
||||
#[serde(default = "default_git_provider")]
|
||||
#[builder(default = "default_git_provider()")]
|
||||
#[partial_default(default_git_provider())]
|
||||
pub git_provider: String,
|
||||
|
||||
/// The github repo to clone.
|
||||
#[serde(default)]
|
||||
#[builder(default)]
|
||||
@@ -93,11 +101,22 @@ pub struct RepoConfig {
|
||||
#[builder(default)]
|
||||
pub commit: String,
|
||||
|
||||
/// The github account to use to clone.
|
||||
/// It must be available in the server's periphery config.
|
||||
#[serde(default)]
|
||||
/// The git account used to access private repos.
|
||||
/// Passing empty string can only clone public repos.
|
||||
///
|
||||
/// Note. A token for the account must be available in the core config or the builder server's periphery config
|
||||
/// for the configured git provider.
|
||||
#[serde(default, alias = "github_account")]
|
||||
#[builder(default)]
|
||||
pub github_account: String,
|
||||
pub git_account: String,
|
||||
|
||||
/// Whether to use https to clone the repo (versus http). Default: true
|
||||
///
|
||||
/// Note. Monitor does not currently support cloning repos via ssh.
|
||||
#[serde(default = "default_git_https")]
|
||||
#[builder(default = "default_git_https()")]
|
||||
#[partial_default(default_git_https())]
|
||||
pub git_https: bool,
|
||||
|
||||
/// Explicitly specificy the folder to clone the repo in.
|
||||
#[serde(default)]
|
||||
@@ -129,6 +148,14 @@ impl RepoConfig {
|
||||
}
|
||||
}
|
||||
|
||||
fn default_git_provider() -> String {
|
||||
String::from("github.com")
|
||||
}
|
||||
|
||||
fn default_git_https() -> bool {
|
||||
true
|
||||
}
|
||||
|
||||
fn default_branch() -> String {
|
||||
String::from("main")
|
||||
}
|
||||
@@ -141,10 +168,12 @@ impl Default for RepoConfig {
|
||||
fn default() -> Self {
|
||||
Self {
|
||||
server_id: Default::default(),
|
||||
git_provider: default_git_provider(),
|
||||
git_https: default_git_https(),
|
||||
repo: Default::default(),
|
||||
branch: default_branch(),
|
||||
commit: Default::default(),
|
||||
github_account: Default::default(),
|
||||
git_account: Default::default(),
|
||||
path: Default::default(),
|
||||
on_clone: Default::default(),
|
||||
on_pull: Default::default(),
|
||||
|
||||
@@ -152,27 +152,47 @@ pub enum HetznerVolumeFormat {
|
||||
)]
|
||||
#[allow(clippy::enum_variant_names)]
|
||||
pub enum HetznerServerType {
|
||||
SharedIntel1Core2Ram20Disk,
|
||||
// The lowest tier available at all locations
|
||||
// Shared
|
||||
#[default]
|
||||
/// CPX11 - AMD 2 Cores, 2 Gb Ram, 40 Gb disk
|
||||
SharedAmd2Core2Ram40Disk,
|
||||
/// CAX11 - Arm 2 Cores, 4 Gb Ram, 40 Gb disk
|
||||
SharedArm2Core4Ram40Disk,
|
||||
/// CX22 - Intel 2 Cores, 4 Gb Ram, 40 Gb disk
|
||||
SharedIntel2Core4Ram40Disk,
|
||||
/// CPX21 - AMD 3 Cores, 4 Gb Ram, 80 Gb disk
|
||||
SharedAmd3Core4Ram80Disk,
|
||||
/// CAX21 - Arm 4 Cores, 8 Gb Ram, 80 Gb disk
|
||||
SharedArm4Core8Ram80Disk,
|
||||
SharedIntel2Core8Ram80Disk,
|
||||
/// CX32 - Intel 4 Cores, 8 Gb Ram, 80 Gb disk
|
||||
SharedIntel4Core8Ram80Disk,
|
||||
/// CPX31 - AMD 4 Cores, 8 Gb Ram, 160 Gb disk
|
||||
SharedAmd4Core8Ram160Disk,
|
||||
/// CAX31 - Arm 8 Cores, 16 Gb Ram, 160 Gb disk
|
||||
SharedArm8Core16Ram160Disk,
|
||||
SharedIntel4Core16Ram160Disk,
|
||||
/// CX42 - Intel 8 Cores, 16 Gb Ram, 160 Gb disk
|
||||
SharedIntel8Core16Ram160Disk,
|
||||
/// CPX41 - AMD 8 Cores, 16 Gb Ram, 240 Gb disk
|
||||
SharedAmd8Core16Ram240Disk,
|
||||
/// CAX41 - Arm 16 Cores, 32 Gb Ram, 320 Gb disk
|
||||
SharedArm16Core32Ram320Disk,
|
||||
SharedIntel8Core32Ram240Disk,
|
||||
/// CX52 - Intel 16 Cores, 32 Gb Ram, 320 Gb disk
|
||||
SharedIntel16Core32Ram320Disk,
|
||||
/// CPX51 - AMD 16 Cores, 32 Gb Ram, 360 Gb disk
|
||||
SharedAmd16Core32Ram360Disk,
|
||||
|
||||
// Dedicated
|
||||
/// CCX13 - AMD 2 Cores, 8 Gb Ram, 80 Gb disk
|
||||
DedicatedAmd2Core8Ram80Disk,
|
||||
/// CCX23 - AMD 4 Cores, 16 Gb Ram, 160 Gb disk
|
||||
DedicatedAmd4Core16Ram160Disk,
|
||||
/// CCX33 - AMD 8 Cores, 32 Gb Ram, 240 Gb disk
|
||||
DedicatedAmd8Core32Ram240Disk,
|
||||
/// CCX43 - AMD 16 Cores, 64 Gb Ram, 360 Gb disk
|
||||
DedicatedAmd16Core64Ram360Disk,
|
||||
/// CCX53 - AMD 32 Cores, 128 Gb Ram, 600 Gb disk
|
||||
DedicatedAmd32Core128Ram600Disk,
|
||||
/// CCX63 - AMD 48 Cores, 192 Gb Ram, 960 Gb disk
|
||||
DedicatedAmd48Core192Ram960Disk,
|
||||
}
|
||||
|
||||
|
||||
@@ -24,6 +24,8 @@ pub struct ResourceSyncListItemInfo {
|
||||
pub last_sync_hash: String,
|
||||
/// Commit message of last sync, or empty string
|
||||
pub last_sync_message: String,
|
||||
/// The git provider domain
|
||||
pub git_provider: String,
|
||||
/// The Github repo used as the source of the sync resources
|
||||
pub repo: String,
|
||||
/// The branch of the repo
|
||||
@@ -165,6 +167,20 @@ pub type _PartialResourceSyncConfig = PartialResourceSyncConfig;
|
||||
#[partial_derive(Debug, Clone, Default, Serialize, Deserialize)]
|
||||
#[partial(skip_serializing_none, from, diff)]
|
||||
pub struct ResourceSyncConfig {
|
||||
/// The git provider domain. Default: github.com
|
||||
#[serde(default = "default_git_provider")]
|
||||
#[builder(default = "default_git_provider()")]
|
||||
#[partial_default(default_git_provider())]
|
||||
pub git_provider: String,
|
||||
|
||||
/// Whether to use https to clone the repo (versus http). Default: true
|
||||
///
|
||||
/// Note. Monitor does not currently support cloning repos via ssh.
|
||||
#[serde(default = "default_git_https")]
|
||||
#[builder(default = "default_git_https()")]
|
||||
#[partial_default(default_git_https())]
|
||||
pub git_https: bool,
|
||||
|
||||
/// The Github repo used as the source of the build.
|
||||
#[serde(default)]
|
||||
#[builder(default)]
|
||||
@@ -181,11 +197,14 @@ pub struct ResourceSyncConfig {
|
||||
#[builder(default)]
|
||||
pub commit: String,
|
||||
|
||||
/// The github account used to clone (used to access private repos).
|
||||
/// Empty string is public clone (only public repos).
|
||||
#[serde(default)]
|
||||
/// The git account used to access private repos.
|
||||
/// Passing empty string can only clone public repos.
|
||||
///
|
||||
/// Note. A token for the account must be available in the core config or the builder server's periphery config
|
||||
/// for the configured git provider.
|
||||
#[serde(default, alias = "github_account")]
|
||||
#[builder(default)]
|
||||
pub github_account: String,
|
||||
pub git_account: String,
|
||||
|
||||
/// The github account used to clone (used to access private repos).
|
||||
/// Empty string is public clone (only public repos).
|
||||
@@ -213,6 +232,14 @@ impl ResourceSyncConfig {
|
||||
}
|
||||
}
|
||||
|
||||
fn default_git_provider() -> String {
|
||||
String::from("github.com")
|
||||
}
|
||||
|
||||
fn default_git_https() -> bool {
|
||||
true
|
||||
}
|
||||
|
||||
fn default_branch() -> String {
|
||||
String::from("main")
|
||||
}
|
||||
@@ -228,10 +255,12 @@ fn default_webhook_enabled() -> bool {
|
||||
impl Default for ResourceSyncConfig {
|
||||
fn default() -> Self {
|
||||
Self {
|
||||
git_provider: default_git_provider(),
|
||||
git_https: default_git_https(),
|
||||
repo: Default::default(),
|
||||
branch: default_branch(),
|
||||
commit: Default::default(),
|
||||
github_account: Default::default(),
|
||||
git_account: Default::default(),
|
||||
resource_path: default_resource_path(),
|
||||
delete: Default::default(),
|
||||
webhook_enabled: default_webhook_enabled(),
|
||||
|
||||
@@ -3,12 +3,17 @@ use std::collections::HashMap;
|
||||
use serde::{Deserialize, Serialize};
|
||||
|
||||
use super::{
|
||||
alerter::PartialAlerterConfig, build::PartialBuildConfig,
|
||||
builder::PartialBuilderConfig, deployment::PartialDeploymentConfig,
|
||||
permission::PermissionLevel, procedure::PartialProcedureConfig,
|
||||
repo::PartialRepoConfig, server::PartialServerConfig,
|
||||
alerter::PartialAlerterConfig,
|
||||
build::PartialBuildConfig,
|
||||
builder::PartialBuilderConfig,
|
||||
deployment::PartialDeploymentConfig,
|
||||
permission::PermissionLevel,
|
||||
procedure::PartialProcedureConfig,
|
||||
repo::PartialRepoConfig,
|
||||
server::PartialServerConfig,
|
||||
server_template::PartialServerTemplateConfig,
|
||||
sync::PartialResourceSyncConfig, update::{ResourceTarget, ResourceTargetVariant},
|
||||
sync::PartialResourceSyncConfig,
|
||||
update::{ResourceTarget, ResourceTargetVariant},
|
||||
variable::Variable,
|
||||
};
|
||||
|
||||
|
||||
@@ -3,10 +3,13 @@ use std::collections::HashMap;
|
||||
use serde::{Deserialize, Serialize};
|
||||
use typeshare::typeshare;
|
||||
|
||||
use super::{permission::PermissionLevel, update::ResourceTargetVariant, MongoId, I64};
|
||||
use super::{
|
||||
permission::PermissionLevel, update::ResourceTargetVariant,
|
||||
MongoId, I64,
|
||||
};
|
||||
|
||||
/// Permission users at the group level.
|
||||
///
|
||||
///
|
||||
/// All users that are part of a group inherit the group's permissions.
|
||||
/// A user can be a part of multiple groups. A user's permission on a particular resource
|
||||
/// will be resolved to be the maximum permission level between the user's own permissions and
|
||||
|
||||
@@ -18,7 +18,10 @@ export type UserResponses = {
|
||||
export type ReadResponses = {
|
||||
GetVersion: Types.GetVersionResponse;
|
||||
GetCoreInfo: Types.GetCoreInfoResponse;
|
||||
GetAvailableAwsEcrLabels: Types.GetAvailableAwsEcrLabelsResponse;
|
||||
ListAwsEcrLabels: Types.ListAwsEcrLabelsResponse;
|
||||
ListSecrets: Types.ListSecretsResponse;
|
||||
ListGitProviders: Types.ListGitProvidersResponse;
|
||||
ListDockerRegistries: Types.ListDockerRegistriesResponse;
|
||||
|
||||
// ==== USER ====
|
||||
GetUsername: Types.GetUsernameResponse;
|
||||
@@ -61,8 +64,6 @@ export type ReadResponses = {
|
||||
GetDockerNetworks: Types.GetDockerNetworksResponse;
|
||||
GetServerActionState: Types.GetServerActionStateResponse;
|
||||
GetHistoricalServerStats: Types.GetHistoricalServerStatsResponse;
|
||||
GetAvailableAccounts: Types.GetAvailableAccountsResponse;
|
||||
GetAvailableSecrets: Types.GetAvailableSecretsResponse;
|
||||
ListServers: Types.ListServersResponse;
|
||||
ListFullServers: Types.ListFullServersResponse;
|
||||
|
||||
@@ -83,13 +84,11 @@ export type ReadResponses = {
|
||||
GetBuild: Types.GetBuildResponse;
|
||||
GetBuildActionState: Types.GetBuildActionStateResponse;
|
||||
GetBuildMonthlyStats: Types.GetBuildMonthlyStatsResponse;
|
||||
GetBuildVersions: Types.GetBuildVersionsResponse;
|
||||
GetBuildWebhookEnabled: Types.GetBuildWebhookEnabledResponse;
|
||||
ListBuilds: Types.ListBuildsResponse;
|
||||
ListFullBuilds: Types.ListFullBuildsResponse;
|
||||
ListBuildVersions: Types.ListBuildVersionsResponse;
|
||||
ListCommonBuildExtraArgs: Types.ListCommonBuildExtraArgsResponse;
|
||||
ListGithubOrganizations: Types.ListGithubOrganizationsResponse;
|
||||
ListDockerOrganizations: Types.ListDockerOrganizationsResponse;
|
||||
|
||||
// ==== REPO ====
|
||||
GetReposSummary: Types.GetReposSummaryResponse;
|
||||
@@ -102,7 +101,6 @@ export type ReadResponses = {
|
||||
// ==== BUILDER ====
|
||||
GetBuildersSummary: Types.GetBuildersSummaryResponse;
|
||||
GetBuilder: Types.GetBuilderResponse;
|
||||
GetBuilderAvailableAccounts: Types.GetBuilderAvailableAccountsResponse;
|
||||
ListBuilders: Types.ListBuildersResponse;
|
||||
ListFullBuilders: Types.ListFullBuildersResponse;
|
||||
|
||||
|
||||
@@ -332,23 +332,14 @@ export interface SystemCommand {
|
||||
export type ImageRegistry =
|
||||
/** Don't push the image to any registry */
|
||||
| { type: "None", params: NoData }
|
||||
/** Push the image to DockerHub */
|
||||
| { type: "DockerHub", params: CloudRegistryConfig }
|
||||
/**
|
||||
* Push the image to the Github Container Registry.
|
||||
*
|
||||
* See [the Github docs](https://docs.github.com/en/packages/working-with-a-github-packages-registry/working-with-the-container-registry#pushing-container-images)
|
||||
* for information on creating an access token
|
||||
*/
|
||||
| { type: "Ghcr", params: CloudRegistryConfig }
|
||||
/** Push the image to a standard image registry (any domain) */
|
||||
| { type: "Standard", params: StandardRegistryConfig }
|
||||
/**
|
||||
* Push the image to Aws Elastic Container Registry
|
||||
*
|
||||
* The string held in 'params' should match a label of an `aws_ecr_registry` in the core config.
|
||||
*/
|
||||
| { type: "AwsEcr", params: string }
|
||||
/** Todo. Will point to a custom "Registry" resource by id */
|
||||
| { type: "Custom", params: string };
|
||||
| { type: "AwsEcr", params: string };
|
||||
|
||||
export interface EnvironmentVar {
|
||||
variable: string;
|
||||
@@ -361,17 +352,28 @@ export interface BuildConfig {
|
||||
builder_id?: string;
|
||||
/** The current version of the build. */
|
||||
version?: Version;
|
||||
/** The Github repo used as the source of the build. */
|
||||
/** The git provider domain. Default: github.com */
|
||||
git_provider: string;
|
||||
/**
|
||||
* Whether to use https to clone the repo (versus http). Default: true
|
||||
*
|
||||
* Note. Monitor does not currently support cloning repos via ssh.
|
||||
*/
|
||||
git_https: boolean;
|
||||
/** The repo used as the source of the build. */
|
||||
repo?: string;
|
||||
/** The branch of the repo. */
|
||||
branch: string;
|
||||
/** Optionally set a specific commit hash. */
|
||||
commit?: string;
|
||||
/**
|
||||
* The github account used to clone (used to access private repos).
|
||||
* Empty string is public clone (only public repos).
|
||||
* The git account used to access private repos.
|
||||
* Passing empty string can only clone public repos.
|
||||
*
|
||||
* Note. A token for the account must be available in the core config or the builder server's periphery config
|
||||
* for the configured git provider.
|
||||
*/
|
||||
github_account?: string;
|
||||
git_account?: string;
|
||||
/** The optional command run after repo clone and before docker build. */
|
||||
pre_build?: SystemCommand;
|
||||
/** Configuration for the registry to push the built image to. */
|
||||
@@ -438,7 +440,9 @@ export interface BuildListItemInfo {
|
||||
last_built_at: I64;
|
||||
/** The current version of the build */
|
||||
version: Version;
|
||||
/** The Github repo used as the source of the build */
|
||||
/** The git provider domain */
|
||||
git_provider: string;
|
||||
/** The repo used as the source of the build */
|
||||
repo: string;
|
||||
/** The branch of the repo */
|
||||
branch: string;
|
||||
@@ -463,11 +467,7 @@ export interface BuildVersionResponseItem {
|
||||
ts: I64;
|
||||
}
|
||||
|
||||
export type GetBuildVersionsResponse = BuildVersionResponseItem[];
|
||||
|
||||
export type ListGithubOrganizationsResponse = string[];
|
||||
|
||||
export type ListDockerOrganizationsResponse = string[];
|
||||
export type ListBuildVersionsResponse = BuildVersionResponseItem[];
|
||||
|
||||
export type ListCommonBuildExtraArgsResponse = string[];
|
||||
|
||||
@@ -544,15 +544,14 @@ export interface DeploymentConfig {
|
||||
*/
|
||||
image?: DeploymentImage;
|
||||
/**
|
||||
* Configure the registry used to pull the image from the registry.
|
||||
* Configure the account used to pull the image from the registry.
|
||||
* Used with `docker login`.
|
||||
*
|
||||
* When using attached build as image source:
|
||||
* - If the field is `None` variant, will use the same ImageRegistry config as the build.
|
||||
* - Otherwise, it must match the variant of the ImageRegistry build config.
|
||||
* - Only the account is used, the organization is not needed here
|
||||
* - If the field is empty string, will use the same account config as the build, or none at all if using image.
|
||||
* - If the field contains an account, a token for the account must be available.
|
||||
* - Will get the registry domain from the build / image
|
||||
*/
|
||||
image_registry?: ImageRegistry;
|
||||
image_registry_account?: string;
|
||||
/** Whether to skip secret interpolation into the deployment environment variables. */
|
||||
skip_secret_interp?: boolean;
|
||||
/** Whether to redeploy the deployment whenever the attached build finishes. */
|
||||
@@ -693,7 +692,39 @@ export type GetDeploymentActionStateResponse = DeploymentActionState;
|
||||
|
||||
export type ListCommonDeploymentExtraArgsResponse = string[];
|
||||
|
||||
export type GetAvailableAwsEcrLabelsResponse = string[];
|
||||
export interface ProviderAccount {
|
||||
/** The account username. Required. */
|
||||
username: string;
|
||||
/** The account access token. Required. */
|
||||
token: string;
|
||||
}
|
||||
|
||||
export interface GitProvider {
|
||||
/** The git provider domain. Default: `github.com`. */
|
||||
domain: string;
|
||||
/** The account username. Required. */
|
||||
accounts: ProviderAccount[];
|
||||
}
|
||||
|
||||
export type ListGitProvidersResponse = GitProvider[];
|
||||
|
||||
export interface DockerRegistry {
|
||||
/** The docker provider domain. Default: `docker.io`. */
|
||||
domain: string;
|
||||
/** The account username. Required. */
|
||||
accounts?: ProviderAccount[];
|
||||
/**
|
||||
* Available organizations on the registry provider.
|
||||
* Used to push an image under an organization's repo rather than an account's repo.
|
||||
*/
|
||||
organizations?: string[];
|
||||
}
|
||||
|
||||
export type ListDockerRegistriesResponse = DockerRegistry[];
|
||||
|
||||
export type ListAwsEcrLabelsResponse = string[];
|
||||
|
||||
export type ListSecretsResponse = string[];
|
||||
|
||||
export type UserTarget =
|
||||
/** User Id */
|
||||
@@ -805,6 +836,8 @@ export type GetProcedureActionStateResponse = ProcedureActionState;
|
||||
export interface RepoConfig {
|
||||
/** The server to clone the repo on. */
|
||||
server_id?: string;
|
||||
/** The git provider domain. Default: github.com */
|
||||
git_provider: string;
|
||||
/** The github repo to clone. */
|
||||
repo?: string;
|
||||
/** The repo branch. */
|
||||
@@ -812,10 +845,19 @@ export interface RepoConfig {
|
||||
/** Optionally set a specific commit hash. */
|
||||
commit?: string;
|
||||
/**
|
||||
* The github account to use to clone.
|
||||
* It must be available in the server's periphery config.
|
||||
* The git account used to access private repos.
|
||||
* Passing empty string can only clone public repos.
|
||||
*
|
||||
* Note. A token for the account must be available in the core config or the builder server's periphery config
|
||||
* for the configured git provider.
|
||||
*/
|
||||
github_account?: string;
|
||||
git_account?: string;
|
||||
/**
|
||||
* Whether to use https to clone the repo (versus http). Default: true
|
||||
*
|
||||
* Note. Monitor does not currently support cloning repos via ssh.
|
||||
*/
|
||||
git_https: boolean;
|
||||
/** Explicitly specificy the folder to clone the repo in. */
|
||||
path?: string;
|
||||
/**
|
||||
@@ -859,7 +901,9 @@ export interface RepoListItemInfo {
|
||||
server_id: string;
|
||||
/** Repo last cloned / pulled timestamp in ms. */
|
||||
last_pulled_at: I64;
|
||||
/** The configured github repo */
|
||||
/** The git provider domain */
|
||||
git_provider: string;
|
||||
/** The configured repo */
|
||||
repo: string;
|
||||
/** The configured branch */
|
||||
branch: string;
|
||||
@@ -1177,8 +1221,6 @@ export interface SystemProcess {
|
||||
|
||||
export type GetSystemProcessesResponse = SystemProcess[];
|
||||
|
||||
export type GetAvailableSecretsResponse = string[];
|
||||
|
||||
export type ServerTemplateConfig =
|
||||
/** Template to launch an AWS EC2 instance */
|
||||
| { type: "Aws", params: AwsServerTemplateConfig }
|
||||
@@ -1204,6 +1246,14 @@ export type ListFullServerTemplatesResponse = ServerTemplate[];
|
||||
|
||||
/** The sync configuration. */
|
||||
export interface ResourceSyncConfig {
|
||||
/** The git provider domain. Default: github.com */
|
||||
git_provider: string;
|
||||
/**
|
||||
* Whether to use https to clone the repo (versus http). Default: true
|
||||
*
|
||||
* Note. Monitor does not currently support cloning repos via ssh.
|
||||
*/
|
||||
git_https: boolean;
|
||||
/** The Github repo used as the source of the build. */
|
||||
repo?: string;
|
||||
/** The branch of the repo. */
|
||||
@@ -1211,10 +1261,13 @@ export interface ResourceSyncConfig {
|
||||
/** Optionally set a specific commit hash. */
|
||||
commit?: string;
|
||||
/**
|
||||
* The github account used to clone (used to access private repos).
|
||||
* Empty string is public clone (only public repos).
|
||||
* The git account used to access private repos.
|
||||
* Passing empty string can only clone public repos.
|
||||
*
|
||||
* Note. A token for the account must be available in the core config or the builder server's periphery config
|
||||
* for the configured git provider.
|
||||
*/
|
||||
github_account?: string;
|
||||
git_account?: string;
|
||||
/**
|
||||
* The github account used to clone (used to access private repos).
|
||||
* Empty string is public clone (only public repos).
|
||||
@@ -1280,6 +1333,8 @@ export interface ResourceSyncListItemInfo {
|
||||
last_sync_hash: string;
|
||||
/** Commit message of last sync, or empty string */
|
||||
last_sync_message: string;
|
||||
/** The git provider domain */
|
||||
git_provider: string;
|
||||
/** The Github repo used as the source of the sync resources */
|
||||
repo: string;
|
||||
/** The branch of the repo */
|
||||
@@ -1503,6 +1558,8 @@ export interface Variable {
|
||||
|
||||
export type GetVariableResponse = Variable;
|
||||
|
||||
export type ListVariablesResponse = Variable[];
|
||||
|
||||
export type PushRecentlyViewedResponse = NoData;
|
||||
|
||||
export type SetLastSeenUpdateResponse = NoData;
|
||||
@@ -2094,7 +2151,7 @@ export interface GetBuildMonthlyStatsResponse {
|
||||
* sorted by most recent first.
|
||||
* Response: [GetBuildVersionsResponse].
|
||||
*/
|
||||
export interface GetBuildVersions {
|
||||
export interface ListBuildVersions {
|
||||
/** Id or name */
|
||||
build: string;
|
||||
/** Filter to only include versions matching this major version. */
|
||||
@@ -2107,20 +2164,6 @@ export interface GetBuildVersions {
|
||||
limit?: I64;
|
||||
}
|
||||
|
||||
/**
|
||||
* List the available github organizations which can be attached to builds.
|
||||
* Response: [ListGithubOrganizationsResponse].
|
||||
*/
|
||||
export interface ListGithubOrganizations {
|
||||
}
|
||||
|
||||
/**
|
||||
* List the available docker organizations which can be attached to builds.
|
||||
* Response: [ListDockerOrganizationsResponse].
|
||||
*/
|
||||
export interface ListDockerOrganizations {
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets a list of existing values used as extra args across other builds.
|
||||
* Useful to offer suggestions. Response: [ListCommonBuildExtraArgsResponse]
|
||||
@@ -2176,23 +2219,6 @@ export interface GetBuildersSummaryResponse {
|
||||
total: number;
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the docker / github accounts which are available for use on the builder.
|
||||
* Response: [GetBuilderAvailableAccountsResponse].
|
||||
*
|
||||
* Note. Builds using this builder can only use the docker / github accounts available in this response.
|
||||
*/
|
||||
export interface GetBuilderAvailableAccounts {
|
||||
/** Id or name */
|
||||
builder: string;
|
||||
}
|
||||
|
||||
/** Response for [GetBuilderAvailableAccounts]. */
|
||||
export interface GetBuilderAvailableAccountsResponse {
|
||||
github: string[];
|
||||
docker: string[];
|
||||
}
|
||||
|
||||
/** Get a specific deployment by name or id. Response: [Deployment]. */
|
||||
export interface GetDeployment {
|
||||
/** Id or name */
|
||||
@@ -2339,7 +2365,7 @@ export interface GetVersionResponse {
|
||||
}
|
||||
|
||||
/**
|
||||
* Get info about the core api.
|
||||
* Get info about the core api configuration.
|
||||
* Response: [GetCoreInfoResponse].
|
||||
*/
|
||||
export interface GetCoreInfo {
|
||||
@@ -2351,8 +2377,8 @@ export interface GetCoreInfoResponse {
|
||||
title: string;
|
||||
/** The monitoring interval of this core api. */
|
||||
monitoring_interval: Timelength;
|
||||
/** The github webhook base url to use with github webhooks. */
|
||||
github_webhook_base_url: string;
|
||||
/** The webhook base url. */
|
||||
webhook_base_url: string;
|
||||
/** Whether transparent mode is enabled, which gives all users read access to all resources. */
|
||||
transparent_mode: boolean;
|
||||
/** Whether UI write access should be disabled */
|
||||
@@ -2362,10 +2388,56 @@ export interface GetCoreInfoResponse {
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the available aws ecr config labels from the core config.
|
||||
* Response: [GetAvailableAwsEcrLabelsResponse].
|
||||
* List the git providers.
|
||||
* Response: [ListGitProvidersResponse].
|
||||
*
|
||||
* Includes:
|
||||
* - providers in core config
|
||||
* - providers configured on builds, repos, syncs
|
||||
* - providers on the optional Server or Builder
|
||||
*/
|
||||
export interface GetAvailableAwsEcrLabels {
|
||||
export interface ListGitProviders {
|
||||
/**
|
||||
* Accepts an optional Server or Builder target to expand the core list with
|
||||
* providers available on that specific resource.
|
||||
*/
|
||||
target?: ResourceTarget;
|
||||
}
|
||||
|
||||
/**
|
||||
* List the suggested docker registry providers.
|
||||
* Response: [ListDockerRegistriesResponse].
|
||||
*
|
||||
* Includes:
|
||||
* - registries in core config
|
||||
* - registries configured on builds, deployments
|
||||
* - registries on the optional Server or Builder
|
||||
*/
|
||||
export interface ListDockerRegistries {
|
||||
/**
|
||||
* Accepts an optional Server or Builder target to expand the core list with
|
||||
* providers available on that specific resource.
|
||||
*/
|
||||
target?: ResourceTarget;
|
||||
}
|
||||
|
||||
/**
|
||||
* List the available aws ecr config labels from the core config.
|
||||
* Response: [ListAwsEcrLabelsResponse].
|
||||
*/
|
||||
export interface ListAwsEcrLabels {
|
||||
}
|
||||
|
||||
/**
|
||||
* List the available secrets from the core config.
|
||||
* Response: [ListSecretsResponse].
|
||||
*/
|
||||
export interface ListSecrets {
|
||||
/**
|
||||
* Accepts an optional Server or Builder target to expand the core list with
|
||||
* providers available on that specific resource.
|
||||
*/
|
||||
target?: ResourceTarget;
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -2700,35 +2772,6 @@ export interface GetServersSummaryResponse {
|
||||
disabled: I64;
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the usernames for the available github / docker accounts
|
||||
* on the target server, or only available globally if no server
|
||||
* is provided.
|
||||
*
|
||||
* Response: [GetAvailableAccountsResponse].
|
||||
*/
|
||||
export interface GetAvailableAccounts {
|
||||
/** Id or name */
|
||||
server?: string;
|
||||
}
|
||||
|
||||
/** Response for [GetAvailableAccounts]. */
|
||||
export interface GetAvailableAccountsResponse {
|
||||
/** The github usernames */
|
||||
github: string[];
|
||||
/** The docker usernames. */
|
||||
docker: string[];
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the keys for available secrets on the target server.
|
||||
* Response: [GetAvailableSecretsResponse].
|
||||
*/
|
||||
export interface GetAvailableSecrets {
|
||||
/** Id or name */
|
||||
server: string;
|
||||
}
|
||||
|
||||
/** Get a specific server template by id or name. Response: [ServerTemplate]. */
|
||||
export interface GetServerTemplate {
|
||||
/** Id or name */
|
||||
@@ -3015,14 +3058,6 @@ export interface GetVariable {
|
||||
export interface ListVariables {
|
||||
}
|
||||
|
||||
/** The response of [ListVariables]. */
|
||||
export interface ListVariablesResponse {
|
||||
/** The available global variables. */
|
||||
variables: Variable[];
|
||||
/** The available global secret keys */
|
||||
secrets: string[];
|
||||
}
|
||||
|
||||
/**
|
||||
* Push a resource to the front of the users 10 most recently viewed resources.
|
||||
* Response: [NoData].
|
||||
@@ -3819,9 +3854,11 @@ export interface SlackAlerterEndpoint {
|
||||
url: string;
|
||||
}
|
||||
|
||||
/** Configuration for a cloud image registry, like account and organization. */
|
||||
export interface CloudRegistryConfig {
|
||||
/** Specify an account to use with the cloud registry. */
|
||||
/** Configuration for a standard image registry */
|
||||
export interface StandardRegistryConfig {
|
||||
/** Specify the registry provider domain. Eg. `docker.io` */
|
||||
domain?: string;
|
||||
/** Specify an account to use with the registry. */
|
||||
account?: string;
|
||||
/**
|
||||
* Optional. Specify an organization to push the image under.
|
||||
@@ -3874,21 +3911,40 @@ export interface AwsBuilderConfig {
|
||||
* This should include a security group to allow core inbound access to the periphery port.
|
||||
*/
|
||||
security_group_ids: string[];
|
||||
/** Which github accounts (usernames) are available on the AMI */
|
||||
github_accounts?: string[];
|
||||
/** Which dockerhub accounts (usernames) are available on the AMI */
|
||||
docker_accounts?: string[];
|
||||
/** Which git providers are available on the AMI */
|
||||
git_providers?: GitProvider[];
|
||||
/** Which docker registries are available on the AMI. */
|
||||
docker_registries?: DockerRegistry[];
|
||||
/** Which secrets are available on the AMI. */
|
||||
secrets?: string[];
|
||||
}
|
||||
|
||||
export interface LatestCommit {
|
||||
hash: string;
|
||||
message: string;
|
||||
}
|
||||
|
||||
export interface CloneArgs {
|
||||
/** Resource name (eg Build name, Repo name) */
|
||||
name: string;
|
||||
/** Git provider domain. Default: `github.com` */
|
||||
provider?: string;
|
||||
/** Use https (vs http). */
|
||||
https: boolean;
|
||||
/** Full repo identifier. <namespace>/<repo_name> */
|
||||
repo?: string;
|
||||
/** Git Branch. Default: `main` */
|
||||
branch?: string;
|
||||
/** Specific commit hash. Optional */
|
||||
commit?: string;
|
||||
/** The clone destination path */
|
||||
destination?: string;
|
||||
/** Command to run after the repo has been cloned */
|
||||
on_clone?: SystemCommand;
|
||||
/** Command to run after the repo has been pulled */
|
||||
on_pull?: SystemCommand;
|
||||
github_account?: string;
|
||||
/** Configure the account used to access repo (if private) */
|
||||
account?: string;
|
||||
}
|
||||
|
||||
/** Info for the all system disks combined. */
|
||||
@@ -3974,25 +4030,43 @@ export enum HetznerDatacenter {
|
||||
}
|
||||
|
||||
export enum HetznerServerType {
|
||||
SharedIntel1Core2Ram20Disk = "SharedIntel1Core2Ram20Disk",
|
||||
/** CPX11 - AMD 2 Cores, 2 Gb Ram, 40 Gb disk */
|
||||
SharedAmd2Core2Ram40Disk = "SharedAmd2Core2Ram40Disk",
|
||||
/** CAX11 - Arm 2 Cores, 4 Gb Ram, 40 Gb disk */
|
||||
SharedArm2Core4Ram40Disk = "SharedArm2Core4Ram40Disk",
|
||||
/** CX22 - Intel 2 Cores, 4 Gb Ram, 40 Gb disk */
|
||||
SharedIntel2Core4Ram40Disk = "SharedIntel2Core4Ram40Disk",
|
||||
/** CPX21 - AMD 3 Cores, 4 Gb Ram, 80 Gb disk */
|
||||
SharedAmd3Core4Ram80Disk = "SharedAmd3Core4Ram80Disk",
|
||||
/** CAX21 - Arm 4 Cores, 8 Gb Ram, 80 Gb disk */
|
||||
SharedArm4Core8Ram80Disk = "SharedArm4Core8Ram80Disk",
|
||||
SharedIntel2Core8Ram80Disk = "SharedIntel2Core8Ram80Disk",
|
||||
/** CX32 - Intel 4 Cores, 8 Gb Ram, 80 Gb disk */
|
||||
SharedIntel4Core8Ram80Disk = "SharedIntel4Core8Ram80Disk",
|
||||
/** CPX31 - AMD 4 Cores, 8 Gb Ram, 160 Gb disk */
|
||||
SharedAmd4Core8Ram160Disk = "SharedAmd4Core8Ram160Disk",
|
||||
/** CAX31 - Arm 8 Cores, 16 Gb Ram, 160 Gb disk */
|
||||
SharedArm8Core16Ram160Disk = "SharedArm8Core16Ram160Disk",
|
||||
SharedIntel4Core16Ram160Disk = "SharedIntel4Core16Ram160Disk",
|
||||
/** CX42 - Intel 8 Cores, 16 Gb Ram, 160 Gb disk */
|
||||
SharedIntel8Core16Ram160Disk = "SharedIntel8Core16Ram160Disk",
|
||||
/** CPX41 - AMD 8 Cores, 16 Gb Ram, 240 Gb disk */
|
||||
SharedAmd8Core16Ram240Disk = "SharedAmd8Core16Ram240Disk",
|
||||
/** CAX41 - Arm 16 Cores, 32 Gb Ram, 320 Gb disk */
|
||||
SharedArm16Core32Ram320Disk = "SharedArm16Core32Ram320Disk",
|
||||
SharedIntel8Core32Ram240Disk = "SharedIntel8Core32Ram240Disk",
|
||||
/** CX52 - Intel 16 Cores, 32 Gb Ram, 320 Gb disk */
|
||||
SharedIntel16Core32Ram320Disk = "SharedIntel16Core32Ram320Disk",
|
||||
/** CPX51 - AMD 16 Cores, 32 Gb Ram, 360 Gb disk */
|
||||
SharedAmd16Core32Ram360Disk = "SharedAmd16Core32Ram360Disk",
|
||||
/** CCX13 - AMD 2 Cores, 8 Gb Ram, 80 Gb disk */
|
||||
DedicatedAmd2Core8Ram80Disk = "DedicatedAmd2Core8Ram80Disk",
|
||||
/** CCX23 - AMD 4 Cores, 16 Gb Ram, 160 Gb disk */
|
||||
DedicatedAmd4Core16Ram160Disk = "DedicatedAmd4Core16Ram160Disk",
|
||||
/** CCX33 - AMD 8 Cores, 32 Gb Ram, 240 Gb disk */
|
||||
DedicatedAmd8Core32Ram240Disk = "DedicatedAmd8Core32Ram240Disk",
|
||||
/** CCX43 - AMD 16 Cores, 64 Gb Ram, 360 Gb disk */
|
||||
DedicatedAmd16Core64Ram360Disk = "DedicatedAmd16Core64Ram360Disk",
|
||||
/** CCX53 - AMD 32 Cores, 128 Gb Ram, 600 Gb disk */
|
||||
DedicatedAmd32Core128Ram600Disk = "DedicatedAmd32Core128Ram600Disk",
|
||||
/** CCX63 - AMD 48 Cores, 192 Gb Ram, 960 Gb disk */
|
||||
DedicatedAmd48Core192Ram960Disk = "DedicatedAmd48Core192Ram960Disk",
|
||||
}
|
||||
|
||||
@@ -4117,7 +4191,10 @@ export type ExecuteRequest =
|
||||
export type ReadRequest =
|
||||
| { type: "GetVersion", params: GetVersion }
|
||||
| { type: "GetCoreInfo", params: GetCoreInfo }
|
||||
| { type: "GetAvailableAwsEcrLabels", params: GetAvailableAwsEcrLabels }
|
||||
| { type: "ListAwsEcrLabels", params: ListAwsEcrLabels }
|
||||
| { type: "ListSecrets", params: ListSecrets }
|
||||
| { type: "ListGitProviders", params: ListGitProviders }
|
||||
| { type: "ListDockerRegistries", params: ListDockerRegistries }
|
||||
| { type: "GetUsername", params: GetUsername }
|
||||
| { type: "GetPermissionLevel", params: GetPermissionLevel }
|
||||
| { type: "FindUser", params: FindUser }
|
||||
@@ -4147,8 +4224,6 @@ export type ReadRequest =
|
||||
| { type: "GetDockerNetworks", params: GetDockerNetworks }
|
||||
| { type: "GetServerActionState", params: GetServerActionState }
|
||||
| { type: "GetHistoricalServerStats", params: GetHistoricalServerStats }
|
||||
| { type: "GetAvailableAccounts", params: GetAvailableAccounts }
|
||||
| { type: "GetAvailableSecrets", params: GetAvailableSecrets }
|
||||
| { type: "ListServers", params: ListServers }
|
||||
| { type: "ListFullServers", params: ListFullServers }
|
||||
| { type: "GetDeploymentsSummary", params: GetDeploymentsSummary }
|
||||
@@ -4165,13 +4240,11 @@ export type ReadRequest =
|
||||
| { type: "GetBuild", params: GetBuild }
|
||||
| { type: "GetBuildActionState", params: GetBuildActionState }
|
||||
| { type: "GetBuildMonthlyStats", params: GetBuildMonthlyStats }
|
||||
| { type: "GetBuildVersions", params: GetBuildVersions }
|
||||
| { type: "ListBuildVersions", params: ListBuildVersions }
|
||||
| { type: "GetBuildWebhookEnabled", params: GetBuildWebhookEnabled }
|
||||
| { type: "ListBuilds", params: ListBuilds }
|
||||
| { type: "ListFullBuilds", params: ListFullBuilds }
|
||||
| { type: "ListCommonBuildExtraArgs", params: ListCommonBuildExtraArgs }
|
||||
| { type: "ListGithubOrganizations", params: ListGithubOrganizations }
|
||||
| { type: "ListDockerOrganizations", params: ListDockerOrganizations }
|
||||
| { type: "GetReposSummary", params: GetReposSummary }
|
||||
| { type: "GetRepo", params: GetRepo }
|
||||
| { type: "GetRepoActionState", params: GetRepoActionState }
|
||||
@@ -4186,7 +4259,6 @@ export type ReadRequest =
|
||||
| { type: "ListFullResourceSyncs", params: ListFullResourceSyncs }
|
||||
| { type: "GetBuildersSummary", params: GetBuildersSummary }
|
||||
| { type: "GetBuilder", params: GetBuilder }
|
||||
| { type: "GetBuilderAvailableAccounts", params: GetBuilderAvailableAccounts }
|
||||
| { type: "ListBuilders", params: ListBuilders }
|
||||
| { type: "ListFullBuilders", params: ListFullBuilders }
|
||||
| { type: "GetAlertersSummary", params: GetAlertersSummary }
|
||||
|
||||
@@ -14,8 +14,8 @@ pub struct GetLatestCommit {
|
||||
#[response(Vec<Log>)]
|
||||
pub struct CloneRepo {
|
||||
pub args: CloneArgs,
|
||||
/// Override github token with one sent from core.
|
||||
pub github_token: Option<String>,
|
||||
/// Override git token with one sent from core.
|
||||
pub git_token: Option<String>,
|
||||
}
|
||||
|
||||
//
|
||||
|
||||
@@ -1,4 +1,8 @@
|
||||
use monitor_client::entities::{update::Log, SystemCommand};
|
||||
use monitor_client::entities::{
|
||||
config::{DockerRegistry, GitProvider},
|
||||
update::Log,
|
||||
SystemCommand,
|
||||
};
|
||||
use resolver_api::derive::Request;
|
||||
use serde::{Deserialize, Serialize};
|
||||
|
||||
@@ -31,20 +35,24 @@ pub struct GetVersionResponse {
|
||||
//
|
||||
|
||||
#[derive(Serialize, Deserialize, Debug, Clone, Request)]
|
||||
#[response(GetAccountsResponse)]
|
||||
pub struct GetAccounts {}
|
||||
#[response(ListGitProvidersResponse)]
|
||||
pub struct ListGitProviders {}
|
||||
|
||||
#[derive(Serialize, Deserialize, Debug, Clone)]
|
||||
pub struct GetAccountsResponse {
|
||||
pub docker: Vec<String>,
|
||||
pub github: Vec<String>,
|
||||
}
|
||||
pub type ListGitProvidersResponse = Vec<GitProvider>;
|
||||
|
||||
//
|
||||
|
||||
#[derive(Serialize, Deserialize, Debug, Clone, Request)]
|
||||
#[response(ListDockerRegistriesResponse)]
|
||||
pub struct ListDockerRegistries {}
|
||||
|
||||
pub type ListDockerRegistriesResponse = Vec<DockerRegistry>;
|
||||
|
||||
//
|
||||
|
||||
#[derive(Serialize, Deserialize, Debug, Clone, Request)]
|
||||
#[response(Vec<String>)]
|
||||
pub struct GetSecrets {}
|
||||
pub struct ListSecrets {}
|
||||
|
||||
//
|
||||
|
||||
|
||||
@@ -15,6 +15,15 @@ host = "https://monitor.dev"
|
||||
## no default
|
||||
passkey = "a_random_passkey"
|
||||
|
||||
## token that has to be given to git provider during repo webhook config as the secret
|
||||
## default: empty (none)
|
||||
webhook_secret = "a_random_webhook_secret"
|
||||
|
||||
## an alternate base url that is used to recieve git webhook requests
|
||||
## if empty or not specified, will use 'host' address as base
|
||||
## default: empty (none)
|
||||
# webhook_base_url = "https://git-webhook.monitor.dev"
|
||||
|
||||
## specify the log level of the monitor core application
|
||||
## default: info
|
||||
## options: off, error, warn, info, debug, trace
|
||||
@@ -53,11 +62,6 @@ passkey = "a_random_passkey"
|
||||
## default: 0 (pruning disabled)
|
||||
# keep_alerts_for_days = 14
|
||||
|
||||
## these will be used by the GUI to attach to builds being pushed to docker hub.
|
||||
## when attached to build, image will be pushed to repo under the specified organization.
|
||||
## default: empty
|
||||
# docker_organizations = ["your_docker_org1", "your_docker_org_2"]
|
||||
|
||||
## allows all users to have read access on all resources
|
||||
## default: false
|
||||
# transparent_mode = true
|
||||
@@ -78,10 +82,6 @@ passkey = "a_random_passkey"
|
||||
# github_oauth.id = "your_github_client_id"
|
||||
# github_oauth.secret = "your_github_client_secret"
|
||||
|
||||
## token that has to be given to github during repo webhook config as the secret
|
||||
## default: empty (none)
|
||||
# github_webhook_secret = "your_random_webhook_secret"
|
||||
|
||||
## Configure github webhook app. Enables webhook management apis.
|
||||
# github_webhook_app.app_id = 1234455 # Find on the app page.
|
||||
# github_webhook_app.installations = [
|
||||
@@ -94,16 +94,6 @@ passkey = "a_random_passkey"
|
||||
## Just mount the private key pem file on the host to `/github/private-key.pem` in the container.
|
||||
# github_webhook_app.pk_path = "/path/to/pk.pem"
|
||||
|
||||
## an alternate base url that is used to recieve github webhook requests
|
||||
## if empty or not specified, will use 'host' address as base
|
||||
## default: empty (none)
|
||||
# github_webhook_base_url = "https://github-webhook.monitor.dev"
|
||||
|
||||
## these will be used by the GUI to attach to builds being pushed to ghcr.
|
||||
## when attached to build, image will be pushed to repo under the specified organization.
|
||||
## default: empty
|
||||
# github_organizations = ["your_github_org1", "your_github_org_2"]
|
||||
|
||||
# mongo.uri = "mongodb://username:password@localhost:27017"
|
||||
## ==== or ====
|
||||
mongo.address = "localhost:27017"
|
||||
@@ -127,15 +117,41 @@ mongo.address = "localhost:27017"
|
||||
# SECRET_1 = "value_1"
|
||||
# SECRET_2 = "value_2"
|
||||
|
||||
## provide core-based github accounts
|
||||
# [github_accounts]
|
||||
# github_username_1 = "github_token_1"
|
||||
# github_username_2 = "github_token_2"
|
||||
## configure git providers
|
||||
# [[git_provider]]
|
||||
# domain = "github.com"
|
||||
# accounts = [
|
||||
# { username = "mbecker20", token = "access_token_for_account" },
|
||||
# { username = "moghtech", token = "access_token_for_other_account" },
|
||||
# ]
|
||||
|
||||
## provide core-based docker accounts
|
||||
# [docker_accounts]
|
||||
# docker_username_1 = "docker_token_1"
|
||||
# docker_username_2 = "docker_token_2"
|
||||
# [[git_provider]]
|
||||
# domain = "git.mogh.tech" # use a custom provider, like self-hosted gitea
|
||||
# accounts = [
|
||||
# { username = "mbecker20", token = "access_token_for_account" },
|
||||
# ]
|
||||
|
||||
# [[git_provider]]
|
||||
# domain = "localhost:8000" # use a custom provider, like self-hosted gitea
|
||||
# https = false # use http://localhost:8000 as base-url for clone
|
||||
# accounts = [
|
||||
# { username = "mbecker20", token = "access_token_for_account" },
|
||||
# ]
|
||||
|
||||
## configure docker registries
|
||||
# [[docker_registry]]
|
||||
# domain = "docker.io"
|
||||
# accounts = [
|
||||
# { username = "mbecker2020", token = "access_token_for_account" }
|
||||
# ]
|
||||
# organizations = ["DockerhubOrganization"]
|
||||
|
||||
# [[docker_registry]]
|
||||
# domain = "git.mogh.tech" # use a custom provider, like self-hosted gitea
|
||||
# accounts = [
|
||||
# { username = "mbecker20", token = "access_token_for_account" },
|
||||
# ]
|
||||
# organizations = ["Mogh"] # These become available in the UI
|
||||
|
||||
## configure aws ecr registries
|
||||
# [aws_ecr_registry.label_1]
|
||||
|
||||
@@ -17,10 +17,8 @@ MONITOR_JWT_VALID_FOR=1-day
|
||||
MONITOR_MONITORING_INTERVAL=15-sec
|
||||
MONITOR_KEEP_STATS_FOR_DAYS=0
|
||||
MONITOR_KEEP_ALERTS_FOR_DAYS=0
|
||||
MONITOR_GITHUB_WEBHOOK_SECRET=asdfasdf
|
||||
MONITOR_GITHUB_WEBHOOK_BASE_URL=https://github-listener.monitor.dev
|
||||
MONITOR_GITHUB_ORGANIZATIONS=org1,org2
|
||||
MONITOR_DOCKER_ORGANIZATIONS=org1,org2
|
||||
MONITOR_WEBHOOK_SECRET=asdfasdf
|
||||
MONITOR_WEBHOOK_BASE_URL=https://github-listener.monitor.dev
|
||||
|
||||
MONITOR_LOGGING_LEVEL=info
|
||||
MONITOR_LOGGING_STDIO=standard
|
||||
|
||||
@@ -31,16 +31,43 @@
|
||||
## Default: "Monitor"
|
||||
# logging.opentelemetry_service_name = "Monitor-02"
|
||||
|
||||
## optional. can inject these values into your deployments configuration.
|
||||
## provide periphery-based secrets
|
||||
# [secrets]
|
||||
# secret_variable = "secret_value"
|
||||
# SECRET_1 = "value_1"
|
||||
# SECRET_2 = "value_2"
|
||||
|
||||
## optional.
|
||||
# [github_accounts]
|
||||
# github_username1 = "github_token1"
|
||||
# github_username2 = "github_token2"
|
||||
## configure periphery-based git providers
|
||||
# [[git_provider]]
|
||||
# domain = "github.com"
|
||||
# accounts = [
|
||||
# { username = "mbecker20", token = "access_token_for_account" },
|
||||
# { username = "moghtech", token = "access_token_for_other_account" },
|
||||
# ]
|
||||
|
||||
## optional.
|
||||
# [docker_accounts]
|
||||
# docker_username1 = "docker_token1"
|
||||
# docker_username2 = "docker_token2"
|
||||
# [[git_provider]]
|
||||
# domain = "git.mogh.tech" # use a custom provider, like self-hosted gitea
|
||||
# accounts = [
|
||||
# { username = "mbecker20", token = "access_token_for_account" },
|
||||
# ]
|
||||
|
||||
# [[git_provider]]
|
||||
# domain = "localhost:8000" # use a custom provider, like self-hosted gitea
|
||||
# https = false # use http://localhost:8000 as base-url for clone
|
||||
# accounts = [
|
||||
# { username = "mbecker20", token = "access_token_for_account" },
|
||||
# ]
|
||||
|
||||
## configure periphery-based docker registries
|
||||
# [[docker_registry]]
|
||||
# domain = "docker.io"
|
||||
# accounts = [
|
||||
# { username = "mbecker2020", token = "access_token_for_account" }
|
||||
# ]
|
||||
# organizations = ["DockerhubOrganization"]
|
||||
|
||||
# [[docker_registry]]
|
||||
# domain = "git.mogh.tech" # use a custom provider, like self-hosted gitea
|
||||
# accounts = [
|
||||
# { username = "mbecker20", token = "access_token_for_account" },
|
||||
# ]
|
||||
# organizations = ["Mogh"] # These become available in the UI
|
||||
|
||||
@@ -2,13 +2,17 @@
|
||||
|
||||
Monitor just needs a bit of information in order to build your image.
|
||||
|
||||
### Repo configuration
|
||||
To specify the github repo to build, just give it the name of the repo and the branch under *repo config*. The name is given like ```mbecker20/monitor```, it includes the username / organization that owns the repo.
|
||||
### Provider configuration
|
||||
Monitor supports cloning repos over http/s, from any provider that supports cloning private repos using `git clone https://<Token>@git-provider.net/<Owner>/<Repo>`.
|
||||
|
||||
Many repos are private, in this case a Github access token is needed by the building server.
|
||||
It can either come from and account defined in the core configuration,
|
||||
Accounts / access tokens can be configured in either the [core config](../core-setup.md#1-create-the-configuration-file) or in the [periphery config](../connecting-servers/setup-periphery.md#manual-install-steps).
|
||||
|
||||
### Repo configuration
|
||||
To specify the git repo to build, just give it the name of the repo and the branch under *repo config*. The name is given like ```mbecker20/monitor```, it includes the username / organization that owns the repo.
|
||||
|
||||
Many repos are private, in this case an access token is needed by the building server.
|
||||
It can either come from a provider defined in the core configuration,
|
||||
or in the periphery configuration of the building server.
|
||||
These are specified in the config like `username = "access_token"`.
|
||||
|
||||
### Docker build configuration
|
||||
|
||||
@@ -42,4 +46,16 @@ BUILD_ARG1=some_value
|
||||
BUILD_ARG2=some_other_value
|
||||
```
|
||||
|
||||
Note that these values are visible in the final image using `docker history`, so shouldn't be used to pass build time secrets. Use [secret mounts](https://docs.docker.com/engine/reference/builder/#run---mounttypesecret) for this instead.
|
||||
Note that these values are visible in the final image using `docker history`, so shouldn't be used to pass build time secrets. Use [secret mounts](https://docs.docker.com/engine/reference/builder/#run---mounttypesecret) for this instead.
|
||||
|
||||
### Adding build secrets
|
||||
|
||||
The Dockerfile may also make use of [build secrets](https://docs.docker.com/build/building/secrets).
|
||||
|
||||
They are configured in the GUI the same way as build args. The values passed here can be used in RUN commands in the Dockerfile:
|
||||
```
|
||||
RUN --mount=type=secret,id=SECRET_KEY \
|
||||
SECRET_KEY=$(cat /run/secrets/SECRET_KEY) ...
|
||||
```
|
||||
|
||||
These values will not be visible with `docker history` command.
|
||||
7
docsite/docs/version-upgrades.md
Normal file
7
docsite/docs/version-upgrades.md
Normal file
@@ -0,0 +1,7 @@
|
||||
# Version Upgrades
|
||||
|
||||
Most version upgrades only require a redeployment of the core container after pulling the latest version, and are fully backward compatible with the periphery clients, which may be updated later on as convenient. This is the default, and will be the case unless specifically mentioned in the [version release notes](https://github.com/mbecker20/monitor/releases).
|
||||
|
||||
Some Core API upgrades may change behavior such as building / cloning, and require updating the Periphery binaries to match the Core version before this functionality can be restored. This will be specifically mentioned in the release notes.
|
||||
|
||||
Additionally, some Core API upgrades may include database schema changes, and require a database migration. This can be accomplished by using the [monitor migrator](https://github.com/mbecker20/monitor/blob/main/bin/migrator/README.md) for the particular version upgrade before upgrading the Core API container.
|
||||
@@ -57,6 +57,7 @@ const sidebars: SidebarsConfig = {
|
||||
},
|
||||
"sync-resources",
|
||||
"permissioning",
|
||||
"version-upgrades",
|
||||
"api",
|
||||
],
|
||||
};
|
||||
|
||||
@@ -198,7 +198,7 @@ export const Config = <T,>({
|
||||
{!contentHidden && (
|
||||
<CardContent
|
||||
className={cn(
|
||||
"flex flex-col gap-2 pb-3",
|
||||
"flex flex-col gap-1 pb-3",
|
||||
labelHidden && "pt-3"
|
||||
)}
|
||||
>
|
||||
|
||||
@@ -184,18 +184,89 @@ export const DoubleInput = <
|
||||
);
|
||||
};
|
||||
|
||||
export const AccountSelectorConfig = (params: {
|
||||
export const ProviderSelector = ({
|
||||
disabled,
|
||||
account_type,
|
||||
selected,
|
||||
onSelect,
|
||||
showCustom = true,
|
||||
}: {
|
||||
disabled: boolean;
|
||||
id?: string;
|
||||
type: "Server" | "None" | "Builder";
|
||||
account_type: keyof Types.GetBuilderAvailableAccountsResponse;
|
||||
account_type: "git" | "docker";
|
||||
selected: string | undefined;
|
||||
onSelect: (provider: string) => void;
|
||||
showCustom?: boolean;
|
||||
}) => {
|
||||
const request =
|
||||
account_type === "git" ? "ListGitProviders" : "ListDockerRegistries";
|
||||
const providers = useRead(request, {}).data;
|
||||
const [customMode, setCustomMode] = useState(false);
|
||||
|
||||
if (customMode) {
|
||||
return (
|
||||
<Input
|
||||
placeholder="Input custom provider domain"
|
||||
value={selected}
|
||||
onChange={(e) => onSelect(e.target.value)}
|
||||
className="max-w-[75%] lg:max-w-[400px]"
|
||||
onBlur={() => setCustomMode(false)}
|
||||
autoFocus
|
||||
/>
|
||||
);
|
||||
}
|
||||
|
||||
return (
|
||||
<Select
|
||||
value={selected}
|
||||
onValueChange={(value) => {
|
||||
if (value === "Custom") {
|
||||
onSelect("");
|
||||
setCustomMode(true);
|
||||
} else {
|
||||
onSelect(value);
|
||||
}
|
||||
}}
|
||||
disabled={disabled}
|
||||
>
|
||||
<SelectTrigger
|
||||
className="w-full lg:w-[200px] max-w-[50%]"
|
||||
disabled={disabled}
|
||||
>
|
||||
<SelectValue placeholder="Select Provider" />
|
||||
</SelectTrigger>
|
||||
<SelectContent>
|
||||
{providers?.map(
|
||||
(provider: Types.GitProvider | Types.DockerRegistry) => (
|
||||
<SelectItem key={provider.domain} value={provider.domain}>
|
||||
{provider.domain}
|
||||
</SelectItem>
|
||||
)
|
||||
)}
|
||||
{providers !== undefined &&
|
||||
selected &&
|
||||
!providers
|
||||
.map(
|
||||
(provider: Types.GitProvider | Types.DockerRegistry) =>
|
||||
provider.domain
|
||||
)
|
||||
.includes(selected) && (
|
||||
<SelectItem value={selected}>{selected}</SelectItem>
|
||||
)}
|
||||
{showCustom && <SelectItem value={"Custom"}>Custom</SelectItem>}
|
||||
</SelectContent>
|
||||
</Select>
|
||||
);
|
||||
};
|
||||
|
||||
export const ProviderSelectorConfig = (params: {
|
||||
disabled: boolean;
|
||||
account_type: "git" | "docker";
|
||||
selected: string | undefined;
|
||||
onSelect: (id: string) => void;
|
||||
placeholder: string;
|
||||
}) => {
|
||||
return (
|
||||
<ConfigItem label={`${params.account_type} Account`}>
|
||||
<AccountSelector {...params} />
|
||||
<ConfigItem label={`${params.account_type} Provider`}>
|
||||
<ProviderSelector {...params} />
|
||||
</ConfigItem>
|
||||
);
|
||||
};
|
||||
@@ -205,21 +276,34 @@ export const AccountSelector = ({
|
||||
id,
|
||||
type,
|
||||
account_type,
|
||||
provider,
|
||||
selected,
|
||||
onSelect,
|
||||
}: {
|
||||
disabled: boolean;
|
||||
type: "Server" | "Builder" | "None";
|
||||
id?: string;
|
||||
type: "Server" | "None" | "Builder";
|
||||
account_type: keyof Types.GetBuilderAvailableAccountsResponse;
|
||||
account_type: "git" | "docker";
|
||||
provider: string;
|
||||
selected: string | undefined;
|
||||
onSelect: (id: string) => void;
|
||||
}) => {
|
||||
const [request, params] =
|
||||
type === "Server" || type === "None"
|
||||
? ["GetAvailableAccounts", { server: id }]
|
||||
: ["GetBuilderAvailableAccounts", { builder: id }];
|
||||
const accounts = useRead(request as any, params).data;
|
||||
const request =
|
||||
account_type === "git" ? "ListGitProviders" : "ListDockerRegistries";
|
||||
const params =
|
||||
type === "None" ? {} : { target: id ? { type, id } : undefined };
|
||||
const providers = useRead(request, params).data?.filter(
|
||||
(_provider) => _provider.domain === provider
|
||||
);
|
||||
|
||||
const _accounts = new Set<string>();
|
||||
for (const provider of providers ?? []) {
|
||||
for (const account of provider.accounts ?? []) {
|
||||
_accounts.add(account.username);
|
||||
}
|
||||
}
|
||||
const accounts = [..._accounts];
|
||||
accounts.sort();
|
||||
return (
|
||||
<Select
|
||||
value={selected}
|
||||
@@ -236,7 +320,7 @@ export const AccountSelector = ({
|
||||
</SelectTrigger>
|
||||
<SelectContent>
|
||||
<SelectItem value={"Empty"}>None</SelectItem>
|
||||
{(accounts as any)?.[account_type]?.map((account: string) => (
|
||||
{accounts?.map((account) => (
|
||||
<SelectItem key={account} value={account}>
|
||||
{account}
|
||||
</SelectItem>
|
||||
@@ -246,6 +330,23 @@ export const AccountSelector = ({
|
||||
);
|
||||
};
|
||||
|
||||
export const AccountSelectorConfig = (params: {
|
||||
disabled: boolean;
|
||||
id?: string;
|
||||
type: "Server" | "Builder" | "None";
|
||||
account_type: "git" | "docker";
|
||||
provider: string;
|
||||
selected: string | undefined;
|
||||
onSelect: (id: string) => void;
|
||||
placeholder: string;
|
||||
}) => {
|
||||
return (
|
||||
<ConfigItem label="Account">
|
||||
<AccountSelector {...params} />
|
||||
</ConfigItem>
|
||||
);
|
||||
};
|
||||
|
||||
export const AwsEcrLabelSelector = ({
|
||||
disabled,
|
||||
selected,
|
||||
@@ -255,7 +356,7 @@ export const AwsEcrLabelSelector = ({
|
||||
selected: string | undefined;
|
||||
onSelect: (id: string) => void;
|
||||
}) => {
|
||||
const labels = useRead("GetAvailableAwsEcrLabels", {}).data;
|
||||
const labels = useRead("ListAwsEcrLabels", {}).data;
|
||||
return (
|
||||
<Select
|
||||
value={selected}
|
||||
@@ -486,45 +587,49 @@ export const AddExtraArgMenu = ({
|
||||
};
|
||||
|
||||
export const ImageRegistryConfig = ({
|
||||
registry,
|
||||
registry: _registry,
|
||||
setRegistry,
|
||||
disabled,
|
||||
type,
|
||||
resource_id,
|
||||
registry_types,
|
||||
}: {
|
||||
registry: Types.ImageRegistry | undefined;
|
||||
setRegistry: (registry: Types.ImageRegistry) => void;
|
||||
disabled: boolean;
|
||||
type: "Build" | "Deployment";
|
||||
// For builds, its builder id. For servers, its server id.
|
||||
resource_id?: string;
|
||||
registry_types?: Types.ImageRegistry["type"][];
|
||||
}) => {
|
||||
const _registry = registry ?? default_registry_config("None");
|
||||
const cloud_params =
|
||||
_registry.type === "DockerHub" || _registry.type === "Ghcr"
|
||||
? _registry.params
|
||||
: undefined;
|
||||
if (_registry.type === "None" || _registry.type === "Custom") {
|
||||
const registry = _registry ?? default_registry_config("None");
|
||||
|
||||
const provider = useRead("ListDockerRegistries", {
|
||||
target: resource_id ? { type: "Builder", id: resource_id } : undefined,
|
||||
}).data?.find((provider) => {
|
||||
if (registry.type === "Standard") {
|
||||
return provider.domain === registry.params.domain;
|
||||
} else {
|
||||
return false;
|
||||
}
|
||||
});
|
||||
|
||||
if (registry.type === "None") {
|
||||
return (
|
||||
<ConfigItem label="Image Registry">
|
||||
<RegistryTypeSelector
|
||||
registry={_registry}
|
||||
registry={registry}
|
||||
setRegistry={setRegistry}
|
||||
disabled={disabled}
|
||||
deployment={type === "Deployment"}
|
||||
registry_types={registry_types}
|
||||
/>
|
||||
</ConfigItem>
|
||||
);
|
||||
}
|
||||
if (_registry.type === "AwsEcr") {
|
||||
if (registry.type === "AwsEcr") {
|
||||
return (
|
||||
<ConfigItem label="Image Registry">
|
||||
<div className="flex items-center justify-stretch gap-4">
|
||||
<AwsEcrLabelSelector
|
||||
selected={_registry.params}
|
||||
selected={registry.params}
|
||||
onSelect={(label) =>
|
||||
setRegistry({
|
||||
type: "AwsEcr",
|
||||
@@ -534,61 +639,80 @@ export const ImageRegistryConfig = ({
|
||||
disabled={disabled}
|
||||
/>
|
||||
<RegistryTypeSelector
|
||||
registry={_registry}
|
||||
registry={registry}
|
||||
setRegistry={setRegistry}
|
||||
disabled={disabled}
|
||||
deployment={type === "Deployment"}
|
||||
registry_types={registry_types}
|
||||
/>
|
||||
</div>
|
||||
</ConfigItem>
|
||||
);
|
||||
}
|
||||
|
||||
const organizations = provider?.organizations ?? [];
|
||||
|
||||
return (
|
||||
<ConfigItem label="Image Registry">
|
||||
<div className="flex items-center justify-stretch gap-4">
|
||||
{type === "Build" && cloud_params?.account && (
|
||||
<>
|
||||
<ConfigItem label="Image Registry">
|
||||
<div className="flex items-center justify-stretch gap-4">
|
||||
<ProviderSelector
|
||||
disabled={disabled}
|
||||
account_type="docker"
|
||||
selected={registry.params?.domain}
|
||||
onSelect={(domain) =>
|
||||
setRegistry({
|
||||
...registry,
|
||||
params: { ...registry.params, domain },
|
||||
})
|
||||
}
|
||||
showCustom={false}
|
||||
/>
|
||||
<RegistryTypeSelector
|
||||
registry={registry}
|
||||
setRegistry={setRegistry}
|
||||
disabled={disabled}
|
||||
registry_types={registry_types}
|
||||
/>
|
||||
</div>
|
||||
</ConfigItem>
|
||||
{organizations.length > 0 && (
|
||||
<ConfigItem label="Organization">
|
||||
<OrganizationSelector
|
||||
value={cloud_params?.organization}
|
||||
organizations={organizations}
|
||||
selected={registry.params?.organization}
|
||||
set={(organization) =>
|
||||
setRegistry({
|
||||
..._registry,
|
||||
params: { ..._registry.params, organization },
|
||||
...registry,
|
||||
params: { ...registry.params, organization },
|
||||
})
|
||||
}
|
||||
disabled={disabled}
|
||||
type={_registry.type === "DockerHub" ? "Docker" : "Github"}
|
||||
/>
|
||||
)}
|
||||
</ConfigItem>
|
||||
)}
|
||||
<ConfigItem label="Account">
|
||||
<AccountSelector
|
||||
id={resource_id}
|
||||
type={type === "Build" ? "Builder" : "Server"}
|
||||
account_type={_registry.type === "DockerHub" ? "docker" : "github"}
|
||||
selected={cloud_params?.account}
|
||||
type="Builder"
|
||||
account_type="docker"
|
||||
provider={registry.params.domain!}
|
||||
selected={registry.params.account}
|
||||
onSelect={(account) =>
|
||||
setRegistry({
|
||||
..._registry,
|
||||
params: { ..._registry.params, account },
|
||||
...registry,
|
||||
params: { ...registry.params, account },
|
||||
})
|
||||
}
|
||||
disabled={disabled}
|
||||
/>
|
||||
<RegistryTypeSelector
|
||||
registry={_registry}
|
||||
setRegistry={setRegistry}
|
||||
disabled={disabled}
|
||||
deployment={type === "Deployment"}
|
||||
registry_types={registry_types}
|
||||
/>
|
||||
</div>
|
||||
</ConfigItem>
|
||||
</ConfigItem>
|
||||
</>
|
||||
);
|
||||
};
|
||||
|
||||
const REGISTRY_TYPES: Types.ImageRegistry["type"][] = [
|
||||
"None",
|
||||
"DockerHub",
|
||||
"Ghcr",
|
||||
"Standard",
|
||||
"AwsEcr",
|
||||
];
|
||||
|
||||
@@ -597,21 +721,17 @@ const RegistryTypeSelector = ({
|
||||
setRegistry,
|
||||
registry_types = REGISTRY_TYPES,
|
||||
disabled,
|
||||
deployment,
|
||||
}: {
|
||||
registry: Types.ImageRegistry;
|
||||
setRegistry: (registry: Types.ImageRegistry) => void;
|
||||
registry_types?: Types.ImageRegistry["type"][];
|
||||
disabled: boolean;
|
||||
deployment?: boolean;
|
||||
}) => {
|
||||
return (
|
||||
<Select
|
||||
value={to_readable_registry_type(registry.type, deployment)}
|
||||
onValueChange={(type) => {
|
||||
setRegistry(
|
||||
default_registry_config(from_readable_registry_type(type, deployment))
|
||||
);
|
||||
value={registry.type}
|
||||
onValueChange={(type: Types.ImageRegistry["type"]) => {
|
||||
setRegistry(default_registry_config(type));
|
||||
}}
|
||||
disabled={disabled}
|
||||
>
|
||||
@@ -623,10 +743,9 @@ const RegistryTypeSelector = ({
|
||||
</SelectTrigger>
|
||||
<SelectContent align="end">
|
||||
{registry_types.map((type) => {
|
||||
const t = to_readable_registry_type(type, deployment);
|
||||
return (
|
||||
<SelectItem key={type} value={t}>
|
||||
{t}
|
||||
<SelectItem key={type} value={type}>
|
||||
{type}
|
||||
</SelectItem>
|
||||
);
|
||||
})}
|
||||
@@ -636,21 +755,20 @@ const RegistryTypeSelector = ({
|
||||
};
|
||||
|
||||
const OrganizationSelector = ({
|
||||
value,
|
||||
organizations,
|
||||
selected,
|
||||
set,
|
||||
disabled,
|
||||
type,
|
||||
}: {
|
||||
value?: string;
|
||||
organizations: string[];
|
||||
selected?: string;
|
||||
set: (org: string) => void;
|
||||
disabled: boolean;
|
||||
type: "Docker" | "Github";
|
||||
}) => {
|
||||
const organizations = useRead(`List${type}Organizations`, {}).data;
|
||||
if (!organizations || organizations.length === 0) return null;
|
||||
if (organizations.length === 0) return null;
|
||||
return (
|
||||
<Select
|
||||
value={value}
|
||||
value={selected}
|
||||
onValueChange={(v) => set(v === "Empty" ? "" : v)}
|
||||
disabled={disabled}
|
||||
>
|
||||
@@ -672,36 +790,19 @@ const OrganizationSelector = ({
|
||||
);
|
||||
};
|
||||
|
||||
const to_readable_registry_type = (
|
||||
type: Types.ImageRegistry["type"],
|
||||
deployment?: boolean
|
||||
) => {
|
||||
if (deployment && type === "None") return "Same as build";
|
||||
return type;
|
||||
};
|
||||
|
||||
const from_readable_registry_type = (
|
||||
readable: string,
|
||||
deployment?: boolean
|
||||
) => {
|
||||
if (deployment && readable === "Same as build") return "None";
|
||||
return readable as Types.ImageRegistry["type"];
|
||||
};
|
||||
|
||||
const default_registry_config = (
|
||||
type: Types.ImageRegistry["type"]
|
||||
): Types.ImageRegistry => {
|
||||
switch (type) {
|
||||
case "None":
|
||||
return { type, params: {} };
|
||||
case "DockerHub":
|
||||
return { type, params: { account: "", organization: "" } };
|
||||
case "Ghcr":
|
||||
return { type, params: { account: "", organization: "" } };
|
||||
case "AwsEcr":
|
||||
return { type, params: "" };
|
||||
case "Custom":
|
||||
return { type, params: "" };
|
||||
case "Standard":
|
||||
return {
|
||||
type,
|
||||
params: { domain: "docker.io", account: "", organization: "" },
|
||||
};
|
||||
}
|
||||
};
|
||||
|
||||
|
||||
@@ -5,6 +5,7 @@ import {
|
||||
ConfigItem,
|
||||
ImageRegistryConfig,
|
||||
InputList,
|
||||
ProviderSelectorConfig,
|
||||
SecretSelector,
|
||||
SystemCommand,
|
||||
} from "@components/config/util";
|
||||
@@ -112,43 +113,47 @@ export const BuildConfig = ({
|
||||
{
|
||||
label: "Git",
|
||||
components: {
|
||||
git_provider: (provider, set) => (
|
||||
<ProviderSelectorConfig
|
||||
account_type="git"
|
||||
selected={provider}
|
||||
disabled={disabled}
|
||||
onSelect={(git_provider) => set({ git_provider })}
|
||||
/>
|
||||
),
|
||||
git_https: { label: "Use Https" },
|
||||
git_account: (account, set) => (
|
||||
<AccountSelectorConfig
|
||||
id={update.builder_id ?? config.builder_id ?? undefined}
|
||||
type="Builder"
|
||||
account_type="git"
|
||||
provider={update.git_provider ?? config.git_provider}
|
||||
selected={account}
|
||||
onSelect={(git_account) => set({ git_account })}
|
||||
disabled={disabled}
|
||||
placeholder="None"
|
||||
/>
|
||||
),
|
||||
repo: { placeholder: "Enter repo" },
|
||||
branch: { placeholder: "Enter branch" },
|
||||
commit: { placeholder: "Enter specific commit hash. Optional." },
|
||||
github_account:
|
||||
(update.builder_id ?? config.builder_id ? true : false) &&
|
||||
((account, set) => (
|
||||
<AccountSelectorConfig
|
||||
id={update.builder_id ?? config.builder_id ?? undefined}
|
||||
type="Builder"
|
||||
account_type="github"
|
||||
selected={account}
|
||||
onSelect={(github_account) => set({ github_account })}
|
||||
disabled={disabled}
|
||||
placeholder="None"
|
||||
/>
|
||||
)),
|
||||
commit: {
|
||||
placeholder: "Enter a specific commit hash. Optional.",
|
||||
},
|
||||
},
|
||||
},
|
||||
{
|
||||
label: "Docker",
|
||||
components: {
|
||||
image_registry: (registry, set) => {
|
||||
const builder_id = update.builder_id ?? config.builder_id;
|
||||
if (!builder_id) return null;
|
||||
return (
|
||||
<ImageRegistryConfig
|
||||
registry={registry}
|
||||
setRegistry={(image_registry) => set({ image_registry })}
|
||||
type="Build"
|
||||
resource_id={builder_id}
|
||||
disabled={disabled}
|
||||
/>
|
||||
);
|
||||
},
|
||||
image_registry: (registry, set) => (
|
||||
<ImageRegistryConfig
|
||||
registry={registry}
|
||||
setRegistry={(image_registry) => set({ image_registry })}
|
||||
resource_id={update.builder_id ?? config.builder_id}
|
||||
disabled={disabled}
|
||||
/>
|
||||
),
|
||||
build_path: true,
|
||||
dockerfile_path: true,
|
||||
use_buildx: true,
|
||||
},
|
||||
},
|
||||
{
|
||||
@@ -386,10 +391,8 @@ const Secrets = ({
|
||||
setArgs: (args: string) => void;
|
||||
argsRef: RefObject<HTMLTextAreaElement>;
|
||||
}) => {
|
||||
const { variables, secrets } = useRead("ListVariables", {}).data ?? {
|
||||
variables: [],
|
||||
secrets: [],
|
||||
};
|
||||
const variables = useRead("ListVariables", {}).data ?? [];
|
||||
const secrets = useRead("ListSecrets", {}).data ?? [];
|
||||
|
||||
const _args = args || "";
|
||||
|
||||
|
||||
@@ -5,7 +5,17 @@ import { Types } from "@monitor/client";
|
||||
import { useState } from "react";
|
||||
import { ResourceSelector } from "../common";
|
||||
import { Button } from "@ui/button";
|
||||
import { PlusCircle } from "lucide-react";
|
||||
import { MinusCircle, PlusCircle } from "lucide-react";
|
||||
import {
|
||||
Dialog,
|
||||
DialogContent,
|
||||
DialogFooter,
|
||||
DialogHeader,
|
||||
DialogTrigger,
|
||||
} from "@ui/dialog";
|
||||
import { Card } from "@ui/card";
|
||||
import { cn } from "@lib/utils";
|
||||
import { Input } from "@ui/input";
|
||||
|
||||
export const BuilderConfig = ({ id }: { id: string }) => {
|
||||
const config = useRead("GetBuilder", { builder: id }).data?.config;
|
||||
@@ -90,73 +100,102 @@ const AwsBuilderConfig = ({ id }: { id: string }) => {
|
||||
},
|
||||
},
|
||||
{
|
||||
label: "Github Accounts",
|
||||
label: "Additional Git Providers",
|
||||
contentHidden:
|
||||
(update.github_accounts ?? config.github_accounts)?.length === 0,
|
||||
(update.git_providers ?? config.git_providers)?.length === 0,
|
||||
actions: !disabled && (
|
||||
<Button
|
||||
variant="secondary"
|
||||
onClick={() =>
|
||||
set((update) => ({
|
||||
...update,
|
||||
github_accounts: [
|
||||
...(update.github_accounts ??
|
||||
config.github_accounts ??
|
||||
[]),
|
||||
"",
|
||||
git_providers: [
|
||||
...(update.git_providers ?? config.git_providers ?? []),
|
||||
{ domain: "github.com", accounts: [] },
|
||||
],
|
||||
}))
|
||||
}
|
||||
className="flex items-center gap-2 w-[200px]"
|
||||
>
|
||||
<PlusCircle className="w-4 h-4" />
|
||||
Add Github Account
|
||||
Add Git Provider
|
||||
</Button>
|
||||
),
|
||||
components: {
|
||||
github_accounts: (accounts, set) => (
|
||||
<InputList
|
||||
field="github_accounts"
|
||||
values={accounts ?? []}
|
||||
set={set}
|
||||
disabled={disabled}
|
||||
placeholder="Github Username"
|
||||
/>
|
||||
),
|
||||
git_providers: (providers, set) =>
|
||||
providers && (
|
||||
<ProvidersConfig
|
||||
type="git"
|
||||
providers={providers}
|
||||
set={set}
|
||||
disabled={disabled}
|
||||
/>
|
||||
),
|
||||
},
|
||||
},
|
||||
{
|
||||
label: "Docker Accounts",
|
||||
label: "Additional Docker Registries",
|
||||
contentHidden:
|
||||
(update.docker_accounts ?? config.docker_accounts)?.length === 0,
|
||||
(update.docker_registries ?? config.docker_registries)?.length ===
|
||||
0,
|
||||
actions: !disabled && (
|
||||
<Button
|
||||
variant="secondary"
|
||||
onClick={() =>
|
||||
set((update) => ({
|
||||
...update,
|
||||
docker_accounts: [
|
||||
...(update.docker_accounts ??
|
||||
config.docker_accounts ??
|
||||
docker_registries: [
|
||||
...(update.docker_registries ??
|
||||
config.docker_registries ??
|
||||
[]),
|
||||
"",
|
||||
{ domain: "docker.io", accounts: [], organizations: [] },
|
||||
],
|
||||
}))
|
||||
}
|
||||
className="flex items-center gap-2 w-[200px]"
|
||||
>
|
||||
<PlusCircle className="w-4 h-4" />
|
||||
Add Docker Account
|
||||
Add Docker Registry
|
||||
</Button>
|
||||
),
|
||||
components: {
|
||||
docker_accounts: (accounts, set) => (
|
||||
docker_registries: (providers, set) =>
|
||||
providers && (
|
||||
<ProvidersConfig
|
||||
type="docker"
|
||||
providers={providers}
|
||||
set={set}
|
||||
disabled={disabled}
|
||||
/>
|
||||
),
|
||||
},
|
||||
},
|
||||
{
|
||||
label: "Additional Secret Keys",
|
||||
contentHidden: (update.secrets ?? config.secrets)?.length === 0,
|
||||
actions: !disabled && (
|
||||
<Button
|
||||
variant="secondary"
|
||||
onClick={() =>
|
||||
set((update) => ({
|
||||
...update,
|
||||
secrets: [...(update.secrets ?? config.secrets ?? []), ""],
|
||||
}))
|
||||
}
|
||||
className="flex items-center gap-2 w-[200px]"
|
||||
>
|
||||
<PlusCircle className="w-4 h-4" />
|
||||
Add Secret Key
|
||||
</Button>
|
||||
),
|
||||
components: {
|
||||
secrets: (secrets, set) => (
|
||||
<InputList
|
||||
field="docker_accounts"
|
||||
values={accounts ?? []}
|
||||
field="secrets"
|
||||
values={secrets ?? []}
|
||||
set={set}
|
||||
disabled={disabled}
|
||||
placeholder="Docker Username"
|
||||
placeholder="SECRET_KEY"
|
||||
/>
|
||||
),
|
||||
},
|
||||
@@ -210,3 +249,267 @@ const ServerBuilderConfig = ({ id }: { id: string }) => {
|
||||
/>
|
||||
);
|
||||
};
|
||||
|
||||
const ProvidersConfig = (params: {
|
||||
type: "git" | "docker";
|
||||
providers: Types.GitProvider[] | Types.DockerRegistry[];
|
||||
set: (input: Partial<Types.AwsBuilderConfig>) => void;
|
||||
disabled: boolean;
|
||||
}) => {
|
||||
const arr_field =
|
||||
params.type === "git" ? "git_providers" : "docker_registries";
|
||||
return (
|
||||
<div className="w-full flex justify-end">
|
||||
<div className="flex flex-col gap-4 w-full max-w-[400px]">
|
||||
{params.providers?.map((_, index) => (
|
||||
<div key={index} className="flex items-center justify-between gap-4">
|
||||
<ProviderDialog {...params} index={index} />
|
||||
{!params.disabled && (
|
||||
<Button
|
||||
variant="secondary"
|
||||
onClick={() =>
|
||||
params.set({
|
||||
[arr_field]: params.providers.filter((_, i) => i !== index),
|
||||
})
|
||||
}
|
||||
>
|
||||
<MinusCircle className="w-4 h-4" />
|
||||
</Button>
|
||||
)}
|
||||
</div>
|
||||
))}
|
||||
</div>
|
||||
</div>
|
||||
);
|
||||
};
|
||||
|
||||
const ProviderDialog = ({
|
||||
type,
|
||||
providers,
|
||||
set,
|
||||
disabled,
|
||||
index,
|
||||
}: {
|
||||
type: "git" | "docker";
|
||||
providers: Types.GitProvider[] | Types.DockerRegistry[];
|
||||
index: number;
|
||||
set: (input: Partial<Types.AwsBuilderConfig>) => void;
|
||||
disabled: boolean;
|
||||
}) => {
|
||||
const [open, setOpen] = useState(false);
|
||||
const provider = providers[index];
|
||||
const arr_field = type === "git" ? "git_providers" : "docker_registries";
|
||||
const example_domain = type === "git" ? "github.com" : "docker.io";
|
||||
const update_domain = (domain: string) =>
|
||||
set({
|
||||
[arr_field]: providers.map((provider, i) =>
|
||||
i === index ? { ...provider, domain } : provider
|
||||
),
|
||||
});
|
||||
const add_account = () =>
|
||||
set({
|
||||
[arr_field]: providers.map(
|
||||
(provider: Types.GitProvider | Types.DockerRegistry, i) =>
|
||||
i === index
|
||||
? {
|
||||
...provider,
|
||||
accounts: [...(provider.accounts ?? []), { username: "" }],
|
||||
}
|
||||
: provider
|
||||
) as Types.GitProvider[] | Types.DockerRegistry[],
|
||||
});
|
||||
const update_username = (username: string, account_index: number) =>
|
||||
set({
|
||||
[arr_field]: providers.map(
|
||||
(provider: Types.GitProvider | Types.DockerRegistry, provider_index) =>
|
||||
provider_index === index
|
||||
? {
|
||||
...provider,
|
||||
accounts: provider.accounts?.map((account, i) =>
|
||||
account_index === i ? { username } : account
|
||||
),
|
||||
}
|
||||
: provider
|
||||
) as Types.GitProvider[] | Types.DockerRegistry[],
|
||||
});
|
||||
const remove_account = (account_index) =>
|
||||
set({
|
||||
[arr_field]: providers.map(
|
||||
(provider: Types.GitProvider | Types.DockerRegistry, provider_index) =>
|
||||
provider_index === index
|
||||
? {
|
||||
...provider,
|
||||
accounts: provider.accounts?.filter(
|
||||
(_, i) => account_index !== i
|
||||
),
|
||||
}
|
||||
: provider
|
||||
) as Types.GitProvider[] | Types.DockerRegistry[],
|
||||
});
|
||||
const add_organization = () =>
|
||||
set({
|
||||
[arr_field]: providers.map((provider: Types.DockerRegistry, i) =>
|
||||
i === index
|
||||
? {
|
||||
...provider,
|
||||
organizations: [...(provider.organizations ?? []), ""],
|
||||
}
|
||||
: provider
|
||||
) as Types.DockerRegistry[],
|
||||
});
|
||||
const update_organization = (name: string, organization_index: number) =>
|
||||
set({
|
||||
[arr_field]: providers.map(
|
||||
(provider: Types.DockerRegistry, provider_index) =>
|
||||
provider_index === index
|
||||
? {
|
||||
...provider,
|
||||
organizations: provider.organizations?.map((organization, i) =>
|
||||
organization_index === i ? name : organization
|
||||
),
|
||||
}
|
||||
: provider
|
||||
) as Types.GitProvider[] | Types.DockerRegistry[],
|
||||
});
|
||||
const remove_organization = (organization_index) =>
|
||||
set({
|
||||
[arr_field]: providers.map(
|
||||
(provider: Types.DockerRegistry, provider_index) =>
|
||||
provider_index === index
|
||||
? {
|
||||
...provider,
|
||||
organizations: provider.organizations?.filter(
|
||||
(_, i) => organization_index !== i
|
||||
),
|
||||
}
|
||||
: provider
|
||||
) as Types.DockerRegistry[],
|
||||
});
|
||||
return (
|
||||
<Dialog open={open} onOpenChange={setOpen}>
|
||||
<DialogTrigger asChild>
|
||||
<Card className="px-3 py-2 hover:bg-accent/50 transition-colors cursor-pointer w-full">
|
||||
<div
|
||||
className={cn(
|
||||
"flex gap-2 text-sm text-nowrap overflow-hidden overflow-ellipsis"
|
||||
)}
|
||||
>
|
||||
<div className="flex gap-2">{provider.domain}</div>
|
||||
<div className="flex gap-2">
|
||||
<div className="text-muted-foreground">accounts:</div>{" "}
|
||||
{provider.accounts?.length || 0}
|
||||
</div>
|
||||
{(provider as Types.DockerRegistry).organizations !== undefined && (
|
||||
<div className="flex gap-2">
|
||||
<div className="text-muted-foreground">organizations:</div>{" "}
|
||||
{(provider as Types.DockerRegistry).organizations?.length || 0}
|
||||
</div>
|
||||
)}
|
||||
</div>
|
||||
</Card>
|
||||
</DialogTrigger>
|
||||
<DialogContent>
|
||||
<DialogHeader>
|
||||
{type === "git" ? "Git Provider" : "Docker Registry"}
|
||||
</DialogHeader>
|
||||
<div className="flex flex-col gap-4">
|
||||
{/* Domain */}
|
||||
<div className="flex items-center justify-between w-fill">
|
||||
<div className="text-nowrap">Domain</div>
|
||||
<Input
|
||||
value={provider.domain}
|
||||
onChange={(e) => update_domain(e.target.value)}
|
||||
disabled={disabled}
|
||||
className="w-[300px]"
|
||||
placeholder={example_domain}
|
||||
/>
|
||||
</div>
|
||||
|
||||
{/* Accounts */}
|
||||
<div className="flex flex-col gap-2 w-fill">
|
||||
<div className="flex items-center justify-between w-fill">
|
||||
<div className="text-nowrap">Available Accounts</div>
|
||||
<Button variant="secondary" onClick={add_account}>
|
||||
Add
|
||||
</Button>
|
||||
</div>
|
||||
<div className="flex flex-col gap-2">
|
||||
{provider.accounts?.map((account, account_index) => {
|
||||
return (
|
||||
<div
|
||||
key={account_index}
|
||||
className="flex gap-2 items-center justify-end"
|
||||
>
|
||||
<Input
|
||||
placeholder="Account Username"
|
||||
value={account.username}
|
||||
onChange={(e) =>
|
||||
update_username(e.target.value, account_index)
|
||||
}
|
||||
/>
|
||||
{!disabled && (
|
||||
<Button
|
||||
variant="secondary"
|
||||
onClick={() => remove_account(account_index)}
|
||||
>
|
||||
<MinusCircle className="w-4 h-4" />
|
||||
</Button>
|
||||
)}
|
||||
</div>
|
||||
);
|
||||
})}
|
||||
</div>
|
||||
</div>
|
||||
|
||||
{/* Organizations */}
|
||||
{type === "docker" && (
|
||||
<div className="flex flex-col gap-2 w-fill">
|
||||
<div className="flex items-center justify-between w-fill">
|
||||
<div className="text-nowrap">Available Organizations</div>
|
||||
<Button variant="secondary" onClick={add_organization}>
|
||||
Add
|
||||
</Button>
|
||||
</div>
|
||||
<div className="flex flex-col gap-2">
|
||||
{(provider as Types.DockerRegistry).organizations?.map(
|
||||
(organization, organization_index) => {
|
||||
return (
|
||||
<div
|
||||
key={organization_index}
|
||||
className="flex gap-2 items-center justify-end"
|
||||
>
|
||||
<Input
|
||||
value={organization}
|
||||
onChange={(e) =>
|
||||
update_organization(
|
||||
e.target.value,
|
||||
organization_index
|
||||
)
|
||||
}
|
||||
placeholder="Organization Name"
|
||||
/>
|
||||
{!disabled && (
|
||||
<Button
|
||||
variant="secondary"
|
||||
onClick={() =>
|
||||
remove_organization(organization_index)
|
||||
}
|
||||
>
|
||||
<MinusCircle className="w-4 h-4" />
|
||||
</Button>
|
||||
)}
|
||||
</div>
|
||||
);
|
||||
}
|
||||
)}
|
||||
</div>
|
||||
</div>
|
||||
)}
|
||||
</div>
|
||||
<DialogFooter>
|
||||
<Button onClick={() => setOpen(false)}>Confirm</Button>
|
||||
</DialogFooter>
|
||||
</DialogContent>
|
||||
</Dialog>
|
||||
);
|
||||
};
|
||||
|
||||
@@ -372,7 +372,7 @@ export const LabelsConfig = ({
|
||||
);
|
||||
|
||||
export const CopyGithubWebhook = ({ path }: { path: string }) => {
|
||||
const base_url = useRead("GetCoreInfo", {}).data?.github_webhook_base_url;
|
||||
const base_url = useRead("GetCoreInfo", {}).data?.webhook_base_url;
|
||||
const url = base_url + "/listener/github" + path;
|
||||
return (
|
||||
<div className="flex gap-2 items-center">
|
||||
|
||||
@@ -48,16 +48,10 @@ const Secrets = ({
|
||||
/// eg server id
|
||||
server: string;
|
||||
}) => {
|
||||
const { variables, secrets: core_secrets } = useRead("ListVariables", {})
|
||||
.data ?? {
|
||||
variables: [],
|
||||
secrets: [],
|
||||
};
|
||||
const periphery_secrets =
|
||||
useRead("GetAvailableSecrets", { server }).data || [];
|
||||
|
||||
// Get unique list of secrets between core and periphery
|
||||
const secrets = [...new Set([...core_secrets, ...periphery_secrets])];
|
||||
const variables = useRead("ListVariables", {}).data ?? [];
|
||||
const secrets =
|
||||
useRead("ListSecrets", { target: { type: "Server", id: server } }).data ??
|
||||
[];
|
||||
|
||||
const _env = env || "";
|
||||
|
||||
|
||||
@@ -40,7 +40,7 @@ const BuildVersionSelector = ({
|
||||
const [open, setOpen] = useState(false);
|
||||
const [search, setSearch] = useState("");
|
||||
const versions = useRead(
|
||||
"GetBuildVersions",
|
||||
"ListBuildVersions",
|
||||
{ build: buildId! },
|
||||
{ enabled: !!buildId }
|
||||
).data;
|
||||
|
||||
@@ -4,7 +4,6 @@ import { ReactNode, useState } from "react";
|
||||
import {
|
||||
AddExtraArgMenu,
|
||||
ConfigItem,
|
||||
ImageRegistryConfig,
|
||||
InputList,
|
||||
} from "@components/config/util";
|
||||
import { ImageConfig } from "./components/image";
|
||||
@@ -83,29 +82,29 @@ export const DeploymentConfig = ({
|
||||
image: (value, set) => (
|
||||
<ImageConfig image={value} set={set} disabled={disabled} />
|
||||
),
|
||||
image_registry: (registry, set) => {
|
||||
const image_type = update.image?.type ?? config.image?.type;
|
||||
const build_id: string | undefined =
|
||||
(image_type === "Build" &&
|
||||
(update.image?.params as any)?.build_id) ??
|
||||
(config.image?.params as any)?.build_id;
|
||||
const build_registry_type = useRead("GetBuild", {
|
||||
build: build_id!,
|
||||
}).data?.config?.image_registry?.type;
|
||||
const server_id = update.server_id ?? config.server_id;
|
||||
return (
|
||||
<ImageRegistryConfig
|
||||
registry={registry}
|
||||
setRegistry={(image_registry) => set({ image_registry })}
|
||||
type="Deployment"
|
||||
resource_id={server_id}
|
||||
disabled={disabled}
|
||||
registry_types={
|
||||
build_registry_type && ["None", build_registry_type]
|
||||
}
|
||||
/>
|
||||
);
|
||||
},
|
||||
// image_registry_account: (registry, set) => {
|
||||
// const image_type = update.image?.type ?? config.image?.type;
|
||||
// const build_id: string | undefined =
|
||||
// (image_type === "Build" &&
|
||||
// (update.image?.params as any)?.build_id) ??
|
||||
// (config.image?.params as any)?.build_id;
|
||||
// const build_registry_type = useRead("GetBuild", {
|
||||
// build: build_id!,
|
||||
// }).data?.config?.image_registry?.type;
|
||||
// const server_id = update.server_id ?? config.server_id;
|
||||
// return (
|
||||
// <ImageRegistryConfig
|
||||
// registry={registry}
|
||||
// setRegistry={(image_registry) => set({ image_registry })}
|
||||
// type="Deployment"
|
||||
// resource_id={server_id}
|
||||
// disabled={disabled}
|
||||
// registry_types={
|
||||
// build_registry_type && ["None", build_registry_type]
|
||||
// }
|
||||
// />
|
||||
// );
|
||||
// },
|
||||
restart: (value, set) => (
|
||||
<RestartModeSelector
|
||||
selected={value}
|
||||
|
||||
@@ -2,6 +2,7 @@ import { Config } from "@components/config";
|
||||
import {
|
||||
AccountSelectorConfig,
|
||||
ConfigItem,
|
||||
ProviderSelectorConfig,
|
||||
SystemCommand,
|
||||
} from "@components/config/util";
|
||||
import { useInvalidate, useRead, useWrite } from "@lib/hooks";
|
||||
@@ -54,26 +55,38 @@ export const RepoConfig = ({ id }: { id: string }) => {
|
||||
{
|
||||
label: "General",
|
||||
components: {
|
||||
repo: { placeholder: "Enter repo" },
|
||||
branch: { placeholder: "Enter branch" },
|
||||
commit: { placeholder: "Enter specific commit hash. Optional." },
|
||||
path: {
|
||||
placeholder: "Enter a specific clone path. Optional.",
|
||||
},
|
||||
github_account: (value, set) => {
|
||||
git_provider: (provider, set) => (
|
||||
<ProviderSelectorConfig
|
||||
account_type="git"
|
||||
selected={provider}
|
||||
disabled={disabled}
|
||||
onSelect={(git_provider) => set({ git_provider })}
|
||||
/>
|
||||
),
|
||||
git_https: { label: "Use Https" },
|
||||
git_account: (value, set) => {
|
||||
const server_id = update.server_id || config.server_id;
|
||||
return (
|
||||
<AccountSelectorConfig
|
||||
id={server_id}
|
||||
account_type="github"
|
||||
type={server_id ? "Server" : "None"}
|
||||
account_type="git"
|
||||
provider={update.git_provider ?? config.git_provider}
|
||||
selected={value}
|
||||
onSelect={(github_account) => set({ github_account })}
|
||||
onSelect={(git_account) => set({ git_account })}
|
||||
disabled={disabled}
|
||||
placeholder="None"
|
||||
/>
|
||||
);
|
||||
},
|
||||
repo: { placeholder: "Enter repo" },
|
||||
branch: { placeholder: "Enter branch" },
|
||||
commit: {
|
||||
placeholder: "Enter a specific commit hash. Optional.",
|
||||
},
|
||||
path: {
|
||||
placeholder: "Enter a specific clone path. Optional.",
|
||||
},
|
||||
},
|
||||
},
|
||||
{
|
||||
|
||||
@@ -1,5 +1,9 @@
|
||||
import { Config } from "@components/config";
|
||||
import { AccountSelectorConfig, ConfigItem } from "@components/config/util";
|
||||
import {
|
||||
AccountSelectorConfig,
|
||||
ConfigItem,
|
||||
ProviderSelectorConfig,
|
||||
} from "@components/config/util";
|
||||
import { useInvalidate, useRead, useWrite } from "@lib/hooks";
|
||||
import { Types } from "@monitor/client";
|
||||
import { ReactNode, useState } from "react";
|
||||
@@ -44,21 +48,33 @@ export const ResourceSyncConfig = ({
|
||||
{
|
||||
label: "General",
|
||||
components: {
|
||||
repo: { placeholder: "Enter repo" },
|
||||
branch: { placeholder: "Enter branch" },
|
||||
commit: { placeholder: "Enter specific commit hash. Optional." },
|
||||
github_account: (value, set) => {
|
||||
git_provider: (provider, set) => (
|
||||
<ProviderSelectorConfig
|
||||
account_type="git"
|
||||
selected={provider}
|
||||
disabled={disabled}
|
||||
onSelect={(git_provider) => set({ git_provider })}
|
||||
/>
|
||||
),
|
||||
git_https: { label: "Use Https" },
|
||||
git_account: (value, set) => {
|
||||
return (
|
||||
<AccountSelectorConfig
|
||||
account_type="github"
|
||||
account_type="git"
|
||||
type="None"
|
||||
provider={update.git_provider ?? config.git_provider}
|
||||
selected={value}
|
||||
onSelect={(github_account) => set({ github_account })}
|
||||
onSelect={(git_account) => set({ git_account })}
|
||||
disabled={disabled}
|
||||
placeholder="None"
|
||||
/>
|
||||
);
|
||||
},
|
||||
repo: { placeholder: "Enter repo" },
|
||||
branch: { placeholder: "Enter branch" },
|
||||
commit: {
|
||||
placeholder: "Enter a specific commit hash. Optional.",
|
||||
},
|
||||
resource_path: { placeholder: "./resources" },
|
||||
delete: { label: "Delete Unmatched Resources" },
|
||||
},
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
import { Config } from "@components/config";
|
||||
import { ConfigItem, InputList } from "@components/config/util";
|
||||
import { InputList } from "@components/config/util";
|
||||
import { TextUpdateMenu } from "@components/util";
|
||||
import { useRead, useWrite } from "@lib/hooks";
|
||||
import { cn } from "@lib/utils";
|
||||
@@ -160,21 +160,18 @@ export const AwsServerTemplateConfig = ({
|
||||
},
|
||||
{
|
||||
label: "User Data",
|
||||
labelHidden: true,
|
||||
components: {
|
||||
user_data: (user_data, set) => (
|
||||
<ConfigItem label="User Data">
|
||||
<TextUpdateMenu
|
||||
title="Update User Data"
|
||||
placeholder="Set User Data"
|
||||
value={user_data}
|
||||
onUpdate={(user_data) => set({ user_data })}
|
||||
triggerClassName="min-w-[300px] max-w-[400px]"
|
||||
disabled={disabled}
|
||||
/>
|
||||
</ConfigItem>
|
||||
),
|
||||
},
|
||||
contentHidden: true,
|
||||
actions: (
|
||||
<TextUpdateMenu
|
||||
title="Update User Data"
|
||||
placeholder="Set User Data"
|
||||
value={update.user_data ?? config.user_data}
|
||||
onUpdate={(user_data) => set({ ...update, user_data })}
|
||||
triggerClassName="min-w-[300px] max-w-[400px]"
|
||||
disabled={disabled}
|
||||
/>
|
||||
),
|
||||
components: {},
|
||||
},
|
||||
],
|
||||
}}
|
||||
|
||||
@@ -199,60 +199,16 @@ export const HetznerServerTemplateConfig = ({
|
||||
components: {
|
||||
volumes: (volumes, set) => {
|
||||
return (
|
||||
<div className="w-full flex justify-end">
|
||||
<div className="flex flex-col gap-4 w-full max-w-[400px]">
|
||||
{volumes?.map((_, index) => (
|
||||
<div
|
||||
key={index}
|
||||
className="flex items-center justify-between gap-4"
|
||||
>
|
||||
<HetznerVolumeDialog
|
||||
volumes={volumes}
|
||||
index={index}
|
||||
set={set}
|
||||
disabled={disabled}
|
||||
/>
|
||||
{!disabled && (
|
||||
<Button
|
||||
variant="secondary"
|
||||
disabled={disabled}
|
||||
onClick={() =>
|
||||
set({
|
||||
volumes: volumes.filter(
|
||||
(_, i) => i !== index
|
||||
),
|
||||
})
|
||||
}
|
||||
>
|
||||
<MinusCircle className="w-4 h-4" />
|
||||
</Button>
|
||||
)}
|
||||
</div>
|
||||
))}
|
||||
</div>
|
||||
</div>
|
||||
<HetznerVolumesConfig
|
||||
volumes={volumes ?? []}
|
||||
set={set}
|
||||
disabled={disabled}
|
||||
/>
|
||||
);
|
||||
},
|
||||
},
|
||||
},
|
||||
{
|
||||
label: "User Data",
|
||||
labelHidden: true,
|
||||
components: {
|
||||
user_data: (user_data, set) => (
|
||||
<ConfigItem label="User Data">
|
||||
<TextUpdateMenu
|
||||
title="Update User Data"
|
||||
placeholder="Set User Data"
|
||||
value={user_data}
|
||||
onUpdate={(user_data) => set({ user_data })}
|
||||
triggerClassName="min-w-[300px] max-w-[400px]"
|
||||
disabled={disabled}
|
||||
/>
|
||||
</ConfigItem>
|
||||
),
|
||||
},
|
||||
},
|
||||
|
||||
{
|
||||
label: "SSH Keys",
|
||||
contentHidden: (update.ssh_keys ?? config.ssh_keys)?.length === 0,
|
||||
@@ -286,6 +242,22 @@ export const HetznerServerTemplateConfig = ({
|
||||
),
|
||||
},
|
||||
},
|
||||
|
||||
{
|
||||
label: "User Data",
|
||||
contentHidden: true,
|
||||
actions: (
|
||||
<TextUpdateMenu
|
||||
title="Update User Data"
|
||||
placeholder="Set User Data"
|
||||
value={update.user_data ?? config.user_data}
|
||||
onUpdate={(user_data) => set({ ...update, user_data })}
|
||||
triggerClassName="min-w-[300px] max-w-[400px]"
|
||||
disabled={disabled}
|
||||
/>
|
||||
),
|
||||
components: {},
|
||||
},
|
||||
],
|
||||
}}
|
||||
/>
|
||||
@@ -398,6 +370,36 @@ const ServerTypeSelector = ({
|
||||
);
|
||||
};
|
||||
|
||||
const HetznerVolumesConfig = (params: {
|
||||
volumes: Types.HetznerVolumeSpecs[];
|
||||
set: (value: Partial<Types.HetznerServerTemplateConfig>) => void;
|
||||
disabled: boolean;
|
||||
}) => {
|
||||
return (
|
||||
<div className="w-full flex justify-end">
|
||||
<div className="flex flex-col gap-4 w-full max-w-[400px]">
|
||||
{params.volumes?.map((_, index) => (
|
||||
<div key={index} className="flex items-center justify-between gap-4">
|
||||
<HetznerVolumeDialog {...params} index={index} />
|
||||
{!params.disabled && (
|
||||
<Button
|
||||
variant="secondary"
|
||||
onClick={() =>
|
||||
params.set({
|
||||
volumes: params.volumes.filter((_, i) => i !== index),
|
||||
})
|
||||
}
|
||||
>
|
||||
<MinusCircle className="w-4 h-4" />
|
||||
</Button>
|
||||
)}
|
||||
</div>
|
||||
))}
|
||||
</div>
|
||||
</div>
|
||||
);
|
||||
};
|
||||
|
||||
const HetznerVolumeDialog = ({
|
||||
volumes,
|
||||
index,
|
||||
@@ -407,7 +409,7 @@ const HetznerVolumeDialog = ({
|
||||
volumes: Types.HetznerVolumeSpecs[];
|
||||
index: number;
|
||||
set: (value: Partial<Types.HetznerServerTemplateConfig>) => void;
|
||||
disabled?: boolean;
|
||||
disabled: boolean;
|
||||
}) => {
|
||||
const volume = volumes[index];
|
||||
const [open, setOpen] = useState(false);
|
||||
|
||||
@@ -106,7 +106,7 @@ const on_message = (
|
||||
["GetBuildsSummary"],
|
||||
["GetBuildMonthlyStats"],
|
||||
["GetBuild", { build: update.target.id }],
|
||||
["GetBuildVersions", { build: update.target.id }]
|
||||
["ListBuildVersions", { build: update.target.id }]
|
||||
);
|
||||
}
|
||||
|
||||
@@ -130,7 +130,6 @@ const on_message = (
|
||||
invalidate(
|
||||
["ListBuilders"],
|
||||
["GetBuildersSummary"],
|
||||
["GetBuilderAvailableAccounts", { builder: update.target.id }],
|
||||
["GetBuilder", { builder: update.target.id }]
|
||||
);
|
||||
}
|
||||
|
||||
@@ -45,7 +45,7 @@ const ResourceRow = ({ type }: { type: UsableResource }) => {
|
||||
return (
|
||||
<div className="flex gap-4">
|
||||
<Components.Dashboard />
|
||||
<div className="hidden lg:flex gap-4 w-full">
|
||||
<div className="hidden md:flex gap-4 w-full">
|
||||
<div className="py-2">
|
||||
<Separator orientation="vertical" />
|
||||
</div>
|
||||
|
||||
@@ -38,11 +38,8 @@ export const Variables = () => {
|
||||
}
|
||||
>(false);
|
||||
const [search, setSearch] = useState("");
|
||||
const { variables, secrets } = useRead("ListVariables", {}).data ?? {
|
||||
variables: [],
|
||||
secrets: [],
|
||||
};
|
||||
secrets.sort();
|
||||
const variables = useRead("ListVariables", {}).data ?? [];
|
||||
const secrets = useRead("ListSecrets", {}).data ?? [];
|
||||
const searchSplit = search?.toLowerCase().split(" ") || [];
|
||||
const filtered =
|
||||
variables?.filter((variable) => {
|
||||
|
||||
@@ -67,17 +67,19 @@ pub async fn pull(
|
||||
logs
|
||||
}
|
||||
|
||||
#[tracing::instrument(level = "debug", skip(github_token))]
|
||||
#[tracing::instrument(level = "debug", skip(access_token))]
|
||||
pub async fn clone<T>(
|
||||
clone_args: T,
|
||||
repo_dir: &Path,
|
||||
github_token: Option<String>,
|
||||
access_token: Option<String>,
|
||||
) -> anyhow::Result<Vec<Log>>
|
||||
where
|
||||
T: Into<CloneArgs> + std::fmt::Debug,
|
||||
{
|
||||
let CloneArgs {
|
||||
name,
|
||||
provider,
|
||||
https,
|
||||
repo,
|
||||
branch,
|
||||
commit,
|
||||
@@ -87,7 +89,11 @@ where
|
||||
..
|
||||
} = clone_args.into();
|
||||
|
||||
let repo = repo.as_ref().context("build has no repo attached")?;
|
||||
let provider = provider
|
||||
.as_ref()
|
||||
.context("resource has no provider attached")?;
|
||||
let repo =
|
||||
repo.as_ref().context("resource has no repo attached")?;
|
||||
let name = to_monitor_name(&name);
|
||||
|
||||
let repo_dir = match destination {
|
||||
@@ -96,12 +102,19 @@ where
|
||||
None => repo_dir.join(name),
|
||||
};
|
||||
|
||||
let mut logs =
|
||||
clone_inner(repo, &repo_dir, &branch, &commit, github_token)
|
||||
.await;
|
||||
let mut logs = clone_inner(
|
||||
provider,
|
||||
https,
|
||||
repo,
|
||||
&branch,
|
||||
&commit,
|
||||
&repo_dir,
|
||||
access_token,
|
||||
)
|
||||
.await;
|
||||
|
||||
if !all_logs_success(&logs) {
|
||||
tracing::warn!("repo at {repo_dir:?} failed to clone");
|
||||
tracing::warn!("failed to clone repo at {repo_dir:?}");
|
||||
return Ok(logs);
|
||||
}
|
||||
|
||||
@@ -158,10 +171,12 @@ where
|
||||
skip(destination, access_token)
|
||||
)]
|
||||
async fn clone_inner(
|
||||
provider: &str,
|
||||
https: bool,
|
||||
repo: &str,
|
||||
destination: &Path,
|
||||
branch: &Option<String>,
|
||||
commit: &Option<String>,
|
||||
destination: &Path,
|
||||
access_token: Option<String>,
|
||||
) -> Vec<Log> {
|
||||
let _ = std::fs::remove_dir_all(destination);
|
||||
@@ -173,8 +188,9 @@ async fn clone_inner(
|
||||
Some(branch) => format!(" -b {branch}"),
|
||||
None => String::new(),
|
||||
};
|
||||
let protocol = if https { "https" } else { "http" };
|
||||
let repo_url =
|
||||
format!("https://{access_token_at}github.com/{repo}.git");
|
||||
format!("{protocol}://{access_token_at}{provider}/{repo}.git");
|
||||
let command =
|
||||
format!("git clone {repo_url} {}{branch}", destination.display());
|
||||
let start_ts = monitor_timestamp();
|
||||
|
||||
@@ -4,9 +4,11 @@ A tool to build and deploy software across many servers. [docs](https://mbecker2
|
||||
|
||||
Docs for periphery setup script can be found in [scripts/readme.md](https://github.com/mbecker20/monitor/blob/main/scripts/readme.md).
|
||||
|
||||
## Changelog
|
||||
## Links
|
||||
|
||||
View the [changelog](https://github.com/mbecker20/monitor/blob/main/changelog.md)
|
||||
[roadmap](https://github.com/mbecker20/monitor/blob/main/roadmap.md)
|
||||
[changelog](https://github.com/mbecker20/monitor/blob/main/changelog.md)
|
||||
[migrator](https://github.com/mbecker20/monitor/blob/main/bin/migrator/README.md)
|
||||
|
||||
## Screenshots
|
||||
|
||||
|
||||
13
roadmap.md
Normal file
13
roadmap.md
Normal file
@@ -0,0 +1,13 @@
|
||||
# Roadmap
|
||||
|
||||
In order to clarify the goals and invite community participation in the direction of the project, this document will serve as a roadmap for upcoming features / releases.
|
||||
|
||||
If you have an idea for Monitor, feel free to open an issue beginning with the `[Request]` tag. The community is also encouraged to open PRs fulfilling the goals of any planned release.
|
||||
|
||||
## Release plans
|
||||
|
||||
- **v1.12**: Support any git provider / docker registry (supports self-hosted providers like Gitea) ✅
|
||||
- **v1.13**: Support "Compose" resource - Paste in a docker compose file and manage it like a Portainer "Stack"
|
||||
- **v1.14+**: Support "Cluster" resource - Manage Kubernetes cluster, can attach deployments to "Cluster" (in addition to existing "Server")
|
||||
|
||||
**Note. The specific versions associated with these features are not final.**
|
||||
Reference in New Issue
Block a user