Commit graph

35 commits

Author SHA1 Message Date
daniel
404f4a8512 Fix edge cases in schema validation.
Since PHP arrays make no clear distinction between lists (JSON arrays)
and maps (JSON objects), some edge case handling is needed to make
validation work reliably when we declare types for all arrays:

1) Allow array keys to be ignored, so an associative PHP array validates
as a JSON array. This is needed for the SessionProviders setting.

2) Allow associative arrays with numeric keys to validate as JSON
objects. This is done by ignoring the type validation when numeric keys
are detected. A warning is returned in the status object.

3) Work around validation failing on float values that are expected to
be integers. All numbers come from the yaml parser as floats, and the
"integer" type in JSON schema should accept floats with if the
fractional part is 0. But that doesn't seem to work, we need to cast the
values to integers explicitly.

Also, this fixes some mistakes in the schema: LockManagers is a list,
so it should use the JSON type "array". NamespacesToBeSearchedDefault
is a map (JSON object), even though it uses numeric keys. The Actions
registry is also a map.

Change-Id: I9d0453d740c377b7cce574df743536c39a0ec619
2022-03-08 13:59:19 +01:00
Umherirrender
b126dbe3f2 Fix various documentation related to null types
The functions returning null or the class property is set explict null

Found by phan strict checks

Change-Id: I4a271093fb6526564d8083a08249c64cb21f2453
2022-02-26 10:31:24 +01:00
daniel
f9b589f556 config-schema: Define types for all arrays.
This patch ensures that we know which arrays are lists (JsonSchema type
"array") and which are maps (JsonSchema type "object"). We can then
default to array_merge for lists and to array_plus for maps. This seems
clearer than requiring an explicit merge strategy to be declared for all
arrays.

This patch specified a mergeTrategy for some config variables that need
behavior different from the default.

This patch also changes the merging behavior to allow non-array values
to replace arrays and vice versa. It also changes the behavior of
defaults to allow falsy values to override non-falsy defaults.

Bug: T300129
Change-Id: Ia7b0c0250af6a957eac1efb554fb47511f5e093f
2022-02-23 14:09:41 +01:00
jenkins-bot
6a85933fd7 Merge "Avoid references to DefaultSettings." 2022-02-22 23:47:25 +00:00
daniel
cf499e8491 Allow config merge strategies to be bypassed.
Sometimes, we need to force an exact value and bypass the default
behavior of merging config variables.

This also renames setConfigValue to putConfigValue, to avoid confusion
about the behavior of that method.

Change-Id: I82c606632b94f974e655a44a0b63394de7a0804b
2022-02-22 22:59:25 +00:00
daniel
a5277ce87f Avoid references to DefaultSettings.
This replaces references to DefaultSettings with
references to config-schema.yaml where appropriate.

NOTE: this does not yet change Setup.php. DefaultSettings.php
remains intact and is still being used.

NOTE: this does not remove usages in the installer, see I5d8843a1062fbf
for that.

Bug: T300129
Change-Id: Ie6152cf510c3be61bc22167ca6d90dfc28910a45
2022-02-22 19:43:50 +01:00
daniel
8299c9de3f Introduce IterableConfig
Bug: T301544
Change-Id: I0a93ebb5305f95cf1b12df276f25a44195fedafa
2022-02-14 21:27:23 +01:00
Dan Duvall
aae7c326ef Use a mutex to prevent settings cache stampedes
There are cases where probabilistic early expiry is not enough to
prevent cache stampedes, most notably during a cold start/restart where
the cache is not yet populated and during conditions where source I/O
wait times may exceed the possible range of early expiry offset.

To completely prevent cache stampedes from occurring, a mutex must be
used around settings (re)caching.

Early expiry is left in place as it should still be quite effective in
reducing cache lock contention.

