Пример #1
0
def sync_active_stable_tasks(db_session: SessionLocal, project: Project):
    """Syncs incident tasks."""
    task_plugin = plugin_service.get_active_instance(db_session=db_session,
                                                     project_id=project.id,
                                                     plugin_type="task")

    if not task_plugin:
        log.warning(
            f"Skipping task sync no task plugin enabled. ProjectId: {project.id}"
        )
        return

    # we get all active and stable incidents
    active_incidents = incident_service.get_all_by_status(
        db_session=db_session,
        project_id=project.id,
        status=IncidentStatus.active)
    stable_incidents = incident_service.get_all_by_status(
        db_session=db_session,
        project_id=project.id,
        status=IncidentStatus.stable)

    incidents = active_incidents + stable_incidents
    lookback = 60 * 5  # 5 min
    sync_tasks(db_session,
               task_plugin,
               incidents,
               lookback=lookback,
               notify=True)
Пример #2
0
def list_incidents(incident_id: int, command: dict = None, db_session=None):
    """Returns the list of current active and stable incidents,
    and closed incidents in the last 24 hours."""
    incidents = []

    # We fetch active incidents
    incidents = incident_service.get_all_by_status(
        db_session=db_session, status=IncidentStatus.active.value)
    # We fetch stable incidents
    incidents.extend(
        incident_service.get_all_by_status(db_session=db_session,
                                           status=IncidentStatus.stable.value))
    # We fetch closed incidents in the last 24 hours
    incidents.extend(
        incident_service.get_all_last_x_hours_by_status(
            db_session=db_session,
            status=IncidentStatus.closed.value,
            hours=24))

    blocks = []
    blocks.append({
        "type": "header",
        "text": {
            "type": "plain_text",
            "text": "List of Incidents"
        }
    })

    if incidents:
        for incident in incidents:
            if incident.visibility == Visibility.open:
                ticket_weblink = resolve_attr(incident, "ticket.weblink")
                try:
                    blocks.append({
                        "type": "section",
                        "text": {
                            "type":
                            "mrkdwn",
                            "text":
                            (f"*<{ticket_weblink}|{incident.name}>*\n"
                             f"*Title*: {incident.title}\n"
                             f"*Type*: {incident.incident_type.name}\n"
                             f"*Priority*: {incident.incident_priority.name}\n"
                             f"*Status*: {incident.status}\n"
                             f"*Incident Commander*: <{incident.commander.individual.weblink}|{incident.commander.individual.name}>"
                             ),
                        },
                    })
                except Exception as e:
                    log.exception(e)

    dispatch_slack_service.send_ephemeral_message(
        slack_client,
        command["channel_id"],
        command["user_id"],
        "Incident List",
        blocks=blocks,
    )
Пример #3
0
def sync_active_stable_workflows(db_session=None):
    """Syncs incident workflows."""
    # we get all active and stable incidents
    active_incidents = incident_service.get_all_by_status(
        db_session=db_session, status=IncidentStatus.active)
    stable_incidents = incident_service.get_all_by_status(
        db_session=db_session, status=IncidentStatus.stable)
    incidents = active_incidents + stable_incidents
    sync_workflows(db_session, incidents, notify=True)
Пример #4
0
def sync_active_stable_tasks(db_session=None):
    """Syncs incident tasks."""
    for project in project_service.get_all(db_session=db_session):
        # we get all active and stable incidents
        active_incidents = incident_service.get_all_by_status(
            db_session=db_session,
            project_id=project.id,
            status=IncidentStatus.active)
        stable_incidents = incident_service.get_all_by_status(
            db_session=db_session,
            project_id=project.id,
            status=IncidentStatus.stable)
        incidents = active_incidents + stable_incidents
        sync_tasks(db_session, incidents, notify=True)
Пример #5
0
def incident_report_reminders(db_session=None):
    """Sends report reminders to incident commanders for active incidents."""
    incidents = incident_service.get_all_by_status(
        db_session=db_session, status=IncidentStatus.active
    )

    for incident in incidents:
        for report_type in ReportTypes:
            try:
                remind_after = incident.created_at
                if report_type == ReportTypes.tactical_report:
                    notification_hour = incident.incident_priority.tactical_report_reminder
                    if incident.last_tactical_report:
                        remind_after = incident.last_tactical_report.created_at
                elif report_type == ReportTypes.executive_report:
                    notification_hour = incident.incident_priority.executive_report_reminder
                    if incident.last_executive_report:
                        remind_after = incident.last_executive_report.created_at

                now = datetime.utcnow() - remind_after

                # we calculate the number of hours and seconds since last report was sent
                hours, seconds = divmod((now.days * 86400) + now.seconds, 3600)

                q, r = divmod(hours, notification_hour)
                if q >= 1 and r == 0:  # it's time to send the reminder
                    send_incident_report_reminder(incident, report_type)

            except Exception as e:
                # we shouldn't fail to send all reminders when one fails
                sentry_sdk.capture_exception(e)
