forked from github-starred/komodo
Compare commits
1 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
8ee270d045 |
106
Cargo.lock
generated
106
Cargo.lock
generated
@@ -41,7 +41,7 @@ dependencies = [
|
||||
|
||||
[[package]]
|
||||
name = "alerter"
|
||||
version = "1.15.3"
|
||||
version = "1.15.4"
|
||||
dependencies = [
|
||||
"anyhow",
|
||||
"axum",
|
||||
@@ -201,9 +201,9 @@ checksum = "0c4b4d0bd25bd0b74681c0ad21497610ce1b7c91b1022cd21c80c6fbdd9476b0"
|
||||
|
||||
[[package]]
|
||||
name = "aws-config"
|
||||
version = "1.5.7"
|
||||
version = "1.5.8"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "8191fb3091fa0561d1379ef80333c3c7191c6f0435d986e85821bcf7acbd1126"
|
||||
checksum = "7198e6f03240fdceba36656d8be440297b6b82270325908c7381f37d826a74f6"
|
||||
dependencies = [
|
||||
"aws-credential-types",
|
||||
"aws-runtime",
|
||||
@@ -268,9 +268,9 @@ dependencies = [
|
||||
|
||||
[[package]]
|
||||
name = "aws-sdk-ec2"
|
||||
version = "1.75.0"
|
||||
version = "1.77.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "f6787d920877cca6a4ee3953093f6a47cefe26de95a4f7b3681c5850bfe657b4"
|
||||
checksum = "4bb6f841697b994ec3a020c560b52693bc9fcb7b9c69210088ab56e03df23b5e"
|
||||
dependencies = [
|
||||
"aws-credential-types",
|
||||
"aws-runtime",
|
||||
@@ -292,9 +292,9 @@ dependencies = [
|
||||
|
||||
[[package]]
|
||||
name = "aws-sdk-sso"
|
||||
version = "1.44.0"
|
||||
version = "1.45.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "0b90cfe6504115e13c41d3ea90286ede5aa14da294f3fe077027a6e83850843c"
|
||||
checksum = "e33ae899566f3d395cbf42858e433930682cc9c1889fa89318896082fef45efb"
|
||||
dependencies = [
|
||||
"aws-credential-types",
|
||||
"aws-runtime",
|
||||
@@ -314,9 +314,9 @@ dependencies = [
|
||||
|
||||
[[package]]
|
||||
name = "aws-sdk-ssooidc"
|
||||
version = "1.45.0"
|
||||
version = "1.46.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "167c0fad1f212952084137308359e8e4c4724d1c643038ce163f06de9662c1d0"
|
||||
checksum = "f39c09e199ebd96b9f860b0fce4b6625f211e064ad7c8693b72ecf7ef03881e0"
|
||||
dependencies = [
|
||||
"aws-credential-types",
|
||||
"aws-runtime",
|
||||
@@ -336,9 +336,9 @@ dependencies = [
|
||||
|
||||
[[package]]
|
||||
name = "aws-sdk-sts"
|
||||
version = "1.44.0"
|
||||
version = "1.45.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "2cb5f98188ec1435b68097daa2a37d74b9d17c9caa799466338a8d1544e71b9d"
|
||||
checksum = "3d95f93a98130389eb6233b9d615249e543f6c24a68ca1f109af9ca5164a8765"
|
||||
dependencies = [
|
||||
"aws-credential-types",
|
||||
"aws-runtime",
|
||||
@@ -887,9 +887,9 @@ dependencies = [
|
||||
|
||||
[[package]]
|
||||
name = "clap"
|
||||
version = "4.5.19"
|
||||
version = "4.5.20"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "7be5744db7978a28d9df86a214130d106a89ce49644cbc4e3f0c22c3fba30615"
|
||||
checksum = "b97f376d85a664d5837dbae44bf546e6477a679ff6610010f17276f686d867e8"
|
||||
dependencies = [
|
||||
"clap_builder",
|
||||
"clap_derive",
|
||||
@@ -897,9 +897,9 @@ dependencies = [
|
||||
|
||||
[[package]]
|
||||
name = "clap_builder"
|
||||
version = "4.5.19"
|
||||
version = "4.5.20"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "a5fbc17d3ef8278f55b282b2a2e75ae6f6c7d4bb70ed3d0382375104bfafdb4b"
|
||||
checksum = "19bc80abd44e4bed93ca373a0704ccbd1b710dc5749406201bb018272808dc54"
|
||||
dependencies = [
|
||||
"anstream",
|
||||
"anstyle",
|
||||
@@ -943,7 +943,7 @@ dependencies = [
|
||||
|
||||
[[package]]
|
||||
name = "command"
|
||||
version = "1.15.3"
|
||||
version = "1.15.4"
|
||||
dependencies = [
|
||||
"komodo_client",
|
||||
"run_command",
|
||||
@@ -1149,18 +1149,18 @@ dependencies = [
|
||||
|
||||
[[package]]
|
||||
name = "derive_builder"
|
||||
version = "0.20.1"
|
||||
version = "0.20.2"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "cd33f37ee6a119146a1781d3356a7c26028f83d779b2e04ecd45fdc75c76877b"
|
||||
checksum = "507dfb09ea8b7fa618fcf76e953f4f5e192547945816d5358edffe39f6f94947"
|
||||
dependencies = [
|
||||
"derive_builder_macro",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "derive_builder_core"
|
||||
version = "0.20.1"
|
||||
version = "0.20.2"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "7431fa049613920234f22c47fdc33e6cf3ee83067091ea4277a3f8c4587aae38"
|
||||
checksum = "2d5bcf7b024d6835cfb3d473887cd966994907effbe9227e8c8219824d06c4e8"
|
||||
dependencies = [
|
||||
"darling",
|
||||
"proc-macro2",
|
||||
@@ -1170,9 +1170,9 @@ dependencies = [
|
||||
|
||||
[[package]]
|
||||
name = "derive_builder_macro"
|
||||
version = "0.20.1"
|
||||
version = "0.20.2"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "4abae7035bf79b9877b779505d8cf3749285b80c43941eda66604841889451dc"
|
||||
checksum = "ab63b0e2bf4d5928aff72e83a7dace85d7bba5fe12dcc3c5a572d78caffd3f3c"
|
||||
dependencies = [
|
||||
"derive_builder_core",
|
||||
"syn 2.0.77",
|
||||
@@ -1355,7 +1355,7 @@ dependencies = [
|
||||
|
||||
[[package]]
|
||||
name = "environment_file"
|
||||
version = "1.15.3"
|
||||
version = "1.15.4"
|
||||
dependencies = [
|
||||
"thiserror",
|
||||
]
|
||||
@@ -1439,7 +1439,7 @@ dependencies = [
|
||||
|
||||
[[package]]
|
||||
name = "formatting"
|
||||
version = "1.15.3"
|
||||
version = "1.15.4"
|
||||
dependencies = [
|
||||
"serror",
|
||||
]
|
||||
@@ -1452,9 +1452,9 @@ checksum = "e6d5a32815ae3f33302d95fdcb2ce17862f8c65363dcfd29360480ba1001fc9c"
|
||||
|
||||
[[package]]
|
||||
name = "futures"
|
||||
version = "0.3.30"
|
||||
version = "0.3.31"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "645c6916888f6cb6350d2550b80fb63e734897a8498abe35cfb732b6487804b0"
|
||||
checksum = "65bc07b1a8bc7c85c5f2e110c476c7389b4554ba72af57d8445ea63a576b0876"
|
||||
dependencies = [
|
||||
"futures-channel",
|
||||
"futures-core",
|
||||
@@ -1467,9 +1467,9 @@ dependencies = [
|
||||
|
||||
[[package]]
|
||||
name = "futures-channel"
|
||||
version = "0.3.30"
|
||||
version = "0.3.31"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "eac8f7d7865dcb88bd4373ab671c8cf4508703796caa2b1985a9ca867b3fcb78"
|
||||
checksum = "2dff15bf788c671c1934e366d07e30c1814a8ef514e1af724a602e8a2fbe1b10"
|
||||
dependencies = [
|
||||
"futures-core",
|
||||
"futures-sink",
|
||||
@@ -1477,15 +1477,15 @@ dependencies = [
|
||||
|
||||
[[package]]
|
||||
name = "futures-core"
|
||||
version = "0.3.30"
|
||||
version = "0.3.31"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "dfc6580bb841c5a68e9ef15c77ccc837b40a7504914d52e47b8b0e9bbda25a1d"
|
||||
checksum = "05f29059c0c2090612e8d742178b0580d2dc940c837851ad723096f87af6663e"
|
||||
|
||||
[[package]]
|
||||
name = "futures-executor"
|
||||
version = "0.3.30"
|
||||
version = "0.3.31"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "a576fc72ae164fca6b9db127eaa9a9dda0d61316034f33a0a0d4eda41f02b01d"
|
||||
checksum = "1e28d1d997f585e54aebc3f97d39e72338912123a67330d723fdbb564d646c9f"
|
||||
dependencies = [
|
||||
"futures-core",
|
||||
"futures-task",
|
||||
@@ -1494,15 +1494,15 @@ dependencies = [
|
||||
|
||||
[[package]]
|
||||
name = "futures-io"
|
||||
version = "0.3.30"
|
||||
version = "0.3.31"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "a44623e20b9681a318efdd71c299b6b222ed6f231972bfe2f224ebad6311f0c1"
|
||||
checksum = "9e5c1b78ca4aae1ac06c48a526a655760685149f0d465d21f37abfe57ce075c6"
|
||||
|
||||
[[package]]
|
||||
name = "futures-macro"
|
||||
version = "0.3.30"
|
||||
version = "0.3.31"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "87750cf4b7a4c0625b1529e4c543c2182106e4dedc60a2a6455e00d212c489ac"
|
||||
checksum = "162ee34ebcb7c64a8abebc059ce0fee27c2262618d7b60ed8faf72fef13c3650"
|
||||
dependencies = [
|
||||
"proc-macro2",
|
||||
"quote",
|
||||
@@ -1511,21 +1511,21 @@ dependencies = [
|
||||
|
||||
[[package]]
|
||||
name = "futures-sink"
|
||||
version = "0.3.30"
|
||||
version = "0.3.31"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "9fb8e00e87438d937621c1c6269e53f536c14d3fbd6a042bb24879e57d474fb5"
|
||||
checksum = "e575fab7d1e0dcb8d0c7bcf9a63ee213816ab51902e6d244a95819acacf1d4f7"
|
||||
|
||||
[[package]]
|
||||
name = "futures-task"
|
||||
version = "0.3.30"
|
||||
version = "0.3.31"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "38d84fa142264698cdce1a9f9172cf383a0c82de1bddcf3092901442c4097004"
|
||||
checksum = "f90f7dce0722e95104fcb095585910c0977252f286e354b5e3bd38902cd99988"
|
||||
|
||||
[[package]]
|
||||
name = "futures-util"
|
||||
version = "0.3.30"
|
||||
version = "0.3.31"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "3d6401deb83407ab3da39eba7e33987a73c3df0c82b4bb5813ee871c19c41d48"
|
||||
checksum = "9fa08315bb612088cc391249efdc3bc77536f16c91f6cf495e6fbe85b20a4a81"
|
||||
dependencies = [
|
||||
"futures-channel",
|
||||
"futures-core",
|
||||
@@ -1571,7 +1571,7 @@ checksum = "40ecd4077b5ae9fd2e9e169b102c6c330d0605168eb0e8bf79952b256dbefffd"
|
||||
|
||||
[[package]]
|
||||
name = "git"
|
||||
version = "1.15.3"
|
||||
version = "1.15.4"
|
||||
dependencies = [
|
||||
"anyhow",
|
||||
"command",
|
||||
@@ -2192,7 +2192,7 @@ dependencies = [
|
||||
|
||||
[[package]]
|
||||
name = "komodo_cli"
|
||||
version = "1.15.3"
|
||||
version = "1.15.4"
|
||||
dependencies = [
|
||||
"anyhow",
|
||||
"clap",
|
||||
@@ -2208,7 +2208,7 @@ dependencies = [
|
||||
|
||||
[[package]]
|
||||
name = "komodo_client"
|
||||
version = "1.15.3"
|
||||
version = "1.15.4"
|
||||
dependencies = [
|
||||
"anyhow",
|
||||
"async_timing_util",
|
||||
@@ -2239,7 +2239,7 @@ dependencies = [
|
||||
|
||||
[[package]]
|
||||
name = "komodo_core"
|
||||
version = "1.15.3"
|
||||
version = "1.15.4"
|
||||
dependencies = [
|
||||
"anyhow",
|
||||
"async_timing_util",
|
||||
@@ -2296,7 +2296,7 @@ dependencies = [
|
||||
|
||||
[[package]]
|
||||
name = "komodo_periphery"
|
||||
version = "1.15.3"
|
||||
version = "1.15.4"
|
||||
dependencies = [
|
||||
"anyhow",
|
||||
"async_timing_util",
|
||||
@@ -2383,7 +2383,7 @@ dependencies = [
|
||||
|
||||
[[package]]
|
||||
name = "logger"
|
||||
version = "1.15.3"
|
||||
version = "1.15.4"
|
||||
dependencies = [
|
||||
"anyhow",
|
||||
"komodo_client",
|
||||
@@ -2447,7 +2447,7 @@ dependencies = [
|
||||
|
||||
[[package]]
|
||||
name = "migrator"
|
||||
version = "1.15.3"
|
||||
version = "1.15.4"
|
||||
dependencies = [
|
||||
"anyhow",
|
||||
"dotenvy",
|
||||
@@ -3102,7 +3102,7 @@ checksum = "e3148f5046208a5d56bcfc03053e3ca6334e51da8dfb19b6cdc8b306fae3283e"
|
||||
|
||||
[[package]]
|
||||
name = "periphery_client"
|
||||
version = "1.15.3"
|
||||
version = "1.15.4"
|
||||
dependencies = [
|
||||
"anyhow",
|
||||
"komodo_client",
|
||||
@@ -4250,9 +4250,9 @@ dependencies = [
|
||||
|
||||
[[package]]
|
||||
name = "sysinfo"
|
||||
version = "0.31.4"
|
||||
version = "0.32.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "355dbe4f8799b304b05e1b0f05fc59b2a18d36645cf169607da45bde2f69a1be"
|
||||
checksum = "e3b5ae3f4f7d64646c46c4cae4e3f01d1c5d255c7406fdd7c7f999a94e488791"
|
||||
dependencies = [
|
||||
"core-foundation-sys",
|
||||
"libc",
|
||||
@@ -4880,7 +4880,7 @@ checksum = "8ecb6da28b8a351d773b68d5825ac39017e680750f980f3a1a85cd8dd28a47c1"
|
||||
|
||||
[[package]]
|
||||
name = "update_logger"
|
||||
version = "1.15.3"
|
||||
version = "1.15.4"
|
||||
dependencies = [
|
||||
"anyhow",
|
||||
"komodo_client",
|
||||
|
||||
16
Cargo.toml
16
Cargo.toml
@@ -3,7 +3,7 @@ resolver = "2"
|
||||
members = ["bin/*", "lib/*", "client/core/rs", "client/periphery/rs"]
|
||||
|
||||
[workspace.package]
|
||||
version = "1.15.3"
|
||||
version = "1.15.4"
|
||||
edition = "2021"
|
||||
authors = ["mbecker20 <becker.maxh@gmail.com>"]
|
||||
license = "GPL-3.0-or-later"
|
||||
@@ -44,8 +44,8 @@ svi = "1.0.1"
|
||||
reqwest = { version = "0.12.8", features = ["json"] }
|
||||
tokio = { version = "1.38.1", features = ["full"] }
|
||||
tokio-util = "0.7.12"
|
||||
futures = "0.3.30"
|
||||
futures-util = "0.3.30"
|
||||
futures = "0.3.31"
|
||||
futures-util = "0.3.31"
|
||||
|
||||
# SERVER
|
||||
axum-extra = { version = "0.9.4", features = ["typed-header"] }
|
||||
@@ -76,7 +76,7 @@ opentelemetry = "0.25.0"
|
||||
tracing = "0.1.40"
|
||||
|
||||
# CONFIG
|
||||
clap = { version = "4.5.19", features = ["derive"] }
|
||||
clap = { version = "4.5.20", features = ["derive"] }
|
||||
dotenvy = "0.15.7"
|
||||
envy = "0.4.2"
|
||||
|
||||
@@ -95,14 +95,14 @@ hex = "0.4.3"
|
||||
|
||||
# SYSTEM
|
||||
bollard = "0.17.1"
|
||||
sysinfo = "0.31.4"
|
||||
sysinfo = "0.32.0"
|
||||
|
||||
# CLOUD
|
||||
aws-config = "1.5.7"
|
||||
aws-sdk-ec2 = "1.75.0"
|
||||
aws-config = "1.5.8"
|
||||
aws-sdk-ec2 = "1.77.0"
|
||||
|
||||
# MISC
|
||||
derive_builder = "0.20.1"
|
||||
derive_builder = "0.20.2"
|
||||
typeshare = "1.0.3"
|
||||
octorust = "0.7.0"
|
||||
dashmap = "6.1.0"
|
||||
|
||||
@@ -64,7 +64,7 @@ impl Resolve<RunBuild, (User, Update)> for State {
|
||||
PermissionLevel::Execute,
|
||||
)
|
||||
.await?;
|
||||
let vars_and_secrets = get_variables_and_secrets().await?;
|
||||
let mut vars_and_secrets = get_variables_and_secrets().await?;
|
||||
|
||||
if build.config.builder_id.is_empty() {
|
||||
return Err(anyhow!("Must attach builder to RunBuild"));
|
||||
@@ -85,6 +85,14 @@ impl Resolve<RunBuild, (User, Update)> for State {
|
||||
update.version = build.config.version;
|
||||
update_update(update.clone()).await?;
|
||||
|
||||
// Add the $VERSION to variables. Use with [[$VERSION]]
|
||||
if !vars_and_secrets.variables.contains_key("$VERSION") {
|
||||
vars_and_secrets.variables.insert(
|
||||
String::from("$VERSION"),
|
||||
build.config.version.to_string(),
|
||||
);
|
||||
}
|
||||
|
||||
let git_token = git_token(
|
||||
&build.config.git_provider,
|
||||
&build.config.git_account,
|
||||
@@ -171,7 +179,6 @@ impl Resolve<RunBuild, (User, Update)> for State {
|
||||
};
|
||||
|
||||
// CLONE REPO
|
||||
|
||||
let secret_replacers = if !build.config.skip_secret_interp {
|
||||
// Interpolate variables / secrets into pre build command
|
||||
let mut global_replacers = HashSet::new();
|
||||
|
||||
@@ -88,7 +88,11 @@ const MAX_LOG_LENGTH: u64 = 5000;
|
||||
impl Resolve<GetDeploymentLog, User> for State {
|
||||
async fn resolve(
|
||||
&self,
|
||||
GetDeploymentLog { deployment, tail }: GetDeploymentLog,
|
||||
GetDeploymentLog {
|
||||
deployment,
|
||||
tail,
|
||||
timestamps,
|
||||
}: GetDeploymentLog,
|
||||
user: User,
|
||||
) -> anyhow::Result<Log> {
|
||||
let Deployment {
|
||||
@@ -109,6 +113,7 @@ impl Resolve<GetDeploymentLog, User> for State {
|
||||
.request(api::container::GetContainerLog {
|
||||
name,
|
||||
tail: cmp::min(tail, MAX_LOG_LENGTH),
|
||||
timestamps,
|
||||
})
|
||||
.await
|
||||
.context("failed at call to periphery")
|
||||
@@ -123,6 +128,7 @@ impl Resolve<SearchDeploymentLog, User> for State {
|
||||
terms,
|
||||
combinator,
|
||||
invert,
|
||||
timestamps,
|
||||
}: SearchDeploymentLog,
|
||||
user: User,
|
||||
) -> anyhow::Result<Log> {
|
||||
@@ -146,6 +152,7 @@ impl Resolve<SearchDeploymentLog, User> for State {
|
||||
terms,
|
||||
combinator,
|
||||
invert,
|
||||
timestamps,
|
||||
})
|
||||
.await
|
||||
.context("failed at call to periphery")
|
||||
|
||||
@@ -404,6 +404,7 @@ impl Resolve<GetContainerLog, User> for State {
|
||||
server,
|
||||
container,
|
||||
tail,
|
||||
timestamps,
|
||||
}: GetContainerLog,
|
||||
user: User,
|
||||
) -> anyhow::Result<Log> {
|
||||
@@ -417,6 +418,7 @@ impl Resolve<GetContainerLog, User> for State {
|
||||
.request(periphery::container::GetContainerLog {
|
||||
name: container,
|
||||
tail: cmp::min(tail, MAX_LOG_LENGTH),
|
||||
timestamps,
|
||||
})
|
||||
.await
|
||||
.context("failed at call to periphery")
|
||||
@@ -432,6 +434,7 @@ impl Resolve<SearchContainerLog, User> for State {
|
||||
terms,
|
||||
combinator,
|
||||
invert,
|
||||
timestamps,
|
||||
}: SearchContainerLog,
|
||||
user: User,
|
||||
) -> anyhow::Result<Log> {
|
||||
@@ -447,6 +450,7 @@ impl Resolve<SearchContainerLog, User> for State {
|
||||
terms,
|
||||
combinator,
|
||||
invert,
|
||||
timestamps,
|
||||
})
|
||||
.await
|
||||
.context("failed at call to periphery")
|
||||
|
||||
@@ -70,6 +70,7 @@ impl Resolve<GetStackServiceLog, User> for State {
|
||||
stack,
|
||||
service,
|
||||
tail,
|
||||
timestamps,
|
||||
}: GetStackServiceLog,
|
||||
user: User,
|
||||
) -> anyhow::Result<GetStackServiceLogResponse> {
|
||||
@@ -85,6 +86,7 @@ impl Resolve<GetStackServiceLog, User> for State {
|
||||
project: stack.project_name(false),
|
||||
service,
|
||||
tail,
|
||||
timestamps,
|
||||
})
|
||||
.await
|
||||
.context("failed to get stack service log from periphery")
|
||||
@@ -100,6 +102,7 @@ impl Resolve<SearchStackServiceLog, User> for State {
|
||||
terms,
|
||||
combinator,
|
||||
invert,
|
||||
timestamps,
|
||||
}: SearchStackServiceLog,
|
||||
user: User,
|
||||
) -> anyhow::Result<SearchStackServiceLogResponse> {
|
||||
@@ -117,6 +120,7 @@ impl Resolve<SearchStackServiceLog, User> for State {
|
||||
terms,
|
||||
combinator,
|
||||
invert,
|
||||
timestamps,
|
||||
})
|
||||
.await
|
||||
.context("failed to get stack service log from periphery")
|
||||
|
||||
@@ -3,8 +3,9 @@ use std::{str::FromStr, time::Duration};
|
||||
use anyhow::{anyhow, Context};
|
||||
use futures::future::join_all;
|
||||
use komodo_client::{
|
||||
api::write::CreateServer,
|
||||
api::write::{CreateBuilder, CreateServer},
|
||||
entities::{
|
||||
builder::{PartialBuilderConfig, PartialServerBuilderConfig},
|
||||
komodo_timestamp,
|
||||
permission::{Permission, PermissionLevel, UserTarget},
|
||||
server::{PartialServerConfig, Server},
|
||||
@@ -280,8 +281,8 @@ async fn startup_open_alert_cleanup() {
|
||||
}
|
||||
}
|
||||
|
||||
/// Ensures a default server exists with the defined address
|
||||
pub async fn ensure_first_server() {
|
||||
/// Ensures a default server / builder exists with the defined address
|
||||
pub async fn ensure_first_server_and_builder() {
|
||||
let first_server = &core_config().first_server;
|
||||
if first_server.is_empty() {
|
||||
return;
|
||||
@@ -295,23 +296,49 @@ pub async fn ensure_first_server() {
|
||||
else {
|
||||
return;
|
||||
};
|
||||
if server.is_some() {
|
||||
return;
|
||||
}
|
||||
let server = if let Some(server) = server {
|
||||
server
|
||||
} else {
|
||||
match State
|
||||
.resolve(
|
||||
CreateServer {
|
||||
name: format!("server-{}", random_string(5)),
|
||||
config: PartialServerConfig {
|
||||
address: Some(first_server.to_string()),
|
||||
enabled: Some(true),
|
||||
..Default::default()
|
||||
},
|
||||
},
|
||||
system_user().to_owned(),
|
||||
)
|
||||
.await
|
||||
{
|
||||
Ok(server) => server,
|
||||
Err(e) => {
|
||||
error!("Failed to initialize 'first_server'. Failed to CreateServer. {e:?}");
|
||||
return;
|
||||
}
|
||||
}
|
||||
};
|
||||
let Ok(None) = db.builders
|
||||
.find_one(Document::new()).await
|
||||
.inspect_err(|e| error!("Failed to initialize 'first_builder'. Failed to query db. {e:?}")) else {
|
||||
return;
|
||||
};
|
||||
if let Err(e) = State
|
||||
.resolve(
|
||||
CreateServer {
|
||||
name: format!("server-{}", random_string(5)),
|
||||
config: PartialServerConfig {
|
||||
address: Some(first_server.to_string()),
|
||||
enabled: Some(true),
|
||||
..Default::default()
|
||||
},
|
||||
CreateBuilder {
|
||||
name: String::from("local"),
|
||||
config: PartialBuilderConfig::Server(
|
||||
PartialServerBuilderConfig {
|
||||
server_id: Some(server.id),
|
||||
},
|
||||
),
|
||||
},
|
||||
system_user().to_owned(),
|
||||
)
|
||||
.await
|
||||
{
|
||||
error!("Failed to initialize 'first_server'. Failed to CreateServer. {e:?}");
|
||||
error!("Failed to initialize 'first_builder'. Failed to CreateBuilder. {e:?}");
|
||||
}
|
||||
}
|
||||
|
||||
@@ -44,7 +44,7 @@ async fn app() -> anyhow::Result<()> {
|
||||
);
|
||||
tokio::join!(
|
||||
// Maybe initialize first server
|
||||
helpers::ensure_first_server(),
|
||||
helpers::ensure_first_server_and_builder(),
|
||||
// Cleanup open updates / invalid alerts
|
||||
helpers::startup_cleanup(),
|
||||
);
|
||||
|
||||
@@ -514,8 +514,7 @@ pub async fn create<T: KomodoResource>(
|
||||
.await
|
||||
.context("Failed to list all resources for duplicate name check")?
|
||||
.into_iter()
|
||||
.find(|r| r.name == name)
|
||||
.is_some()
|
||||
.any(|r| r.name == name)
|
||||
{
|
||||
return Err(anyhow!("Must provide unique name for resource."));
|
||||
}
|
||||
|
||||
@@ -274,7 +274,7 @@ impl ToToml for Build {
|
||||
config
|
||||
.into_iter()
|
||||
.map(|(key, value)| match key.as_str() {
|
||||
"builder_id" => return Ok((String::from("builder"), value)),
|
||||
"builder_id" => Ok((String::from("builder"), value)),
|
||||
"version" => {
|
||||
match (
|
||||
&resource.config.version,
|
||||
|
||||
@@ -87,10 +87,18 @@ impl Resolve<build::Build> for State {
|
||||
// Get command parts
|
||||
let image_name =
|
||||
get_image_name(&build).context("failed to make image name")?;
|
||||
let build_args = parse_build_args(
|
||||
&environment_vars_from_str(build_args)
|
||||
.context("Invalid build_args")?,
|
||||
);
|
||||
|
||||
// Add VERSION to build args (if not already there)
|
||||
let mut build_args = environment_vars_from_str(build_args)
|
||||
.context("Invalid build_args")?;
|
||||
if !build_args.iter().any(|a| a.variable == "VERSION") {
|
||||
build_args.push(EnvironmentVar {
|
||||
variable: String::from("VERSION"),
|
||||
value: build.config.version.to_string(),
|
||||
});
|
||||
}
|
||||
let build_args = parse_build_args(&build_args);
|
||||
|
||||
let secret_args = environment_vars_from_str(secret_args)
|
||||
.context("Invalid secret_args")?;
|
||||
let _secret_args =
|
||||
@@ -110,13 +118,16 @@ impl Resolve<build::Build> for State {
|
||||
|
||||
// Construct command
|
||||
let command = format!(
|
||||
"cd {} && docker{buildx} build{build_args}{_secret_args}{extra_args}{labels}{image_tags} -f {dockerfile_path} .{push_command}",
|
||||
build_dir.display()
|
||||
"docker{buildx} build{build_args}{_secret_args}{extra_args}{labels}{image_tags} -f {dockerfile_path} .{push_command}",
|
||||
);
|
||||
|
||||
if *skip_secret_interp {
|
||||
let build_log =
|
||||
run_komodo_command("docker build", command).await;
|
||||
let build_log = run_komodo_command(
|
||||
"docker build",
|
||||
build_dir.as_ref(),
|
||||
command,
|
||||
)
|
||||
.await;
|
||||
logs.push(build_log);
|
||||
} else {
|
||||
// Interpolate any missing secrets
|
||||
@@ -131,8 +142,12 @@ impl Resolve<build::Build> for State {
|
||||
)?;
|
||||
replacers.extend(core_replacers);
|
||||
|
||||
let mut build_log =
|
||||
run_komodo_command("docker build", command).await;
|
||||
let mut build_log = run_komodo_command(
|
||||
"docker build",
|
||||
build_dir.as_ref(),
|
||||
command,
|
||||
)
|
||||
.await;
|
||||
build_log.command =
|
||||
svi::replace_in_string(&build_log.command, &replacers);
|
||||
build_log.stdout =
|
||||
@@ -229,7 +244,7 @@ impl Resolve<PruneBuilders> for State {
|
||||
_: (),
|
||||
) -> anyhow::Result<Log> {
|
||||
let command = String::from("docker builder prune -a -f");
|
||||
Ok(run_komodo_command("prune builders", command).await)
|
||||
Ok(run_komodo_command("prune builders", None, command).await)
|
||||
}
|
||||
}
|
||||
|
||||
@@ -243,6 +258,6 @@ impl Resolve<PruneBuildx> for State {
|
||||
_: (),
|
||||
) -> anyhow::Result<Log> {
|
||||
let command = String::from("docker buildx prune -a -f");
|
||||
Ok(run_komodo_command("prune buildx", command).await)
|
||||
Ok(run_komodo_command("prune buildx", None, command).await)
|
||||
}
|
||||
}
|
||||
|
||||
@@ -28,6 +28,7 @@ impl Resolve<ListComposeProjects, ()> for State {
|
||||
let docker_compose = docker_compose();
|
||||
let res = run_komodo_command(
|
||||
"list projects",
|
||||
None,
|
||||
format!("{docker_compose} ls --all --format json"),
|
||||
)
|
||||
.await;
|
||||
@@ -88,14 +89,17 @@ impl Resolve<GetComposeServiceLog> for State {
|
||||
project,
|
||||
service,
|
||||
tail,
|
||||
timestamps,
|
||||
}: GetComposeServiceLog,
|
||||
_: (),
|
||||
) -> anyhow::Result<Log> {
|
||||
let docker_compose = docker_compose();
|
||||
let timestamps =
|
||||
timestamps.then_some(" --timestamps").unwrap_or_default();
|
||||
let command = format!(
|
||||
"{docker_compose} -p {project} logs {service} --tail {tail}"
|
||||
"{docker_compose} -p {project} logs {service} --tail {tail}{timestamps}"
|
||||
);
|
||||
Ok(run_komodo_command("get stack log", command).await)
|
||||
Ok(run_komodo_command("get stack log", None, command).await)
|
||||
}
|
||||
}
|
||||
|
||||
@@ -113,13 +117,16 @@ impl Resolve<GetComposeServiceLogSearch> for State {
|
||||
terms,
|
||||
combinator,
|
||||
invert,
|
||||
timestamps,
|
||||
}: GetComposeServiceLogSearch,
|
||||
_: (),
|
||||
) -> anyhow::Result<Log> {
|
||||
let docker_compose = docker_compose();
|
||||
let grep = log_grep(&terms, combinator, invert);
|
||||
let command = format!("{docker_compose} -p {project} logs {service} --tail 5000 2>&1 | {grep}");
|
||||
Ok(run_komodo_command("get stack log grep", command).await)
|
||||
let timestamps =
|
||||
timestamps.then_some(" --timestamps").unwrap_or_default();
|
||||
let command = format!("{docker_compose} -p {project} logs {service} --tail 5000{timestamps} 2>&1 | {grep}");
|
||||
Ok(run_komodo_command("get stack log grep", None, command).await)
|
||||
}
|
||||
}
|
||||
|
||||
@@ -289,6 +296,7 @@ impl Resolve<ComposeExecution> for State {
|
||||
let docker_compose = docker_compose();
|
||||
let log = run_komodo_command(
|
||||
"compose command",
|
||||
None,
|
||||
format!("{docker_compose} -p {project} {command}"),
|
||||
)
|
||||
.await;
|
||||
|
||||
@@ -42,11 +42,18 @@ impl Resolve<GetContainerLog> for State {
|
||||
#[instrument(name = "GetContainerLog", level = "debug", skip(self))]
|
||||
async fn resolve(
|
||||
&self,
|
||||
GetContainerLog { name, tail }: GetContainerLog,
|
||||
GetContainerLog {
|
||||
name,
|
||||
tail,
|
||||
timestamps,
|
||||
}: GetContainerLog,
|
||||
_: (),
|
||||
) -> anyhow::Result<Log> {
|
||||
let command = format!("docker logs {name} --tail {tail}");
|
||||
Ok(run_komodo_command("get container log", command).await)
|
||||
let timestamps =
|
||||
timestamps.then_some(" --timestamps").unwrap_or_default();
|
||||
let command =
|
||||
format!("docker logs {name} --tail {tail}{timestamps}");
|
||||
Ok(run_komodo_command("get container log", None, command).await)
|
||||
}
|
||||
}
|
||||
|
||||
@@ -65,13 +72,20 @@ impl Resolve<GetContainerLogSearch> for State {
|
||||
terms,
|
||||
combinator,
|
||||
invert,
|
||||
timestamps,
|
||||
}: GetContainerLogSearch,
|
||||
_: (),
|
||||
) -> anyhow::Result<Log> {
|
||||
let grep = log_grep(&terms, combinator, invert);
|
||||
let command =
|
||||
format!("docker logs {name} --tail 5000 2>&1 | {grep}");
|
||||
Ok(run_komodo_command("get container log grep", command).await)
|
||||
let timestamps =
|
||||
timestamps.then_some(" --timestamps").unwrap_or_default();
|
||||
let command = format!(
|
||||
"docker logs {name} --tail 5000{timestamps} 2>&1 | {grep}"
|
||||
);
|
||||
Ok(
|
||||
run_komodo_command("get container log grep", None, command)
|
||||
.await,
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
@@ -126,6 +140,7 @@ impl Resolve<StartContainer> for State {
|
||||
Ok(
|
||||
run_komodo_command(
|
||||
"docker start",
|
||||
None,
|
||||
format!("docker start {name}"),
|
||||
)
|
||||
.await,
|
||||
@@ -145,6 +160,7 @@ impl Resolve<RestartContainer> for State {
|
||||
Ok(
|
||||
run_komodo_command(
|
||||
"docker restart",
|
||||
None,
|
||||
format!("docker restart {name}"),
|
||||
)
|
||||
.await,
|
||||
@@ -164,6 +180,7 @@ impl Resolve<PauseContainer> for State {
|
||||
Ok(
|
||||
run_komodo_command(
|
||||
"docker pause",
|
||||
None,
|
||||
format!("docker pause {name}"),
|
||||
)
|
||||
.await,
|
||||
@@ -181,6 +198,7 @@ impl Resolve<UnpauseContainer> for State {
|
||||
Ok(
|
||||
run_komodo_command(
|
||||
"docker unpause",
|
||||
None,
|
||||
format!("docker unpause {name}"),
|
||||
)
|
||||
.await,
|
||||
@@ -198,10 +216,11 @@ impl Resolve<StopContainer> for State {
|
||||
_: (),
|
||||
) -> anyhow::Result<Log> {
|
||||
let command = stop_container_command(&name, signal, time);
|
||||
let log = run_komodo_command("docker stop", command).await;
|
||||
let log = run_komodo_command("docker stop", None, command).await;
|
||||
if log.stderr.contains("unknown flag: --signal") {
|
||||
let command = stop_container_command(&name, None, time);
|
||||
let mut log = run_komodo_command("docker stop", command).await;
|
||||
let mut log =
|
||||
run_komodo_command("docker stop", None, command).await;
|
||||
log.stderr = format!(
|
||||
"old docker version: unable to use --signal flag{}",
|
||||
if !log.stderr.is_empty() {
|
||||
@@ -230,12 +249,14 @@ impl Resolve<RemoveContainer> for State {
|
||||
let command =
|
||||
format!("{stop_command} && docker container rm {name}");
|
||||
let log =
|
||||
run_komodo_command("docker stop and remove", command).await;
|
||||
run_komodo_command("docker stop and remove", None, command)
|
||||
.await;
|
||||
if log.stderr.contains("unknown flag: --signal") {
|
||||
let stop_command = stop_container_command(&name, None, time);
|
||||
let command =
|
||||
format!("{stop_command} && docker container rm {name}");
|
||||
let mut log = run_komodo_command("docker stop", command).await;
|
||||
let mut log =
|
||||
run_komodo_command("docker stop", None, command).await;
|
||||
log.stderr = format!(
|
||||
"old docker version: unable to use --signal flag{}",
|
||||
if !log.stderr.is_empty() {
|
||||
@@ -265,7 +286,7 @@ impl Resolve<RenameContainer> for State {
|
||||
) -> anyhow::Result<Log> {
|
||||
let new = to_komodo_name(&new_name);
|
||||
let command = format!("docker rename {curr_name} {new}");
|
||||
Ok(run_komodo_command("docker rename", command).await)
|
||||
Ok(run_komodo_command("docker rename", None, command).await)
|
||||
}
|
||||
}
|
||||
|
||||
@@ -279,7 +300,7 @@ impl Resolve<PruneContainers> for State {
|
||||
_: (),
|
||||
) -> anyhow::Result<Log> {
|
||||
let command = String::from("docker container prune -f");
|
||||
Ok(run_komodo_command("prune containers", command).await)
|
||||
Ok(run_komodo_command("prune containers", None, command).await)
|
||||
}
|
||||
}
|
||||
|
||||
@@ -297,14 +318,12 @@ impl Resolve<StartAllContainers> for State {
|
||||
.await
|
||||
.context("failed to list all containers on host")?;
|
||||
let futures =
|
||||
containers.iter().map(
|
||||
|ContainerListItem { name, .. }| {
|
||||
let command = format!("docker start {name}");
|
||||
async move {
|
||||
run_komodo_command(&command.clone(), command).await
|
||||
}
|
||||
},
|
||||
);
|
||||
containers.iter().map(|ContainerListItem { name, .. }| {
|
||||
let command = format!("docker start {name}");
|
||||
async move {
|
||||
run_komodo_command(&command.clone(), None, command).await
|
||||
}
|
||||
});
|
||||
Ok(join_all(futures).await)
|
||||
}
|
||||
}
|
||||
@@ -322,14 +341,13 @@ impl Resolve<RestartAllContainers> for State {
|
||||
.list_containers()
|
||||
.await
|
||||
.context("failed to list all containers on host")?;
|
||||
let futures = containers.iter().map(
|
||||
|ContainerListItem { name, .. }| {
|
||||
let futures =
|
||||
containers.iter().map(|ContainerListItem { name, .. }| {
|
||||
let command = format!("docker restart {name}");
|
||||
async move {
|
||||
run_komodo_command(&command.clone(), command).await
|
||||
run_komodo_command(&command.clone(), None, command).await
|
||||
}
|
||||
},
|
||||
);
|
||||
});
|
||||
Ok(join_all(futures).await)
|
||||
}
|
||||
}
|
||||
@@ -347,14 +365,13 @@ impl Resolve<PauseAllContainers> for State {
|
||||
.list_containers()
|
||||
.await
|
||||
.context("failed to list all containers on host")?;
|
||||
let futures = containers.iter().map(
|
||||
|ContainerListItem { name, .. }| {
|
||||
let futures =
|
||||
containers.iter().map(|ContainerListItem { name, .. }| {
|
||||
let command = format!("docker pause {name}");
|
||||
async move {
|
||||
run_komodo_command(&command.clone(), command).await
|
||||
run_komodo_command(&command.clone(), None, command).await
|
||||
}
|
||||
},
|
||||
);
|
||||
});
|
||||
Ok(join_all(futures).await)
|
||||
}
|
||||
}
|
||||
@@ -372,14 +389,13 @@ impl Resolve<UnpauseAllContainers> for State {
|
||||
.list_containers()
|
||||
.await
|
||||
.context("failed to list all containers on host")?;
|
||||
let futures = containers.iter().map(
|
||||
|ContainerListItem { name, .. }| {
|
||||
let futures =
|
||||
containers.iter().map(|ContainerListItem { name, .. }| {
|
||||
let command = format!("docker unpause {name}");
|
||||
async move {
|
||||
run_komodo_command(&command.clone(), command).await
|
||||
run_komodo_command(&command.clone(), None, command).await
|
||||
}
|
||||
},
|
||||
);
|
||||
});
|
||||
Ok(join_all(futures).await)
|
||||
}
|
||||
}
|
||||
@@ -401,6 +417,7 @@ impl Resolve<StopAllContainers> for State {
|
||||
|ContainerListItem { name, .. }| async move {
|
||||
run_komodo_command(
|
||||
&format!("docker stop {name}"),
|
||||
None,
|
||||
stop_container_command(name, None, None),
|
||||
)
|
||||
.await
|
||||
|
||||
@@ -87,7 +87,7 @@ impl Resolve<Deploy> for State {
|
||||
debug!("docker run command: {command}");
|
||||
|
||||
if deployment.config.skip_secret_interp {
|
||||
Ok(run_komodo_command("docker run", command).await)
|
||||
Ok(run_komodo_command("docker run", None, command).await)
|
||||
} else {
|
||||
let command = svi::interpolate_variables(
|
||||
&command,
|
||||
@@ -107,7 +107,8 @@ impl Resolve<Deploy> for State {
|
||||
};
|
||||
|
||||
replacers.extend(core_replacers);
|
||||
let mut log = run_komodo_command("docker run", command).await;
|
||||
let mut log =
|
||||
run_komodo_command("docker run", None, command).await;
|
||||
log.command = svi::replace_in_string(&log.command, &replacers);
|
||||
log.stdout = svi::replace_in_string(&log.stdout, &replacers);
|
||||
log.stderr = svi::replace_in_string(&log.stderr, &replacers);
|
||||
|
||||
@@ -44,7 +44,7 @@ impl Resolve<DeleteImage> for State {
|
||||
_: (),
|
||||
) -> anyhow::Result<Log> {
|
||||
let command = format!("docker image rm {name}");
|
||||
Ok(run_komodo_command("delete image", command).await)
|
||||
Ok(run_komodo_command("delete image", None, command).await)
|
||||
}
|
||||
}
|
||||
|
||||
@@ -58,6 +58,6 @@ impl Resolve<PruneImages> for State {
|
||||
_: (),
|
||||
) -> anyhow::Result<Log> {
|
||||
let command = String::from("docker image prune -a -f");
|
||||
Ok(run_komodo_command("prune images", command).await)
|
||||
Ok(run_komodo_command("prune images", None, command).await)
|
||||
}
|
||||
}
|
||||
|
||||
@@ -255,7 +255,7 @@ impl Resolve<RunCommand> for State {
|
||||
} else {
|
||||
format!("cd {path} && {command}")
|
||||
};
|
||||
run_komodo_command("run command", command).await
|
||||
run_komodo_command("run command", None, command).await
|
||||
})
|
||||
.await
|
||||
.context("failure in spawned task")
|
||||
@@ -270,6 +270,6 @@ impl Resolve<PruneSystem> for State {
|
||||
_: (),
|
||||
) -> anyhow::Result<Log> {
|
||||
let command = String::from("docker system prune -a -f --volumes");
|
||||
Ok(run_komodo_command("prune system", command).await)
|
||||
Ok(run_komodo_command("prune system", None, command).await)
|
||||
}
|
||||
}
|
||||
|
||||
@@ -34,7 +34,7 @@ impl Resolve<CreateNetwork> for State {
|
||||
None => String::new(),
|
||||
};
|
||||
let command = format!("docker network create{driver} {name}");
|
||||
Ok(run_komodo_command("create network", command).await)
|
||||
Ok(run_komodo_command("create network", None, command).await)
|
||||
}
|
||||
}
|
||||
|
||||
@@ -48,7 +48,7 @@ impl Resolve<DeleteNetwork> for State {
|
||||
_: (),
|
||||
) -> anyhow::Result<Log> {
|
||||
let command = format!("docker network rm {name}");
|
||||
Ok(run_komodo_command("delete network", command).await)
|
||||
Ok(run_komodo_command("delete network", None, command).await)
|
||||
}
|
||||
}
|
||||
|
||||
@@ -62,6 +62,6 @@ impl Resolve<PruneNetworks> for State {
|
||||
_: (),
|
||||
) -> anyhow::Result<Log> {
|
||||
let command = String::from("docker network prune -f");
|
||||
Ok(run_komodo_command("prune networks", command).await)
|
||||
Ok(run_komodo_command("prune networks", None, command).await)
|
||||
}
|
||||
}
|
||||
|
||||
@@ -28,7 +28,7 @@ impl Resolve<DeleteVolume> for State {
|
||||
_: (),
|
||||
) -> anyhow::Result<Log> {
|
||||
let command = format!("docker volume rm {name}");
|
||||
Ok(run_komodo_command("delete volume", command).await)
|
||||
Ok(run_komodo_command("delete volume", None, command).await)
|
||||
}
|
||||
}
|
||||
|
||||
@@ -42,6 +42,6 @@ impl Resolve<PruneVolumes> for State {
|
||||
_: (),
|
||||
) -> anyhow::Result<Log> {
|
||||
let command = String::from("docker volume prune -a -f");
|
||||
Ok(run_komodo_command("prune volumes", command).await)
|
||||
Ok(run_komodo_command("prune volumes", None, command).await)
|
||||
}
|
||||
}
|
||||
|
||||
@@ -16,8 +16,10 @@ use resolver_api::Resolve;
|
||||
use tokio::fs;
|
||||
|
||||
use crate::{
|
||||
config::periphery_config, docker::docker_login,
|
||||
helpers::parse_extra_args, State,
|
||||
config::periphery_config,
|
||||
docker::docker_login,
|
||||
helpers::{interpolate_variables, parse_extra_args},
|
||||
State,
|
||||
};
|
||||
|
||||
pub fn docker_compose() -> &'static str {
|
||||
@@ -101,7 +103,6 @@ pub async fn compose_up(
|
||||
}
|
||||
|
||||
let docker_compose = docker_compose();
|
||||
let run_dir = run_directory.display();
|
||||
let service_arg = service
|
||||
.as_ref()
|
||||
.map(|service| format!(" {service}"))
|
||||
@@ -146,10 +147,15 @@ pub async fn compose_up(
|
||||
let build_extra_args =
|
||||
parse_extra_args(&stack.config.build_extra_args);
|
||||
let command = format!(
|
||||
"cd {run_dir} && {docker_compose} -p {project_name} -f {file_args}{env_file} build{build_extra_args}{service_arg}",
|
||||
"{docker_compose} -p {project_name} -f {file_args}{env_file} build{build_extra_args}{service_arg}",
|
||||
);
|
||||
if stack.config.skip_secret_interp {
|
||||
let log = run_komodo_command("compose build", command).await;
|
||||
let log = run_komodo_command(
|
||||
"compose build",
|
||||
run_directory.as_ref(),
|
||||
command,
|
||||
)
|
||||
.await;
|
||||
res.logs.push(log);
|
||||
} else {
|
||||
let (command, mut replacers) = svi::interpolate_variables(
|
||||
@@ -160,8 +166,12 @@ pub async fn compose_up(
|
||||
).context("failed to interpolate periphery secrets into stack build command")?;
|
||||
replacers.extend(core_replacers.clone());
|
||||
|
||||
let mut log =
|
||||
run_komodo_command("compose build", command).await;
|
||||
let mut log = run_komodo_command(
|
||||
"compose build",
|
||||
run_directory.as_ref(),
|
||||
command,
|
||||
)
|
||||
.await;
|
||||
|
||||
log.command = svi::replace_in_string(&log.command, &replacers);
|
||||
log.stdout = svi::replace_in_string(&log.stdout, &replacers);
|
||||
@@ -177,13 +187,15 @@ pub async fn compose_up(
|
||||
}
|
||||
}
|
||||
|
||||
//
|
||||
if stack.config.auto_pull {
|
||||
// Pull images before destroying to minimize downtime.
|
||||
// If this fails, do not continue.
|
||||
let log = run_komodo_command(
|
||||
"compose pull",
|
||||
run_directory.as_ref(),
|
||||
format!(
|
||||
"cd {run_dir} && {docker_compose} -p {project_name} -f {file_args}{env_file} pull{service_arg}",
|
||||
"{docker_compose} -p {project_name} -f {file_args}{env_file} pull{service_arg}",
|
||||
),
|
||||
)
|
||||
.await;
|
||||
@@ -201,19 +213,16 @@ pub async fn compose_up(
|
||||
let pre_deploy_path =
|
||||
run_directory.join(&stack.config.pre_deploy.path);
|
||||
if !stack.config.skip_secret_interp {
|
||||
let (full_command, mut replacers) = svi::interpolate_variables(
|
||||
&stack.config.pre_deploy.command,
|
||||
&periphery_config().secrets,
|
||||
svi::Interpolator::DoubleBrackets,
|
||||
true,
|
||||
)
|
||||
.context(
|
||||
"failed to interpolate secrets into pre_deploy command",
|
||||
)?;
|
||||
let (full_command, mut replacers) =
|
||||
interpolate_variables(&stack.config.pre_deploy.command)
|
||||
.context(
|
||||
"failed to interpolate secrets into pre_deploy command",
|
||||
)?;
|
||||
replacers.extend(core_replacers.to_owned());
|
||||
let mut pre_deploy_log = run_komodo_command(
|
||||
"pre deploy",
|
||||
format!("cd {} && {full_command}", pre_deploy_path.display()),
|
||||
pre_deploy_path.as_ref(),
|
||||
&full_command,
|
||||
)
|
||||
.await;
|
||||
|
||||
@@ -234,11 +243,8 @@ pub async fn compose_up(
|
||||
} else {
|
||||
let pre_deploy_log = run_komodo_command(
|
||||
"pre deploy",
|
||||
format!(
|
||||
"cd {} && {}",
|
||||
pre_deploy_path.display(),
|
||||
stack.config.pre_deploy.command
|
||||
),
|
||||
pre_deploy_path.as_ref(),
|
||||
&stack.config.pre_deploy.command,
|
||||
)
|
||||
.await;
|
||||
tracing::debug!(
|
||||
@@ -255,20 +261,26 @@ pub async fn compose_up(
|
||||
}
|
||||
}
|
||||
|
||||
// Take down the existing containers.
|
||||
// This one tries to use the previously deployed service name, to ensure the right stack is taken down.
|
||||
compose_down(&last_project_name, service, res)
|
||||
.await
|
||||
.context("failed to destroy existing containers")?;
|
||||
if stack.config.destroy_before_deploy
|
||||
// Also check if project name changed, which also requires taking down.
|
||||
|| last_project_name != project_name
|
||||
{
|
||||
// Take down the existing containers.
|
||||
// This one tries to use the previously deployed service name, to ensure the right stack is taken down.
|
||||
compose_down(&last_project_name, service, res)
|
||||
.await
|
||||
.context("failed to destroy existing containers")?;
|
||||
}
|
||||
|
||||
// Run compose up
|
||||
let extra_args = parse_extra_args(&stack.config.extra_args);
|
||||
let command = format!(
|
||||
"cd {run_dir} && {docker_compose} -p {project_name} -f {file_args}{env_file} up -d{extra_args}{service_arg}",
|
||||
"{docker_compose} -p {project_name} -f {file_args}{env_file} up -d{extra_args}{service_arg}",
|
||||
);
|
||||
|
||||
let log = if stack.config.skip_secret_interp {
|
||||
run_komodo_command("compose up", command).await
|
||||
run_komodo_command("compose up", run_directory.as_ref(), command)
|
||||
.await
|
||||
} else {
|
||||
let (command, mut replacers) = svi::interpolate_variables(
|
||||
&command,
|
||||
@@ -278,7 +290,12 @@ pub async fn compose_up(
|
||||
).context("failed to interpolate periphery secrets into stack run command")?;
|
||||
replacers.extend(core_replacers);
|
||||
|
||||
let mut log = run_komodo_command("compose up", command).await;
|
||||
let mut log = run_komodo_command(
|
||||
"compose up",
|
||||
run_directory.as_ref(),
|
||||
command,
|
||||
)
|
||||
.await;
|
||||
|
||||
log.command = svi::replace_in_string(&log.command, &replacers);
|
||||
log.stdout = svi::replace_in_string(&log.stdout, &replacers);
|
||||
@@ -323,7 +340,7 @@ async fn write_stack<'a>(
|
||||
.config
|
||||
.skip_secret_interp
|
||||
.then_some(&periphery_config().secrets),
|
||||
&run_directory,
|
||||
run_directory.as_ref(),
|
||||
&mut res.logs,
|
||||
)
|
||||
.await
|
||||
@@ -361,7 +378,7 @@ async fn write_stack<'a>(
|
||||
.config
|
||||
.skip_secret_interp
|
||||
.then_some(&periphery_config().secrets),
|
||||
&run_directory,
|
||||
run_directory.as_ref(),
|
||||
&mut res.logs,
|
||||
)
|
||||
.await
|
||||
@@ -517,6 +534,7 @@ async fn compose_down(
|
||||
.unwrap_or_default();
|
||||
let log = run_komodo_command(
|
||||
"compose down",
|
||||
None,
|
||||
format!("{docker_compose} -p {project} down{service_arg}"),
|
||||
)
|
||||
.await;
|
||||
|
||||
@@ -935,7 +935,7 @@ pub async fn docker_login(
|
||||
#[instrument]
|
||||
pub async fn pull_image(image: &str) -> Log {
|
||||
let command = format!("docker pull {image}");
|
||||
run_komodo_command("docker pull", command).await
|
||||
run_komodo_command("docker pull", None, command).await
|
||||
}
|
||||
|
||||
pub fn stop_container_command(
|
||||
|
||||
@@ -66,3 +66,14 @@ pub fn log_grep(
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
pub fn interpolate_variables(
|
||||
input: &str,
|
||||
) -> svi::Result<(String, Vec<(String, String)>)> {
|
||||
svi::interpolate_variables(
|
||||
input,
|
||||
&periphery_config().secrets,
|
||||
svi::Interpolator::DoubleBrackets,
|
||||
true,
|
||||
)
|
||||
}
|
||||
|
||||
@@ -128,7 +128,7 @@ pub struct UnpauseStack {
|
||||
|
||||
//
|
||||
|
||||
/// Starts the target stack. `docker compose stop`. Response: [Update]
|
||||
/// Stops the target stack. `docker compose stop`. Response: [Update]
|
||||
#[typeshare]
|
||||
#[derive(
|
||||
Debug,
|
||||
|
||||
@@ -120,6 +120,9 @@ pub struct GetDeploymentLog {
|
||||
/// Max: 5000.
|
||||
#[serde(default = "default_tail")]
|
||||
pub tail: U64,
|
||||
/// Enable `--timestamps`
|
||||
#[serde(default)]
|
||||
pub timestamps: bool,
|
||||
}
|
||||
|
||||
fn default_tail() -> u64 {
|
||||
@@ -156,6 +159,9 @@ pub struct SearchDeploymentLog {
|
||||
/// Invert the results, ie return all lines that DON'T match the terms / combinator.
|
||||
#[serde(default)]
|
||||
pub invert: bool,
|
||||
/// Enable `--timestamps`
|
||||
#[serde(default)]
|
||||
pub timestamps: bool,
|
||||
}
|
||||
|
||||
#[typeshare]
|
||||
|
||||
@@ -303,6 +303,9 @@ pub struct GetContainerLog {
|
||||
/// Max: 5000.
|
||||
#[serde(default = "default_tail")]
|
||||
pub tail: U64,
|
||||
/// Enable `--timestamps`
|
||||
#[serde(default)]
|
||||
pub timestamps: bool,
|
||||
}
|
||||
|
||||
fn default_tail() -> u64 {
|
||||
@@ -341,6 +344,9 @@ pub struct SearchContainerLog {
|
||||
/// Invert the results, ie return all lines that DON'T match the terms / combinator.
|
||||
#[serde(default)]
|
||||
pub invert: bool,
|
||||
/// Enable `--timestamps`
|
||||
#[serde(default)]
|
||||
pub timestamps: bool,
|
||||
}
|
||||
|
||||
#[typeshare]
|
||||
|
||||
@@ -69,6 +69,9 @@ pub struct GetStackServiceLog {
|
||||
/// Max: 5000.
|
||||
#[serde(default = "default_tail")]
|
||||
pub tail: U64,
|
||||
/// Enable `--timestamps`
|
||||
#[serde(default)]
|
||||
pub timestamps: bool,
|
||||
}
|
||||
|
||||
fn default_tail() -> u64 {
|
||||
@@ -107,6 +110,9 @@ pub struct SearchStackServiceLog {
|
||||
/// Invert the results, ie return all lines that DON'T match the terms / combinator.
|
||||
#[serde(default)]
|
||||
pub invert: bool,
|
||||
/// Enable `--timestamps`
|
||||
#[serde(default)]
|
||||
pub timestamps: bool,
|
||||
}
|
||||
|
||||
#[typeshare]
|
||||
|
||||
@@ -219,7 +219,7 @@ impl SystemCommand {
|
||||
}
|
||||
|
||||
pub fn is_none(&self) -> bool {
|
||||
self.path.is_empty() || self.command.is_empty()
|
||||
self.command.is_empty()
|
||||
}
|
||||
}
|
||||
|
||||
@@ -614,7 +614,7 @@ impl CloneArgs {
|
||||
pub fn path(&self, repo_dir: &Path) -> PathBuf {
|
||||
let path = match &self.destination {
|
||||
Some(destination) => PathBuf::from(&destination),
|
||||
None => repo_dir.join(&to_komodo_name(&self.name)),
|
||||
None => repo_dir.join(to_komodo_name(&self.name)),
|
||||
};
|
||||
path.components().collect::<PathBuf>()
|
||||
}
|
||||
@@ -650,9 +650,7 @@ impl CloneArgs {
|
||||
.join(self.provider.replace('/', "-"))
|
||||
.join(repo.replace('/', "-"))
|
||||
.join(self.branch.replace('/', "-"))
|
||||
.join(
|
||||
self.commit.as_ref().map(String::as_str).unwrap_or("latest"),
|
||||
);
|
||||
.join(self.commit.as_deref().unwrap_or("latest"));
|
||||
Ok(res)
|
||||
}
|
||||
}
|
||||
|
||||
@@ -104,7 +104,7 @@ pub struct ProcedureStage {
|
||||
#[serde(default = "default_enabled")]
|
||||
pub enabled: bool,
|
||||
/// The executions in the stage
|
||||
#[serde(default)]
|
||||
#[serde(default, alias = "execution")]
|
||||
pub executions: Vec<EnabledExecution>,
|
||||
}
|
||||
|
||||
|
||||
@@ -213,6 +213,11 @@ pub struct StackConfig {
|
||||
#[builder(default)]
|
||||
pub run_build: bool,
|
||||
|
||||
/// Whether to run `docker compose down` before `compose up`.
|
||||
#[serde(default)]
|
||||
#[builder(default)]
|
||||
pub destroy_before_deploy: bool,
|
||||
|
||||
/// Whether to skip secret interpolation into the stack environment variables.
|
||||
#[serde(default)]
|
||||
#[builder(default)]
|
||||
@@ -426,6 +431,7 @@ impl Default for StackConfig {
|
||||
environment: Default::default(),
|
||||
env_file_path: default_env_file_path(),
|
||||
run_build: Default::default(),
|
||||
destroy_before_deploy: Default::default(),
|
||||
build_extra_args: Default::default(),
|
||||
skip_secret_interp: Default::default(),
|
||||
git_provider: default_git_provider(),
|
||||
|
||||
@@ -2323,6 +2323,8 @@ export interface StackConfig {
|
||||
* Combine with build_extra_args for custom behaviors.
|
||||
*/
|
||||
run_build?: boolean;
|
||||
/** Whether to run `docker compose down` before `compose up`. */
|
||||
destroy_before_deploy?: boolean;
|
||||
/** Whether to skip secret interpolation into the stack environment variables. */
|
||||
skip_secret_interp?: boolean;
|
||||
/**
|
||||
@@ -3797,7 +3799,7 @@ export interface UnpauseStack {
|
||||
service?: string;
|
||||
}
|
||||
|
||||
/** Starts the target stack. `docker compose stop`. Response: [Update] */
|
||||
/** Stops the target stack. `docker compose stop`. Response: [Update] */
|
||||
export interface StopStack {
|
||||
/** Id or name */
|
||||
stack: string;
|
||||
@@ -4112,6 +4114,8 @@ export interface GetDeploymentLog {
|
||||
* Max: 5000.
|
||||
*/
|
||||
tail: U64;
|
||||
/** Enable `--timestamps` */
|
||||
timestamps?: boolean;
|
||||
}
|
||||
|
||||
export enum SearchCombinator {
|
||||
@@ -4139,6 +4143,8 @@ export interface SearchDeploymentLog {
|
||||
combinator?: SearchCombinator;
|
||||
/** Invert the results, ie return all lines that DON'T match the terms / combinator. */
|
||||
invert?: boolean;
|
||||
/** Enable `--timestamps` */
|
||||
timestamps?: boolean;
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -4605,6 +4611,8 @@ export interface GetContainerLog {
|
||||
* Max: 5000.
|
||||
*/
|
||||
tail: U64;
|
||||
/** Enable `--timestamps` */
|
||||
timestamps?: boolean;
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -4629,6 +4637,8 @@ export interface SearchContainerLog {
|
||||
combinator?: SearchCombinator;
|
||||
/** Invert the results, ie return all lines that DON'T match the terms / combinator. */
|
||||
invert?: boolean;
|
||||
/** Enable `--timestamps` */
|
||||
timestamps?: boolean;
|
||||
}
|
||||
|
||||
/** Inspect a docker container on the server. Response: [Container]. */
|
||||
@@ -4819,6 +4829,8 @@ export interface GetStackServiceLog {
|
||||
* Max: 5000.
|
||||
*/
|
||||
tail: U64;
|
||||
/** Enable `--timestamps` */
|
||||
timestamps?: boolean;
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -4843,6 +4855,8 @@ export interface SearchStackServiceLog {
|
||||
combinator?: SearchCombinator;
|
||||
/** Invert the results, ie return all lines that DON'T match the terms / combinator. */
|
||||
invert?: boolean;
|
||||
/** Enable `--timestamps` */
|
||||
timestamps?: boolean;
|
||||
}
|
||||
|
||||
/**
|
||||
|
||||
@@ -44,9 +44,12 @@ pub struct GetComposeServiceLog {
|
||||
pub project: String,
|
||||
/// The service name
|
||||
pub service: String,
|
||||
/// pass `--tail` for only recent log contents
|
||||
/// Pass `--tail` for only recent log contents. Max of 5000
|
||||
#[serde(default = "default_tail")]
|
||||
pub tail: u64,
|
||||
/// Enable `--timestamps`
|
||||
#[serde(default)]
|
||||
pub timestamps: bool,
|
||||
}
|
||||
|
||||
fn default_tail() -> u64 {
|
||||
@@ -72,6 +75,9 @@ pub struct GetComposeServiceLogSearch {
|
||||
/// Invert the search (search for everything not matching terms)
|
||||
#[serde(default)]
|
||||
pub invert: bool,
|
||||
/// Enable `--timestamps`
|
||||
#[serde(default)]
|
||||
pub timestamps: bool,
|
||||
}
|
||||
|
||||
//
|
||||
|
||||
@@ -23,6 +23,9 @@ pub struct GetContainerLog {
|
||||
pub name: String,
|
||||
#[serde(default = "default_tail")]
|
||||
pub tail: u64,
|
||||
/// Enable `--timestamps`
|
||||
#[serde(default)]
|
||||
pub timestamps: bool,
|
||||
}
|
||||
|
||||
fn default_tail() -> u64 {
|
||||
@@ -40,6 +43,9 @@ pub struct GetContainerLogSearch {
|
||||
pub combinator: SearchCombinator,
|
||||
#[serde(default)]
|
||||
pub invert: bool,
|
||||
/// Enable `--timestamps`
|
||||
#[serde(default)]
|
||||
pub timestamps: bool,
|
||||
}
|
||||
|
||||
//
|
||||
|
||||
@@ -749,7 +749,7 @@ export const SystemCommand = ({
|
||||
/>
|
||||
</div>
|
||||
<MonacoEditor
|
||||
value={value?.command}
|
||||
value={value?.command || " # Add multiple commands on new lines. Supports comments.\n "}
|
||||
language="shell"
|
||||
onValueChange={(command) => set({ ...(value || {}), command })}
|
||||
readOnly={disabled}
|
||||
|
||||
@@ -100,7 +100,7 @@ export const BuildConfig = ({
|
||||
<ConfigInput
|
||||
className="text-lg w-[200px]"
|
||||
label="Version"
|
||||
description="Version the image tag using server (major.minor.patch)"
|
||||
description="Version the image with major.minor.patch. It can be interpolated using [[$VERSION]]."
|
||||
placeholder="0.0.0"
|
||||
value={version}
|
||||
onChange={(version) => set({ version: version as any })}
|
||||
|
||||
@@ -43,6 +43,10 @@ const DeploymentLogsInner = ({
|
||||
const [invert, setInvert] = useState(false);
|
||||
const [search, setSearch] = useState("");
|
||||
const [poll, setPoll] = useLocalStorage("log-poll-v1", false);
|
||||
const [timestamps, setTimestamps] = useLocalStorage(
|
||||
"log-timestamps-v1",
|
||||
false
|
||||
);
|
||||
|
||||
const addTerm = () => {
|
||||
if (!search.length) return;
|
||||
@@ -61,8 +65,8 @@ const DeploymentLogsInner = ({
|
||||
};
|
||||
|
||||
const { Log, refetch, stderr } = terms.length
|
||||
? SearchLogs(id, terms, invert)
|
||||
: NoSearchLogs(id, tail, stream);
|
||||
? SearchLogs(id, terms, invert, timestamps)
|
||||
: NoSearchLogs(id, tail, timestamps, stream);
|
||||
|
||||
useEffect(() => {
|
||||
const interval = setInterval(() => {
|
||||
@@ -77,9 +81,8 @@ const DeploymentLogsInner = ({
|
||||
actions={
|
||||
<div className="flex items-center gap-4 flex-wrap">
|
||||
<div className="flex items-center gap-2">
|
||||
<div className="text-muted-foreground flex gap-1">
|
||||
<div>Invert</div>
|
||||
<div className="hidden xl:block">Search</div>
|
||||
<div className="text-muted-foreground flex gap-1 text-sm">
|
||||
Invert
|
||||
</div>
|
||||
<Switch checked={invert} onCheckedChange={setInvert} />
|
||||
</div>
|
||||
@@ -126,9 +129,19 @@ const DeploymentLogsInner = ({
|
||||
<Button variant="secondary" size="icon" onClick={() => refetch()}>
|
||||
<RefreshCw className="w-4 h-4" />
|
||||
</Button>
|
||||
<div className="flex items-center gap-2">
|
||||
<div className="text-muted-foreground">Poll</div>
|
||||
<Switch checked={poll} onCheckedChange={setPoll} />
|
||||
<div
|
||||
className="flex items-center gap-2 cursor-pointer"
|
||||
onClick={() => setTimestamps((t) => !t)}
|
||||
>
|
||||
<div className="text-muted-foreground text-sm">Timestamps</div>
|
||||
<Switch checked={timestamps} />
|
||||
</div>
|
||||
<div
|
||||
className="flex items-center gap-2 cursor-pointer"
|
||||
onClick={() => setPoll((p) => !p)}
|
||||
>
|
||||
<div className="text-muted-foreground text-sm">Poll</div>
|
||||
<Switch checked={poll} />
|
||||
</div>
|
||||
<TailLengthSelector
|
||||
selected={tail}
|
||||
@@ -143,12 +156,17 @@ const DeploymentLogsInner = ({
|
||||
);
|
||||
};
|
||||
|
||||
const NoSearchLogs = (id: string, tail: string, stream: string) => {
|
||||
const { data: log, refetch } = useRead(
|
||||
"GetDeploymentLog",
|
||||
{ deployment: id, tail: Number(tail) },
|
||||
{ refetchInterval: 30000 }
|
||||
);
|
||||
const NoSearchLogs = (
|
||||
id: string,
|
||||
tail: string,
|
||||
timestamps: boolean,
|
||||
stream: string
|
||||
) => {
|
||||
const { data: log, refetch } = useRead("GetDeploymentLog", {
|
||||
deployment: id,
|
||||
tail: Number(tail),
|
||||
timestamps,
|
||||
});
|
||||
return {
|
||||
Log: (
|
||||
<div className="relative">
|
||||
@@ -160,12 +178,18 @@ const NoSearchLogs = (id: string, tail: string, stream: string) => {
|
||||
};
|
||||
};
|
||||
|
||||
const SearchLogs = (id: string, terms: string[], invert: boolean) => {
|
||||
const SearchLogs = (
|
||||
id: string,
|
||||
terms: string[],
|
||||
invert: boolean,
|
||||
timestamps: boolean
|
||||
) => {
|
||||
const { data: log, refetch } = useRead("SearchDeploymentLog", {
|
||||
deployment: id,
|
||||
terms,
|
||||
combinator: Types.SearchCombinator.And,
|
||||
invert,
|
||||
timestamps,
|
||||
});
|
||||
return {
|
||||
Log: (
|
||||
|
||||
@@ -389,6 +389,17 @@ export const StackConfig = ({
|
||||
),
|
||||
},
|
||||
},
|
||||
{
|
||||
label: "Destroy",
|
||||
labelHidden: true,
|
||||
components: {
|
||||
run_build: {
|
||||
label: "Destroy Before Deploy",
|
||||
description:
|
||||
"Ensure 'docker compose down' is run before redeploying the Stack.",
|
||||
},
|
||||
},
|
||||
},
|
||||
];
|
||||
|
||||
if (mode === undefined) {
|
||||
|
||||
@@ -25,6 +25,10 @@ export const ContainerLogs = ({
|
||||
const [invert, setInvert] = useState(false);
|
||||
const [search, setSearch] = useState("");
|
||||
const [poll, setPoll] = useLocalStorage("log-poll-v1", false);
|
||||
const [timestamps, setTimestamps] = useLocalStorage(
|
||||
"log-timestamps-v1",
|
||||
false
|
||||
);
|
||||
|
||||
const addTerm = () => {
|
||||
if (!search.length) return;
|
||||
@@ -43,8 +47,8 @@ export const ContainerLogs = ({
|
||||
};
|
||||
|
||||
const { Log, refetch, stderr } = terms.length
|
||||
? SearchLogs(id, container_name, terms, invert)
|
||||
: NoSearchLogs(id, container_name, tail, stream);
|
||||
? SearchLogs(id, container_name, terms, invert, timestamps)
|
||||
: NoSearchLogs(id, container_name, tail, timestamps, stream);
|
||||
|
||||
useEffect(() => {
|
||||
const interval = setInterval(() => {
|
||||
@@ -61,10 +65,7 @@ export const ContainerLogs = ({
|
||||
actions={
|
||||
<div className="flex items-center gap-4 flex-wrap">
|
||||
<div className="flex items-center gap-2">
|
||||
<div className="text-muted-foreground flex gap-1">
|
||||
<div>Invert</div>
|
||||
<div className="hidden xl:block">Search</div>
|
||||
</div>
|
||||
<div className="text-muted-foreground flex gap-1">Invert</div>
|
||||
<Switch checked={invert} onCheckedChange={setInvert} />
|
||||
</div>
|
||||
{terms.map((term, index) => (
|
||||
@@ -110,9 +111,19 @@ export const ContainerLogs = ({
|
||||
<Button variant="secondary" size="icon" onClick={() => refetch()}>
|
||||
<RefreshCw className="w-4 h-4" />
|
||||
</Button>
|
||||
<div className="flex items-center gap-2">
|
||||
<div className="text-muted-foreground">Poll</div>
|
||||
<Switch checked={poll} onCheckedChange={setPoll} />
|
||||
<div
|
||||
className="flex items-center gap-2 cursor-pointer"
|
||||
onClick={() => setTimestamps((t) => !t)}
|
||||
>
|
||||
<div className="text-muted-foreground text-sm">Timestamps</div>
|
||||
<Switch checked={timestamps} />
|
||||
</div>
|
||||
<div
|
||||
className="flex items-center gap-2 cursor-pointer"
|
||||
onClick={() => setPoll((p) => !p)}
|
||||
>
|
||||
<div className="text-muted-foreground text-sm">Poll</div>
|
||||
<Switch checked={poll} />
|
||||
</div>
|
||||
<TailLengthSelector
|
||||
selected={tail}
|
||||
@@ -131,13 +142,15 @@ const NoSearchLogs = (
|
||||
id: string,
|
||||
container: string,
|
||||
tail: string,
|
||||
timestamps: boolean,
|
||||
stream: string
|
||||
) => {
|
||||
const { data: log, refetch } = useRead(
|
||||
"GetContainerLog",
|
||||
{ server: id, container, tail: Number(tail) },
|
||||
{ refetchInterval: 30000 }
|
||||
);
|
||||
const { data: log, refetch } = useRead("GetContainerLog", {
|
||||
server: id,
|
||||
container,
|
||||
tail: Number(tail),
|
||||
timestamps,
|
||||
});
|
||||
return {
|
||||
Log: (
|
||||
<div className="relative">
|
||||
@@ -153,7 +166,8 @@ const SearchLogs = (
|
||||
id: string,
|
||||
container: string,
|
||||
terms: string[],
|
||||
invert: boolean
|
||||
invert: boolean,
|
||||
timestamps: boolean
|
||||
) => {
|
||||
const { data: log, refetch } = useRead("SearchContainerLog", {
|
||||
server: id,
|
||||
@@ -161,6 +175,7 @@ const SearchLogs = (
|
||||
terms,
|
||||
combinator: Types.SearchCombinator.And,
|
||||
invert,
|
||||
timestamps,
|
||||
});
|
||||
return {
|
||||
Log: (
|
||||
|
||||
@@ -45,6 +45,10 @@ const StackLogsInner = ({
|
||||
const [invert, setInvert] = useState(false);
|
||||
const [search, setSearch] = useState("");
|
||||
const [poll, setPoll] = useLocalStorage("log-poll-v1", false);
|
||||
const [timestamps, setTimestamps] = useLocalStorage(
|
||||
"log-timestamps-v1",
|
||||
false
|
||||
);
|
||||
|
||||
const addTerm = () => {
|
||||
if (!search.length) return;
|
||||
@@ -63,8 +67,8 @@ const StackLogsInner = ({
|
||||
};
|
||||
|
||||
const { Log, refetch, stderr } = terms.length
|
||||
? SearchLogs(id, service, terms, invert)
|
||||
: NoSearchLogs(id, service, tail, stream);
|
||||
? SearchLogs(id, service, terms, invert, timestamps)
|
||||
: NoSearchLogs(id, service, tail, timestamps, stream);
|
||||
|
||||
useEffect(() => {
|
||||
const interval = setInterval(() => {
|
||||
@@ -81,9 +85,8 @@ const StackLogsInner = ({
|
||||
actions={
|
||||
<div className="flex items-center gap-4 flex-wrap">
|
||||
<div className="flex items-center gap-2">
|
||||
<div className="text-muted-foreground flex gap-1">
|
||||
<div>Invert</div>
|
||||
<div className="hidden xl:block">Search</div>
|
||||
<div className="text-muted-foreground flex gap-1 text-sm">
|
||||
Invert
|
||||
</div>
|
||||
<Switch checked={invert} onCheckedChange={setInvert} />
|
||||
</div>
|
||||
@@ -130,9 +133,19 @@ const StackLogsInner = ({
|
||||
<Button variant="secondary" size="icon" onClick={() => refetch()}>
|
||||
<RefreshCw className="w-4 h-4" />
|
||||
</Button>
|
||||
<div className="flex items-center gap-2">
|
||||
<div className="text-muted-foreground">Poll</div>
|
||||
<Switch checked={poll} onCheckedChange={setPoll} />
|
||||
<div
|
||||
className="flex items-center gap-2 cursor-pointer"
|
||||
onClick={() => setTimestamps((t) => !t)}
|
||||
>
|
||||
<div className="text-muted-foreground text-sm">Timestamps</div>
|
||||
<Switch checked={timestamps} />
|
||||
</div>
|
||||
<div
|
||||
className="flex items-center gap-2 cursor-pointer"
|
||||
onClick={() => setPoll((p) => !p)}
|
||||
>
|
||||
<div className="text-muted-foreground text-sm">Poll</div>
|
||||
<Switch checked={poll} />
|
||||
</div>
|
||||
<TailLengthSelector
|
||||
selected={tail}
|
||||
@@ -151,13 +164,15 @@ const NoSearchLogs = (
|
||||
id: string,
|
||||
service: string,
|
||||
tail: string,
|
||||
timestamps: boolean,
|
||||
stream: string
|
||||
) => {
|
||||
const { data: log, refetch } = useRead(
|
||||
"GetStackServiceLog",
|
||||
{ stack: id, service, tail: Number(tail) },
|
||||
{ refetchInterval: 30000 }
|
||||
);
|
||||
const { data: log, refetch } = useRead("GetStackServiceLog", {
|
||||
stack: id,
|
||||
service,
|
||||
tail: Number(tail),
|
||||
timestamps,
|
||||
});
|
||||
return {
|
||||
Log: (
|
||||
<div className="relative">
|
||||
@@ -173,7 +188,8 @@ const SearchLogs = (
|
||||
id: string,
|
||||
service: string,
|
||||
terms: string[],
|
||||
invert: boolean
|
||||
invert: boolean,
|
||||
timestamps: boolean
|
||||
) => {
|
||||
const { data: log, refetch } = useRead("SearchStackServiceLog", {
|
||||
stack: id,
|
||||
@@ -181,6 +197,7 @@ const SearchLogs = (
|
||||
terms,
|
||||
combinator: Types.SearchCombinator.And,
|
||||
invert,
|
||||
timestamps,
|
||||
});
|
||||
return {
|
||||
Log: (
|
||||
|
||||
@@ -1,12 +1,57 @@
|
||||
use std::path::Path;
|
||||
|
||||
use komodo_client::entities::{komodo_timestamp, update::Log};
|
||||
use run_command::{async_run_command, CommandOutput};
|
||||
|
||||
pub async fn run_komodo_command(stage: &str, command: String) -> Log {
|
||||
/// Parses commands out of multiline string
|
||||
/// and chains them together with '&&'
|
||||
///
|
||||
/// Supports full line and end of line comments. See [parse_multiline_command].
|
||||
pub async fn run_komodo_command(
|
||||
stage: &str,
|
||||
path: impl Into<Option<&Path>>,
|
||||
command: impl AsRef<str>,
|
||||
) -> Log {
|
||||
let command = parse_multiline_command(command);
|
||||
let command = if let Some(path) = path.into() {
|
||||
format!("cd {} && {command}", path.display(),)
|
||||
} else {
|
||||
command
|
||||
};
|
||||
let start_ts = komodo_timestamp();
|
||||
let output = async_run_command(&command).await;
|
||||
output_into_log(stage, command, start_ts, output)
|
||||
}
|
||||
|
||||
/// Parses commands out of multiline string
|
||||
/// and chains them together with '&&'
|
||||
///
|
||||
/// Supports full line and end of line comments.
|
||||
///
|
||||
/// ## Example:
|
||||
/// ```sh
|
||||
/// # comments supported
|
||||
/// sh ./shell1.sh # end of line supported
|
||||
/// sh ./shell2.sh
|
||||
/// # print done
|
||||
/// echo done
|
||||
/// ```
|
||||
/// becomes
|
||||
/// ```sh
|
||||
/// sh ./shell1.sh && sh ./shell2.sh && echo done
|
||||
/// ```
|
||||
pub fn parse_multiline_command(command: impl AsRef<str>) -> String {
|
||||
command
|
||||
.as_ref()
|
||||
.split('\n')
|
||||
.map(str::trim)
|
||||
.filter(|line| !line.is_empty() && !line.starts_with('#'))
|
||||
.filter_map(|line| line.split(" #").next())
|
||||
.map(str::trim)
|
||||
.collect::<Vec<_>>()
|
||||
.join(" && ")
|
||||
}
|
||||
|
||||
pub fn output_into_log(
|
||||
stage: &str,
|
||||
command: String,
|
||||
|
||||
@@ -39,8 +39,7 @@ where
|
||||
{
|
||||
let args: CloneArgs = clone_args.into();
|
||||
let repo_dir = args.path(repo_dir);
|
||||
let repo_url =
|
||||
args.remote_url(access_token.as_ref().map(String::as_str))?;
|
||||
let repo_url = args.remote_url(access_token.as_deref())?;
|
||||
|
||||
let mut logs = clone_inner(
|
||||
&repo_url,
|
||||
@@ -116,7 +115,8 @@ where
|
||||
replacers.extend(core_replacers.to_owned());
|
||||
let mut on_clone_log = run_komodo_command(
|
||||
"on clone",
|
||||
format!("cd {} && {full_command}", on_clone_path.display()),
|
||||
on_clone_path.as_ref(),
|
||||
full_command,
|
||||
)
|
||||
.await;
|
||||
|
||||
@@ -137,11 +137,8 @@ where
|
||||
} else {
|
||||
let on_clone_log = run_komodo_command(
|
||||
"on clone",
|
||||
format!(
|
||||
"cd {} && {}",
|
||||
on_clone_path.display(),
|
||||
command.command
|
||||
),
|
||||
on_clone_path.as_ref(),
|
||||
&command.command,
|
||||
)
|
||||
.await;
|
||||
tracing::debug!(
|
||||
@@ -170,7 +167,8 @@ where
|
||||
replacers.extend(core_replacers.to_owned());
|
||||
let mut on_pull_log = run_komodo_command(
|
||||
"on pull",
|
||||
format!("cd {} && {full_command}", on_pull_path.display()),
|
||||
on_pull_path.as_ref(),
|
||||
&full_command,
|
||||
)
|
||||
.await;
|
||||
|
||||
@@ -191,11 +189,8 @@ where
|
||||
} else {
|
||||
let on_pull_log = run_komodo_command(
|
||||
"on pull",
|
||||
format!(
|
||||
"cd {} && {}",
|
||||
on_pull_path.display(),
|
||||
command.command
|
||||
),
|
||||
on_pull_path.as_ref(),
|
||||
&command.command,
|
||||
)
|
||||
.await;
|
||||
tracing::debug!(
|
||||
@@ -256,10 +251,8 @@ async fn clone_inner(
|
||||
if let Some(commit) = commit {
|
||||
let reset_log = run_komodo_command(
|
||||
"set commit",
|
||||
format!(
|
||||
"cd {} && git reset --hard {commit}",
|
||||
destination.display()
|
||||
),
|
||||
destination,
|
||||
format!("git reset --hard {commit}",),
|
||||
)
|
||||
.await;
|
||||
logs.push(reset_log);
|
||||
|
||||
@@ -38,16 +38,13 @@ where
|
||||
{
|
||||
let args: CloneArgs = clone_args.into();
|
||||
let path = args.path(repo_dir);
|
||||
let path_display = path.display();
|
||||
let repo_url =
|
||||
args.remote_url(access_token.as_ref().map(String::as_str))?;
|
||||
let repo_url = args.remote_url(access_token.as_deref())?;
|
||||
|
||||
// Set remote url
|
||||
let mut set_remote = run_komodo_command(
|
||||
"set git remote",
|
||||
format!(
|
||||
"cd {path_display} && git remote set-url origin {repo_url}"
|
||||
),
|
||||
path.as_ref(),
|
||||
format!("git remote set-url origin {repo_url}"),
|
||||
)
|
||||
.await;
|
||||
|
||||
@@ -70,7 +67,8 @@ where
|
||||
|
||||
let checkout = run_komodo_command(
|
||||
"checkout branch",
|
||||
format!("cd {path_display} && git checkout -f {}", args.branch),
|
||||
path.as_ref(),
|
||||
format!("git checkout -f {}", args.branch),
|
||||
)
|
||||
.await;
|
||||
|
||||
@@ -83,12 +81,12 @@ where
|
||||
});
|
||||
}
|
||||
|
||||
let command = format!(
|
||||
"cd {path_display} && git pull --rebase --force origin {}",
|
||||
args.branch
|
||||
);
|
||||
|
||||
let pull_log = run_komodo_command("git pull", command).await;
|
||||
let pull_log = run_komodo_command(
|
||||
"git pull",
|
||||
path.as_ref(),
|
||||
format!("git pull --rebase --force origin {}", args.branch),
|
||||
)
|
||||
.await;
|
||||
|
||||
let mut logs = vec![pull_log];
|
||||
|
||||
@@ -104,7 +102,8 @@ where
|
||||
if let Some(commit) = args.commit {
|
||||
let reset_log = run_komodo_command(
|
||||
"set commit",
|
||||
format!("cd {path_display} && git reset --hard {commit}"),
|
||||
path.as_ref(),
|
||||
format!("git reset --hard {commit}"),
|
||||
)
|
||||
.await;
|
||||
logs.push(reset_log);
|
||||
@@ -144,7 +143,7 @@ where
|
||||
};
|
||||
|
||||
if let Some(command) = args.on_pull {
|
||||
if !command.path.is_empty() && !command.command.is_empty() {
|
||||
if !command.command.is_empty() {
|
||||
let on_pull_path = path.join(&command.path);
|
||||
if let Some(secrets) = secrets {
|
||||
let (full_command, mut replacers) =
|
||||
@@ -174,7 +173,8 @@ where
|
||||
replacers.extend(core_replacers.to_owned());
|
||||
let mut on_pull_log = run_komodo_command(
|
||||
"on pull",
|
||||
format!("cd {} && {full_command}", on_pull_path.display()),
|
||||
on_pull_path.as_ref(),
|
||||
&full_command,
|
||||
)
|
||||
.await;
|
||||
|
||||
@@ -195,11 +195,8 @@ where
|
||||
} else {
|
||||
let on_pull_log = run_komodo_command(
|
||||
"on pull",
|
||||
format!(
|
||||
"cd {} && {}",
|
||||
on_pull_path.display(),
|
||||
command.command
|
||||
),
|
||||
on_pull_path.as_ref(),
|
||||
&command.command,
|
||||
)
|
||||
.await;
|
||||
tracing::debug!(
|
||||
|
||||
Reference in New Issue
Block a user