mirror of
https://github.com/moghtech/komodo.git
synced 2026-11-03 19:27:02 -06:00
Compare commits
7
Commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
5c99958cba | ||
|
|
7288f067c5 | ||
|
|
5d0f7de9fb | ||
|
|
4129abcfd0 | ||
|
|
4275e903eb | ||
|
|
c57c321cbb | ||
|
|
9a7d49b35e |
Generated
+21
-21
@@ -1131,7 +1131,7 @@ dependencies = [
|
||||
|
||||
[[package]]
|
||||
name = "command"
|
||||
version = "2.0.0-dev-114"
|
||||
version = "2.0.0-dev-116"
|
||||
dependencies = [
|
||||
"komodo_client",
|
||||
"shlex",
|
||||
@@ -1462,7 +1462,7 @@ checksum = "d7a1e2f27636f116493b8b860f5546edb47c8d8f8ea73e1d2a20be88e28d1fea"
|
||||
|
||||
[[package]]
|
||||
name = "database"
|
||||
version = "2.0.0-dev-114"
|
||||
version = "2.0.0-dev-116"
|
||||
dependencies = [
|
||||
"anyhow",
|
||||
"async-compression",
|
||||
@@ -1732,7 +1732,7 @@ dependencies = [
|
||||
|
||||
[[package]]
|
||||
name = "encoding"
|
||||
version = "2.0.0-dev-114"
|
||||
version = "2.0.0-dev-116"
|
||||
dependencies = [
|
||||
"anyhow",
|
||||
"bytes",
|
||||
@@ -1774,7 +1774,7 @@ dependencies = [
|
||||
|
||||
[[package]]
|
||||
name = "environment"
|
||||
version = "2.0.0-dev-114"
|
||||
version = "2.0.0-dev-116"
|
||||
dependencies = [
|
||||
"anyhow",
|
||||
"formatting",
|
||||
@@ -1903,7 +1903,7 @@ dependencies = [
|
||||
|
||||
[[package]]
|
||||
name = "formatting"
|
||||
version = "2.0.0-dev-114"
|
||||
version = "2.0.0-dev-116"
|
||||
dependencies = [
|
||||
"mogh_error",
|
||||
]
|
||||
@@ -2069,7 +2069,7 @@ dependencies = [
|
||||
|
||||
[[package]]
|
||||
name = "git"
|
||||
version = "2.0.0-dev-114"
|
||||
version = "2.0.0-dev-116"
|
||||
dependencies = [
|
||||
"anyhow",
|
||||
"command",
|
||||
@@ -2663,7 +2663,7 @@ dependencies = [
|
||||
|
||||
[[package]]
|
||||
name = "interpolate"
|
||||
version = "2.0.0-dev-114"
|
||||
version = "2.0.0-dev-116"
|
||||
dependencies = [
|
||||
"anyhow",
|
||||
"komodo_client",
|
||||
@@ -2772,9 +2772,9 @@ dependencies = [
|
||||
|
||||
[[package]]
|
||||
name = "jsonwebtoken"
|
||||
version = "10.2.0"
|
||||
version = "10.3.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "c76e1c7d7df3e34443b3621b459b066a7b79644f059fc8b2db7070c825fd417e"
|
||||
checksum = "0529410abe238729a60b108898784df8984c87f6054c9c4fcacc47e4803c1ce1"
|
||||
dependencies = [
|
||||
"aws-lc-rs",
|
||||
"base64 0.22.1",
|
||||
@@ -2789,7 +2789,7 @@ dependencies = [
|
||||
|
||||
[[package]]
|
||||
name = "komodo_cli"
|
||||
version = "2.0.0-dev-114"
|
||||
version = "2.0.0-dev-116"
|
||||
dependencies = [
|
||||
"anyhow",
|
||||
"chrono",
|
||||
@@ -2817,7 +2817,7 @@ dependencies = [
|
||||
|
||||
[[package]]
|
||||
name = "komodo_client"
|
||||
version = "2.0.0-dev-114"
|
||||
version = "2.0.0-dev-116"
|
||||
dependencies = [
|
||||
"anyhow",
|
||||
"async_timing_util",
|
||||
@@ -2856,7 +2856,7 @@ dependencies = [
|
||||
|
||||
[[package]]
|
||||
name = "komodo_core"
|
||||
version = "2.0.0-dev-114"
|
||||
version = "2.0.0-dev-116"
|
||||
dependencies = [
|
||||
"anyhow",
|
||||
"arc-swap",
|
||||
@@ -2929,7 +2929,7 @@ dependencies = [
|
||||
|
||||
[[package]]
|
||||
name = "komodo_periphery"
|
||||
version = "2.0.0-dev-114"
|
||||
version = "2.0.0-dev-116"
|
||||
dependencies = [
|
||||
"anyhow",
|
||||
"arc-swap",
|
||||
@@ -3173,9 +3173,9 @@ dependencies = [
|
||||
|
||||
[[package]]
|
||||
name = "mogh_auth_server"
|
||||
version = "1.2.4"
|
||||
version = "1.2.5"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "2eeb8c898da571c59ec9f4997b6869c5a3b31303d95c765ee50713cb4c045be9"
|
||||
checksum = "fa05efbe7caf986807ba12d9dcafb722a7c0f2fb51f6dafd87fa2529122a3b87"
|
||||
dependencies = [
|
||||
"anyhow",
|
||||
"arc-swap",
|
||||
@@ -3341,9 +3341,9 @@ dependencies = [
|
||||
|
||||
[[package]]
|
||||
name = "mogh_server"
|
||||
version = "1.3.0"
|
||||
version = "1.4.3"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "ffd2b7646dbaa1a09b3df6782f1692e459775a6fb46fb2d613d43ae5ca1a9dcb"
|
||||
checksum = "9601ac6b48b8a932d5944aa68944b03147b79187dd046d78dcc077d5c64089c2"
|
||||
dependencies = [
|
||||
"anyhow",
|
||||
"axum",
|
||||
@@ -3979,7 +3979,7 @@ checksum = "9b4f627cb1b25917193a259e49bdad08f671f8d9708acfd5fe0a8c1455d87220"
|
||||
|
||||
[[package]]
|
||||
name = "periphery_client"
|
||||
version = "2.0.0-dev-114"
|
||||
version = "2.0.0-dev-116"
|
||||
dependencies = [
|
||||
"anyhow",
|
||||
"encoding",
|
||||
@@ -5883,7 +5883,7 @@ dependencies = [
|
||||
|
||||
[[package]]
|
||||
name = "transport"
|
||||
version = "2.0.0-dev-114"
|
||||
version = "2.0.0-dev-116"
|
||||
dependencies = [
|
||||
"anyhow",
|
||||
"axum",
|
||||
@@ -6135,9 +6135,9 @@ dependencies = [
|
||||
|
||||
[[package]]
|
||||
name = "uuid"
|
||||
version = "1.19.0"
|
||||
version = "1.20.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "e2e054861b4bd027cd373e18e8d8d8e6548085000e41290d95ce0c373a654b4a"
|
||||
checksum = "ee48d38b119b0cd71fe4141b30f5ba9c7c5d9f4e7a3a8b4a674e4b6ef789976f"
|
||||
dependencies = [
|
||||
"getrandom 0.3.4",
|
||||
"js-sys",
|
||||
|
||||
+3
-3
@@ -8,7 +8,7 @@ members = [
|
||||
]
|
||||
|
||||
[workspace.package]
|
||||
version = "2.0.0-dev-114"
|
||||
version = "2.0.0-dev-116"
|
||||
edition = "2024"
|
||||
authors = ["mbecker20 <becker.maxh@gmail.com>"]
|
||||
license = "GPL-3.0-or-later"
|
||||
@@ -37,7 +37,7 @@ mogh_error = { version = "1.0.3", default-features = false }
|
||||
derive_default_builder = "0.1.8"
|
||||
async_timing_util = "1.1.0"
|
||||
mogh_auth_client = "1.2.1"
|
||||
mogh_auth_server = "1.2.4"
|
||||
mogh_auth_server = "1.2.5"
|
||||
mogh_secret_file = "1.0.0"
|
||||
mogh_validations = "1.0.0"
|
||||
mogh_rate_limit = "1.0.0"
|
||||
@@ -46,7 +46,7 @@ mongo_indexed = "2.0.2"
|
||||
mogh_resolver = "1.0.0"
|
||||
mogh_config = "1.0.1"
|
||||
mogh_logger = "1.3.0"
|
||||
mogh_server = "1.3.0"
|
||||
mogh_server = "1.4.3"
|
||||
toml_pretty = "2.0.0"
|
||||
mogh_cache = "1.1.1"
|
||||
mogh_pki = "1.1.0"
|
||||
|
||||
@@ -27,12 +27,12 @@ use periphery_client::api::{self, container::InspectContainer};
|
||||
|
||||
use crate::{
|
||||
alert::send_alerts,
|
||||
api::execute::{self, ExecuteRequest},
|
||||
api::execute::{self, ExecuteRequest, ExecutionResult},
|
||||
helpers::{
|
||||
periphery_client,
|
||||
query::{get_deployment_state, get_swarm_or_server},
|
||||
registry_token,
|
||||
update::{add_update, make_update},
|
||||
update::{add_update, make_update, poll_update_until_complete},
|
||||
},
|
||||
permission::get_check_permissions,
|
||||
resource::{
|
||||
@@ -520,32 +520,42 @@ pub async fn check_deployment_for_update_inner(
|
||||
)
|
||||
.await
|
||||
{
|
||||
Ok(_) => {
|
||||
let ts = komodo_timestamp();
|
||||
let alert = Alert {
|
||||
id: Default::default(),
|
||||
ts,
|
||||
resolved: true,
|
||||
resolved_ts: ts.into(),
|
||||
level: SeverityLevel::Ok,
|
||||
target: ResourceTarget::Deployment(id.clone()),
|
||||
data: AlertData::DeploymentAutoUpdated {
|
||||
id,
|
||||
name,
|
||||
swarm_id,
|
||||
swarm_name,
|
||||
server_id,
|
||||
server_name,
|
||||
image,
|
||||
},
|
||||
Ok(res) => {
|
||||
let ExecutionResult::Single(update) = res else {
|
||||
unreachable!()
|
||||
};
|
||||
let res = db_client().alerts.insert_one(&alert).await;
|
||||
if let Err(e) = res {
|
||||
error!(
|
||||
"Failed to record DeploymentAutoUpdated to db | {e:#}"
|
||||
);
|
||||
let Ok(update) =
|
||||
poll_update_until_complete(&update.id).await
|
||||
else {
|
||||
return;
|
||||
};
|
||||
if update.success {
|
||||
let ts = komodo_timestamp();
|
||||
let alert = Alert {
|
||||
id: Default::default(),
|
||||
ts,
|
||||
resolved: true,
|
||||
resolved_ts: ts.into(),
|
||||
level: SeverityLevel::Ok,
|
||||
target: ResourceTarget::Deployment(id.clone()),
|
||||
data: AlertData::DeploymentAutoUpdated {
|
||||
id,
|
||||
name,
|
||||
swarm_id,
|
||||
swarm_name,
|
||||
server_id,
|
||||
server_name,
|
||||
image,
|
||||
},
|
||||
};
|
||||
let res = db_client().alerts.insert_one(&alert).await;
|
||||
if let Err(e) = res {
|
||||
error!(
|
||||
"Failed to record DeploymentAutoUpdated to db | {e:#}"
|
||||
);
|
||||
}
|
||||
send_alerts(&[alert]).await;
|
||||
}
|
||||
send_alerts(&[alert]).await;
|
||||
}
|
||||
Err(e) => {
|
||||
warn!("Failed to auto update Deployment {name} | {e:#}",)
|
||||
|
||||
@@ -33,12 +33,12 @@ use periphery_client::api::compose::{
|
||||
|
||||
use crate::{
|
||||
alert::send_alerts,
|
||||
api::execute::{self, ExecuteRequest},
|
||||
api::execute::{self, ExecuteRequest, ExecutionResult},
|
||||
config::core_config,
|
||||
helpers::{
|
||||
query::get_swarm_or_server,
|
||||
stack_git_token, swarm_or_server_request,
|
||||
update::{add_update, make_update},
|
||||
update::{add_update, make_update, poll_update_until_complete},
|
||||
},
|
||||
permission::get_check_permissions,
|
||||
resource::{self, list_full_for_user_using_pattern},
|
||||
@@ -750,17 +750,28 @@ pub async fn check_stack_for_update_inner(
|
||||
let cache = image_digest_cache();
|
||||
|
||||
for service in &mut stack.info.latest_services {
|
||||
if service.image.is_empty() ||
|
||||
// Prefer the image coming from deployed services
|
||||
// so it will be after any interpolation.
|
||||
let image = stack
|
||||
.info
|
||||
.deployed_services
|
||||
.as_ref()
|
||||
.and_then(|services| {
|
||||
services.iter().find_map(|deployed| {
|
||||
(deployed.service_name == service.service_name)
|
||||
.then_some(&deployed.image)
|
||||
})
|
||||
})
|
||||
.unwrap_or(&service.image);
|
||||
|
||||
if image.is_empty() ||
|
||||
// Images with a hardcoded digest can't have update.
|
||||
service.image.contains('@')
|
||||
image.contains('@')
|
||||
{
|
||||
service.image_digest = None;
|
||||
continue;
|
||||
}
|
||||
match cache
|
||||
.get(&swarm_or_server, &service.image, None, None)
|
||||
.await
|
||||
{
|
||||
match cache.get(&swarm_or_server, image, None, None).await {
|
||||
Ok(digest) => service.image_digest = Some(digest),
|
||||
Err(e) => {
|
||||
warn!(
|
||||
@@ -946,33 +957,42 @@ pub async fn check_stack_for_update_inner(
|
||||
)
|
||||
.await
|
||||
{
|
||||
Ok(_) => {
|
||||
let ts = komodo_timestamp();
|
||||
let alert = Alert {
|
||||
id: Default::default(),
|
||||
ts,
|
||||
resolved: true,
|
||||
resolved_ts: ts.into(),
|
||||
level: SeverityLevel::Ok,
|
||||
target: ResourceTarget::Stack(stack.id.clone()),
|
||||
data: AlertData::StackAutoUpdated {
|
||||
id: stack.id.clone(),
|
||||
name: stack.name.clone(),
|
||||
swarm_id,
|
||||
swarm_name,
|
||||
server_id,
|
||||
server_name,
|
||||
images: services_with_update
|
||||
.iter()
|
||||
.map(|service| service.image.clone())
|
||||
.collect(),
|
||||
},
|
||||
Ok(res) => {
|
||||
let ExecutionResult::Single(update) = res else {
|
||||
unreachable!()
|
||||
};
|
||||
let res = db_client().alerts.insert_one(&alert).await;
|
||||
if let Err(e) = res {
|
||||
error!("Failed to record StackAutoUpdated to db | {e:#}");
|
||||
let Ok(update) = poll_update_until_complete(&update.id).await
|
||||
else {
|
||||
return;
|
||||
};
|
||||
if update.success {
|
||||
let ts = komodo_timestamp();
|
||||
let alert = Alert {
|
||||
id: Default::default(),
|
||||
ts,
|
||||
resolved: true,
|
||||
resolved_ts: ts.into(),
|
||||
level: SeverityLevel::Ok,
|
||||
target: ResourceTarget::Stack(stack.id.clone()),
|
||||
data: AlertData::StackAutoUpdated {
|
||||
id: stack.id.clone(),
|
||||
name: stack.name.clone(),
|
||||
swarm_id,
|
||||
swarm_name,
|
||||
server_id,
|
||||
server_name,
|
||||
images: services_with_update
|
||||
.iter()
|
||||
.map(|service| service.image.clone())
|
||||
.collect(),
|
||||
},
|
||||
};
|
||||
let res = db_client().alerts.insert_one(&alert).await;
|
||||
if let Err(e) = res {
|
||||
error!("Failed to record StackAutoUpdated to db | {e:#}");
|
||||
}
|
||||
send_alerts(&[alert]).await;
|
||||
}
|
||||
send_alerts(&[alert]).await;
|
||||
}
|
||||
Err(e) => {
|
||||
warn!("Failed to auto update Stack {} | {e:#}", stack.name)
|
||||
|
||||
@@ -143,9 +143,7 @@ impl AuthImpl for KomodoAuthImpl {
|
||||
}
|
||||
|
||||
fn host(&self) -> &str {
|
||||
static AUTH_HOST: LazyLock<String> =
|
||||
LazyLock::new(|| format!("{}/auth", core_config().host));
|
||||
&AUTH_HOST
|
||||
&core_config().host
|
||||
}
|
||||
|
||||
fn post_link_redirect(&self) -> &str {
|
||||
|
||||
@@ -309,6 +309,9 @@ pub fn core_config() -> &'static CoreConfig {
|
||||
cors_allow_credentials: env
|
||||
.komodo_cors_allow_credentials
|
||||
.unwrap_or(config.cors_allow_credentials),
|
||||
session_allow_cross_site: env
|
||||
.komodo_session_allow_cross_site
|
||||
.unwrap_or(config.session_allow_cross_site),
|
||||
resource_poll_interval: env
|
||||
.komodo_resource_poll_interval
|
||||
.unwrap_or(config.resource_poll_interval),
|
||||
|
||||
@@ -1,3 +1,5 @@
|
||||
use std::time::Duration;
|
||||
|
||||
use anyhow::Context;
|
||||
use database::mungos::{
|
||||
by_id::{find_one_by_id, update_one_by_id},
|
||||
@@ -16,7 +18,7 @@ use komodo_client::entities::{
|
||||
stack::Stack,
|
||||
swarm::Swarm,
|
||||
sync::ResourceSync,
|
||||
update::{Update, UpdateListItem},
|
||||
update::{Update, UpdateListItem, UpdateStatus},
|
||||
user::User,
|
||||
};
|
||||
|
||||
@@ -591,3 +593,17 @@ pub async fn init_execution_update(
|
||||
|
||||
Ok(update)
|
||||
}
|
||||
|
||||
pub async fn poll_update_until_complete(
|
||||
update_id: &str,
|
||||
) -> anyhow::Result<Update> {
|
||||
loop {
|
||||
tokio::time::sleep(Duration::from_secs(1)).await;
|
||||
let update = find_one_by_id(&db_client().updates, update_id)
|
||||
.await?
|
||||
.context("No update found at given ID")?;
|
||||
if matches!(update.status, UpdateStatus::Complete) {
|
||||
return Ok(update);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -225,6 +225,8 @@ pub struct Env {
|
||||
pub komodo_cors_allowed_origins: Option<Vec<String>>,
|
||||
/// Override `cors_allow_credentials`
|
||||
pub komodo_cors_allow_credentials: Option<bool>,
|
||||
/// Override `session_allow_cross_site`
|
||||
pub komodo_session_allow_cross_site: Option<bool>,
|
||||
|
||||
/// Override `database.uri`
|
||||
#[serde(alias = "komodo_mongo_uri")]
|
||||
@@ -561,6 +563,12 @@ pub struct CoreConfig {
|
||||
#[serde(default)]
|
||||
pub cors_allow_credentials: bool,
|
||||
|
||||
/// Use SameSite=None (actually allows samesite) instead of SameSite=Lax.
|
||||
/// The third option, SameSite=Strict, won't work with external login,
|
||||
/// as the session cookie will be lost on redirect with auth provider.
|
||||
#[serde(default)]
|
||||
pub session_allow_cross_site: bool,
|
||||
|
||||
// ============
|
||||
// = Webhooks =
|
||||
// ============
|
||||
@@ -836,6 +844,7 @@ impl Default for CoreConfig {
|
||||
default_auth_rate_limit_window_seconds(),
|
||||
cors_allowed_origins: Default::default(),
|
||||
cors_allow_credentials: Default::default(),
|
||||
session_allow_cross_site: Default::default(),
|
||||
webhook_secret: Default::default(),
|
||||
webhook_base_url: Default::default(),
|
||||
logging: Default::default(),
|
||||
@@ -942,6 +951,7 @@ impl CoreConfig {
|
||||
.auth_rate_limit_window_seconds,
|
||||
cors_allowed_origins: config.cors_allowed_origins,
|
||||
cors_allow_credentials: config.cors_allow_credentials,
|
||||
session_allow_cross_site: config.session_allow_cross_site,
|
||||
webhook_secret: empty_or_redacted(&config.webhook_secret),
|
||||
webhook_base_url: config.webhook_base_url,
|
||||
database: config.database.sanitized(),
|
||||
@@ -1023,9 +1033,6 @@ impl mogh_server::ServerConfig for &CoreConfig {
|
||||
}
|
||||
|
||||
impl mogh_server::cors::CorsConfig for &CoreConfig {
|
||||
fn allowed_origins_env_field(&self) -> &'static str {
|
||||
"KOMODO_CORS_ALLOWED_ORIGINS"
|
||||
}
|
||||
fn allowed_origins(&self) -> &[String] {
|
||||
&self.cors_allowed_origins
|
||||
}
|
||||
@@ -1035,13 +1042,16 @@ impl mogh_server::cors::CorsConfig for &CoreConfig {
|
||||
}
|
||||
|
||||
impl mogh_server::session::SessionConfig for &CoreConfig {
|
||||
fn expiry_seconds(&self) -> i64 {
|
||||
60
|
||||
fn host(&self) -> &str {
|
||||
&self.host
|
||||
}
|
||||
fn host_env_field(&self) -> &str {
|
||||
"KOMODO_HOST"
|
||||
}
|
||||
fn host(&self) -> &str {
|
||||
&self.host
|
||||
fn expiry_seconds(&self) -> i64 {
|
||||
60
|
||||
}
|
||||
fn allow_cross_site(&self) -> bool {
|
||||
self.session_allow_cross_site
|
||||
}
|
||||
}
|
||||
|
||||
@@ -324,9 +324,9 @@ auth_rate_limit_max_attempts = 5
|
||||
## Default: 15
|
||||
auth_rate_limit_window_seconds = 15
|
||||
|
||||
########
|
||||
# CORS #
|
||||
########
|
||||
##################
|
||||
# CORS / SESSION #
|
||||
##################
|
||||
|
||||
## Specifically set list of CORS allowed origins.
|
||||
## If empty, allows all origins (`*`).
|
||||
@@ -341,6 +341,10 @@ cors_allowed_origins = []
|
||||
## Default: false
|
||||
cors_allow_credentials = false
|
||||
|
||||
## Enabling this sets 'SameSite=None', which allows externally
|
||||
## hosted frontends to use the login flows.
|
||||
session_allow_cross_site = false
|
||||
|
||||
##################
|
||||
# POLL INTERVALS #
|
||||
##################
|
||||
|
||||
Reference in New Issue
Block a user