From f70a7ec4241f1891e185690c99390fdf18044131 Mon Sep 17 00:00:00 2001 From: Guillaume Bougard Date: Wed, 4 Oct 2023 15:24:20 +0200 Subject: [PATCH] feat: Refacto NetDisco-Devices target storage Store deviceid defined during ESX inventory Update ESX task to reuse stored deviceid on next netscan This avoid inventory files duplication in local target folder --- lib/GLPI/Agent/Task/ESX.pm | 24 ++++++++---- lib/GLPI/Agent/Task/NetDiscovery.pm | 59 ++++++++++++++++++++++++++--- 2 files changed, 70 insertions(+), 13 deletions(-) diff --git a/lib/GLPI/Agent/Task/ESX.pm b/lib/GLPI/Agent/Task/ESX.pm index cdef9dece..336083cfa 100644 --- a/lib/GLPI/Agent/Task/ESX.pm +++ b/lib/GLPI/Agent/Task/ESX.pm @@ -45,7 +45,7 @@ sub connect { } sub createInventory { - my ( $self, $id, $tag ) = @_; + my ( $self, $id, $tag, $deviceid ) = @_; die unless $self->{vpbs}; @@ -54,9 +54,11 @@ sub createInventory { my $host = $vpbs->getHostFullInfo($id); my $inventory = GLPI::Agent::Inventory->new( - datadir => $self->{datadir}, - logger => $self->{logger}, - tag => $tag + datadir => $self->{datadir}, + logger => $self->{logger}, + tag => $tag, + # deviceid can be set and so reused from previous netscan + deviceid => $deviceid ); $inventory->setRemote('esx'); @@ -226,7 +228,7 @@ sub run { sub serverInventory { # $host_callback can be used to dump datas retrieved from ESX server as done by glpi-esx # and is only used for local target - my ($self, $path, $host_callback) = @_; + my ($self, $path, $host_callback, $deviceids) = @_; # Initialize GLPI server submission if required if ($self->{target}->isType('server') && !$self->{serverclient}) { @@ -271,8 +273,10 @@ sub serverInventory { my $hostIds = $self->getHostIds(); foreach my $hostId (@$hostIds) { + my $deviceid; + $deviceid = $deviceids->{$hostId} if ref($deviceids) eq 'HASH'; my $inventory = $self->createInventory( - $hostId, $self->{config}->{tag} + $hostId, $self->{config}->{tag}, $deviceid ); if ($self->{target}->isType('server')) { @@ -308,7 +312,13 @@ sub serverInventory { last; } if (ref($host_callback) eq 'CODE') { - &{$host_callback}($hostId, $file); + # $devices is set when called by netscan to keep esx deviceid consistent + # and don't duplicate inventory file when storing them + if ($deviceids) { + &{$host_callback}($inventory, $hostId); + } else { + &{$host_callback}($hostId, $file); + } } } } diff --git a/lib/GLPI/Agent/Task/NetDiscovery.pm b/lib/GLPI/Agent/Task/NetDiscovery.pm index 3347872b1..47ff2f271 100644 --- a/lib/GLPI/Agent/Task/NetDiscovery.pm +++ b/lib/GLPI/Agent/Task/NetDiscovery.pm @@ -369,6 +369,7 @@ sub run { my $esxscan = delete $result->{_esxscan}; my $authsnmp = $result->{AUTHSNMP}; + my $deviceid; # AUTHREMOTE can be set in results but is not actually supported by GLPI my $authremote = delete $result->{AUTHREMOTE}; if (($authsnmp || $authremote) && $job->localtask) { @@ -376,15 +377,16 @@ sub run { delete $result->{AUTHSNMP}; # For TooBox, we keep used authsnmp|authremote & ip_range for results page in target storage if ($self->{target}->isType('local')) { - my $storage = $self->{target}->getStorage(); - my $devices = $storage->restore(name => "NetDisco-Devices") // {}; - $devices->{$result->{IP}} = { + my $device = $self->_storeNetDiscoDevices( + ip => $result->{IP}, credential => $authsnmp || $authremote, ip_range => $range->{name}, # Set expiration to ~3 months (3*30*86400) expiration => time + 7776000 - }; - $storage->save(name => "NetDisco-Devices", data => $devices); + ); + # Still keep eventually known deviceid for later check + $deviceid = $device->{deviceid} + if defined($device->{deviceid}); } } @@ -430,6 +432,17 @@ sub run { $inventory->run(); } elsif ($authremote) { + my $collectdeviceid = sub { + my ($inventory, $hostid) = @_; + # No need to update deviceid if used one if the stored one + return if ($hostid && ref($deviceid) eq 'HASH' && $inventory->getDeviceId() eq $deviceid->{$hostid}) + || ($deviceid && $inventory->getDeviceId() eq $deviceid); + $self->_storeNetDiscoDevices( + ip => $result->{IP}, + deviceid => $inventory->getDeviceId(), + hostid => $hostid + ); + }; my $credentials = first { $_->{ID} eq $authremote } @{$jobaddress->{remote_credentials}}; if ($credentials) { my $path; @@ -438,7 +451,7 @@ sub run { $path .= '/inventory' if $path eq '.'; if ($credentials->{TYPE} eq 'esx' && $esxscan) { # As we still have run the connection part in _scanAddressByRemote(), we reuse the connected object - $esxscan->serverInventory($path); + $esxscan->serverInventory($path, $collectdeviceid, $deviceid); } else { GLPI::Agent::Task::RemoteInventory->require(); # TODO Support RemoteInventory task run @@ -481,6 +494,40 @@ sub run { setExpirationTime(); } +sub _storeNetDiscoDevices { + my ($self, %params) = @_; + + my $storage = $self->{target}->getStorage() + or return; + + my $ip = $params{ip} + or return; + + my $devices = $storage->restore(name => "NetDisco-Devices") // {}; + my $hostid = $params{hostid}; + my $updated = $devices->{$ip} ? 0 : 1; + my $device = $devices->{$ip} // {}; + + foreach my $key (qw{credential ip_range expiration deviceid}) { + next unless defined($params{$key}); + if ($key eq 'deviceid' && $hostid) { + $device->{$key} = {} unless ref($device->{$key}) eq 'HASH'; + next if defined($device->{$key}->{$hostid}) && $device->{$key}->{$hostid} eq $params{$key}; + $device->{$key}->{$hostid} = $params{$key}; + } else { + next if defined($device->{$key}) && $device->{$key} eq $params{$key}; + $device->{$key} = $params{$key}; + } + $updated++; + } + + $devices->{$ip} = $device; + $storage->save(name => "NetDisco-Devices", data => $devices) + if $updated; + + return $device; +} + sub _logExpirationHours { my ($self, $expiration) = @_;