diff --git a/config/packages/Centreon.yaml b/config/packages/Centreon.yaml index 55d9eede4dd..151e467dfd8 100644 --- a/config/packages/Centreon.yaml +++ b/config/packages/Centreon.yaml @@ -234,6 +234,7 @@ services: Core\Platform\Application\Repository\WriteUpdateRepositoryInterface: class: Core\Platform\Infrastructure\Repository\DbWriteUpdateRepository + arguments: ['%centreon_var_lib%', '%centreon_install_path%'] public: true # Monitoring resources diff --git a/lang/fr_FR.UTF-8/LC_MESSAGES/messages.po b/lang/fr_FR.UTF-8/LC_MESSAGES/messages.po index e19e9a2dd5b..33965c90d90 100644 --- a/lang/fr_FR.UTF-8/LC_MESSAGES/messages.po +++ b/lang/fr_FR.UTF-8/LC_MESSAGES/messages.po @@ -16935,5 +16935,8 @@ msgstr "Une erreur s'est produite lors de l'application de la mise à jour %s (% msgid "Error while locking update process" msgstr "Erreur lors du verrouillage du processus de mise à jour" -msgid "'Error while unlocking update process" +msgid "Error while unlocking update process" msgstr "Erreur lors du déverrouillage du processus de mise à jour" + +msgid "An error occurred when applying post update actions" +msgstr "Une erreur s'est produite lors de l'application des actions postérieures à la mise à jour" diff --git a/src/Core/Platform/Application/Repository/WriteUpdateRepositoryInterface.php b/src/Core/Platform/Application/Repository/WriteUpdateRepositoryInterface.php index 458557f07f0..982b32fc101 100644 --- a/src/Core/Platform/Application/Repository/WriteUpdateRepositoryInterface.php +++ b/src/Core/Platform/Application/Repository/WriteUpdateRepositoryInterface.php @@ -30,4 +30,11 @@ interface WriteUpdateRepositoryInterface * @param string $version */ public function runUpdate(string $version): void; + + /** + * Run post update actions + * + * @param string $currentVersion + */ + public function runPostUpdate(string $currentVersion): void; } diff --git a/src/Core/Platform/Application/UseCase/UpdateVersions/UpdateVersions.php b/src/Core/Platform/Application/UseCase/UpdateVersions/UpdateVersions.php index b8c1daf8861..181fa50f51e 100644 --- a/src/Core/Platform/Application/UseCase/UpdateVersions/UpdateVersions.php +++ b/src/Core/Platform/Application/UseCase/UpdateVersions/UpdateVersions.php @@ -66,6 +66,8 @@ public function __invoke( $this->runUpdates($availableUpdates); $this->unlockUpdate(); + + $this->runPostUpdate($this->getCurrentVersionOrFail()); } catch (\Throwable $e) { $this->error( $e->getMessage(), @@ -166,4 +168,22 @@ private function runUpdates(array $versions): void } } } + + /** + * Run post update actions + * + * @param string $currentVersion + * + * @throws UpdateVersionsException + */ + private function runPostUpdate(string $currentVersion): void + { + $this->info("Running post update actions"); + + try { + $this->writeUpdateRepository->runPostUpdate($currentVersion); + } catch (\Throwable $e) { + throw UpdateVersionsException::errorWhenApplyingPostUpdate($e); + } + } } diff --git a/src/Core/Platform/Application/UseCase/UpdateVersions/UpdateVersionsException.php b/src/Core/Platform/Application/UseCase/UpdateVersions/UpdateVersionsException.php index 98edafd9779..58045eed72c 100644 --- a/src/Core/Platform/Application/UseCase/UpdateVersions/UpdateVersionsException.php +++ b/src/Core/Platform/Application/UseCase/UpdateVersions/UpdateVersionsException.php @@ -75,4 +75,13 @@ public static function errorWhenApplyingUpdate( $e ); } + + /** + * @param \Throwable $e + * @return self + */ + public static function errorWhenApplyingPostUpdate(\Throwable $e): self + { + return new self(_('An error occurred when applying post update actions'), 0, $e); + } } diff --git a/src/Core/Platform/Infrastructure/Repository/DbWriteUpdateRepository.php b/src/Core/Platform/Infrastructure/Repository/DbWriteUpdateRepository.php index 3fe397f02f5..1255ee9ecc8 100644 --- a/src/Core/Platform/Infrastructure/Repository/DbWriteUpdateRepository.php +++ b/src/Core/Platform/Infrastructure/Repository/DbWriteUpdateRepository.php @@ -28,21 +28,26 @@ use Centreon\Infrastructure\DatabaseConnection; use Centreon\Infrastructure\Repository\AbstractRepositoryDRB; use Core\Platform\Application\Repository\WriteUpdateRepositoryInterface; +use Symfony\Component\Filesystem\Filesystem; use Centreon\Domain\Repository\RepositoryException; class DbWriteUpdateRepository extends AbstractRepositoryDRB implements WriteUpdateRepositoryInterface { use LoggerTrait; - private const INSTALL_DIR = __DIR__ . '/../../../../../www/install'; - /** + * @param string $libDir + * @param string $installDir * @param Container $dependencyInjector * @param DatabaseConnection $db + * @param Filesystem $filesystem */ public function __construct( + private string $libDir, + private string $installDir, private Container $dependencyInjector, DatabaseConnection $db, + private Filesystem $filesystem, ) { $this->db = $db; } @@ -59,6 +64,57 @@ public function runUpdate(string $version): void $this->updateVersionInformation($version); } + /** + * @inheritDoc + */ + public function runPostUpdate(string $currentVersion): void + { + if (! $this->filesystem->exists($this->installDir)) { + return; + } + + $this->backupInstallDirectory($currentVersion); + $this->removeInstallDirectory(); + } + + /** + * Backup installation directory + * + * @param string $currentVersion + */ + private function backupInstallDirectory(string $currentVersion): void + { + $backupDirectory = $this->libDir . '/installs/install-' . $currentVersion . '-' . date('Ymd_His'); + + $this->info( + "Backing up installation directory", + [ + 'source' => $this->installDir, + 'destination' => $backupDirectory, + ], + ); + + $this->filesystem->mirror( + $this->installDir, + $backupDirectory, + ); + } + + /** + * Remove installation directory + */ + private function removeInstallDirectory(): void + { + $this->info( + "Removing installation directory", + [ + 'installation_directory' => $this->installDir, + ], + ); + + $this->filesystem->remove($this->installDir); + } + /** * Run sql queries on monitoring database * @@ -66,7 +122,7 @@ public function runUpdate(string $version): void */ private function runMonitoringSql(string $version): void { - $upgradeFilePath = self::INSTALL_DIR . '/sql/centstorage/Update-CSTG-' . $version . '.sql'; + $upgradeFilePath = $this->installDir . '/sql/centstorage/Update-CSTG-' . $version . '.sql'; if (is_readable($upgradeFilePath)) { $this->db->switchToDb($this->db->getStorageDbName()); $this->runSqlFile($upgradeFilePath); @@ -83,7 +139,7 @@ private function runScript(string $version): void $pearDB = $this->dependencyInjector['configuration_db']; $pearDBO = $this->dependencyInjector['realtime_db']; - $upgradeFilePath = self::INSTALL_DIR . '/php/Update-' . $version . '.php'; + $upgradeFilePath = $this->installDir . '/php/Update-' . $version . '.php'; if (is_readable($upgradeFilePath)) { include_once $upgradeFilePath; } @@ -96,7 +152,7 @@ private function runScript(string $version): void */ private function runConfigurationSql(string $version): void { - $upgradeFilePath = self::INSTALL_DIR . '/sql/centreon/Update-DB-' . $version . '.sql'; + $upgradeFilePath = $this->installDir . '/sql/centreon/Update-DB-' . $version . '.sql'; if (is_readable($upgradeFilePath)) { $this->db->switchToDb($this->db->getCentreonDbName()); $this->runSqlFile($upgradeFilePath); @@ -113,7 +169,7 @@ private function runPostScript(string $version): void $pearDB = $this->dependencyInjector['configuration_db']; $pearDBO = $this->dependencyInjector['realtime_db']; - $upgradeFilePath = self::INSTALL_DIR . '/php/Update-' . $version . '.post.php'; + $upgradeFilePath = $this->installDir . '/php/Update-' . $version . '.post.php'; if (is_readable($upgradeFilePath)) { include_once $upgradeFilePath; } @@ -146,7 +202,7 @@ private function runSqlFile(string $filePath): void set_time_limit(0); $fileName = basename($filePath); - $tmpFile = self::INSTALL_DIR . '/tmp/' . $fileName; + $tmpFile = $this->installDir . '/tmp/' . $fileName; $alreadyExecutedQueriesCount = $this->getAlreadyExecutedQueriesCount($tmpFile); diff --git a/src/Core/Platform/Infrastructure/Repository/FsReadUpdateRepository.php b/src/Core/Platform/Infrastructure/Repository/FsReadUpdateRepository.php index dc15f27f654..d6c44956814 100644 --- a/src/Core/Platform/Infrastructure/Repository/FsReadUpdateRepository.php +++ b/src/Core/Platform/Infrastructure/Repository/FsReadUpdateRepository.php @@ -25,16 +25,21 @@ use Centreon\Domain\Log\LoggerTrait; use Core\Platform\Application\Repository\ReadUpdateRepositoryInterface; +use Symfony\Component\Filesystem\Filesystem; use Symfony\Component\Finder\Finder; class FsReadUpdateRepository implements ReadUpdateRepositoryInterface { use LoggerTrait; + private const INSTALL_DIR = __DIR__ . '/../../../../../www/install'; + /** + * @param Filesystem $filesystem * @param Finder $finder */ public function __construct( + private Filesystem $filesystem, private Finder $finder, ) { } @@ -57,10 +62,15 @@ public function findOrderedAvailableUpdates(string $currentVersion): array */ private function findAvailableUpdates(string $currentVersion): array { + if (! $this->filesystem->exists(self::INSTALL_DIR)) { + return []; + } + $fileNameVersionRegex = '/Update-(?[a-zA-Z0-9\-\.]+)\.php/'; $availableUpdates = []; + $updateFiles = $this->finder->files() - ->in(__DIR__ . '/../../../../../www/install/php') + ->in(self::INSTALL_DIR) ->name($fileNameVersionRegex); foreach ($updateFiles as $updateFile) { diff --git a/tests/php/Core/Platform/Application/UseCase/UpdateVersions/UpdateVersionsTest.php b/tests/php/Core/Platform/Application/UseCase/UpdateVersions/UpdateVersionsTest.php index 2efa5aa9ae0..4b402bff1b4 100644 --- a/tests/php/Core/Platform/Application/UseCase/UpdateVersions/UpdateVersionsTest.php +++ b/tests/php/Core/Platform/Application/UseCase/UpdateVersions/UpdateVersionsTest.php @@ -101,9 +101,9 @@ ->willReturn(true); $this->readVersionRepository - ->expects($this->once()) + ->expects($this->exactly(2)) ->method('findCurrentVersion') - ->willReturn('22.04.0'); + ->will($this->onConsecutiveCalls('22.04.0', '22.10.1')); $this->readUpdateRepository ->expects($this->once()) diff --git a/tests/php/Core/Platform/Infrastructure/Repository/LegacyReadVersionRepositoryTest.php b/tests/php/Core/Platform/Infrastructure/Repository/FsReadUpdateRepositoryTest.php similarity index 73% rename from tests/php/Core/Platform/Infrastructure/Repository/LegacyReadVersionRepositoryTest.php rename to tests/php/Core/Platform/Infrastructure/Repository/FsReadUpdateRepositoryTest.php index 2064430fe22..34c261621c2 100644 --- a/tests/php/Core/Platform/Infrastructure/Repository/LegacyReadVersionRepositoryTest.php +++ b/tests/php/Core/Platform/Infrastructure/Repository/FsReadUpdateRepositoryTest.php @@ -24,14 +24,33 @@ namespace Tests\Core\Platform\Infrastructure\Repository; use Core\Platform\Infrastructure\Repository\FsReadUpdateRepository; +use Symfony\Component\Filesystem\Filesystem; use Symfony\Component\Finder\Finder; beforeEach(function () { + $this->filesystem = $this->createMock(Filesystem::class); $this->finder = $this->createMock(Finder::class); }); +it('should not find updates if install directory does not exist', function () { + $repository = new FsReadUpdateRepository($this->filesystem, $this->finder); + + $this->filesystem + ->expects($this->once()) + ->method('exists') + ->willReturn(false); + + $availableUpdates = $repository->findOrderedAvailableUpdates('22.04.0'); + expect($availableUpdates)->toEqual([]); +}); + it('should order found updates', function () { - $repository = new FsReadUpdateRepository($this->finder); + $repository = new FsReadUpdateRepository($this->filesystem, $this->finder); + + $this->filesystem + ->expects($this->once()) + ->method('exists') + ->willReturn(true); $this->finder ->expects($this->once()) diff --git a/www/install/step_upgrade/process/process_step5.php b/www/install/step_upgrade/process/process_step5.php index df5d79e2174..c4a723a14f2 100644 --- a/www/install/step_upgrade/process/process_step5.php +++ b/www/install/step_upgrade/process/process_step5.php @@ -37,44 +37,15 @@ require_once __DIR__ . '/../../../../bootstrap.php'; require_once '../../steps/functions.php'; -function recurseRmdir($dir) -{ - $files = array_diff(scandir($dir), array('.', '..')); - foreach ($files as $file) { - (is_dir("$dir/$file")) ? recurseRmdir("$dir/$file") : unlink("$dir/$file"); - } - return rmdir($dir); -} - -function recurseCopy($source, $dest) -{ - if (is_link($source)) { - return symlink(readlink($source), $dest); - } +use Core\Platform\Application\Repository\WriteUpdateRepositoryInterface; +use Core\Platform\Application\UseCase\UpdateVersions\UpdateVersionsException; - if (is_file($source)) { - return copy($source, $dest); - } - - if (!is_dir($dest)) { - mkdir($dest); - } +$kernel = \App\Kernel::createForWeb(); - $dir = dir($source); - while (false !== $entry = $dir->read()) { - if ($entry == '.' || $entry == '..') { - continue; - } - - recurseCopy("$source/$entry", "$dest/$entry"); - } - - $dir->close(); - return true; -} +$updateWriteRepository = $kernel->getContainer()->get(WriteUpdateRepositoryInterface::class); $parameters = filter_input_array(INPUT_POST); -$current = filter_var($_POST['current'] ?? "step 5", FILTER_SANITIZE_STRING); +$current = filter_var($_POST['current'] ?? "step 5", FILTER_SANITIZE_FULL_SPECIAL_CHARS); if ($parameters) { if ((int)$parameters["send_statistics"] === 1) { @@ -88,16 +59,19 @@ function recurseCopy($source, $dest) $db->query($query); } -$name = 'install-' . $_SESSION['CURRENT_VERSION'] . '-' . date('Ymd_His'); -$completeName = _CENTREON_VARLIB_ . '/installs/' . $name; -$sourceInstallDir = str_replace('step_upgrade', '', realpath(dirname(__FILE__) . '/../')); - try { - if (recurseCopy($sourceInstallDir, $completeName)) { - recurseRmdir($sourceInstallDir); + if (!isset($_SESSION['CURRENT_VERSION']) || ! preg_match('/^\d+\.\d+\.\d+/', $_SESSION['CURRENT_VERSION'])) { + throw new \Exception('Cannot get current version'); } -} catch (Exception $e) { - exitUpgradeProcess(1, $current, '', $e->getMessage()); + + $updateWriteRepository->runPostUpdate($_SESSION['CURRENT_VERSION']); +} catch (\Throwable $e) { + exitUpgradeProcess( + 1, + $current, + '', + UpdateVersionsException::errorWhenApplyingPostUpdate($e)->getMessage() + ); } session_destroy();