Skip to content

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>&nbsp;</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> &copy; Better HPC
            {% endblock %}
          </td>
        </tr>
      </table>
    </td>
    <td>&nbsp;</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 %}
    &nbsp;
  {% 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 %}