Notification Templates¶
Keystone issues automated notifications regarding changes to user accounts and resource allocations. Administrators can customize these notifications using templates to reflect organization-specific branding and messaging.
Overriding Templates¶
Keystone generates notifications using HTML templates and the Jinja2 templating engine. The location of custom templates is configurable via application settings.
When a notification is triggered, Keystone first checks for a custom template file. If no custom template is available, Keystone falls back to an internal default. The selected template is then rendered using the context data outlined below.
For security reasons, data is sanitized before being injected into the template. Certain Jinja features — such as access to application internals — are also disabled.
Note
Email notification templates can be rendered and written to disk using the keystone-api render_templates
command.
It is strongly recommended to develop and test templates locally before deploying them to a production environment.
See keystone-api render_templates --help
for details.
Base Template¶
Template file: base.html
The base template serves as the parent layout for all notification content, providing top-level styling and structure. The template defines two content blocks that child templates override to inject content.
Available Template Fields
Block Name | Description |
---|---|
main |
Main body content of the email notification. |
footer |
Footer content displayed at the bottom of the message. |
Default Template Content
<!doctype html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>Keystone User Notification</title>
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<style>
body {
font-family: Helvetica, sans-serif;
font-size: 16px;
line-height: 1.4;
background-color: #f5f5f5;
margin: 0;
padding: 0;
}
table.body {
width: 100%;
}
table.main {
width: 100%;
background-color: #ffffff;
border: 1px solid #eaeaea;
border-radius: 0;
}
table.footer {
width: 100%;
text-align: center;
padding-top: 24px;
padding-bottom: 24px;
}
td.container {
width: 800px;
padding-top: 24px;
}
td.wrapper {
padding: 24px;
}
td.footer-text {
color: #a1a1a1;
font-size: 11px;
}
</style>
</head>
<body>
<table role="presentation" class="body">
<tr>
<td> </td>
<td class="container">
<table role="presentation" class="main">
<tr>
<td class="wrapper">
{% block main %}{% endblock %}
</td>
</tr>
</table>
<table role="presentation" class="footer">
<tr>
<td class="footer-text">
{% block footer %}
The Keystone HPC Utility <br> © Better HPC
{% endblock %}
</td>
</tr>
</table>
</td>
<td> </td>
</tr>
</table>
</body>
</html>
Upcoming Resource Expiration¶
Template file: upcoming_expiration.html
The upcoming expiration notification alerts users that one or more of their active resource allocations is nearing its expiration date.
Available Template Fields
Field Name | Type | Description |
---|---|---|
user_name |
str |
Username of the notified user. |
user_first |
str |
First name of the notified user. |
user_last |
str |
Last name of the notified user. |
req_id |
int |
ID of the allocation request being notified about. |
req_title |
str |
Title or of the allocation request. |
req_team |
str |
Name of the team associated with the allocation request. |
req_submitted |
date |
Date when the allocation request was submitted. |
req_active |
date |
Date when the allocation request became active. |
req_expire |
date or None |
Date when the allocation request expires. |
req_days_left |
int or None |
Number of days remaining until expiration (calculated from current date). |
allocations |
list[dict] |
List of allocated resources tied to the request. Each item includes: |
├─ alloc_cluster |
str |
Name of the cluster where the resource is allocated. |
├─ alloc_requested |
int |
Number of service units requested (or 0 if unavailable). |
└─ alloc_awarded |
int |
Number of service units awarded (or 0 if unavailable). |
Default Template Content
{% extends "base.html" %}
{% block main %}
{% if user_first and user_last %}
<p>Dear {{ user_first }} {{ user_last }},</p>
{% else %}
<p>Dear {{ user_name }},</p>
{% endif %}
<p>
This is an automated notification that the HPC allocation request <strong>"{{ req_title }}"</strong>
(ID: {{ req_id }}) is scheduled to expire in {{ req_days_left }} days on {{ req_expire.strftime('%B %d, %Y') }}.
</p>
<p style="padding-top: 10px">
<strong>What Does This Mean</strong>
</p>
<p>
On {{ req_active.strftime('%B %d, %Y') }} the <em>{{ req_team }}</em> team was granted computational time across one
or more HPC clusters.
These allocated resources are set to expire on {{ req_expire.strftime('%B %d, %Y') }},
after which any unused service units will no longer be available to your team.
</p>
<p style="padding-top: 10px">
<strong>What Happens Now</strong>
</p>
<p>
Your team may continue to submit jobs and utilize any remaining service units up to the expiration date.
If you require additional compute time after expiration, an administrator for the <em>{{ req_team }}</em> team
will need to submit a request for additional resources.
</p>
<p style="padding-top: 10px">
Sincerely,<br>The Keystone HPC Utility
</p>
{% endblock %}
Expired Resource Allocation¶
Template file: past_expiration.html
The past expiration notification alerts users that one or more of their active resource allocations has expired and that the resources granted under that allocation are no longer available for use.
Available Template Fields
Field Name | Type | Description |
---|---|---|
user_name |
str |
Username of the notified user. |
user_first |
str |
First name of the notified user. |
user_last |
str |
Last name of the notified user. |
req_id |
int |
ID of the allocation request being notified about. |
req_title |
str |
Title or of the allocation request. |
req_team |
str |
Name of the team associated with the allocation request. |
req_submitted |
date |
Date when the allocation request was submitted. |
req_active |
date |
Date when the allocation request became active. |
req_expire |
date or None |
Date when the allocation request expires. |
allocations |
list[dict] |
List of allocated resources tied to the request. Each item includes: |
├─ alloc_cluster |
str |
Name of the cluster where the resource is allocated. |
├─ alloc_requested |
int |
Number of service units requested (or 0 if unavailable). |
└─ alloc_awarded |
int |
Number of service units awarded (or 0 if unavailable). |
└─ alloc_awarded |
int |
Number of service unitss used by the team (or 0 if unavailable). |
Default Template Content
{% extends "base.html" %}
{% macro percent(numerator, denominator) %}
{% if denominator %}
({{ '%.0f' % ((numerator / denominator) * 100) }}%)
{% else %}
{% endif %}
{% endmacro %}
{% block main %}
{% if user_first and user_last %}
<p>Dear {{ user_first }} {{ user_last }},</p>
{% else %}
<p>Dear {{ user_name }},</p>
{% endif %}
<p>
This is an automated notification that the HPC allocation request <strong>"{{ req_title }}"</strong>
(ID: {{ req_id }}) submitted by the <em>{{ req_team }}</em> team has expired.
</p>
<p>
Your team's total resource usage under this allocation request is provided below.
</p>
<table style="width: 100%; border-collapse: collapse; font-family: sans-serif; font-size: 14px;">
<thead>
<tr style="background-color: #f2f2f2;">
<th style="text-align: center; padding: 8px; border: 1px solid #ccc;">Cluster</th>
<th style="text-align: center; padding: 8px; border: 1px solid #ccc;">Awarded SUs</th>
<th style="text-align: center; padding: 8px; border: 1px solid #ccc;">Utilized SUs</th>
</tr>
</thead>
<tbody>
{% for alloc in allocations %}
<tr>
<td style="text-align: center; padding: 8px; border: 1px solid #ccc;">{{ alloc.alloc_cluster }}</td>
<td style="text-align: center; padding: 8px; border: 1px solid #ccc;">{{ "{:,}".format(alloc.alloc_awarded) }}</td>
<td style="text-align: center; padding: 8px; border: 1px solid #ccc;">
{{ "{:,}".format(alloc.alloc_final) }} {{ percent(alloc.alloc_final, alloc.alloc_awarded) }}
</td>
</tr>
{% endfor %}
</tbody>
</table>
<p style="padding-top: 10px">
<strong>What Does This Mean</strong>
</p>
<p>
On {{ req_submitted.strftime('%B %d, %Y') }} your team requested the HPC service units listed above.
Access to these resources went into effect on {{ req_active.strftime('%B %d, %Y') }} and expired on
{{ req_expire.strftime('%B %d, %Y') }}.
Now that the allocation request has expired, any unused service units are no longer available for use by your team.
</p>
<p>
Any resources granted to your team by other allocation requests remain unaffected.
The system will automatically apply as much of your system usage as possible to the expiring request, maximizing
the total service units available in any remaining allocations.
</p>
<p style="padding-top: 10px">
<strong>What Happens Now</strong>
</p>
<p>
If you no longer require HPC service units, have already submitted a follow-up request, or have sufficient service
units through a different request, then no action is required at this time.
</p>
<p>
If you require additional HPC service units, an administrator for the <em>{{ req_team }}</em> team
will need to submit a new request for additional resources.
</p>
<p>
For any additional questions, please contact your system administrator(s).
</p>
<p style="padding-top: 10px">
Sincerely,<br>The Keystone HPC Utility
</p>
{% endblock %}