Bug: T296771
Change-Id: I99676466ce1ad4f1622867158d2ed15ef9202ec2
2022-01-28 09:13:38 -08:00
jenkins-bot
3843d16823 Merge "Reapply "SettingsBuilder: allow maintenance scripts to manipulate config"" 2022-01-27 17:53:01 +00:00
Ppchelko
44edde6295 Reapply "SettingsBuilder: allow maintenance scripts to manipulate config"
This reverts commit 4f7a4a2477.

Reason for revert: This change is good, just need some preparation in extensions.

Depends-On: I24221be2cedfa132fc94d39d72e4a133cc3cdb12
Depends-On: I5e6119b650e581c6aa5a1132aa071b49cff8b8ca
Change-Id: I5a5a9000751fa3914c9d432eb49475091b3bdb80
2022-01-26 19:21:58 +00:00
jenkins-bot
89d2a6403d Merge "Revert "SettingsBuilder: allow maintenance scripts to manipulate config"" 2022-01-26 17:40:58 +00:00
Ppchelko
4f7a4a2477 Revert "SettingsBuilder: allow maintenance scripts to manipulate config"
This reverts commit a652f306a5.

Reason for revert: need to prepare extensions first

Change-Id: Iccedf38a8dc964db7c49fd51c971912655122081
2022-01-26 17:24:31 +00:00
jenkins-bot
21ba2d4dab Merge "SettingsBuilder: allow maintenance scripts to manipulate config" 2022-01-26 15:20:10 +00:00
daniel
a652f306a5 SettingsBuilder: allow maintenance scripts to manipulate config
Maintenance scripts often need to manipulate configuration settings.
This introduces a way to do this cleanly via SettingsBuilder,
removing the need to rely on global variables.

Bug: T294739
Bug: T294742
Bug: T300128
Change-Id: Ibf443fd564bbbf388cce8ab4dabba55ebca0dfa4
2022-01-26 12:02:56 +00:00
jenkins-bot
73794a1846 Merge "SettingsBuilder: fix merging into globals" 2022-01-25 18:21:54 +00:00
daniel
3ef1fdff8d SettingsBuilder: fix merging into globals
GlobalConfigBuilder needs to use the appropriate merge strategy to
combine new values with the value already rpesent in a global variable.
For this, GlobalConfigBuilder needs to actually look at the current
value of the global variable. Also, we need to define merge strategies
for all settings that need them (at least the ones used directly by
ExtensionProcessor).

Change-Id: I834d4b3506bdd8d416e5eb6e03fb4dd6b60b6e05
2022-01-24 17:35:15 +01:00
Dan Duvall
a824da0f34 Support stale cached settings for failover
Require a `CacheableSource` implementation to signal whether stale
settings may be served from the cache by implementing an
`allowsStaleLoad()` method. This will be useful for sources (e.g. etcd)
that expect some degree of unavailability and failover during
unavailability is desired.

In order to support stale results, `CachedSource` sets cache items with
an indefinite TTL but uses the computed expiry timestamp in the envelope
to consider whether the item is considered expired as opposed to a true
miss where the item is malformed or not present in the cache store.  If
a `SettingsBuilderException` is thrown during the source's `load()`
method but the cache check was not a real miss, the stale cached results
are returned.

Note there is currently no pruning of cache items so it is advised that
`CacheableSource` implementations for which stale loads are allowed also
implement an immutable `getHashKey()` based on constructor arguments.

Bug: T296771
Change-Id: Ida0698a237dc0939230799700b6f54956f033d50
2022-01-21 13:31:09 -08:00
Petr Pchelko
26c4cc489c SettingsBuilder: expose default config
This will be useful in CI

Bug: T296045
Change-Id: I4d412c5ff2abe9c07f4cbe0b299f0ddf6fb6a169
2022-01-20 12:10:57 -08:00
daniel
da99bcd6aa SettingsBuilder: load settings recursively
Allows settings files to include other settings files.

Change-Id: Ieab7def1ada8b255e60c58927850a58e18309f6e
2022-01-18 21:51:35 +01:00
Florian
367e8c3423 Settings: Fix GlobalConfigBuilder use of GLOBALS for PHP 8.1
Follows-up Ibb4fdf83d87ad204da.

