mirror of
https://github.com/nextcloud/server.git
synced 2026-06-09 08:44:07 -04:00
Merge pull request #52864 from nextcloud/backport/51818/stable31
[stable31] feat: add command to get basic storage info
This commit is contained in:
commit
7112144b9c
6 changed files with 200 additions and 0 deletions
|
|
@ -13,6 +13,7 @@ use OCA\Files_External\Config\ExternalMountPoint;
|
|||
use OCA\Files_Sharing\SharedMount;
|
||||
use OCA\GroupFolders\Mount\GroupMountPoint;
|
||||
use OCP\Constants;
|
||||
use OCP\DB\QueryBuilder\IQueryBuilder;
|
||||
use OCP\Files\Config\IUserMountCache;
|
||||
use OCP\Files\FileInfo;
|
||||
use OCP\Files\Folder;
|
||||
|
|
@ -21,14 +22,19 @@ use OCP\Files\IRootFolder;
|
|||
use OCP\Files\Mount\IMountPoint;
|
||||
use OCP\Files\Node;
|
||||
use OCP\Files\NotFoundException;
|
||||
use OCP\IDBConnection;
|
||||
use OCP\Share\IShare;
|
||||
use OCP\Util;
|
||||
use Symfony\Component\Console\Output\OutputInterface;
|
||||
|
||||
/**
|
||||
* @psalm-type StorageInfo array{numeric_id: int, id: string, available: bool, last_checked: ?\DateTime, files: int, mount_id: ?int}
|
||||
*/
|
||||
class FileUtils {
|
||||
public function __construct(
|
||||
private IRootFolder $rootFolder,
|
||||
private IUserMountCache $userMountCache,
|
||||
private IDBConnection $connection,
|
||||
) {
|
||||
}
|
||||
|
||||
|
|
@ -219,4 +225,100 @@ class FileUtils {
|
|||
}
|
||||
return $count;
|
||||
}
|
||||
|
||||
public function getNumericStorageId(string $id): ?int {
|
||||
if (is_numeric($id)) {
|
||||
return (int)$id;
|
||||
}
|
||||
$query = $this->connection->getQueryBuilder();
|
||||
$query->select('numeric_id')
|
||||
->from('storages')
|
||||
->where($query->expr()->eq('id', $query->createNamedParameter($id)));
|
||||
$result = $query->executeQuery()->fetchOne();
|
||||
return $result ? (int)$result : null;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param int|null $limit
|
||||
* @return ?StorageInfo
|
||||
* @throws \OCP\DB\Exception
|
||||
*/
|
||||
public function getStorage(int $id): ?array {
|
||||
$query = $this->connection->getQueryBuilder();
|
||||
$query->select('numeric_id', 's.id', 'available', 'last_checked', 'mount_id')
|
||||
->selectAlias($query->func()->count('fileid'), 'files')
|
||||
->from('storages', 's')
|
||||
->innerJoin('s', 'filecache', 'f', $query->expr()->eq('f.storage', 's.numeric_id'))
|
||||
->leftJoin('s', 'mounts', 'm', $query->expr()->eq('s.numeric_id', 'm.storage_id'))
|
||||
->where($query->expr()->eq('s.numeric_id', $query->createNamedParameter($id, IQueryBuilder::PARAM_INT)))
|
||||
->groupBy('s.numeric_id', 's.id', 's.available', 's.last_checked', 'mount_id');
|
||||
$row = $query->executeQuery()->fetch();
|
||||
if ($row) {
|
||||
return [
|
||||
'numeric_id' => $row['numeric_id'],
|
||||
'id' => $row['id'],
|
||||
'files' => $row['files'],
|
||||
'available' => (bool)$row['available'],
|
||||
'last_checked' => $row['last_checked'] ? new \DateTime('@' . $row['last_checked']) : null,
|
||||
'mount_id' => $row['mount_id'],
|
||||
];
|
||||
} else {
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* @param int|null $limit
|
||||
* @return \Iterator<StorageInfo>
|
||||
* @throws \OCP\DB\Exception
|
||||
*/
|
||||
public function listStorages(?int $limit): \Iterator {
|
||||
$query = $this->connection->getQueryBuilder();
|
||||
$query->select('numeric_id', 's.id', 'available', 'last_checked', 'mount_id')
|
||||
->selectAlias($query->func()->count('fileid'), 'files')
|
||||
->from('storages', 's')
|
||||
->innerJoin('s', 'filecache', 'f', $query->expr()->eq('f.storage', 's.numeric_id'))
|
||||
->leftJoin('s', 'mounts', 'm', $query->expr()->eq('s.numeric_id', 'm.storage_id'))
|
||||
->groupBy('s.numeric_id', 's.id', 's.available', 's.last_checked', 'mount_id')
|
||||
->orderBy('files', 'DESC');
|
||||
if ($limit !== null) {
|
||||
$query->setMaxResults($limit);
|
||||
}
|
||||
$result = $query->executeQuery();
|
||||
while ($row = $result->fetch()) {
|
||||
yield [
|
||||
'numeric_id' => $row['numeric_id'],
|
||||
'id' => $row['id'],
|
||||
'files' => $row['files'],
|
||||
'available' => (bool)$row['available'],
|
||||
'last_checked' => $row['last_checked'] ? new \DateTime('@' . $row['last_checked']) : null,
|
||||
'mount_id' => $row['mount_id'],
|
||||
];
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* @param StorageInfo $storage
|
||||
* @return array
|
||||
*/
|
||||
public function formatStorage(array $storage): array {
|
||||
return [
|
||||
'numeric_id' => $storage['numeric_id'],
|
||||
'id' => $storage['id'],
|
||||
'files' => $storage['files'],
|
||||
'available' => $storage['available'] ? 'true' : 'false',
|
||||
'last_checked' => $storage['last_checked']?->format(\DATE_ATOM),
|
||||
'external_mount_id' => $storage['mount_id'],
|
||||
];
|
||||
}
|
||||
|
||||
/**
|
||||
* @param \Iterator<StorageInfo> $storages
|
||||
* @return \Iterator
|
||||
*/
|
||||
public function formatStorages(\Iterator $storages): \Iterator {
|
||||
foreach ($storages as $storage) {
|
||||
yield $this->formatStorage($storage);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
|||
49
core/Command/Info/Storage.php
Normal file
49
core/Command/Info/Storage.php
Normal file
|
|
@ -0,0 +1,49 @@
|
|||
<?php
|
||||
|
||||
declare(strict_types=1);
|
||||
/**
|
||||
* SPDX-FileCopyrightText: 2023 Nextcloud GmbH and Nextcloud contributors
|
||||
* SPDX-License-Identifier: AGPL-3.0-or-later
|
||||
*/
|
||||
|
||||
namespace OC\Core\Command\Info;
|
||||
|
||||
use OC\Core\Command\Base;
|
||||
use OCP\IDBConnection;
|
||||
use Symfony\Component\Console\Input\InputArgument;
|
||||
use Symfony\Component\Console\Input\InputInterface;
|
||||
use Symfony\Component\Console\Output\OutputInterface;
|
||||
|
||||
class Storage extends Base {
|
||||
public function __construct(
|
||||
private readonly IDBConnection $connection,
|
||||
private readonly FileUtils $fileUtils,
|
||||
) {
|
||||
parent::__construct();
|
||||
}
|
||||
|
||||
protected function configure(): void {
|
||||
parent::configure();
|
||||
$this
|
||||
->setName('info:storage')
|
||||
->setDescription('Get information a single storage')
|
||||
->addArgument('storage', InputArgument::REQUIRED, 'Storage to get information for');
|
||||
}
|
||||
|
||||
public function execute(InputInterface $input, OutputInterface $output): int {
|
||||
$storage = $input->getArgument('storage');
|
||||
$storageId = $this->fileUtils->getNumericStorageId($storage);
|
||||
if (!$storageId) {
|
||||
$output->writeln('<error>No storage with id ' . $storage . ' found</error>');
|
||||
return 1;
|
||||
}
|
||||
|
||||
$info = $this->fileUtils->getStorage($storageId);
|
||||
if (!$info) {
|
||||
$output->writeln('<error>No storage with id ' . $storage . ' found</error>');
|
||||
return 1;
|
||||
}
|
||||
$this->writeArrayInOutputFormat($input, $output, $this->fileUtils->formatStorage($info));
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
43
core/Command/Info/Storages.php
Normal file
43
core/Command/Info/Storages.php
Normal file
|
|
@ -0,0 +1,43 @@
|
|||
<?php
|
||||
|
||||
declare(strict_types=1);
|
||||
/**
|
||||
* SPDX-FileCopyrightText: 2023 Nextcloud GmbH and Nextcloud contributors
|
||||
* SPDX-License-Identifier: AGPL-3.0-or-later
|
||||
*/
|
||||
|
||||
namespace OC\Core\Command\Info;
|
||||
|
||||
use OC\Core\Command\Base;
|
||||
use OCP\IDBConnection;
|
||||
use Symfony\Component\Console\Input\InputInterface;
|
||||
use Symfony\Component\Console\Input\InputOption;
|
||||
use Symfony\Component\Console\Output\OutputInterface;
|
||||
|
||||
class Storages extends Base {
|
||||
public function __construct(
|
||||
private readonly IDBConnection $connection,
|
||||
private readonly FileUtils $fileUtils,
|
||||
) {
|
||||
parent::__construct();
|
||||
}
|
||||
|
||||
protected function configure(): void {
|
||||
parent::configure();
|
||||
$this
|
||||
->setName('info:storages')
|
||||
->setDescription('List storages ordered by the number of files')
|
||||
->addOption('count', 'c', InputOption::VALUE_REQUIRED, 'Number of storages to display', 25)
|
||||
->addOption('all', 'a', InputOption::VALUE_NONE, 'Display all storages');
|
||||
}
|
||||
|
||||
public function execute(InputInterface $input, OutputInterface $output): int {
|
||||
$count = (int)$input->getOption('count');
|
||||
$all = $input->getOption('all');
|
||||
|
||||
$limit = $all ? null : $count;
|
||||
$storages = $this->fileUtils->listStorages($limit);
|
||||
$this->writeStreamingTableInOutputFormat($input, $output, $this->fileUtils->formatStorages($storages), 100);
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
|
|
@ -57,6 +57,8 @@ if ($config->getSystemValueBool('installed', false)) {
|
|||
|
||||
$application->add(Server::get(Command\Info\File::class));
|
||||
$application->add(Server::get(Command\Info\Space::class));
|
||||
$application->add(Server::get(Command\Info\Storage::class));
|
||||
$application->add(Server::get(Command\Info\Storages::class));
|
||||
|
||||
$application->add(Server::get(Command\Db\ConvertType::class));
|
||||
$application->add(Server::get(Command\Db\ConvertMysqlToMB4::class));
|
||||
|
|
|
|||
|
|
@ -1260,6 +1260,8 @@ return array(
|
|||
'OC\\Core\\Command\\Info\\File' => $baseDir . '/core/Command/Info/File.php',
|
||||
'OC\\Core\\Command\\Info\\FileUtils' => $baseDir . '/core/Command/Info/FileUtils.php',
|
||||
'OC\\Core\\Command\\Info\\Space' => $baseDir . '/core/Command/Info/Space.php',
|
||||
'OC\\Core\\Command\\Info\\Storage' => $baseDir . '/core/Command/Info/Storage.php',
|
||||
'OC\\Core\\Command\\Info\\Storages' => $baseDir . '/core/Command/Info/Storages.php',
|
||||
'OC\\Core\\Command\\Integrity\\CheckApp' => $baseDir . '/core/Command/Integrity/CheckApp.php',
|
||||
'OC\\Core\\Command\\Integrity\\CheckCore' => $baseDir . '/core/Command/Integrity/CheckCore.php',
|
||||
'OC\\Core\\Command\\Integrity\\SignApp' => $baseDir . '/core/Command/Integrity/SignApp.php',
|
||||
|
|
|
|||
|
|
@ -1309,6 +1309,8 @@ class ComposerStaticInit749170dad3f5e7f9ca158f5a9f04f6a2
|
|||
'OC\\Core\\Command\\Info\\File' => __DIR__ . '/../../..' . '/core/Command/Info/File.php',
|
||||
'OC\\Core\\Command\\Info\\FileUtils' => __DIR__ . '/../../..' . '/core/Command/Info/FileUtils.php',
|
||||
'OC\\Core\\Command\\Info\\Space' => __DIR__ . '/../../..' . '/core/Command/Info/Space.php',
|
||||
'OC\\Core\\Command\\Info\\Storage' => __DIR__ . '/../../..' . '/core/Command/Info/Storage.php',
|
||||
'OC\\Core\\Command\\Info\\Storages' => __DIR__ . '/../../..' . '/core/Command/Info/Storages.php',
|
||||
'OC\\Core\\Command\\Integrity\\CheckApp' => __DIR__ . '/../../..' . '/core/Command/Integrity/CheckApp.php',
|
||||
'OC\\Core\\Command\\Integrity\\CheckCore' => __DIR__ . '/../../..' . '/core/Command/Integrity/CheckCore.php',
|
||||
'OC\\Core\\Command\\Integrity\\SignApp' => __DIR__ . '/../../..' . '/core/Command/Integrity/SignApp.php',
|
||||
|
|
|
|||
Loading…
Reference in a new issue