Commit 709099f7 authored by Élie Bouttier's avatar Élie Bouttier
Browse files

ip resources states history

parent 2c1c2734
Loading
Loading
Loading
Loading
+51 −28
Original line number Diff line number Diff line
@@ -26,9 +26,9 @@ from datetime import timedelta
from djadhere.utils import get_active_filter
from adhesions.models import Adhesion
from banking.models import PaymentUpdate
from .models import Service, ServiceType, IPPrefix, IPResource, Route, Tunnel, \
from .models import Service, ServiceType, IPPrefix, IPResource, IPResourceState, \
                    ServiceAllocation, Antenna, AntennaAllocation, Allocation, \
                    Switch, Port
                    Route, Tunnel, Switch, Port
from .utils.notifications import notify_allocation
from .forms import AntennaForm

@@ -67,13 +67,15 @@ class ResourcePingFilter(admin.SimpleListFilter):

    def queryset(self, request, queryset):
        if self.value() == 'up':
            return queryset.filter(up=True)
            return queryset.filter(last_state__state=IPResourceState.STATE_UP)
        if self.value() == 'down':
            return queryset.filter(models.Q(up__isnull=True) | models.Q(up=False))
            return queryset.exclude(last_state__state=IPResourceState.STATE_UP) # DOWN + UNKNOWN
        if self.value() == 'down-since':
            return queryset.filter(up=False)
            queryset = queryset.exclude(last_state__state=IPResourceState.STATE_UP)
            return queryset.filter(last_time_up__isnull=False)
        if self.value() == 'never-up':
            return queryset.filter(up__isnull=True)
            queryset = queryset.exclude(last_state__state=IPResourceState.STATE_UP) # DOWN + UNKWON
            return queryset.filter(last_time_up__isnull=True)


class ActiveServiceFilter(admin.SimpleListFilter):
@@ -265,6 +267,22 @@ class InactiveAntennaAllocationInline(AntennaAllocationMixin, InactiveAllocation
    pass


class IPResourceStateInline(admin.TabularInline):
    model = IPResourceState
    verbose_name_plural = 'Historique des changements d’état'
    fields = ['date']
    ordering = ['-date']

    def has_add_permission(self, request):
        return False

    def has_change_permission(self, request, obj):
        return False

    def has_delete_permission(self, request, obj=None):
        return False


class PortInline(admin.TabularInline):
    model = Port
    max_num = 0
@@ -385,27 +403,32 @@ class IPResourceAdmin(admin.ModelAdmin):
    )
    search_fields = ('=ip', 'notes',)
    actions = ['contact_ip_owners']
    ordering = ['ip']
    inlines = [ IPResourceStateInline ]

    def get_fields(self, request, obj=None):
        return self.get_readonly_fields(request, obj)

    def get_readonly_fields(self, request, obj=None):
        fields = ['ip']
        if obj and obj.reserved:
        if obj:
            if obj.reserved:
                fields += ['reserved']
        if obj and not obj.in_use:
            if not obj.in_use:
                fields += ['last_use']
        if obj and obj.last_time_up and obj.last_check:
            fields += ['last_time_up', 'last_check']
            fields += ['last_state']
            if obj.last_state.state != IPResourceState.STATE_UP:
                fields += ['last_time_up']
            if obj.category == IPResource.CATEGORY_PUBLIC:
                fields += ['password']
        if obj and obj.checkmk_label:
            if obj.checkmk_label:
                fields += ['checkmk']
        if obj and obj.notes:
            if obj.notes:
                fields += ['notes']
        return fields

    def get_inline_instances(self, request, obj=None):
        super_inlines = super().get_inline_instances(request, obj)
        if obj:
            if obj.category == 0:
                inlines = (ActiveServiceAllocationInline, InactiveServiceAllocationInline,)
@@ -413,7 +436,7 @@ class IPResourceAdmin(admin.ModelAdmin):
                inlines = (ActiveAntennaAllocationInline, InactiveAntennaAllocationInline,)
        else:
            inlines = ()
        return [inline(self.model, self.admin_site) for inline in inlines]
        return [inline(self.model, self.admin_site) for inline in inlines] + super_inlines

    def get_queryset(self, request):
        qs = super().get_queryset(request)