Пример #6
0
def sync_active_stable_monitors(db_session: SessionLocal, project: Project):
    """Syncs incident monitors."""
    monitor_plugin = plugin_service.get_active_instance(db_session=db_session,
                                                        project_id=project.id,
                                                        plugin_type="monitor")
    if not monitor_plugin:
        log.warning(f"No monitor plugin is enabled. ProjectId: {project.id}")
        return

    # we get all active and stable incidents
    active_incidents = incident_service.get_all_by_status(
        db_session=db_session,
        project_id=project.id,
        status=IncidentStatus.active)
    stable_incidents = incident_service.get_all_by_status(
        db_session=db_session,
        project_id=project.id,
        status=IncidentStatus.stable)
    incidents = active_incidents + stable_incidents
    run_monitors(db_session, project, monitor_plugin, incidents, notify=True)
Пример #7
0
def list_incidents(
    user_id: str,
    user_email: str,
    channel_id: str,
    incident_id: int,
    config: SlackConversationConfiguration = None,
    command: dict = None,
    db_session=None,
    slack_client=None,
):
    """Returns the list of current active and stable incidents,
    and closed incidents in the last 24 hours."""
    projects = []
    incidents = []
    args = command["text"].split(" ")

    # scopes reply to the current incident's project
    incident = incident_service.get(db_session=db_session, incident_id=incident_id)

    if incident:
        # command was run in an incident conversation
        projects.append(incident.project)
    else:
        # command was run in a non-incident conversation
        if len(args) == 2:
            project = project_service.get_by_name(db_session=db_session, name=args[1])

            if project:
                projects.append()
            else:
                raise ValidationError(
                    [
                        ErrorWrapper(
                            NotFoundError(
                                msg=f"Project name '{args[1]}' in organization '{args[0]}' not found. Check your spelling."
                            ),
                            loc="project",
                        )
                    ],
                    model=BaseModel,
                )

        else:
            projects = project_service.get_all(db_session=db_session)

    for project in projects:
        # we fetch active incidents
        incidents.extend(
            incident_service.get_all_by_status(
                db_session=db_session, project_id=project.id, status=IncidentStatus.active
            )
        )
        # We fetch stable incidents
        incidents.extend(
            incident_service.get_all_by_status(
                db_session=db_session,
                project_id=project.id,
                status=IncidentStatus.stable,
            )
        )
        # We fetch closed incidents in the last 24 hours
        incidents.extend(
            incident_service.get_all_last_x_hours_by_status(
                db_session=db_session,
                project_id=project.id,
                status=IncidentStatus.closed,
                hours=24,
            )
        )

    blocks = []
    blocks.append({"type": "header", "text": {"type": "plain_text", "text": "List of Incidents"}})

    if incidents:
        for incident in incidents:
            if incident.visibility == Visibility.open:
                ticket_weblink = resolve_attr(incident, "ticket.weblink")
                try:
                    blocks.append(
                        {
                            "type": "section",
                            "text": {
                                "type": "mrkdwn",
                                "text": (
                                    f"*<{ticket_weblink}|{incident.name}>*\n"
                                    f"*Title*: {incident.title}\n"
                                    f"*Type*: {incident.incident_type.name}\n"
                                    f"*Priority*: {incident.incident_priority.name}\n"
                                    f"*Status*: {incident.status}\n"
                                    f"*Incident Commander*: <{incident.commander.individual.weblink}|{incident.commander.individual.name}>\n"
                                    f"*Project*: {incident.project.name}"
                                ),
                            },
                        }
                    )
                except Exception as e:
                    log.exception(e)

    dispatch_slack_service.send_ephemeral_message(
        slack_client,
        channel_id,
        user_id,
        "Incident List",
        blocks=blocks,
    )
