Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Fix bugs in web title and message templates rendering and visual representation #1747

Merged
merged 17 commits into from
May 2, 2023
Merged
Show file tree
Hide file tree
Changes from 6 commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
Expand Up @@ -76,7 +76,7 @@ def __init__(self, alert):
self.alert = alert
self.slack_formatter = SlackFormatter(alert.group.channel.organization)
self.template_manager = TemplateLoader()
self.incident_id = self.alert.group.inside_organization_number
self.alert_group_id = self.alert.group.inside_organization_number
self.link = self.alert.group.web_link

def render(self):
Expand Down Expand Up @@ -168,13 +168,34 @@ def _render_attribute_with_template(self, attr, data, channel, templated_alert):
attr_template = self.template_manager.get_attr_template(attr, channel, self._render_for())
if attr_template is not None:
context = {
"grafana_oncall_incident_id": self.incident_id,
"grafana_oncall_link": self.link,
"integration_name": channel.verbal_name,
"source_link": templated_alert.source_link,
"amixr_incident_id": self.incident_id, # TODO: decide on variable names
"amixr_link": self.link, # TODO: decide on variable names
"grafana_oncall_alert_group_id": self.alert_group_id,
"grafana_oncall_incident_id": self.alert_group_id, # Keep for backward compatibility
"amixr_incident_id": self.alert_group_id, # Keep for backward compatibility
"grafana_oncall_link": self.link,
"amixr_link": self.link, # Keep for backward compatibility
}
# Hardcoding, as AlertWebTemplater.RENDER_FOR_WEB cause circular import
render_for_web = "web"
# Propagate rendered web templates to the other templates
if self._render_for() != render_for_web:
added_context = {
"web_title": apply_jinja_template(
self.template_manager.get_attr_template("title", channel, render_for_web),
data,
result_length_limit=settings.JINJA_RESULT_TITLE_MAX_LENGTH,
**context,
),
"web_message": apply_jinja_template(
self.template_manager.get_attr_template("message", channel, render_for_web), data, **context
),
"web_image_url": apply_jinja_template(
self.template_manager.get_attr_template("image_url", channel, render_for_web), data, **context
),
}
context = {**context, **added_context}

try:
if attr == "title":
return apply_jinja_template(
Expand Down
11 changes: 6 additions & 5 deletions engine/common/utils.py
Original file line number Diff line number Diff line change
Expand Up @@ -168,13 +168,14 @@ def convert_md_to_html(text):
# This gives us <pre> and <code> tags for ```-fenced blocks
"fenced-code-blocks",
"pyshell",
"nl2br",
"target-blank-links",
"nofollow",
"pymdownx.emoji",
"pymdownx.magiclink",
"tables",
],
).strip()
# Special handling cases for lists
text = text.replace("\n\n<ul>", "<ul>")
text = text.replace("\n<li>", "<li>")
# Special handling cases for newlines
text = text.replace("\n", "<br/>")
return text


