From c2a0892354f80125f0f1c24e926512b04c6f2063 Mon Sep 17 00:00:00 2001 From: Matthieu CERDA Date: Fri, 7 Oct 2016 10:30:55 +0200 Subject: [PATCH] Fixes #166: inventory the local timezone name and offset to UTC --- Makefile.PL | 11 ++- README | 1 + lib/FusionInventory/Agent/Inventory.pm | 2 +- .../Agent/Task/Inventory/Generic/Timezone.pm | 96 +++++++++++++++++++ 4 files changed, 104 insertions(+), 6 deletions(-) create mode 100644 lib/FusionInventory/Agent/Task/Inventory/Generic/Timezone.pm diff --git a/Makefile.PL b/Makefile.PL index 7c9b6cb977..e8b8dde362 100644 --- a/Makefile.PL +++ b/Makefile.PL @@ -32,10 +32,10 @@ recommends 'IO::Socket::SSL' => '1.14'; recommends 'LWP::Protocol::https' => '0'; if ($OSNAME ne 'MSWin32') { - recommends 'Proc::Daemon' => '0'; - recommends 'Proc::PID::File' => '0'; + recommends 'Proc::Daemon' => '0'; + recommends 'Proc::PID::File' => '0'; } else { - recommends 'Win32::Daemon' => '0'; + recommends 'Win32::Daemon' => '0'; recommends 'Win32::Unicode::File' => '0'; } @@ -59,8 +59,9 @@ test_requires 'Net::SNMP' => '0'; test_requires 'Parallel::ForkManager' => '0'; # Inventory -recommends 'Parse::EDID' => '0'; -recommends 'Net::CUPS' => 0.60 if $OSNAME ne 'MSWin32'; +recommends 'Parse::EDID' => '0'; +recommends 'Net::CUPS' => 0.60 if $OSNAME ne 'MSWin32'; +recommends 'DateTime' => '0'; # Deploy recommends 'Archive::Extract' => '0'; diff --git a/README b/README index 09d892c2d6..80f9edeb1f 100644 --- a/README +++ b/README @@ -40,6 +40,7 @@ Optional Perl modules: * Net::CUPS, for printers detection * Parse::EDID, for EDID data parsing +* DateTime, for reliable timezone name extraction Optional programs: diff --git a/lib/FusionInventory/Agent/Inventory.pm b/lib/FusionInventory/Agent/Inventory.pm index c5f1b98c64..73b39a708c 100644 --- a/lib/FusionInventory/Agent/Inventory.pm +++ b/lib/FusionInventory/Agent/Inventory.pm @@ -25,7 +25,7 @@ my %fields = ( VMNAME VMHOSTSERIAL/ ], OPERATINGSYSTEM => [ qw/KERNEL_NAME KERNEL_VERSION NAME VERSION FULL_NAME SERVICE_PACK INSTALL_DATE FQDN DNS_DOMAIN - SSH_KEY ARCH BOOT_TIME/ ], + SSH_KEY ARCH BOOT_TIME TIMEZONE/ ], ACCESSLOG => [ qw/USERID LOGDATE/ ], ANTIVIRUS => [ qw/COMPANY ENABLED GUID NAME UPTODATE VERSION diff --git a/lib/FusionInventory/Agent/Task/Inventory/Generic/Timezone.pm b/lib/FusionInventory/Agent/Task/Inventory/Generic/Timezone.pm new file mode 100644 index 0000000000..d12699bb3a --- /dev/null +++ b/lib/FusionInventory/Agent/Task/Inventory/Generic/Timezone.pm @@ -0,0 +1,96 @@ +package FusionInventory::Agent::Task::Inventory::Generic::Timezone; + +use strict; +use warnings; + +use English qw(-no_match_vars); +use UNIVERSAL::require; + +use POSIX; +use Time::Local; + +use FusionInventory::Agent::Tools; + +my $seen; + +sub isEnabled { + + # No specific dependencies necessary + return 1; +} + +sub doInventory { + my (%params) = @_; + + my $inventory = $params{inventory}; + my $logger = $params{logger}; + + # Compute a timezone offset like '+0200' using the difference between UTC and local time + # Might require merging with detectLocalTimeOffset (macOS inventory) in the future + + ## Get the local time + my @t = localtime(time); + + ## Compute the time offset in seconds between local and UTC time (relative and absolute) + my $utc_offset_seconds = timegm(@t) - timelocal(@t); + my $utc_offset_seconds_abs = abs($utc_offset_seconds); + + ## Offset sign is minus if $utc_offset_seconds is negative, plus otherwise. + my $offset_sign = $utc_offset_seconds < 0 ? '-' : '+'; + + ## Format the offset string: sign + H (XX) + M (XX) + my $tz_offset = + strftime( $offset_sign . "\%H\%M", gmtime($utc_offset_seconds_abs) ); + + # Assume by default that the offset is empty (safe default in case something goes wrong below) + my $tz_name = ''; + + # Timezone name extraction will use one of the following sources: + # * DateTime::TimeZone and DateTime::TimeZone::Local::{Win32,Unix} => 'Europe/Paris' + # * tzutil (Win 7+, Win 2008+) => 'Romance Standard Time' + # * strftime '%Z' => 'CEST' + # + # strftime will not be used on Windows, as it returns unpredictable localized TZ names. It means + # that if reliable timezone name extraction is wanted, DateTime::TimeZone MUST be used. + if ( + ( DateTime::TimeZone->require() ) + && ( $OSNAME eq 'MSWin32' + ? DateTime::TimeZone::Local::Win32->require() + : DateTime::TimeZone::Local::Unix->require() ) + ) + { + $logger->debug("Using DateTime::TimeZone to get the timezone name"); + $tz_name = DateTime::TimeZone->new( name => 'local' )->name(); + } + elsif ( ( $OSNAME eq 'MSWin32' ) || ( canRun('tzutil') ) ) { + + $logger->debug("Using tzutil to get the timezone name"); + + my $handle = getFileHandle( + logger => $logger, + command => 'tzutil /g', + ); + + while ( my $line = <$handle> ) { + $tz_name = $line; + } + close $handle; + + } + elsif ( $OSNAME ne 'MSWin32' ) { + $logger->debug("Using strftime to get the timezone name"); + $tz_name = strftime( "%Z", localtime() ); + } + + $inventory->setOperatingSystem( + { + TIMEZONE => { + NAME => $tz_name, + OFFSET => $tz_offset, + } + } + ); + +} + +1;