Пример #8
0
def list_incidents(
    user_id: str,
    user_email: str,
    channel_id: str,
    incident_id: int,
    command: dict = None,
    db_session=None,
    slack_client=None,
):
    """Returns the list of current active and stable incidents,
    and closed incidents in the last 24 hours."""
    projects = []
    incidents = []

    # scopes reply to the current incident's project
    incident = incident_service.get(db_session=db_session,
                                    incident_id=incident_id)

    if incident:
        # command was run in an incident conversation
        projects.append(incident.project)
    else:
        # command was run in a non-incident conversation
        projects = project_service.get_all(db_session=db_session)

    for project in projects:
        # we fetch active incidents
        incidents.extend(
            incident_service.get_all_by_status(db_session=db_session,
                                               project_id=project.id,
                                               status=IncidentStatus.active))
        # We fetch stable incidents
        incidents.extend(
            incident_service.get_all_by_status(
                db_session=db_session,
                project_id=project.id,
                status=IncidentStatus.stable,
            ))
        # We fetch closed incidents in the last 24 hours
        incidents.extend(
            incident_service.get_all_last_x_hours_by_status(
                db_session=db_session,
                project_id=project.id,
                status=IncidentStatus.closed,
                hours=24,
            ))

    blocks = []
    blocks.append({
        "type": "header",
        "text": {
            "type": "plain_text",
            "text": "List of Incidents"
        }
    })

    if incidents:
        for incident in incidents:
            if incident.visibility == Visibility.open:
                ticket_weblink = resolve_attr(incident, "ticket.weblink")
                try:
                    blocks.append({
                        "type": "section",
                        "text": {
                            "type":
                            "mrkdwn",
                            "text":
                            (f"*<{ticket_weblink}|{incident.name}>*\n"
                             f"*Title*: {incident.title}\n"
                             f"*Type*: {incident.incident_type.name}\n"
                             f"*Priority*: {incident.incident_priority.name}\n"
                             f"*Status*: {incident.status}\n"
                             f"*Incident Commander*: <{incident.commander.individual.weblink}|{incident.commander.individual.name}>\n"
                             f"*Project*: {incident.project.name}"),
                        },
                    })
                except Exception as e:
                    log.exception(e)

    dispatch_slack_service.send_ephemeral_message(
        slack_client,
        channel_id,
        user_id,
        "Incident List",
        blocks=blocks,
    )
Пример #9
0
def sync_tasks(db_session=None):
    """Syncs incident tasks."""
    # we get all active and stable incidents
    active_incidents = incident_service.get_all_by_status(
        db_session=db_session, status=IncidentStatus.active)
    stable_incidents = incident_service.get_all_by_status(
        db_session=db_session, status=IncidentStatus.stable)
    incidents = active_incidents + stable_incidents

    # we create an instance of the drive task plugin
    drive_task_plugin = plugins.get(INCIDENT_PLUGIN_TASK_SLUG)

    for incident in incidents:
        for doc_type in [
                INCIDENT_RESOURCE_INVESTIGATION_DOCUMENT,
                INCIDENT_RESOURCE_INCIDENT_REVIEW_DOCUMENT,
        ]:
            # we get the document object
            document = get_document(db_session=db_session,
                                    incident_id=incident.id,
                                    resource_type=doc_type)

            if not document:
                # the document may have not been created yet (e.g. incident review document)
                break

            # we get the list of tasks in the document
            tasks = drive_task_plugin.list(file_id=document.resource_id)

            for t in tasks:
                # we get the task information
                creator = t["task"]["owner"]
                assignees = ", ".join(t["task"]["assignees"])
                description = t["task"]["description"][0]
                status = TaskStatus.open if not t["task"][
                    "status"] else TaskStatus.resolved
                resource_id = t["task"]["id"]
                weblink = t["task"]["web_link"]

                incident_task = task_service.get_by_resource_id(
                    db_session=db_session, resource_id=t["task"]["id"])
                if incident_task:
                    if status == TaskStatus.open:
                        # we don't need to take any actions if the status of the task in the collaboration doc is open
                        break
                    else:
                        if incident_task.status == TaskStatus.resolved:
                            # we don't need to take any actions if the task has already been marked as resolved in the database
                            break
                        else:
                            # we mark the task as resolved in the database
                            incident_task.status = TaskStatus.resolved
                            db_session.add(incident_task)
                            db_session.commit()

                            # we send a notification to the incident conversation
                            notification_text = "Incident Notification"
                            notification_type = "incident-notification"
                            convo_plugin = plugins.get(
                                INCIDENT_PLUGIN_CONVERSATION_SLUG)
                            convo_plugin.send(
                                incident.conversation.channel_id,
                                notification_text,
                                INCIDENT_TASK_RESOLVED_NOTIFICATION,
                                notification_type,
                                task_assignees=assignees,
                                task_description=description,
                                task_weblink=weblink,
                            )
                else:
                    # we add the task to the incident
                    task = task_service.create(
                        db_session=db_session,
                        creator=creator,
                        assignees=assignees,
                        description=description,
                        status=status,
                        resource_id=resource_id,
                        resource_type=INCIDENT_RESOURCE_INCIDENT_TASK,
                        weblink=weblink,
                    )
                    incident.tasks.append(task)
                    db_session.add(incident)
                    db_session.commit()

                    # we send a notification to the incident conversation
                    notification_text = "Incident Notification"
                    notification_type = "incident-notification"
                    convo_plugin = plugins.get(
                        INCIDENT_PLUGIN_CONVERSATION_SLUG)
                    convo_plugin.send(
                        incident.conversation.channel_id,
                        notification_text,
                        INCIDENT_TASK_NEW_NOTIFICATION,
                        notification_type,
                        task_assignees=assignees,
                        task_description=description,
                        task_weblink=weblink,
                    )