make an App::Netdisco dist using Module::Install

This commit is contained in:
Oliver Gorwits
2012-12-17 18:31:16 +00:00
parent 6a0aa7864e
commit 05086e8b78
125 changed files with 428 additions and 127 deletions

View File

@@ -0,0 +1,25 @@
<table class="table-bordered table-condensed table-striped">
<thead>
<tr>
<th>Address</th>
<th>DNS</th>
<th class="center_cell">Interface</th>
<th>Description</th>
<th>Prefix</th>
</tr>
</thead>
</tbody>
[% WHILE (row = results.next) %]
<tr>
<td>[% row.alias %]</a>
<td>[% row.dns.remove(settings.domain_suffix) %]</a>
<td class="center_cell"><a class="nd_linkcell"
href="[% vars.device_ports %]&q=[% row.ip %]&f=[% row.port %]">[% row.port %]</a></td>
<td>[% row.device_port.name %]</td>
<td><a class="nd_linkcell"
href="[% vars.search_device %]&ip=[% row.subnet %]">[% row.subnet %]</a></td>
</tr>
[% END %]
</tbody>
</table>

View File

@@ -0,0 +1,97 @@
<table class="table-condensed table-striped">
</tbody>
<tr>
<td>System Name</td>
<td>[% d.name %]</td>
</tr>
<tr>
<td>Location
[% IF vars.user.port_control %]
<i class="icon-edit nd_edit_icon nd_device_details_edit"></i>
[% END %]
</td>
[% IF vars.user.port_control %]
<td class="nd_editable_cell" contenteditable="true"
data-field="location" data-for-device="[% d.ip %]">
[% d.location %]
</td>
[% ELSE %]
<td>
<a rel="tooltip" data-placement="top" data-offset="5" data-title="Find Similar Devices"
href="[% vars.search_device %]&location=[% d.location | uri %]">[% d.location %]</a>
</td>
[% END %]
</tr>
<tr>
<td>Contact
[% IF vars.user.port_control %]
<i class="icon-edit nd_edit_icon nd_device_details_edit"></i>
[% END %]
</td>
[% IF vars.user.port_control %]
<td class="nd_editable_cell" contenteditable="true"
data-field="contact" data-for-device="[% d.ip %]">
[% d.contact %]
</td>
[% ELSE %]
<td>[% d.contact %]</td>
[% END %]
</tr>
<tr>
<td>Vendor / Model</td>
<td>
<a rel="tooltip" data-placement="top" data-offset="5" data-title="Find Similar Devices"
href="[% vars.search_device %]&vendor=[% d.vendor | uri %]">[% d.vendor %]</a>
/
<a rel="tooltip" data-placement="top" data-offset="5" data-title="Find Similar Devices"
href="[% vars.search_device %]&model=[% d.model | uri %]">[% d.model %]</a>
</td>
</tr>
<tr>
<td>OS / Version</td>
<td>[% d.os %] /
<a rel="tooltip" data-placement="top" data-offset="5"
data-title="Find Similar Devices"
href="[% vars.search_device %]&os_ver=[% d.os_ver | uri %]">[% d.os_ver %]</a>
</td>
</tr>
<tr>
<td>Serial Number</td>
<td>[% d.serial %]</td>
</tr>
<tr>
<td>Description</td>
<td>[% d.description.replace(', ',",<br/>") %]</td>
</tr>
<tr>
<td>Uptime</td>
<td>[% d.uptime_age %]</td>
</tr>
<tr>
<td>Last Discover</td>
<td>[% d.last_discover_stamp %]</td>
</tr>
<tr>
<td>Last Arpnip</td>
<td>[% d.last_arpnip_stamp %]</td>
</tr>
<tr>
<td>Last Macsuck</td>
<td>[% d.last_macsuck_stamp %]</td>
</tr>
<tr>
<td>Hardware Status</td>
<td>Fan: [% d.fan %]
<br/>PS1 [[% d.ps1_type %]]: [% d.ps1_status %]
<br/>PS2 [[% d.ps2_type %]]: [% d.ps2_status %]</td>
</tr>
<tr>
<td>MAC Address</td>
<td>[% d.mac %]</td>
</tr>
<tr>
<td>VTP Domain</td>
<td>[% d.vtp_domain %]</td>
</tr>
</tbody>
</table>

View File

