Skip to content

Commit

Permalink
1.16.4 (#151)
Browse files Browse the repository at this point in the history
* rust client improvements and docs

* sync rust client

* version 1.16.4

* UI support YAML / TOML utils, typed Deno namespace

* add ResourcesToml to typeshare

* add YAML and TOML convenience

* make the types available globally

* preload container with @std/yaml and @std/toml, clean up genned files

* add deno setup to alpine dockerfile
  • Loading branch information
mbecker20 authored Oct 26, 2024
1 parent 3f1cfa9 commit 7a9ad42
Show file tree
Hide file tree
Showing 22 changed files with 8,201 additions and 130 deletions.
25 changes: 13 additions & 12 deletions Cargo.lock

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

2 changes: 1 addition & 1 deletion Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,7 @@ members = [
]

[workspace.package]
version = "1.16.3"
version = "1.16.4"
edition = "2021"
authors = ["mbecker20 <[email protected]>"]
license = "GPL-3.0-or-later"
Expand Down
6 changes: 4 additions & 2 deletions bin/cli/src/state.rs
Original file line number Diff line number Diff line change
Expand Up @@ -40,7 +40,9 @@ pub fn komodo_client() -> &'static KomodoClient {
creds
}
};
futures::executor::block_on(KomodoClient::new(url, key, secret))
.expect("failed to initialize Komodo client")
futures::executor::block_on(
KomodoClient::new(url, key, secret).with_healthcheck(),
)
.expect("failed to initialize Komodo client")
})
}
6 changes: 6 additions & 0 deletions bin/core/alpine.Dockerfile
Original file line number Diff line number Diff line change
Expand Up @@ -34,6 +34,12 @@ COPY --from=core-builder /builder/target/release/core /app
COPY --from=frontend-builder /builder/frontend/dist /app/frontend
COPY --from=denoland/deno:bin /deno /usr/local/bin/deno

# Set $DENO_DIR and preload external Deno deps
ENV DENO_DIR=/action-cache/deno
RUN mkdir /action-cache && \
cd /action-cache && \
deno install jsr:@std/yaml jsr:@std/toml

# Hint at the port
EXPOSE 9120

Expand Down
6 changes: 6 additions & 0 deletions bin/core/debian.Dockerfile
Original file line number Diff line number Diff line change
Expand Up @@ -29,6 +29,12 @@ COPY --from=core-builder /builder/target/release/core /app
COPY --from=frontend-builder /builder/frontend/dist /app/frontend
COPY --from=denoland/deno:bin /deno /usr/local/bin/deno

# Set $DENO_DIR and preload external Deno deps
ENV DENO_DIR=/action-cache/deno
RUN mkdir /action-cache && \
cd /action-cache && \
deno install jsr:@std/yaml jsr:@std/toml

# Hint at the port
EXPOSE 9120

Expand Down
122 changes: 108 additions & 14 deletions bin/core/src/api/execute/action.rs
Original file line number Diff line number Diff line change
@@ -1,4 +1,9 @@
use std::collections::HashSet;
use std::{
collections::HashSet,
path::{Path, PathBuf},
str::FromStr,
sync::OnceLock,
};