@@ -426,13 +449,12 @@ class IPResourceAdmin(admin.ModelAdmin):
                    default=None,
                ))
        qs = qs.annotate(
                up=models.Case(
                    models.When(last_check__isnull=False, last_time_up__isnull=False, last_time_up=models.F('last_check'), then=True),
                    models.When(last_check__isnull=False, last_time_up__isnull=False, then=False),
                downtime=models.Case(
                    models.When(last_state__state=IPResourceState.STATE_UP, then=models.F('last_state__date')-models.Value(now)),
                    models.When(last_state__state=IPResourceState.STATE_DOWN, then=models.Value(now)-models.F('last_time_up')),
                    default=None,
                    output_field=models.NullBooleanField(),
                    output_field=models.DurationField(),
                ))
        qs = qs.annotate(downtime=models.F('last_check') - models.F('last_time_up'))
        qs = qs.annotate(
                route=models.Case(
                    models.When(
@@ -461,9 +483,10 @@ class IPResourceAdmin(admin.ModelAdmin):
    last_use.admin_order_field = 'last_use'

    def ping(self, obj):
        if obj.up:
        if obj.last_state.state == IPResourceState.STATE_UP:
            label = 'UP'
        elif obj.last_time_up:
        else:
            if obj.last_time_up:
                label = 'dernier ping : ' + naturaltime(obj.last_time_up)
            else:
                label = 'DOWN'
+28 −0
Original line number Diff line number Diff line
# Generated by Django 2.1.1 on 2019-02-19 20:46

from django.db import migrations, models
from django.utils import timezone


class Migration(migrations.Migration):

    dependencies = [
        ('services', '0051_auto_20180602_1346'),
    ]

    operations = [
        migrations.CreateModel(
            name='IPResourceState',
            fields=[
                ('id', models.AutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')),
                ('date', models.DateTimeField(default=timezone.now)),
                ('state', models.IntegerField(choices=[(0, 'DOWN'), (1, 'UP'), (2, 'Inconnu')])),
                ('ip', models.ForeignKey(on_delete=models.deletion.CASCADE, related_name='state_set', to='services.IPResource')),
            ],
        ),
        migrations.AddField(
            model_name='ipresource',
            name='last_state',
            field=models.ForeignKey(null=True, on_delete=models.deletion.PROTECT, to='services.IPResourceState', related_name='+'),
        ),
    ]
+51 −0
Original line number Diff line number Diff line
# Generated by Django 2.1.1 on 2019-02-19 20:47

from django.db import migrations
from django.utils import timezone

from datetime import timedelta


def forward(apps, schema_editor):
    db_alias = schema_editor.connection.alias
    IPResource = apps.get_model('services', 'IPResource')
    IPResourceState = apps.get_model('services', 'IPResourceState')
    now = timezone.now()
    for ip in IPResource.objects.all():
        if ip.last_check:
            if ip.last_time_up:
                if ip.last_check == ip.last_time_up: # UP
                    ip.last_state = IPResourceState.objects.create(ip=ip, date=ip.last_time_up, state=1) # UP
                    ip.save()
                else: # DOWN but UP some time before
                    ip.last_state = IPResourceState.objects.create(ip=ip, date=ip.last_time_up, state=0) # DOWN
                    ip.save()
            else: # Always DOWN
                ip.last_state = IPResourceState.objects.create(ip=ip, date=ip.last_check, state=0) # DOWN
                ip.save()
        else:
            ip.last_state = IPResourceState.objects.create(ip=ip, date=now, state=2) # UNKNOWN
            ip.save()


def backward(apps, schema_editor):
    db_alias = schema_editor.connection.alias
    IPResource = apps.get_model('services', 'IPResource')
    IPResourceState = apps.get_model('services', 'IPResourceState')
    for ip in IPResource.objects.all():
        if ip.last_state.state != 2:
            ip.last_check = ip.last_state.date
            if ip.last_state.state == 1:
                ip.last_time_up = ip.last_check
            ip.save()


class Migration(migrations.Migration):

    dependencies = [
        ('services', '0052_auto_20190219_2146'),
    ]

    operations = [
		migrations.RunPython(forward, backward)
    ]
+22 −0
Original line number Diff line number Diff line
# Generated by Django 2.1.1 on 2019-02-19 21:06

from django.db import migrations, models


class Migration(migrations.Migration):

    dependencies = [
        ('services', '0053_auto_20190219_2147'),
    ]

    operations = [
        migrations.RemoveField(
            model_name='ipresource',
            name='last_check',
        ),
        migrations.AlterField(
            model_name='ipresource',
            name='last_state',
            field=models.ForeignKey(on_delete=models.deletion.PROTECT, to='services.IPResourceState', related_name='+'),
        ),
    ]
+18 −1
Original line number Diff line number Diff line
@@ -102,8 +102,8 @@ class IPResource(models.Model):
    category = models.IntegerField(choices=CATEGORIES, verbose_name='catégorie')
    notes = models.TextField(blank=True, default='')
    checkmk_label = models.CharField(max_length=128, blank=True, default='')
    last_state = models.ForeignKey("IPResourceState", on_delete=models.PROTECT, related_name='+', verbose_name='dernier état')
    last_time_up = models.DateTimeField(null=True, blank=True, verbose_name='Dernière réponse au ping')
    last_check = models.DateTimeField(null=True, blank=True, verbose_name='Dernier contrôle')

    objects = IPResourceManager()

@@ -135,6 +135,23 @@ class IPResource(models.Model):
        return str(self.ip)


class IPResourceState(models.Model):
    STATE_DOWN = 0
    STATE_UP = 1
    STATE_UNKNOWN = 2
    STATE_CHOICES = (
        (STATE_DOWN, 'DOWN'),
        (STATE_UP, 'UP'),
        (STATE_UNKNOWN, 'Inconnu'),
    )
    ip = models.ForeignKey(IPResource, on_delete=models.CASCADE, related_name='state_set')
    date = models.DateTimeField(default=timezone.now)
    state = models.IntegerField(choices=STATE_CHOICES)

    def __str__(self):
        return self.get_state_display()


class ServiceType(models.Model):
    name = models.CharField(max_length=64, verbose_name='Nom', unique=True)
    contact = models.CharField(max_length=64, verbose_name='Contact en cas de problème', blank=True, default='')
Loading