From 9179b410e77d04287752bd828206cd131631ee3d Mon Sep 17 00:00:00 2001 From: Oliver Gorwits Date: Wed, 4 Feb 2015 15:00:00 +0000 Subject: [PATCH] [#197] Change IP address of device with "renumber" option to netdisco-do --- Netdisco/Changes | 1 + Netdisco/bin/netdisco-do | 35 +++++++++- Netdisco/lib/App/Netdisco/DB/Result/Device.pm | 64 +++++++++++++++++++ .../lib/App/Netdisco/DB/Result/DevicePort.pm | 14 ---- Netdisco/lib/App/Netdisco/Util/Device.pm | 31 +++++++++ 5 files changed, 130 insertions(+), 15 deletions(-) diff --git a/Netdisco/Changes b/Netdisco/Changes index 8d9b0c90..bba7b554 100644 --- a/Netdisco/Changes +++ b/Netdisco/Changes @@ -4,6 +4,7 @@ * [#171] Log files now rotate at 10MB up to seven times * Delete device from CLI with new "delete" option to netdisco-do + * [#197] Change IP address of device with "renumber" option to netdisco-do [ENHANCEMENTS] diff --git a/Netdisco/bin/netdisco-do b/Netdisco/bin/netdisco-do index b2eec25e..6b51ac10 100755 --- a/Netdisco/bin/netdisco-do +++ b/Netdisco/bin/netdisco-do @@ -113,7 +113,8 @@ unless ($action) { } use App::Netdisco::Util::SNMP (); - use App::Netdisco::Util::Device qw/get_device delete_device/; + use App::Netdisco::Util::Device + qw/get_device delete_device renumber_device/; use NetAddr::IP::Lite ':lower'; use Scalar::Util 'blessed'; @@ -154,6 +155,27 @@ unless ($action) { delete_device($dev->ip, $archive, $extra); return ('done', "Deleted device $device."); } + + sub renumber { + my $ip = NetAddr::IP::Lite->new($device) + or return ('error', "Bad host or IP: $device"); + my $dev = get_device($ip->addr); + unless (blessed $dev and $dev->in_storage) { + return ('error', "Don't know device: $device"); + } + my $old_ip = $dev->ip; + + my $new_ip = NetAddr::IP::Lite->new($extra) + or return ('error', "Bad host or IP: $extra"); + my $new_dev = get_device($new_ip->addr); + unless ($new_dev and not $new_dev->in_storage) { + return ('error', "Already know new device: $device"); + } + + renumber_device($dev->ip, $new_dev->ip); + return ('done', sprintf 'Renumbered device %s from %s to %s.', + $device, $old_ip, $new_dev->ip); + } } my $worker = MyWorker->new(); @@ -237,6 +259,17 @@ the C<-e> parameter. Optionally request for associated nodes to be archived ~netdisco/bin/netdisco-do delete -d 192.0.2.1 -e 'older than the sun' ~netdisco/bin/netdisco-do delete -d 192.0.2.1 -e '1,older than the sun' +=head2 renumber + +Change the canonical IP address of a device (specified with C<-d>). Pass the +new IP address in the C<-e> parameter. All related records such as topology, +log and node information will also be updated to refer to the new device. + +Note that I check is made as to whether the new IP is reachable for future +polling. + + ~netdisco/bin/netdisco-do renumber -d 192.0.2.1 -e 192.0.2.254 + =head2 nbtstat Run an nbtstat on the node (specified with C<-d>). diff --git a/Netdisco/lib/App/Netdisco/DB/Result/Device.pm b/Netdisco/lib/App/Netdisco/DB/Result/Device.pm index 19aefbc2..62ae78d0 100644 --- a/Netdisco/lib/App/Netdisco/DB/Result/Device.pm +++ b/Netdisco/lib/App/Netdisco/DB/Result/Device.pm @@ -6,6 +6,7 @@ package App::Netdisco::DB::Result::Device; use strict; use warnings; +use NetAddr::IP::Lite ':lower'; use base 'DBIx::Class::Core'; __PACKAGE__->table("device"); @@ -186,6 +187,69 @@ Returns the row from the community string table, if one exists. __PACKAGE__->might_have( community => 'App::Netdisco::DB::Result::Community', 'ip'); +=head1 ADDITIONAL METHODS + +=head2 renumber( $new_ip ) + +Will update this device and all related database records to use the new IP +C<$new_ip>. Returns C if $new_ip seems invalid, otherwise returns the +Device row object. + +=cut + +sub renumber { + my ($device, $ip) = @_; + my $schema = $device->result_source->schema; + + my $new_ip = NetAddr::IP::Lite->new($ip) + or return; + + foreach my $set (qw/ + DeviceIp + DeviceModule + DevicePower + DeviceVlan + DevicePort + DevicePortLog + DevicePortPower + DevicePortSsid + DevicePortVlan + DevicePortWireless + Community + /) { + $schema->resultset($set) + ->search({ip => $device->ip}) + ->update({ip => $new_ip->addr}); + } + + $schema->resultset('DevicePort') + ->search({remote_ip => $device->ip}) + ->update({remote_ip => $new_ip->addr}); + + $schema->resultset('DeviceIp') + ->search({alias => $device->ip}) + ->update({alias => $new_ip->addr}); + + $schema->resultset('Admin') + ->search({device => $device->ip}) + ->update({device => $new_ip->addr}); + + $schema->resultset('Node') + ->search({switch => $device->ip}) + ->update({switch => $new_ip->addr}); + + $schema->resultset('Topology') + ->search({dev1 => $device->ip}) + ->update({dev1 => $new_ip->addr}); + $schema->resultset('Topology') + ->search({dev2 => $device->ip}) + ->update({dev2 => $new_ip->addr}); + + $device->update({ip => $new_ip->addr}); + + return $device; +} + =head1 ADDITIONAL COLUMNS =head2 port_count diff --git a/Netdisco/lib/App/Netdisco/DB/Result/DevicePort.pm b/Netdisco/lib/App/Netdisco/DB/Result/DevicePort.pm index 137225ed..8093e42e 100644 --- a/Netdisco/lib/App/Netdisco/DB/Result/DevicePort.pm +++ b/Netdisco/lib/App/Netdisco/DB/Result/DevicePort.pm @@ -195,20 +195,6 @@ __PACKAGE__->might_have( } ); -=head2 ssid - -Returns a row from the C table if one refers to this -device port. - -=cut - -__PACKAGE__->might_have( - ssid => 'App::Netdisco::DB::Result::DevicePortSsid', - { 'foreign.ip' => 'self.ip', - 'foreign.port' => 'self.port', - } -); - =head2 wireless Returns a row from the C table if one refers to this diff --git a/Netdisco/lib/App/Netdisco/Util/Device.pm b/Netdisco/lib/App/Netdisco/Util/Device.pm index a5677516..6329c376 100644 --- a/Netdisco/lib/App/Netdisco/Util/Device.pm +++ b/Netdisco/lib/App/Netdisco/Util/Device.pm @@ -9,6 +9,7 @@ our @EXPORT = (); our @EXPORT_OK = qw/ get_device delete_device + renumber_device check_device_no check_device_only is_discoverable @@ -95,6 +96,36 @@ sub delete_device { return $happy; } +=head2 renumber_device( $current_ip, $new_ip ) + +Will update all records in Netdisco referring to the device with +C<$current_ip> to use C<$new_ip> instead, followed by renumbering the device +iteself. + +Returns true if the transaction completes, else returns false. + +=cut + +sub renumber_device { + my ($ip, $new_ip) = @_; + my $device = get_device($ip) or return 0; + return 0 if not $device->in_storage; + + my $happy = 0; + schema('netdisco')->txn_do(sub { + schema('netdisco')->resultset('UserLog')->create({ + username => session('logged_in_user'), + userip => scalar eval {request->remote_address}, + event => "Renumbered device from $ip to $new_ip", + }); + + $device->renumber($new_ip); + $happy = 1; + }); + + return $happy; +} + =head2 check_device_no( $ip, $setting_name ) Given the IP address of a device, returns true if the configuration setting