Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
49 changes: 33 additions & 16 deletions src/handlers/http/alerts.rs
Original file line number Diff line number Diff line change
Expand Up @@ -387,33 +387,39 @@ pub async fn delete(req: HttpRequest, alert_id: Path<Ulid>) -> Result<impl Respo
let session_key = extract_session_key_from_req(&req)?;
let alert_id = alert_id.into_inner();
let tenant_id = get_tenant_id_from_request(&req);
delete_internal(&session_key, alert_id, &tenant_id).await
}

/// Shared alert deletion implementation for HTTP handlers and in-process callers.
pub async fn delete_internal(
session_key: &SessionKey,
alert_id: Ulid,
tenant_id: &Option<String>,
) -> Result<String, AlertError> {
let guard = ALERTS.write().await;
let alerts = if let Some(alerts) = guard.as_ref() {
alerts
} else {
return Err(AlertError::CustomError("No AlertManager set".into()));
};

let alert = alerts.get_alert_by_id(alert_id, &tenant_id).await?;
let alert = alerts.get_alert_by_id(alert_id, tenant_id).await?;

// validate that the user has access to the tables mentioned in the query
user_auth_for_alert_config(&session_key, &alert.to_alert_config()).await?;
user_auth_for_alert_config(session_key, &alert.to_alert_config()).await?;

PARSEABLE
.metastore
.delete_alert(&*alert, &tenant_id)
.await?;
PARSEABLE.metastore.delete_alert(&*alert, tenant_id).await?;

// delete the associated alert state
let state_to_delete =
AlertStateEntry::new(alert_id, AlertState::NotTriggered, tenant_id.clone()); // state doesn't matter for deletion
PARSEABLE
.metastore
.delete_alert_state(&state_to_delete as &dyn MetastoreObject, &tenant_id)
.delete_alert_state(&state_to_delete as &dyn MetastoreObject, tenant_id)
.await?;

// delete from memory
alerts.delete(alert_id, &tenant_id).await?;
alerts.delete(alert_id, tenant_id).await?;

// delete the scheduled task
alerts.delete_task(alert_id).await?;
Expand Down Expand Up @@ -585,6 +591,18 @@ pub async fn modify_alert(
let session_key = extract_session_key_from_req(&req)?;
let alert_id = alert_id.into_inner();
let tenant_id = get_tenant_id_from_request(&req);
Ok(web::Json(
modify_alert_internal(&session_key, alert_id, alert_request, &tenant_id).await?,
))
}

/// Shared alert update implementation for HTTP handlers and in-process callers.
pub async fn modify_alert_internal(
session_key: &SessionKey,
alert_id: Ulid,
alert_request: AlertRequest,
tenant_id: &Option<String>,
) -> Result<AlertConfigResponse, AlertError> {
// Get alerts manager reference without holding the global lock
let alerts = {
let guard = ALERTS.read().await;
Expand All @@ -596,15 +614,15 @@ pub async fn modify_alert(
};

// Validate and prepare the new alert
let alert = alerts.get_alert_by_id(alert_id, &tenant_id).await?;
user_auth_for_alert_config(&session_key, &alert.to_alert_config()).await?;
let alert = alerts.get_alert_by_id(alert_id, tenant_id).await?;
user_auth_for_alert_config(session_key, &alert.to_alert_config()).await?;

let mut new_config = alert_request.into(tenant_id.clone()).await?;
if &new_config.alert_type != alert.get_alert_type() {
return Err(AlertError::InvalidAlertModifyRequest);
}

user_auth_for_alert_config(&session_key, &new_config).await?;
user_auth_for_alert_config(session_key, &new_config).await?;

// Calculate notification config
let eval_freq = new_config.get_eval_frequency();
Expand Down Expand Up @@ -639,27 +657,26 @@ pub async fn modify_alert(
}
};

new_alert.validate(&session_key).await?;
new_alert.validate(session_key).await?;

// Perform I/O operations
PARSEABLE
.metastore
.put_alert(&new_alert.to_alert_config(), &tenant_id)
.put_alert(&new_alert.to_alert_config(), tenant_id)
.await?;

let is_disabled = new_alert.get_state().eq(&AlertState::Disabled);
// Now perform the atomic operations
alerts.delete_task(alert_id).await?;
alerts.delete(alert_id, &tenant_id).await?;
alerts.delete(alert_id, tenant_id).await?;
alerts.update(&*new_alert).await;

// only restart the task if the state was not set to disabled
if !is_disabled {
alerts.start_task(new_alert.clone_box()).await?;
}

let config = new_alert.to_alert_config().to_response();
Ok(web::Json(config))
Ok(new_alert.to_alert_config().to_response())
}

// PUT /alerts/{alert_id}/evaluate_alert
Expand Down
30 changes: 24 additions & 6 deletions src/handlers/http/targets.rs
Original file line number Diff line number Diff line change
Expand Up @@ -136,12 +136,23 @@ pub async fn get_internal(
pub async fn update(
req: HttpRequest,
target_id: Path<Ulid>,
Json(mut target): Json<Target>,
Json(target): Json<Target>,
) -> Result<impl Responder, AlertError> {
let target_id = target_id.into_inner();
let tenant_id = get_tenant_id_from_request(&req);
Ok(web::Json(
update_internal(target_id, target, &tenant_id).await?,
))
}

/// Shared target update implementation for HTTP handlers and in-process callers.
pub async fn update_internal(
target_id: Ulid,
mut target: Target,
tenant_id: &Option<String>,
) -> Result<serde_json::Value, AlertError> {
// if target_id does not exist, error
let old_target = TARGETS.get_target_by_id(&target_id, &tenant_id).await?;
let old_target = TARGETS.get_target_by_id(&target_id, tenant_id).await?;

// do not allow modifying name
if old_target.name != target.name {
Expand All @@ -152,22 +163,29 @@ pub async fn update(

// esnure that the supplied target id is assigned to the target config
target.id = target_id;
target.tenant = tenant_id;
target.tenant.clone_from(tenant_id);
target.validate_outbound_policy().await?;
// should check for duplicacy and liveness (??)
// add to the map
TARGETS.update(target.clone()).await?;

Ok(web::Json(target.mask()))
Ok(serde_json::to_value(target.mask())?)
}

// DELETE /targets/{target_id}
pub async fn delete(req: HttpRequest, target_id: Path<Ulid>) -> Result<impl Responder, AlertError> {
let target_id = target_id.into_inner();
let tenant_id = get_tenant_id_from_request(&req);
let target = TARGETS.delete(&target_id, &tenant_id).await?;
Ok(web::Json(delete_internal(target_id, &tenant_id).await?))
}

Ok(web::Json(target.mask()))
/// Shared target deletion implementation for HTTP handlers and in-process callers.
pub async fn delete_internal(
target_id: Ulid,
tenant_id: &Option<String>,
) -> Result<serde_json::Value, AlertError> {
let target = TARGETS.delete(&target_id, tenant_id).await?;
Ok(serde_json::to_value(target.mask())?)
}

#[cfg(test)]
Expand Down
Loading
Loading