Merge branch 'master' into og-autoload

Conflicts:
	Netdisco/share/public/javascripts/netdisco_portcontrol.js
This commit is contained in:
Oliver Gorwits
2014-07-31 21:32:30 +01:00
12 changed files with 124 additions and 48 deletions

View File

@@ -1,3 +1,26 @@
2.028014
[ENHANCEMENTS]
* [#108] Port Bounce port control feature (down and up in succession)
[BUG FIXES]
* Missing action to netdisco-do should not throw Perl error
* Sort CDP/LLDP data to be more consistent when multiple neighbors on a port
* Add "AP" as a hint for WAP support
2.028013 - 2014-07-31
[ENHANCEMENTS]
* [#122] CDP/LLDP discovery for some HP switches (M. Kosmach)
[BUG FIXES]
* Fix when Interactives number set to zero
* [#121] Daemon crash when restarting with in-progress jobs and many workers
2.028012 - 2014-07-22 2.028012 - 2014-07-22
[BUG FIXES] [BUG FIXES]

View File

@@ -81,4 +81,4 @@ resources:
homepage: http://netdisco.org/ homepage: http://netdisco.org/
license: http://opensource.org/licenses/bsd-license.php license: http://opensource.org/licenses/bsd-license.php
repository: git://git.code.sf.net/p/netdisco/netdisco-ng repository: git://git.code.sf.net/p/netdisco/netdisco-ng
version: 2.028012 version: 2.028013

View File

@@ -41,7 +41,7 @@ my $mce = MCE->new(
job_delay => 1.15, job_delay => 1.15,
tmp_dir => $tmp_dir, tmp_dir => $tmp_dir,
user_func => sub { $_[0]->worker_body }, user_func => sub { $_[0]->worker_body },
on_post_exit => \&restart_worker, on_post_exit => \&restart_this_worker,
user_tasks => build_tasks_list(), user_tasks => build_tasks_list(),
)->run(); )->run();
@@ -100,7 +100,7 @@ sub worker_factory {
}; };
} }
sub restart_worker { sub restart_this_worker {
my ($self, $e) = @_; my ($self, $e) = @_;
reset_jobs($e->{wid}); reset_jobs($e->{wid});

View File

@@ -65,7 +65,7 @@ schema('daemon')->deploy;
# get requested action # get requested action
my $action = shift @ARGV; my $action = shift @ARGV;
if (!length $action) { unless ($action) {
error 'error: missing action!'; error 'error: missing action!';
exit (1); exit (1);
} }

View File

@@ -4,7 +4,7 @@ use strict;
use warnings; use warnings;
use 5.010_000; use 5.010_000;
our $VERSION = '2.028012'; our $VERSION = '2.028013';
use App::Netdisco::Configuration; use App::Netdisco::Configuration;
use Module::Find (); use Module::Find ();

View File

@@ -43,7 +43,8 @@ setting('plugins')->{DBIC}->{daemon} = {
# defaults for workers # defaults for workers
setting('workers')->{queue} ||= 'PostgreSQL'; setting('workers')->{queue} ||= 'PostgreSQL';
setting('workers')->{interactives} ||= 1; setting('workers')->{interactives} = 1
if setting('workers') and not exists setting('workers')->{interactives};
# force skipped DNS resolution, if unset # force skipped DNS resolution, if unset
setting('dns')->{hosts_file} ||= '/etc/hosts'; setting('dns')->{hosts_file} ||= '/etc/hosts';

View File

@@ -666,7 +666,7 @@ sub store_neighbors {
my $c_platform = $snmp->c_platform; my $c_platform = $snmp->c_platform;
my $c_cap = $snmp->c_cap; my $c_cap = $snmp->c_cap;
foreach my $entry (List::MoreUtils::uniq( (keys %$c_ip), (keys %$c_cap) )) { foreach my $entry (sort (List::MoreUtils::uniq( (keys %$c_ip), (keys %$c_cap) ))) {
if (!defined $c_if->{$entry} or !defined $interfaces->{ $c_if->{$entry} }) { if (!defined $c_if->{$entry} or !defined $interfaces->{ $c_if->{$entry} }) {
debug sprintf ' [%s] neigh - port for IID:%s not resolved, skipping', debug sprintf ' [%s] neigh - port for IID:%s not resolved, skipping',
$device->ip, $entry; $device->ip, $entry;
@@ -695,11 +695,11 @@ sub store_neighbors {
my $phone_flag = grep {/phone/i} @$remote_cap; my $phone_flag = grep {/phone/i} @$remote_cap;
my $ap_flag = grep {/wlanAccessPoint/} @$remote_cap; my $ap_flag = grep {/wlanAccessPoint/} @$remote_cap;
if ($phone_flag or $remote_type =~ m/(mitel.5\d{3})/i) { if ($phone_flag or $remote_type =~ m/mitel.5\d{3}/i) {
$remote_type = 'IP Phone: '. $remote_type $remote_type = 'IP Phone: '. $remote_type
if $remote_type !~ /ip phone/i; if $remote_type !~ /ip phone/i;
} }
elsif ($ap_flag) { elsif ($ap_flag or $remote_type =~ m/\bw?ap\b/i) {
$remote_type = 'AP: '. $remote_type; $remote_type = 'AP: '. $remote_type;
} }
@@ -730,7 +730,22 @@ sub store_neighbors {
if (!defined $neigh) { if (!defined $neigh) {
my $mac = Net::MAC->new(mac => $remote_id, 'die' => 0, verbose => 0); my $mac = Net::MAC->new(mac => $remote_id, 'die' => 0, verbose => 0);
if (not $mac->get_error) { if (not $mac->get_error) {
$neigh = $devices->single({mac => $remote_id}); $neigh = $devices->single({mac => $mac->as_IEEE()});
}
}
# some HP switches send 127.0.0.1 as remote_ip if no ip address
# on default vlan for HP switches remote_ip looks like
# "myswitchname(012345-012345)"
if (!defined $neigh) {
(my $tmpid = $remote_id) =~ s/.([0-9a-f]{6})-([0-9a-f]{6})./$1$2/;
my $mac = Net::MAC->new(mac => $tmpid, 'die' => 0, verbose => 0);
if (not $mac->get_error) {
info sprintf
'[%s] neigh - found neighbor %s by MAC %s',
$device->ip, $remote_id, $mac->as_IEEE();
$neigh = $devices->single({mac => $mac->as_IEEE()});
} }
} }

View File

@@ -5,7 +5,7 @@ use Dancer::Plugin::DBIC 'schema';
use base 'Exporter'; use base 'Exporter';
our @EXPORT = (); our @EXPORT = ();
our @EXPORT_OK = qw/ add_jobs capacity_for take_jobs reset_jobs/; our @EXPORT_OK = qw/ add_jobs capacity_for take_jobs reset_jobs release_jobs /;
our %EXPORT_TAGS = ( all => \@EXPORT_OK ); our %EXPORT_TAGS = ( all => \@EXPORT_OK );
schema('daemon')->deploy; schema('daemon')->deploy;
@@ -59,4 +59,11 @@ sub reset_jobs {
->update({wid => 0}); ->update({wid => 0});
} }
# not used by workers, only the daemon when reinitializing a worker
sub release_jobs {
my ($jid) = @_;
debug "releasing local job ID $jid";
$queue->search({job => $jid})->delete;
}
1; 1;

View File

@@ -27,7 +27,16 @@ sub set_portcontrol {
(my $sa = $job->subaction) =~ s/-\w+//; (my $sa = $job->subaction) =~ s/-\w+//;
$job->subaction($sa); $job->subaction($sa);
return _set_port_generic($job, 'up_admin'); if ($sa eq 'bounce') {
$job->subaction('down');
my @stat = _set_port_generic($job, 'up_admin');
return @stat if $stat[0] ne 'done';
$job->subaction('up');
return _set_port_generic($job, 'up_admin');
}
else {
return _set_port_generic($job, 'up_admin');
}
} }
sub set_vlan { sub set_vlan {

View File

@@ -143,12 +143,19 @@ sub jq_lock {
return $happy; return $happy;
} }
# PostgreSQL engine depends on LocalQueue, which is accessed synchronously via
# the main daemon process. This is only used by daemon workers which can use
# MCE ->do() method.
sub jq_defer { sub jq_defer {
my $job = shift; my $job = shift;
my $happy = false; my $happy = false;
# lock db row and update to show job is available
try { try {
# other local workers are polling the central queue, so
# to prevent a race, first delete the job in our local queue
MCE->do('release_jobs', $job->id);
# lock db row and update to show job is available
schema('netdisco')->txn_do(sub { schema('netdisco')->txn_do(sub {
schema('netdisco')->resultset('Admin') schema('netdisco')->resultset('Admin')
->find($job->id, {for => 'update'}) ->find($job->id, {for => 'update'})

View File

@@ -22,7 +22,7 @@ function port_control (e) {
device: td.data('for-device') device: td.data('for-device')
,port: td.data('for-port') ,port: td.data('for-port')
,field: td.data('field') ,field: td.data('field')
,action: td.data('action') ,action: ($(e).data('action') || td.data('action'))
,value: td.text().trim() ,value: td.text().trim()
,reason: reason ,reason: reason
,log: logmessage ,log: logmessage
@@ -30,31 +30,35 @@ function port_control (e) {
,success: function() { ,success: function() {
toastr.info('Submitted change request'); toastr.info('Submitted change request');
// update all the screen furniture for port up/down control // update all the screen furniture unless bouncing
if ($.trim(td.data('action')) == 'down') { if (! $(e).hasClass('icon-bullseye')) {
td.prev('td').html('<i class="icon-remove"></i>'); if ($.trim(td.data('action')) == 'down') {
$(e).toggleClass('icon-hand-down'); td.prev('td').html('<i class="icon-remove"></i>');
$(e).toggleClass('icon-hand-up'); $(e).toggleClass('icon-hand-down');
$(e).data('tooltip').options.title = 'Click to Enable'; $(e).toggleClass('icon-hand-up');
td.data('action', 'up'); $(e).siblings('.icon-bullseye').hide();
} $(e).data('tooltip').options.title = 'Enable Port';
else if ($.trim(td.data('action')) == 'up') { td.data('action', 'up');
td.prev('td').html('<i class="icon-refresh icon-spin"></i>'); }
$(e).toggleClass('icon-hand-up'); else if ($.trim(td.data('action')) == 'up') {
$(e).toggleClass('icon-hand-down'); td.prev('td').html('<i class="icon-refresh icon-spin"></i>');
$(e).data('tooltip').options.title = 'Click to Disable'; $(e).toggleClass('icon-hand-up');
td.data('action', 'down'); $(e).toggleClass('icon-hand-down');
} $(e).siblings('.icon-bullseye').show();
else if ($.trim(td.data('action')) == 'false') { $(e).data('tooltip').options.title = 'Disable Port';
$(e).next('span').text(''); td.data('action', 'down');
$(e).toggleClass('nd_power-on'); }
$(e).data('tooltip').options.title = 'Click to Enable'; else if ($.trim(td.data('action')) == 'false') {
td.data('action', 'true'); $(e).next('span').text('');
} $(e).toggleClass('nd_power-on');
else if ($.trim(td.data('action')) == 'true') { $(e).data('tooltip').options.title = 'Enable Power';
$(e).toggleClass('nd_power-on'); td.data('action', 'true');
$(e).data('tooltip').options.title = 'Click to Disable'; }
td.data('action', 'false'); else if ($.trim(td.data('action')) == 'true') {
$(e).toggleClass('nd_power-on');
$(e).data('tooltip').options.title = 'Disable Power';
td.data('action', 'false');
}
} }
} }
,error: function() { ,error: function() {
@@ -118,7 +122,7 @@ $(document).ready(function() {
}); });
// activity for port up/down control, power enable/disable control // activity for port up/down control, power enable/disable control
$('#ports_pane').on('click', '.icon-hand-up,.icon-hand-down,.nd_pointer-icon', function() { $('#ports_pane').on('click', '.icon-hand-up,.icon-hand-down,.nd_pointer-icon,.icon-bullseye', function() {
var clicked = this; // create a closure var clicked = this; // create a closure
$('#nd_portlog').one('hidden', function() { $('#nd_portlog').one('hidden', function() {
port_control(clicked); // save port_control(clicked); // save

View File

@@ -62,16 +62,26 @@
<td nowrap class="nd_editable-cell" data-action="down" <td nowrap class="nd_editable-cell" data-action="down"
data-order="[% row.port | html_entity %]" data-filter="[% row.port | html_entity %]" data-order="[% row.port | html_entity %]" data-filter="[% row.port | html_entity %]"
data-field="c_port" data-for-device="[% device.ip | html_entity %]" data-for-port="[% row.port | html_entity %]"> data-field="c_port" data-for-device="[% device.ip | html_entity %]" data-for-port="[% row.port | html_entity %]">
<i class="icon-hand-down nd_hand-icon" <span class="nd_hand-icon">
rel="tooltip" data-placement="top" data-offset="3" <i class="icon-bullseye" data-action="bounce"
data-animation="" data-title="Click to Disable"></i> rel="tooltip" data-placement="top" data-offset="3"
data-animation="" data-title="Bounce Port"></i>
<i class="icon-hand-down"
rel="tooltip" data-placement="top" data-offset="3"
data-animation="" data-title="Disable Port"></i>
</span>
[% ELSE %] [% ELSE %]
<td nowrap class="nd_editable-cell" data-action="up" <td nowrap class="nd_editable-cell" data-action="up"
data-order="[% row.port | html_entity %]" data-filter="[% row.port | html_entity %]" data-order="[% row.port | html_entity %]" data-filter="[% row.port | html_entity %]"
data-field="c_port" data-for-device="[% device.ip | html_entity %]" data-for-port="[% row.port | html_entity %]"> data-field="c_port" data-for-device="[% device.ip | html_entity %]" data-for-port="[% row.port | html_entity %]">
<i class="icon-hand-up nd_hand-icon" <span class="nd_hand-icon">
rel="tooltip" data-placement="top" data-offset="3" <i class="icon-bullseye" data-action="bounce" style="display: none"
data-animation="" data-title="Click to Enable"></i> rel="tooltip" data-placement="top" data-offset="3"
data-animation="" data-title="Bounce Port"></i>
<i class="icon-hand-up"
rel="tooltip" data-placement="top" data-offset="3"
data-animation="" data-title="Enable Port"></i>
</span>
[% END %] [% END %]
<a class="nd_log-icon" <a class="nd_log-icon"
href="[% uri_for('/report/portlog') %]?q=[% device.ip | uri %]&f=[% row.port | uri %]"> href="[% uri_for('/report/portlog') %]?q=[% device.ip | uri %]&f=[% row.port | uri %]">
@@ -208,7 +218,7 @@
<i class="icon-off nd_pointer-icon nd_power-on" <i class="icon-off nd_pointer-icon nd_power-on"
rel="tooltip" data-placement="top" data-offset="3" rel="tooltip" data-placement="top" data-offset="3"
data-animation="" data-title="Click to Disable"></i> data-animation="" data-title="Disable Power"></i>
[% ELSE %] [% ELSE %]
<td nowrap> <td nowrap>
<i class="icon-off nd_power-on"></i> <i class="icon-off nd_power-on"></i>
@@ -228,7 +238,7 @@
<i class="icon-off nd_pointer-icon" <i class="icon-off nd_pointer-icon"
rel="tooltip" data-placement="top" data-offset="3" rel="tooltip" data-placement="top" data-offset="3"
data-animation="" data-title="Click to Enable"></i> data-animation="" data-title="Enable Power"></i>
[% ELSE %] [% ELSE %]
<td> <td>
<i class="icon-off"></i> <i class="icon-off"></i>