#325 significant speed-up to Device > Ports tab (thx to T. Teräs)

This commit is contained in:
Oliver Gorwits
2017-07-09 10:03:52 +01:00
parent 46c0b6b6e0
commit 4e5b544b9c
6 changed files with 69 additions and 69 deletions

View File

@@ -4,6 +4,7 @@
* Documentation note on OS upgrade * Documentation note on OS upgrade
* #324 use a (better) host group for internal localnet filter * #324 use a (better) host group for internal localnet filter
* #325 significant speed-up to Device > Ports tab (thx to T. Teräs)
2.036005 - 2017-07-05 2.036005 - 2017-07-05

View File

@@ -91,26 +91,11 @@ __PACKAGE__->belongs_to( device => 'App::Netdisco::DB::Result::Device', 'ip' );
Returns the set of C<device_port_vlan> entries associated with this Port. Returns the set of C<device_port_vlan> entries associated with this Port.
These will be both tagged and untagged. Use this relation in search conditions. These will be both tagged and untagged. Use this relation in search conditions.
See also C<all_port_vlans>.
=cut =cut
__PACKAGE__->has_many( port_vlans => 'App::Netdisco::DB::Result::DevicePortVlan', __PACKAGE__->has_many( port_vlans => 'App::Netdisco::DB::Result::DevicePortVlan',
{ 'foreign.ip' => 'self.ip', 'foreign.port' => 'self.port' } ); { 'foreign.ip' => 'self.ip', 'foreign.port' => 'self.port' } );
=head2 all_port_vlans
Returns the set of C<device_port_vlan> entries associated with this Port.
These will be both tagged and untagged. Use this relation when prefetching related
C<device_port_vlan> rows.
See also C<port_vlans>.
=cut
__PACKAGE__->has_many( all_port_vlans => 'App::Netdisco::DB::Result::DevicePortVlan',
{ 'foreign.ip' => 'self.ip', 'foreign.port' => 'self.port' } );
=head2 nodes / active_nodes / nodes_with_age / active_nodes_with_age =head2 nodes / active_nodes / nodes_with_age / active_nodes_with_age
Returns the set of Nodes whose MAC addresses are associated with this Device Returns the set of Nodes whose MAC addresses are associated with this Device
@@ -241,10 +226,10 @@ __PACKAGE__->belongs_to( neighbor_alias => 'App::Netdisco::DB::Result::DeviceIp'
sub { sub {
my $args = shift; my $args = shift;
return { return {
"$args->{foreign_alias}.ip" => { '=' => "$args->{foreign_alias}.alias" => { '=' =>
$args->{self_resultsource}->schema->resultset('DeviceIp') $args->{self_resultsource}->schema->resultset('DeviceIp')
->search({alias => { -ident => "$args->{self_alias}.remote_ip"}}, ->search({alias => { -ident => "$args->{self_alias}.remote_ip"}},
{rows => 1, columns => 'ip', alias => 'devipsub'})->as_query } {rows => 1, columns => 'alias', alias => 'devipsub'})->as_query }
}; };
}, },
{ join_type => 'LEFT' }, { join_type => 'LEFT' },
@@ -252,7 +237,7 @@ __PACKAGE__->belongs_to( neighbor_alias => 'App::Netdisco::DB::Result::DeviceIp'
=head2 vlans =head2 vlans
As compared to C<port_vlans>, this relationship returns a set of VLAN As compared to C<port_vlans>, this relationship returns a set of Device VLAN
row objects for the VLANs on the given port, which might be more useful if you row objects for the VLANs on the given port, which might be more useful if you
want to find out details such as the VLAN name. want to find out details such as the VLAN name.
@@ -260,7 +245,7 @@ See also C<vlan_count>.
=cut =cut
__PACKAGE__->many_to_many( vlans => 'all_port_vlans', 'vlan' ); __PACKAGE__->many_to_many( vlans => 'port_vlans', 'vlan' );
=head2 oui =head2 oui

View File

@@ -96,7 +96,7 @@ sub search_aliases {
{ {
order_by => [qw/ me.dns me.ip /], order_by => [qw/ me.dns me.ip /],
join => 'device_ips', join => 'device_ips',
distinct => 1, group_by => 'me.ip',
} }
); );
} }

View File

