mirror of
https://github.com/nextcloud/server.git
synced 2026-06-13 18:50:47 -04:00
feat(config): allow to override some config values by hostname
Signed-off-by: Benjamin Gaussorgues <benjamin.gaussorgues@nextcloud.com>
This commit is contained in:
parent
f06168f6c4
commit
36ce48152e
5 changed files with 65 additions and 9 deletions
|
|
@ -3522,10 +3522,6 @@
|
|||
<code><![CDATA[$this->delete($key)]]></code>
|
||||
<code><![CDATA[$this->set($key, $value)]]></code>
|
||||
</InvalidOperand>
|
||||
<UndefinedVariable>
|
||||
<code><![CDATA[$CONFIG]]></code>
|
||||
<code><![CDATA[$CONFIG]]></code>
|
||||
</UndefinedVariable>
|
||||
</file>
|
||||
<file src="lib/private/Console/Application.php">
|
||||
<NoInterfaceProperties>
|
||||
|
|
|
|||
|
|
@ -45,6 +45,17 @@ $CONFIG = [
|
|||
*/
|
||||
'instanceid' => '',
|
||||
|
||||
/**
|
||||
* This is a unique identifier for your server.
|
||||
* It is useful when your Nextcloud instance is spread between different servers.
|
||||
* Once it's set it shouldn't be changed.
|
||||
*
|
||||
* Value must be an integer, comprised between 0 and 1023.
|
||||
*
|
||||
* This value should be overriden by hostname in $CONFIG_HOSTNAME
|
||||
*/
|
||||
'serverid' => -1,
|
||||
|
||||
/**
|
||||
* The salt used to hash all passwords, auto-generated by the Nextcloud
|
||||
* installer. (There are also per-user salts.) If you lose this salt, you lose
|
||||
|
|
@ -2813,3 +2824,18 @@ $CONFIG = [
|
|||
*/
|
||||
'enable_lazy_objects' => true,
|
||||
];
|
||||
|
||||
/**
|
||||
* CONFIG_HOSTNAME allows to set specific configuration value on specific hosts.
|
||||
* It should be used when configuration is stored on a shared filesystem between several servers.
|
||||
*
|
||||
* Only options listed in \OC\Config::HOST_OVERRIDE_CONFIG can be defined here.
|
||||
*/
|
||||
$CONFIG_HOSTNAME = [
|
||||
'hostname_a' => [
|
||||
'serverid' => 42,
|
||||
],
|
||||
'hostname_b' => [
|
||||
'serverid' => 43,
|
||||
],
|
||||
];
|
||||
|
|
|
|||
|
|
@ -15,6 +15,10 @@ use OCP\HintException;
|
|||
*/
|
||||
class Config {
|
||||
public const ENV_PREFIX = 'NC_';
|
||||
// List configurations that can be overriden based on server hostname
|
||||
private const HOST_OVERRIDE_CONFIG = [
|
||||
'serverid',
|
||||
];
|
||||
|
||||
/** @var array Associative array ($key => $value) */
|
||||
protected $cache = [];
|
||||
|
|
@ -199,7 +203,7 @@ class Config {
|
|||
|
||||
// Include file and merge config
|
||||
foreach ($configFiles as $file) {
|
||||
unset($CONFIG);
|
||||
$CONFIG = $CONFIG_HOSTNAME = null;
|
||||
|
||||
// Invalidate opcache (only if the timestamp changed)
|
||||
if (function_exists('opcache_invalidate')) {
|
||||
|
|
@ -226,6 +230,10 @@ class Config {
|
|||
}
|
||||
|
||||
try {
|
||||
/**
|
||||
* @var ?array $CONFIG
|
||||
* @var ?array $CONFIG_HOSTNAME
|
||||
*/
|
||||
include $file;
|
||||
} finally {
|
||||
// Close the file pointer and release the lock
|
||||
|
|
@ -241,9 +249,20 @@ class Config {
|
|||
}
|
||||
throw new \Exception($errorMessage);
|
||||
}
|
||||
if (isset($CONFIG) && is_array($CONFIG)) {
|
||||
if (is_array($CONFIG)) {
|
||||
$this->cache = array_merge($this->cache, $CONFIG);
|
||||
}
|
||||
if (is_array($CONFIG_HOSTNAME) && !empty($CONFIG_HOSTNAME)) {
|
||||
$hostname = gethostname();
|
||||
if (isset($CONFIG_HOSTNAME[$hostname]) && is_array($CONFIG_HOSTNAME[$hostname])) {
|
||||
$filteredConfig = array_filter(
|
||||
$CONFIG_HOSTNAME[$hostname],
|
||||
fn ($key) => in_array($key, self::HOST_OVERRIDE_CONFIG),
|
||||
ARRAY_FILTER_USE_KEY,
|
||||
);
|
||||
$this->cache = array_merge($this->cache, $filteredConfig);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// grab any "NC_" environment variables
|
||||
|
|
|
|||
|
|
@ -10,6 +10,7 @@ declare(strict_types=1);
|
|||
namespace OC\Snowflake;
|
||||
|
||||
use OCP\AppFramework\Utility\ITimeFactory;
|
||||
use OCP\IConfig;
|
||||
use OCP\Snowflake\IGenerator;
|
||||
use Override;
|
||||
|
||||
|
|
@ -23,6 +24,7 @@ use Override;
|
|||
final class Generator implements IGenerator {
|
||||
public function __construct(
|
||||
private readonly ITimeFactory $timeFactory,
|
||||
private readonly IConfig $config,
|
||||
) {
|
||||
}
|
||||
|
||||
|
|
@ -100,7 +102,10 @@ final class Generator implements IGenerator {
|
|||
}
|
||||
|
||||
private function getServerId(): int {
|
||||
return crc32(gethostname() ?: random_bytes(8));
|
||||
$serverid = $this->config->getSystemValueInt('serverid', -1);
|
||||
return $serverid > 0
|
||||
? $serverid
|
||||
: crc32(gethostname() ?: random_bytes(8));
|
||||
}
|
||||
|
||||
private function isCli(): bool {
|
||||
|
|
|
|||
|
|
@ -13,6 +13,7 @@ use OC\AppFramework\Utility\TimeFactory;
|
|||
use OC\Snowflake\Decoder;
|
||||
use OC\Snowflake\Generator;
|
||||
use OCP\AppFramework\Utility\ITimeFactory;
|
||||
use OCP\IConfig;
|
||||
use OCP\Snowflake\IGenerator;
|
||||
use PHPUnit\Framework\Attributes\DataProvider;
|
||||
use Test\TestCase;
|
||||
|
|
@ -22,12 +23,17 @@ use Test\TestCase;
|
|||
*/
|
||||
class GeneratorTest extends TestCase {
|
||||
private Decoder $decoder;
|
||||
private IConfig|MockObject $config;
|
||||
|
||||
public function setUp():void {
|
||||
$this->decoder = new Decoder();
|
||||
$this->config = $this->createMock(IConfig::class);
|
||||
$this->config->method('getSystemValueInt')
|
||||
->with('serverid')
|
||||
->willReturn(42);
|
||||
}
|
||||
public function testGenerator(): void {
|
||||
$generator = new Generator(new TimeFactory());
|
||||
$generator = new Generator(new TimeFactory(), $this->config);
|
||||
$snowflakeId = $generator->nextId();
|
||||
$data = $this->decoder->decode($generator->nextId());
|
||||
|
||||
|
|
@ -45,6 +51,9 @@ class GeneratorTest extends TestCase {
|
|||
|
||||
// Check CLI
|
||||
$this->assertTrue($data['isCli']);
|
||||
|
||||
// Check serverId
|
||||
$this->assertEquals(42, $data['serverId']);
|
||||
}
|
||||
|
||||
#[DataProvider('provideSnowflakeData')]
|
||||
|
|
@ -53,11 +62,12 @@ class GeneratorTest extends TestCase {
|
|||
$timeFactory = $this->createMock(ITimeFactory::class);
|
||||
$timeFactory->method('now')->willReturn($dt);
|
||||
|
||||
$generator = new Generator($timeFactory);
|
||||
$generator = new Generator($timeFactory, $this->config);
|
||||
$data = $this->decoder->decode($generator->nextId());
|
||||
|
||||
$this->assertEquals($expectedSeconds, ($data['createdAt']->format('U') - IGenerator::TS_OFFSET));
|
||||
$this->assertEquals($expectedMilliseconds, (int)$data['createdAt']->format('v'));
|
||||
$this->assertEquals(42, $data['serverId']);
|
||||
}
|
||||
|
||||
public static function provideSnowflakeData(): array {
|
||||
|
|
|
|||
Loading…
Reference in a new issue