# -- # 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::Console::Command::Admin::Package::UpgradeAll; use strict; use warnings; use utf8; use Kernel::System::VariableCheck qw(:all); use parent qw(Kernel::System::Console::BaseCommand); our @ObjectDependencies = ( 'Kernel::Config', 'Kernel::System::Cache', 'Kernel::System::Package', 'Kernel::System::SystemData', ); sub Configure { my ( $Self, %Param ) = @_; $Self->Description('Upgrade all OTRS packages to the latest versions from the on-line repositories.'); $Self->AddOption( Name => 'force', Description => 'Force package upgrade/installation even if validation fails.', Required => 0, HasValue => 0, ); return; } sub Run { my ( $Self, %Param ) = @_; my $CacheObject = $Kernel::OM->Get('Kernel::System::Cache'); # Enable in-memory cache to improve SysConfig performance, which is normally disabled for commands. $CacheObject->Configure( CacheInMemory => 1, ); my $PackageObject = $Kernel::OM->Get('Kernel::System::Package'); my %IsRunningResult = $PackageObject->PackageUpgradeAllIsRunning(); if ( $IsRunningResult{IsRunning} ) { $Self->Print("\nThere is another package upgrade process running\n"); $Self->Print("\nDone.\n"); return $Self->ExitCodeOk(); } my @List = $PackageObject->RepositoryList( Result => 'short', ); if ( !@List ) { $Self->Print("\nThere are no installed packages\n"); $Self->Print("\nDone.\n"); return $Self->ExitCodeOk(); } my %RepositoryList = $PackageObject->_ConfiguredRepositoryDefinitionGet(); # Show cloud repositories if system is registered. my $RepositoryCloudList; my $RegistrationState = $Kernel::OM->Get('Kernel::System::SystemData')->SystemDataGet( Key => 'Registration::State', ) || ''; if ( $RegistrationState eq 'registered' && !$Kernel::OM->Get('Kernel::Config')->Get('CloudServices::Disabled') ) { $Self->Print("Getting cloud repositories information...\n"); $RepositoryCloudList = $PackageObject->RepositoryCloudList( NoCache => 1 ); $Self->Print(" Cloud repositories... Done\n\n"); } my %RepositoryListAll = ( %RepositoryList, %{ $RepositoryCloudList || {} } ); my @PackageOnlineList; my %PackageSoruceLookup; $Self->Print("Fetching on-line repositories...\n"); URL: for my $URL ( sort keys %RepositoryListAll ) { $Self->Print(" $RepositoryListAll{$URL}... "); my $FromCloud = 0; if ( $RepositoryCloudList->{$URL} ) { $FromCloud = 1; } my @OnlineList = $PackageObject->PackageOnlineList( URL => $URL, Lang => 'en', Cache => 1, FromCloud => $FromCloud, ); $Self->Print("Done\n"); } # Check again after repository refresh %IsRunningResult = $PackageObject->PackageUpgradeAllIsRunning(); if ( $IsRunningResult{IsRunning} ) { $Self->Print("\nThere is another package upgrade process running\n"); $Self->Print("\nDone.\n"); return $Self->ExitCodeOk(); } $Self->Print("\nUpgrading installed packages...\n"); my $ErrorMessage; my %Result; eval { # Localize the standard error, everything will be restored after the eval block. # Package installation or upgrades always produce messages in STDERR for files and directories. local *STDERR; # Redirect the standard error to a variable. open STDERR, ">>", \$ErrorMessage; %Result = $PackageObject->PackageUpgradeAll( Force => $Self->GetOption('force'), ); }; # Remove package upgrade data from the DB, so the GUI will not show the finished notification. $PackageObject->PackageUpgradeAllDataDelete(); # Be sure to print any error messages in case of a failure. if ( IsHashRefWithData( $Result{Failed} ) ) { print STDERR $ErrorMessage if $ErrorMessage; } if ( !IsHashRefWithData( $Result{Updated} ) && !IsHashRefWithData( $Result{Installed} ) && !IsHashRefWithData( $Result{Undeployed} ) && !IsHashRefWithData( $Result{Failed} ) ) { $Self->Print(" All installed packages are already at their latest versions.\n"); $Self->Print("\nDone.\n"); return $Self->ExitCodeOk(); } my %SuccessMessages = ( Updated => 'updated', Installed => 'installed', AlreadyUpdated => 'already up-to-date', Undeployed => 'already up-to-date but not deployed correctly', ); for my $ResultPart (qw(AlreadyUpdated Undeployed Updated Installed)) { if ( IsHashRefWithData( $Result{$ResultPart} ) ) { $Self->Print( ' The following packages were ' . $SuccessMessages{$ResultPart} . "...\n" ); my $Color = 'green'; if ( $ResultPart eq 'Installed' || $ResultPart eq 'Undeployed' ) { $Color = 'yellow'; } for my $PackageName ( sort keys %{ $Result{$ResultPart} } ) { $Self->Print(" <$Color>$PackageName\n"); } } } my %FailedMessages = ( UpdateError => 'could not be upgraded...', InstallError => 'could not be installed...', Cyclic => 'had cyclic dependencies...', NotFound => 'could not be found in the on-line repositories...', WrongVersion => 'require a version higher than the one found in the on-line repositories...', DependencyFail => 'fail to upgrade/install their package dependencies...' ); if ( IsHashRefWithData( $Result{Failed} ) ) { for my $FailedPart (qw(UpdateError InstallError DependencyFail Cyclic NotFound WrongVersion)) { if ( IsHashRefWithData( $Result{Failed}->{$FailedPart} ) ) { $Self->Print(" The following packages $FailedMessages{$FailedPart}\n"); for my $PackageName ( sort keys %{ $Result{Failed}->{$FailedPart} } ) { $Self->Print(" $PackageName\n"); } } } } if ( !$Result{Success} ) { $Self->Print("\nFail.\n"); return $Self->ExitCodeError(); } if ( IsHashRefWithData( $Result{Undeployed} ) ) { my $Message = "\nPlease reinstall not correctly deployed packages using" . " Admin::Package::Reinstall" . " or Admin::Package::ReinstallAll console commands.\n"; $Self->Print($Message); } # Disable in memory cache. $CacheObject->Configure( CacheInMemory => 0, ); $Self->Print("\nDone.\n"); return $Self->ExitCodeOk(); } 1;