Run SO migration after plugins setup phase.#55012
Run SO migration after plugins setup phase.#55012pgayvallet merged 22 commits intoelastic:masterfrom
Conversation
pgayvallet
left a comment
There was a problem hiding this comment.
My thoughts on this first draft.
Finishing the PR implies heavy changes on plugins code, and also now got #54886 as a requirement. I would like to be sure that this is the direction we want to take before continuing this work.
I also got the feeling that is we exposes everything SO-client related in start, we should probably do the same for elasticsearch and uisettings
| const clientProvider = new SavedObjectsClientProvider<KibanaRequest>({ | ||
| defaultClientFactory({ request }) { | ||
| const repository = repositoryFactory.createScopedRepository(request); | ||
| return new SavedObjectsClient(repository); | ||
| }, | ||
| }); | ||
| if (this.clientFactoryProvider) { | ||
| const clientFactory = this.clientFactoryProvider(repositoryFactory); | ||
| clientProvider.setClientFactory(clientFactory); | ||
| } | ||
| this.clientFactoryWrappers.forEach(({ id, factory, priority }) => { | ||
| clientProvider.addClientWrapperFactory(priority, id, factory); | ||
| }); |
There was a problem hiding this comment.
Now that the clientProvider is created after everything has been registered to the service, we should probably use a simple constructor instead,
const clientProvider = new SavedObjectsClientProvider<KibanaRequest>({
clientFactory,
clientWrappers,
})
There was a problem hiding this comment.
I tried to do it, but TIL is that the clientProvider is exposed in the internal API to be directly used from the legacy SO service in src/legacy/server/saved_objects/saved_objects_mixin.js, so changing the class is not trivial. This should wait until legacy has been removed.
|
Pinging @elastic/kibana-platform (Team:Platform) |
|
@elastic/kibana-platform I would like you opinion on this because going further into the development. |
I'm wondering if we could resolve this if we keep creating the repository in There's quite a bit of complexity in how all the SO parts get stitched together, so we would probably have to create a new POC to test this out and make sure it doesn't lead to some sort of dead end. |
I wanted to try that, however:
If the only thing pushing in that direction is this single own core usage for But the discussion is still widely open. I really don't have a clear vision of what the best thing to do is... |
joshdover
left a comment
There was a problem hiding this comment.
This looks like the right direction to me.
I agree that uiSettings and Elasticsearch maybe shouldn't be exposed before migrations are ran. uiSettings I'm very sure shouldn't be. However, Elasticsearch might be safe. Many plugins set up or query other non-SO indices. However, I'm not sure there's any advantage to allowing these during setup rather than start.
The strict separation between setup and start has been very helpful on the client. Keeping registration logic and setup and "running" logic in start seems like the way to go, though I do fear the number of plugins that this will affect.
| * | ||
| * @public | ||
| */ | ||
| export type SavedObjectsClientFactoryProvider<Request = unknown> = ( |
There was a problem hiding this comment.
oh no, a factory provider ☕️
There was a problem hiding this comment.
seen on a real previous project: RPCClientFactoryBridgedProviderCachedRegistry. We still got some margin.
There was a problem hiding this comment.
Haha, in legacy we have Scoped- too so we could create an impressive ScopedClientFactoryWrapperProvider
kibana/src/legacy/server/saved_objects/saved_objects_mixin.js
Lines 139 to 140 in ca55402
There was a problem hiding this comment.
AFAIK all usages of setScopedSavedObjectsClientFactory has been migrated to be using NP API from legacy instead (which is not the case of setScopedSavedObjectsClientFactory ). I think I might removes it in this PR. will do after a first green CI though
That's my feeling too. The I guess we need to finish this attempt on SO to see if it becomes clear that it should be done also on UI (and maybe ES) |
Looking at this again I agree. Registering mappings, schemas and migrations aren't fundamentally things we would ever want to be reactive. Modelling these as observables will probably reduce the clarity of the code. |
|
Now waiting for #55156 to be integrated to be able to properly updates plugin's calls of the moved APIs |
…ation-after-setup
|
#55156 has been merged on master and integrated in the PR branch. Should now be able to continue with the PR. |
👍 to restrict access to elasticsearch API or provide |
…ation-after-setup
…ation-after-setup
| getServices(rawRequest: Hapi.Request): Services { | ||
| const request = KibanaRequest.from(rawRequest); | ||
| return { | ||
| callCluster: (...args) => | ||
| adminClient!.asScoped(KibanaRequest.from(request)).callAsCurrentUser(...args), | ||
| savedObjectsClient: core.savedObjects.getScopedSavedObjectsClient(request), | ||
| callCluster: (...args) => adminClient!.asScoped(request).callAsCurrentUser(...args), | ||
| // rawRequest is actually a fake request, converting it to KibanaRequest causes issue in SO access | ||
| savedObjectsClient: core.savedObjects.getScopedSavedObjectsClient(rawRequest as any), |
There was a problem hiding this comment.
I did properly adapt this to use core.savedObjects.getScopedSavedObjectsClient(request). However I got test failures, and I isolated it to this change.
Calling core.savedObjects.getScopedSavedObjectsClient with KibanaRequest.from(request) instead of the raw HAPI request makes the test fail, with
Saved object [alert/dbbfe2a1-e3ab-4ebe-84f2-9ed495b9d81b] not found
Forcecasting the raw request fix the failure:
savedObjectsClient: core.savedObjects.getScopedSavedObjectsClient(rawRequest as any)AFAIK it's because the rawRequest, even if typed as Hapi.Request, is actually a fake request:
and the GetServices signature differs from between the type and the actual implementation, allowing to call it without a proper hapi request...
Not sure what the underlying cause is though. I though only the headers from the request were actually used when using the request to create the scoped repository. But the fake request does miss some properties used when converting from request to kibanaRequest such as method.
Is this comment acceptable/enough for now, or should I investigate in this PR?
There was a problem hiding this comment.
Is this comment acceptable/enough for now, or should I investigate in this PR?
As for me, it's not a blocker for the current PR. But we should prioritize #39430 to be able to cut off legacy server-side plugins in 7.7
| addInstall: async (dataSet: string) => { | ||
| try { | ||
| await internalRepository.incrementCounter(SAVED_OBJECT_ID, dataSet, `installCount`); | ||
| await (await internalRepository).incrementCounter(SAVED_OBJECT_ID, dataSet, `installCount`); |
There was a problem hiding this comment.
optional: I'd expect something similar to https://github.com/elastic/kibana/pull/55012/files#diff-b7a00ca0a0cbdb5c3792d6a7dbfd6811R67-R74
There was a problem hiding this comment.
Missed this one when cleanup up the calls, thanks
| * factory can be set, subsequent calls to this method will fail. | ||
| */ | ||
| setClientFactory: (customClientFactory: SavedObjectsClientFactory<KibanaRequest>) => void; | ||
| setClientFactoryProvider: (clientFactoryProvider: SavedObjectsClientFactoryProvider) => void; |
There was a problem hiding this comment.
nit: can we update the comment above to make it clear that this sets a default factory provider. Also it'd be nice if we used {@link SavedObjectsClientFactoryProvider | factory provider}
* change setClientFactory api to setClientFactoryProvider * cleanup and add test for service * change the signatures of SO start/setup * fix registerCoreContext by accessing stored start contract reference * move migration inside `start` * adapt and add service tests * add doc and export new types * adapt plugins code * update generated doc * better core access * address some review comments * remove parametrized type from SavedObjectsClientFactory, use KibanaRequest instead * add logs when starting and ending so migration * fix KibanaRequest imports * NITs and review comments * fix alerting FTR test * review comments
* change setClientFactory api to setClientFactoryProvider * cleanup and add test for service * change the signatures of SO start/setup * fix registerCoreContext by accessing stored start contract reference * move migration inside `start` * adapt and add service tests * add doc and export new types * adapt plugins code * update generated doc * better core access * address some review comments * remove parametrized type from SavedObjectsClientFactory, use KibanaRequest instead * add logs when starting and ending so migration * fix KibanaRequest imports * NITs and review comments * fix alerting FTR test * review comments
💔 Build FailedHistory
To update your PR or re-run it, just comment with: |
Summary
Fix #52071
PR does the following:
createScopedRepositoryandcreateInternalRepositoryfromsetupcontract tostartcontract, and removesgetScopedClientfrom thesetupcontract. There is no longer a possibility to be performing any call to SO before core'sstartis doneSavedObjectsService.start(), meaning that any SO call performed is assured to be done after the migrationsetClientFactoryAPI tosetClientFactoryProviderto provides a SO repository provider when registering the client factorysetupto be now usinggetStartServicesto access them on the corestartcontractDepends on #55156 (merged)
This is also a requirement for SO issues regarding registration of SO mappings / migrations / schemas / validations from NP (#50313, #50311, #50309)
Dev Docs
createScopedRepositoryandcreateInternalRepositoryfromsetupcontract tostartcontract, and removesgetScopedClientfrom thesetupcontract. There is no longer a possibility to be performing any call to SO before core'sstartis doneSavedObjectsService.start(), meaning that any SO call performed is assured to be done after the migrationsetClientFactoryAPI tosetClientFactoryProviderto provides a SO repository provider when registering the client factorysetupto be now usinggetStartServicesto access them on the corestartcontractChecklist
Use
strikethroughsto remove checklist items you don't feel are applicable to this PR.[ ] This was checked for cross-browser compatibility, including a check against IE11[ ] Any text added follows EUI's writing guidelines, uses sentence case text and includes i18n support[ ] This was checked for keyboard-only and screenreader accessibilityFor maintainers
Devs Docs
core
savedObjectsAPIs are no longer exposing methods that allows to perform SO calls from it'ssetupcontract.createScopedRepository,createInternalRepositoryandgetScopedClientare now only accessible from the servicestartcontract.When registering asynchronous handlers during a plugin
setupphase that relies on these APIs,getStartServicesshould be used:before
after