diff --git a/core/js/setupchecks.js b/core/js/setupchecks.js index 67f75c8206f4c..03f109c872590 100644 --- a/core/js/setupchecks.js +++ b/core/js/setupchecks.js @@ -462,6 +462,15 @@ type: OC.SetupChecks.MESSAGE_TYPE_WARNING }) } + if (!data.isEnoughTempSpaceAvailableIfS3PrimaryStorageIsUsed) { + messages.push({ + msg: t( + 'core', + 'This instance uses an S3 based object store as primary storage. The uploaded files are stored temporarily on the server and thus it is recommended to have 50 GB of free space available in the temp directory of PHP. Check the logs for full details about the path and the available space. To improve this please change the temporary directory in the php.ini or make more space available in that path.' + ), + type: OC.SetupChecks.MESSAGE_TYPE_WARNING + }) + } } else { messages.push({ diff --git a/core/js/tests/specs/setupchecksSpec.js b/core/js/tests/specs/setupchecksSpec.js index ffa7aaec3ea69..8ef574f54d38d 100644 --- a/core/js/tests/specs/setupchecksSpec.js +++ b/core/js/tests/specs/setupchecksSpec.js @@ -249,7 +249,8 @@ describe('OC.SetupChecks tests', function() { appDirsWithDifferentOwner: [], recommendedPHPModules: [], pendingBigIntConversionColumns: [], - isMysqlUsedWithoutUTF8MB4: false + isMysqlUsedWithoutUTF8MB4: false, + isEnoughTempSpaceAvailableIfS3PrimaryStorageIsUsed: true }) ); @@ -301,7 +302,8 @@ describe('OC.SetupChecks tests', function() { appDirsWithDifferentOwner: [], recommendedPHPModules: [], pendingBigIntConversionColumns: [], - isMysqlUsedWithoutUTF8MB4: false + isMysqlUsedWithoutUTF8MB4: false, + isEnoughTempSpaceAvailableIfS3PrimaryStorageIsUsed: true }) ); @@ -354,7 +356,8 @@ describe('OC.SetupChecks tests', function() { appDirsWithDifferentOwner: [], recommendedPHPModules: [], pendingBigIntConversionColumns: [], - isMysqlUsedWithoutUTF8MB4: false + isMysqlUsedWithoutUTF8MB4: false, + isEnoughTempSpaceAvailableIfS3PrimaryStorageIsUsed: true }) ); @@ -405,7 +408,8 @@ describe('OC.SetupChecks tests', function() { appDirsWithDifferentOwner: [], recommendedPHPModules: [], pendingBigIntConversionColumns: [], - isMysqlUsedWithoutUTF8MB4: false + isMysqlUsedWithoutUTF8MB4: false, + isEnoughTempSpaceAvailableIfS3PrimaryStorageIsUsed: true }) ); @@ -454,7 +458,8 @@ describe('OC.SetupChecks tests', function() { appDirsWithDifferentOwner: [], recommendedPHPModules: [], pendingBigIntConversionColumns: [], - isMysqlUsedWithoutUTF8MB4: false + isMysqlUsedWithoutUTF8MB4: false, + isEnoughTempSpaceAvailableIfS3PrimaryStorageIsUsed: true }) ); @@ -505,7 +510,8 @@ describe('OC.SetupChecks tests', function() { ], recommendedPHPModules: [], pendingBigIntConversionColumns: [], - isMysqlUsedWithoutUTF8MB4: false + isMysqlUsedWithoutUTF8MB4: false, + isEnoughTempSpaceAvailableIfS3PrimaryStorageIsUsed: true }) ); @@ -554,7 +560,8 @@ describe('OC.SetupChecks tests', function() { appDirsWithDifferentOwner: [], recommendedPHPModules: [], pendingBigIntConversionColumns: [], - isMysqlUsedWithoutUTF8MB4: false + isMysqlUsedWithoutUTF8MB4: false, + isEnoughTempSpaceAvailableIfS3PrimaryStorageIsUsed: true }) ); @@ -603,7 +610,8 @@ describe('OC.SetupChecks tests', function() { appDirsWithDifferentOwner: [], recommendedPHPModules: [], pendingBigIntConversionColumns: [], - isMysqlUsedWithoutUTF8MB4: false + isMysqlUsedWithoutUTF8MB4: false, + isEnoughTempSpaceAvailableIfS3PrimaryStorageIsUsed: true }) ); @@ -652,7 +660,8 @@ describe('OC.SetupChecks tests', function() { appDirsWithDifferentOwner: [], recommendedPHPModules: [], pendingBigIntConversionColumns: [], - isMysqlUsedWithoutUTF8MB4: false + isMysqlUsedWithoutUTF8MB4: false, + isEnoughTempSpaceAvailableIfS3PrimaryStorageIsUsed: true }) ); @@ -722,7 +731,8 @@ describe('OC.SetupChecks tests', function() { appDirsWithDifferentOwner: [], recommendedPHPModules: [], pendingBigIntConversionColumns: [], - isMysqlUsedWithoutUTF8MB4: false + isMysqlUsedWithoutUTF8MB4: false, + isEnoughTempSpaceAvailableIfS3PrimaryStorageIsUsed: true }) ); @@ -772,7 +782,8 @@ describe('OC.SetupChecks tests', function() { appDirsWithDifferentOwner: [], recommendedPHPModules: [], pendingBigIntConversionColumns: [], - isMysqlUsedWithoutUTF8MB4: false + isMysqlUsedWithoutUTF8MB4: false, + isEnoughTempSpaceAvailableIfS3PrimaryStorageIsUsed: true }) ); @@ -822,7 +833,8 @@ describe('OC.SetupChecks tests', function() { appDirsWithDifferentOwner: [], recommendedPHPModules: [], pendingBigIntConversionColumns: [], - isMysqlUsedWithoutUTF8MB4: false + isMysqlUsedWithoutUTF8MB4: false, + isEnoughTempSpaceAvailableIfS3PrimaryStorageIsUsed: true }) ); @@ -872,7 +884,8 @@ describe('OC.SetupChecks tests', function() { appDirsWithDifferentOwner: [], recommendedPHPModules: [], pendingBigIntConversionColumns: [], - isMysqlUsedWithoutUTF8MB4: false + isMysqlUsedWithoutUTF8MB4: false, + isEnoughTempSpaceAvailableIfS3PrimaryStorageIsUsed: true }) ); @@ -921,7 +934,8 @@ describe('OC.SetupChecks tests', function() { appDirsWithDifferentOwner: [], recommendedPHPModules: [], pendingBigIntConversionColumns: [], - isMysqlUsedWithoutUTF8MB4: true + isMysqlUsedWithoutUTF8MB4: true, + isEnoughTempSpaceAvailableIfS3PrimaryStorageIsUsed: true }) ); @@ -933,6 +947,56 @@ describe('OC.SetupChecks tests', function() { done(); }); }); + + it('should return an error if there is not enough free space in the temp directory', function(done) { + var async = OC.SetupChecks.checkSetup(); + + suite.server.requests[0].respond( + 200, + { + 'Content-Type': 'application/json', + }, + JSON.stringify({ + hasFileinfoInstalled: true, + isGetenvServerWorking: true, + isReadOnlyConfig: false, + hasWorkingFileLocking: true, + hasValidTransactionIsolationLevel: true, + suggestedOverwriteCliURL: '', + isRandomnessSecure: true, + securityDocs: 'https://docs.owncloud.org/myDocs.html', + serverHasInternetConnection: true, + isMemcacheConfigured: true, + forwardedForHeadersWorking: true, + isCorrectMemcachedPHPModuleInstalled: true, + hasPassedCodeIntegrityCheck: true, + isOpcacheProperlySetup: true, + hasOpcacheLoaded: true, + isSettimelimitAvailable: true, + hasFreeTypeSupport: true, + missingIndexes: [], + outdatedCaches: [], + cronErrors: [], + cronInfo: { + diffInSeconds: 0 + }, + isMemoryLimitSufficient: true, + appDirsWithDifferentOwner: [], + recommendedPHPModules: [], + pendingBigIntConversionColumns: [], + isMysqlUsedWithoutUTF8MB4: false, + isEnoughTempSpaceAvailableIfS3PrimaryStorageIsUsed: false + }) + ); + + async.done(function( data, s, x ){ + expect(data).toEqual([{ + msg: 'This instance uses an S3 based object store as primary storage. The uploaded files are stored temporarily on the server and thus it is recommended to have 50 GB of free space available in the temp directory of PHP. Check the logs for full details about the path and the available space. To improve this please change the temporary directory in the php.ini or make more space available in that path.', + type: OC.SetupChecks.MESSAGE_TYPE_WARNING + }]); + done(); + }); + }); }); describe('checkGeneric', function() { diff --git a/settings/Controller/CheckSetupController.php b/settings/Controller/CheckSetupController.php index b86f25a7fea28..70dfadd196f84 100644 --- a/settings/Controller/CheckSetupController.php +++ b/settings/Controller/CheckSetupController.php @@ -642,6 +642,42 @@ protected function hasBigIntConversionPendingColumns(): array { return $pendingColumns; } + protected function isEnoughTempSpaceAvailableIfS3PrimaryStorageIsUsed(): bool { + $objectStore = $this->config->getSystemValue('objectstore', null); + $objectStoreMultibucket = $this->config->getSystemValue('objectstore_multibucket', null); + + if (!isset($objectStoreMultibucket) && !isset($objectStore)) { + return true; + } + + if (isset($objectStoreMultibucket['class']) && $objectStoreMultibucket['class'] !== 'OC\\Files\\ObjectStore\\S3') { + return true; + } + + if (isset($objectStore['class']) && $objectStore['class'] !== 'OC\\Files\\ObjectStore\\S3') { + return true; + } + + $tempPath = sys_get_temp_dir(); + if (!is_dir($tempPath)) { + $this->logger->error('Error while checking the temporary PHP path - it was not properly set to a directory. value: ' . $tempPath); + return false; + } + $freeSpaceInTemp = disk_free_space($tempPath); + if ($freeSpaceInTemp === false) { + $this->logger->error('Error while checking the available disk space of temporary PHP path - no free disk space returned. temporary path: ' . $tempPath); + return false; + } + + $freeSpaceInTempInGB = $freeSpaceInTemp / 1024 / 1024 / 1024; + if ($freeSpaceInTempInGB > 50) { + return true; + } + + $this->logger->warning('Checking the available space in the temporary path resulted in ' . round($freeSpaceInTempInGB, 1) . ' GB instead of the recommended 50GB. Path: ' . $tempPath); + return false; + } + /** * @return DataResponse */ @@ -684,6 +720,7 @@ public function check() { 'recommendedPHPModules' => $this->hasRecommendedPHPModules(), 'pendingBigIntConversionColumns' => $this->hasBigIntConversionPendingColumns(), 'isMysqlUsedWithoutUTF8MB4' => $this->isMysqlUsedWithoutUTF8MB4(), + 'isEnoughTempSpaceAvailableIfS3PrimaryStorageIsUsed' => $this->isEnoughTempSpaceAvailableIfS3PrimaryStorageIsUsed(), ] ); } diff --git a/tests/Settings/Controller/CheckSetupControllerTest.php b/tests/Settings/Controller/CheckSetupControllerTest.php index 8a491d0d047ff..8b4837f3b23d5 100644 --- a/tests/Settings/Controller/CheckSetupControllerTest.php +++ b/tests/Settings/Controller/CheckSetupControllerTest.php @@ -161,6 +161,7 @@ public function setUp() { 'hasRecommendedPHPModules', 'hasBigIntConversionPendingColumns', 'isMysqlUsedWithoutUTF8MB4', + 'isEnoughTempSpaceAvailableIfS3PrimaryStorageIsUsed', ])->getMock(); } @@ -505,6 +506,11 @@ public function testCheck() { ->method('isMysqlUsedWithoutUTF8MB4') ->willReturn(false); + $this->checkSetupController + ->expects($this->once()) + ->method('isEnoughTempSpaceAvailableIfS3PrimaryStorageIsUsed') + ->willReturn(true); + $expected = new DataResponse( [ 'isGetenvServerWorking' => true, @@ -550,6 +556,7 @@ public function testCheck() { 'recommendedPHPModules' => [], 'pendingBigIntConversionColumns' => [], 'isMysqlUsedWithoutUTF8MB4' => false, + 'isEnoughTempSpaceAvailableIfS3PrimaryStorageIsUsed' => true, ] ); $this->assertEquals($expected, $this->checkSetupController->check()); @@ -1380,4 +1387,53 @@ public function testIsMysqlUsedWithoutUTF8MB4(string $db, bool $useUTF8MB4, bool $this->assertSame($expected, $this->invokePrivate($checkSetupController, 'isMysqlUsedWithoutUTF8MB4')); } + + public function dataForIsEnoughTempSpaceAvailableIfS3PrimaryStorageIsUsed() { + return [ + ['singlebucket', 'OC\\Files\\ObjectStore\\Swift', true], + ['multibucket', 'OC\\Files\\ObjectStore\\Swift', true], + ['singlebucket', 'OC\\Files\\ObjectStore\\Custom', true], + ['multibucket', 'OC\Files\\ObjectStore\\Custom', true], + ['singlebucket', 'OC\Files\ObjectStore\Swift', true], + ['multibucket', 'OC\Files\ObjectStore\Swift', true], + ['singlebucket', 'OC\Files\ObjectStore\Custom', true], + ['multibucket', 'OC\Files\ObjectStore\Custom', true], + ]; + } + + /** + * @dataProvider dataForIsEnoughTempSpaceAvailableIfS3PrimaryStorageIsUsed + */ + public function testIsEnoughTempSpaceAvailableIfS3PrimaryStorageIsUsed(string $mode, string $className, bool $expected) { + $this->config->method('getSystemValue') + ->will($this->returnCallback(function($key, $default) use ($mode, $className) { + if ($key === 'objectstore' && $mode === 'singlebucket') { + return ['class' => $className]; + } + if ($key === 'objectstore_multibucket' && $mode === 'multibucket') { + return ['class' => $className]; + } + return $default; + })); + + $checkSetupController = new CheckSetupController( + 'settings', + $this->request, + $this->config, + $this->clientService, + $this->urlGenerator, + $this->util, + $this->l10n, + $this->checker, + $this->logger, + $this->dispatcher, + $this->db, + $this->lockingProvider, + $this->dateTimeFormatter, + $this->memoryInfo, + $this->secureRandom + ); + + $this->assertSame($expected, $this->invokePrivate($checkSetupController, 'isEnoughTempSpaceAvailableIfS3PrimaryStorageIsUsed')); + } }