outposts: add support for version checking
This commit is contained in:
parent
e75c9e9a79
commit
18886697d6
|
@ -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>
|
||||||
|
|
|
@ -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
|
||||||
|
|
||||||
|
|
|
@ -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"""
|
||||||
|
|
Reference in New Issue