# -- # 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::ITSM::Configitem::Delete; use strict; use warnings; ## nofilter(TidyAll::Plugin::OTRS::Migrations::OTRS6::SysConfig) use Kernel::System::VariableCheck qw(:all); use parent qw(Kernel::System::Console::BaseCommand); our @ObjectDependencies = ( 'Kernel::System::GeneralCatalog', 'Kernel::System::ITSMConfigItem', 'Kernel::System::DateTime', ); sub Configure { my ( $Self, %Param ) = @_; $Self->Description('Delete config items (all, by class (and deployment state) or by number).'); $Self->AddOption( Name => 'all', Description => "Delete all config items.", Required => 0, HasValue => 0, ); $Self->AddArgument( Name => 'accept', Description => "Accept delete all or cancel.", Required => 0, ValueRegex => qr/(y|n)/smx, ); $Self->AddOption( Name => 'class', Description => "Delete all config items of this class.", Required => 0, HasValue => 1, ValueRegex => qr/.*/smx, ); $Self->AddOption( Name => 'deployment-state', Description => "Delete all config items with this deployment state (ONLY TOGETHER with the --class parameter).", Required => 0, HasValue => 1, ValueRegex => qr/.*/smx, ); $Self->AddOption( Name => 'configitem-number', Description => "Delete listed config items.", Required => 0, HasValue => 1, ValueRegex => qr/\d+/smx, Multiple => 1, ); $Self->AddOption( Name => 'all-old-versions', Description => "Delete all config item versions except the newest version.", Required => 0, HasValue => 0, ); $Self->AddOption( Name => 'all-but-keep-last-versions', Description => "Delete all config item versions but keep the last XX versions.", Required => 0, HasValue => 1, ValueRegex => qr/\d+/smx, ); $Self->AddOption( Name => 'all-older-than-days-versions', Description => "Delete all config item versions older than XX days.", Required => 0, HasValue => 1, ValueRegex => qr/\d+/smx, ); return; } sub PreRun { my ( $Self, %Param ) = @_; my $All = $Self->GetOption('all'); my $Class = $Self->GetOption('class') // ''; my @ConfigItemNumbers = @{ $Self->GetOption('configitem-number') // [] }; my $DeploymentState = $Self->GetOption('deployment-state') // ''; my $AllOldVersions = $Self->GetOption('all-old-versions') // ''; my $AllButKeepLast = $Self->GetOption('all-but-keep-last-versions') // ''; my $AllOlderThanDays = $Self->GetOption('all-older-than-days-versions') // ''; if ( !$All && !$Class && !@ConfigItemNumbers && !$DeploymentState && !$AllOldVersions && !$AllButKeepLast && !$AllOlderThanDays ) { die "Please provide option --all, --class, --configitem-number, --all-old-versions, --all-but-keep-last-versions or --all-older-than-days-versions." . " For more details use --help\n"; } my $AllOptionTypeCount; for my $Value ( $All, $AllOldVersions, $AllButKeepLast, $AllOlderThanDays ) { if ($Value) { $AllOptionTypeCount++; } } if ( $AllOptionTypeCount > 1 ) { die "The options --all, --all-old-versions, --all-but-keep-last-versions and --all-older-than-days-versions can not be mixed. \nFor more details use --help\n"; } if ( $AllOptionTypeCount && ( $Class || @ConfigItemNumbers || $DeploymentState ) ) { die "The options --all, --all-old-versions, --all-but-keep-last-versions and --all-older-than-days-versions can not used together with any other option. \nFor more details use --help\n"; } if ( $DeploymentState && !$Class ) { die "Deleting all config items with this deployment state is posible ONLY TOGETHER with the --class parameter. \nFor more details use --help\n"; } if ( @ConfigItemNumbers && ( $Class || $DeploymentState ) ) { die "The option --configitem-number can not be used together with the --class or the --deployment-state parameter. \nFor more details use --help\n"; } return; } sub Run { my ( $Self, %Param ) = @_; $Self->Print("Deleting config items...\n\n"); my $All = $Self->GetOption('all'); my $Class = $Self->GetOption('class') // ''; my @ConfigItemNumbers = @{ $Self->GetOption('configitem-number') // [] }; my $DeploymentState = $Self->GetOption('deployment-state') // ''; my $AllOldVersions = $Self->GetOption('all-old-versions') // ''; my $AllButKeepLast = $Self->GetOption('all-but-keep-last-versions') // ''; my $AllOlderThanDays = $Self->GetOption('all-older-than-days-versions') // ''; # delete all config items if ($All) { # get all config items ids my @ConfigItemIDs = @{ $Kernel::OM->Get('Kernel::System::ITSMConfigItem')->ConfigItemSearch() }; # get number of config items my $CICount = scalar @ConfigItemIDs; # if there are any CI to delete if ($CICount) { $Self->Print("Are you sure that you want to delete ALL $CICount config items?\n"); $Self->Print("This is irrevocable. [y/n] \n"); my $Confirmation = $Self->GetArgument('accept'); chomp( $Confirmation = lc ) if !defined $Confirmation; # if the user confirms the deletion if ( $Confirmation eq 'y' ) { # delete config items $Self->Print("Deleting all config items...\n"); $Self->DeleteConfigItems( ConfigItemIDs => \@ConfigItemIDs ); } else { $Self->Print("Command delete was canceled\n"); return $Self->ExitCodeOk(); } } else { $Self->Print("There are NO config items to delete.\n"); } } # delete listed config items elsif ( IsArrayRefWithData( \@ConfigItemNumbers ) ) { my @ConfigItemIDs; for my $ConfigItemNumber (@ConfigItemNumbers) { # checks the validity of the config item id my $ID = $Kernel::OM->Get('Kernel::System::ITSMConfigItem')->ConfigItemLookup( ConfigItemNumber => $ConfigItemNumber, ); if ($ID) { push @ConfigItemIDs, $ID; } else { $Self->Print("Unable to find config item $ConfigItemNumber.\n"); } } # delete config items (if any valid number was given) if (@ConfigItemIDs) { $Self->Print("Deleting specified config items...\n"); $Self->DeleteConfigItems( ConfigItemIDs => \@ConfigItemIDs ); } } # delete config items that belong to the class elsif ($Class) { my @ConfigItemIDs; # get class list my $ClassList = $Kernel::OM->Get('Kernel::System::GeneralCatalog')->ItemList( Class => 'ITSM::ConfigItem::Class', Valid => 0, ); # invert the hash to have the classes names as keys my %ClassName2ID = reverse %{$ClassList}; if ( $ClassName2ID{$Class} ) { my $ID = $ClassName2ID{$Class}; # define the search param for the class search my %SearchParam = ( ClassIDs => [$ID], ); # also a deployment state is given if ($DeploymentState) { # get deployment state list my $DeploymentStateList = $Kernel::OM->Get('Kernel::System::GeneralCatalog')->ItemList( Class => 'ITSM::ConfigItem::DeploymentState', ); # invert the hash to have the deployment state names as keys my %DeploymentState2ID = reverse %{$DeploymentStateList}; # if the deployment state is valid if ( $DeploymentState2ID{$DeploymentState} ) { # get the deployment state id my $ID = $DeploymentState2ID{$DeploymentState}; # add search parameter $SearchParam{DeplStateIDs} = [$ID]; } else { $Self->PrintError("Unable to find deployment state $DeploymentState."); return $Self->ExitCodeError(); } } # get ids of this class (and maybe deployment state) config items @ConfigItemIDs = @{ $Kernel::OM->Get('Kernel::System::ITSMConfigItem')->ConfigItemSearch(%SearchParam) }; } else { $Self->PrintError("Unable to find class name $Class."); return $Self->ExitCodeError(); } # delete config items (if any valid number was given) if (@ConfigItemIDs) { $Self->Print("Deleting config items that belong to the class $Class...\n"); $Self->DeleteConfigItems( ConfigItemIDs => \@ConfigItemIDs ); } else { $Self->Print("There are no config items that belong to the class $Class...\n"); } } # delete versions older than xx days from all config items elsif ($AllOlderThanDays) { my $OlderDateDTObject = $Kernel::OM->Create('Kernel::System::DateTime'); $OlderDateDTObject->Subtract( Days => $AllOlderThanDays, ); my $VersionsOlderDate = $Kernel::OM->Get('Kernel::System::ITSMConfigItem')->VersionListAll( OlderDate => $OlderDateDTObject->ToString(), ); # We need to get all versions to make sure that at least one version remains # -> if one version of a configitem is younger than the amount of days, # we can delete all Versions received by the "OlderDate" query # -> if no version is younger than the amount of days # we have to keep one version of the "OlderDate" query result my $VersionsAll = $Kernel::OM->Get('Kernel::System::ITSMConfigItem')->VersionListAll(); my @VersionsToDelete; CONFIGITEMID: for my $ConfigItemID ( sort keys %{$VersionsOlderDate} ) { # number of found older versions of this CI my $NumberOfOlderVersions = scalar keys %{ $VersionsOlderDate->{$ConfigItemID} }; # number of all versions of this CI my $NumberOfAllVersions = scalar keys %{ $VersionsAll->{$ConfigItemID} }; # next if there are no older versions next CONFIGITEMID if !$NumberOfOlderVersions; # next if there is only one or zero of all versions next CONFIGITEMID if $NumberOfAllVersions <= 1; # if the amount of Versions we have to delete # is exactly the same as the amount of AllVersions # we have to keep the last one # in order to keep the system working # # -> so let's start counting at "1" instead of "0" # in order to stop deleting before we reach the newest version my $Count = 0; if ( $NumberOfOlderVersions == $NumberOfAllVersions ) { $Count = 1; } # make sure that the versions are numerically sorted for my $Version ( sort { $a <=> $b } keys %{ $VersionsOlderDate->{$ConfigItemID} } ) { if ( $Count < $NumberOfOlderVersions ) { push @VersionsToDelete, $Version; } $Count++; } } $Self->DeleteConfigItemVersions( VersionIDs => \@VersionsToDelete, UserID => 1, ); } # delete all config item versions except the newest version elsif ($AllOldVersions) { my $VersionsAll = $Kernel::OM->Get('Kernel::System::ITSMConfigItem')->VersionListAll(); my @VersionsToDelete; if ( IsHashRefWithData($VersionsAll) ) { CONFIGITEMID: for my $ConfigItemID ( sort keys %{$VersionsAll} ) { next CONFIGITEMID if !IsHashRefWithData( $VersionsAll->{$ConfigItemID} ); # make sure that the versions are numerically sorted my @ReducedVersions = sort { $a <=> $b } keys %{ $VersionsAll->{$ConfigItemID} }; # remove the last (newest) version pop @ReducedVersions; push @VersionsToDelete, @ReducedVersions; } } $Self->DeleteConfigItemVersions( VersionIDs => \@VersionsToDelete, UserID => 1, ); } # delete all config item versions but keep the last XX versions elsif ($AllButKeepLast) { my $VersionsAll = $Kernel::OM->Get('Kernel::System::ITSMConfigItem')->VersionListAll(); my @VersionsToDelete; if ( IsHashRefWithData($VersionsAll) ) { CONFIGITEMID: for my $ConfigItemID ( sort keys %{$VersionsAll} ) { next CONFIGITEMID if !IsHashRefWithData( $VersionsAll->{$ConfigItemID} ); # make sure that the versions are numerically reverse sorted my @ReducedVersions = reverse sort { $a <=> $b } keys %{ $VersionsAll->{$ConfigItemID} }; my $Count = 0; @ReducedVersions = grep { $Count++; $Count > $AllButKeepLast } @ReducedVersions; push @VersionsToDelete, @ReducedVersions; } } $Self->DeleteConfigItemVersions( VersionIDs => \@VersionsToDelete, UserID => 1, ); } else { $Self->PrintError("No config item for delete."); } # show successfull output $Self->Print("Done.\n"); return $Self->ExitCodeOk(); } sub DeleteConfigItems { my ( $Self, %Param ) = @_; my $DeletedCI; # delete specified config items for my $ConfigItemID ( @{ $Param{ConfigItemIDs} } ) { my $True = $Kernel::OM->Get('Kernel::System::ITSMConfigItem')->ConfigItemDelete( ConfigItemID => $ConfigItemID, UserID => 1, ); if ( !$True ) { $Self->PrintError("Unable to delete config item with id $ConfigItemID."); } else { $DeletedCI++; } } $Self->Print("Deleted $DeletedCI config item(s).\n\n"); return 1; } sub DeleteConfigItemVersions { my ( $Self, %Param ) = @_; # check needed stuff return if !IsArrayRefWithData( $Param{VersionIDs} ); $Self->Print("Deleting config item versions.\n\n"); $Kernel::OM->Get('Kernel::System::ITSMConfigItem')->VersionDelete( VersionIDs => $Param{VersionIDs}, UserID => 1, ); return 1; } 1; =head1 TERMS AND CONDITIONS This software is part of the OTRS project (L). 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. =cut