improve efficiency of general case device ports list
This commit is contained in:
148
Netdisco/lib/Netdisco/DB/Result/ActiveNode.pm
Normal file
148
Netdisco/lib/Netdisco/DB/Result/ActiveNode.pm
Normal file
@@ -0,0 +1,148 @@
|
|||||||
|
use utf8;
|
||||||
|
package Netdisco::DB::Result::ActiveNode;
|
||||||
|
|
||||||
|
use strict;
|
||||||
|
use warnings;
|
||||||
|
|
||||||
|
use base 'DBIx::Class::Core';
|
||||||
|
__PACKAGE__->table_class('DBIx::Class::ResultSource::View');
|
||||||
|
|
||||||
|
__PACKAGE__->table("active_node");
|
||||||
|
__PACKAGE__->result_source_instance->is_virtual(1);
|
||||||
|
__PACKAGE__->result_source_instance->view_definition(
|
||||||
|
'SELECT * FROM node WHERE active'
|
||||||
|
);
|
||||||
|
|
||||||
|
__PACKAGE__->add_columns(
|
||||||
|
"mac",
|
||||||
|
{ data_type => "macaddr", is_nullable => 0 },
|
||||||
|
"switch",
|
||||||
|
{ data_type => "inet", is_nullable => 0 },
|
||||||
|
"port",
|
||||||
|
{ data_type => "text", is_nullable => 0 },
|
||||||
|
"active",
|
||||||
|
{ data_type => "boolean", is_nullable => 1 },
|
||||||
|
"oui",
|
||||||
|
{ data_type => "varchar", is_nullable => 1, size => 8 },
|
||||||
|
"time_first",
|
||||||
|
{
|
||||||
|
data_type => "timestamp",
|
||||||
|
default_value => \"current_timestamp",
|
||||||
|
is_nullable => 1,
|
||||||
|
original => { default_value => \"now()" },
|
||||||
|
},
|
||||||
|
"time_recent",
|
||||||
|
{
|
||||||
|
data_type => "timestamp",
|
||||||
|
default_value => \"current_timestamp",
|
||||||
|
is_nullable => 1,
|
||||||
|
original => { default_value => \"now()" },
|
||||||
|
},
|
||||||
|
"time_last",
|
||||||
|
{
|
||||||
|
data_type => "timestamp",
|
||||||
|
default_value => \"current_timestamp",
|
||||||
|
is_nullable => 1,
|
||||||
|
original => { default_value => \"now()" },
|
||||||
|
},
|
||||||
|
);
|
||||||
|
__PACKAGE__->set_primary_key("mac", "switch", "port");
|
||||||
|
|
||||||
|
|
||||||
|
=head1 RELATIONSHIPS
|
||||||
|
|
||||||
|
=head2 device
|
||||||
|
|
||||||
|
Returns the single C<device> to which this Node entry was associated at the
|
||||||
|
time of discovery.
|
||||||
|
|
||||||
|
The JOIN is of type LEFT, in case the C<device> is no longer present in the
|
||||||
|
database but the relation is being used in C<search()>.
|
||||||
|
|
||||||
|
=cut
|
||||||
|
|
||||||
|
__PACKAGE__->belongs_to( device => 'Netdisco::DB::Result::Device',
|
||||||
|
{ 'foreign.ip' => 'self.switch' }, { join_type => 'LEFT' } );
|
||||||
|
|
||||||
|
=head2 device_port
|
||||||
|
|
||||||
|
Returns the single C<device_port> to which this Node entry was associated at
|
||||||
|
the time of discovery.
|
||||||
|
|
||||||
|
The JOIN is of type LEFT, in case the C<device> is no longer present in the
|
||||||
|
database but the relation is being used in C<search()>.
|
||||||
|
|
||||||
|
=cut
|
||||||
|
|
||||||
|
# device port may have been deleted (reconfigured modules?) but node remains
|
||||||
|
__PACKAGE__->belongs_to( device_port => 'Netdisco::DB::Result::DevicePort',
|
||||||
|
{ 'foreign.ip' => 'self.switch', 'foreign.port' => 'self.port' },
|
||||||
|
{ join_type => 'LEFT' }
|
||||||
|
);
|
||||||
|
|
||||||
|
=head2 ips
|
||||||
|
|
||||||
|
Returns the set of C<node_ip> entries associated with this Node. That is, the
|
||||||
|
IP addresses which this MAC address was hosting at the time of discovery.
|
||||||
|
|
||||||
|
Note that the Active status of the returned IP entries will all be the same as
|
||||||
|
the current Node's.
|
||||||
|
|
||||||
|
=cut
|
||||||
|
|
||||||
|
__PACKAGE__->has_many( ips => 'Netdisco::DB::Result::NodeIp',
|
||||||
|
{ 'foreign.mac' => 'self.mac', 'foreign.active' => 'self.active' } );
|
||||||
|
|
||||||
|
=head2 oui
|
||||||
|
|
||||||
|
Returns the C<oui> table entry matching this Node. You can then join on this
|
||||||
|
relation and retrieve the Company name from the related table.
|
||||||
|
|
||||||
|
The JOIN is of type LEFT, in case the OUI table has not been populated.
|
||||||
|
|
||||||
|
=cut
|
||||||
|
|
||||||
|
__PACKAGE__->belongs_to( oui => 'Netdisco::DB::Result::Oui', 'oui',
|
||||||
|
{ join_type => 'LEFT' } );
|
||||||
|
|
||||||
|
=head1 ADDITIONAL COLUMNS
|
||||||
|
|
||||||
|
=head2 time_first_stamp
|
||||||
|
|
||||||
|
Formatted version of the C<time_first> field, accurate to the minute.
|
||||||
|
|
||||||
|
The format is somewhat like ISO 8601 or RFC3339 but without the middle C<T>
|
||||||
|
between the date stamp and time stamp. That is:
|
||||||
|
|
||||||
|
2012-02-06 12:49
|
||||||
|
|
||||||
|
=cut
|
||||||
|
|
||||||
|
sub time_first_stamp { return (shift)->get_column('time_first_stamp') }
|
||||||
|
|
||||||
|
=head2 time_last_stamp
|
||||||
|
|
||||||
|
Formatted version of the C<time_last> field, accurate to the minute.
|
||||||
|
|
||||||
|
The format is somewhat like ISO 8601 or RFC3339 but without the middle C<T>
|
||||||
|
between the date stamp and time stamp. That is:
|
||||||
|
|
||||||
|
2012-02-06 12:49
|
||||||
|
|
||||||
|
=cut
|
||||||
|
|
||||||
|
sub time_last_stamp { return (shift)->get_column('time_last_stamp') }
|
||||||
|
|
||||||
|
=head2 time_last_age
|
||||||
|
|
||||||
|
Formatted version of the C<time_last> field, accurate to the minute.
|
||||||
|
|
||||||
|
The format is in "X days/months/years" style, similar to:
|
||||||
|
|
||||||
|
1 year 4 months 05:46:00
|
||||||
|
|
||||||
|
=cut
|
||||||
|
|
||||||
|
sub time_last_age { return (shift)->get_column('time_last_age') }
|
||||||
|
|
||||||
|
1;
|
||||||
@@ -77,11 +77,7 @@ __PACKAGE__->belongs_to( device => 'Netdisco::DB::Result::Device', 'ip');
|
|||||||
=head2 nodes
|
=head2 nodes
|
||||||
|
|
||||||
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
|
||||||
Port.
|
Port. See C<active_nodes()> to find only the active Nodes, instead.
|
||||||
|
|
||||||
Remember you can pass a filter to this method to find only active or inactive
|
|
||||||
nodes, but do take into account that both the C<node> and C<node_ip> tables
|
|
||||||
include independent C<active> fields.
|
|
||||||
|
|
||||||
=over 4
|
=over 4
|
||||||
|
|
||||||
@@ -91,11 +87,6 @@ Rows returned are sorted by the Node MAC address.
|
|||||||
|
|
||||||
=item *
|
=item *
|
||||||
|
|
||||||
The Node's related IP addresses (that is, entries from the C<node_ip> table)
|
|
||||||
will also be retrieved.
|
|
||||||
|
|
||||||
=item *
|
|
||||||
|
|
||||||
The additional column C<time_last_age> is a preformatted value for the Node's
|
The additional column C<time_last_age> is a preformatted value for the Node's
|
||||||
C<time_last> field, which reads as "X days/weeks/months/years".
|
C<time_last> field, which reads as "X days/weeks/months/years".
|
||||||
|
|
||||||
@@ -108,15 +99,35 @@ __PACKAGE__->has_many( nodes => 'Netdisco::DB::Result::Node',
|
|||||||
'foreign.switch' => 'self.ip',
|
'foreign.switch' => 'self.ip',
|
||||||
'foreign.port' => 'self.port',
|
'foreign.port' => 'self.port',
|
||||||
},
|
},
|
||||||
|
{ join_type => 'LEFT' },
|
||||||
|
);
|
||||||
|
|
||||||
|
=head2 active_nodes
|
||||||
|
|
||||||
|
Returns the set of I<active> Nodes whose MAC addresses are associated with
|
||||||
|
this Device Port. See C<nodes()> to find all Nodes (active and inactive).
|
||||||
|
|
||||||
|
=over 4
|
||||||
|
|
||||||
|
=item *
|
||||||
|
|
||||||
|
Rows returned are sorted by the Node MAC address.
|
||||||
|
|
||||||
|
=item *
|
||||||
|
|
||||||
|
The additional column C<time_last_age> is a preformatted value for the Node's
|
||||||
|
C<time_last> field, which reads as "X days/weeks/months/years".
|
||||||
|
|
||||||
|
=back
|
||||||
|
|
||||||
|
=cut
|
||||||
|
|
||||||
|
__PACKAGE__->has_many( active_nodes => 'Netdisco::DB::Result::ActiveNode',
|
||||||
{
|
{
|
||||||
prefetch => 'ips',
|
'foreign.switch' => 'self.ip',
|
||||||
order_by => 'me.mac',
|
'foreign.port' => 'self.port',
|
||||||
'+select' => [
|
|
||||||
\"replace(age(date_trunc('minute',
|
|
||||||
me.time_last + interval '30 second'))::text, 'mon', 'month')",
|
|
||||||
],
|
|
||||||
'+as' => [ 'me.time_last_age' ],
|
|
||||||
},
|
},
|
||||||
|
{ join_type => 'LEFT' },
|
||||||
);
|
);
|
||||||
|
|
||||||
=head2 neighbor_alias
|
=head2 neighbor_alias
|
||||||
@@ -139,19 +150,16 @@ __PACKAGE__->belongs_to( neighbor_alias => 'Netdisco::DB::Result::DeviceIp',
|
|||||||
=head2 port_vlans_tagged
|
=head2 port_vlans_tagged
|
||||||
|
|
||||||
Returns a set of rows from the C<device_port_vlan> table relating to this
|
Returns a set of rows from the C<device_port_vlan> table relating to this
|
||||||
port, where the VLANs are all tagged. See also the C<native_port_vlan>
|
port, where the VLANs are all tagged.
|
||||||
relationship.
|
|
||||||
|
|
||||||
=cut
|
=cut
|
||||||
|
|
||||||
__PACKAGE__->has_many( port_vlans_tagged => 'Netdisco::DB::Result::DevicePortVlan',
|
__PACKAGE__->has_many( port_vlans_tagged => 'Netdisco::DB::Result::DevicePortVlanTagged',
|
||||||
{
|
{
|
||||||
'foreign.ip' => 'self.ip',
|
'foreign.ip' => 'self.ip',
|
||||||
'foreign.port' => 'self.port',
|
'foreign.port' => 'self.port',
|
||||||
},
|
},
|
||||||
{
|
{ join_type => 'LEFT' },
|
||||||
where => { -not_bool => 'me.native' },
|
|
||||||
}
|
|
||||||
);
|
);
|
||||||
|
|
||||||
=head2 tagged_vlans
|
=head2 tagged_vlans
|
||||||
@@ -167,25 +175,6 @@ See also C<tagged_vlans_count>.
|
|||||||
__PACKAGE__->many_to_many( tagged_vlans => 'port_vlans_tagged', 'vlan' );
|
__PACKAGE__->many_to_many( tagged_vlans => 'port_vlans_tagged', 'vlan' );
|
||||||
|
|
||||||
|
|
||||||
=head2 native_port_vlan
|
|
||||||
|
|
||||||
Returns an entry from the C<device_port_vlan> table relating to this port,
|
|
||||||
where the VLAN is not tagged.
|
|
||||||
|
|
||||||
See also the C<native_vlan> helper method.
|
|
||||||
|
|
||||||
=cut
|
|
||||||
|
|
||||||
__PACKAGE__->might_have( native_port_vlan => 'Netdisco::DB::Result::DevicePortVlan',
|
|
||||||
{
|
|
||||||
'foreign.ip' => 'self.ip',
|
|
||||||
'foreign.port' => 'self.port',
|
|
||||||
},
|
|
||||||
{
|
|
||||||
where => { -bool => 'me.native' },
|
|
||||||
}
|
|
||||||
);
|
|
||||||
|
|
||||||
=head2 oui
|
=head2 oui
|
||||||
|
|
||||||
Returns the C<oui> table entry matching this Port. You can then join on this
|
Returns the C<oui> table entry matching this Port. You can then join on this
|
||||||
@@ -224,32 +213,6 @@ sub neighbor {
|
|||||||
return eval { $row->neighbor_alias->device || undef };
|
return eval { $row->neighbor_alias->device || undef };
|
||||||
}
|
}
|
||||||
|
|
||||||
=head2 native_vlan
|
|
||||||
|
|
||||||
This is a convenience method to be used instead of the C<native_port_vlan>
|
|
||||||
relationship described above.
|
|
||||||
|
|
||||||
Whereas the C<native_port_vlan> relation returns the entire row from the
|
|
||||||
C<device_port_vlan> table, this helper returns the VLAN number itself from
|
|
||||||
that row - probably the thing you actually want in the end.
|
|
||||||
|
|
||||||
=cut
|
|
||||||
|
|
||||||
sub native_vlan {
|
|
||||||
my $row = shift;
|
|
||||||
return eval { $row->native_port_vlan->vlan || undef };
|
|
||||||
};
|
|
||||||
|
|
||||||
=head2 tagged_vlans_count
|
|
||||||
|
|
||||||
Returns the number of tagged VLANs active on this device port.
|
|
||||||
|
|
||||||
=cut
|
|
||||||
|
|
||||||
sub tagged_vlans_count {
|
|
||||||
return (shift)->tagged_vlans->count;
|
|
||||||
}
|
|
||||||
|
|
||||||
=head2 is_free( $quantity, $unit )
|
=head2 is_free( $quantity, $unit )
|
||||||
|
|
||||||
This method can be used to evaluate whether a device port could be considered
|
This method can be used to evaluate whether a device port could be considered
|
||||||
@@ -290,9 +253,19 @@ sub is_free {
|
|||||||
|
|
||||||
=head1 ADDITIONAL COLUMNS
|
=head1 ADDITIONAL COLUMNS
|
||||||
|
|
||||||
|
=head2 tagged_vlans_count
|
||||||
|
|
||||||
|
Returns the number of tagged VLANs active on this device port. Enable this
|
||||||
|
column by applying the C<with_vlan_count()> modifier to C<search()>.
|
||||||
|
|
||||||
|
=cut
|
||||||
|
|
||||||
|
sub tagged_vlans_count { return (shift)->get_column('tagged_vlans_count') }
|
||||||
|
|
||||||
=head2 lastchange_stamp
|
=head2 lastchange_stamp
|
||||||
|
|
||||||
Formatted version of the C<lastchange> field, accurate to the minute.
|
Formatted version of the C<lastchange> field, accurate to the minute. Enable
|
||||||
|
this column by applying the C<with_vlan_count()> modifier to C<search()>.
|
||||||
|
|
||||||
The format is somewhat like ISO 8601 or RFC3339 but without the middle C<T>
|
The format is somewhat like ISO 8601 or RFC3339 but without the middle C<T>
|
||||||
between the date stamp and time stamp. That is:
|
between the date stamp and time stamp. That is:
|
||||||
|
|||||||
81
Netdisco/lib/Netdisco/DB/Result/DevicePortVlanTagged.pm
Normal file
81
Netdisco/lib/Netdisco/DB/Result/DevicePortVlanTagged.pm
Normal file
@@ -0,0 +1,81 @@
|
|||||||
|
use utf8;
|
||||||
|
package Netdisco::DB::Result::DevicePortVlanTagged;
|
||||||
|
|
||||||
|
# Created by DBIx::Class::Schema::Loader
|
||||||
|
# DO NOT MODIFY THE FIRST PART OF THIS FILE
|
||||||
|
|
||||||
|
use strict;
|
||||||
|
use warnings;
|
||||||
|
|
||||||
|
use base 'DBIx::Class::Core';
|
||||||
|
__PACKAGE__->table_class('DBIx::Class::ResultSource::View');
|
||||||
|
|
||||||
|
__PACKAGE__->table("device_port_vlan_tagged");
|
||||||
|
__PACKAGE__->result_source_instance->is_virtual(1);
|
||||||
|
__PACKAGE__->result_source_instance->view_definition(
|
||||||
|
'SELECT * FROM device_port_vlan WHERE NOT native'
|
||||||
|
);
|
||||||
|
|
||||||
|
__PACKAGE__->add_columns(
|
||||||
|
"ip",
|
||||||
|
{ data_type => "inet", is_nullable => 0 },
|
||||||
|
"port",
|
||||||
|
{ data_type => "text", is_nullable => 0 },
|
||||||
|
"vlan",
|
||||||
|
{ data_type => "integer", is_nullable => 0 },
|
||||||
|
"native",
|
||||||
|
{ data_type => "boolean", default_value => \"false", is_nullable => 0 },
|
||||||
|
"creation",
|
||||||
|
{
|
||||||
|
data_type => "timestamp",
|
||||||
|
default_value => \"current_timestamp",
|
||||||
|
is_nullable => 1,
|
||||||
|
original => { default_value => \"now()" },
|
||||||
|
},
|
||||||
|
"last_discover",
|
||||||
|
{
|
||||||
|
data_type => "timestamp",
|
||||||
|
default_value => \"current_timestamp",
|
||||||
|
is_nullable => 1,
|
||||||
|
original => { default_value => \"now()" },
|
||||||
|
},
|
||||||
|
);
|
||||||
|
__PACKAGE__->set_primary_key("ip", "port", "vlan");
|
||||||
|
|
||||||
|
|
||||||
|
# Created by DBIx::Class::Schema::Loader v0.07015 @ 2012-01-07 14:20:02
|
||||||
|
# DO NOT MODIFY THIS OR ANYTHING ABOVE! md5sum:/3KLjJ3D18pGaPEaw9EU5w
|
||||||
|
|
||||||
|
=head1 RELATIONSHIPS
|
||||||
|
|
||||||
|
=head2 device
|
||||||
|
|
||||||
|
Returns the entry from the C<device> table which hosts the Port on which this
|
||||||
|
VLAN is configured.
|
||||||
|
|
||||||
|
=cut
|
||||||
|
|
||||||
|
__PACKAGE__->belongs_to( device => 'Netdisco::DB::Result::Device', 'ip' );
|
||||||
|
|
||||||
|
=head2 port
|
||||||
|
|
||||||
|
Returns the entry from the C<port> table on which this VLAN is configured.
|
||||||
|
|
||||||
|
=cut
|
||||||
|
|
||||||
|
__PACKAGE__->belongs_to( port => 'Netdisco::DB::Result::DevicePort', {
|
||||||
|
'foreign.ip' => 'self.ip', 'foreign.port' => 'self.port',
|
||||||
|
});
|
||||||
|
|
||||||
|
=head2 vlan
|
||||||
|
|
||||||
|
Returns the entry from the C<device_vlan> table describing this VLAN in
|
||||||
|
detail, typically in order that the C<name> can be retrieved.
|
||||||
|
|
||||||
|
=cut
|
||||||
|
|
||||||
|
__PACKAGE__->belongs_to( vlan => 'Netdisco::DB::Result::DeviceVlan', {
|
||||||
|
'foreign.ip' => 'self.ip', 'foreign.vlan' => 'self.vlan',
|
||||||
|
});
|
||||||
|
|
||||||
|
1;
|
||||||
64
Netdisco/lib/Netdisco/DB/ResultSet/ActiveNode.pm
Normal file
64
Netdisco/lib/Netdisco/DB/ResultSet/ActiveNode.pm
Normal file
@@ -0,0 +1,64 @@
|
|||||||
|
package Netdisco::DB::ResultSet::ActiveNode;
|
||||||
|
use base 'DBIx::Class::ResultSet';
|
||||||
|
|
||||||
|
use strict;
|
||||||
|
use warnings FATAL => 'all';
|
||||||
|
|
||||||
|
=head1 search_by_mac( \%cond, \%attrs? )
|
||||||
|
|
||||||
|
my $set = $rs->search_by_mac({mac => '00:11:22:33:44:55', active => 1});
|
||||||
|
|
||||||
|
Like C<search()>, this returns a ResultSet of matching rows from the Node
|
||||||
|
table.
|
||||||
|
|
||||||
|
=over 4
|
||||||
|
|
||||||
|
=item *
|
||||||
|
|
||||||
|
The C<cond> parameter must be a hashref containing a key C<mac> with
|
||||||
|
the value to search for.
|
||||||
|
|
||||||
|
=item *
|
||||||
|
|
||||||
|
Results are ordered by time last seen.
|
||||||
|
|
||||||
|
=item *
|
||||||
|
|
||||||
|
Additional columns C<time_first_stamp> and C<time_last_stamp> provide
|
||||||
|
preformatted timestamps of the C<time_first> and C<time_last> fields.
|
||||||
|
|
||||||
|
=item *
|
||||||
|
|
||||||
|
A JOIN is performed on the Device table and the Device C<dns> column
|
||||||
|
prefetched.
|
||||||
|
|
||||||
|
=back
|
||||||
|
|
||||||
|
To limit results only to active nodes, set C<< {active => 1} >> in C<cond>.
|
||||||
|
|
||||||
|
=cut
|
||||||
|
|
||||||
|
sub search_by_mac {
|
||||||
|
my ($rs, $cond, $attrs) = @_;
|
||||||
|
|
||||||
|
die "mac address required for search_by_mac\n"
|
||||||
|
if ref {} ne ref $cond or !exists $cond->{mac};
|
||||||
|
|
||||||
|
$cond->{'me.mac'} = delete $cond->{mac};
|
||||||
|
$attrs ||= {};
|
||||||
|
|
||||||
|
return $rs
|
||||||
|
->search_rs({}, {
|
||||||
|
order_by => {'-desc' => 'time_last'},
|
||||||
|
'+columns' => [qw/ device.dns /],
|
||||||
|
'+select' => [
|
||||||
|
\"to_char(time_first, 'YYYY-MM-DD HH24:MI')",
|
||||||
|
\"to_char(time_last, 'YYYY-MM-DD HH24:MI')",
|
||||||
|
],
|
||||||
|
'+as' => [qw/ time_first_stamp time_last_stamp /],
|
||||||
|
join => 'device',
|
||||||
|
})
|
||||||
|
->search($cond, $attrs);
|
||||||
|
}
|
||||||
|
|
||||||
|
1;
|
||||||
@@ -29,7 +29,7 @@ sub with_times {
|
|||||||
->search({},
|
->search({},
|
||||||
{
|
{
|
||||||
'+select' => [
|
'+select' => [
|
||||||
\"to_char(last_discover - (uptime - lastchange) / 100 * interval '1 second',
|
\"to_char(device.last_discover - (device.uptime - lastchange) / 100 * interval '1 second',
|
||||||
'YYYY-MM-DD HH24:MI:SS')",
|
'YYYY-MM-DD HH24:MI:SS')",
|
||||||
],
|
],
|
||||||
'+as' => [qw/ lastchange_stamp /],
|
'+as' => [qw/ lastchange_stamp /],
|
||||||
@@ -37,6 +37,64 @@ sub with_times {
|
|||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
|
=head2 with_node_age
|
||||||
|
|
||||||
|
This is a modifier for any C<search()> (including the helpers below) which
|
||||||
|
will add the following additional synthesized columns to the result set:
|
||||||
|
|
||||||
|
=over 4
|
||||||
|
|
||||||
|
=item $nodes.time_last_age
|
||||||
|
|
||||||
|
=back
|
||||||
|
|
||||||
|
You can pass in the table alias for the Nodes relation, which defaults to
|
||||||
|
C<nodes>.
|
||||||
|
|
||||||
|
=cut
|
||||||
|
|
||||||
|
sub with_node_age {
|
||||||
|
my ($rs, $alias) = @_;
|
||||||
|
$alias ||= 'nodes';
|
||||||
|
|
||||||
|
return $rs
|
||||||
|
->search_rs({},
|
||||||
|
{
|
||||||
|
'+select' =>
|
||||||
|
[\"replace(age(date_trunc('minute', $alias.time_last + interval '30 second'))::text, 'mon', 'month')"],
|
||||||
|
'+as' => [ "$alias.time_last_age" ],
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
=head2 with_vlan_count
|
||||||
|
|
||||||
|
This is a modifier for any C<search()> (including the helpers below) which
|
||||||
|
will add the following additional synthesized columns to the result set:
|
||||||
|
|
||||||
|
=over 4
|
||||||
|
|
||||||
|
=item tagged_vlans_count
|
||||||
|
|
||||||
|
=back
|
||||||
|
|
||||||
|
=cut
|
||||||
|
|
||||||
|
sub with_vlan_count {
|
||||||
|
my ($rs, $cond, $attrs) = @_;
|
||||||
|
$cond ||= {};
|
||||||
|
$attrs ||= {};
|
||||||
|
|
||||||
|
return $rs
|
||||||
|
->search_rs($cond, $attrs)
|
||||||
|
->search({},
|
||||||
|
{
|
||||||
|
'+select' => [ { count => 'port_vlans_tagged.vlan' } ],
|
||||||
|
'+as' => [qw/ tagged_vlans_count /],
|
||||||
|
join => 'port_vlans_tagged',
|
||||||
|
distinct => 1,
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
=head2 search_by_mac( \%cond, \%attrs? )
|
=head2 search_by_mac( \%cond, \%attrs? )
|
||||||
|
|
||||||
my $set = $rs->search_by_mac({mac => '00:11:22:33:44:55'});
|
my $set = $rs->search_by_mac({mac => '00:11:22:33:44:55'});
|
||||||
|
|||||||
@@ -75,9 +75,6 @@ ajax '/ajax/content/device/ports' => sub {
|
|||||||
my $set = schema('netdisco')->resultset('DevicePort')
|
my $set = schema('netdisco')->resultset('DevicePort')
|
||||||
->search_by_ip({ip => $ip});
|
->search_by_ip({ip => $ip});
|
||||||
|
|
||||||
# make sure query asks for formatted timestamps when needed
|
|
||||||
$set = $set->with_times if param('c_lastchange');
|
|
||||||
|
|
||||||
# refine by ports if requested
|
# refine by ports if requested
|
||||||
my $q = param('f');
|
my $q = param('f');
|
||||||
if ($q) {
|
if ($q) {
|
||||||
@@ -96,21 +93,21 @@ ajax '/ajax/content/device/ports' => sub {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
# retrieve related data for additonal table columns, if asked for
|
# make sure query asks for formatted timestamps when needed
|
||||||
$set = $set->search_rs({}, {prefetch => {nodes => 'ips'}})
|
$set = $set->with_times if param('c_lastchange');
|
||||||
if param('c_connected');
|
|
||||||
$set = $set->search_rs({}, {prefetch => {port_vlans_tagged => 'vlan'}})
|
|
||||||
if param('c_vmember');
|
|
||||||
|
|
||||||
# if active or not, control the join to Node table
|
# get number of vlans on the port to control whether to list them or not
|
||||||
if (param('n_archived')) {
|
$set = $set->with_vlan_count if param('c_vmember');
|
||||||
$set = $set->search_rs({
|
|
||||||
-or => [{-bool => 'nodes.active'}, {-not_bool => 'nodes.active'}]
|
# retrieve active/all connected nodes, and device, if asked for
|
||||||
});
|
my $nodes_name = (param('n_archived') ? 'nodes' : 'active_nodes');
|
||||||
}
|
$set = $set->search_rs({}, {
|
||||||
else {
|
prefetch => [{$nodes_name => 'ips'}, {neighbor_alias => 'device'}],
|
||||||
$set = $set->search_rs({-bool => 'nodes.active'});
|
}) if param('c_connected');
|
||||||
}
|
|
||||||
|
# add constructed node age col if requested (and showing connected)
|
||||||
|
$set = $set->with_node_age($nodes_name)
|
||||||
|
if param('c_connected') and param('n_age');
|
||||||
|
|
||||||
# sort, and filter by free ports
|
# sort, and filter by free ports
|
||||||
# the filter could be in the template but here allows a 'no records' msg
|
# the filter could be in the template but here allows a 'no records' msg
|
||||||
@@ -123,6 +120,7 @@ ajax '/ajax/content/device/ports' => sub {
|
|||||||
content_type('text/html');
|
content_type('text/html');
|
||||||
template 'ajax/device/ports.tt', {
|
template 'ajax/device/ports.tt', {
|
||||||
results => $results,
|
results => $results,
|
||||||
|
nodes => $nodes_name,
|
||||||
}, { layout => undef };
|
}, { layout => undef };
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|||||||
@@ -63,22 +63,21 @@
|
|||||||
[% END %]
|
[% END %]
|
||||||
[% IF params.c_vmember %]
|
[% IF params.c_vmember %]
|
||||||
<td>
|
<td>
|
||||||
[%# this is really ugly because for some reason
|
[% IF row.tagged_vlans_count %]
|
||||||
I could not get size/max to work on row.tagged_vlans.all %]
|
|
||||||
[% SET output = '' %]
|
[% SET output = '' %]
|
||||||
[% SET count = 0 %]
|
|
||||||
[% FOREACH vlan IN row.tagged_vlans %]
|
[% FOREACH vlan IN row.tagged_vlans %]
|
||||||
[% SET output = output _
|
[% SET output = output _
|
||||||
'<a href="' _ uri_for('/search') _ '?tab=vlan&q=' _ vlan.vlan _ '">' _ vlan.vlan _ '</a>' %]
|
'<a href="' _ uri_for('/search') _ '?tab=vlan&q=' _ vlan.vlan _ '">' _ vlan.vlan _ '</a>' %]
|
||||||
[% SET output = output _ ', ' IF NOT loop.last %]
|
[% SET output = output _ ', ' IF NOT loop.last %]
|
||||||
[% SET count = count + 1 %]
|
|
||||||
[% END %]
|
[% END %]
|
||||||
[% IF count > 10 %]
|
[% IF row.tagged_vlans_count > 10 %]
|
||||||
[% SET output = '<div class="vlan_total">(' _ count _ ')</div><a href="#" class="nd_linkcell nd_collapse_vlans">'
|
[% SET output = '<div class="vlan_total">(' _ row.tagged_vlans_count
|
||||||
|
_ ')</div><a href="#" class="nd_linkcell nd_collapse_vlans">'
|
||||||
_ 'Show VLANs</a><div class="nd_collapse_pre_hidden">' _ output %]
|
_ 'Show VLANs</a><div class="nd_collapse_pre_hidden">' _ output %]
|
||||||
[% SET output = output _ '</div>' %]
|
[% SET output = output _ '</div>' %]
|
||||||
[% END %]
|
[% END %]
|
||||||
[% output %]
|
[% output %]
|
||||||
|
[% END %]
|
||||||
</td>
|
</td>
|
||||||
[% END %]
|
[% END %]
|
||||||
[% IF params.c_connected %]
|
[% IF params.c_connected %]
|
||||||
@@ -94,7 +93,7 @@
|
|||||||
<br/> ([% row.remote_type %]) / ([% row.remote_id %])</a>
|
<br/> ([% row.remote_type %]) / ([% row.remote_id %])</a>
|
||||||
[% END %]
|
[% END %]
|
||||||
[% END %]
|
[% END %]
|
||||||
[% FOREACH node IN row.nodes %]
|
[% FOREACH node IN row.$nodes %]
|
||||||
[% '<br/>' IF row.remote_ip OR NOT loop.first %]
|
[% '<br/>' IF row.remote_ip OR NOT loop.first %]
|
||||||
[% '<span class="label warning">a</span> ' IF NOT node.active %]
|
[% '<span class="label warning">a</span> ' IF NOT node.active %]
|
||||||
<a href="[% uri_for('/search') %]?tab=node&q=[% node.mac | uri %]">[% node.mac %]</a>
|
<a href="[% uri_for('/search') %]?tab=node&q=[% node.mac | uri %]">[% node.mac %]</a>
|
||||||
|
|||||||
Reference in New Issue
Block a user