1
0
mirror of https://github.com/netbox-community/netbox.git synced 2024-05-10 07:54:54 +00:00

Introduced TopologyMap

This commit is contained in:
Jeremy Stretch
2016-04-08 14:57:54 -04:00
parent 42e16db8b4
commit 29fd04026d
7 changed files with 94 additions and 11 deletions

View File

@@ -1,6 +1,6 @@
from django.contrib import admin
from .models import Graph, ExportTemplate
from .models import Graph, ExportTemplate, TopologyMap
@admin.register(Graph)
@@ -11,3 +11,11 @@ class GraphAdmin(admin.ModelAdmin):
@admin.register(ExportTemplate)
class ExportTemplateAdmin(admin.ModelAdmin):
list_display = ['content_type', 'name', 'mime_type', 'file_extension']
@admin.register(TopologyMap)
class TopologyMapAdmin(admin.ModelAdmin):
list_display = ['name', 'slug', 'site']
prepopulated_fields = {
'slug': ['name'],
}

View File

@@ -10,7 +10,7 @@ from django.shortcuts import get_object_or_404
from circuits.models import Provider
from dcim.models import Site, Device, Interface, InterfaceConnection
from extras.models import Graph, GRAPH_TYPE_INTERFACE, GRAPH_TYPE_PROVIDER, GRAPH_TYPE_SITE
from extras.models import Graph, TopologyMap, GRAPH_TYPE_INTERFACE, GRAPH_TYPE_PROVIDER, GRAPH_TYPE_SITE
from .serializers import GraphSerializer
@@ -38,24 +38,23 @@ class GraphListView(generics.ListAPIView):
return queryset
class TopologyMapperView(APIView):
class TopologyMapView(APIView):
"""
Generate a topology diagram
"""
def get(self, request):
def get(self, request, slug):
# Glean device sets to map. Each set is represented as a hierarchical tier in the diagram.
device_sets = request.GET.getlist('devices', [])
tmap = get_object_or_404(TopologyMap, slug=slug)
# Construct the graph
graph = pydot.Dot(graph_type='graph', ranksep='1')
for i, device_set in enumerate(device_sets):
for i, device_set in enumerate(tmap.device_sets):
subgraph = pydot.Subgraph('sg{}'.format(i), rank='same')
# Add a pseudonode for each device_set to enforce hierarchical layout
subgraph.add_node(pydot.Node('set{}'.format(i), shape='none'))
subgraph.add_node(pydot.Node('set{}'.format(i), shape='none', width='0', label=''))
if i:
graph.add_edge(pydot.Edge('set{}'.format(i - 1), 'set{}'.format(i), style='invis'))
@@ -76,7 +75,7 @@ class TopologyMapperView(APIView):
# Compile list of all devices
device_superset = Q()
for regex in device_sets:
for regex in tmap.device_sets:
device_superset = device_superset | Q(name__regex=regex)
# Add all connections to the graph

View File

@@ -0,0 +1,31 @@
# -*- coding: utf-8 -*-
# Generated by Django 1.9.1 on 2016-04-08 18:53
from __future__ import unicode_literals
from django.db import migrations, models
import django.db.models.deletion
class Migration(migrations.Migration):
dependencies = [
('dcim', '0005_auto_20160328_2135'),
('extras', '0001_initial'),
]
operations = [
migrations.CreateModel(
name='TopologyMap',
fields=[
('id', models.AutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')),
('name', models.CharField(max_length=50, unique=True)),
('slug', models.SlugField(unique=True)),
('device_patterns', models.TextField()),
('description', models.CharField(blank=True, max_length=100)),
('site', models.ForeignKey(blank=True, null=True, on_delete=django.db.models.deletion.CASCADE, related_name='topology_maps', to='dcim.Site')),
],
options={
'ordering': ['name'],
},
),
]

View File

@@ -4,6 +4,9 @@ from django.http import HttpResponse
from django.template import Template, Context
from dcim.models import Site
GRAPH_TYPE_INTERFACE = 100
GRAPH_TYPE_PROVIDER = 200
GRAPH_TYPE_SITE = 300
@@ -68,3 +71,23 @@ class ExportTemplate(models.Model):
filename += '.{}'.format(self.file_extension)
response['Content-Disposition'] = 'attachment; filename="{}"'.format(filename)
return response
class TopologyMap(models.Model):
name = models.CharField(max_length=50, unique=True)
slug = models.SlugField(unique=True)
site = models.ForeignKey(Site, related_name='topology_maps', blank=True, null=True)
device_patterns = models.TextField()
description = models.CharField(max_length=100, blank=True)
class Meta:
ordering = ['name']
def __unicode__(self):
return self.name
@property
def device_sets(self):
if not self.device_patterns:
return None
return [line.strip() for line in self.device_patterns.split('\n')]