add machines
This commit is contained in:
parent
f19e04c962
commit
6310c2f878
7 changed files with 121 additions and 19 deletions
|
@ -1,7 +1,7 @@
|
|||
from django.contrib import admin
|
||||
from ordered_model.admin import OrderedModelAdmin
|
||||
|
||||
from sdbs_infra.dashboard.models import Service, Link
|
||||
from sdbs_infra.dashboard.models import Service, Link, Machine
|
||||
|
||||
|
||||
class LinkAdmin(OrderedModelAdmin):
|
||||
|
@ -12,5 +12,10 @@ class ServiceAdmin(OrderedModelAdmin):
|
|||
list_display = ('short_name', 'url', 'move_up_down_links')
|
||||
|
||||
|
||||
class MachineAdmin(OrderedModelAdmin):
|
||||
list_display = ('short_name', 'move_up_down_links')
|
||||
|
||||
|
||||
admin.site.register(Link, LinkAdmin)
|
||||
admin.site.register(Service, ServiceAdmin)
|
||||
admin.site.register(Machine, MachineAdmin)
|
||||
|
|
|
@ -0,0 +1,31 @@
|
|||
# Generated by Django 3.0.7 on 2020-07-15 01:51
|
||||
|
||||
from django.db import migrations, models
|
||||
|
||||
|
||||
class Migration(migrations.Migration):
|
||||
|
||||
replaces = [('dashboard', '0009_machine'), ('dashboard', '0010_auto_20200715_0344'), ('dashboard', '0011_machine_url'), ('dashboard', '0012_auto_20200715_0350')]
|
||||
|
||||
dependencies = [
|
||||
('dashboard', '0008_auto_20200620_1952'),
|
||||
]
|
||||
|
||||
operations = [
|
||||
migrations.CreateModel(
|
||||
name='Machine',
|
||||
fields=[
|
||||
('id', models.AutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')),
|
||||
('order', models.PositiveIntegerField(db_index=True, editable=False, verbose_name='order')),
|
||||
('short_name', models.CharField(max_length=64)),
|
||||
('image', models.ImageField(blank=True, null=True, upload_to='machines')),
|
||||
('description', models.TextField(blank=True, null=True)),
|
||||
('healthcheck_id', models.CharField(blank=True, max_length=36, null=True)),
|
||||
('url', models.URLField(blank=True, null=True)),
|
||||
],
|
||||
options={
|
||||
'ordering': ('order',),
|
||||
'abstract': False,
|
||||
},
|
||||
),
|
||||
]
|
|
@ -4,7 +4,7 @@ from django.db import models
|
|||
from ordered_model.models import OrderedModel
|
||||
|
||||
|
||||
class ServiceStatus(Enum):
|
||||
class Status(Enum):
|
||||
OK = 'ok'
|
||||
DOWN = 'down'
|
||||
UNKNOWN = 'unknown'
|
||||
|
@ -33,3 +33,14 @@ class Link(OrderedModel):
|
|||
class Meta(OrderedModel.Meta):
|
||||
verbose_name = "Important Link"
|
||||
verbose_name_plural = "Important Links"
|
||||
|
||||
|
||||
class Machine(OrderedModel):
|
||||
short_name = models.CharField(null=False, max_length=64)
|
||||
image = models.ImageField(null=True, blank=True, upload_to='machines')
|
||||
description = models.TextField(null=True, blank=True)
|
||||
url = models.URLField(null=True, blank=True)
|
||||
healthcheck_id = models.CharField(null=True, blank=True, max_length=36)
|
||||
|
||||
def __str__(self):
|
||||
return f"{self.short_name}"
|
||||
|
|
|
@ -70,7 +70,9 @@ h2 {
|
|||
padding: 2rem;
|
||||
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
align-items: center;
|
||||
justify-content: flex-end;
|
||||
}
|
||||
|
||||
.link .box-content {
|
||||
|
@ -78,18 +80,13 @@ h2 {
|
|||
justify-content: space-evenly;
|
||||
}
|
||||
|
||||
.service .box-content {
|
||||
flex-direction: column;
|
||||
justify-content: flex-end;
|
||||
}
|
||||
|
||||
.box-content img {
|
||||
filter: grayscale(100%);
|
||||
image-rendering: crisp-edges;
|
||||
text-align: center;
|
||||
}
|
||||
|
||||
.service img {
|
||||
.machine img, .service img {
|
||||
min-width: 50%;
|
||||
max-width: 100%;
|
||||
}
|
||||
|
@ -99,7 +96,7 @@ h2 {
|
|||
max-height: 4rem;
|
||||
}
|
||||
|
||||
.service .label h3 {
|
||||
.label h3 {
|
||||
margin: 1rem 0;
|
||||
text-align: center;
|
||||
}
|
||||
|
@ -118,7 +115,7 @@ h2 {
|
|||
align-self: flex-start;
|
||||
}
|
||||
|
||||
.service-status {
|
||||
.status {
|
||||
border: 1px solid white;
|
||||
border-top: 0;
|
||||
text-transform: uppercase;
|
||||
|
@ -126,15 +123,15 @@ h2 {
|
|||
padding: .25em .5em;
|
||||
}
|
||||
|
||||
.status-ok .service-status {
|
||||
.status-ok .status {
|
||||
color: gray;
|
||||
}
|
||||
|
||||
.status-down .service-status {
|
||||
.status-down .status {
|
||||
color: darkred;
|
||||
}
|
||||
|
||||
.status-unknown .service-status {
|
||||
.status-unknown .status {
|
||||
color: darkorange;
|
||||
}
|
||||
|
||||
|
|
|
@ -44,12 +44,33 @@
|
|||
{% endif %}
|
||||
</div>
|
||||
</section>
|
||||
<section class="service-status">
|
||||
<section class="status">
|
||||
STATUS: {{ service.status }}
|
||||
</section>
|
||||
</a>
|
||||
{% endfor %}
|
||||
</section>
|
||||
<h2>machines</h2>
|
||||
<section class="machines boxes">
|
||||
{% for machine in machines %}
|
||||
<a class="machine box status-{{ machine.status }}" href="{{ machine.url|default:"#" }}">
|
||||
<section class="box-content">
|
||||
{% if machine.image_url %}
|
||||
<img src="{{ machine.image_url }}" alt="image for {{ machine.short_name }}"/>
|
||||
{% endif %}
|
||||
<div class="label">
|
||||
<h3>{{ machine.short_name }}</h3>
|
||||
{% if machine.description %}
|
||||
<p class="description">{{ machine.description }}</p>
|
||||
{% endif %}
|
||||
</div>
|
||||
</section>
|
||||
<section class="status" title="Last ping at: {{ machine.last_ping|default:"UNKNOWN" }}">
|
||||
STATUS: {{ machine.status }}
|
||||
</section>
|
||||
</a>
|
||||
{% endfor %}
|
||||
</section>
|
||||
<section class="stats">
|
||||
VPS STATS — {{ vps_stats|safe }}
|
||||
</section>
|
||||
|
|
|
@ -2,6 +2,7 @@ import asyncio
|
|||
import socket
|
||||
import time
|
||||
from collections import namedtuple
|
||||
from datetime import datetime
|
||||
from urllib.parse import urlparse
|
||||
|
||||
import aiohttp
|
||||
|
@ -11,7 +12,8 @@ from bs4 import BeautifulSoup
|
|||
from django.views.generic import TemplateView
|
||||
from humanize import naturalsize
|
||||
|
||||
from sdbs_infra.dashboard.models import Service, ServiceStatus, Link
|
||||
from sdbs_infra import settings
|
||||
from sdbs_infra.dashboard.models import Service, Status, Link, Machine
|
||||
|
||||
|
||||
class IndexView(TemplateView):
|
||||
|
@ -22,6 +24,7 @@ class IndexView(TemplateView):
|
|||
return {
|
||||
'links': asyncio.run(self.process_links(list(Link.objects.all()))),
|
||||
'services': asyncio.run(self.process_services(list(Service.objects.all()))),
|
||||
'machines': asyncio.run(self.process_machines(list(Machine.objects.all()))),
|
||||
'vps_stats': self.vps_stats()
|
||||
}
|
||||
|
||||
|
@ -68,13 +71,13 @@ class IndexView(TemplateView):
|
|||
location = ("localhost", service.port)
|
||||
result_of_check = a_socket.connect_ex(location)
|
||||
if result_of_check == 0:
|
||||
status = ServiceStatus.OK
|
||||
status = Status.OK
|
||||
else:
|
||||
status = ServiceStatus.DOWN
|
||||
status = Status.DOWN
|
||||
elif index_status:
|
||||
status = ServiceStatus.OK if index_status == 200 else ServiceStatus.DOWN
|
||||
status = Status.OK if index_status == 200 else Status.DOWN
|
||||
else:
|
||||
status = ServiceStatus.UNKNOWN
|
||||
status = Status.UNKNOWN
|
||||
|
||||
image = service.image.url if service.image else self.extract_favicon(service.url, index_text)
|
||||
|
||||
|
@ -87,6 +90,38 @@ class IndexView(TemplateView):
|
|||
await session.close()
|
||||
return result
|
||||
|
||||
async def process_machines(self, machines):
|
||||
result = []
|
||||
|
||||
session = aiohttp.ClientSession(timeout=aiohttp.ClientTimeout(total=5, sock_connect=1), headers={
|
||||
'X-Api-Key': settings.HEALTCHECKS_API_KEY
|
||||
})
|
||||
|
||||
for machine in machines:
|
||||
status = Status.UNKNOWN
|
||||
last_ping = None
|
||||
|
||||
if settings.HEALTCHECKS_API_KEY and machine.healthcheck_id:
|
||||
try:
|
||||
async with session.get(
|
||||
f"https://healthchecks.io/api/v1/checks/{machine.healthcheck_id}") as response:
|
||||
check = await response.json()
|
||||
status = {
|
||||
'up': Status.OK,
|
||||
'down': Status.DOWN
|
||||
}.get(check.get('status'), Status.UNKNOWN)
|
||||
last_ping = datetime.fromisoformat(check.get('last_ping'))
|
||||
except (asyncio.TimeoutError, ClientConnectorError):
|
||||
pass
|
||||
|
||||
result.append({
|
||||
'status': status.value,
|
||||
'last_ping': last_ping,
|
||||
**vars(machine)
|
||||
})
|
||||
|
||||
return result
|
||||
|
||||
@staticmethod
|
||||
def extract_favicon(url, index_text):
|
||||
if not index_text:
|
||||
|
|
|
@ -128,3 +128,5 @@ STATIC_ROOT = os.path.join(BASE_DIR, "static")
|
|||
|
||||
MEDIA_URL = '/media/'
|
||||
MEDIA_ROOT = os.path.join(BASE_DIR, "media")
|
||||
|
||||
HEALTCHECKS_API_KEY = os.getenv("HEALTHCHECKS_API_KEY")
|
||||
|
|
Loading…
Reference in a new issue