Expand Down
133 changes: 82 additions & 51 deletions engine/config_integrations/alertmanager.py
Original file line number Diff line number Diff line change
Expand Up @@ -20,60 +20,101 @@
<br>Creating contact points and routes for other alertmanagers...
{% endif %}"""

# Default templates
slack_title = """\
{# Usually title is located in payload.labels.alertname #}
{% set title = payload.get("labels", {}).get("alertname", "No title (check Web Title Template)") %}
{# Combine the title from different built-in variables into slack-formatted url #}
*<{{ grafana_oncall_link }}|#{{ grafana_oncall_incident_id }} {{ title }}>* via {{ integration_name }}
{% if source_link %}
(*<{{ source_link }}|source>*)
{%- endif %}
# Web
web_title = """{{- payload.labels.alertname }}
"""
web_message = """\
{%- set annotations = payload.annotations -%}
{%- set labels = payload.labels -%}

{%- set severity = payload.labels.severity | default("Unknown") -%}
{%- set severity_emoji = {"critical": "🚨", "warning": "⚠️" }[severity] | default("⁉️") -%}
**Severity**: {{ severity }}{{ severity_emoji }}

{% set status = payload.status | default("") -%}
{%- set status_emoji = {"firing": "🔥", "resolved": "✅"}[status] | default("⚠️") -%}
**Status**: {{ status }}{{ status_emoji }}

{%- if "message" in payload.annotations %}
{{ annotations.message }}
{% set _ = annotations.pop('message') %}
{% endif %}

{%- if "runbook_url" in payload.annotations %}
[📖 Runbook]({{ payload.annotations.runbook_url }})
{% set _ = annotations.pop('runbook_url') %}
{% endif %}

**🏷️ Labels:**
```
{%- for k, v in payload["labels"].items() %}
{{ k }}={{ v }}
{%- endfor %}
```

{%- if annotations |length > 0%}
**Other annotations:**
{% for k, v in payload["annotations"].items() %}
{#- render annotation as markdown url if it starts with http #}
- *{{ k }}*: {% if v.startswith("http") %} [here]({{v}}){% else %} {{v}} {% endif -%}
{% endfor %}
{% endif %}
```

slack_message = """\
{{- payload.message }}
{%- if "status" in payload -%}
*Status*: {{ payload.status }}
{% endif -%}
*Labels:* {% for k, v in payload["labels"].items() %}
{{ k }}: {{ v }}{% endfor %}
*Annotations:*
{%- for k, v in payload.get("annotations", {}).items() %}
{#- render annotation as slack markdown url if it starts with http #}
{{ k }}: {% if v.startswith("http") %} <{{v}}|here> {% else %} {{v}} {% endif -%}
{%- if annotations |length > 0%}
**Other annotations:**
{% for k, v in payload["annotations"].items() %}
{#- render annotation as markdown url if it starts with http #}
- *{{ k }}*: {% if v.startswith("http") %} [here]({{v}}){% else %} {{v}} {% endif -%}
{% endfor %}
{% endif %}
```

{%- if annotations |length > 0%}
**Other annotations:**
{%- for k, v in payload["annotations"].items() %}
{#- render annotation as markdown url if it starts with http #}
*{{ k }}*: {% if v.startswith("http") %} [here]({{v}}){% else %} {{v}} {% endif -%}
{% endfor %}
{% endif %}
""" # noqa: W291

web_image_url = None

slack_image_url = None
# Behaviour
source_link = "{{ payload.generatorURL }}"

web_title = """\
{# Usually title is located in payload.labels.alertname #}
{{- payload.get("labels", {}).get("alertname", "No title (check Web Title Template)") }}
grouping_id = "{{ payload.labels }}"

resolve_condition = """\
{{ payload.status == "resolved" }}
"""

web_message = """\
{{- payload.message }}
{%- if "status" in payload %}
**Status**: {{ payload.status }}
{% endif -%}
**Labels:** {% for k, v in payload["labels"].items() %}
*{{ k }}*: {{ v }}{% endfor %}
**Annotations:**
{%- for k, v in payload.get("annotations", {}).items() %}
{#- render annotation as markdown url if it starts with http #}
*{{ k }}*: {% if v.startswith("http") %} [here]({{v}}){% else %} {{v}} {% endif -%}
{% endfor %}
acknowledge_condition = None

# Slack
slack_title = """\
*<{{ grafana_oncall_link }}|#{{ grafana_oncall_incident_id }} {{ web_title_template }}>* via {{ integration_name }}
{% if source_link %}
(*<{{ source_link }}|source>*)
{%- endif %}
"""

slack_message = """\
{{ web_message_template }}
""" # noqa: W291


web_image_url = slack_image_url
slack_image_url = web_image_url

# SMS
sms_title = web_title

sms_title = '{{ payload.get("labels", {}).get("alertname", "Title undefined") }}'
phone_call_title = sms_title
# Phone
phone_call_title = web_title

telegram_title = sms_title
# Telegram
telegram_title = web_title

telegram_message = """\
{{- payload.messsage }}
Expand All @@ -88,17 +129,7 @@
{{ k }}: {{ v }}
{% endfor %}""" # noqa: W291

telegram_image_url = slack_image_url

source_link = "{{ payload.generatorURL }}"

grouping_id = "{{ payload.labels }}"

resolve_condition = """\
{{ payload.get("status", "") == "resolved" }}
"""

acknowledge_condition = None
telegram_image_url = web_image_url

tests = {
"payload": {
Expand Down
1 change: 1 addition & 0 deletions engine/requirements.txt
Original file line number Diff line number Diff line change
Expand Up @@ -52,3 +52,4 @@ django-dbconn-retry==0.1.7
django-ipware==4.0.2
django-anymail==8.6
django-deprecate-fields==0.1.1
pymdown-extensions==9.11
2 changes: 1 addition & 1 deletion grafana-plugin/src/utils/sanitize.ts
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@ import dompurify from 'dompurify';
export default function sanitize(str: string): string {
return dompurify.sanitize(str, {
USE_PROFILES: { html: true },
FORBID_TAGS: ['form', 'input', 'pre'],
FORBID_TAGS: ['form', 'input'],
Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@maskin25 can you approve this change?

ADD_ATTR: ['target'],
});
}