diff --git a/django_netjsongraph/api/generics.py b/django_netjsongraph/api/generics.py index 31a33a0..7fae835 100644 --- a/django_netjsongraph/api/generics.py +++ b/django_netjsongraph/api/generics.py @@ -37,7 +37,10 @@ class BaseNetworkGraphHistoryView(APIView): def get(self, request, pk, format=None): topology = get_object_or_404(self.topology_model, pk) date = request.query_params.get('date') - options = dict(topology=topology, date=date) + kind = request.query_params.get('kind') + if not kind: + kind = "normal" + options = dict(topology=topology, date=date, kind=kind) # missing date: 400 if not date: return Response({'detail': _('missing required "date" parameter')}, diff --git a/django_netjsongraph/base/snapshot.py b/django_netjsongraph/base/snapshot.py index 2792ed0..aca79fc 100644 --- a/django_netjsongraph/base/snapshot.py +++ b/django_netjsongraph/base/snapshot.py @@ -2,6 +2,7 @@ from django.utils.translation import ugettext_lazy as _ from .base import TimeStampedEditableModel +from .topology import SNAPSHOT_KINDS class AbstractSnapshot(TimeStampedEditableModel): @@ -11,6 +12,11 @@ class AbstractSnapshot(TimeStampedEditableModel): topology = models.ForeignKey('django_netjsongraph.topology') data = models.TextField(blank=False) date = models.DateField(auto_now=True) + kind = models.CharField(_('kind'), + max_length=16, + choices=SNAPSHOT_KINDS, + default=SNAPSHOT_KINDS[0], + db_index=True) class Meta: verbose_name_plural = _('snapshots') diff --git a/django_netjsongraph/base/topology.py b/django_netjsongraph/base/topology.py index 802e2e5..e07649c 100644 --- a/django_netjsongraph/base/topology.py +++ b/django_netjsongraph/base/topology.py @@ -12,6 +12,9 @@ from django.utils.translation import ugettext_lazy as _ from netdiff import NetJsonParser, diff from rest_framework.utils.encoders import JSONEncoder +from netdiff.utils import _netjson_networkgraph as to_netjson +from netjson_robustness.analyser import ParsedGraph + from ..contextmanagers import log_failure from ..settings import PARSERS, TIMEOUT @@ -23,6 +26,13 @@ ('receive', _('RECEIVE')) ) +# TODO export these in the configuration +# First element is default +SNAPSHOT_KINDS = ( + ('normal', _('NORMAL')), + ('block_cut_tree', _('BLOCK_CUT_TREE')) +) + @python_2_unicode_compatible class AbstractTopology(TimeStampedEditableModel): @@ -254,16 +264,34 @@ def save_snapshot(self, **kwargs): """ Saves the snapshot of topology """ - Snapshot = self.snapshot_model - date = datetime.now().date() - options = dict(topology=self, date=date) - options.update(kwargs) - try: - s = Snapshot.objects.get(**options) - except: - s = Snapshot(**options) - s.data = self.json() - s.save() + for kind in SNAPSHOT_KINDS: + Snapshot = self.snapshot_model + date = datetime.now().date() + options = dict(topology=self, date=date, kind=kind[0]) + options.update(kwargs) + try: + s = Snapshot.objects.get(**options) + except: + s = Snapshot(**options) + + if kind[0] == "block_cut_tree": + s.data = self.compute_cut_block_tree() + elif kind[0] == "normal": + s.data = self.json() + s.save() + + def compute_cut_block_tree(self): + """ + transform a given topology in a cut-block tree for better + visualization of the critical nodes + """ + netjson = NetJsonParser(self.json(dict=True, omit_down=True)) + p = ParsedGraph(netjson) + p.condensate_graph() + return json.dumps(to_netjson(p.netJSON.protocol, p.netJSON.version, + p.netJSON.revision, p.netJSON.metric, + p.condensed_graph.nodes(data=True), + p.condensed_graph.edges(data=True), dict=True)) def link_status_changed(self, link, status): """ diff --git a/django_netjsongraph/static/netjsongraph/js/topology-history.js b/django_netjsongraph/static/netjsongraph/js/topology-history.js index 2dcf2d9..a30539b 100644 --- a/django_netjsongraph/static/netjsongraph/js/topology-history.js +++ b/django_netjsongraph/static/netjsongraph/js/topology-history.js @@ -2,16 +2,22 @@ window.initTopologyHistory = function($){ var datepicker = $('#njg-datepicker'), today = new Date(), apiUrl = datepicker.attr('data-history-api'); + var kindpicker=$("input[name='visualization_kind']"); + var kind = 'normal'; + kindpicker.change(function() {; + kind = this.value + }); today.setHours(0, 0, 0, 0); datepicker.datepicker({dateFormat: 'dd/mm/yy'}); datepicker.datepicker('setDate', today); datepicker.change(function() {; var date = datepicker.val().split('/').reverse().join('-'), - url = apiUrl + '?date=' + date; + url = apiUrl + '?kind=' + kind + '&date=' + date; // load latest data when looking currentDate if(datepicker.datepicker('getDate').getTime() == today.getTime()){ url = window.__njg_default_url__; } + // load latest data when looking currentDate $.getJSON(url).done(function(data){ window.graph = window.loadNetJsonGraph(data); }).error(function(xhr){ diff --git a/django_netjsongraph/templates/netjsongraph/netjsongraph-content.html b/django_netjsongraph/templates/netjsongraph/netjsongraph-content.html index d94cd52..cfe4855 100644 --- a/django_netjsongraph/templates/netjsongraph/netjsongraph-content.html +++ b/django_netjsongraph/templates/netjsongraph/netjsongraph-content.html @@ -4,7 +4,13 @@

  {% trans 'link down' %}

+
+ Choose Visualization + data-history-api="{{ history_url }}">
+
+
+
+