outposts: add support for version checking

This commit is contained in:
Jens Langhammer 2020-09-19 00:54:48 +02:00
parent e75c9e9a79
commit 18886697d6
3 changed files with 43 additions and 9 deletions

View File

@ -44,6 +44,7 @@
<th role="columnheader" scope="col">{% trans 'Name' %}</th> <th role="columnheader" scope="col">{% trans 'Name' %}</th>
<th role="columnheader" scope="col">{% trans 'Providers' %}</th> <th role="columnheader" scope="col">{% trans 'Providers' %}</th>
<th role="columnheader" scope="col">{% trans 'Health' %}</th> <th role="columnheader" scope="col">{% trans 'Health' %}</th>
<th role="columnheader" scope="col">{% trans 'Version' %}</th>
<th role="cell"></th> <th role="cell"></th>
</tr> </tr>
</thead> </thead>
@ -59,7 +60,7 @@
</span> </span>
</td> </td>
<td role="cell"> <td role="cell">
{% with health=outpost.health %} {% with health=outpost.deployment_health %}
{% if health %} {% if health %}
<i class="fas fa-check pf-m-success"></i> {{ health|naturaltime }} <i class="fas fa-check pf-m-success"></i> {{ health|naturaltime }}
{% else %} {% else %}
@ -67,6 +68,17 @@
{% endif %} {% endif %}
{% endwith %} {% endwith %}
</td> </td>
<td role="cell">
<span>
{% with ver=outpost.deployment_version %}
{% if ver.outdated or ver.version == "" %}
<i class="fas fa-times pf-m-danger"></i> {{ ver.version|default:"-" }}
{% else %}
<i class="fas fa-check pf-m-success"></i> {{ ver.version }}
{% endif %}
{% endwith %}
</span>
</td>
<td> <td>
<a class="pf-c-button pf-m-secondary" href="{% url 'passbook_admin:outpost-update' pk=outpost.pk %}?back={{ request.get_full_path }}">{% trans 'Edit' %}</a> <a class="pf-c-button pf-m-secondary" href="{% url 'passbook_admin:outpost-update' pk=outpost.pk %}?back={{ request.get_full_path }}">{% trans 'Edit' %}</a>
<a class="pf-c-button pf-m-danger" href="{% url 'passbook_admin:outpost-delete' pk=outpost.pk %}?back={{ request.get_full_path }}">{% trans 'Delete' %}</a> <a class="pf-c-button pf-m-danger" href="{% url 'passbook_admin:outpost-delete' pk=outpost.pk %}?back={{ request.get_full_path }}">{% trans 'Delete' %}</a>

View File

@ -83,7 +83,11 @@ class OutpostConsumer(JsonWebsocketConsumer):
def receive_json(self, content: Data): def receive_json(self, content: Data):
msg = from_dict(WebsocketMessage, content) msg = from_dict(WebsocketMessage, content)
if msg.instruction == WebsocketMessageInstruction.HELLO: if msg.instruction == WebsocketMessageInstruction.HELLO:
cache.set(self.outpost.health_cache_key, time(), timeout=60) cache.set(self.outpost.state_cache_prefix("health"), time(), timeout=60)
if "version" in msg.args:
cache.set(
self.outpost.state_cache_prefix("version"), msg.args["version"]
)
elif msg.instruction == WebsocketMessageInstruction.ACK: elif msg.instruction == WebsocketMessageInstruction.ACK:
return return

View File

@ -1,7 +1,7 @@
"""Outpost models""" """Outpost models"""
from dataclasses import asdict, dataclass from dataclasses import asdict, dataclass
from datetime import datetime from datetime import datetime
from typing import Iterable, Optional from typing import Any, Dict, Iterable, Optional
from uuid import uuid4 from uuid import uuid4
from dacite import from_dict from dacite import from_dict
@ -10,14 +10,19 @@ from django.core.cache import cache
from django.db import models, transaction from django.db import models, transaction
from django.db.models.base import Model from django.db.models.base import Model
from django.http import HttpRequest from django.http import HttpRequest
from django.utils import version
from django.utils.translation import gettext_lazy as _ from django.utils.translation import gettext_lazy as _
from guardian.models import UserObjectPermission from guardian.models import UserObjectPermission
from guardian.shortcuts import assign_perm from guardian.shortcuts import assign_perm
from packaging.version import InvalidVersion, parse
from passbook import __version__
from passbook.core.models import Provider, Token, TokenIntents, User from passbook.core.models import Provider, Token, TokenIntents, User
from passbook.lib.config import CONFIG from passbook.lib.config import CONFIG
from passbook.lib.utils.template import render_to_string from passbook.lib.utils.template import render_to_string
OUR_VERSION = parse(__version__)
@dataclass @dataclass
class OutpostConfig: class OutpostConfig:
@ -93,20 +98,33 @@ class Outpost(models.Model):
"""Dump config into json""" """Dump config into json"""
self._config = asdict(value) self._config = asdict(value)
@property def state_cache_prefix(self, suffix: str) -> str:
def health_cache_key(self) -> str: """Key by which the outposts status is saved"""
"""Key by which the outposts health status is saved""" return f"outpost_{self.uuid.hex}_state_{suffix}"
return f"outpost_{self.uuid.hex}_health"
@property @property
def health(self) -> Optional[datetime]: def deployment_health(self) -> Optional[datetime]:
"""Get outpost's health status""" """Get outpost's health status"""
key = self.health_cache_key key = self.state_cache_prefix("health")
value = cache.get(key, None) value = cache.get(key, None)
if value: if value:
return datetime.fromtimestamp(value) return datetime.fromtimestamp(value)
return None return None
@property
def deployment_version(self) -> Dict[str, Any]:
"""Get deployed outposts version, and if the version is behind ours.
Returns a dict with keys version and outdated."""
key = self.state_cache_prefix("version")
value = cache.get(key, None)
if not value:
return {"version": "", "outdated": False}
try:
outpost_version = parse(value)
return {"version": value, "outdated": outpost_version < OUR_VERSION}
except InvalidVersion:
return {"version": version, "outdated": False}
@property @property
def user(self) -> User: def user(self) -> User:
"""Get/create user with access to all required objects""" """Get/create user with access to all required objects"""