Skip to content

Commit

Permalink
refactor: remove/add alerts per incident, return merged_ids instead o…
Browse files Browse the repository at this point in the history
…f updated incident
  • Loading branch information
Kiryous committed Oct 22, 2024
1 parent 8df75a2 commit 1b17935
Show file tree
Hide file tree
Showing 4 changed files with 59 additions and 24 deletions.
39 changes: 24 additions & 15 deletions keep/api/core/db.py
Original file line number Diff line number Diff line change
Expand Up @@ -3255,9 +3255,10 @@ class DestinationIncidentNotFound(Exception):
def merge_incidents_to_id(
tenant_id: str,
source_incident_ids: List[UUID],
# Maybe to add optional destionation_incident_dto to merge to
destination_incident_id: UUID,
merged_by: str | None = None,
) -> Optional[Incident]:
) -> (List[UUID], List[UUID], List[UUID]):
with Session(engine) as session:
destination_incident = session.exec(
select(Incident)
Expand All @@ -3268,7 +3269,6 @@ def merge_incidents_to_id(
).first()

if not destination_incident:
# TODO: maybe allow to create a new incident if the destination incident does not exist
raise DestinationIncidentNotFound(
f"Destination incident with id {destination_incident_id} not found"
)
Expand All @@ -3280,15 +3280,20 @@ def merge_incidents_to_id(
)
).all()

alerts_to_add_ids = []
merged_incident_ids = []
skipped_incident_ids = []
failed_incident_ids = []
for source_incident in source_incidents:
alerts_to_add_ids.extend([alert.id for alert in source_incident.alerts])
source_incident_alerts_ids = [alert.id for alert in source_incident.alerts]
if not source_incident_alerts_ids:
logger.info(f"Source incident {source_incident.id} doesn't have alerts")
skipped_incident_ids.append(source_incident.id)
continue
source_incident.merged_into_incident_id = destination_incident.id
source_incident.merged_at = datetime.now(tz=timezone.utc)
source_incident.status = IncidentStatus.MERGED.value
source_incident.merged_by = merged_by
try:
# TODO: optimize, process in bulk
remove_alerts_to_incident_by_incident_id(
tenant_id,
source_incident.id,
Expand All @@ -3298,19 +3303,23 @@ def merge_incidents_to_id(
logger.error(
f"Error removing alerts to incident {source_incident.id}: {e}"
)

try:
add_alerts_to_incident(
tenant_id, destination_incident, alerts_to_add_ids, session=session
)
except OperationalError as e:
logger.error(
f"Error adding alerts to incident {destination_incident.id}: {e}"
)
try:
add_alerts_to_incident(
tenant_id,
destination_incident,
source_incident_alerts_ids,
session=session,
)
merged_incident_ids.append(source_incident.id)
except OperationalError as e:
logger.error(
f"Error adding alerts to incident {destination_incident.id} from {source_incident.id}: {e}"
)
failed_incident_ids.append(source_incident.id)

session.commit()
session.refresh(destination_incident)
return destination_incident
return merged_incident_ids, skipped_incident_ids, failed_incident_ids


def get_alerts_count(
Expand Down
10 changes: 9 additions & 1 deletion keep/api/models/alert.py
Original file line number Diff line number Diff line change
Expand Up @@ -502,11 +502,19 @@ def from_db_incident(cls, db_incident: "Incident"):
return dto


class MergeIncidentsCommandDto(BaseModel):
class MergeIncidentsRequestDto(BaseModel):
source_incident_ids: list[UUID]
destination_incident_id: UUID


class MergeIncidentsResponseDto(BaseModel):
merged_incident_ids: list[UUID]
skipped_incident_ids: list[UUID]
failed_incident_ids: list[UUID]
destination_incident_id: UUID
message: str


class DeduplicationRuleDto(BaseModel):
id: str | None # UUID
name: str
Expand Down
32 changes: 25 additions & 7 deletions keep/api/routes/incidents.py
Original file line number Diff line number Diff line change
Expand Up @@ -40,11 +40,12 @@
IncidentDto,
IncidentDtoIn,
IncidentListFilterParamsDto,
MergeIncidentsCommandDto,
MergeIncidentsRequestDto,
IncidentSeverity,
IncidentSorting,
IncidentStatus,
IncidentStatusChangeDto,
MergeIncidentsResponseDto,
)
from keep.api.models.db.alert import AlertActionType, AlertAudit
from keep.api.routes.alerts import _enrich_alert
Expand Down Expand Up @@ -352,13 +353,15 @@ def delete_incident(
return Response(status_code=202)


@router.post("/merge", description="Merge incidents", response_model=IncidentDto)
@router.post(
"/merge", description="Merge incidents", response_model=MergeIncidentsResponseDto
)
def merge_incidents(
command: MergeIncidentsCommandDto,
command: MergeIncidentsRequestDto,
authenticated_entity: AuthenticatedEntity = Depends(
IdentityManagerFactory.get_auth_verifier(["write:incident"])
),
) -> Response:
) -> MergeIncidentsResponseDto:
tenant_id = authenticated_entity.tenant_id
logger.info(
"Merging incidents",
Expand All @@ -370,14 +373,29 @@ def merge_incidents(
)

try:
updated_incident = merge_incidents_to_id(
merged_ids, skipped_ids, failed_ids = merge_incidents_to_id(
tenant_id,
command.source_incident_ids,
command.destination_incident_id,
authenticated_entity.email,
)
updated_incident_dto = IncidentDto.from_db_incident(updated_incident)
return updated_incident_dto

message = f"{len(merged_ids)} incidents merged into {command.destination_incident_id} successfully"
if not merged_ids:
message = f"No incidents merged"
if skipped_ids:
# TODO: plural
message += f", {len(skipped_ids)} incidents were skipped"
if failed_ids:
message += f", {len(failed_ids)} incidents failed to merge"

return MergeIncidentsResponseDto(
merged_incident_ids=merged_ids,
skipped_incident_ids=skipped_ids,
failed_incident_ids=failed_ids,
destination_incident_id=command.destination_incident_id,
message=message,
)
except DestinationIncidentNotFound as e:
raise HTTPException(status_code=400, detail=str(e))

Expand Down
2 changes: 1 addition & 1 deletion tests/test_incidents.py
Original file line number Diff line number Diff line change
Expand Up @@ -512,7 +512,7 @@ def test_merge_incidents(db_session, setup_stress_alerts_no_elastic):

@pytest.mark.parametrize("test_app", ["NO_AUTH"], indirect=True)
def test_merge_incidents_app(
db_session, client, test_app, setup_stress_alerts_no_elastic, create_alert
db_session, client, test_app, setup_stress_alerts_no_elastic, create_alert
):
incident_1 = create_incident_from_dict(
SINGLE_TENANT_UUID,
Expand Down

0 comments on commit 1b17935

Please sign in to comment.