init III
This commit is contained in:
475
Perl OTRS/Kernel/System/SupportDataCollector.pm
Normal file
475
Perl OTRS/Kernel/System/SupportDataCollector.pm
Normal file
@@ -0,0 +1,475 @@
|
||||
# --
|
||||
# Copyright (C) 2001-2019 OTRS AG, https://otrs.com/
|
||||
# --
|
||||
# This software comes with ABSOLUTELY NO WARRANTY. For details, see
|
||||
# the enclosed file COPYING for license information (GPL). If you
|
||||
# did not receive this file, see https://www.gnu.org/licenses/gpl-3.0.txt.
|
||||
# --
|
||||
|
||||
package Kernel::System::SupportDataCollector;
|
||||
|
||||
use strict;
|
||||
use warnings;
|
||||
|
||||
use File::Basename;
|
||||
|
||||
use Kernel::System::WebUserAgent;
|
||||
|
||||
our @ObjectDependencies = (
|
||||
'Kernel::Config',
|
||||
'Kernel::System::Cache',
|
||||
'Kernel::System::Encode',
|
||||
'Kernel::System::JSON',
|
||||
'Kernel::System::Log',
|
||||
'Kernel::System::Main',
|
||||
'Kernel::System::SystemData',
|
||||
);
|
||||
|
||||
=head1 NAME
|
||||
|
||||
Kernel::System::SupportDataCollector - system data collector
|
||||
|
||||
=head1 DESCRIPTION
|
||||
|
||||
All stats functions.
|
||||
|
||||
=head1 PUBLIC INTERFACE
|
||||
|
||||
=head2 new()
|
||||
|
||||
Don't use the constructor directly, use the ObjectManager instead:
|
||||
|
||||
my $SupportDataCollectorObject = $Kernel::OM->Get('Kernel::System::SupportDataCollector');
|
||||
|
||||
|
||||
=cut
|
||||
|
||||
sub new {
|
||||
my ( $Type, %Param ) = @_;
|
||||
|
||||
# allocate new hash ref to object
|
||||
my $Self = {};
|
||||
bless( $Self, $Type );
|
||||
|
||||
return $Self;
|
||||
}
|
||||
|
||||
=head2 Collect()
|
||||
|
||||
collect system data
|
||||
|
||||
my %Result = $SupportDataCollectorObject->Collect(
|
||||
UseCache => 1, # (optional) to get data from cache if any
|
||||
WebTimeout => 60, # (optional)
|
||||
Debug => 1, # (optional)
|
||||
Hostname => 'my.test.host:8080' # (optional, for testing purposes)
|
||||
);
|
||||
|
||||
returns in case of error
|
||||
|
||||
(
|
||||
Success => 0,
|
||||
ErrorMessage => '...',
|
||||
)
|
||||
|
||||
otherwise
|
||||
|
||||
(
|
||||
Success => 1,
|
||||
Result => [
|
||||
{
|
||||
Identifier => 'Kernel::System::SupportDataCollector::OTRS::Version',
|
||||
DisplayPath => 'OTRS',
|
||||
Status => $StatusOK,
|
||||
Label => 'OTRS Version'
|
||||
Value => '3.3.2',
|
||||
Message => '',
|
||||
},
|
||||
{
|
||||
Identifier => 'Kernel::System::SupportDataCollector::Apache::mod_perl',
|
||||
DisplayPath => 'OTRS',
|
||||
Status => $StatusProblem,
|
||||
Label => 'mod_perl usage'
|
||||
Value => '0',
|
||||
Message => 'Please enable mod_perl to speed up OTRS.',
|
||||
},
|
||||
{
|
||||
Identifier => 'Some::Identifier',
|
||||
DisplayPath => 'SomePath',
|
||||
Status => $StatusOK,
|
||||
Label => 'Some Label'
|
||||
Value => '0',
|
||||
MessageFormatted => 'Some \n Formatted \n\t Text.',
|
||||
},
|
||||
],
|
||||
)
|
||||
|
||||
=cut
|
||||
|
||||
sub Collect {
|
||||
my ( $Self, %Param ) = @_;
|
||||
|
||||
my $CacheKey = 'DataCollect';
|
||||
|
||||
if ( $Param{UseCache} ) {
|
||||
my $Cache = $Kernel::OM->Get('Kernel::System::Cache')->Get(
|
||||
Type => 'SupportDataCollector',
|
||||
Key => $CacheKey,
|
||||
);
|
||||
return %{$Cache} if ref $Cache eq 'HASH';
|
||||
}
|
||||
|
||||
# Data must be collected in a web request context to be able to collect web server data.
|
||||
# If called from CLI, make a web request to collect the data, but if the data couldn't
|
||||
# be collected the function runs normal.
|
||||
if ( !$ENV{GATEWAY_INTERFACE} ) {
|
||||
|
||||
my %ResultWebRequest = $Self->CollectByWebRequest(%Param);
|
||||
|
||||
return %ResultWebRequest if $ResultWebRequest{Success};
|
||||
}
|
||||
|
||||
# Get the disabled plugins from the config to generate a lookup hash, which can be used to skip these plugins.
|
||||
my $PluginDisabled = $Kernel::OM->Get('Kernel::Config')->Get('SupportDataCollector::DisablePlugins') || [];
|
||||
my %LookupPluginDisabled = map { $_ => 1 } @{$PluginDisabled};
|
||||
|
||||
# Get the identifier filter blacklist from the config to generate a lookup hash, which can be used to
|
||||
# filter these identifier.
|
||||
my $IdentifierFilterBlacklist
|
||||
= $Kernel::OM->Get('Kernel::Config')->Get('SupportDataCollector::IdentifierFilterBlacklist') || [];
|
||||
my %LookupIdentifierFilterBlacklist = map { $_ => 1 } @{$IdentifierFilterBlacklist};
|
||||
|
||||
# Look for all plug-ins in the FS.
|
||||
my @PluginFiles = $Kernel::OM->Get('Kernel::System::Main')->DirectoryRead(
|
||||
Directory => dirname(__FILE__) . "/SupportDataCollector/Plugin",
|
||||
Filter => "*.pm",
|
||||
Recursive => 1,
|
||||
);
|
||||
|
||||
# Look for all asynchronous plug-ins in the FS.
|
||||
my @PluginAsynchronousFiles = $Kernel::OM->Get('Kernel::System::Main')->DirectoryRead(
|
||||
Directory => dirname(__FILE__) . "/SupportDataCollector/PluginAsynchronous",
|
||||
Filter => "*.pm",
|
||||
Recursive => 1,
|
||||
);
|
||||
|
||||
# Merge the both plug-in types together.
|
||||
my @PluginFilesAll = ( @PluginFiles, @PluginAsynchronousFiles );
|
||||
|
||||
my @Result;
|
||||
|
||||
# Execute all plug-ins.
|
||||
PLUGINFILE:
|
||||
for my $PluginFile (@PluginFilesAll) {
|
||||
|
||||
# Convert file name => package name
|
||||
$PluginFile =~ s{^.*(Kernel/System.*)[.]pm$}{$1}xmsg;
|
||||
$PluginFile =~ s{/+}{::}xmsg;
|
||||
|
||||
next PLUGINFILE if $LookupPluginDisabled{$PluginFile};
|
||||
|
||||
if ( !$Kernel::OM->Get('Kernel::System::Main')->Require($PluginFile) ) {
|
||||
return (
|
||||
Success => 0,
|
||||
ErrorMessage => "Could not load $PluginFile!",
|
||||
);
|
||||
}
|
||||
my $PluginObject = $PluginFile->new( %{$Self} );
|
||||
|
||||
my %PluginResult = $PluginObject->Run();
|
||||
|
||||
if ( !%PluginResult || !$PluginResult{Success} ) {
|
||||
return (
|
||||
Success => 0,
|
||||
ErrorMessage => "Error during execution of $PluginFile: $PluginResult{ErrorMessage}",
|
||||
);
|
||||
}
|
||||
|
||||
push @Result, @{ $PluginResult{Result} // [] };
|
||||
}
|
||||
|
||||
# Remove the disabled plugins after the execution, because some plugins returns
|
||||
# more information with a own identifier.
|
||||
@Result = grep { !$LookupIdentifierFilterBlacklist{ $_->{Identifier} } } @Result;
|
||||
|
||||
# Sort the results from the plug-ins by the short identifier.
|
||||
@Result = sort { $a->{ShortIdentifier} cmp $b->{ShortIdentifier} } @Result;
|
||||
|
||||
my %ReturnData = (
|
||||
Success => 1,
|
||||
Result => \@Result,
|
||||
);
|
||||
|
||||
# Cache the result only, if the support data were collected in a web request,
|
||||
# to have all support data in the admin view.
|
||||
if ( $ENV{GATEWAY_INTERFACE} ) {
|
||||
|
||||
$Kernel::OM->Get('Kernel::System::Cache')->Set(
|
||||
Type => 'SupportDataCollector',
|
||||
Key => $CacheKey,
|
||||
Value => \%ReturnData,
|
||||
TTL => 60 * 10,
|
||||
);
|
||||
}
|
||||
|
||||
return %ReturnData;
|
||||
}
|
||||
|
||||
sub CollectByWebRequest {
|
||||
my ( $Self, %Param ) = @_;
|
||||
|
||||
# Create a challenge token to authenticate this request without customer/agent login.
|
||||
# PublicSupportDataCollector requires this ChallengeToken.
|
||||
my $ChallengeToken = $Kernel::OM->Get('Kernel::System::Main')->GenerateRandomString(
|
||||
Length => 32,
|
||||
Dictionary => [ 0 .. 9, 'a' .. 'f' ], # Generate a hexadecimal value.
|
||||
);
|
||||
|
||||
if (
|
||||
$Kernel::OM->Get('Kernel::System::SystemData')->SystemDataGet( Key => 'SupportDataCollector::ChallengeToken' )
|
||||
)
|
||||
{
|
||||
$Kernel::OM->Get('Kernel::System::SystemData')->SystemDataUpdate(
|
||||
Key => 'SupportDataCollector::ChallengeToken',
|
||||
Value => $ChallengeToken,
|
||||
UserID => 1,
|
||||
);
|
||||
}
|
||||
else {
|
||||
$Kernel::OM->Get('Kernel::System::SystemData')->SystemDataAdd(
|
||||
Key => 'SupportDataCollector::ChallengeToken',
|
||||
Value => $ChallengeToken,
|
||||
UserID => 1,
|
||||
);
|
||||
}
|
||||
|
||||
my $ConfigObject = $Kernel::OM->Get('Kernel::Config');
|
||||
|
||||
my $Host = $Param{Hostname};
|
||||
$Host ||= $ConfigObject->Get('SupportDataCollector::HTTPHostname');
|
||||
|
||||
if ( !$Host ) {
|
||||
my $FQDN = $ConfigObject->Get('FQDN');
|
||||
|
||||
if ( $FQDN ne 'yourhost.example.com' && gethostbyname($FQDN) ) {
|
||||
$Host = $FQDN;
|
||||
}
|
||||
|
||||
if ( !$Host && gethostbyname('localhost') ) {
|
||||
$Host = 'localhost';
|
||||
}
|
||||
|
||||
$Host ||= '127.0.0.1';
|
||||
}
|
||||
|
||||
# If the public interface is proteceted with .htaccess
|
||||
# we can specify the htaccess login data here,
|
||||
# this is neccessary for the support data collector.
|
||||
my $AuthString = '';
|
||||
my $AuthUser = $ConfigObject->Get('PublicFrontend::AuthUser');
|
||||
my $AuthPassword = $ConfigObject->Get('PublicFrontend::AuthPassword');
|
||||
if ( $AuthUser && $AuthPassword ) {
|
||||
$AuthString = $AuthUser . ':' . $AuthPassword . '@';
|
||||
}
|
||||
|
||||
# Prepare web service config for the internal web request.
|
||||
my $URL =
|
||||
$ConfigObject->Get('HttpType')
|
||||
. '://'
|
||||
. $AuthString
|
||||
. $Host
|
||||
. '/'
|
||||
. $ConfigObject->Get('ScriptAlias')
|
||||
. 'public.pl';
|
||||
|
||||
my $WebUserAgentObject = Kernel::System::WebUserAgent->new(
|
||||
Timeout => $Param{WebTimeout} || 20,
|
||||
);
|
||||
|
||||
# Disable webuseragent proxy since the call is sent to self server, see bug#11680.
|
||||
$WebUserAgentObject->{Proxy} = '';
|
||||
|
||||
my %Result = (
|
||||
Success => 0,
|
||||
);
|
||||
|
||||
# Skip the ssl verification, because this is only a internal web request.
|
||||
my %Response = $WebUserAgentObject->Request(
|
||||
Type => 'POST',
|
||||
URL => $URL,
|
||||
Data => {
|
||||
Action => 'PublicSupportDataCollector',
|
||||
ChallengeToken => $ChallengeToken,
|
||||
},
|
||||
SkipSSLVerification => 1,
|
||||
NoLog => $Param{Debug} ? 0 : 1,
|
||||
);
|
||||
|
||||
if ( $Response{Status} ne '200 OK' ) {
|
||||
|
||||
if ( $Param{Debug} ) {
|
||||
$Kernel::OM->Get('Kernel::System::Log')->Log(
|
||||
Priority => 'notice',
|
||||
Message => "SupportDataCollector - Can't connect to server - $Response{Status}",
|
||||
);
|
||||
}
|
||||
|
||||
return %Result;
|
||||
}
|
||||
|
||||
# check if we have content as a scalar ref
|
||||
if ( !$Response{Content} || ref $Response{Content} ne 'SCALAR' ) {
|
||||
|
||||
if ( $Param{Debug} ) {
|
||||
$Kernel::OM->Get('Kernel::System::Log')->Log(
|
||||
Priority => 'notice',
|
||||
Message => "SupportDataCollector - No content received.",
|
||||
);
|
||||
}
|
||||
return %Result;
|
||||
}
|
||||
|
||||
# convert internal used charset
|
||||
$Kernel::OM->Get('Kernel::System::Encode')->EncodeInput( $Response{Content} );
|
||||
|
||||
# Discard HTML responses (error pages etc.).
|
||||
if ( substr( ${ $Response{Content} }, 0, 1 ) eq '<' ) {
|
||||
|
||||
if ( $Param{Debug} ) {
|
||||
$Kernel::OM->Get('Kernel::System::Log')->Log(
|
||||
Priority => 'notice',
|
||||
Message => "SupportDataCollector - Response looks like HTML instead of JSON.",
|
||||
);
|
||||
}
|
||||
|
||||
return %Result;
|
||||
}
|
||||
|
||||
# decode JSON data
|
||||
my $ResponseData = $Kernel::OM->Get('Kernel::System::JSON')->Decode(
|
||||
Data => ${ $Response{Content} },
|
||||
);
|
||||
if ( !$ResponseData || ref $ResponseData ne 'HASH' ) {
|
||||
|
||||
if ( $Param{Debug} ) {
|
||||
$Kernel::OM->Get('Kernel::System::Log')->Log(
|
||||
Priority => 'error',
|
||||
Message => "SupportDataCollector - Can't decode JSON: '" . ${ $Response{Content} } . "'!",
|
||||
);
|
||||
}
|
||||
return %Result;
|
||||
}
|
||||
|
||||
return %{$ResponseData};
|
||||
}
|
||||
|
||||
=head2 CollectAsynchronous()
|
||||
|
||||
collect asynchronous data (the asynchronous plug-in decide at which place the data will be saved)
|
||||
|
||||
my %Result = $SupportDataCollectorObject->CollectAsynchronous();
|
||||
|
||||
returns:
|
||||
|
||||
%Result = (
|
||||
Success => 1, # or 0 in case of an error
|
||||
ErrorMessage => 'some message' # optional (only in case of an error)
|
||||
);
|
||||
|
||||
return
|
||||
|
||||
=cut
|
||||
|
||||
sub CollectAsynchronous {
|
||||
my ( $Self, %Param ) = @_;
|
||||
|
||||
# Look for all plug-ins in the FS
|
||||
my @PluginFiles = $Kernel::OM->Get('Kernel::System::Main')->DirectoryRead(
|
||||
Directory => dirname(__FILE__) . "/SupportDataCollector/PluginAsynchronous",
|
||||
Filter => "*.pm",
|
||||
Recursive => 1,
|
||||
);
|
||||
|
||||
# Execute all plug-ins
|
||||
for my $PluginFile (@PluginFiles) {
|
||||
|
||||
# Convert file name => package name
|
||||
$PluginFile =~ s{^.*(Kernel/System.*)[.]pm$}{$1}xmsg;
|
||||
$PluginFile =~ s{/+}{::}xmsg;
|
||||
|
||||
if ( !$Kernel::OM->Get('Kernel::System::Main')->Require($PluginFile) ) {
|
||||
return (
|
||||
Success => 0,
|
||||
ErrorMessage => "Could not load $PluginFile!",
|
||||
);
|
||||
}
|
||||
my $PluginObject = $PluginFile->new( %{$Self} );
|
||||
|
||||
my $Success = $PluginObject->RunAsynchronous();
|
||||
|
||||
if ( !$Success ) {
|
||||
return (
|
||||
Success => 0,
|
||||
ErrorMessage => "Error during asynchronous execution of $PluginFile.",
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
return (
|
||||
Success => 1,
|
||||
);
|
||||
}
|
||||
|
||||
=head2 CleanupAsynchronous()
|
||||
|
||||
clean-up asynchronous data (the asynchronous plug-in decide for themselves)
|
||||
|
||||
my $Success = $SupportDataCollectorObject->CleanupAsynchronous();
|
||||
|
||||
=cut
|
||||
|
||||
sub CleanupAsynchronous {
|
||||
my ( $Self, %Param ) = @_;
|
||||
|
||||
# Look for all plug-ins in the FS
|
||||
my @PluginFiles = $Kernel::OM->Get('Kernel::System::Main')->DirectoryRead(
|
||||
Directory => dirname(__FILE__) . "/SupportDataCollector/PluginAsynchronous",
|
||||
Filter => "*.pm",
|
||||
Recursive => 1,
|
||||
);
|
||||
|
||||
# Execute all Plug-ins
|
||||
PLUGINFILE:
|
||||
for my $PluginFile (@PluginFiles) {
|
||||
|
||||
# Convert file name => package name
|
||||
$PluginFile =~ s{^.*(Kernel/System.*)[.]pm$}{$1}xmsg;
|
||||
$PluginFile =~ s{/+}{::}xmsg;
|
||||
|
||||
if ( !$Kernel::OM->Get('Kernel::System::Main')->Require($PluginFile) ) {
|
||||
return (
|
||||
Success => 0,
|
||||
ErrorMessage => "Could not load $PluginFile!",
|
||||
);
|
||||
}
|
||||
my $PluginObject = $PluginFile->new( %{$Self} );
|
||||
|
||||
next PLUGINFILE if !$PluginFile->can('CleanupAsynchronous');
|
||||
|
||||
$PluginObject->CleanupAsynchronous();
|
||||
}
|
||||
|
||||
return 1;
|
||||
}
|
||||
|
||||
=head1 TERMS AND CONDITIONS
|
||||
|
||||
This software is part of the OTRS project (L<https://otrs.org/>).
|
||||
|
||||
This software comes with ABSOLUTELY NO WARRANTY. For details, see
|
||||
the enclosed file COPYING for license information (GPL). If you
|
||||
did not receive this file, see L<https://www.gnu.org/licenses/gpl-3.0.txt>.
|
||||
|
||||
=cut
|
||||
|
||||
1;
|
||||
Reference in New Issue
Block a user