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 'Providers' %}</th>
<th role="columnheader" scope="col">{% trans 'Health' %}</th>
<th role="columnheader" scope="col">{% trans 'Version' %}</th>
<th role="cell"></th>
</tr>
</thead>
@ -59,7 +60,7 @@
</span>
</td>
<td role="cell">
{% with health=outpost.health %}
{% with health=outpost.deployment_health %}
{% if health %}
<i class="fas fa-check pf-m-success"></i> {{ health|naturaltime }}
{% else %}
@ -67,6 +68,17 @@
{% endif %}
{% endwith %}
</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>
<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>

View File

@ -83,7 +83,11 @@ class OutpostConsumer(JsonWebsocketConsumer):
def receive_json(self, content: Data):
msg = from_dict(WebsocketMessage, content)
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:
return

View File

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