@@ -0,0 +1,174 @@
<script>
var winHeight = window.innerHeight;
var winWidth = window.innerWidth;
var tree = d3.layout.tree()
.size([360, winHeight])
.separation(function(a, b) { return (a.parent == b.parent ? 1 : 2) / a.depth; });
// links in the initial tree drawing use this generator
var treeLink = d3.svg.diagonal.radial()
.projection(function(d) { return [d.y, d.x / 180 * Math.PI]; });
// actual device neighbor links use this generator
var neighLink = d3.svg.diagonal.radial();
// store x,y for all circles on the map
var loc = {};
// store actual links between all nodes
var neighbors_data = {};
// main SVG background, with support for pan/zoom
var svg = d3.select("#netmap_pane").append("svg")
.attr("width", winWidth - 50)
.attr("height", winHeight - 100)
.attr("pointer-events", "all")
.append('g')
.call(d3.behavior.zoom().on("zoom", redraw))
.append("g")
.attr("transform", "translate(" + winHeight / 2 + "," + winHeight / 2 + ")");
// this is the image background
// FIXME there must be a way to discover the radial tree's size?
svg.append('rect')
.attr("x", (0 - (winHeight * 2)))
.attr('width', "400%")
.attr("y", (0 - (winHeight * 2)))
.attr('height', "400%")
.attr('fill', 'white');
// handle pan and zoom
function redraw() {
svg.attr("transform",
"translate(" + d3.event.translate + ")"
+ "scale(" + d3.event.scale + ")"
+ "translate(" + (winHeight / 2) + "," + (winHeight / 2) + ")");
}
// save the x,y of an element into the loc dictionary
function recordLocation(d,i) {
var rect = this.getBoundingClientRect();
loc[d.name] = {
'x': (rect.left + ((rect.right - rect.left) / 2))
,'y': (rect.top + ((rect.bottom - rect.top) / 2))
};
}
// convert a device name to a valid CSS class name
function to_class(name) { return 'nd_' + name.replace(/\./g, "_") }
// handler for clicking on a circle - redirect to that device's netmap
function circleClick(d) {
window.location = '[% uri_for('/device') %]?tab=netmap&q=' + d.ip;
}
// handler for mouseover on a circle - show that device's real neighbors
function circleOver(d) {
$('.link').hide();
$('path.' + to_class(d.name)).show();
$(this).css('cursor', 'pointer');
$.each(neighbors_data[d.name], function(idx, target) {
if (! (target in loc)) { return true }
$('circle.' + to_class(target)).css('fill', '#e96cfa');
});
}
// handler for mouseout on a circle - hide real neighbours and show treeLinks
function circleOut(d) {
$.each(neighbors_data[d.name], function(idx, target) {
if (! (target in loc)) { return true }
$('circle.' + to_class(target)).css('fill', '#fff');
});
$(this).css('cursor', 'auto');
$('path.' + to_class(d.name)).hide();
$('.link').show();
}
// load all device connections into neighbors_data dictionary
$.getJSON('[% uri_for('/ajax/data/device/alldevicelinks') %]', function(data) {
neighbors_data = data;
// draw the tree
d3.json("[% uri_for('/ajax/data/device/netmap') %]?&q=[% params.q | uri %]", function(error, root) {
var nodes = tree.nodes(root),
links = tree.links(nodes);
var link = svg.selectAll(".link")
.data(links)
.enter().append("path")
.attr("class", "link")
.attr("d", treeLink);
var node = svg.selectAll(".node")
.data(nodes)
.enter().append("g")
.attr("class", "node")
.attr("transform", function(d) { return "rotate(" + (d.x - 90) + ")translate(" + d.y + ")"; });
node.append("circle")
.attr("r", 4.5)
// circle has class name of its device, so we can show/hide it
.attr("class", function(d) { return to_class(d.name) })
// store the x,y of every circle we've just drawn
.each(recordLocation)
// handlers for mouse interaction with the circles
.on("click", circleClick)
.on("mouseover", circleOver)
.on("mouseout", circleOut);
node.append("text")
.attr("dy", ".31em")
.attr("text-anchor", function(d) { return d.x < 180 ? "start" : "end"; })
.attr("transform", function(d) { return d.x < 180 ? "translate(8)" : "rotate(180)translate(-8)"; })
.text(function(d) { return d.name; });
// reorient text on the root node
svg.select(".node")
.attr("transform", function(d) {
return d.x < 180 ? "rotate(0)translate(0)" : "rotate(180)translate(0)"; });
// key (name) of the root node in our locations store
var rootname = svg.select(".node").data()[0].name;
// reformatted neighbors_data for the real neighbor links
var neighbors = [];
// need to build neighbors array only after we have built loc dictionary,
// after drawing the circles and storing their x,y
$.each(neighbors_data, function(key, val) {
if (! (key in loc)) { return true }
$.each(val, function(idx, name) {
if (! (name in loc)) { return true }
neighbors.push({
'source': {
'name': key
,'x': loc[key]['x']
,'y': loc[key]['y']
}
,'target': {
'name': name
,'x': loc[name]['x']
,'y': loc[name]['y']
}
});
});
});
// insert Netdisco neighbor links below circles but above tree links
svg.selectAll(".neighbor")
.data(neighbors)
.enter().insert("path", ".node")
// add class name of source device, so we can show/hide the link
// (also "neighbor" class)
.attr("class", function(d) { return ("neighbor " + to_class( d.source.name )) })
.attr("d", neighLink)
.attr("transform", "translate(-" + loc[rootname]['x'] + ",-" + loc[rootname]['y'] + ")");
});
}); // jquery getJSON for all connections
</script>