use anyhow::Context;
use command::run_komodo_command;
Expand Down Expand Up @@ -81,26 +86,22 @@ impl Resolve<RunAction, (User, Update)> for State {
.into_iter()
.collect::<Vec<_>>();

let path = core_config()
.action_directory
.join(format!("{}.ts", random_string(10)));
let file = format!("{}.ts", random_string(10));
let path = core_config().action_directory.join(&file);

if let Some(parent) = path.parent() {
let _ = fs::create_dir_all(parent).await;
}

fs::write(&path, contents).await.with_context(|| {
format!("Faild to write action file to {path:?}")
format!("Failed to write action file to {path:?}")
})?;

let mut res = run_komodo_command(
// Keep this stage name as is, the UI will find the latest update log by matching the stage name
"Execute Action",
None,
format!(
"deno run --allow-read --allow-net --allow-import {}",
path.display()
),
format!("deno run --allow-all {}", path.display()),
false,
)
.await;
Expand All @@ -110,11 +111,7 @@ impl Resolve<RunAction, (User, Update)> for State {
res.stderr = svi::replace_in_string(&res.stderr, &replacers)
.replace(&secret, "<ACTION_API_SECRET>");

if let Err(e) = fs::remove_file(path).await {
warn!(
"Failed to delete action file after action execution | {e:#}"
);
}
cleanup_run(file + ".js", &path).await;

if let Err(e) = State
.resolve(DeleteApiKey { key }, action_user().to_owned())
Expand Down Expand Up @@ -187,6 +184,22 @@ fn full_contents(contents: &str, key: &str, secret: &str) -> String {
let base_url = format!("{protocol}://localhost:{port}");
format!(
"import {{ KomodoClient }} from '{base_url}/client/lib.js';
import * as __YAML__ from 'jsr:@std/yaml';
import * as __TOML__ from 'jsr:@std/toml';
const YAML = {{
stringify: __YAML__.stringify,
parse: __YAML__.parse,
parseAll: __YAML__.parseAll,
parseDockerCompose: __YAML__.parse,
}}
const TOML = {{
stringify: __TOML__.stringify,
parse: __TOML__.parse,
parseResourceToml: __TOML__.parse,
parseCargoToml: __TOML__.parse,
}}
const komodo = KomodoClient('{base_url}', {{
type: 'api-key',
Expand All @@ -207,3 +220,84 @@ main().catch(error => {{
}}).then(() => console.log('🦎 Action completed successfully 🦎'));"
)
}

/// Cleans up file at given path.
/// ALSO if $DENO_DIR is set,
/// will clean up the generated file matching "file"
async fn cleanup_run(file: String, path: &Path) {
if let Err(e) = fs::remove_file(path).await {
warn!(
"Failed to delete action file after action execution | {e:#}"
);
}
// If $DENO_DIR is set (will be in container),
// will clean up the generated file matching "file" (NOT under path)
let Some(deno_dir) = deno_dir() else {
return;
};
delete_file(deno_dir.join("gen/file"), file).await;
}

fn deno_dir() -> Option<&'static Path> {
static DENO_DIR: OnceLock<Option<PathBuf>> = OnceLock::new();
DENO_DIR
.get_or_init(|| {
let deno_dir = std::env::var("DENO_DIR").ok()?;
PathBuf::from_str(&deno_dir).ok()
})
.as_deref()
}

/// file is just the terminating file path,
/// it may be nested multiple folder under path,
/// this will find the nested file and delete it.
/// Assumes the file is only there once.
fn delete_file(
dir: PathBuf,
file: String,
) -> std::pin::Pin<Box<dyn std::future::Future<Output = bool> + Send>>
{
Box::pin(async move {
let Ok(mut dir) = fs::read_dir(dir).await else {
return false;
};
// Collect the nested folders for recursing
// only after checking all the files in directory.
let mut folders = Vec::<PathBuf>::new();

while let Ok(Some(entry)) = dir.next_entry().await {
let Ok(meta) = entry.metadata().await else {
continue;
};
if meta.is_file() {
let Ok(name) = entry.file_name().into_string() else {
continue;
};
if name == file {
if let Err(e) = fs::remove_file(entry.path()).await {
warn!(
"Failed to clean up generated file after action execution | {e:#}"
);
};
return true;
}
} else {
folders.push(entry.path());
}
}

if folders.len() == 1 {
// unwrap ok, folders definitely is not empty
let folder = folders.pop().unwrap();
delete_file(folder, file).await
} else {
// Check folders with file.clone
for folder in folders {
if delete_file(folder, file.clone()).await {
return true;
}
}
false
}
})
}
2 changes: 2 additions & 0 deletions client/core/rs/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -11,7 +11,9 @@ repository.workspace = true
# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html

[features]
# default = ["blocking"] # use to dev client blocking mode
mongo = ["dep:mongo_indexed"]
blocking = ["reqwest/blocking"]

[dependencies]
# mogh
Expand Down
33 changes: 32 additions & 1 deletion client/core/rs/README.md
Original file line number Diff line number Diff line change
@@ -1,4 +1,35 @@
# Komodo
*A system to build and deploy software across many servers*

Docs: [https://docs.rs/komodo_client/latest/komodo_client](https://docs.rs/komodo_client/latest/komodo_client)
Full Docs: [https://docs.rs/komodo_client/latest/komodo_client](https://docs.rs/komodo_client/latest/komodo_client).

This is a client library for the Komodo Core API.
It contains:
- Definitions for the application [api](https://docs.rs/komodo_client/latest/komodo_client/api/index.html)
and [entities](https://docs.rs/komodo_client/latest/komodo_client/entities/index.html).
- A [client](https://docs.rs/komodo_client/latest/komodo_client/struct.KomodoClient.html)
to interact with the Komodo Core API.
- Information on configuring Komodo
[Core](https://docs.rs/komodo_client/latest/komodo_client/entities/config/core/index.html) and
[Periphery](https://docs.rs/komodo_client/latest/komodo_client/entities/config/periphery/index.html).

## Client Configuration

The client includes a convenenience method to parse the Komodo API url and credentials from the environment:
- `KOMODO_ADDRESS`
- `KOMODO_API_KEY`
- `KOMODO_API_SECRET`

## Client Example
```rust
dotenvy::dotenv().ok();

let client = KomodoClient::new_from_env()?;

// Get all the deployments
let deployments = client.read(ListDeployments::default()).await?;

println!("{deployments:#?}");

let update = client.execute(RunBuild { build: "test-build".to_string() }).await?:
```
Loading

0 comments on commit 7a9ad42

Please sign in to comment.