From 4d9f16db3a41a154ddd1f7b9457081b1be31575e Mon Sep 17 00:00:00 2001 From: Oliver Gorwits Date: Sun, 6 Oct 2013 17:37:28 +0100 Subject: [PATCH 01/14] Fix SSL-proxy behaviour by using only path+query in links (W. Gould) --- Netdisco/Changes | 1 + Netdisco/lib/App/Netdisco/Manual/WritingPlugins.pod | 12 ++++++------ Netdisco/lib/App/Netdisco/Web.pm | 5 +++++ Netdisco/lib/App/Netdisco/Web/AdminTask.pm | 2 +- Netdisco/lib/App/Netdisco/Web/Device.pm | 2 +- Netdisco/lib/App/Netdisco/Web/Search.pm | 4 ++-- 6 files changed, 16 insertions(+), 10 deletions(-) diff --git a/Netdisco/Changes b/Netdisco/Changes index f4c86751..c62ea26f 100644 --- a/Netdisco/Changes +++ b/Netdisco/Changes @@ -8,6 +8,7 @@ [BUG FIXES] * Update NodeWireless entries which match both MAC and SSID found, only + * Fix SSL-proxy behaviour by using only path+query in links (W. Gould) 2.017000 - 2013-09-23 diff --git a/Netdisco/lib/App/Netdisco/Manual/WritingPlugins.pod b/Netdisco/lib/App/Netdisco/Manual/WritingPlugins.pod index 2d37fad7..2befd384 100644 --- a/Netdisco/lib/App/Netdisco/Manual/WritingPlugins.pod +++ b/Netdisco/lib/App/Netdisco/Manual/WritingPlugins.pod @@ -307,18 +307,18 @@ App::Netdisco: =item C -A base url which links to the Node tab of the Search page, together with the -correct default search options set. +A path and query string which links to the Node tab of the Search page, +together with the correct default search options set. =item C -A base url which links to the Device tab of the Search page, together with the -correct default search options set. +A path and query string which links to the Device tab of the Search page, +together with the correct default search options set. =item C -A base url which links to the Ports tab of the Device page, together with -the correct default column view options set. +A path and query sting which links to the Ports tab of the Device page, +together with the correct default column view options set. =item C diff --git a/Netdisco/lib/App/Netdisco/Web.pm b/Netdisco/lib/App/Netdisco/Web.pm index fdf3c4f4..22430c0e 100644 --- a/Netdisco/lib/App/Netdisco/Web.pm +++ b/Netdisco/lib/App/Netdisco/Web.pm @@ -48,6 +48,7 @@ if (setting('extra_web_plugins') and ref [] eq ref setting('extra_web_plugins')) # workaround for https://github.com/PerlDancer/Dancer/issues/935 hook after_error_render => sub { setting('layout' => 'main') }; +# this hook should be loaded _after_ all plugins hook 'before_template' => sub { my $tokens = shift; @@ -61,6 +62,10 @@ hook 'before_template' => sub { # access to logged in user's roles $tokens->{user_has_role} = sub { user_has_role(@_) }; + # fix Plugin Template Variables to be only path+query + $tokens->{$_} = $tokens->{$_}->path_query + for qw/search_node search_device device_ports/; + # allow very long lists of ports $Template::Directive::WHILE_MAX = 10_000; diff --git a/Netdisco/lib/App/Netdisco/Web/AdminTask.pm b/Netdisco/lib/App/Netdisco/Web/AdminTask.pm index c9b7278b..3a600d2a 100644 --- a/Netdisco/lib/App/Netdisco/Web/AdminTask.pm +++ b/Netdisco/lib/App/Netdisco/Web/AdminTask.pm @@ -55,7 +55,7 @@ foreach my $jobtype (keys %jobs_all, keys %jobs) { if exists $jobs{$jobtype} and not param('device'); add_job($jobtype, param('device'), param('extra')); - redirect uri_for('/admin/jobqueue')->as_string; + redirect uri_for('/admin/jobqueue')->path; }; } diff --git a/Netdisco/lib/App/Netdisco/Web/Device.pm b/Netdisco/lib/App/Netdisco/Web/Device.pm index 4e66ac27..f5853f92 100644 --- a/Netdisco/lib/App/Netdisco/Web/Device.pm +++ b/Netdisco/lib/App/Netdisco/Web/Device.pm @@ -159,7 +159,7 @@ get '/device' => require_login sub { }); if (!defined $dev) { - return redirect uri_for('/', {nosuchdevice => 1})->as_string(); + return redirect uri_for('/', {nosuchdevice => 1})->path_query; } params->{'tab'} ||= 'details'; diff --git a/Netdisco/lib/App/Netdisco/Web/Search.pm b/Netdisco/lib/App/Netdisco/Web/Search.pm index 376a5a9c..d20510e3 100644 --- a/Netdisco/lib/App/Netdisco/Web/Search.pm +++ b/Netdisco/lib/App/Netdisco/Web/Search.pm @@ -66,7 +66,7 @@ get '/search' => require_login sub { if (not param('tab')) { if (not $q) { - return redirect uri_for('/')->as_string; + return redirect uri_for('/')->path; } # pick most likely tab for initial results @@ -83,7 +83,7 @@ get '/search' => require_login sub { tab => 'details', q => ($nd->first->dns || $nd->first->ip), f => '', - })->as_string; + })->path; } # multiple devices From 794dd03b1468e6a351cd94273c038ade3407ae69 Mon Sep 17 00:00:00 2001 From: Oliver Gorwits Date: Sun, 6 Oct 2013 18:08:06 +0100 Subject: [PATCH 02/14] Avoid macsuck generated SQL bug when cleaning NULL VLAN --- Netdisco/Changes | 1 + Netdisco/lib/App/Netdisco/Core/Macsuck.pm | 63 +++++++++---------- .../lib/App/Netdisco/DB/ResultSet/Node.pm | 4 ++ 3 files changed, 34 insertions(+), 34 deletions(-) diff --git a/Netdisco/Changes b/Netdisco/Changes index c62ea26f..22ea2aba 100644 --- a/Netdisco/Changes +++ b/Netdisco/Changes @@ -9,6 +9,7 @@ * Update NodeWireless entries which match both MAC and SSID found, only * Fix SSL-proxy behaviour by using only path+query in links (W. Gould) + * Avoid macsuck generated SQL bug when cleaning NULL VLAN (W. Gould) 2.017000 - 2013-09-23 diff --git a/Netdisco/lib/App/Netdisco/Core/Macsuck.pm b/Netdisco/lib/App/Netdisco/Core/Macsuck.pm index a8126804..d97b3ccf 100644 --- a/Netdisco/lib/App/Netdisco/Core/Macsuck.pm +++ b/Netdisco/lib/App/Netdisco/Core/Macsuck.pm @@ -130,53 +130,48 @@ sub store_node { my $nodes = schema('netdisco')->resultset('Node'); # TODO: probably needs changing if we're to support VTP domains - my $old = $nodes->search( - { - mac => $mac, - vlan => $vlan, - -bool => 'active', - -not => { - switch => $ip, - port => $port, - }, - }); + my $old = $nodes->search({ + mac => $mac, + vlan => $vlan, + -bool => 'active', + -not => { + switch => $ip, + port => $port, + }, + }); # lock rows, # and get the count so we know whether to set time_recent my $old_count = scalar $old->search(undef, { columns => [qw/switch vlan port mac/], - order_by => [qw/switch vlan port mac/], for => 'update', })->all; $old->update({ active => \'false' }); - my $new = $nodes->search( - { - 'me.switch' => $ip, - 'me.port' => $port, - 'me.mac' => $mac, - }, - { - order_by => [qw/switch vlan port mac/], - for => 'update', - }); - - # lock rows - $new->search({vlan => [$vlan, 0, undef]})->first; - - # upgrade old schema - $new->search({vlan => [0, undef]})->delete(); + my $new = $nodes->search({ + 'me.switch' => $ip, + 'me.port' => $port, + 'me.mac' => $mac, + }); # new data - $new->update_or_create({ - vlan => $vlan, - active => \'true', - oui => substr($mac,0,8), - time_last => \$now, - ($old_count ? (time_recent => \$now) : ()), - }); + $new->update_or_create( + { + vlan => $vlan, + active => \'true', + oui => substr($mac,0,8), + time_last => \$now, + ($old_count ? (time_recent => \$now) : ()), + }, + { for => 'update' } + ); + + # upgrade old schema + # an entry for this MAC existed in old schema with vlan => null + # which now has either vlan number or 0 + $new->search({vlan => undef})->delete({only_nodes => 1}); }); } diff --git a/Netdisco/lib/App/Netdisco/DB/ResultSet/Node.pm b/Netdisco/lib/App/Netdisco/DB/ResultSet/Node.pm index 1c77a8fc..acdf8761 100644 --- a/Netdisco/lib/App/Netdisco/DB/ResultSet/Node.pm +++ b/Netdisco/lib/App/Netdisco/DB/ResultSet/Node.pm @@ -100,6 +100,10 @@ sub delete { # avoid letting DBIC delete nodes return 0E0; } + elsif (exists $opts->{only_nodes} and $opts->{only_nodes}) { + # now let DBIC do its thing + return $self->next::method(); + } elsif (exists $opts->{keep_nodes} and $opts->{keep_nodes}) { # avoid letting DBIC delete nodes return 0E0; From 86900805718897a590583bd8e924c2b6c1a84683 Mon Sep 17 00:00:00 2001 From: Oliver Gorwits Date: Sun, 6 Oct 2013 21:04:49 +0100 Subject: [PATCH 03/14] During macsuck get VLAN from Q-BRIDGE if available --- Netdisco/Changes | 1 + Netdisco/lib/App/Netdisco/Core/Macsuck.pm | 6 +++++- 2 files changed, 6 insertions(+), 1 deletion(-) diff --git a/Netdisco/Changes b/Netdisco/Changes index 22ea2aba..cb571299 100644 --- a/Netdisco/Changes +++ b/Netdisco/Changes @@ -10,6 +10,7 @@ * Update NodeWireless entries which match both MAC and SSID found, only * Fix SSL-proxy behaviour by using only path+query in links (W. Gould) * Avoid macsuck generated SQL bug when cleaning NULL VLAN (W. Gould) + * During macsuck get VLAN from Q-BRIDGE if available (jeneric) 2.017000 - 2013-09-23 diff --git a/Netdisco/lib/App/Netdisco/Core/Macsuck.pm b/Netdisco/lib/App/Netdisco/Core/Macsuck.pm index d97b3ccf..39dda17a 100644 --- a/Netdisco/lib/App/Netdisco/Core/Macsuck.pm +++ b/Netdisco/lib/App/Netdisco/Core/Macsuck.pm @@ -94,6 +94,10 @@ sub do_macsuck { $device->ip, $port, $vlan, scalar keys %{ $fwtable->{$vlan}->{$port} }; foreach my $mac (keys %{ $fwtable->{$vlan}->{$port} }) { + # get VLAN from Q-BRIDGE if available + $vlan = $fwtable->{$vlan}->{$port}->{$mac} + if $vlan == 0; + # remove vlan 0 entry for this MAC addr delete $fwtable->{0}->{$_}->{$mac} for keys %{ $fwtable->{0} }; @@ -382,7 +386,7 @@ sub _walk_fwtable { next unless setting('macsuck_bleed'); } - ++$cache->{$port}->{$mac}; + $cache->{$port}->{$mac} = ($fw_vlan->{$idx} || '0'); } return $cache; From 50ed3d0b90989600045241b6e27d8c19bba4109d Mon Sep 17 00:00:00 2001 From: Oliver Gorwits Date: Sun, 6 Oct 2013 22:22:48 +0100 Subject: [PATCH 04/14] OK to include device ports when doing arpnip --- Netdisco/Changes | 1 + Netdisco/lib/App/Netdisco/Core/Arpnip.pm | 11 ++++------- Netdisco/lib/App/Netdisco/Util/SanityCheck.pm | 13 ++++++++----- 3 files changed, 13 insertions(+), 12 deletions(-) diff --git a/Netdisco/Changes b/Netdisco/Changes index cb571299..577b0311 100644 --- a/Netdisco/Changes +++ b/Netdisco/Changes @@ -11,6 +11,7 @@ * Fix SSL-proxy behaviour by using only path+query in links (W. Gould) * Avoid macsuck generated SQL bug when cleaning NULL VLAN (W. Gould) * During macsuck get VLAN from Q-BRIDGE if available (jeneric) + * OK to include device ports when doing arpnip (jeneric) 2.017000 - 2013-09-23 diff --git a/Netdisco/lib/App/Netdisco/Core/Arpnip.pm b/Netdisco/lib/App/Netdisco/Core/Arpnip.pm index f441f05e..22538ead 100644 --- a/Netdisco/lib/App/Netdisco/Core/Arpnip.pm +++ b/Netdisco/lib/App/Netdisco/Core/Arpnip.pm @@ -3,7 +3,6 @@ package App::Netdisco::Core::Arpnip; use Dancer qw/:syntax :script/; use Dancer::Plugin::DBIC 'schema'; -use App::Netdisco::Util::PortMAC 'get_port_macs'; use App::Netdisco::Util::SanityCheck 'check_mac'; use App::Netdisco::Util::DNS ':all'; use NetAddr::IP::Lite ':lower'; @@ -44,12 +43,10 @@ sub do_arpnip { return; } - my $port_macs = get_port_macs($device); - # get v4 arp table - my @v4 = _get_arps($device, $port_macs, $snmp->at_paddr, $snmp->at_netaddr); + my @v4 = _get_arps($device, $snmp->at_paddr, $snmp->at_netaddr); # get v6 neighbor cache - my @v6 = _get_arps($device, $port_macs, $snmp->ipv6_n2p_mac, $snmp->ipv6_n2p_addr); + my @v6 = _get_arps($device, $snmp->ipv6_n2p_mac, $snmp->ipv6_n2p_addr); # get directly connected networks my @subnets = _gather_subnets($device, $snmp); @@ -78,13 +75,13 @@ sub do_arpnip { # get an arp table (v4 or v6) sub _get_arps { - my ($device, $port_macs, $paddr, $netaddr) = @_; + my ($device, $paddr, $netaddr) = @_; my @arps = (); while (my ($arp, $node) = each %$paddr) { my $ip = $netaddr->{$arp}; next unless defined $ip; - next unless check_mac($device, $node, $port_macs); + next unless check_mac($device, $node); push @arps, [$node, $ip, hostname_from_ip($ip)]; } diff --git a/Netdisco/lib/App/Netdisco/Util/SanityCheck.pm b/Netdisco/lib/App/Netdisco/Util/SanityCheck.pm index 43a3fe5a..5319d840 100644 --- a/Netdisco/lib/App/Netdisco/Util/SanityCheck.pm +++ b/Netdisco/lib/App/Netdisco/Util/SanityCheck.pm @@ -44,22 +44,25 @@ MAC address is well-formed (according to common formats) MAC address is not all-zero, broadcast, CLIP, VRRP or HSRP +=back + +Optionally pass a cached set of Device port MAC addresses as the third +argument, in which case an additional check is added: + +=over 4 + =item * MAC address does not belong to an interface on any known Device =back -Optionally pass a cached set of Device port MAC addresses as the third -argument, or else C will retrieve this for itself from the -database. - =cut sub check_mac { my ($device, $node, $port_macs) = @_; - $port_macs ||= get_port_macs($device); my $mac = Net::MAC->new(mac => $node, 'die' => 0, verbose => 0); + $port_macs ||= {}; # incomplete MAC addresses (BayRS frame relay DLCI, etc) if ($mac->get_error) { From e367805e51c807adad041ed55a20fce943dc5c6b Mon Sep 17 00:00:00 2001 From: Oliver Gorwits Date: Sun, 6 Oct 2013 23:37:20 +0100 Subject: [PATCH 05/14] release 2.017001_001 --- Netdisco/Changes | 11 ++++++++++- Netdisco/MANIFEST | 9 +++++++++ Netdisco/META.yml | 3 ++- Netdisco/lib/App/Netdisco.pm | 2 +- Netdisco/lib/App/Netdisco/Manual/ReleaseNotes.pod | 10 ++++++++++ 5 files changed, 32 insertions(+), 3 deletions(-) diff --git a/Netdisco/Changes b/Netdisco/Changes index 577b0311..e4208ec8 100644 --- a/Netdisco/Changes +++ b/Netdisco/Changes @@ -1,9 +1,16 @@ -2.017001 - +2.017001_001 - + + [NEW FEATURES] + + * Add VLAN Inventory Report + * Add Wireless SSID Inventory Report + * Add Device Inventory by Location Report [ENHANCEMENTS] * Respect ignore_interfaces and i_ignore when detecting wrapped device uptime * Try NodeIp OUI company name search if no node results found + * Format About page numbers [BUG FIXES] @@ -12,6 +19,8 @@ * Avoid macsuck generated SQL bug when cleaning NULL VLAN (W. Gould) * During macsuck get VLAN from Q-BRIDGE if available (jeneric) * OK to include device ports when doing arpnip (jeneric) + * Correct bulkwalk_off logic + * Silence warnings when ports don't support i_lastchange 2.017000 - 2013-09-23 diff --git a/Netdisco/MANIFEST b/Netdisco/MANIFEST index 89ab3308..0a407855 100644 --- a/Netdisco/MANIFEST +++ b/Netdisco/MANIFEST @@ -146,9 +146,12 @@ lib/App/Netdisco/Web/Plugin/Device/Ports.pm lib/App/Netdisco/Web/Plugin/Inventory.pm lib/App/Netdisco/Web/Plugin/Report/ApChannelDist.pm lib/App/Netdisco/Web/Plugin/Report/ApRadioChannelPower.pm +lib/App/Netdisco/Web/Plugin/Report/DeviceByLocation.pm lib/App/Netdisco/Web/Plugin/Report/DuplexMismatch.pm lib/App/Netdisco/Web/Plugin/Report/HalfDuplex.pm lib/App/Netdisco/Web/Plugin/Report/PortUtilization.pm +lib/App/Netdisco/Web/Plugin/Report/SsidInventory.pm +lib/App/Netdisco/Web/Plugin/Report/VlanInventory.pm lib/App/Netdisco/Web/Plugin/Search/Device.pm lib/App/Netdisco/Web/Plugin/Search/Node.pm lib/App/Netdisco/Web/Plugin/Search/Port.pm @@ -235,12 +238,18 @@ share/views/ajax/report/apchanneldist.tt share/views/ajax/report/apchanneldist_csv.tt share/views/ajax/report/apradiochannelpower.tt share/views/ajax/report/apradiochannelpower_csv.tt +share/views/ajax/report/devicebylocation.tt +share/views/ajax/report/devicebylocation_csv.tt share/views/ajax/report/duplexmismatch.tt share/views/ajax/report/duplexmismatch_csv.tt share/views/ajax/report/halfduplex.tt share/views/ajax/report/halfduplex_csv.tt share/views/ajax/report/portutilization.tt share/views/ajax/report/portutilization_csv.tt +share/views/ajax/report/ssidinventory.tt +share/views/ajax/report/ssidinventory_csv.tt +share/views/ajax/report/vlaninventory.tt +share/views/ajax/report/vlaninventory_csv.tt share/views/ajax/search/device.tt share/views/ajax/search/device_csv.tt share/views/ajax/search/node_by_ip.tt diff --git a/Netdisco/META.yml b/Netdisco/META.yml index 60d8aaa8..7439e605 100644 --- a/Netdisco/META.yml +++ b/Netdisco/META.yml @@ -52,6 +52,7 @@ requires: Starman: 0.4008 Template: 2.24 Template::Plugin::CSV: 0.04 + Template::Plugin::Number::Format: 1.02 URL::Encode: 0.01 YAML: 0.84 YAML::XS: 0.41 @@ -64,4 +65,4 @@ resources: homepage: http://netdisco.org/ license: http://opensource.org/licenses/bsd-license.php repository: git://git.code.sf.net/p/netdisco/netdisco-ng -version: 2.017000 +version: 2.017001_001 diff --git a/Netdisco/lib/App/Netdisco.pm b/Netdisco/lib/App/Netdisco.pm index 0671940f..6a51a2c7 100644 --- a/Netdisco/lib/App/Netdisco.pm +++ b/Netdisco/lib/App/Netdisco.pm @@ -7,7 +7,7 @@ use 5.010_000; use File::ShareDir 'dist_dir'; use Path::Class; -our $VERSION = '2.017000'; +our $VERSION = '2.017001_001'; BEGIN { if (not ($ENV{DANCER_APPDIR} || '') diff --git a/Netdisco/lib/App/Netdisco/Manual/ReleaseNotes.pod b/Netdisco/lib/App/Netdisco/Manual/ReleaseNotes.pod index d9a08d0d..641723e4 100644 --- a/Netdisco/lib/App/Netdisco/Manual/ReleaseNotes.pod +++ b/Netdisco/lib/App/Netdisco/Manual/ReleaseNotes.pod @@ -35,6 +35,16 @@ but they are backwards compatible. =back +=head1 2.017001_001 + +=head2 General Notices + +The previous mentioned bug in Macsuck is now fixed. + +During Arpnip, Node IPs are no longer resolved to DNS hostnames in real-time. +In the next release, another job will be queued to perform this action for the +device. + =head1 2.017000 =head2 General Notices From 1deba8f90cf87de0a6c922984cb711a8256d1981 Mon Sep 17 00:00:00 2001 From: Oliver Gorwits Date: Mon, 7 Oct 2013 21:44:40 +0100 Subject: [PATCH 06/14] Node DNS names resolved in their own job --- Netdisco/Changes | 3 +- Netdisco/lib/App/Netdisco/Core/Arpnip.pm | 48 +++++++++++++++--- Netdisco/lib/App/Netdisco/Daemon/Queue.pm | 2 +- .../lib/App/Netdisco/Daemon/Worker/Manager.pm | 2 +- .../Netdisco/Daemon/Worker/Poller/Arpnip.pm | 49 ++++++++++++++++++- .../lib/App/Netdisco/Manual/Configuration.pod | 16 ++++++ .../lib/App/Netdisco/Manual/ReleaseNotes.pod | 11 +++-- Netdisco/lib/App/Netdisco/Util/Device.pm | 27 ++++++++++ Netdisco/share/config.yml | 2 + 9 files changed, 146 insertions(+), 14 deletions(-) diff --git a/Netdisco/Changes b/Netdisco/Changes index e4208ec8..9776caee 100644 --- a/Netdisco/Changes +++ b/Netdisco/Changes @@ -1,10 +1,11 @@ -2.017001_001 - +2.017001_002 - [NEW FEATURES] * Add VLAN Inventory Report * Add Wireless SSID Inventory Report * Add Device Inventory by Location Report + * Node DNS names resolved in their own job - see nodenames_no and nodenames_only [ENHANCEMENTS] diff --git a/Netdisco/lib/App/Netdisco/Core/Arpnip.pm b/Netdisco/lib/App/Netdisco/Core/Arpnip.pm index 22538ead..549169bc 100644 --- a/Netdisco/lib/App/Netdisco/Core/Arpnip.pm +++ b/Netdisco/lib/App/Netdisco/Core/Arpnip.pm @@ -10,7 +10,7 @@ use Time::HiRes 'gettimeofday'; use base 'Exporter'; our @EXPORT = (); -our @EXPORT_OK = qw/ do_arpnip store_arp /; +our @EXPORT_OK = qw/ do_arpnip store_arp resolve_node_names /; our %EXPORT_TAGS = (all => \@EXPORT_OK); =head1 NAME @@ -82,16 +82,16 @@ sub _get_arps { my $ip = $netaddr->{$arp}; next unless defined $ip; next unless check_mac($device, $node); - push @arps, [$node, $ip, hostname_from_ip($ip)]; + push @arps, [$node, $ip]; } return @arps; } -=head2 store_arp( $mac, $ip, $name, $now? ) +=head2 store_arp( $mac, $ip, $now? ) -Stores a new entry to the C table with the given MAC, IP (v4 or v6) -and DNS host name. +Stores a new entry to the C table with the given MAC, and IP (v4 or +v6). Will mark old entries for this IP as no longer C. @@ -101,7 +101,7 @@ C timestamp, otherwise the current timestamp (C) is used. =cut sub store_arp { - my ($mac, $ip, $name, $now) = @_; + my ($mac, $ip, $now) = @_; $now ||= 'now()'; schema('netdisco')->txn_do(sub { @@ -119,7 +119,6 @@ sub store_arp { ->search({'me.mac' => $mac, 'me.ip' => $ip}) ->update_or_create( { - dns => $name, active => \'true', time_last => \$now, }, @@ -172,4 +171,39 @@ sub _store_subnet { }); } +=head2 resolve_node_names( $device ) + +Given a Device database object, resolve Node IP (ARP) entries belonging to +this device into DNS names, and store them in the C database table. + +This action is usually queued following C so that it may run +asynchronously, and/or on another daemon worker node. + +=cut + +sub resolve_node_names { + my ($device) = @_; + + schema('netdisco')->txn_do(sub { + my $nodeips = schema('netdisco') + ->resultset('NodeIp')->search( + { + -and => [ + -bool => 'me.active', + -bool => 'nodes.active', + ], + 'nodes.switch' => $device->ip, + }, + { + join => 'nodes', + for => 'update', + } + ); + + while (my $nodeip = $nodeips->next) { + $nodeip->update({dns => hostname_from_ip($nodeip->ip)}); + } + }); +} + 1; diff --git a/Netdisco/lib/App/Netdisco/Daemon/Queue.pm b/Netdisco/lib/App/Netdisco/Daemon/Queue.pm index f89e14fb..336f65a4 100644 --- a/Netdisco/lib/App/Netdisco/Daemon/Queue.pm +++ b/Netdisco/lib/App/Netdisco/Daemon/Queue.pm @@ -22,7 +22,7 @@ sub capacity_for { debug "checking local capacity for action $action"; my $action_map = { - Poller => [qw/discoverall discover arpwalk arpnip macwalk macsuck/], + Poller => [qw/discoverall discover arpwalk arpnip nodenames macwalk macsuck/], Interactive => [qw/location contact portcontrol portname vlan power/], }; diff --git a/Netdisco/lib/App/Netdisco/Daemon/Worker/Manager.pm b/Netdisco/lib/App/Netdisco/Daemon/Worker/Manager.pm index 047196f2..0087d149 100644 --- a/Netdisco/lib/App/Netdisco/Daemon/Worker/Manager.pm +++ b/Netdisco/lib/App/Netdisco/Daemon/Worker/Manager.pm @@ -13,7 +13,7 @@ my $fqdn = hostfqdn || 'localhost'; my $role_map = { (map {$_ => 'Poller'} - qw/discoverall discover arpwalk arpnip macwalk macsuck/), + qw/discoverall discover arpwalk arpnip nodenames macwalk macsuck/), (map {$_ => 'Interactive'} qw/location contact portcontrol portname vlan power/) }; diff --git a/Netdisco/lib/App/Netdisco/Daemon/Worker/Poller/Arpnip.pm b/Netdisco/lib/App/Netdisco/Daemon/Worker/Poller/Arpnip.pm index d511c1b4..26e47be2 100644 --- a/Netdisco/lib/App/Netdisco/Daemon/Worker/Poller/Arpnip.pm +++ b/Netdisco/lib/App/Netdisco/Daemon/Worker/Poller/Arpnip.pm @@ -1,9 +1,17 @@ package App::Netdisco::Daemon::Worker::Poller::Arpnip; +use Dancer::Plugin::DBIC 'schema'; + use App::Netdisco::Core::Arpnip 'do_arpnip'; -use App::Netdisco::Util::Device 'is_arpnipable'; +use App::Netdisco::Util::Device qw/get_device is_arpnipable can_nodenames/; + +use App::Netdisco::Core::Arpnip 'resolve_node_names'; +use App::Netdisco::Daemon::Util ':all'; + +use NetAddr::IP::Lite ':lower'; use Role::Tiny; +use Class::Method::Modifiers; use namespace::clean; with 'App::Netdisco::Daemon::Worker::Poller::Common'; @@ -15,4 +23,43 @@ sub arpnip_layer { 3 } sub arpwalk { (shift)->_walk_body('arpnip', @_) } sub arpnip { (shift)->_single_body('arpnip', @_) } +after 'arpnip' => sub { + my ($self, $job) = @_; + + my $host = NetAddr::IP::Lite->new($job->device); + my $device = get_device($host->addr); + my $jobqueue = schema('netdisco')->resultset('Admin'); + + schema('netdisco')->txn_do(sub { + $jobqueue->create({ + device => $device->ip, + action => 'nodenames', + status => 'queued', + username => $job->username, + userip => $job->userip, + }); + }); +}; + +# run a nodenames job for one device +sub nodenames { + my ($self, $job) = @_; + + my $host = NetAddr::IP::Lite->new($job->device); + my $device = get_device($host->addr); + my $jobqueue = schema('netdisco')->resultset('Admin'); + + if ($device->ip eq '0.0.0.0') { + return job_error("nodenames failed: no device param (need -d ?)"); + } + + unless (can_nodenames($device->ip)) { + return job_defer("nodenames deferred: cannot run for $host"); + } + + resolve_node_names($device); + + return job_done("Ended nodenames for ". $host->addr); +} + 1; diff --git a/Netdisco/lib/App/Netdisco/Manual/Configuration.pod b/Netdisco/lib/App/Netdisco/Manual/Configuration.pod index 591e19bb..906f0aa2 100644 --- a/Netdisco/lib/App/Netdisco/Manual/Configuration.pod +++ b/Netdisco/lib/App/Netdisco/Manual/Configuration.pod @@ -444,6 +444,22 @@ Value: Number. Default: 0. Sets the minimum amount of time in seconds which must elapse between any two arpnip jobs for a device. +=head3 C + +Value: List of Network Identifiers or Device Properties. Default: Empty List. + +Devices in the list will not have their Node IPs resolved to names using the +DNS. You can include hostnames, IP addresses and subnets (IPv4 or IPv6) in the +list. + +=head3 C + +Value: List of Network Identifiers or Device Properties. Default: Empty List. + +Only thos devices in the list will have their Node IPs resolved to names using +the DNS. You can include hostnames, IP addresses and subnets (IPv4 or IPv6) in +the list. + =head3 C Value: Boolean. Default: C. diff --git a/Netdisco/lib/App/Netdisco/Manual/ReleaseNotes.pod b/Netdisco/lib/App/Netdisco/Manual/ReleaseNotes.pod index 641723e4..41fe1254 100644 --- a/Netdisco/lib/App/Netdisco/Manual/ReleaseNotes.pod +++ b/Netdisco/lib/App/Netdisco/Manual/ReleaseNotes.pod @@ -35,15 +35,20 @@ but they are backwards compatible. =back -=head1 2.017001_001 +=head1 2.017001_002 =head2 General Notices The previous mentioned bug in Macsuck is now fixed. During Arpnip, Node IPs are no longer resolved to DNS hostnames in real-time. -In the next release, another job will be queued to perform this action for the -device. +Another job is queued to perform this action for the device. You can therefore +control using the new C and C config parameters +which daemons run this job. + +The idea here is to support sites where the SNMP polling node has no useful +DNS, but another system can update the DNS entries for nodes (yet do no +polling). =head1 2.017000 diff --git a/Netdisco/lib/App/Netdisco/Util/Device.pm b/Netdisco/lib/App/Netdisco/Util/Device.pm index 720aa783..b3d01b65 100644 --- a/Netdisco/lib/App/Netdisco/Util/Device.pm +++ b/Netdisco/lib/App/Netdisco/Util/Device.pm @@ -12,6 +12,7 @@ our @EXPORT_OK = qw/ check_no is_discoverable is_arpnipable + can_nodenames is_macsuckable /; our %EXPORT_TAGS = (all => \@EXPORT_OK); @@ -195,6 +196,32 @@ sub is_arpnipable { return 1; } +=head2 can_nodenames( $ip ) + +Given an IP address, returns C if Netdisco on this host is permitted by +the local configuration to resolve Node IPs to DNS names for the device. + +The configuration items C and C are checked +against the given IP. + +Returns false if the host is not permitted to do this job for the target +device. + +=cut + +sub can_nodenames { + my $ip = shift; + my $device = get_device($ip) or return 0; + + return _bail_msg("can_nodenames device matched nodenames_no") + if check_no($device, 'nodenames_no'); + + return _bail_msg("can_nodenames: device failed to match nodenames_only") + if check_no($device, 'nodenames_only'); + + return 1; +} + =head2 is_macsuckable( $ip ) Given an IP address, returns C if Netdisco on this host is permitted by diff --git a/Netdisco/share/config.yml b/Netdisco/share/config.yml index 3b753507..f8a366e8 100644 --- a/Netdisco/share/config.yml +++ b/Netdisco/share/config.yml @@ -86,6 +86,8 @@ macsuck_min_age: 0 arpnip_no: [] arpnip_only: [] arpnip_min_age: 0 +nodenames_no: [] +nodenames_only: [] store_wireless_clients: true store_modules: true ignore_interfaces: From f38816bffbc4a1d0f7bd8e121fd65e500ebc28c6 Mon Sep 17 00:00:00 2001 From: Oliver Gorwits Date: Mon, 7 Oct 2013 21:53:35 +0100 Subject: [PATCH 07/14] release 2.017001_002 --- Netdisco/META.yml | 4 ++-- Netdisco/Makefile.PL | 2 +- Netdisco/lib/App/Netdisco.pm | 2 +- 3 files changed, 4 insertions(+), 4 deletions(-) diff --git a/Netdisco/META.yml b/Netdisco/META.yml index 7439e605..fa186d16 100644 --- a/Netdisco/META.yml +++ b/Netdisco/META.yml @@ -25,7 +25,7 @@ requires: DBD::Pg: 0 DBD::SQLite: 1.37 DBIx::Class: 0.0821 - DBIx::Class::Helpers: 2.016006 + DBIx::Class::Helpers: 2.018004 Daemon::Control: 0.001 Dancer: 1.3112 Dancer::Plugin::Auth::Extensible: 0.2 @@ -65,4 +65,4 @@ resources: homepage: http://netdisco.org/ license: http://opensource.org/licenses/bsd-license.php repository: git://git.code.sf.net/p/netdisco/netdisco-ng -version: 2.017001_001 +version: 2.017001_002 diff --git a/Netdisco/Makefile.PL b/Netdisco/Makefile.PL index e9c5e82f..42ca0b0e 100644 --- a/Netdisco/Makefile.PL +++ b/Netdisco/Makefile.PL @@ -10,7 +10,7 @@ requires 'App::local::lib::helper' => 0.07; requires 'DBD::Pg' => 0; requires 'DBD::SQLite' => 1.37; requires 'DBIx::Class' => 0.08210; -requires 'DBIx::Class::Helpers' => 2.016006; +requires 'DBIx::Class::Helpers' => 2.018004; requires 'Daemon::Control' => 0.001000; requires 'Dancer' => 1.3112; requires 'Dancer::Plugin::DBIC' => 0.1802; diff --git a/Netdisco/lib/App/Netdisco.pm b/Netdisco/lib/App/Netdisco.pm index 6a51a2c7..18d8c90a 100644 --- a/Netdisco/lib/App/Netdisco.pm +++ b/Netdisco/lib/App/Netdisco.pm @@ -7,7 +7,7 @@ use 5.010_000; use File::ShareDir 'dist_dir'; use Path::Class; -our $VERSION = '2.017001_001'; +our $VERSION = '2.017001_002'; BEGIN { if (not ($ENV{DANCER_APPDIR} || '') From 7014b1097839e1f766e95c05014b67f5d8ac0f36 Mon Sep 17 00:00:00 2001 From: Oliver Gorwits Date: Mon, 7 Oct 2013 22:53:32 +0100 Subject: [PATCH 08/14] update TODO to refer to Sourceforge tracker --- TODO | 32 +------------------------------- 1 file changed, 1 insertion(+), 31 deletions(-) diff --git a/TODO b/TODO index cea74e79..f207fb1a 100644 --- a/TODO +++ b/TODO @@ -1,31 +1 @@ -FRONTEND -======== - -* moar reports - -DAEMON -====== - -BACKEND -======= - -* PING from workers? - -CORE -==== - -* VRF support (multi-tenancy?) -* import legacy config file? - -DOCS -==== - -* Scheduler -* Discover/Refresh jobs -* new X:: plugin namespace -* observiumsparklines plugin -* port column plugins -* add css and js for plugin -* site_plugins -* missing user management ("User Rights") -* Auth::Extensible +See: https://sourceforge.net/p/netdisco/netdisco2/ From 5bb2fcdb46c34f78300cdd62ef1a8b77f9f47bbb Mon Sep 17 00:00:00 2001 From: Oliver Gorwits Date: Mon, 7 Oct 2013 23:35:22 +0100 Subject: [PATCH 09/14] make sure query string is included in redirect --- Netdisco/lib/App/Netdisco/Web/Search.pm | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Netdisco/lib/App/Netdisco/Web/Search.pm b/Netdisco/lib/App/Netdisco/Web/Search.pm index d20510e3..92f48675 100644 --- a/Netdisco/lib/App/Netdisco/Web/Search.pm +++ b/Netdisco/lib/App/Netdisco/Web/Search.pm @@ -83,7 +83,7 @@ get '/search' => require_login sub { tab => 'details', q => ($nd->first->dns || $nd->first->ip), f => '', - })->path; + })->path_query; } # multiple devices From 5905f94500c9a0509acd778daae79202235a60d6 Mon Sep 17 00:00:00 2001 From: Oliver Gorwits Date: Mon, 7 Oct 2013 23:35:29 +0100 Subject: [PATCH 10/14] release 2.017001_003 --- Netdisco/Changes | 2 +- Netdisco/META.yml | 2 +- Netdisco/lib/App/Netdisco.pm | 2 +- 3 files changed, 3 insertions(+), 3 deletions(-) diff --git a/Netdisco/Changes b/Netdisco/Changes index 9776caee..fd0ae1d7 100644 --- a/Netdisco/Changes +++ b/Netdisco/Changes @@ -1,4 +1,4 @@ -2.017001_002 - +2.017001_003 - [NEW FEATURES] diff --git a/Netdisco/META.yml b/Netdisco/META.yml index fa186d16..e4f3d959 100644 --- a/Netdisco/META.yml +++ b/Netdisco/META.yml @@ -65,4 +65,4 @@ resources: homepage: http://netdisco.org/ license: http://opensource.org/licenses/bsd-license.php repository: git://git.code.sf.net/p/netdisco/netdisco-ng -version: 2.017001_002 +version: 2.017001_003 diff --git a/Netdisco/lib/App/Netdisco.pm b/Netdisco/lib/App/Netdisco.pm index 18d8c90a..5370cd83 100644 --- a/Netdisco/lib/App/Netdisco.pm +++ b/Netdisco/lib/App/Netdisco.pm @@ -7,7 +7,7 @@ use 5.010_000; use File::ShareDir 'dist_dir'; use Path::Class; -our $VERSION = '2.017001_002'; +our $VERSION = '2.017001_003'; BEGIN { if (not ($ENV{DANCER_APPDIR} || '') From d3e9aa28d3d48613a21372dc3df0829c8a5711ba Mon Sep 17 00:00:00 2001 From: Oliver Gorwits Date: Tue, 8 Oct 2013 11:10:22 +0100 Subject: [PATCH 11/14] Correct *_only and *_no setting logic --- Netdisco/Changes | 1 + Netdisco/lib/App/Netdisco/Util/Device.pm | 124 ++++++++++++++++------- 2 files changed, 88 insertions(+), 37 deletions(-) diff --git a/Netdisco/Changes b/Netdisco/Changes index fd0ae1d7..5a898853 100644 --- a/Netdisco/Changes +++ b/Netdisco/Changes @@ -22,6 +22,7 @@ * OK to include device ports when doing arpnip (jeneric) * Correct bulkwalk_off logic * Silence warnings when ports don't support i_lastchange + * Correct *_only and *_no setting logic 2.017000 - 2013-09-23 diff --git a/Netdisco/lib/App/Netdisco/Util/Device.pm b/Netdisco/lib/App/Netdisco/Util/Device.pm index b3d01b65..11863c71 100644 --- a/Netdisco/lib/App/Netdisco/Util/Device.pm +++ b/Netdisco/lib/App/Netdisco/Util/Device.pm @@ -10,6 +10,7 @@ our @EXPORT = (); our @EXPORT_OK = qw/ get_device check_no + check_only is_discoverable is_arpnipable can_nodenames @@ -58,42 +59,11 @@ sub get_device { ->find_or_new({ip => $ip}); } -=head2 check_no( $ip, $setting_name ) - -Given the IP address of a device, returns true if the configuration setting -C<$setting_name> matches that device, else returns false. - -There are several options for what C<$setting_name> can contain: - -=over 4 - -=item * - -Hostname, IP address, IP prefix - -=item * - -C<"model:regex"> - matched against the device model - -=item * - -C<"vendor:regex"> - matched against the device vendor - -=back - -To simply match all devices, use IP Prefix "C<0.0.0.0/0>". All regular -expressions are anchored (that is, they must match the whole string). - -=cut - -sub check_no { - my ($ip, $setting_name) = @_; +sub _check_acl { + my ($ip, $config) = @_; my $device = get_device($ip) or return 0; my $addr = NetAddr::IP::Lite->new($device->ip); - my $config = setting($setting_name) || []; - return 0 unless scalar @$config; - foreach my $item (@$config) { if ($item =~ m/^(.*)\s*:\s*(.*)$/) { my $prop = $1; @@ -117,6 +87,86 @@ sub check_no { return 0; } +=head2 check_no( $ip, $setting_name ) + +Given the IP address of a device, returns true if the configuration setting +C<$setting_name> matches that device, else returns false. + + print "rejected!" if check_no($ip, 'discover_no'); + +There are several options for what C<$setting_name> can contain: + +=over 4 + +=item * + +Hostname, IP address, IP prefix + +=item * + +C<"model:regex"> - matched against the device model + +=item * + +C<"vendor:regex"> - matched against the device vendor + +=back + +To simply match all devices, use "C" or IP Prefix "C<0.0.0.0/0>". All +regular expressions are anchored (that is, they must match the whole string). +To match no devices we recommend an entry of "C" in the setting. + +=cut + +sub check_no { + my ($ip, $setting_name) = @_; + + my $config = setting($setting_name) || []; + return 0 unless scalar @$config; + + return _check_acl($ip, $config); +} + +=head2 check_only( $ip, $setting_name ) + +Given the IP address of a device, returns false if the configuration setting +C<$setting_name> matches that device, else returns true. + + print "rejected!" unless check_only($ip, 'discover_only'); + +There are several options for what C<$setting_name> can contain: + +=over 4 + +=item * + +Hostname, IP address, IP prefix + +=item * + +C<"model:regex"> - matched against the device model + +=item * + +C<"vendor:regex"> - matched against the device vendor + +=back + +To simply match all devices, use "C" or IP Prefix "C<0.0.0.0/0>". All +regular expressions are anchored (that is, they must match the whole string). +To match no devices we recommend an entry of "C" in the setting. + +=cut + +sub check_only { + my ($ip, $setting_name) = @_; + + my $config = setting($setting_name) || []; + return 1 unless scalar @$config; + + return _check_acl($ip, $config); +} + =head2 is_discoverable( $ip, $device_type? ) Given an IP address, returns C if Netdisco on this host is permitted by @@ -148,7 +198,7 @@ sub is_discoverable { if check_no($device, 'discover_no'); return _bail_msg("is_discoverable: device failed to match discover_only") - if check_no($device, 'discover_only'); + unless check_only($device, 'discover_only'); # cannot check last_discover for as yet undiscovered devices :-) return 1 if not $device->in_storage; @@ -182,7 +232,7 @@ sub is_arpnipable { if check_no($device, 'arpnip_no'); return _bail_msg("is_arpnipable: device failed to match arpnip_only") - if check_no($device, 'arpnip_only'); + unless check_only($device, 'arpnip_only'); return _bail_msg("is_arpnipable: cannot arpnip an undiscovered device") if not $device->in_storage; @@ -217,7 +267,7 @@ sub can_nodenames { if check_no($device, 'nodenames_no'); return _bail_msg("can_nodenames: device failed to match nodenames_only") - if check_no($device, 'nodenames_only'); + unless check_only($device, 'nodenames_only'); return 1; } @@ -242,7 +292,7 @@ sub is_macsuckable { if check_no($device, 'macsuck_no'); return _bail_msg("is_macsuckable: device failed to match macsuck_only") - if check_no($device, 'macsuck_only'); + unless check_only($device, 'macsuck_only'); return _bail_msg("is_macsuckable: cannot macsuck an undiscovered device") if not $device->in_storage; From 9ff24377ddb8cb4bab79ea2cc6db279f868ea86c Mon Sep 17 00:00:00 2001 From: Oliver Gorwits Date: Tue, 8 Oct 2013 11:15:09 +0100 Subject: [PATCH 12/14] Correct the instructions for runing dev instance of web and daemon --- Netdisco/Changes | 1 + Netdisco/lib/App/Netdisco/Manual/Developing.pod | 15 ++++++++++++--- 2 files changed, 13 insertions(+), 3 deletions(-) diff --git a/Netdisco/Changes b/Netdisco/Changes index 5a898853..6a5a1eb3 100644 --- a/Netdisco/Changes +++ b/Netdisco/Changes @@ -23,6 +23,7 @@ * Correct bulkwalk_off logic * Silence warnings when ports don't support i_lastchange * Correct *_only and *_no setting logic + * Correct the instructions for runing dev instance of web and daemon 2.017000 - 2013-09-23 diff --git a/Netdisco/lib/App/Netdisco/Manual/Developing.pod b/Netdisco/lib/App/Netdisco/Manual/Developing.pod index fbe82cff..4e4cefe0 100644 --- a/Netdisco/lib/App/Netdisco/Manual/Developing.pod +++ b/Netdisco/lib/App/Netdisco/Manual/Developing.pod @@ -18,7 +18,7 @@ the L. Then: git clone git://git.code.sf.net/p/netdisco/netdisco-ng netdisco-ng cd netdisco-ng/Netdisco - ~/bin/localenv DBIC_TRACE_PROFILE=console DBIC_TRACE=1 plackup -R share,lib -p 5001 bin/netdisco-web-fg + DBIC_TRACE_PROFILE=console DBIC_TRACE=1 ~/bin/localenv plackup -R share,lib -p 5001 bin/netdisco-web-fg The above creates you a git clone (change the URL if you're a Netdisco Developer) and runs the web server: @@ -47,8 +47,17 @@ Restarts the web server when you save a file in the C or C directory =back -You should be able to work out something similar for -C, too. Happy hacking! +You might also want to set C to C in your config to quieten +some of the web client callbacks. + +For the daemon, it's very similar: + + DBIC_TRACE_PROFILE=console DBIC_TRACE=1 ~/bin/localenv bin/netdisco-daemon-fg + +Don't be alarmed by the high rate of database queries in the daemon - most of +them are communicating only with a local in-memory SQLite database. + +Happy hacking! =head1 Introduction From cd576b9e7fe140dc408e73ceb054b53c27411c7a Mon Sep 17 00:00:00 2001 From: Oliver Gorwits Date: Tue, 8 Oct 2013 11:19:36 +0100 Subject: [PATCH 13/14] release 2.018000 --- Netdisco/Changes | 2 +- Netdisco/META.yml | 4 ++-- Netdisco/Makefile.PL | 2 +- Netdisco/lib/App/Netdisco.pm | 2 +- Netdisco/lib/App/Netdisco/Manual/ReleaseNotes.pod | 2 +- 5 files changed, 6 insertions(+), 6 deletions(-) diff --git a/Netdisco/Changes b/Netdisco/Changes index 6a5a1eb3..0ac79833 100644 --- a/Netdisco/Changes +++ b/Netdisco/Changes @@ -1,4 +1,4 @@ -2.017001_003 - +2.018000 - 2013-10-08 [NEW FEATURES] diff --git a/Netdisco/META.yml b/Netdisco/META.yml index e4f3d959..c3017ff8 100644 --- a/Netdisco/META.yml +++ b/Netdisco/META.yml @@ -29,7 +29,7 @@ requires: Daemon::Control: 0.001 Dancer: 1.3112 Dancer::Plugin::Auth::Extensible: 0.2 - Dancer::Plugin::DBIC: 0.1802 + Dancer::Plugin::DBIC: 0.1803 File::ShareDir: 1.03 HTML::Parser: 3.7 HTTP::Tiny: 0.029 @@ -65,4 +65,4 @@ resources: homepage: http://netdisco.org/ license: http://opensource.org/licenses/bsd-license.php repository: git://git.code.sf.net/p/netdisco/netdisco-ng -version: 2.017001_003 +version: 2.018000 diff --git a/Netdisco/Makefile.PL b/Netdisco/Makefile.PL index 42ca0b0e..be3ec6a0 100644 --- a/Netdisco/Makefile.PL +++ b/Netdisco/Makefile.PL @@ -13,7 +13,7 @@ requires 'DBIx::Class' => 0.08210; requires 'DBIx::Class::Helpers' => 2.018004; requires 'Daemon::Control' => 0.001000; requires 'Dancer' => 1.3112; -requires 'Dancer::Plugin::DBIC' => 0.1802; +requires 'Dancer::Plugin::DBIC' => 0.1803; requires 'Dancer::Plugin::Auth::Extensible' => 0.20; requires 'File::ShareDir' => 1.03; requires 'HTML::Parser' => 3.70; diff --git a/Netdisco/lib/App/Netdisco.pm b/Netdisco/lib/App/Netdisco.pm index 5370cd83..23a7b9fb 100644 --- a/Netdisco/lib/App/Netdisco.pm +++ b/Netdisco/lib/App/Netdisco.pm @@ -7,7 +7,7 @@ use 5.010_000; use File::ShareDir 'dist_dir'; use Path::Class; -our $VERSION = '2.017001_003'; +our $VERSION = '2.018000'; BEGIN { if (not ($ENV{DANCER_APPDIR} || '') diff --git a/Netdisco/lib/App/Netdisco/Manual/ReleaseNotes.pod b/Netdisco/lib/App/Netdisco/Manual/ReleaseNotes.pod index 41fe1254..ad0fba31 100644 --- a/Netdisco/lib/App/Netdisco/Manual/ReleaseNotes.pod +++ b/Netdisco/lib/App/Netdisco/Manual/ReleaseNotes.pod @@ -35,7 +35,7 @@ but they are backwards compatible. =back -=head1 2.017001_002 +=head1 2.018000 =head2 General Notices From 253bf769fb72f64c5bf6eb9b8a7edc0e050ddbed Mon Sep 17 00:00:00 2001 From: Oliver Gorwits Date: Tue, 8 Oct 2013 13:33:14 +0100 Subject: [PATCH 14/14] Update Print media CSS to handle new UI components --- Netdisco/Changes | 6 ++++++ Netdisco/share/public/css/nd_print.css | 9 +++++++++ 2 files changed, 15 insertions(+) diff --git a/Netdisco/Changes b/Netdisco/Changes index 0ac79833..f993df0f 100644 --- a/Netdisco/Changes +++ b/Netdisco/Changes @@ -1,3 +1,9 @@ +2.018001 - + + [BUG FIXES] + + * Update Print media CSS to handle new UI components + 2.018000 - 2013-10-08 [NEW FEATURES] diff --git a/Netdisco/share/public/css/nd_print.css b/Netdisco/share/public/css/nd_print.css index 0944b8e5..bb1b653b 100644 --- a/Netdisco/share/public/css/nd_print.css +++ b/Netdisco/share/public/css/nd_print.css @@ -14,3 +14,12 @@ body { margin-left: 0px !important; margin-right: 0px !important; } + +.floatThead-table { + position: inherit; + top: 45px; +} + +a:after { + content: "" !important; +}