implementation of first per port control - untested

This commit is contained in:
Oliver Gorwits
2012-12-06 22:54:44 +00:00
parent c153bfe593
commit 5423f18cb1
2 changed files with 151 additions and 9 deletions

View File

@@ -3,6 +3,55 @@ package Netdisco::PortControl::Actions;
use Netdisco::Util ':port_control'; use Netdisco::Util ':port_control';
use Try::Tiny; use Try::Tiny;
sub portcontrol {
my ($self, $job) = @_;
my $ip = $job->device;
my $pn = $job->port;
(my $dir = $job->subaction) =~ s/-\w+//;
try {
my $port = get_port($ip, $pn)
or return _error("Unknown port name [$pn] on device [$ip]");
my $reconfig_check = port_reconfig_check($port);
return _error("Cannot alter port: $reconfig_check")
if length $reconfig_check;
# snmp connect using rw community
my $info = snmp_connect($ip)
or return _error("Failed to connect to device [$ip] to control port");
my $iid = get_iid($port)
or return _error("Failed to get port ID for [$pn] from [$ip]");
my $rv = $info->set_i_up_admin(lc($dir), $iid);
return _error("Failed to set [$pn] port status to [$dir] on [$ip]")
if !defined $rv;
# confirm the set happened
$info->clear_cache;
my $state = ($info->i_up_admin($iid) || '');
if ($state ne $dir) {
return _error("Verify of [$pn] port status failed on [$ip]: $state");
}
# get device details from db
my $device = $port->device
or return _error("Updated [$pn] port status on [$ip] but failed to update DB");
# update netdisco DB
$device->update({up_admin => $state});
return _done("Updated [$pn] port status on [$ip] to [$state]");
}
catch {
return _error("Failed to update [$pn] port status on [$ip]: $_");
};
}
sub set_location { sub set_location {
my ($self, $job) = @_; my ($self, $job) = @_;
return $self->_set_generic($job->device, 'location', $job->subaction); return $self->_set_generic($job->device, 'location', $job->subaction);
@@ -34,7 +83,7 @@ sub _set_generic {
$info->clear_cache; $info->clear_cache;
my $new_data = ($info->$slot || ''); my $new_data = ($info->$slot || '');
if ($new_data ne $data) { if ($new_data ne $data) {
return _error("Verify of $slot update failed on [$ip]"); return _error("Verify of $slot update failed on [$ip]: $new_data");
} }
# get device details from db # get device details from db

View File

@@ -12,13 +12,18 @@ use Try::Tiny;
use base 'Exporter'; use base 'Exporter';
our @EXPORT = (); our @EXPORT = ();
our @EXPORT_OK = qw/ our @EXPORT_OK = qw/
is_discoverable
load_nd_config load_nd_config
get_device is_discoverable
is_vlan_interface port_has_phone
get_device get_port get_iid
vlan_reconfig_check port_reconfig_check
snmp_connect snmp_connect
sort_port sort_port
/; /;
our %EXPORT_TAGS = (port_control => [qw/get_device snmp_connect/]); our %EXPORT_TAGS = (port_control => [qw/
get_device get_port snmp_connect
port_reconfig_check
/]);
=head1 Netdisco::Util =head1 Netdisco::Util
@@ -126,12 +131,92 @@ sub get_device {
->find({ip => $alias->ip}); ->find({ip => $alias->ip});
} }
sub _build_mibdirs { sub get_port {
my $mibhome = var('nd_config')->{_}->{mibhome}; my ($device, $portname) = @_;
(my $mibdirs = var('nd_config')->{_}->{mibdirs}) =~ s/\s+//g;
$mibdirs =~ s/\$mibhome/$mibhome/g; # accept either ip or dbic object
return [ split /,/, $mibdirs ]; $device = get_device($device)
if not ref $device;
my $port = schema('Netdisco')->resultset('DevicePort')
->find({ip => $device->ip, port => $portname});
return $port;
}
sub get_iid {
my ($info, $port) = @_;
# accept either port name or dbic object
$port = $port->port if ref $port;
my $interfaces = $info->interfaces;
my %rev_if = reverse %$interfaces;
my $iid = $rev_if{$port};
return $iid;
}
sub is_vlan_interface {
my $port = shift;
my $is_vlan = (($port->type and
$port->type =~ /^(53|propVirtual|l2vlan|l3ipvlan|135|136|137)$/i)
or ($port->port and $port->port =~ /vlan/i)
or ($port->name and $port->name =~ /vlan/i)) ? 1 : 0;
return $is_vlan;
}
sub port_has_phone {
my $port = shift;
my $has_phone = ($port->remote_type
and $port->remote_type =~ /ip.phone/i) ? 1 : 0;
return $has_phone;
}
sub vlan_reconfig_check {
my $port = shift;
my $ip = $port->ip;
my $name = $port->port;
my $nd_config = var('nd_config')->{_};
my $is_vlan = is_vlan_interface($port);
# vlan (routed) interface check
return "forbidden: [$name] is a vlan interface on [$ip]"
if $is_vlan;
return "forbidden: not permitted to change native vlan"
if not $nd_config->{vlanctl};
return;
}
sub port_reconfig_check {
my $port = shift;
my $ip = $port->ip;
my $name = $port->port;
my $nd_config = var('nd_config')->{_};
my $has_phone = has_phone($port);
my $is_vlan = is_vlan_interface($port);
# uplink check
return "forbidden: port [$name] on [$ip] is an uplink"
if $port->remote_type and not $has_phone and not $nd_config->{allow_uplinks};
# phone check
return "forbidden: port [$name] on [$ip] is a phone"
if $has_phone and $nd_config->{portctl_nophones};
# vlan (routed) interface check
return "forbidden: [$name] is a vlan interface on [$ip]"
if $is_vlan and not $nd_config->{portctl_vlans};
return;
} }
=head2 snmp_connect( $ip ) =head2 snmp_connect( $ip )
@@ -185,6 +270,14 @@ sub snmp_connect {
return $info; return $info;
} }
sub _build_mibdirs {
my $mibhome = var('nd_config')->{_}->{mibhome};
(my $mibdirs = var('nd_config')->{_}->{mibdirs}) =~ s/\s+//g;
$mibdirs =~ s/\$mibhome/$mibhome/g;
return [ split /,/, $mibdirs ];
}
=head2 sort_port( $a, $b ) =head2 sort_port( $a, $b )
Sort port names of various types used by device vendors. Interface is as Sort port names of various types used by device vendors. Interface is as