-
Notifications
You must be signed in to change notification settings - Fork 8.3k
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
[content mgmt / maps] Saved Object wrapper for Content Management API #155680
[content mgmt / maps] Saved Object wrapper for Content Management API #155680
Conversation
…om:mattkime/kibana into content_management_api_so_type_abstraction
enableMSearch?: boolean; | ||
} | ||
|
||
export abstract class SOContentStorage<Types extends CMCrudTypes> |
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 class is where the work happens.
packages/kbn-content-management-utils/src/saved_object_content_storage.ts
Show resolved
Hide resolved
total: response.total, | ||
}, | ||
export class MapsStorage extends SOContentStorage<MapCrudTypes> { | ||
constructor() { |
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 the result. Expressing your SO / content mgmt api integration in a very concise number of lines of code. Easier to see if you look at the file view - https://github.com/elastic/kibana/blob/861b8af7545082b2aae79205be6c3e98ad480d55/x-pack/plugins/maps/server/content_management/maps_storage.ts
|
||
// todo - talk to anton about a better way to implement this | ||
if (enableMSearch) { | ||
this.mSearch = { |
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.
@Dosant We should find a better api for this. I'd prefer to use some sort of boolean to determine whether mSearch is enabled. As best I can tell this is largely a reconfiguration of code used elsewhere
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.
will improve. #155718
hopefully non blocking
Pinging @elastic/kibana-data-discovery (Team:DataDiscovery) |
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.
Thanks for putting this PR together. I keep having some concerns about trying to fit it all under one package in terms of interfaces and schema.
At the very least I think that the utility package should follow the same versioning folder mechanism that the one I put for maps. It will be versioned based on change in the underlying SO server client.
We need to be able to version and up/down grade all those common interfaces (options, SO meta...) and schema somehow.
Let's take an example: in the SavedObjectSearchOptions
interface there is an namespaces
field which is a string[]
- How can we make it evolve to
{ name: string; group: string }
? - How is the up transform going to occur when the UI will still send a list of string and the server has been upgraded to accept an object?
It seems that we will have to also send the request version to the utility that will in turn return the correct schema... This starts to get complex (in my head at least 😄 )
packages/kbn-content-management-utils/src/saved_object_content_storage.ts
Show resolved
Hide resolved
This confuses me a bit. If there's an underlying change in the SO server client then all SO CM integrations will need to work with it. I don't think the callee's (in this case the SO server client) need to be versioned in the same way that the arguments need to. If there's something I'm missing here, I suspect the code in this PR would have the same weaknesses as the maps CM integration code.
Oh, perhaps I'm misunderstanding and this is a restatement of a previous concern - that the various Option types are too closely tied to the actual SO api. If thats the concern, then I think this is addressed by the existing transform code. I think its okay to have arguments that map to SO api arguments as long as they're well defined AND we could transform them. If a map of arguments was being tossed into the SO api without further definition that would be clearly wrong.
We have two options. Either we can inspect the items in the namespace array and convert the strings to objects OR we could add an namespaceObjects argument and we could handle the two types appropriately. Perhaps I'm repeating a familiar debate regarding how to transform apis. A big part of my reason for arguing against using args that are purposefully different from SO args is that I suspect it creates unnecessary work. Implementing the CM api can be very easy, thinking about how to abstract every call into the SO api is much more work. I do think it may eventually be necessary to change these calls but its possible that we could delay it I'd like to state any outstanding concerns as plainly as possible -
Is this correct? |
If you are 100% sure you got a solution for the concerns I raised about being able to version any object that comes in for any SO, then I trust your judgment. From where I am standing I see it even more complex now than before to handle it. But with that said... we still don't have the final verdict if we even have to worry about it (e.g. if we have a blue/green upgrade we won't have to do any kind of transform in the storage class). Otherwise your abstraction might start looking like: async create(ctx, data, options) {
const transforms = ctx.utils.getTransforms(this.cmServicesDefinition);
const soClient = await savedObjectClientFromRequest(ctx);
// NEW: we need a new definition for the shared schemas
const transformsForAbstraction = ctx.utils.getTransforms(<some-definition>);
// Validate data & UP transform them to the latest version
const { value: dataToLatest, error: dataError } = transforms.create.in.data.up<
Types['Attributes'],
Types['Attributes']
>(data);
if (dataError) {
throw Boom.badRequest(`Invalid data. ${dataError.message}`);
}
// NEW: Add this block to handle BWC for **shared** option schema
// But do we really need it, what if the options are completely different for one specific SO type??
const { value: optionsToLatest, error: optionsError } = transformsForAbstraction.create.in.options.up(options);
if (optionsError) {
throw Boom.badRequest(`Invalid options. ${optionsError.message}`);
}
// What do we do here?? Do we do it or is it behind a if condition?
const { value: optionsToLatest, error: optionsError } = transforms.create.in.options.up<
Types['CreateOptions'],
Types['CreateOptions']
>(optionsToLatest1);
if (optionsError) {
throw Boom.badRequest(`Invalid options. ${optionsError.message}`);
}
const createOptions = this.createArgsToSoCreateOptions(optionsToLatest);
} As you can see it starts to get very complex and IMO pretty hard to maintain. |
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.
Approving to unblock the work. It is still unclear to me how we will migrate the shared options
object in the abstraction as mentioned in my previous comments.
As we don't have yet a way to test a server upgrade and a UI doing request from an older version we can revisit later. But I do think at some point we'll have to address this problem 😊 and my personal take is that abstracting too early until all unknown are known might create more problem down the road.
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.
Code changes LGTM 👍
const hasReference: SavedObjectsFindOptions['hasReference'] = included | ||
? included.map((id) => ({ | ||
id, | ||
type: 'tag', | ||
})) | ||
: undefined; | ||
|
||
const hasNoReference: SavedObjectsFindOptions['hasNoReference'] = excluded | ||
? excluded.map((id) => ({ | ||
id, | ||
type: 'tag', | ||
})) | ||
: undefined; |
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.
Can we use tagsToFindOptions
here too?
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.
kibana-gis changes LGTM
code review only
💚 Build Succeeded
Metrics [docs]Public APIs missing comments
Unknown metric groupsAPI count
ESLint disabled line counts
Total ESLint disabled count
History
To update your PR or re-run it, just comment with: cc @mattkime |
…#155680) ## Summary Abstract class for implementing content storage for saved objects. --------- Co-authored-by: kibanamachine <[email protected]>
Summary
Abstract class for implementing content storage for saved objects.
Follow up to #155342
The maps content management storage class for maps has been reduced to -