@@ -113,7 +113,32 @@ get '/ajax/content/device/ports' => require_login sub {
$set = $set->search({-or => \@combi}); $set = $set->search({-or => \@combi});
} }
# get aggregate master status # so far only the basic device_port data
# now begin to join tables depending on the selected columns/options
# get vlans on the port
# leave this query dormant (lazy) unless c_vmember is set
my $vlans = $set->search({}, {
select => [
'port',
{ array_agg => 'port_vlans.vlan', -as => 'vlan_set' },
{ count => 'port_vlans.vlan', -as => 'vlan_count' },
],
join => 'port_vlans',
group_by => 'me.port',
});
if (param('c_vmember')) {
$vlans = { map {(
$_->port => {
# DBIC smart enough to work out this should be an arrayref :)
vlan_set => $_->get_column('vlan_set'),
vlan_count => $_->get_column('vlan_count'),
},
)} $vlans->all };
}
# get aggregate master status (self join)
$set = $set->search({}, { $set = $set->search({}, {
'join' => 'agg_master', 'join' => 'agg_master',
'+select' => [qw/agg_master.up_admin agg_master.up/], '+select' => [qw/agg_master.up_admin agg_master.up/],
@@ -123,17 +148,6 @@ get '/ajax/content/device/ports' => require_login sub {
# make sure query asks for formatted timestamps when needed # make sure query asks for formatted timestamps when needed
$set = $set->with_times if param('c_lastchange'); $set = $set->with_times if param('c_lastchange');
# get vlans on the port, if there aren't too many
my $port_cnt = $device->ports->count() || 1;
my $vlan_cnt = $device->port_vlans->count() || 1;
my $vmember_ok =
(($vlan_cnt / $port_cnt) <= setting('devport_vlan_limit'));
if ($vmember_ok) {
$set = $set->search_rs({}, { prefetch => 'all_port_vlans' })->with_vlan_count
if param('c_vmember');
}
# what kind of nodes are we interested in? # what kind of nodes are we interested in?
my $nodes_name = (param('n_archived') ? 'nodes' : 'active_nodes'); my $nodes_name = (param('n_archived') ? 'nodes' : 'active_nodes');
$nodes_name .= '_with_age' if param('n_age'); $nodes_name .= '_with_age' if param('n_age');
@@ -144,28 +158,35 @@ get '/ajax/content/device/ports' => require_login sub {
if (param('c_nodes')) { if (param('c_nodes')) {
# retrieve active/all connected nodes, if asked for # retrieve active/all connected nodes, if asked for
$set = $set->search_rs({}, { prefetch => [{$nodes_name => $ips_name}] }); $set = $set->search({}, { prefetch => [{$nodes_name => $ips_name}] });
$set = $set->search_rs({}, { order_by => ["${nodes_name}.vlan", "${nodes_name}.mac", "${ips_name}.ip"] }); $set = $set->search({}, { order_by => ["${nodes_name}.vlan", "${nodes_name}.mac", "${ips_name}.ip"] });
# retrieve wireless SSIDs, if asked for # retrieve wireless SSIDs, if asked for
$set = $set->search_rs({}, { prefetch => [{$nodes_name => 'wireless'}] }) $set = $set->search({}, { prefetch => [{$nodes_name => 'wireless'}] })
if param('n_ssid'); if param('n_ssid');
# retrieve NetBIOS, if asked for # retrieve NetBIOS, if asked for
$set = $set->search_rs({}, { prefetch => [{$nodes_name => 'netbios'}] }) $set = $set->search({}, { prefetch => [{$nodes_name => 'netbios'}] })
if param('n_netbios'); if param('n_netbios');
# retrieve vendor, if asked for # retrieve vendor, if asked for
$set = $set->search_rs({}, { prefetch => [{$nodes_name => 'oui'}] }) $set = $set->search({}, { prefetch => [{$nodes_name => 'oui'}] })
if param('n_vendor'); if param('n_vendor');
} }
# retrieve SSID, if asked for # retrieve SSID, if asked for
$set = $set->search({}, { prefetch => 'ssid' }) if param('c_ssid'); $set = $set->search({}, { prefetch => 'ssid' })
if param('c_ssid');
# retrieve neighbor devices, if asked for # retrieve neighbor devices, if asked for
$set = $set->search_rs({}, { prefetch => [{neighbor_alias => 'device'}] }) #$set = $set->search({}, { prefetch => [{neighbor_alias => 'device'}] })
if param('c_neighbors'); # if param('c_neighbors');
# retrieve neighbor devices, if asked for
$set = $set->search({}, {
join => 'neighbor_alias',
'+select' => ['neighbor_alias.ip', 'neighbor_alias.dns'],
'+as' => ['neighbor_ip', 'neighbor_dns'],
}) if param('c_neighbors');
# sort ports (empty set would be a 'no records' msg) # 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 ]; my $results = [ sort { &App::Netdisco::Util::Web::sort_port($a->port, $b->port) } $set->all ];
@@ -177,7 +198,7 @@ get '/ajax/content/device/ports' => require_login sub {
nodes => $nodes_name, nodes => $nodes_name,
ips => $ips_name, ips => $ips_name,
device => $device, device => $device,
vmember_ok => $vmember_ok, vlans => $vlans,
}, { layout => undef }; }, { layout => undef };
} }
else { else {
@@ -187,6 +208,7 @@ get '/ajax/content/device/ports' => require_login sub {
nodes => $nodes_name, nodes => $nodes_name,
ips => $ips_name, ips => $ips_name,
device => $device, device => $device,
vlans => $vlans,
}, { layout => undef }; }, { layout => undef };
} }
}; };

