-
Notifications
You must be signed in to change notification settings - Fork 8.2k
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Run SO migration after plugins setup phase. #55012
Run SO migration after plugins setup phase. #55012
Conversation
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
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.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
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.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
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... |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
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.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
oh no, a factory provider ☕️
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
seen on a real previous project: RPCClientFactoryBridgedProviderCachedRegistry
. We still got some margin.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
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
setScopedSavedObjectsClientFactory: (...args) => provider.setClientFactory(...args), | |
addScopedSavedObjectsClientWrapperFactory: (...args) => |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
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. |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Security changes LGTM
…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.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
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:
const fakeRequest = { | |
headers: requestHeaders, | |
getBasePath: () => this.context.getBasePath(spaceId), | |
path: '/', | |
route: { settings: {} }, | |
url: { | |
href: '/', | |
}, | |
raw: { | |
req: { | |
url: '/', | |
}, | |
}, | |
}; | |
return this.context.getServices(fakeRequest); |
and the GetServices
signature differs from between the type and the actual implementation, allowing to call it without a proper hapi request...
export type GetServicesFunction = (request: any) => Services; |
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.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This is related to #39430 btw
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
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
|
||
return { | ||
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.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
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.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Missed this one when cleanup up the calls, thanks
@@ -83,58 +87,22 @@ export interface SavedObjectsServiceSetup { | |||
* Set a default factory for creating Saved Objects clients. Only one client | |||
* 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.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
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:
createScopedRepository
andcreateInternalRepository
fromsetup
contract tostart
contract, and removesgetScopedClient
from thesetup
contract. There is no longer a possibility to be performing any call to SO before core'sstart
is doneSavedObjectsService.start()
, meaning that any SO call performed is assured to be done after the migrationsetClientFactory
API tosetClientFactoryProvider
to provides a SO repository provider when registering the client factorysetup
to be now usinggetStartServices
to access them on the corestart
contractDepends 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
createScopedRepository
andcreateInternalRepository
fromsetup
contract tostart
contract, and removesgetScopedClient
from thesetup
contract. There is no longer a possibility to be performing any call to SO before core'sstart
is doneSavedObjectsService.start()
, meaning that any SO call performed is assured to be done after the migrationsetClientFactory
API tosetClientFactoryProvider
to provides a SO repository provider when registering the client factorysetup
to be now usinggetStartServices
to access them on the corestart
contractChecklist
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
savedObjects
APIs are no longer exposing methods that allows to perform SO calls from it'ssetup
contract.createScopedRepository
,createInternalRepository
andgetScopedClient
are now only accessible from the servicestart
contract.When registering asynchronous handlers during a plugin
setup
phase that relies on these APIs,getStartServices
should be used:before
after