make an App::Netdisco dist using Module::Install
This commit is contained in:
44
Netdisco/lib/App/Netdisco/Web/AuthN.pm
Normal file
44
Netdisco/lib/App/Netdisco/Web/AuthN.pm
Normal file
@@ -0,0 +1,44 @@
|
||||
package App::Netdisco::Web::AuthN;
|
||||
|
||||
use Dancer ':syntax';
|
||||
use Dancer::Plugin::DBIC;
|
||||
|
||||
use Digest::MD5 ();
|
||||
|
||||
hook 'before' => sub {
|
||||
if (! session('user') && request->path ne uri_for('/login')->path) {
|
||||
if (setting('no_auth')) {
|
||||
session(user => 'guest');
|
||||
}
|
||||
else {
|
||||
request->path_info('/');
|
||||
}
|
||||
}
|
||||
|
||||
if (session('user') && session->id) {
|
||||
var(user => schema('netdisco')->resultset('User')
|
||||
->find(session('user')));
|
||||
}
|
||||
};
|
||||
|
||||
post '/login' => sub {
|
||||
if (param('username') and param('password')) {
|
||||
my $user = schema('netdisco')->resultset('User')->find(param('username'));
|
||||
if ($user) {
|
||||
my $sum = Digest::MD5::md5_hex(param('password'));
|
||||
if ($sum and $sum eq $user->password) {
|
||||
session(user => $user->username);
|
||||
redirect uri_for('/inventory');
|
||||
return;
|
||||
}
|
||||
}
|
||||
}
|
||||
redirect uri_for('/', {failed => 1});
|
||||
};
|
||||
|
||||
get '/logout' => sub {
|
||||
session->destroy;
|
||||
redirect uri_for('/', {logout => 1});
|
||||
};
|
||||
|
||||
true;
|
||||
305
Netdisco/lib/App/Netdisco/Web/Device.pm
Normal file
305
Netdisco/lib/App/Netdisco/Web/Device.pm
Normal file
@@ -0,0 +1,305 @@
|
||||
package App::Netdisco::Web::Device;
|
||||
|
||||
use Dancer ':syntax';
|
||||
use Dancer::Plugin::Ajax;
|
||||
use Dancer::Plugin::DBIC;
|
||||
|
||||
use NetAddr::IP::Lite ':lower';
|
||||
use App::Netdisco::Util::Web (); # for sort_port
|
||||
|
||||
hook 'before' => sub {
|
||||
# list of port detail columns
|
||||
var('port_columns' => [
|
||||
{ name => 'c_admin', label => 'Port Control', default => '' },
|
||||
{ name => 'c_port', label => 'Port', default => 'on' },
|
||||
{ name => 'c_descr', label => 'Description', default => '' },
|
||||
{ name => 'c_type', label => 'Type', default => '' },
|
||||
{ name => 'c_duplex', label => 'Duplex', default => '' },
|
||||
{ name => 'c_lastchange', label => 'Last Change', default => '' },
|
||||
{ name => 'c_name', label => 'Name', default => 'on' },
|
||||
{ name => 'c_speed', label => 'Speed', default => '' },
|
||||
{ name => 'c_mac', label => 'Port MAC', default => '' },
|
||||
{ name => 'c_mtu', label => 'MTU', default => '' },
|
||||
{ name => 'c_vlan', label => 'Native VLAN', default => 'on' },
|
||||
{ name => 'c_vmember', label => 'Tagged VLANs', default => 'on' },
|
||||
{ name => 'c_power', label => 'PoE', default => '' },
|
||||
{ name => 'c_nodes', label => 'Connected Nodes', default => '' },
|
||||
{ name => 'c_neighbors', label => 'Connected Devices', default => 'on' },
|
||||
{ name => 'c_stp', label => 'Spanning Tree', default => '' },
|
||||
{ name => 'c_up', label => 'Status', default => '' },
|
||||
]);
|
||||
|
||||
# view settings for port connected devices
|
||||
var('connected_properties' => [
|
||||
{ name => 'n_age', label => 'Age Stamp', default => '' },
|
||||
{ name => 'n_ip', label => 'IP Address', default => 'on' },
|
||||
{ name => 'n_archived', label => 'Archived Data', default => '' },
|
||||
]);
|
||||
|
||||
# new searches will use these defaults in their sidebars
|
||||
var('device_ports' => uri_for('/device', {
|
||||
tab => 'ports',
|
||||
age_num => 3,
|
||||
age_unit => 'months',
|
||||
}));
|
||||
|
||||
foreach my $col (@{ var('port_columns') }) {
|
||||
next unless $col->{default} eq 'on';
|
||||
var('device_ports')->query_param($col->{name}, 'checked');
|
||||
}
|
||||
|
||||
foreach my $col (@{ var('connected_properties') }) {
|
||||
next unless $col->{default} eq 'on';
|
||||
var('device_ports')->query_param($col->{name}, 'checked');
|
||||
}
|
||||
|
||||
if (request->path eq uri_for('/device')->path
|
||||
or index(request->path, uri_for('/ajax/content/device')->path) == 0) {
|
||||
|
||||
foreach my $col (@{ var('port_columns') }) {
|
||||
next unless $col->{default} eq 'on';
|
||||
params->{$col->{name}} = 'checked'
|
||||
if not param('tab') or param('tab') ne 'ports';
|
||||
}
|
||||
|
||||
foreach my $col (@{ var('connected_properties') }) {
|
||||
next unless $col->{default} eq 'on';
|
||||
params->{$col->{name}} = 'checked'
|
||||
if not param('tab') or param('tab') ne 'ports';
|
||||
}
|
||||
|
||||
if (not param('tab') or param('tab') ne 'ports') {
|
||||
params->{'age_num'} = 3;
|
||||
params->{'age_unit'} = 'months';
|
||||
}
|
||||
|
||||
# for templates to link to same page with modified query but same options
|
||||
my $self_uri = uri_for(request->path, scalar params);
|
||||
$self_uri->query_param_delete('q');
|
||||
$self_uri->query_param_delete('f');
|
||||
var('self_options' => $self_uri->query_form_hash);
|
||||
}
|
||||
};
|
||||
|
||||
ajax '/ajax/content/device/:thing' => sub {
|
||||
return "<p>Hello, this is where the ". param('thing') ." content goes.</p>";
|
||||
};
|
||||
|
||||
ajax '/ajax/content/device/netmap' => sub {
|
||||
content_type('text/html');
|
||||
template 'ajax/device/netmap.tt', {}, { layout => undef };
|
||||
};
|
||||
|
||||
sub _get_name {
|
||||
my $ip = shift;
|
||||
my $domain = quotemeta( setting('domain_suffix') || '' );
|
||||
|
||||
(my $dns = (var('devices')->{$ip} || '')) =~ s/$domain$//;
|
||||
return ($dns || $ip);
|
||||
}
|
||||
|
||||
sub _add_children {
|
||||
my ($ptr, $childs) = @_;
|
||||
my @legit = ();
|
||||
|
||||
foreach my $c (@$childs) {
|
||||
next if exists var('seen')->{$c};
|
||||
var('seen')->{$c}++;
|
||||
push @legit, $c;
|
||||
push @{$ptr}, { name => _get_name($c), ip => $c };
|
||||
}
|
||||
|
||||
for (my $i = 0; $i < @legit; $i++) {
|
||||
$ptr->[$i]->{children} = [];
|
||||
_add_children($ptr->[$i]->{children}, var('links')->{$legit[$i]});
|
||||
}
|
||||
}
|
||||
|
||||
# d3 seems not to use proper json semantics, so get instead of ajax
|
||||
get '/ajax/data/device/netmap' => sub {
|
||||
my $start = param('q');
|
||||
return unless $start;
|
||||
|
||||
my @devices = schema->resultset('Device')->search({}, {
|
||||
result_class => 'DBIx::Class::ResultClass::HashRefInflator',
|
||||
columns => ['ip', 'dns'],
|
||||
})->all;
|
||||
var(devices => { map { $_->{ip} => $_->{dns} } @devices });
|
||||
|
||||
var(links => {});
|
||||
my $rs = schema->resultset('Virtual::DeviceLinks')->search({}, {
|
||||
result_class => 'DBIx::Class::ResultClass::HashRefInflator',
|
||||
});
|
||||
|
||||
while (my $l = $rs->next) {
|
||||
var('links')->{ $l->{left_ip} } ||= [];
|
||||
push @{ var('links')->{ $l->{left_ip} } }, $l->{right_ip};
|
||||
}
|
||||
|
||||
my %tree = (
|
||||
ip => $start,
|
||||
name => _get_name($start),
|
||||
children => [],
|
||||
);
|
||||
|
||||
var(seen => {$start => 1});
|
||||
_add_children($tree{children}, var('links')->{$start});
|
||||
|
||||
content_type('application/json');
|
||||
return to_json(\%tree);
|
||||
};
|
||||
|
||||
ajax '/ajax/data/device/alldevicelinks' => sub {
|
||||
my @devices = schema->resultset('Device')->search({}, {
|
||||
result_class => 'DBIx::Class::ResultClass::HashRefInflator',
|
||||
columns => ['ip', 'dns'],
|
||||
})->all;
|
||||
var(devices => { map { $_->{ip} => $_->{dns} } @devices });
|
||||
|
||||
my $rs = schema->resultset('Virtual::DeviceLinks')->search({}, {
|
||||
result_class => 'DBIx::Class::ResultClass::HashRefInflator',
|
||||
});
|
||||
|
||||
my %tree = ();
|
||||
while (my $l = $rs->next) {
|
||||
push @{ $tree{ _get_name($l->{left_ip} )} },
|
||||
_get_name($l->{right_ip});
|
||||
}
|
||||
|
||||
content_type('application/json');
|
||||
return to_json(\%tree);
|
||||
};
|
||||
|
||||
# device interface addresses
|
||||
ajax '/ajax/content/device/addresses' => sub {
|
||||
my $ip = param('q');
|
||||
return unless $ip;
|
||||
|
||||
my $set = schema('netdisco')->resultset('DeviceIp')
|
||||
->search({ip => $ip}, {order_by => 'alias'});
|
||||
return unless $set->count;
|
||||
|
||||
content_type('text/html');
|
||||
template 'ajax/device/addresses.tt', {
|
||||
results => $set,
|
||||
}, { layout => undef };
|
||||
};
|
||||
|
||||
# device ports with a description (er, name) matching
|
||||
ajax '/ajax/content/device/ports' => sub {
|
||||
my $ip = param('q');
|
||||
return unless $ip;
|
||||
|
||||
my $set = schema('netdisco')->resultset('DevicePort')
|
||||
->search({'me.ip' => $ip});
|
||||
|
||||
# refine by ports if requested
|
||||
my $q = param('f');
|
||||
if ($q) {
|
||||
if ($q =~ m/^\d+$/) {
|
||||
$set = $set->search({'me.vlan' => $q});
|
||||
return unless $set->count;
|
||||
}
|
||||
else {
|
||||
$q =~ s/\*/%/g if index($q, '*') >= 0;
|
||||
$q =~ s/\?/_/g if index($q, '?') >= 0;
|
||||
$q = { '-ilike' => $q };
|
||||
|
||||
if ($set->search({'me.port' => $q})->count) {
|
||||
$set = $set->search({'me.port' => $q});
|
||||
}
|
||||
else {
|
||||
$set = $set->search({'me.name' => $q});
|
||||
return unless $set->count;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
# filter for free ports if asked
|
||||
my $free_filter = (param('free') ? 'only_free_ports' : 'with_is_free');
|
||||
$set = $set->$free_filter({
|
||||
age_num => (param('age_num') || 3),
|
||||
age_unit => (param('age_unit') || 'months')
|
||||
});
|
||||
|
||||
# make sure query asks for formatted timestamps when needed
|
||||
$set = $set->with_times if param('c_lastchange');
|
||||
|
||||
# get number of vlans on the port to control whether to list them or not
|
||||
$set = $set->with_vlan_count if param('c_vmember');
|
||||
|
||||
# what kind of nodes are we interested in?
|
||||
my $nodes_name = (param('n_archived') ? 'nodes' : 'active_nodes');
|
||||
$nodes_name .= '_with_age' if param('c_nodes') and param('n_age');
|
||||
|
||||
# retrieve active/all connected nodes, if asked for
|
||||
$set = $set->search_rs({}, { prefetch => [{$nodes_name => 'ips'}] })
|
||||
if param('c_nodes');
|
||||
|
||||
# retrieve neighbor devices, if asked for
|
||||
$set = $set->search_rs({}, { prefetch => [{neighbor_alias => 'device'}] })
|
||||
if param('c_neighbors');
|
||||
|
||||
# sort ports (empty set would be a 'no records' msg)
|
||||
my $results = [ sort { &App::Netdisco::Util::Web::sort_port($a->port, $b->port) } $set->all ];
|
||||
return unless scalar @$results;
|
||||
|
||||
content_type('text/html');
|
||||
template 'ajax/device/ports.tt', {
|
||||
results => $results,
|
||||
nodes => $nodes_name,
|
||||
device => $ip,
|
||||
}, { layout => undef };
|
||||
};
|
||||
|
||||
# device details table
|
||||
ajax '/ajax/content/device/details' => sub {
|
||||
my $ip = param('q');
|
||||
return unless $ip;
|
||||
|
||||
my $device = schema('netdisco')->resultset('Device')
|
||||
->with_times()->find($ip);
|
||||
return unless $device;
|
||||
|
||||
content_type('text/html');
|
||||
template 'ajax/device/details.tt', {
|
||||
d => $device,
|
||||
}, { layout => undef };
|
||||
};
|
||||
|
||||
# support typeahead with simple AJAX query for device names
|
||||
ajax '/ajax/data/device/typeahead' => sub {
|
||||
my $q = param('query');
|
||||
my $set = schema('netdisco')->resultset('Device')->search_fuzzy($q);
|
||||
|
||||
content_type 'application/json';
|
||||
return to_json [map {$_->dns || $_->name || $_->ip} $set->all];
|
||||
};
|
||||
|
||||
get '/device' => sub {
|
||||
my $ip = NetAddr::IP::Lite->new(param('q'));
|
||||
if (! $ip) {
|
||||
redirect uri_for('/', {nosuchdevice => 1});
|
||||
return;
|
||||
}
|
||||
|
||||
my $device = schema('netdisco')->resultset('Device')->find($ip->addr);
|
||||
if (! $device) {
|
||||
redirect uri_for('/', {nosuchdevice => 1});
|
||||
return;
|
||||
}
|
||||
|
||||
# list of tabs
|
||||
var('tabs' => [
|
||||
{ id => 'details', label => 'Details' },
|
||||
{ id => 'ports', label => 'Ports' },
|
||||
{ id => 'modules', label => 'Modules' },
|
||||
{ id => 'netmap', label => 'Neighbors' },
|
||||
{ id => 'addresses', label => 'Addresses' },
|
||||
]);
|
||||
|
||||
params->{'tab'} ||= 'details';
|
||||
template 'device', { d => $device };
|
||||
};
|
||||
|
||||
true;
|
||||
18
Netdisco/lib/App/Netdisco/Web/Inventory.pm
Normal file
18
Netdisco/lib/App/Netdisco/Web/Inventory.pm
Normal file
@@ -0,0 +1,18 @@
|
||||
package App::Netdisco::Web::Inventory;
|
||||
|
||||
use Dancer ':syntax';
|
||||
use Dancer::Plugin::DBIC;
|
||||
|
||||
get '/inventory' => sub {
|
||||
my $models = schema('netdisco')->resultset('Device')->get_models();
|
||||
my $releases = schema('netdisco')->resultset('Device')->get_releases();
|
||||
|
||||
var(nav => 'inventory');
|
||||
|
||||
template 'inventory', {
|
||||
models => $models,
|
||||
releases => $releases,
|
||||
};
|
||||
};
|
||||
|
||||
true;
|
||||
72
Netdisco/lib/App/Netdisco/Web/PortControl.pm
Normal file
72
Netdisco/lib/App/Netdisco/Web/PortControl.pm
Normal file
@@ -0,0 +1,72 @@
|
||||
package App::Netdisco::Web::PortControl;
|
||||
|
||||
use Dancer ':syntax';
|
||||
use Dancer::Plugin::Ajax;
|
||||
use Dancer::Plugin::DBIC;
|
||||
use Try::Tiny;
|
||||
|
||||
ajax '/ajax/portcontrol' => sub {
|
||||
try {
|
||||
my $log = sprintf 'd:[%s] p:[%s] f:[%s]. a:[%s] v[%s]',
|
||||
param('device'), (param('port') || ''), param('field'),
|
||||
(param('action') || ''), (param('value') || '');
|
||||
|
||||
my %action_map = (
|
||||
'location' => 'location',
|
||||
'contact' => 'contact',
|
||||
'c_port' => 'portcontrol',
|
||||
'c_name' => 'portname',
|
||||
'c_vlan' => 'vlan',
|
||||
'c_power' => 'power',
|
||||
);
|
||||
|
||||
my $action = $action_map{ param('field') };
|
||||
my $subaction = ($action =~ m/^(?:power|portcontrol)/
|
||||
? (param('action') ."-other")
|
||||
: param('value'));
|
||||
|
||||
schema('netdisco')->resultset('Admin')->create({
|
||||
device => param('device'),
|
||||
port => param('port'),
|
||||
action => $action,
|
||||
subaction => $subaction,
|
||||
status => 'queued',
|
||||
username => session('user'),
|
||||
userip => request->remote_address,
|
||||
log => $log,
|
||||
});
|
||||
}
|
||||
catch {
|
||||
send_error('Failed to parse params or add DB record');
|
||||
};
|
||||
|
||||
content_type('application/json');
|
||||
to_json({});
|
||||
};
|
||||
|
||||
ajax '/ajax/userlog' => sub {
|
||||
my $user = session('user');
|
||||
send_error('No username') unless $user;
|
||||
|
||||
my $rs = schema('netdisco')->resultset('Admin')->search({
|
||||
username => $user,
|
||||
action => [qw/location contact portcontrol portname vlan power/],
|
||||
finished => { '>' => \"(now() - interval '5 seconds')" },
|
||||
});
|
||||
|
||||
my %status = (
|
||||
'done' => [
|
||||
map {s/\[\]/<empty>/; $_}
|
||||
$rs->search({status => 'done'})->get_column('log')->all
|
||||
],
|
||||
'error' => [
|
||||
map {s/\[\]/<empty>/; $_}
|
||||
$rs->search({status => 'error'})->get_column('log')->all
|
||||
],
|
||||
);
|
||||
|
||||
content_type('application/json');
|
||||
to_json(\%status);
|
||||
};
|
||||
|
||||
true;
|
||||
250
Netdisco/lib/App/Netdisco/Web/Search.pm
Normal file
250
Netdisco/lib/App/Netdisco/Web/Search.pm
Normal file
@@ -0,0 +1,250 @@
|
||||
package App::Netdisco::Web::Search;
|
||||
|
||||
use Dancer ':syntax';
|
||||
use Dancer::Plugin::Ajax;
|
||||
use Dancer::Plugin::DBIC;
|
||||
|
||||
use NetAddr::IP::Lite ':lower';
|
||||
use Net::MAC ();
|
||||
use List::MoreUtils ();
|
||||
|
||||
hook 'before' => sub {
|
||||
# view settings for node options
|
||||
var('node_options' => [
|
||||
{ name => 'stamps', label => 'Time Stamps', default => 'on' },
|
||||
]);
|
||||
# view settings for device options
|
||||
var('device_options' => [
|
||||
{ name => 'matchall', label => 'Match All Options', default => 'on' },
|
||||
]);
|
||||
|
||||
# new searches will use these defaults in their sidebars
|
||||
var('search_node' => uri_for('/search', {tab => 'node'}));
|
||||
var('search_device' => uri_for('/search', {tab => 'device'}));
|
||||
|
||||
foreach my $col (@{ var('node_options') }) {
|
||||
next unless $col->{default} eq 'on';
|
||||
var('search_node')->query_param($col->{name}, 'checked');
|
||||
}
|
||||
|
||||
foreach my $col (@{ var('device_options') }) {
|
||||
next unless $col->{default} eq 'on';
|
||||
var('search_device')->query_param($col->{name}, 'checked');
|
||||
}
|
||||
|
||||
if (request->path eq uri_for('/search')->path
|
||||
or index(request->path, uri_for('/ajax/content/search')->path) == 0) {
|
||||
|
||||
foreach my $col (@{ var('node_options') }) {
|
||||
next unless $col->{default} eq 'on';
|
||||
params->{$col->{name}} = 'checked'
|
||||
if not param('tab') or param('tab') ne 'node';
|
||||
}
|
||||
|
||||
foreach my $col (@{ var('device_options') }) {
|
||||
next unless $col->{default} eq 'on';
|
||||
params->{$col->{name}} = 'checked'
|
||||
if not param('tab') or param('tab') ne 'device';
|
||||
}
|
||||
|
||||
# used in the device search sidebar template to set selected items
|
||||
foreach my $opt (qw/model vendor os_ver/) {
|
||||
my $p = (ref [] eq ref param($opt) ? param($opt)
|
||||
: (param($opt) ? [param($opt)] : []));
|
||||
var("${opt}_lkp" => { map { $_ => 1 } @$p });
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
# device with various properties or a default match-all
|
||||
ajax '/ajax/content/search/device' => sub {
|
||||
my $has_opt = List::MoreUtils::any {param($_)}
|
||||
qw/name location dns ip description model os_ver vendor/;
|
||||
my $set;
|
||||
|
||||
if ($has_opt) {
|
||||
$set = schema('netdisco')->resultset('Device')->search_by_field(scalar params);
|
||||
}
|
||||
else {
|
||||
my $q = param('q');
|
||||
return unless $q;
|
||||
|
||||
$set = schema('netdisco')->resultset('Device')->search_fuzzy($q);
|
||||
}
|
||||
return unless $set->count;
|
||||
|
||||
content_type('text/html');
|
||||
template 'ajax/search/device.tt', {
|
||||
results => $set,
|
||||
}, { layout => undef };
|
||||
};
|
||||
|
||||
# nodes matching the param as an IP or DNS hostname or MAC
|
||||
ajax '/ajax/content/search/node' => sub {
|
||||
my $node = param('q');
|
||||
return unless $node;
|
||||
content_type('text/html');
|
||||
|
||||
my $mac = Net::MAC->new(mac => $node, 'die' => 0, verbose => 0);
|
||||
my @active = (param('archived') ? () : (-bool => 'active'));
|
||||
|
||||
if (! $mac->get_error) {
|
||||
my $sightings = schema('netdisco')->resultset('Node')
|
||||
->search_by_mac({mac => $mac->as_IEEE, @active});
|
||||
|
||||
my $ips = schema('netdisco')->resultset('NodeIp')
|
||||
->search_by_mac({mac => $mac->as_IEEE, @active});
|
||||
|
||||
my $ports = schema('netdisco')->resultset('DevicePort')
|
||||
->search({mac => $mac->as_IEEE});
|
||||
|
||||
return unless $sightings->count
|
||||
or $ips->count
|
||||
or $ports->count;
|
||||
|
||||
template 'ajax/search/node_by_mac.tt', {
|
||||
ips => $ips,
|
||||
sightings => $sightings,
|
||||
ports => $ports,
|
||||
}, { layout => undef };
|
||||
}
|
||||
else {
|
||||
my $set;
|
||||
|
||||
if (my $ip = NetAddr::IP::Lite->new($node)) {
|
||||
# search_by_ip() will extract cidr notation if necessary
|
||||
$set = schema('netdisco')->resultset('NodeIp')
|
||||
->search_by_ip({ip => $ip, @active});
|
||||
}
|
||||
else {
|
||||
if (param('partial')) {
|
||||
$node = "\%$node\%";
|
||||
}
|
||||
elsif (setting('domain_suffix')) {
|
||||
$node .= setting('domain_suffix')
|
||||
if index($node, setting('domain_suffix')) == -1;
|
||||
}
|
||||
$set = schema('netdisco')->resultset('NodeIp')
|
||||
->search_by_dns({dns => $node, @active});
|
||||
}
|
||||
return unless $set and $set->count;
|
||||
|
||||
template 'ajax/search/node_by_ip.tt', {
|
||||
macs => $set,
|
||||
archive_filter => {@active},
|
||||
}, { layout => undef };
|
||||
}
|
||||
};
|
||||
|
||||
# devices carrying vlan xxx
|
||||
ajax '/ajax/content/search/vlan' => sub {
|
||||
my $q = param('q');
|
||||
return unless $q;
|
||||
my $set;
|
||||
|
||||
if ($q =~ m/^\d+$/) {
|
||||
$set = schema('netdisco')->resultset('Device')->carrying_vlan({vlan => $q});
|
||||
}
|
||||
else {
|
||||
$set = schema('netdisco')->resultset('Device')->carrying_vlan_name({name => $q});
|
||||
}
|
||||
return unless $set->count;
|
||||
|
||||
content_type('text/html');
|
||||
template 'ajax/search/vlan.tt', {
|
||||
results => $set,
|
||||
}, { layout => undef };
|
||||
};
|
||||
|
||||
# device ports with a description (er, name) matching
|
||||
ajax '/ajax/content/search/port' => sub {
|
||||
my $q = param('q');
|
||||
return unless $q;
|
||||
my $set;
|
||||
|
||||
if ($q =~ m/^\d+$/) {
|
||||
$set = schema('netdisco')->resultset('DevicePort')->search({vlan => $q});
|
||||
}
|
||||
else {
|
||||
$set = schema('netdisco')->resultset('DevicePort')->search({name => $q});
|
||||
}
|
||||
return unless $set->count;
|
||||
|
||||
content_type('text/html');
|
||||
template 'ajax/search/port.tt', {
|
||||
results => $set,
|
||||
}, { layout => undef };
|
||||
};
|
||||
|
||||
get '/search' => sub {
|
||||
my $q = param('q');
|
||||
if (not param('tab')) {
|
||||
if (not $q) {
|
||||
redirect uri_for('/');
|
||||
}
|
||||
|
||||
# pick most likely tab for initial results
|
||||
if ($q =~ m/^\d+$/) {
|
||||
params->{'tab'} = 'vlan';
|
||||
}
|
||||
else {
|
||||
my $s = schema('netdisco');
|
||||
if ($q =~ m{^[a-f0-9.:/]+$}i) {
|
||||
my $ip = NetAddr::IP::Lite->new($q);
|
||||
my $nd = $s->resultset('Device')->search_by_field({ip => $q});
|
||||
if ($ip and $nd->count) {
|
||||
if ($nd->count == 1) {
|
||||
# redirect to device details for the one device
|
||||
redirect uri_for('/device',
|
||||
{tab => 'details', q => $q, f => ''});
|
||||
}
|
||||
params->{'tab'} = 'device';
|
||||
}
|
||||
else {
|
||||
# this will match for MAC addresses
|
||||
# and partial IPs (subnets?)
|
||||
params->{'tab'} = 'node';
|
||||
}
|
||||
}
|
||||
else {
|
||||
my $nd = $s->resultset('Device')->search({dns => { '-ilike' => "\%$q\%" }});
|
||||
if ($nd->count) {
|
||||
if ($nd->count == 1) {
|
||||
# redirect to device details for the one device
|
||||
redirect uri_for('/device',
|
||||
{tab => 'details', q => $nd->first->ip, f => ''});
|
||||
}
|
||||
params->{'tab'} = 'device';
|
||||
}
|
||||
elsif ($s->resultset('DevicePort')
|
||||
->search({name => "\%$q\%"})->count) {
|
||||
params->{'tab'} = 'port';
|
||||
}
|
||||
}
|
||||
params->{'tab'} ||= 'node';
|
||||
}
|
||||
}
|
||||
|
||||
# used in the device search sidebar to populate select inputs
|
||||
var('model_list' => [
|
||||
schema('netdisco')->resultset('Device')->get_distinct_col('model')
|
||||
]);
|
||||
var('os_ver_list' => [
|
||||
schema('netdisco')->resultset('Device')->get_distinct_col('os_ver')
|
||||
]);
|
||||
var('vendor_list' => [
|
||||
schema('netdisco')->resultset('Device')->get_distinct_col('vendor')
|
||||
]);
|
||||
|
||||
# list of tabs
|
||||
var('tabs' => [
|
||||
{ id => 'device', label => 'Device' },
|
||||
{ id => 'node', label => 'Node' },
|
||||
{ id => 'vlan', label => 'VLAN' },
|
||||
{ id => 'port', label => 'Port' },
|
||||
]);
|
||||
|
||||
template 'search';
|
||||
};
|
||||
|
||||
true;
|
||||
Reference in New Issue
Block a user