Saving a reference to the whole $GLOBALS object is not supported in PHP
8.1 anymore. This change aims to workaround this and still propagate the
new variable setting to the globals.

Bug: T297911
Change-Id: Idafdfae7cbcb353dc5644457d2ebfb1be82aef73
2021-12-17 00:19:49 +00:00
Dan Duvall
9778adf1c5 Refactor SettingsBuilder to use BagOStuff.
Removed use of Psr\SimpleCache\CacheInterface in favor of BagOStuff, as
the latter is a tried-and-true abstraction and the former offers no real
upfront benefits since the caching patterns of SettingsBuilder are quite
basic at this time.

The simplicity of cache interface use is largely in part to the minimal
probabilistic stampede protection implementation within CachedSource
which is left untouched by this change.

Bug: T294748
Change-Id: Ie59b37a8d5c7bf96225757fa9eb9d2c762476713
2021-12-10 10:20:05 -08:00
Derick Alangi
6aac95eb44 Settings: Introduce PhpSettingsSource for provisioning settings
This is an intermediate step before converting the merge strategies or
other configs/config schemas to YAML.

Bug: T297320
Change-Id: I91cd04d14f0ff86125fc8870984dab045c2098b5
2021-12-09 20:35:32 +00:00
daniel
ffc247d417 SettingsBuilder: load skins and extensions
This is a minimal baseline implementation that allows skins and
extensions to be loaded from settings files.

This should be improved by closely integrating SettingsBuilder with
ExtensionRegistry. They should probably end up being the same thing
eventually. Loading extension.json is essentially the same as loading
settings files.

Change-Id: I02a1d9b517815463f150b53c0602927609ff9eeb
2021-12-07 17:25:58 +01:00
jenkins-bot
ac553b8d3f Merge "Settings: Prevent applying more settings after invoking ->finalize()" 2021-12-06 21:47:14 +00:00
Dan Duvall
9fb695d75c Refactor cache TTL for SettingsBuilder sources
Move cache TTL from `CachedSource` into the `CacheableSource` interface,
allowing each source to define a TTL most appropriate to its own
settings loading implementation.

Fix bug where `generation` time was computed incorrectly by `CachedSource`.

Include tests to exercise all `CachedSource` interactions with
`CacheInterface` and `CacheableSource`.

Bug: T296771
Change-Id: I97c42cf6ca716516c32104de25245aa21ec110e4
2021-12-02 09:53:46 -08:00
Derick Alangi
086f4b1c5f Settings: Prevent applying more settings after invoking ->finalize()
When we're done applying settings and we call `finalize()`, any further
attempt to apply settings too late should throw.

This is a defensive mechanism for us to track the state of settings applied
in during setup process and will guide us to bring all settings to be applied
in the appropriate place so unexpected things don't happen.

Bug: T296684
Change-Id: Id58654c8265bc8310e1fe464ff5a480aad8a8666
2021-12-02 11:05:50 +00:00
Petr Pchelko
2932c3c92f GlobalConfigSink: don't double-prefix in setDefault
$this->set was calling the overridden method, so if it was
called from setDefault, we'd end up double-prefixing the config.

Change-Id: I5f912332cc69cb58bb71e87cd9f8154246b53232
2021-11-30 14:03:11 +00:00
Petr Pchelko
f98f7312e1 SettingsBuilder: add ability to validate config against schema
Not yet sure if config validation makes sense in production,
possibly before we write into cache we can validate, and then
trust that the cached values are all valid. This patch just
adds ability to validate the configuration.

"justinrainbow/json-schema" is already a transitive dependency
and is already in vendor.

Change-Id: Ib039c897a36a7e1911309fd29514657042b1b139
2021-11-30 00:09:07 +00:00
Dan Duvall
d83a7bcd09 Cache loading of SettingsBuilder sources
The `SettingsBuilder` now accepts a PSR-16 cache interface with which to
store and query settings before attempting to load from each source. By
default, no cache is used, but any object that implements the
`Psr\SimpleCache\CacheInterface` may be provided to the constructor.