View File

@@ -0,0 +1,229 @@
<table class="table-bordered table-condensed table-striped">
<thead>
<tr>
<th></th>
[% FOREACH item IN vars.port_columns %]
[% NEXT IF item.name == 'c_admin' %]
[% NEXT IF item.name == 'c_nodes' AND params.c_nodes AND params.c_neighbors %]
[% NEXT UNLESS params.${item.name} %]
<th[% ' class="center_cell"' IF NOT loop.first %]>[% item.label %]</th>
[% END %]
</tr>
</thead>
</tbody>
[% FOREACH row IN results %]
<tr>
<td>
[% IF row.up_admin == 'down' %]
<span class="label">S</span>
[% ELSIF row.stp == 'blocking' %]
<span class="label label-info">B</span>
[% ELSIF params.free OR row.is_free %]
<span class="label label-success">F</span>
[% ELSIF row.up_admin == 'up' AND row.up == 'down' %]
<span class="label label-warning">D</span>
[% END %]
</td>
[% IF params.c_port %]
[% IF vars.user.port_control AND params.c_admin %]
[% IF row.up_admin == 'up' %]
<td class="nd_editable_cell" data-action="down"
data-field="c_port" data-for-device="[% device %]" data-for-port="[% row.port | html_entity %]">
<i class="icon-hand-down nd_hand_icon"
rel="tooltip" data-placement="top" data-offset="3"
data-animation="" data-title="Click to Disable"></i>
[% ELSE %]
<td class="nd_editable_cell" data-action="up"
data-field="c_port" data-for-device="[% device %]" data-for-port="[% row.port | html_entity %]">
<i class="icon-hand-up nd_hand_icon"
rel="tooltip" data-placement="top" data-offset="3"
data-animation="" data-title="Click to Enable"></i>
[% END %]
[% ELSE %]
<td>
[% END %]
<a class="nd_linkcell nd_this_port_only" href="[% uri_for('/device',
vars.self_options) %]&q=[% params.q | uri %]&f=[% row.port | uri %]">
[% row.port | html_entity %]
</a></td>
[% END %]
[% IF params.c_descr %]
<td class="center_cell">[% row.descr | html_entity %]</td>
[% END %]
[% IF params.c_type %]
<td class="center_cell">[% row.type | html_entity %]</td>
[% END %]
[% IF params.c_duplex %]
<td class="center_cell">
[% IF row.up == 'up' AND row.duplex %]
[% row.duplex_admin | html_entity %] / [% row.duplex | html_entity %]
[% END %]
</td>
[% END %]
[% IF params.c_lastchange %]
<td class="center_cell">[% row.lastchange_stamp | html_entity %]</td>
[% END %]
[% IF params.c_name %]
[% IF vars.user.port_control AND params.c_admin %]
<td nowrap class="center_cell nd_editable_cell" contenteditable="true"
data-field="c_name" data-for-device="[% device %]" data-for-port="[% row.port | html_entity %]">
<i class="icon-edit nd_edit_icon"></i>
[% ELSE %]
<td nowrap class="center_cell">
[% END %]
<div class="nd_editable_cell_content">
[% row.name | html_entity %]
</div>
</td>
[% END %]
[% IF params.c_speed %]
<td class="center_cell">[% row.speed | html_entity %]</td>
[% END %]
[% IF params.c_mac %]
<td class="center_cell">[% row.mac | html_entity %]</td>
[% END %]
[% IF params.c_mtu %]
<td class="center_cell">[% row.mtu | html_entity %]</td>
[% END %]
[% IF params.c_vlan %]
[% IF vars.user.port_control AND params.c_admin %]
<td class="center_cell nd_editable_cell" contenteditable="true"
data-field="c_vlan" data-for-device="[% device %]" data-for-port="[% row.port | html_entity %]">
<i class="icon-edit nd_edit_icon"></i>
<div class="nd_editable_cell_content">
[% IF row.vlan %][% row.vlan | html_entity %][% END %]
</div>
</td>
[% ELSE %]
<td class="center_cell">
<a class="nd_linkcell"
href="[% uri_for('/search') %]?tab=vlan&q=[% row.vlan | uri %]">
[% row.vlan | html_entity %]</a>
</td>
[% END %]
[% END %]
[% IF params.c_vmember %]
<td>
[% IF row.tagged_vlans_count %]
[% SET output = '' %]
[% FOREACH vlan IN row.tagged_vlans %]
[% SET output = output _
'<a href="' _ uri_for('/search') _ '?tab=vlan&q=' _ vlan.vlan _ '">' _ vlan.vlan _ '</a>' %]
[% SET output = output _ ', ' IF NOT loop.last %]
[% END %]
[% IF row.tagged_vlans_count > 10 %] [%# FIXME make this a settable variable %]
[% SET output = '<div class="vlan_total">(' _ row.tagged_vlans_count
_ ')</div><span class="nd_linkcell nd_collapse_vlans">
<i class="cell-arrow-up-down icon-chevron-up icon-large">
</i>Show VLANs</span>
<div class="nd_collapsing nd_collapse_pre_hidden">' _ output %]
[% SET output = output _ '</div>' %]
[% END %]
[% output %]
[% END %]
</td>
[% END %]
[% IF params.c_power %]
[% IF row.power %]
[% IF row.power.admin == 'true' %]
[% IF vars.user.port_control AND params.c_admin %]
<td nowrap data-action="false"
data-field="c_power" data-for-device="[% device %]"
data-for-port="[% row.port | html_entity %]">
<i class="icon-off nd_power_icon nd_power_on"
rel="tooltip" data-placement="top" data-offset="3"
data-animation="" data-title="Click to Disable"></i>
[% ELSE %]
<td nowrap>
<i class="icon-off nd_power_on"></i>
[% END %]
<span>
[% IF row.power.power > 0 %]
[% row.power.power %]&nbsp;mW
[% ELSE %]
([% row.power.status %])
[% END %]
</span>
[% ELSE %]
[% IF vars.user.port_control AND params.c_admin %]
<td nowrap data-action="true"
data-field="c_power" data-for-device="[% device %]"
data-for-port="[% row.port | html_entity %]">
<i class="icon-off nd_power_icon"
rel="tooltip" data-placement="top" data-offset="3"
data-animation="" data-title="Click to Enable"></i>
[% ELSE %]
<td>
<i class="icon-off"></i>
[% END %]
[% END %]
</td>
[% ELSE %]
<td></td>
[% END %]
[% END %]
[% IF params.c_nodes OR params.c_neighbors %]
<td>
[% IF params.c_neighbors AND row.remote_ip %]
[% IF row.neighbor %]
<a href="[% uri_for('/device',
vars.self_options) %]&q=[% row.neighbor.ip | uri %]&f=[% row.remote_port | uri %]">
[% row.neighbor.dns.remove(settings.domain_suffix) || row.neighbor.ip %]
([% row.remote_port | html_entity %])</a>
[% ELSE %]
<span class="label label-important">N</span>
<a href="[% vars.search_node %]&q=[% row.remote_ip | uri %]">
[% row.remote_ip %] (port: [% row.remote_port %]
id: [% (row.remote_type _ ' / ') IF row.remote_type %][% row.remote_id %])</a>
[% END %]
[% END %]
[% IF params.c_nodes %]
[% FOREACH node IN row.$nodes %]
[% '<br/>' IF row.remote_ip OR NOT loop.first %]
[% '<span class="label label-warning">A</span> &nbsp;' IF NOT node.active %]
<a href="[% vars.search_node %]&q=[% node.mac | uri %]">[% node.mac %]</a>
[% ' (' _ node.time_last_age _ ')' IF params.n_age %]
[% IF params.n_ip %]
[% FOREACH ip IN node.ips %]
<br/>&nbsp; [% '<span class="label label-warning">A</span> &nbsp;' IF NOT ip.active %]
[% SET dns = ip.dns %]
[% IF dns %]
<a href="[% vars.search_node %]&q=[% ip.ip | uri %]">[% dns %] ([% ip.ip %])</a>
[% ELSE %]
<a href="[% vars.search_node %]&q=[% ip.ip | uri %]">[% ip.ip %]</a>
[% END %]
[% END %]
[% END %]
[% END %]
[% END %]
</td>
[% END %]
[% IF params.c_stp %]
<td class="center_cell">[% row.stp | html_entity %]</td>
[% END %]
[% IF params.c_up %]
<td class="center_cell">
[% row.up_admin | html_entity %] / [% row.up | html_entity %]
</td>
[% END %]
</tr>
[% END %]
</tbody>
</table>