Skip to content

Commit

Permalink
working version
Browse files Browse the repository at this point in the history
  • Loading branch information
Avi-Robusta committed Jan 2, 2025
1 parent f02485c commit ce26d0f
Show file tree
Hide file tree
Showing 4 changed files with 109 additions and 8 deletions.
20 changes: 16 additions & 4 deletions playbooks/robusta_playbooks/sink_enrichments.py
Original file line number Diff line number Diff line change
Expand Up @@ -20,7 +20,7 @@ class OpsGenieAckParams(ActionParams):

alert_fingerprint: str
slack_username: Optional[str]
slack_message: Optional[Dict[str, Any]]
slack_message: Optional[Any]


@action
Expand All @@ -32,8 +32,20 @@ def ack_opsgenie_alert() -> None:
user=params.slack_username,
note=f"This alert was ack-ed from a Robusta Slack message by {params.slack_username}"
)
logging.info(f"Acking {params.alert_fingerprint} {params.slack_username}")
logging.warning(params.slack_message)

# slack action block
actions = params.slack_message.get("actions", [])
if len(actions) == 0:
return
block_id = actions[0].get("block_id")

event.emit_event(
"replace_callback_with_string",
slack_message=params.slack_message,
block_id=block_id,
message_string=f"✅ *OpsGenie Ack by @{params.slack_username}*"
)

ack_opsgenie_alert()


Expand Down Expand Up @@ -81,4 +93,4 @@ def normalize_url_base(url_base: str) -> str:
@action
def opsgenie_link_enricher(alert: PrometheusKubernetesAlert, params: OpsgenieLinkParams):
normalized_url_base = normalize_url_base(params.url_base)
alert.add_link(Link(url=f"https://{normalized_url_base}/alert/list?query=alias:{alert.alert.fingerprint}", name="OpsGenie Alert", type=LinkType.OPSGENIE))
alert.add_link(Link(url=f"https://{normalized_url_base}/alert/list?query=alias:{alert.alert.fingerprint}", name="OpsGenie Alert", type=LinkType.OPSGENIE))
61 changes: 60 additions & 1 deletion src/robusta/core/sinks/slack/slack_sink.py
Original file line number Diff line number Diff line change
@@ -1,3 +1,5 @@
import logging

from robusta.core.model.env_vars import ROBUSTA_UI_DOMAIN
from robusta.core.reporting.base import Finding, FindingStatus
from robusta.core.sinks.sink_base import NotificationGroup, NotificationSummary, SinkBase
Expand All @@ -15,6 +17,13 @@ def __init__(self, sink_config: SlackSinkConfigWrapper, registry):
self.slack_sender = slack_module.SlackSender(
self.api_key, self.account_id, self.cluster_name, self.signing_key, self.slack_channel
)
self.registry.subscribe("replace_callback_with_string", self)

def handle_event(self, event_name: str, **kwargs):
if event_name == "replace_callback_with_string":
self.__replace_callback_with_string(**kwargs)
else:
logging.warning("SlackSink subscriber called with unknown event")

def write_finding(self, finding: Finding, platform_enabled: bool) -> None:
if self.grouping_enabled:
Expand Down Expand Up @@ -75,6 +84,56 @@ def handle_notification_grouping(self, finding: Finding, platform_enabled: bool)
finding, self.params, platform_enabled, thread_ts=slack_thread_ts
)


def get_timeline_uri(self, account_id: str, cluster_name: str) -> str:
return f"{ROBUSTA_UI_DOMAIN}/graphs?account_id={account_id}&cluster={cluster_name}"

def __replace_callback_with_string(self, slack_message, block_id, message_string):
"""
Replace a specific block in a Slack message with a given string while preserving other blocks.
Args:
json_message (dict): The JSON payload received from Slack.
block_id (str): The ID of the block to replace.
message_string (str): The text to replace the block content with.
"""
try:
# Extract required fields
channel_id = slack_message.get("channel", {}).get("id")
message_ts = slack_message.get("container", {}).get("message_ts")
blocks = slack_message.get("message", {}).get("blocks", [])

# Validate required fields
if not channel_id or not message_ts or not blocks:
raise ValueError("Missing required fields: channel_id, message_ts, or blocks.")

# Update the specific block
updated_blocks = []
block_found = False

for block in blocks:
if block.get("block_id") == block_id:
updated_blocks.append({
"type": "section",
"block_id": block_id,
"text": {
"type": "mrkdwn",
"text": message_string
}
})
block_found = True
else:
updated_blocks.append(block)

if not block_found:
raise ValueError(f"No block found with block_id: {block_id}")

# Call the shorter update function
return self.slack_sender.update_slack_message(
channel=channel_id,
ts=message_ts,
blocks=updated_blocks,
text=message_string
)

except Exception as e:
logging.exception(f"❌ Error updating Slack message: {e}")
4 changes: 2 additions & 2 deletions src/robusta/integrations/receiver.py
Original file line number Diff line number Diff line change
Expand Up @@ -52,7 +52,7 @@ class ValidationResponse(BaseModel):
class SlackExternalActionRequest(ExternalActionRequest):
# Optional Slack Params
slack_username: Optional[str] = None
slack_message: Optional[Dict[str, Any]] = None
slack_message: Optional[Any] = None


class SlackActionRequest(BaseModel):
Expand Down Expand Up @@ -211,7 +211,7 @@ def _parse_slack_message(message: Union[str, bytes, bytearray]) -> SlackActionsM
slack_actions_message = SlackActionsMessage.parse_raw(message) # this is slack callback format
for action in slack_actions_message.actions:
action.value.slack_username = slack_actions_message.user.username
action.value.slack_message = slack_actions_message.message
action.value.slack_message = json.loads(message)
return slack_actions_message

def on_message(self, ws: websocket.WebSocketApp, message: str) -> None:
Expand Down
32 changes: 31 additions & 1 deletion src/robusta/integrations/slack/sender.py
Original file line number Diff line number Diff line change
Expand Up @@ -15,8 +15,8 @@
from robusta.core.model.base_params import AIInvestigateParams, ResourceInfo
from robusta.core.model.env_vars import (
ADDITIONAL_CERTIFICATE,
SLACK_REQUEST_TIMEOUT,
HOLMES_ENABLED,
SLACK_REQUEST_TIMEOUT,
SLACK_TABLE_COLUMNS_LIMIT,
)
from robusta.core.playbooks.internal.ai_integration import ask_holmes
Expand Down Expand Up @@ -695,3 +695,33 @@ def send_or_update_summary_message(
return resp["ts"]
except Exception as e:
logging.exception(f"error sending message to slack\n{e}\nchannel={channel}\n")

def update_slack_message(self, channel: str, ts: str, blocks: list, text: str = ""):
"""
Update a Slack message with new blocks and optional text.
Args:
channel (str): Slack channel ID.
ts (str): Timestamp of the message to update.
blocks (list): List of Slack Block Kit blocks for the updated message.
text (str, optional): Plain text summary for accessibility. Defaults to "".
"""
try:
# Ensure channel ID exists in the mapping
if channel not in self.channel_name_to_id.values():
logging.error(f"Channel ID for {channel} could not be determined. Update aborted.")
return

# Call Slack's chat_update method
resp = self.slack_client.chat_update(
channel=channel,
ts=ts,
text=text,
blocks=blocks
)
logging.debug(f"Message updated successfully: {resp['ts']}")
return resp["ts"]

except Exception as e:
logging.exception(f"Error updating Slack message: {e}")
return None

0 comments on commit ce26d0f

Please sign in to comment.