mirror of
https://github.com/moghtech/komodo.git
synced 2026-09-13 08:01:17 +00:00
* start 1.19.1 * deploy 1.19.1-dev-1 * Global Auto Update rustdoc * support stack additional files * deploy 1.19.1-dev-2 * Fe support additional file language detection * fix tsc * Fix: Example code blocks got interpreted as rust code, leading to compilation errors (#743) * Enhanced Server Stats Dashboard with Performance Optimizations (#746) * Improve the layout of server mini stats in the dashboard. - Server stats and tags made siblings for clearer responsibilities - Changed margin to padding - Unreachable indicator made into an overlay of the stats * feat: optimize dashboard server stats with lazy loading and smart server availability checks - Add enabled prop to ServerStatsMini for conditional data fetching - Implement server availability check (only fetch stats for Ok servers, not NotOk/Disabled) - Prevent 500 errors by avoiding API calls to offline servers - Increase polling interval from 10s to 15s and add 5s stale time - Add useMemo for expensive calculations to reduce re-renders - Add conditional overlay rendering for unreachable servers - Only render stats when showServerStats preference is enabled * fix: show disabled servers with overlay instead of hiding component - Maintain consistent layout by showing disabled state overlay - Prevent UX inconsistency where disabled servers disappeared entirely * fix: show button height * feat: add enhance card animations * cleanup * gen types * deploy 1.19.1-dev-3 * add .ini * deploy 1.19.1-dev-4 * simple configure action args as JSON * server enabled actually defaults false * SendAlert via Action / CLI * fix clippy if let string * deploy 1.19.1-dev-5 * improve cli ergonomics * gen types and fix responses formatting * Add RunStackService API implementing `docker compose run` (#732) * Add RunStackService API implementing `docker compose run` * Add working Procedure configuration * Remove `km execute run` alias. Remove redundant ``#[serde(default)]` on `Option`. * Refactor command from `String` to `Vec<String>` * Implement proper shell escaping * bump deps * Update configuration.md - fix typo: "affect" -> "effect" (#747) * clean up SendAlert doc * deploy 1.19.1-dev-6 * env file args won't double pass env file * deploy 1.19.1-dev-7 * Add Enter Key Support for Dialog Confirmations (#750) * start 1.19.1 * deploy 1.19.1-dev-1 * Implement usePromptHotkeys for enhanced dialog interactions and UX * Refactor usePromptHotkeys to enhance confirm button detection and improve UX * Remove forceConfirmDialog prop from ActionWithDialog and related logic for cleaner implementation * Add dialog descriptions to ConfirmUpdate and ActionWithDialog for better clarity and resolve warnings * fix * Restore forceConfirmDialog prop to ActionWithDialog for enhanced confirmation handling * cleanup * Remove conditional className logic from ConfirmButton --------- Co-authored-by: mbecker20 <max@mogh.tech> * Support complex file depency action resolution * get FE compile * deploy 1.19.1-dev-8 * implement additional file dependency configuration * deploy 1.19.1-dev-9 * UI default file dependency None * default additional file requires is None * deploy 1.19.1-dev-10 * rename additional_files => config_files for clarity * deploy 1.19.1-dev-11 * fix skip serializing if None * deploy 1.19.1-dev-12 * stack file dependency toml parsing aliases * fmt * Add: Server Version Mismatch Warnings & Alert System (#748) * start 1.19.1 * deploy 1.19.1-dev-1 * feat: implement version mismatch warnings in server UI - Replace orange warning colors with yellow for better visibility - Add version mismatch detection that shows warnings instead of OK status Implement responsive "VERSION MISMATCH" badge layout - Update server dashboard to include warning counts - Add backend version comparison logic for GetServersSummary * feat: add warning count to server summary and update backup documentation link * feat: add server version mismatch alert handling and update server summary invalidation logic * fix: correct version mismatch alert config and disabled server display - Use send_version_mismatch_alerts instead of send_unreachable_alerts - Show 'Unknown' instead of 'Disabled' for disabled server versions - Remove commented VersionAlert and Alerts UI components - Update version to 1.19.0 * cleanup * Update TypeScript types after merge * cleanup * cleanup * cleanup * Add "ServerVersionMismatch" to alert types * Adjust color classes for warning states and revert server update invalidation logic --------- Co-authored-by: mbecker20 <max@mogh.tech> * backend for build multi registry push support * deploy 1.19.1-dev-13 * build multi registry configuration * deploy 1.19.1-dev-14 * fix invalid tokens JSON * DeployStackIfChanged restarts also update stack.info.deployed_contents * update deployed services comments * deploy 1.19.1-dev-15 * Enhance server monitoring with load average data and new server monitoring table (#761) * add monitoring page * initial table * moving monitoring table to servers * add cpu load average * typeshare doesnt allow tuples * fix GetHistoricalServerStats * add loadAvg to the server monitoring table * improve styling * add load average chart * multiple colors for average loads chart * make load average chart line and non-stacked * cleanup * use server thresholds * cleanup * Change "Dependents:" to "Services:" in config file service dependency selector * deploy 1.19.1-dev-16 * 1.19.1 --------- Co-authored-by: mbecker20 <max@mogh.tech> Co-authored-by: Marcel Pfennig <82059270+MP-Tool@users.noreply.github.com> Co-authored-by: Brian Bradley <brian.bradley.p@gmail.com> Co-authored-by: Ravi Wolter-Krishan <rkn@gedikas.net> Co-authored-by: jack <45038833+jackra1n@users.noreply.github.com>
214 lines
5.8 KiB
Rust
214 lines
5.8 KiB
Rust
//! # Komodo
|
|
//! *A system to build and deploy software across many servers*. [**https://komo.do**](https://komo.do)
|
|
//!
|
|
//! This is a client library for the Komodo Core API.
|
|
//! It contains:
|
|
//! - Definitions for the application [api] and [entities].
|
|
//! - A [client][KomodoClient] to interact with the Komodo Core API.
|
|
//! - Information on configuring Komodo [Core][entities::config::core] and [Periphery][entities::config::periphery].
|
|
//!
|
|
//! ## 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
|
|
//! ```text
|
|
//! 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?:
|
|
//! ```
|
|
|
|
use std::{sync::OnceLock, time::Duration};
|
|
|
|
use anyhow::Context;
|
|
use api::read::GetVersion;
|
|
use serde::Deserialize;
|
|
|
|
pub mod api;
|
|
pub mod busy;
|
|
pub mod deserializers;
|
|
pub mod entities;
|
|
pub mod parsers;
|
|
pub mod terminal;
|
|
pub mod ws;
|
|
|
|
mod request;
|
|
|
|
/// &'static KomodoClient initialized from environment.
|
|
pub fn komodo_client() -> &'static KomodoClient {
|
|
static KOMODO_CLIENT: OnceLock<KomodoClient> = OnceLock::new();
|
|
KOMODO_CLIENT.get_or_init(|| {
|
|
KomodoClient::new_from_env()
|
|
.context("Missing KOMODO_ADDRESS, KOMODO_API_KEY, KOMODO_API_SECRET from env")
|
|
.unwrap()
|
|
})
|
|
}
|
|
|
|
/// Default environment variables for the [KomodoClient].
|
|
#[derive(Deserialize)]
|
|
pub struct KomodoEnv {
|
|
/// KOMODO_ADDRESS
|
|
pub komodo_address: String,
|
|
/// KOMODO_API_KEY
|
|
pub komodo_api_key: String,
|
|
/// KOMODO_API_SECRET
|
|
pub komodo_api_secret: String,
|
|
}
|
|
|
|
/// Client to interface with [Komodo](https://komo.do/docs/api#rust-client)
|
|
#[derive(Clone)]
|
|
pub struct KomodoClient {
|
|
#[cfg(not(feature = "blocking"))]
|
|
reqwest: reqwest::Client,
|
|
#[cfg(feature = "blocking")]
|
|
reqwest: reqwest::blocking::Client,
|
|
address: String,
|
|
key: String,
|
|
secret: String,
|
|
}
|
|
|
|
impl KomodoClient {
|
|
/// Initializes KomodoClient, including a health check.
|
|
pub fn new(
|
|
address: impl Into<String>,
|
|
key: impl Into<String>,
|
|
secret: impl Into<String>,
|
|
) -> KomodoClient {
|
|
KomodoClient {
|
|
reqwest: Default::default(),
|
|
address: address.into(),
|
|
key: key.into(),
|
|
secret: secret.into(),
|
|
}
|
|
}
|
|
|
|
/// Initializes KomodoClient from environment: [KomodoEnv]
|
|
pub fn new_from_env() -> anyhow::Result<KomodoClient> {
|
|
let KomodoEnv {
|
|
komodo_address,
|
|
komodo_api_key,
|
|
komodo_api_secret,
|
|
} = envy::from_env()
|
|
.context("failed to parse environment for komodo client")?;
|
|
Ok(KomodoClient::new(
|
|
komodo_address,
|
|
komodo_api_key,
|
|
komodo_api_secret,
|
|
))
|
|
}
|
|
|
|
/// Add a healthcheck in the initialization pipeline:
|
|
///
|
|
/// ```text
|
|
/// let komodo = KomodoClient::new_from_env()?
|
|
/// .with_healthcheck().await?;
|
|
/// ```
|
|
#[cfg(not(feature = "blocking"))]
|
|
pub async fn with_healthcheck(self) -> anyhow::Result<Self> {
|
|
self.health_check().await?;
|
|
Ok(self)
|
|
}
|
|
|
|
/// Add a healthcheck in the initialization pipeline:
|
|
///
|
|
/// ```text
|
|
/// let komodo = KomodoClient::new_from_env()?
|
|
/// .with_healthcheck().await?;
|
|
/// ```
|
|
#[cfg(feature = "blocking")]
|
|
pub fn with_healthcheck(self) -> anyhow::Result<Self> {
|
|
self.health_check()?;
|
|
Ok(self)
|
|
}
|
|
|
|
/// Get the Core version.
|
|
#[cfg(not(feature = "blocking"))]
|
|
pub async fn core_version(&self) -> anyhow::Result<String> {
|
|
self.read(GetVersion {}).await.map(|r| r.version)
|
|
}
|
|
|
|
/// Get the Core version.
|
|
#[cfg(feature = "blocking")]
|
|
pub fn core_version(&self) -> anyhow::Result<String> {
|
|
self.read(GetVersion {}).map(|r| r.version)
|
|
}
|
|
|
|
/// Send a health check.
|
|
#[cfg(not(feature = "blocking"))]
|
|
pub async fn health_check(&self) -> anyhow::Result<()> {
|
|
self.read(GetVersion {}).await.map(|_| ())
|
|
}
|
|
|
|
/// Send a health check.
|
|
#[cfg(feature = "blocking")]
|
|
pub fn health_check(&self) -> anyhow::Result<()> {
|
|
self.read(GetVersion {}).map(|_| ())
|
|
}
|
|
|
|
/// Use a custom reqwest client.
|
|
#[cfg(not(feature = "blocking"))]
|
|
pub fn set_reqwest(mut self, reqwest: reqwest::Client) -> Self {
|
|
self.reqwest = reqwest;
|
|
self
|
|
}
|
|
|
|
/// Use a custom reqwest client.
|
|
#[cfg(feature = "blocking")]
|
|
pub fn set_reqwest(
|
|
mut self,
|
|
reqwest: reqwest::blocking::Client,
|
|
) -> Self {
|
|
self.reqwest = reqwest;
|
|
self
|
|
}
|
|
|
|
/// Poll an [Update][entities::update::Update] (returned by the `execute` calls) until the
|
|
/// [UpdateStatus][entities::update::UpdateStatus] is `Complete`, and then return it.
|
|
#[cfg(not(feature = "blocking"))]
|
|
pub async fn poll_update_until_complete(
|
|
&self,
|
|
update_id: impl Into<String>,
|
|
) -> anyhow::Result<entities::update::Update> {
|
|
let update_id = update_id.into();
|
|
loop {
|
|
let update = self
|
|
.read(api::read::GetUpdate {
|
|
id: update_id.clone(),
|
|
})
|
|
.await?;
|
|
if update.status == entities::update::UpdateStatus::Complete {
|
|
return Ok(update);
|
|
}
|
|
tokio::time::sleep(Duration::from_millis(500)).await;
|
|
}
|
|
}
|
|
|
|
/// Poll an [Update][entities::update::Update] (returned by the `execute` calls) until the
|
|
/// [UpdateStatus][entities::update::UpdateStatus] is `Complete`, and then return it.
|
|
#[cfg(feature = "blocking")]
|
|
pub fn poll_update_until_complete(
|
|
&self,
|
|
update_id: impl Into<String>,
|
|
) -> anyhow::Result<entities::update::Update> {
|
|
let update_id = update_id.into();
|
|
loop {
|
|
let update = self.read(api::read::GetUpdate {
|
|
id: update_id.clone(),
|
|
})?;
|
|
if update.status == entities::update::UpdateStatus::Complete {
|
|
return Ok(update);
|
|
}
|
|
}
|
|
}
|
|
}
|