Adds toolbox to network UI

* Calls API to get inventory
* Adds CopySite message
* Adds Toolbox and ToolboxItem model design
* Add Toolbox and ToolboxItem tables
* Sends toolbox items to client from server on connect
This commit is contained in:
Ben Thomasson 2017-08-22 23:57:09 +00:00
parent c79ef60d8b
commit 6f1000cd94
No known key found for this signature in database
GPG Key ID: 5818EF4CC895D5F5
10 changed files with 279 additions and 20 deletions

View File

@ -28,6 +28,10 @@ from awx.network_ui.models import Stream
from awx.network_ui.models import Process
from awx.network_ui.models import Toolbox
from awx.network_ui.models import ToolboxItem
class DeviceAdmin(admin.ModelAdmin):
fields = ('topology', 'name', 'x', 'y', 'id', 'type', 'interface_id_seq', 'process_id_seq',)
@ -139,3 +143,19 @@ class ProcessAdmin(admin.ModelAdmin):
admin.site.register(Process, ProcessAdmin)
class ToolboxAdmin(admin.ModelAdmin):
fields = ('name',)
raw_id_fields = ()
admin.site.register(Toolbox, ToolboxAdmin)
class ToolboxItemAdmin(admin.ModelAdmin):
fields = ('toolbox', 'data',)
raw_id_fields = ('toolbox',)
admin.site.register(ToolboxItem, ToolboxItemAdmin)

View File