View File

@@ -19,11 +19,12 @@
</thead> </thead>
<tbody> <tbody>
[% FOREACH row IN results %] [% FOREACH row IN results %]
[% SET portname = row.port %]
<tr> <tr>
<td class="nd_center-cell nd_devport-icon"> <td class="nd_center-cell nd_devport-icon">
[% IF row.up_admin != 'up' %] [% IF row.up_admin != 'up' %]
<i class="icon-remove"></i> <i class="icon-remove"></i>
[% ELSIF row.up == 'up' AND row.stp == 'blocking' AND row.vlan_count < 2 %] [% ELSIF row.up == 'up' AND row.stp == 'blocking' AND vlans.$portname.vlan_count < 2 %]
<i class="icon-fullscreen text-info"></i> <i class="icon-fullscreen text-info"></i>
[% ELSIF row.has_column_loaded('is_free') AND row.is_free %] [% ELSIF row.has_column_loaded('is_free') AND row.is_free %]
<i class="icon-arrow-down text-success"></i> <i class="icon-arrow-down text-success"></i>
@@ -190,27 +191,23 @@
[% IF params.c_vmember %] [% IF params.c_vmember %]
<td> <td>
[% IF vmember_ok %] [% IF vlans.$portname.vlan_count <= settings.devport_vlan_limit %]
[% IF row.vlan_count %]
[% SET output = '' %] [% SET output = '' %]
[% SET vlanlist = [] %] [% FOREACH vlan IN vlans.$portname.vlan_set.nsort %]
[% FOREACH vlan IN row.all_port_vlans %][% vlanlist.push(vlan.get_column('vlan')) %][% END %]
[% FOREACH vlan IN vlanlist.nsort %]
[% SET output = output _ [% SET output = output _
'<a href="' _ uri_for('/search') _ '?tab=vlan&q=' _ vlan _ '">' _ vlan _ '</a>' %] '<a href="' _ uri_for('/search') _ '?tab=vlan&q=' _ vlan _ '">' _ vlan _ '</a>' %]
[% SET output = output _ ', ' IF NOT loop.last %] [% SET output = output _ ', ' IF NOT loop.last %]
[% END %] [% END %]
[% IF row.vlan_count > 10 %] [%# TODO make this a settable variable %] [% IF vlans.$portname.vlan_count > 10 %] [%# TODO make this a settable variable %]
[% SET output = '<div class="nd_vlan-total">(' _ row.vlan_count [% SET output = '<div class="nd_vlan-total">(' _ vlans.$portname.vlan_count
_ ')</div><span class="nd_linkcell nd_collapse-vlans"> _ ')</div><span class="nd_linkcell nd_collapse-vlans">
<div class="nd_arrow-up-down-left icon-chevron-up icon-large"></div>Show VLANs</span> <div class="nd_arrow-up-down-left icon-chevron-up icon-large"></div>Show VLANs</span>
<div class="nd_collapsing nd_collapse-pre-hidden">' _ output %] <div class="nd_collapsing nd_collapse-pre-hidden">' _ output %]
[% SET output = output _ '</div>' %] [% SET output = output _ '</div>' %]
[% END %] [% END %]
[% output %] [% output %]
[% END %]
[% ELSE %] [% ELSE %]
<i class="icon-asterisk"></i> (too many to list) <i class="icon-asterisk text-warning"></i> ([% vlans.$portname.vlan_count %] is too many to list)
[% END %] [% END %]
</td> </td>
[% END %] [% END %]
@@ -264,18 +261,18 @@
[% IF params.c_nodes OR params.c_neighbors %] [% IF params.c_nodes OR params.c_neighbors %]
<td> <td>
[% IF params.c_neighbors AND (row.remote_ip OR row.is_uplink) %] [% IF params.c_neighbors AND (row.remote_ip OR row.is_uplink) %]
[% IF row.neighbor %] [% IF row.get_column('neighbor_ip') %]
<i class="icon-link[% ' text-warning' IF row.manual_topo %]"></i> <i class="icon-link[% ' text-warning' IF row.manual_topo %]"></i>
[% IF row.remote_type AND row.remote_type.match('(?i)ip.phone') %] [% IF row.remote_type AND row.remote_type.match('(?i)ip.phone') %]
<i class="icon-phone"></i>&nbsp; <i class="icon-phone"></i>&nbsp;
[% ELSIF row.remote_type AND row.remote_type.match('^AP:\s') %] [% ELSIF row.remote_type AND row.remote_type.match('^AP:\s') %]
<i class="icon-signal"></i>&nbsp; <i class="icon-signal"></i>&nbsp;
[% END %] [% END %]
<a href="[% uri_for('/device', self_options) %]&q=[% row.neighbor.ip | uri %]"> <a href="[% uri_for('/device', self_options) %]&q=[% row.get_column('neighbor_ip') | uri %]">
[% row.neighbor.dns.remove(settings.domain_suffix) || row.neighbor.ip | html_entity %]</a> [% row.get_column('neighbor_dns').remove(settings.domain_suffix) || row.get_column('neighbor_ip') | html_entity %]</a>
[% IF row.remote_port %] [% IF row.remote_port %]
- -
<a href="[% uri_for('/device', self_options) %]&q=[% row.neighbor.ip | uri %]&f=[% row.remote_port | uri %]&prefer=port"> <a href="[% uri_for('/device', self_options) %]&q=[% row.get_column('neighbor_ip') | uri %]&f=[% row.remote_port | uri %]&prefer=port">
[% row.remote_port | html_entity %]</a> [% row.remote_port | html_entity %]</a>
[% END %] [% END %]
<br/> <br/>

View File

@@ -104,18 +104,13 @@
[% END %] [% END %]
[% IF params.c_vmember %] [% IF params.c_vmember %]
[% IF row.vlan_count %] [% SET portname = row.port %]
[% SET output = '' %] [% SET output = '' %]
[% SET vlanlist = [] %] [% FOREACH vlan IN vlans.$portname.vlan_set.nsort %]
[% FOREACH vlan IN row.all_port_vlans %][% vlanlist.push(vlan.get_column('vlan')) %][% END %]
[% FOREACH vlan IN vlanlist.nsort %]
[% SET output = output _ ',' IF NOT loop.first %] [% SET output = output _ ',' IF NOT loop.first %]
[% SET output = output _ vlan %] [% SET output = output _ vlan %]
[% END %] [% END %]
[% myport.push(output) %] [% myport.push(output) %]
[% ELSE %]
[% myport.push('') %]
[% END %]
[% END %] [% END %]
[% IF params.c_power %] [% IF params.c_power %]
@@ -139,9 +134,9 @@
[% IF params.c_neighbors %] [% IF params.c_neighbors %]
[% IF (row.remote_ip OR row.is_uplink) %] [% IF (row.remote_ip OR row.is_uplink) %]
[% IF row.neighbor %] [% IF row.get_column('neighbor_ip') %]
[% myport.push( row.neighbor.ip ) %] [% myport.push( row.get_column('neighbor_ip') ) %]
[% myport.push( row.neighbor.dns.remove(settings.domain_suffix) ) %] [% myport.push( row.get_column('neighbor_dns').remove(settings.domain_suffix) ) %]
[% ELSIF row.remote_ip AND row.remote_port %] [% ELSIF row.remote_ip AND row.remote_port %]
[% myport.push( row.remote_ip ) %] [% myport.push( row.remote_ip ) %]
[% myport.push('') %] [% myport.push('') %]