{% extends "admin/_layout.html" %} {% from "_macros.html" import icon %} {% set section = "updates" %} {% block title %}Updates - {{ brand.name }}{% endblock %} {% block heading %}Updates{% endblock %} {% block admin_content %}

This host follows the {{ "stable" if state.channel == "stable" else "edge" }} channel{% if state.channel == "stable" %} — the newest release tag{% else %} — the tip of {{ state.branch }}, which is whatever was pushed most recently and may be half finished{% endif %}. Checking reaches the remote; opening this page does not.

{% if saved %}
{{ icon("check", "icon--sm") }} {{ saved }}
{% endif %} {% if state.error %}
{{ icon("warning", "icon--sm") }} {{ state.error }}
{% endif %}

Running

Version
{# `git describe`, not the version string: "1.0.0" exactly at a tag and "1.0.0-7-gd4f56d" seven commits past one. The second is the honest answer for an edge instance, where the version string alone would claim to be a release it is not. #} {{ state.running or state.version }} {% if state.running and state.running != state.version %} (reports {{ state.version }}) {% endif %}
{% if state.head %}
Commit
{{ state.head.short }} {{ state.head.subject }} {% if state.dirty %}uncommitted changes{% endif %}
{% endif %} {% if state.checkout %}
Checkout
{{ state.checkout }}
{% endif %}
{% if state.version_mismatch %}
{{ icon("warning", "icon--sm") }} This is tagged {{ state.version_mismatch }} but reports version {{ state.version }}. A tag cut before the version bump names a release nobody can identify afterwards.
{% endif %} {% if not state.is_git %}

This was not installed from a git checkout — a container image, or a wheel — so there is nothing here to compare or update. Pull a new image instead.

{% else %}
{% endif %}
{% if state.is_git %}

Available {% if state.no_releases %}nothing released yet {% elif state.up_to_date %}up to date {% elif state.behind %}{{ state.behind | length }} commit{{ '' if state.behind|length == 1 else 's' }} behind {% endif %}

{% if state.no_releases %}

Nothing on {{ state.branch }} has been tagged as a release yet, so the stable channel has nothing to offer. Switch this host to edge in lembas.env to follow the branch instead.

{% elif not state.available %}

Nothing known about the remote yet. Check it above.

{% elif state.up_to_date %}

{{ state.available.label }} is what is running.

{% else %}

{{ state.available.label }} — {{ state.available.subject }}

{# Release notes, out of the annotated tag itself. Escaped and preformatted, never through services/markdown.py: this comes from a tag object rather than from a template, and markdown is the one path allowed to emit HTML. #} {% if state.available.notes %}
{{ state.available.notes }}
{% endif %} {# The commits between, not just a count. "3 behind" is a number somebody has to go and look up; the subjects are what decides whether this is worth restarting for right now. #} {% if state.behind %}
{{ state.behind | length }} commit{{ '' if state.behind|length == 1 else 's' }} between
{% endif %} {% if state.dirty %}
{{ icon("warning", "icon--sm") }} This checkout has uncommitted changes, and updating discards them. Nothing here is meant to be edited in place, so this usually means somebody was debugging on the box.
{% endif %} {% endif %}
{# Its own card, and rendered whether or not there is anything to apply. It used to live inside the "there is an update" branch, so an administrator could not find out that the helper was missing until the day they needed it -- which is the worst moment to discover a thing has to be installed from a shell. #}

Applying an update

{% if state.requested %}
{{ icon("clock", "icon--sm") }} An update has been requested and is waiting for the helper to pick it up. The service restarts when it does.
{% elif state.helper %}

This host has the update helper installed, so the button below writes a request that a systemd unit picks up and runs as root. It always deploys the {{ state.channel }} channel — the request carries no ref and no channel, so pressing it is never “deploy something else”.

Every restart ends every open terminal session — a command still running on the far side is cut off. A reply being written is saved with whatever it has.

{% else %}
{{ icon("shield", "icon--sm") }} The update helper is not installed on this host, so there is no button. That is the honest default: the service runs as an unprivileged account and cannot restart itself, and a web application that can is one whose worst day is much worse. Run this instead: {{ command }}

To install it, re-run the installer with INSTALL_UPDATE_HELPER=1. Doing so means anybody who can administer this web interface can deploy the {{ state.channel }} channel — which is the point, and worth deciding on purpose rather than arriving at.

{% endif %}
{% endif %} {% endblock %}