@ -6,6 +6,7 @@ from awx.network_ui.models import Group as DeviceGroup
from awx.network_ui.models import GroupDevice as GroupDeviceMap
from awx.network_ui.models import DataSheet, DataBinding, DataType
from awx.network_ui.models import Process, Stream
from awx.network_ui.models import Toolbox, ToolboxItem
from awx.network_ui.serializers import yaml_serialize_topology
import urlparse
from django.db.models import Q
@ -382,14 +383,19 @@ class _Persistence(object):
device_map = dict(Device.objects
.filter(topology_id=topology_id, id__in=[stream['from_id'], stream['to_id']])
.values_list('id', 'pk'))
logger.info("onStreamCreate %s", stream)
Stream.objects.get_or_create(id=stream['id'],
label=stream['label'],
label='',
from_device_id=device_map[stream['from_id']],
to_device_id=device_map[stream['to_id']])
(Topology.objects
.filter(topology_id=topology_id, stream_id_seq__lt=stream['id'])
.update(stream_id_seq=stream['id']))
def onCopySite(self, site, topology_id, client_id):
site_toolbox, _ = Toolbox.objects.get_or_create(name="Site")
ToolboxItem(toolbox=site_toolbox, data=json.dumps(site['site'])).save()
def onDeviceSelected(self, message_value, topology_id, client_id):
'Ignore DeviceSelected messages'
pass
@ -460,6 +466,7 @@ class _Persistence(object):
onKeyEvent = write_event
def onGroupCreate(self, group, topology_id, client_id):
logger.info("GroupCreate %s %s %s", group['id'], group['name'], group['type'])
group = transform_dict(dict(x1='x1',
y1='y1',
x2='x2',
@ -775,6 +782,14 @@ def ws_connect(message):
message.reply_channel.send({"text": json.dumps(["Topology", topology_data])})
send_snapshot(message.reply_channel, topology_id)
send_history(message.reply_channel, topology_id)
send_toolboxes(message.reply_channel)
def send_toolboxes(channel):
for toolbox_item in ToolboxItem.objects.filter(toolbox__name__in=['Process', 'Device', 'Rack', 'Site']).values('toolbox__name', 'data'):
item = dict(toolbox_name=toolbox_item['toolbox__name'],
data=toolbox_item['data'])
channel.send({"text": json.dumps(["ToolboxItem", item])})
def send_snapshot(channel, topology_id):
@ -921,7 +936,10 @@ def make_sheet(data, column_headers=[]):
sheet = []
n_columns = max([len(x) for x in data]) - 1
if len(data):
n_columns = max([len(x) for x in data]) - 1
else:
n_columns = 0
row_i = 0
sheet.append([dict(value=x, editable=False) for x in list("ABCDEFGHIJKLMNOPQRSTUVWXYZ")[0:n_columns]])

View File

@ -297,6 +297,29 @@ models:
name: Process
x: 654
y: 778
- fields:
- name: toolbox_id
pk: true
type: AutoField
- len: 200
name: name
type: CharField
name: Toolbox
x: -222
y: 627
- fields:
- name: toolbox_item_id
pk: true
type: AutoField
- name: toolbox
ref: Toolbox
ref_field: toolbox_id
type: ForeignKey
- name: data
type: TextField
name: ToolboxItem
x: 54
y: 664
modules: []
view:
panX: 213.72955551921206

View File

@ -0,0 +1,29 @@
# -*- coding: utf-8 -*-
from __future__ import unicode_literals
from django.db import migrations, models
class Migration(migrations.Migration):
dependencies = [
('network_ui', '0020_device_process_id_seq'),
]
operations = [
migrations.CreateModel(
name='Toolbox',
fields=[
('toolbox_id', models.AutoField(serialize=False, primary_key=True)),
('name', models.CharField(max_length=200)),
],
),
migrations.CreateModel(
name='ToolboxItem',
fields=[
('toolbox_item_id', models.AutoField(serialize=False, primary_key=True)),
('data', models.TextField()),
('toolbox', models.ForeignKey(to='network_ui.Toolbox')),
],
),
]

View File

@ -142,3 +142,16 @@ class Process(models.Model):
name = models.CharField(max_length=200,)
type = models.CharField(max_length=200,)
id = models.IntegerField(default=0)
class Toolbox(models.Model):
toolbox_id = models.AutoField(primary_key=True,)
name = models.CharField(max_length=200,)
class ToolboxItem(models.Model):
toolbox_item_id = models.AutoField(primary_key=True,)
toolbox = models.ForeignKey('Toolbox',)
data = models.TextField()

View File

@ -278,6 +278,12 @@ function PasteSite(group) {
}
exports.PasteSite = PasteSite;
function CopySite(site) {
this.msg_type = "CopySite";
this.site = site;
}
exports.CopySite = CopySite;
function GroupMove(sender, id, x1, y1, x2, y2, previous_x1, previous_y1, previous_x2, previous_y2) {
this.msg_type = "GroupMove";

View File

@ -28,6 +28,16 @@ function Device(id, name, x, y, type) {
}
exports.Device = Device;
Device.prototype.toJSON = function () {
return {id: this.id,
name: this.name,
x: this.x,
y: this.y,
type: this.type,
interfaces: this.interfaces,
processes: this.processes};
};
Device.prototype.is_selected = function (x, y) {
return (x > this.x - this.width &&
@ -51,6 +61,12 @@ function Interface(id, name) {
}
exports.Interface = Interface;
Interface.prototype.toJSON = function () {
return {id: this.id,
name: this.name};
};
Interface.prototype.remote_interface = function () {
if (this.link === null) {
@ -192,6 +208,15 @@ function Link(id, from_device, to_device, from_interface, to_interface) {
}
exports.Link = Link;
Link.prototype.toJSON = function () {
return {from_device_id: this.from_device.id,
to_device_id: this.to_device.id,
from_interface_id: this.from_interface.id,
to_interface_id: this.to_interface.id,
name: this.name};
};
Link.prototype.is_selected = function (x, y) {
// Is the distance to the mouse location less than 25 if on the label side
// or 5 on the other from the shortest line to the link?
@ -349,6 +374,22 @@ function Group(id, name, type, x1, y1, x2, y2, selected) {
}
exports.Group = Group;
Group.prototype.toJSON = function () {
return {id: this.id,
name: this.name,
type: this.type,
x1: this.x1,
y1: this.y1,
x2: this.x2,
y2: this.y2,
devices: this.devices,
links: this.links,
streams: this.streams,
groups: this.groups};
};
Group.prototype.update_hightlighted = function (x, y) {
this.highlighted = this.is_highlighted(x, y);

View File

@ -20,7 +20,7 @@ var messages = require('./messages.js');
var svg_crowbar = require('../vendor/svg-crowbar.js');
var ReconnectingWebSocket = require('reconnectingwebsocket');
var NetworkUIController = function($scope, $document, $location, $window) {
var NetworkUIController = function($scope, $document, $location, $window, $http) {
window.scope = $scope;
var i = 0;
@ -30,6 +30,8 @@ var NetworkUIController = function($scope, $document, $location, $window) {
$scope.topology_id = $location.search().topology_id || 0;
// Create a web socket to connect to the backend server
//
$scope.inventory_id = $location.search().inventory_id || 0;
if (!$scope.disconnected) {
$scope.control_socket = new ReconnectingWebSocket("ws://" + window.location.host + "/network_ui/topology?topology_id=" + $scope.topology_id,
@ -139,19 +141,26 @@ var NetworkUIController = function($scope, $document, $location, $window) {
//Inventory Toolbox Setup
$scope.inventory_toolbox = new models.ToolBox(0, 'Inventory', 'device', 10, 200, 150, $scope.graph.height - 200 - 100);
$scope.inventory_toolbox.items.push(new models.Device(0, 'Router6', 0, 0, 'router'));
$scope.inventory_toolbox.items.push(new models.Device(0, 'Switch6', 0, 0, 'switch'));
$scope.inventory_toolbox.items.push(new models.Device(0, 'Host6', 0, 0, 'host'));
$scope.inventory_toolbox.items.push(new models.Device(0, 'Router7', 0, 0, 'router'));
$scope.inventory_toolbox.items.push(new models.Device(0, 'Router8', 0, 0, 'router'));
$scope.inventory_toolbox.items.push(new models.Device(0, 'Router9', 0, 0, 'router'));
$scope.inventory_toolbox.items.push(new models.Device(0, 'Router10', 0, 0, 'router'));
$scope.inventory_toolbox.items.push(new models.Device(0, 'Router11', 0, 0, 'router'));
$scope.inventory_toolbox.items.push(new models.Device(0, 'Router12', 0, 0, 'router'));
$scope.inventory_toolbox.items.push(new models.Device(0, 'Router13', 0, 0, 'router'));
$scope.inventory_toolbox.items.push(new models.Device(0, 'Router14', 0, 0, 'router'));
$scope.inventory_toolbox.items.push(new models.Device(0, 'Router15', 0, 0, 'router'));
$scope.inventory_toolbox.items.push(new models.Device(0, 'Router16', 0, 0, 'router'));
if (!$scope.disconnected) {
$http.get('/api/v2/inventories/' + $scope.inventory_id + '/hosts/?format=json')
.then(function(response) {
console.log(response);
var host = null;
var i = 0;
function add_host (response) {
console.log(response);
var device = new models.Device(0, response.data.name, 0, 0, response.data.type);
device.icon = true;
$scope.inventory_toolbox.items.push(device);
}
for (i=0; i<response.data.results.length;i++) {
host = response.data.results[i];
$http.get('/api/v2/hosts/'+ host.id + '/variable_data?format=json')
.then(add_host);
}
});
}
$scope.inventory_toolbox.spacing = 150;
$scope.inventory_toolbox.enabled = true;
$scope.inventory_toolbox_controller.toolbox = $scope.inventory_toolbox;
@ -160,9 +169,6 @@ var NetworkUIController = function($scope, $document, $location, $window) {
$scope.first_controller.handle_message("PasteDevice", new messages.PasteDevice(selected_item));
};
for(i = 0; i < $scope.inventory_toolbox.items.length; i++) {
$scope.inventory_toolbox.items[i].icon = true;
}
//End Inventory Toolbox Setup
$scope.rack_toolbox_controller = new fsm.FSMController($scope, toolbox_fsm.Start, $scope.inventory_toolbox_controller);
//Rack Toolbox Setup
@ -1077,7 +1083,7 @@ var NetworkUIController = function($scope, $document, $location, $window) {
$scope.link_id_seq = util.natural_numbers(data.link_id_seq);
$scope.group_id_seq = util.natural_numbers(data.group_id_seq);
$scope.device_id_seq = util.natural_numbers(data.device_id_seq);
$location.search({topology_id: data.topology_id});
$location.search({topology_id: data.topology_id, inventory_id: $scope.inventory_id});
};
$scope.onDeviceSelected = function(data) {
@ -1107,6 +1113,94 @@ var NetworkUIController = function($scope, $document, $location, $window) {
}
};
$scope.onToolboxItem = function (data) {
if (data.toolbox_name === "Site") {
var site = JSON.parse(data.data);
console.log(site);
var i = 0;
var j = 0;
var site_copy = new models.Group(site.id,
site.name,
site.type,
site.x1,
site.y1,
site.x2,
site.y2,
false);
var device, device_copy;
var process, process_copy;
var intf, intf_copy;
var device_map = {};
for (i = 0; i < site.devices.length; i++) {
device = site.devices[i];
device_copy = new models.Device(device.id,
device.name,
device.x,
device.y,
device.type);
device_map[device.id] = device_copy;
device_copy.interface_map = {};
site_copy.devices.push(device_copy);
for(j=0; j < device.interfaces.length; j++) {
intf = device.interfaces[j];
intf_copy = new models.Interface(intf.id, intf.name);
intf_copy.device = device_copy;
device_copy.interfaces.push(intf_copy);
device_copy.interface_map[intf.id] = intf_copy;
}
for(j=0; j < device.processes.length; j++) {
process = device.processes[j];
process_copy = new models.Process(process.id,
process.name,
process.type,
process.x,
process.y);
process_copy.device = device;
device_copy.processes.push(process_copy);
}
}
console.log(device_map);
var group, group_copy;
for (i = 0; i < site.groups.length; i++) {
group = site.groups[i];
group_copy = new models.Group(group.id,
group.name,
group.type,
group.x1,
group.y1,
group.x2,
group.y2,
false);
site_copy.groups.push(group_copy);
}
var link, link_copy;
for (i = 0; i < site.links.length; i++) {
link = site.links[i];
link_copy = new models.Link(link.id,
device_map[link.from_device_id],
device_map[link.to_device_id],
device_map[link.from_device_id].interface_map[link.from_interface_id],
device_map[link.to_device_id].interface_map[link.to_interface_id]);
link_copy.name = link.name;
device_map[link.from_device_id].interface_map[link.from_interface_id].link = link_copy;
device_map[link.to_device_id].interface_map[link.to_interface_id].link = link_copy;
site_copy.links.push(link_copy);
}
var stream, stream_copy;
for(i = 0; i < site.streams.length;i++) {
stream = site.streams[i];
stream_copy = new models.Stream(stream.id,
device_map[stream.from_device],
device_map[stream.to_device],
stream.label);
site_copy.streams.push(stream_copy);
}
$scope.site_toolbox.items.push(site_copy);
}
};
$scope.onSnapshot = function (data) {
//Erase the existing state

View File

@ -208,6 +208,14 @@ _Ready.prototype.onPasteSite = function (controller, msg_type, message) {
false);
scope.groups.push(inner_group);
group.groups.push(inner_group);
c_messages.push(new messages.GroupCreate(scope.client_id,
inner_group.id,
inner_group.x1,
inner_group.y1,
inner_group.x2,
inner_group.y2,
inner_group.name,
inner_group.type));
}
for(i=0; i< group.groups.length; i++) {
group.groups[i].update_membership(scope.devices, scope.groups);
@ -340,6 +348,8 @@ _Selected2.prototype.onCopySelected = function (controller) {
group_copy.groups.push(inner_group);
}
controller.scope.send_control_message(new messages.CopySite(group_copy));
controller.scope.site_toolbox.items.push(group_copy);
}
};

View File

@ -389,6 +389,11 @@ _Present.prototype.onSnapshot = function(controller, msg_type, message) {
controller.scope.onSnapshot(message);
}
};
_Present.prototype.onToolboxItem = function(controller, msg_type, message) {
if (message.sender !== controller.scope.client_id) {
controller.scope.onToolboxItem(message);
}
};
_Present.prototype.onid = function(controller, msg_type, message) {
controller.scope.onClientId(message);
};