-
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
Fix import bugs #121046
Fix import bugs #121046
Conversation
ce1137f
to
a152353
Compare
a152353
to
f69e2d4
Compare
ed9c4e9
to
9e2ca5a
Compare
Change some mocks for better readability.
Split this function into its own module.
Renamed `importIdMap` to `importStateMap`, changed `id` value to `destinationId`, and added TSdocs.
9e2ca5a
to
ed3cd39
Compare
ed3cd39
to
96b1583
Compare
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.
Author's notes for reviewers.
const [object] = savedObjects; | ||
if (id !== object.id) { | ||
return { | ||
key: getObjectKey({ type, id }), |
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'm using getObjectKey
here instead of a string template ${type}:${id}
, and I'm using parseObjectKey
further below.
I'm doing this here because of feedback during recent changes that I made to the SOR, where we had a lot of these string templates and we decided we'd prefer to use a common function instead.
There are tons of other ${type}:${id}
string templates in the import module, but I opted not to change all of them because this PR already turned out to be bigger than expected 😅 we'll leave that tech debt for another day!
export interface ImportStateValue { | ||
/** | ||
* This attribute indicates that the object for this entry is *only* a reference, it does not exist in the import file. | ||
*/ | ||
isOnlyReference?: boolean; |
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 isOnlyReference
attribute is new. I don't love the name, but I couldn't think of anything better. I'm totally open to suggestions here.
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 don't really have anything that much better. isOutboundReference
? referencedObjects
?
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.
🤷 yeah I think the only thing that would make it clearer would be to have a separate state map just for references, but that would add a lot of boilerplate and complexity so I wanted to avoid that.
@@ -8,23 +8,34 @@ | |||
import expect from '@kbn/expect'; | |||
import { SuperTest } from 'supertest'; | |||
import type { Client } from '@elastic/elasticsearch'; | |||
import type { SavedObjectReference } from 'src/core/server'; | |||
import { SAVED_OBJECT_TEST_CASES as CASES } from '../lib/saved_object_test_cases'; | |||
import { SPACES } from '../lib/spaces'; | |||
import { expectResponses, getUrlPrefix, getTestTitle } from '../lib/saved_object_test_utils'; | |||
import { ExpectResponseBody, TestCase, TestDefinition, TestSuite } from '../lib/types'; | |||
|
|||
export interface ImportTestDefinition extends TestDefinition { |
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.
The import
and resolveImportErrors
integration tests were designed to import a mixture of objects that don't exist yet, with objects that already exist. This would generate conflict errors, and the destination objects would need to be overwritten. Each suite exercises three different scenarios:
createNewCopies: false, overwrite: false
createNewCopies: false, overwrite: true
createNewCopies: true
, overwrite: false`
The problem is there is another type of error that can occur, a "missing references" error, that originates from the validateReferences
module. We never had tests for this before, and I thought it would be prudent to add tests for this now, since we need to make assertions that Kibana is correctly matching origins for references anyway.
Unfortunately, these test suites needed some significant refactoring to make this happen. There are a lot of ways to skin this cat, but I tried to make the most minimal changes possible. I think there is a lot of room for improvement, but I didn't want this PR to be any bigger than it already is.
export const SPECIAL_TEST_CASES: Record<string, ImportTestCase> = Object.freeze({ | ||
HIDDEN, |
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.
We already treated the "HIDDEN" test case as a special case before, I'm just making that clearer now.
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.
Last commit was sure fun to review, but I think it's LGTM overall.
We really need to cleanup and refactor our FTR tests related to import/export though, it's becoming VERY hard to review this part of the code.
src/core/server/saved_objects/import/lib/validate_references.ts
Outdated
Show resolved
Hide resolved
src/core/server/saved_objects/import/lib/validate_references.ts
Outdated
Show resolved
Hide resolved
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.
Verified #121038, #122149, and #120312 locally and working as defined.
As discussed though I worry about the complexity of the import and copy functionality.
There are a lot of edge cases which did not behave the way I would have expect in order to preserve the (accidental) legacy behaviour:
- There are situations now where depending on the type of saved objects or the number of references those saved objects have, the "overwrite existing saved objects" setting gets ignored for some of the imported objects but not for others
- Similarly the "resolve conflicts manually" setting gets ignored where users are asked to resolve conflicts themselves for some saved objects even though they selected to automatically resolve conflicts. If that's the case we probably shouldn't provide this option at all.
- There are also situations where conflicts are ignored when index patterns are missing causing duplicate saved objects despite "overwrite existing saved objects" being selected.
I appreciate that we want to have as few breaking changes as possible but I find all of the above quite problematic from a user and maintenance perspective since it's almost impossible to predict what is actually going to happen on import.
The sheer number of scenarios and user flows also means we end up with a lot of code complexity and ultimately these types of bugs and edge cases.
I think it would be good to try and simplify this functionality in the future.
@thomheymann I completely agree. We had some discussions in September for how we could solve this and we were mostly aligned on the approach but unfortunately we haven't made any further progress on this see #91615 (comment) I think it would be useful for you to add your comment to that issue. |
@elasticmachine merge upstream |
Thanks all, I also agree this is way too complex and there are too many edge cases. More motivation for us to actually solve this and do away with this import API once and for all. |
💚 Build Succeeded
Metrics [docs]
History
To update your PR or re-run it, just comment with: |
(cherry picked from commit 116d74a)
💚 All backports created successfully
Note: Successful backport PRs will be merged automatically after passing CI. Questions ?Please refer to the Backport tool documentation |
(cherry picked from commit 116d74a) Co-authored-by: Joe Portner <[email protected]>
Resolves #121038 and #122149 and #120312
I combined these three bugfixes into the same PR because they are all touching the same part of the codebase, and I thought it might be harder on everyone to manage three separate PRs.
The first three commits are simple refactoring:
Now our mocks are more well-defined and easier to work with. Also this removes one of the annoying jest warnings regarding multiple "mocks/index.ts" files.
This function should have been in its own module and it was aggravating me, so I went ahead and moved it.
This renames
importIdMap
toimportStateMap
, since I'm changing it to do more than just track what IDs are getting changed (more on that below). It also adds TSdocs so this part of the codebase is less obtuse!The last three commits are the actual bugfixes. I won't go into too much detail here, the linked issues are quite thorough:
overwrite=true
#121038)This is pretty simple; if we found a regular conflict for an object (exact match), we need to avoid subsequently searching for origin conflicts (inexact match conflicts).
This is also pretty simple; we just needed to remove the
namespace:
prefix from the query incheckOriginConflicts
.This one is a bit more involved... 😅 I had to add a completely new
checkReferenceOrigins
module (that is based on the existingcheckOriginConflicts
module), and I had to change what we are tracking in theimportStateMap
. Before, this map had an entry for each object that is being imported. Now, this map has an entry for each object that is being imported and each outbound reference that is not included in the import file. We rely on the existing ID-remapping functionality in thecreateSavedObjects
module to facilitate changing reference IDs based on a shared origin.All three of these include updates to unit tests and integration tests as well.