Skip to content

Commit

Permalink
Release v1.8.1 - Bug fix for pinned items. (#410)
Browse files Browse the repository at this point in the history
  • Loading branch information
echoboomer committed Jan 5, 2024
1 parent 5391c38 commit 34ed128
Show file tree
Hide file tree
Showing 11 changed files with 270 additions and 30 deletions.
14 changes: 10 additions & 4 deletions backend/bot/incident/actions.py
Original file line number Diff line number Diff line change
Expand Up @@ -696,12 +696,18 @@ async def set_status(
)

# Update jira ticket status last
if config.active.integrations.get(
"atlassian", {}).get("jira", {}).get("status_mapping", []):
if (
config.active.integrations.get("atlassian", {})
.get("jira", {})
.get("status_mapping", [])
):
from bot.jira.api import JiraApi

jira = JiraApi()
jira.update_issue_status(incident_status=action_value,
incident_name=incident_data.channel_name)
jira.update_issue_status(
incident_status=action_value,
incident_name=incident_data.channel_name,
)

# Finally, updated the updated_at column
db_update_incident_updated_at_col(
Expand Down
36 changes: 26 additions & 10 deletions backend/bot/incident/incident.py
Original file line number Diff line number Diff line change
Expand Up @@ -219,7 +219,7 @@ def __format_channel_name(self) -> str:
).lower()

datefmt = self.__format_date()
prefix = "inc"
prefix = config.default_incident_channel_name_prefix

if config.active.options.get("channel_naming"):
if config.active.options.get("channel_naming").get(
Expand Down Expand Up @@ -647,42 +647,58 @@ async def handle_incident_optional_features(
"""
If a Jira incident should be created automatically, create it
"""
if "atlassian" in config.active.integrations and "jira" in config.active.integrations.get("atlassian"):
if (
"atlassian" in config.active.integrations
and "jira" in config.active.integrations.get("atlassian")
):
if (
config.active.integrations.get("atlassian")
.get("jira")
.get("auto_create_incident")
):
from bot.jira.issue import JiraIssue

try:
issue_obj = JiraIssue(
incident_id=channel_name,
description=channel_name,
issue_type=config.active.integrations.get("atlassian").get("jira").get("auto_create_incident_type"),
issue_type=config.active.integrations.get("atlassian")
.get("jira")
.get("auto_create_incident_type"),
summary=created_channel_details["incident_description"],
)
resp = issue_obj.new()
if resp is not None:
from bot.models.incident import db_update_jira_issues_col
issue_link = "{}/browse/{}".format(config.atlassian_api_url, resp.get("key"))

issue_link = "{}/browse/{}".format(
config.atlassian_api_url, resp.get("key")
)
db_update_jira_issues_col(
channel_id=channel_id,
issue_link=issue_link,
)

from bot.slack.messages import new_jira_message

try:
resp = slack_web_client.chat_postMessage(
channel=channel_id,
blocks=new_jira_message(
key = resp.get("key"),
summary=created_channel_details["incident_description"],
type=config.active.integrations.get("atlassian").get("jira").get("auto_create_incident_type"),
key=resp.get("key"),
summary=created_channel_details[
"incident_description"
],
type=config.active.integrations.get(
"atlassian"
)
.get("jira")
.get("auto_create_incident_type"),
link=issue_link,
),
text="A Jira issue has been created for this incident: {}".format(
resp.get("self")
)
),
)
slack_web_client.pins_add(
channel=channel_id,
Expand All @@ -694,5 +710,5 @@ async def handle_incident_optional_features(
)
except Exception as error:
logger.error(
f"Error creating Jira incident for {channel_name}: {error}"
)
f"Error creating Jira incident for {channel_name}: {error}"
)
78 changes: 78 additions & 0 deletions backend/bot/interfaces/kubernetes.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,78 @@
from iblog import logger
from kubernetes import client, config
from typing import Dict, List

"""
WIP
"""

config.load_kube_config()
# config.load_incluster_config()

crd_group = "extensions.incidentbot.io"
crd_namespace = "incident-bot"
crd_plural = "incidents"
crd_version = "v1alpha1"

api = client.CustomObjectsApi()


def get_incident(name: str) -> Dict:
"""Return an incident stored via the CustomResourceDefinition for Kubernetes
Keyword arguments:
name -- string containing the name of the Incident CRD
"""
try:
resource = api.get_namespaced_custom_object(
group=crd_group,
version=crd_version,
name=name,
namespace=crd_namespace,
plural=crd_plural,
)
except client.exceptions.ApiException as error:
logger.Error(
f"Error looking for incident {name} in Kubernetes cluster: {error}"
)

return resource


def get_incidents() -> List[Dict]:
"""Return a list of incidents stored via the CustomResourceDefinition for Kubernetes"""
try:
resources = api.list_namespaced_custom_object(
group=crd_group,
version=crd_version,
namespace=crd_namespace,
plural=crd_plural,
)

return resources.get("items")
except client.exceptions.ApiException as error:
logger.Error(
f"Error looking for incidents in Kubernetes cluster: {error}"
)


def patch_incident(name: str, body: Dict):
"""Patch an incident stored via the CustomResourceDefinition for Kubernetes
Keyword arguments:
name -- string containing the name of the Incident CRD
body -- the body for the patch operation
"""
try:
api.patch_namespaced_custom_object(
group=crd_group,
version=crd_version,
name=name,
namespace=crd_namespace,
plural=crd_plural,
body=body,
)
except client.exceptions.ApiException as error:
logger.Error(
f"Error patching incident {name} in Kubernetes cluster: {error}"
)
38 changes: 27 additions & 11 deletions backend/bot/jira/api.py
Original file line number Diff line number Diff line change
Expand Up @@ -88,34 +88,50 @@ def test(self) -> bool:
logger.error(f"Please check Jira configuration and try again.")

def update_issue_status(self, incident_status: str, incident_name: str):
status_mapping = config.active.integrations.get(
"atlassian", {}).get("jira", {}).get("status_mapping", [])
status_mapping = (
config.active.integrations.get("atlassian", {})
.get("jira", {})
.get("status_mapping", [])
)
if not status_mapping:
logger.debug("No status mapping found for Jira integration")
return
jira_status = ""
for status in status_mapping:
if status.get("incident_status").lower() == incident_status.lower():
if (
status.get("incident_status").lower()
== incident_status.lower()
):
jira_status = status.get("jira_status")
break
if not jira_status:
logger.debug(
f"No Jira status found for incident status {incident_status}")
f"No Jira status found for incident status {incident_status}"
)
return

try:
project = config.active.integrations.get(
"atlassian").get("jira").get("project")
project = (
config.active.integrations.get("atlassian")
.get("jira")
.get("project")
)
labels = [incident_name]
issue_type = config.active.integrations.get(
"atlassian").get("jira").get("issue_type")
issue_type = (
config.active.integrations.get("atlassian")
.get("jira")
.get("issue_type")
)
logger.info(
f"Updating Jira issues with labels {labels} and issue type {issue_type} to status {jira_status}")
f"Updating Jira issues with labels {labels} and issue type {issue_type} to status {jira_status}"
)
issues = self.jira.jql_get_list_of_tickets(
f"project=\"{project}\" and labels in ({','.join(labels)})")
f"project=\"{project}\" and labels in ({','.join(labels)})"
)
for issue in issues:
logger.debug(
f"Updating Jira issue {issue.get('key')} to status {jira_status}")
f"Updating Jira issue {issue.get('key')} to status {jira_status}"
)
self.jira.set_issue_status(issue.get("key"), jira_status)
except requests.exceptions.HTTPError as error:
logger.error(f"Error updating Jira issue: {error}")
12 changes: 11 additions & 1 deletion backend/bot/slack/handler.py
Original file line number Diff line number Diff line change
Expand Up @@ -406,7 +406,17 @@ def reaction_added(event, say):
# Pinned content for incidents
if emoji == "pushpin":
channel_info = slack_web_client.conversations_info(channel=channel_id)
if "inc-" in channel_info["channel"]["name"]:

prefix = config.default_incident_channel_name_prefix
if config.active.options.get("channel_naming"):
if config.active.options.get("channel_naming").get(
"channel_name_prefix"
):
prefix = config.active.options.get("channel_naming").get(
"channel_name_prefix"
)

if f"{prefix}-" in channel_info["channel"]["name"]:
# Retrieve the content of the message that was reacted to
try:
result = slack_web_client.conversations_history(
Expand Down
5 changes: 4 additions & 1 deletion backend/config.py
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,7 @@
from iblog import logger, log_level
from typing import Dict, List

__version__ = "v1.8.0"
__version__ = "v1.8.1"

# .env parse
dotenv_path = os.path.join(os.path.dirname(__file__), ".env")
Expand Down Expand Up @@ -429,6 +429,9 @@ def statuses(self) -> List:
slack_bot_token = os.getenv("SLACK_BOT_TOKEN")
slack_user_token = os.getenv("SLACK_USER_TOKEN")

# Default incident channel name prefix
default_incident_channel_name_prefix = "inc"

# For internal pagination when iterating over collections returned from Slack
slack_items_pagination_per_page = 5

Expand Down
98 changes: 98 additions & 0 deletions backend/kubernetes/incident-crd.yaml
Original file line number Diff line number Diff line change
@@ -0,0 +1,98 @@
apiVersion: apiextensions.k8s.io/v1
kind: CustomResourceDefinition
metadata:
creationTimestamp: null
name: incidents.extensions.incidentbot.io
spec:
group: extensions.incidentbot.io
names:
kind: Incident
listKind: IncidentList
plural: incidents
shortNames:
- inc
singular: incident
scope: Namespaced
versions:
- additionalPrinterColumns:
- description: Creation timestamp
jsonPath: .metadata.creationTimestamp
name: Created
type: date
- description: Severity
jsonPath: .spec.severity
name: Severity
type: string
- description: Status
jsonPath: .spec.status
name: Status
type: string
name: v1alpha1
schema:
openAPIV3Schema:
required:
- spec
type: object
properties:
spec:
required:
- id
- created_at
- channel_description
- channel_id
- channel_name
- is_security_incident
- severity
- status
type: object
properties:
id:
type: string
created_at:
type: string
updated_at:
type: string
channel_description:
type: string
channel_id:
type: string
channel_name:
type: string
conference_bridge:
type: string
is_security_incident:
type: boolean
last_update_sent:
type: string
rca:
type: string
roles:
type: object
severity:
type: string
status:
type: string
tags:
items:
type: string
type: array
bp_message_ts:
type: string
dig_message_ts:
type: string
sp_message_ts:
type: string
sp_incident_id:
type: string
sp_incident_data:
type: object
jira_issues:
items:
type: string
type: array
pagerduty_incidents:
items:
type: string
type: array
served: true
storage: true
13 changes: 13 additions & 0 deletions backend/kubernetes/sample-incident-rd.yaml
Original file line number Diff line number Diff line change
@@ -0,0 +1,13 @@
apiVersion: extensions.incidentbot.io/v1alpha1
kind: Incident
metadata:
name: foo
spec:
id: '2024-01-01-1234'
created_at: '2024-01-01-1234'
channel_description: 'placeholder'
channel_id: 'placeholder'
channel_name: 'placeholder'
is_security_incident: false
severity: 'sev4'
status: 'investigating'
Loading

0 comments on commit 34ed128

Please sign in to comment.