An explicit dependency on "psr/simple-cache" has been added to
`composer.json`. Note that this dependency already existed in vendor
albeit it as a transitive one.

An APCu based `SharedMemoryCache` adapter is provided as a canonical
PSR-16 compliant interface for production use.

Sources are now queued by the `SettingsBuilder` when calling `load()`.
If a cache interface has been provided, and the source is considered
cacheable (implements `CacheableSource`), then it is wrapped as a
`CachedSource` which will query the cache first before loading from the
wrapped source.

Cache stampedes are mitigated using probabilistic early expiry. The
implementation for this was partially based on symfony/cache-contract
source code but also from the Wikipedia article and paper referenced
therein.

See https://en.wikipedia.org/wiki/Cache_stampede#Probabilistic_early_expiration

Bug: T294748
Change-Id: I52ab3899731546876ee58265bd4a1927886746dc
2021-11-29 12:54:59 -08:00
Petr Pchelko
120ef51cbf SettingsBuilder: Add YAML file format.
If php-yaml extension in installed, use that. Otherwise
we fallback to symfony Yaml parser.

php-yaml is about 20 times faster then symfony, for default-settings.yaml
it will take PHP-yaml 6ms to load it vs 100ms for symfony. But given
that the result will be cached, it's better not to bring in
a required native dependency.

Bug: T294751
Change-Id: I3ffde926c3f264cacf39810ff7bd338c9f78823d
2021-11-29 09:27:20 -08:00
Derick Alangi
dce6673430 Introduce setting PHP_INI env configs via a settings source
This feature enables the SettingsBuilder to be able to set php-ini
environment variables at run-time.

We just do so by specifying the various key/value pairs to the `php-ini`
key like below:

```
"php-ini": {
    "key": "value",
    ...
}
```

This will allow us to set things like `display_errors`, `memory_limits` etc.

Bug: T294752
Change-Id: I2ff0e7abc010342537bbaf1e1b71fb84d02a153b
2021-11-25 01:20:35 +01:00
Petr Pchelko
7f5d76d706 SettingsBuilder: Apply merge strategy from the schema to the config
Change-Id: Ia75f501c29d7589782cbbe99f723841dcd2acb75
2021-11-16 21:07:56 +00:00
Petr Pchelko
92f3f1a944 Introduce MergeStrategies for ConfigSink
Change-Id: Ibb4fdf83d87ad204da5fbc4892c9b7610e979f72
2021-11-16 13:07:03 -08:00
Dan Duvall
9a4af25664 Introduced settings sources and formats
A `SettingsSource` is meant to represent any kind of local or remote
store from which settings can be read, be this a local file, remote URL,
database, etc. It is concerned with reading in (and possibly decoding)
settings data, and computing a consistent hash key that may be used in
caching.

A `SettingsFormat` is meant to detect supported file types and/or decode
source contents into settings arrays. As of now, JSON is the only
supported format but others may be implemented.

`FileSource` is the first source implementation, with its default format
being JSON, meant to read settings from local JSON files.

`ArraySource` is mostly useful for testing using array literals.

Refactored `SettingsBuilder` methods to use the new source abstractions.

Bug: T295499
Change-Id: If7869609c4ad1ccd0894d5ba358f885007168972
2021-11-15 14:07:59 -08:00
daniel
84dfbecc1b Introducing SettingsBuilder for loading settings files.
The goal is to use SettingsBuilder to load settings from JSON files
instead of relying on PHP files that manipulate global variables.

To allow for a smooth transition to the new system, config settings read
from JSON files will be applied to global variables, and it will be
possible to load JSON files programmatically from inside traditional
settings files.

Bug: T294740
Bug: T295500
Bug: T294741
Change-Id: Ibf52c660715fd0e6e67fea5169811ece9ed67cf7
2021-11-12 17:59:59 +01:00