forked from github-starred/komodo
add pending update alert
This commit is contained in:
@@ -3,16 +3,23 @@ use monitor_client::{
|
||||
api::write::*,
|
||||
entities::{
|
||||
self,
|
||||
alert::{Alert, AlertData},
|
||||
alerter::Alerter,
|
||||
build::Build,
|
||||
builder::Builder,
|
||||
deployment::Deployment,
|
||||
monitor_timestamp,
|
||||
permission::PermissionLevel,
|
||||
procedure::Procedure,
|
||||
repo::Repo,
|
||||
server::Server,
|
||||
server::{stats::SeverityLevel, Server},
|
||||
server_template::ServerTemplate,
|
||||
sync::{PendingSyncUpdates, ResourceSync},
|
||||
sync::{
|
||||
PendingSyncUpdates, PendingSyncUpdatesData,
|
||||
PendingSyncUpdatesDataErr, PendingSyncUpdatesDataOk,
|
||||
ResourceSync,
|
||||
},
|
||||
update::ResourceTarget,
|
||||
user::User,
|
||||
},
|
||||
};
|
||||
@@ -21,6 +28,7 @@ use mungos::{
|
||||
mongodb::bson::{doc, to_document},
|
||||
};
|
||||
use resolver_api::Resolve;
|
||||
use serror::serialize_error_pretty;
|
||||
|
||||
use crate::{
|
||||
helpers::{
|
||||
@@ -96,108 +104,136 @@ impl Resolve<RefreshResourceSyncPending, User> for State {
|
||||
>(&sync, &user, PermissionLevel::Execute)
|
||||
.await?;
|
||||
|
||||
let (res, _, hash, message) =
|
||||
crate::helpers::sync::remote::get_remote_resources(&sync)
|
||||
.await
|
||||
.context("failed to get remote resources")?;
|
||||
let resources = res?;
|
||||
let res = async {
|
||||
let (res, _, hash, message) =
|
||||
crate::helpers::sync::remote::get_remote_resources(&sync)
|
||||
.await
|
||||
.context("failed to get remote resources")?;
|
||||
let resources = res?;
|
||||
|
||||
let all_resources = AllResourcesById::load().await?;
|
||||
let id_to_tags = get_id_to_tags(None).await?;
|
||||
let all_resources = AllResourcesById::load().await?;
|
||||
let id_to_tags = get_id_to_tags(None).await?;
|
||||
|
||||
let pending = PendingSyncUpdates {
|
||||
hash,
|
||||
message,
|
||||
server_updates: get_updates_for_view::<Server>(
|
||||
resources.servers,
|
||||
sync.config.delete,
|
||||
&all_resources,
|
||||
&id_to_tags,
|
||||
)
|
||||
.await
|
||||
.context("failed to get server updates")?,
|
||||
deployment_updates: get_updates_for_view::<Deployment>(
|
||||
resources.deployments,
|
||||
sync.config.delete,
|
||||
&all_resources,
|
||||
&id_to_tags,
|
||||
)
|
||||
.await
|
||||
.context("failed to get deployment updates")?,
|
||||
build_updates: get_updates_for_view::<Build>(
|
||||
resources.builds,
|
||||
sync.config.delete,
|
||||
&all_resources,
|
||||
&id_to_tags,
|
||||
)
|
||||
.await
|
||||
.context("failed to get build updates")?,
|
||||
repo_updates: get_updates_for_view::<Repo>(
|
||||
resources.repos,
|
||||
sync.config.delete,
|
||||
&all_resources,
|
||||
&id_to_tags,
|
||||
)
|
||||
.await
|
||||
.context("failed to get repo updates")?,
|
||||
procedure_updates: get_updates_for_view::<Procedure>(
|
||||
resources.procedures,
|
||||
sync.config.delete,
|
||||
&all_resources,
|
||||
&id_to_tags,
|
||||
)
|
||||
.await
|
||||
.context("failed to get procedure updates")?,
|
||||
alerter_updates: get_updates_for_view::<Alerter>(
|
||||
resources.alerters,
|
||||
sync.config.delete,
|
||||
&all_resources,
|
||||
&id_to_tags,
|
||||
)
|
||||
.await
|
||||
.context("failed to get alerter updates")?,
|
||||
builder_updates: get_updates_for_view::<Builder>(
|
||||
resources.builders,
|
||||
sync.config.delete,
|
||||
&all_resources,
|
||||
&id_to_tags,
|
||||
)
|
||||
.await
|
||||
.context("failed to get builder updates")?,
|
||||
server_template_updates:
|
||||
get_updates_for_view::<ServerTemplate>(
|
||||
resources.server_templates,
|
||||
let data = PendingSyncUpdatesDataOk {
|
||||
server_updates: get_updates_for_view::<Server>(
|
||||
resources.servers,
|
||||
sync.config.delete,
|
||||
&all_resources,
|
||||
&id_to_tags,
|
||||
)
|
||||
.await
|
||||
.context("failed to get server template updates")?,
|
||||
resource_sync_updates: get_updates_for_view::<
|
||||
entities::sync::ResourceSync,
|
||||
>(
|
||||
resources.resource_syncs,
|
||||
sync.config.delete,
|
||||
&all_resources,
|
||||
&id_to_tags,
|
||||
)
|
||||
.await
|
||||
.context("failed to get resource sync updates")?,
|
||||
variable_updates:
|
||||
crate::helpers::sync::variables::get_updates_for_view(
|
||||
resources.variables,
|
||||
sync.config.delete,
|
||||
)
|
||||
.await
|
||||
.context("failed to get variable updates")?,
|
||||
user_group_updates:
|
||||
crate::helpers::sync::user_groups::get_updates_for_view(
|
||||
resources.user_groups,
|
||||
.context("failed to get server updates")?,
|
||||
deployment_updates: get_updates_for_view::<Deployment>(
|
||||
resources.deployments,
|
||||
sync.config.delete,
|
||||
&all_resources,
|
||||
&id_to_tags,
|
||||
)
|
||||
.await
|
||||
.context("failed to get user group updates")?,
|
||||
.context("failed to get deployment updates")?,
|
||||
build_updates: get_updates_for_view::<Build>(
|
||||
resources.builds,
|
||||
sync.config.delete,
|
||||
&all_resources,
|
||||
&id_to_tags,
|
||||
)
|
||||
.await
|
||||
.context("failed to get build updates")?,
|
||||
repo_updates: get_updates_for_view::<Repo>(
|
||||
resources.repos,
|
||||
sync.config.delete,
|
||||
&all_resources,
|
||||
&id_to_tags,
|
||||
)
|
||||
.await
|
||||
.context("failed to get repo updates")?,
|
||||
procedure_updates: get_updates_for_view::<Procedure>(
|
||||
resources.procedures,
|
||||
sync.config.delete,
|
||||
&all_resources,
|
||||
&id_to_tags,
|
||||
)
|
||||
.await
|
||||
.context("failed to get procedure updates")?,
|
||||
alerter_updates: get_updates_for_view::<Alerter>(
|
||||
resources.alerters,
|
||||
sync.config.delete,
|
||||
&all_resources,
|
||||
&id_to_tags,
|
||||
)
|
||||
.await
|
||||
.context("failed to get alerter updates")?,
|
||||
builder_updates: get_updates_for_view::<Builder>(
|
||||
resources.builders,
|
||||
sync.config.delete,
|
||||
&all_resources,
|
||||
&id_to_tags,
|
||||
)
|
||||
.await
|
||||
.context("failed to get builder updates")?,
|
||||
server_template_updates:
|
||||
get_updates_for_view::<ServerTemplate>(
|
||||
resources.server_templates,
|
||||
sync.config.delete,
|
||||
&all_resources,
|
||||
&id_to_tags,
|
||||
)
|
||||
.await
|
||||
.context("failed to get server template updates")?,
|
||||
resource_sync_updates: get_updates_for_view::<
|
||||
entities::sync::ResourceSync,
|
||||
>(
|
||||
resources.resource_syncs,
|
||||
sync.config.delete,
|
||||
&all_resources,
|
||||
&id_to_tags,
|
||||
)
|
||||
.await
|
||||
.context("failed to get resource sync updates")?,
|
||||
variable_updates:
|
||||
crate::helpers::sync::variables::get_updates_for_view(
|
||||
resources.variables,
|
||||
sync.config.delete,
|
||||
)
|
||||
.await
|
||||
.context("failed to get variable updates")?,
|
||||
user_group_updates:
|
||||
crate::helpers::sync::user_groups::get_updates_for_view(
|
||||
resources.user_groups,
|
||||
sync.config.delete,
|
||||
&all_resources,
|
||||
)
|
||||
.await
|
||||
.context("failed to get user group updates")?,
|
||||
};
|
||||
anyhow::Ok((hash, message, data))
|
||||
}
|
||||
.await;
|
||||
|
||||
let (pending, has_updates) = match res {
|
||||
Ok((hash, message, data)) => {
|
||||
let has_updates = !data.no_updates();
|
||||
(
|
||||
PendingSyncUpdates {
|
||||
hash: Some(hash),
|
||||
message: Some(message),
|
||||
data: PendingSyncUpdatesData::Ok(data),
|
||||
},
|
||||
has_updates,
|
||||
)
|
||||
}
|
||||
Err(e) => (
|
||||
PendingSyncUpdates {
|
||||
hash: None,
|
||||
message: None,
|
||||
data: PendingSyncUpdatesData::Err(
|
||||
PendingSyncUpdatesDataErr {
|
||||
message: serialize_error_pretty(&e),
|
||||
},
|
||||
),
|
||||
},
|
||||
false,
|
||||
),
|
||||
};
|
||||
|
||||
let pending = to_document(&pending)
|
||||
@@ -211,6 +247,71 @@ impl Resolve<RefreshResourceSyncPending, User> for State {
|
||||
)
|
||||
.await?;
|
||||
|
||||
// check to update alert
|
||||
let id = sync.id.clone();
|
||||
let name = sync.name.clone();
|
||||
tokio::task::spawn(async move {
|
||||
let db = db_client().await;
|
||||
let Some(existing) = db_client()
|
||||
.await
|
||||
.alerts
|
||||
.find_one(
|
||||
doc! {
|
||||
"resolved": false,
|
||||
"target.type": "ResourceSync",
|
||||
"target.id": &id,
|
||||
},
|
||||
None,
|
||||
)
|
||||
.await
|
||||
.context("failed to query db for alert")
|
||||
.inspect_err(|e| warn!("{e:#}"))
|
||||
.ok()
|
||||
else {
|
||||
return;
|
||||
};
|
||||
match (existing, has_updates) {
|
||||
// OPEN A NEW ALERT
|
||||
(None, true) => {
|
||||
let alert = Alert {
|
||||
id: Default::default(),
|
||||
ts: monitor_timestamp(),
|
||||
resolved: false,
|
||||
level: SeverityLevel::Ok,
|
||||
target: ResourceTarget::ResourceSync(id.clone()),
|
||||
data: AlertData::ResourceSyncPendingUpdates { id, name },
|
||||
resolved_ts: None,
|
||||
};
|
||||
db.alerts
|
||||
.insert_one(&alert, None)
|
||||
.await
|
||||
.context("failed to open existing pending resource sync updates alert")
|
||||
.inspect_err(|e| warn!("{e:#}"))
|
||||
.ok();
|
||||
}
|
||||
// CLOSE ALERT
|
||||
(Some(existing), false) => {
|
||||
update_one_by_id(
|
||||
&db.alerts,
|
||||
&existing.id,
|
||||
doc! {
|
||||
"$set": {
|
||||
"resolved": true,
|
||||
"resolved_ts": monitor_timestamp()
|
||||
}
|
||||
},
|
||||
None,
|
||||
)
|
||||
.await
|
||||
.context("failed to close existing pending resource sync updates alert")
|
||||
.inspect_err(|e| warn!("{e:#}"))
|
||||
.ok();
|
||||
}
|
||||
// NOTHING TO DO
|
||||
_ => {}
|
||||
}
|
||||
});
|
||||
|
||||
crate::resource::get::<ResourceSync>(&sync.id).await
|
||||
}
|
||||
}
|
||||
|
||||
@@ -246,6 +246,17 @@ async fn send_slack_alert(
|
||||
];
|
||||
(text, blocks.into())
|
||||
}
|
||||
AlertData::ResourceSyncPendingUpdates { id, name } => {
|
||||
let text =
|
||||
format!("{level} | There are pending resource sync updates");
|
||||
let blocks = vec![
|
||||
Block::header(text.clone()),
|
||||
Block::section(format!(
|
||||
"sync id: **{id}**\nsync name: **{name}**"
|
||||
)),
|
||||
];
|
||||
(text, blocks.into())
|
||||
}
|
||||
AlertData::None {} => Default::default(),
|
||||
};
|
||||
if !text.is_empty() {
|
||||
|
||||
@@ -148,6 +148,11 @@ pub enum AlertData {
|
||||
message: String,
|
||||
},
|
||||
|
||||
ResourceSyncPendingUpdates {
|
||||
id: String,
|
||||
name: String,
|
||||
},
|
||||
|
||||
None {},
|
||||
}
|
||||
|
||||
|
||||
@@ -67,24 +67,34 @@ pub struct ResourceSyncInfo {
|
||||
|
||||
#[typeshare]
|
||||
#[derive(Debug, Clone, Default, Serialize, Deserialize)]
|
||||
pub struct SyncUpdate {
|
||||
/// Resources to create
|
||||
pub to_create: i32,
|
||||
/// Resources to update
|
||||
pub to_update: i32,
|
||||
/// Resources to delete
|
||||
pub to_delete: i32,
|
||||
/// A readable log of all the changes to be applied
|
||||
pub log: String,
|
||||
pub struct PendingSyncUpdates {
|
||||
/// The commit hash which produced these pending updates
|
||||
pub hash: Option<String>,
|
||||
/// The commit message which produced these pending updates
|
||||
pub message: Option<String>,
|
||||
/// The data associated with the sync. Either Ok containing diffs,
|
||||
/// or Err containing an error message
|
||||
pub data: PendingSyncUpdatesData,
|
||||
}
|
||||
|
||||
#[typeshare]
|
||||
#[derive(Debug, Clone, Serialize, Deserialize)]
|
||||
#[serde(tag = "type", content = "data")]
|
||||
#[allow(clippy::large_enum_variant)]
|
||||
pub enum PendingSyncUpdatesData {
|
||||
Ok(PendingSyncUpdatesDataOk),
|
||||
Err(PendingSyncUpdatesDataErr),
|
||||
}
|
||||
|
||||
impl Default for PendingSyncUpdatesData {
|
||||
fn default() -> Self {
|
||||
Self::Ok(Default::default())
|
||||
}
|
||||
}
|
||||
|
||||
#[typeshare]
|
||||
#[derive(Debug, Clone, Default, Serialize, Deserialize)]
|
||||
pub struct PendingSyncUpdates {
|
||||
/// The commit hash which produced these pending updates
|
||||
pub hash: String,
|
||||
/// The commit message which produced these pending updates
|
||||
pub message: String,
|
||||
pub struct PendingSyncUpdatesDataOk {
|
||||
/// Readable log of any pending server updates
|
||||
pub server_updates: Option<SyncUpdate>,
|
||||
/// Readable log of any pending deployment updates
|
||||
@@ -109,6 +119,41 @@ pub struct PendingSyncUpdates {
|
||||
pub user_group_updates: Option<SyncUpdate>,
|
||||
}
|
||||
|
||||
impl PendingSyncUpdatesDataOk {
|
||||
pub fn no_updates(&self) -> bool {
|
||||
self.server_updates.is_none()
|
||||
&& self.deployment_updates.is_none()
|
||||
&& self.build_updates.is_none()
|
||||
&& self.repo_updates.is_none()
|
||||
&& self.procedure_updates.is_none()
|
||||
&& self.alerter_updates.is_none()
|
||||
&& self.builder_updates.is_none()
|
||||
&& self.server_template_updates.is_none()
|
||||
&& self.resource_sync_updates.is_none()
|
||||
&& self.variable_updates.is_none()
|
||||
&& self.user_group_updates.is_none()
|
||||
}
|
||||
}
|
||||
|
||||
#[typeshare]
|
||||
#[derive(Debug, Clone, Default, Serialize, Deserialize)]
|
||||
pub struct SyncUpdate {
|
||||
/// Resources to create
|
||||
pub to_create: i32,
|
||||
/// Resources to update
|
||||
pub to_update: i32,
|
||||
/// Resources to delete
|
||||
pub to_delete: i32,
|
||||
/// A readable log of all the changes to be applied
|
||||
pub log: String,
|
||||
}
|
||||
|
||||
#[typeshare]
|
||||
#[derive(Debug, Clone, Serialize, Deserialize)]
|
||||
pub struct PendingSyncUpdatesDataErr {
|
||||
pub message: String,
|
||||
}
|
||||
|
||||
#[typeshare(serialized_as = "Partial<ResourceSyncConfig>")]
|
||||
pub type _PartialResourceSyncConfig = PartialResourceSyncConfig;
|
||||
|
||||
|
||||
@@ -183,6 +183,10 @@ export type AlertData =
|
||||
instance_id: string;
|
||||
/** A reason for the failure */
|
||||
message: string;
|
||||
}}
|
||||
| { type: "ResourceSyncPendingUpdates", data: {
|
||||
id: string;
|
||||
name: string;
|
||||
}}
|
||||
| { type: "None", data: {
|
||||
}};
|
||||
@@ -1174,44 +1178,20 @@ export interface ResourceSyncConfig {
|
||||
webhook_enabled: boolean;
|
||||
}
|
||||
|
||||
export interface SyncUpdate {
|
||||
/** Resources to create */
|
||||
to_create: number;
|
||||
/** Resources to update */
|
||||
to_update: number;
|
||||
/** Resources to delete */
|
||||
to_delete: number;
|
||||
/** A readable log of all the changes to be applied */
|
||||
log: string;
|
||||
}
|
||||
export type PendingSyncUpdatesData =
|
||||
| { type: "Ok", data: PendingSyncUpdatesDataOk }
|
||||
| { type: "Err", data: PendingSyncUpdatesDataErr };
|
||||
|
||||
export interface PendingSyncUpdates {
|
||||
/** The commit hash which produced these pending updates */
|
||||
hash: string;
|
||||
hash?: string;
|
||||
/** The commit message which produced these pending updates */
|
||||
message: string;
|
||||
/** Readable log of any pending server updates */
|
||||
server_updates?: SyncUpdate;
|
||||
/** Readable log of any pending deployment updates */
|
||||
deployment_updates?: SyncUpdate;
|
||||
/** Readable log of any pending build updates */
|
||||
build_updates?: SyncUpdate;
|
||||
/** Readable log of any pending repo updates */
|
||||
repo_updates?: SyncUpdate;
|
||||
/** Readable log of any pending procedure updates */
|
||||
procedure_updates?: SyncUpdate;
|
||||
/** Readable log of any pending alerter updates */
|
||||
alerter_updates?: SyncUpdate;
|
||||
/** Readable log of any pending builder updates */
|
||||
builder_updates?: SyncUpdate;
|
||||
/** Readable log of any pending server template updates */
|
||||
server_template_updates?: SyncUpdate;
|
||||
/** Readable log of any pending resource sync updates */
|
||||
resource_sync_updates?: SyncUpdate;
|
||||
/** Readable log of any pending variable updates */
|
||||
variable_updates?: SyncUpdate;
|
||||
/** Readable log of any pending user group updates */
|
||||
user_group_updates?: SyncUpdate;
|
||||
message?: string;
|
||||
/**
|
||||
* The data associated with the sync. Either Ok containing diffs,
|
||||
* or Err containing an error message
|
||||
*/
|
||||
data: PendingSyncUpdatesData;
|
||||
}
|
||||
|
||||
export interface ResourceSyncInfo {
|
||||
@@ -3801,6 +3781,46 @@ export interface HetznerServerTemplateConfig {
|
||||
port: number;
|
||||
}
|
||||
|
||||
export interface SyncUpdate {
|
||||
/** Resources to create */
|
||||
to_create: number;
|
||||
/** Resources to update */
|
||||
to_update: number;
|
||||
/** Resources to delete */
|
||||
to_delete: number;
|
||||
/** A readable log of all the changes to be applied */
|
||||
log: string;
|
||||
}
|
||||
|
||||
export interface PendingSyncUpdatesDataOk {
|
||||
/** Readable log of any pending server updates */
|
||||
server_updates?: SyncUpdate;
|
||||
/** Readable log of any pending deployment updates */
|
||||
deployment_updates?: SyncUpdate;
|
||||
/** Readable log of any pending build updates */
|
||||
build_updates?: SyncUpdate;
|
||||
/** Readable log of any pending repo updates */
|
||||
repo_updates?: SyncUpdate;
|
||||
/** Readable log of any pending procedure updates */
|
||||
procedure_updates?: SyncUpdate;
|
||||
/** Readable log of any pending alerter updates */
|
||||
alerter_updates?: SyncUpdate;
|
||||
/** Readable log of any pending builder updates */
|
||||
builder_updates?: SyncUpdate;
|
||||
/** Readable log of any pending server template updates */
|
||||
server_template_updates?: SyncUpdate;
|
||||
/** Readable log of any pending resource sync updates */
|
||||
resource_sync_updates?: SyncUpdate;
|
||||
/** Readable log of any pending variable updates */
|
||||
variable_updates?: SyncUpdate;
|
||||
/** Readable log of any pending user group updates */
|
||||
user_group_updates?: SyncUpdate;
|
||||
}
|
||||
|
||||
export interface PendingSyncUpdatesDataErr {
|
||||
message: string;
|
||||
}
|
||||
|
||||
export type AuthRequest =
|
||||
| { type: "GetLoginOptions", params: GetLoginOptions }
|
||||
| { type: "CreateLocalUser", params: CreateLocalUser }
|
||||
|
||||
@@ -177,19 +177,20 @@ export const filterBySplit = <T>(
|
||||
};
|
||||
|
||||
export const sync_no_changes = (sync: Types.ResourceSync) => {
|
||||
const pending = sync.info?.pending;
|
||||
const pending = sync.info?.pending.data;
|
||||
if (!pending) return false;
|
||||
if (pending.type === "Err") return false;
|
||||
return (
|
||||
!pending.server_updates &&
|
||||
!pending.deployment_updates &&
|
||||
!pending.build_updates &&
|
||||
!pending.repo_updates &&
|
||||
!pending.procedure_updates &&
|
||||
!pending.alerter_updates &&
|
||||
!pending.builder_updates &&
|
||||
!pending.server_template_updates &&
|
||||
!pending.resource_sync_updates &&
|
||||
!pending.variable_updates &&
|
||||
!pending.user_group_updates
|
||||
!pending.data.server_updates &&
|
||||
!pending.data.deployment_updates &&
|
||||
!pending.data.build_updates &&
|
||||
!pending.data.repo_updates &&
|
||||
!pending.data.procedure_updates &&
|
||||
!pending.data.alerter_updates &&
|
||||
!pending.data.builder_updates &&
|
||||
!pending.data.server_template_updates &&
|
||||
!pending.data.resource_sync_updates &&
|
||||
!pending.data.variable_updates &&
|
||||
!pending.data.user_group_updates
|
||||
);
|
||||
};
|
||||
|
||||
Reference in New Issue
Block a user