Skip to content

Commit

Permalink
Merge branch 'master' into feat/aws_alb_auth_plugin
Browse files Browse the repository at this point in the history
  • Loading branch information
roblambell authored Dec 11, 2024
2 parents 7d25c91 + e55f9a1 commit fca87c7
Show file tree
Hide file tree
Showing 7 changed files with 114 additions and 16 deletions.
11 changes: 11 additions & 0 deletions src/dispatch/incident/service.py
Original file line number Diff line number Diff line change
Expand Up @@ -29,6 +29,7 @@
from dispatch.project import service as project_service
from dispatch.tag import service as tag_service
from dispatch.term import service as term_service
from dispatch.ticket import flows as ticket_flows

from .enums import IncidentStatus
from .models import Incident, IncidentCreate, IncidentRead, IncidentUpdate
Expand Down Expand Up @@ -384,6 +385,16 @@ def update(*, db_session: Session, incident: Incident, incident_in: IncidentUpda
incident_cost_service.update_incident_response_cost(
incident_id=incident.id, db_session=db_session
)
# if the new incident type has plugin metadata and the
# project key of the ticket is the same, also update the ticket with the new metadata
if incident_type.plugin_metadata:
ticket_flows.update_incident_ticket_metadata(
db_session=db_session,
ticket_id=incident.ticket.resource_id,
project_id=incident.project.id,
incident_id=incident.id,
incident_type=incident_type,
)

update_data = incident_in.dict(
skip_defaults=True,
Expand Down
30 changes: 18 additions & 12 deletions src/dispatch/plugins/dispatch_aws/plugin.py
Original file line number Diff line number Diff line change
Expand Up @@ -74,23 +74,27 @@ def consume(self, db_session: Session, project: Project) -> None:

entries: list[SqsEntries] = []
for message in response["Messages"]:
message_attributes = message.get("MessageAttributes", {})
message_body = message["Body"]
try:
message_body = json.loads(message["Body"])
message_body_message = message_body.get("Message")
message_attributes = message_body.get("MessageAttributes", {})

if message_attributes.get("compressed", {}).get("StringValue") == "zlib":
# Message is compressed, decompress it
message_body = decompress_json(message_body)
if message_attributes.get("compressed", {}).get("Value") == "zlib":
# Message is compressed, decompress it
message_body_message = decompress_json(message_body_message)

message_body = json.loads(message_body)
signal_data = json.loads(message_body["Message"])
signal_data = json.loads(message_body_message)
except Exception as e:
log.exception(f"Unable to extract signal data from SQS message: {e}")
continue

try:
signal_instance_in = SignalInstanceCreate(
project=project, raw=signal_data, **signal_data
)
except ValidationError as e:
log.warning(
f"Received a signal instance that does not conform to the `SignalInstanceCreate` structure. Skipping creation: {e}"
f"Received a signal instance that does not conform to the SignalInstanceCreate pydantic model. Skipping creation: {e}"
)
continue

Expand All @@ -100,7 +104,7 @@ def consume(self, db_session: Session, project: Project) -> None:
db_session=db_session, signal_instance_id=signal_instance_in.raw["id"]
):
log.info(
f"Received a signal instance that already exists in the database. Skipping creation: {signal_instance_in.raw['id']}"
f"Received a signal that already exists in the database. Skipping signal instance creation: {signal_instance_in.raw['id']}"
)
continue

Expand All @@ -113,15 +117,17 @@ def consume(self, db_session: Session, project: Project) -> None:
except IntegrityError as e:
if isinstance(e.orig, UniqueViolation):
log.info(
f"Received a signal instance that already exists in the database. Skipping creation: {e}"
f"Received a signal that already exists in the database. Skipping signal instance creation: {e}"
)
else:
log.exception(
f"Encountered an Integrity error when trying to create a signal instance: {e}"
f"Encountered an integrity error when trying to create a signal instance: {e}"
)
continue
except Exception as e:
log.exception(f"Unable to create signal instance: {e}")
log.exception(
f"Unable to create signal instance. Signal name/variant: {signal_instance_in.raw['name'] if signal_instance_in.raw and signal_instance_in.raw['name'] else signal_instance_in.raw['variant']}. Error: {e}"
)
db_session.rollback()
continue
else:
Expand Down
8 changes: 8 additions & 0 deletions src/dispatch/plugins/dispatch_core/plugin.py
Original file line number Diff line number Diff line change
Expand Up @@ -312,6 +312,14 @@ def create_case_ticket(
"resource_type": "dispatch-internal-ticket",
}

def update_metadata(
self,
ticket_id: str,
metadata: dict,
):
"""Updates the metadata of a Dispatch ticket."""
return

def update_case_ticket(
self,
ticket_id: str,
Expand Down
27 changes: 27 additions & 0 deletions src/dispatch/plugins/dispatch_jira/plugin.py
Original file line number Diff line number Diff line change
Expand Up @@ -315,6 +315,7 @@ def create(
reporter = get_user_field(client, self.configuration, reporter_email)

project_id, issue_type_name = process_plugin_metadata(incident_type_plugin_metadata)
other_fields = create_dict_from_plugin_metadata(incident_type_plugin_metadata)

if not project_id:
project_id = self.configuration.default_project_id
Expand All @@ -335,6 +336,7 @@ def create(
"assignee": assignee,
"reporter": reporter,
"summary": title,
**other_fields,
}

ticket = create(self.configuration, client, issue_fields)
Expand Down Expand Up @@ -401,6 +403,31 @@ def update(

return update(self.configuration, client, issue, issue_fields, status)

def update_metadata(
self,
ticket_id: str,
metadata: dict,
):
"""Updates the metadata of a Jira issue."""
client = create_client(self.configuration)
issue = client.issue(ticket_id)

# check to make sure project id matches metadata
project_id, issue_type_name = process_plugin_metadata(metadata)
if project_id and issue.fields.project.key != project_id:
log.warning(
f"Project key mismatch between Jira issue {issue.fields.project.key} and metadata {project_id} for ticket {ticket_id}"
)
return
other_fields = create_dict_from_plugin_metadata(metadata)
issue_fields = {
**other_fields,
}
if issue_type_name:
issue_fields["issuetype"] = {"name": issue_type_name}

issue.update(fields=issue_fields)

def create_case_ticket(
self,
case_id: int,
Expand Down
15 changes: 12 additions & 3 deletions src/dispatch/signal/service.py
Original file line number Diff line number Diff line change
Expand Up @@ -544,9 +544,18 @@ def delete(*, db_session: Session, signal_id: int):
return signal_id


def is_valid_uuid(val):
def is_valid_uuid(value) -> bool:
"""
Checks if the provided value is a valid UUID.
Args:
val: The value to be checked.
Returns:
bool: True if the value is a valid UUID, False otherwise.
"""
try:
uuid.UUID(str(val), version=4)
uuid.UUID(str(value), version=4)
return True
except ValueError:
return False
Expand Down Expand Up @@ -587,7 +596,7 @@ def create_instance(
signal_instance.id = signal_instance_in.raw["id"]

if signal_instance.id and not is_valid_uuid(signal_instance.id):
msg = f"Invalid signal id format. Expecting UUID format. Received {signal_instance.id}."
msg = f"Invalid signal id format. Expecting UUIDv4 format. Signal id: {signal_instance.id}. Signal name/variant: {signal_instance.raw['name'] if signal_instance and signal_instance.raw and signal_instance.raw.get('name') else signal_instance.raw['variant']}"
log.warn(msg)
raise HTTPException(
status_code=status.HTTP_400_BAD_REQUEST,
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -120,7 +120,6 @@ export default {
sortBy: ["name"],
descending: [false],
itemsPerPage: this.numItems,
enabled: ["true"],
}
if (this.project) {
Expand All @@ -132,6 +131,8 @@ export default {
}
}
filterOptions.filters["enabled"] = ["true"]
filterOptions = SearchUtils.createParametersFromTableOptions(
{ ...filterOptions },
"IncidentType"
Expand Down
36 changes: 36 additions & 0 deletions src/dispatch/ticket/flows.py
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,7 @@
from dispatch.event import service as event_service
from dispatch.incident import service as incident_service
from dispatch.incident.models import Incident
from dispatch.incident.type.models import IncidentType
from dispatch.incident.type import service as incident_type_service
from dispatch.participant import service as participant_service
from dispatch.plugin import service as plugin_service
Expand Down Expand Up @@ -334,3 +335,38 @@ def create_task_ticket(task: Task, db_session: Session):
db_session.commit()

return external_ticket


def update_incident_ticket_metadata(
db_session: Session,
ticket_id: str,
project_id: int,
incident_id: int,
incident_type: IncidentType,
):
"""
Updates the metadata of an incident ticket.
"""
plugin = plugin_service.get_active_instance(
db_session=db_session, project_id=project_id, plugin_type="ticket"
)
if not plugin:
log.warning("Incident ticket metadata not updated. No ticket plugin enabled.")
return

# we update the external incident ticket
try:
plugin.instance.update_metadata(
ticket_id=ticket_id,
metadata=incident_type.get_meta(plugin.plugin.slug),
)
except Exception as e:
log.exception(e)
return

event_service.log_incident_event(
db_session=db_session,
source=plugin.plugin.title,
description="Incident ticket metadata updated",
incident_id=incident_id,
)

0 comments on commit fca87c7

Please sign in to comment.